inter-view tweaks, add clip preview, fix for dupl proxy vicon refs, fix track drag...
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / awindowgui.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "arender.h"
23 #include "asset.h"
24 #include "assetedit.h"
25 #include "assetpopup.h"
26 #include "assetremove.h"
27 #include "assets.h"
28 #include "audiodevice.h"
29 #include "awindow.h"
30 #include "awindowgui.h"
31 #include "bccmodels.h"
32 #include "bcsignals.h"
33 #include "bchash.h"
34 #include "binfolder.h"
35 #include "cache.h"
36 #include "cstrdup.h"
37 #include "clip.h"
38 #include "clipedls.h"
39 #include "clippopup.h"
40 #include "cursors.h"
41 #include "cwindowgui.h"
42 #include "cwindow.h"
43 #include "edits.h"
44 #include "edit.h"
45 #include "edl.h"
46 #include "edlsession.h"
47 #include "effectlist.h"
48 #include "file.h"
49 #include "filesystem.h"
50 #include "folderlistmenu.h"
51 #include "indexable.h"
52 #include "keys.h"
53 #include "language.h"
54 #include "labels.h"
55 #include "labelpopup.h"
56 #include "localsession.h"
57 #include "mainerror.h"
58 #include "mainmenu.h"
59 #include "mainsession.h"
60 #include "mwindowgui.h"
61 #include "mwindow.h"
62 #include "preferences.h"
63 #include "proxy.h"
64 #include "proxypopup.h"
65 #include "renderengine.h"
66 #include "samples.h"
67 #include "theme.h"
68 #include "tracks.h"
69 #include "track.h"
70 #include "transportque.h"
71 #include "vframe.h"
72 #include "vicon.h"
73 #include "vrender.h"
74 #include "vwindowgui.h"
75 #include "vwindow.h"
76
77 #include "data/lad_picon_png.h"
78 #include "data/ff_audio_png.h"
79 #include "data/ff_video_png.h"
80
81 #include<stdio.h>
82 #include<unistd.h>
83 #include<fcntl.h>
84
85
86 const char *AWindowGUI::folder_names[] =
87 {
88         N_("Audio Effects"),
89         N_("Video Effects"),
90         N_("Audio Transitions"),
91         N_("Video Transitions"),
92         N_("Labels"),
93         N_("Clips"),
94         N_("Media"),
95         N_("Proxy"),
96 };
97
98
99 AssetVIcon::AssetVIcon(AssetPicon *picon, int w, int h, double framerate, int64_t length)
100  : VIcon(w, h, framerate), Garbage("AssetVIcon")
101 {
102         this->picon = picon;
103         this->length = length;
104         temp = 0;
105 }
106
107 AssetVIcon::~AssetVIcon()
108 {
109         picon->gui->vicon_thread->del_vicon(this);
110         delete temp;
111 }
112
113 VFrame *AssetVIcon::frame()
114 {
115         AssetVIconThread *avt = picon->gui->vicon_thread;
116         Asset *asset = (Asset *)picon->indexable;
117         if( !asset )
118                 return *images[0];
119         if( !asset->video_data && audio_data && audio_size && length > 0 ) {
120                 if( !temp ) temp = new VFrame(0, -1, w, h, BC_RGB888, -1);
121                 temp->clear_frame();
122                 int sample_rate = asset->get_sample_rate();
123                 int64_t audio_samples = asset->get_audio_samples();
124                 double duration = (double)audio_samples / sample_rate;
125                 picon->draw_hue_bar(temp, duration);
126                 int secs = length / frame_rate + 0.5;
127                 if( !secs ) secs = 1;
128                 int bfrsz = VICON_SAMPLE_RATE;
129                 int samples = audio_size/sizeof(vicon_audio_t);
130                 double line_pos = (double)seq_no/(length-1);
131                 int audio_pos = samples * line_pos * (secs-1)/secs;
132                 vicon_audio_t *audio_data = ((vicon_audio_t *)this->audio_data) + audio_pos;
133                 static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
134                 double data[bfrsz], sample_scale = 1./mx;
135                 int len = samples - audio_pos;
136                 if( len > bfrsz ) len = bfrsz;
137                 int i = 0;
138                 while( i < len ) data[i++] = *audio_data++ * sample_scale;
139                 while( i < bfrsz ) data[i++] = 0;
140                 picon->draw_wave(temp, data, bfrsz, RED, GREEN);
141                 int x = (w-1) * line_pos;
142                 temp->pixel_rgb = RED;
143                 temp->draw_line(x,0, x,h);
144                 return temp;
145         }
146         int vw = avt->vw, vh = avt->vh, vicon_cmodel = avt->vicon_cmodel;
147         if( !asset->video_data ) {
148                 if( !temp ) {
149                         temp = new VFrame(0, -1, vw, vh, BC_RGB888, -1);
150                         temp->clear_frame();
151                 }
152                 return temp;
153         }
154         if( seq_no >= images.size() ) {
155                 MWindow *mwindow = picon->mwindow;
156                 File *file = mwindow->video_cache->check_out(asset, mwindow->edl, 1);
157                 if( !file ) return 0;
158                 if( temp && (temp->get_w() != asset->width || temp->get_h() != asset->height) ) {
159                         delete temp;  temp = 0;
160                 }
161                 if( !temp )
162                         temp = new VFrame(0, -1, asset->width, asset->height, BC_RGB888, -1);
163                 while( seq_no >= images.size() ) {
164                         mwindow->video_cache->check_in(asset);
165                         Thread::yield();
166                         file = mwindow->video_cache->check_out(asset, mwindow->edl, 0);
167                         if( !file ) { usleep(1000);  continue; }
168                         file->set_layer(0);
169                         int64_t pos = images.size() / picon->gui->vicon_thread->refresh_rate * frame_rate;
170                         file->set_video_position(pos,0);
171                         if( file->read_frame(temp) ) temp->clear_frame();
172                         add_image(temp, vw, vh, vicon_cmodel);
173                 }
174                 mwindow->video_cache->check_in(asset);
175         }
176         return *images[seq_no];
177 }
178
179 int64_t AssetVIcon::set_seq_no(int64_t no)
180 {
181         if( no >= length ) no = 0;
182         return seq_no = no;
183 }
184
185 int AssetVIcon::get_vx()
186 {
187         BC_ListBox *lbox = picon->gui->asset_list;
188         return lbox->get_icon_x(picon);
189 }
190 int AssetVIcon::get_vy()
191 {
192         BC_ListBox *lbox = picon->gui->asset_list;
193         return lbox->get_icon_y(picon);
194 }
195
196 void AssetVIcon::load_audio()
197 {
198         MWindow *mwindow = picon->mwindow;
199         Asset *asset = (Asset *)picon->indexable;
200         File *file = mwindow->audio_cache->check_out(asset, mwindow->edl, 1);
201         int channels = asset->get_audio_channels();
202         if( channels > 2 ) channels = 2;
203         int sample_rate = asset->get_sample_rate();
204         int bfrsz = sample_rate;
205         Samples samples(bfrsz);
206         double time_scale = (double)sample_rate / VICON_SAMPLE_RATE;
207         vicon_audio_t *audio_data = (vicon_audio_t *)this->audio_data;
208         static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
209         double sample_scale = (double)mx / channels;
210         int audio_pos = 0, audio_len = audio_size/sizeof(vicon_audio_t);
211         while( audio_pos < audio_len ) {
212                 int64_t pos = audio_pos * time_scale;
213                 for( int ch=0; ch<channels; ++ch ) {
214                         file->set_channel(ch);
215                         file->set_audio_position(pos);
216                         file->read_samples(&samples, bfrsz);
217                         double *data = samples.get_data();
218                         for( int64_t k=audio_pos; k<audio_len; ++k ) {
219                                 int i = k * time_scale - pos;
220                                 if( i >= bfrsz ) break;
221                                 int v = audio_data[k] + data[i] * sample_scale;
222                                 audio_data[k] = CLIP(v, -mx,mx);
223                         }
224                 }
225                 audio_pos = (pos + bfrsz) / time_scale;
226         }
227         mwindow->audio_cache->check_in(asset);
228 }
229
230
231 AssetVIconAudio::AssetVIconAudio(AWindowGUI *gui)
232  : Thread(1, 0, 0)
233 {
234         this->gui = gui;
235         audio = new AudioDevice(gui->mwindow);
236         interrupted = 0;
237         vicon = 0;
238 }
239 AssetVIconAudio::~AssetVIconAudio()
240 {
241         delete audio;
242 }
243
244 void AssetVIconAudio::run()
245 {
246         int channels = 2;
247         int64_t bfrsz = VICON_SAMPLE_RATE;
248         MWindow *mwindow = gui->mwindow;
249         EDL *edl = mwindow->edl;
250         EDLSession *session = edl->session;
251         AudioOutConfig *aconfig = session->playback_config->aconfig;
252         audio->open_output(aconfig, VICON_SAMPLE_RATE, bfrsz, channels, 0);
253         audio->start_playback();
254         double out0[bfrsz], out1[bfrsz], *out[2] = { out0, out1 };
255         vicon_audio_t *audio_data = (vicon_audio_t *)vicon->audio_data;
256         static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
257
258         int audio_len = vicon->audio_size/sizeof(vicon_audio_t);
259         while( !interrupted ) {
260                 int len = audio_len - audio_pos;
261                 if( len <= 0 ) break;
262                 if( len > bfrsz ) len = bfrsz;
263                 int k = audio_pos;
264                 for( int i=0; i<len; ++i,++k )
265                         out0[i] = out1[i] = (double)audio_data[k] / mx;
266                 audio_pos = k;
267                 audio->write_buffer(out, channels, len);
268         }
269
270         if( !interrupted )
271                 audio->set_last_buffer();
272         audio->stop_audio(interrupted ? 0 : 1);
273         audio->close_all();
274 }
275
276 void AssetVIconAudio::start(AssetVIcon *vicon)
277 {
278         if( running() ) return;
279         interrupted = 0;
280         audio_pos = 0;
281         this->vicon = vicon;
282         Thread::start();
283 }
284
285 void AssetVIconAudio::stop(int wait)
286 {
287         if( running() && !interrupted ) {
288                 interrupted = 1;
289                 audio->stop_audio(wait);
290         }
291         Thread::join();
292         if( vicon ) {
293                 vicon->playing_audio = 0;
294                 vicon = 0;
295         }
296 }
297
298 void AssetVIcon::start_audio()
299 {
300         if( playing_audio < 0 ) return;
301         picon->gui->vicon_audio->stop(0);
302         playing_audio = 1;
303         picon->gui->vicon_audio->start(this);
304 }
305
306 void AssetVIcon::stop_audio()
307 {
308         if( playing_audio > 0 )
309                 picon->gui->vicon_audio->stop(0);
310         playing_audio = 0;
311 }
312
313 AssetViewPopup::AssetViewPopup(VIconThread *vt, int draw_mode,
314                 int x, int y, int w, int h)
315  : ViewPopup(vt, x, y, w, h)
316 {
317         this->draw_mode = draw_mode;
318         this->bar_h = (VIEW_POPUP_BAR_H * h) / 200;
319 }
320
321 AssetViewPopup::~AssetViewPopup()
322 {
323 }
324
325 int AssetViewPopup::button_press_event()
326 {
327         if( !is_event_win() ) return 0;
328         AssetVIconThread *avt = (AssetVIconThread *)vt;
329         if( !avt->vicon ) return 0;
330
331         int dir = 1, button = get_buttonpress();
332         switch( button ) {
333         case WHEEL_DOWN: dir = -1; // fall thru
334         case WHEEL_UP:   return zoom_scale(dir);
335         case LEFT_BUTTON:
336                 break;
337         default:
338                 return 0;
339         }
340
341         if( draw_mode != ASSET_VIEW_MEDIA_MAP ) return 0;
342         int x = get_cursor_x(), y = get_cursor_y();
343         AssetVIcon *vicon = (AssetVIcon *)avt->vicon;
344         AssetPicon *picon = vicon->picon;
345         MWindow *mwindow = picon->mwindow;
346         EDL *edl = mwindow->edl;
347         dragging = 0;
348         if( y < bar_h ) {
349                 Indexable *idxbl =
350                         picon->indexable ? picon->indexable :
351                         picon->edl ? picon->edl : 0;
352                 if( !idxbl ) return 0;
353                 double sample_rate = idxbl->get_sample_rate();
354                 double audio_length = sample_rate > 0 && idxbl->have_audio() ?
355                         idxbl->get_audio_samples() / sample_rate : 0;
356                 double frame_rate = idxbl->get_frame_rate();
357                 double video_length = frame_rate > 0 && idxbl->have_video() ?
358                         idxbl->get_video_frames() / frame_rate : 0;
359                 double idxbl_length = bmax(audio_length, video_length);
360                 double pos = x * idxbl_length / get_w();
361                 double start = 0, end = idxbl_length;
362                 double lt = DBL_MAX, rt = DBL_MAX;
363                 for( Track *track=edl->tracks->first; track!=0; track=track->next ) {
364                         for( Edit *edit=track->edits->first; edit!=0; edit=edit->next ) {
365                                 Indexable *indexable = (Indexable *)edit->asset;
366                                 if( !indexable ) indexable = (Indexable *)edit->nested_edl;
367                                 if( !indexable ) continue;
368                                 if( indexable->id == idxbl->id ||
369                                     (!indexable->is_asset == !idxbl->is_asset &&
370                                      !strcmp(indexable->path, idxbl->path)) ) {
371                                         double start_pos = track->from_units(edit->startsource);
372                                         double end_pos = track->from_units(edit->startsource + edit->length);
373                                         double dlt = pos - start_pos, drt = end_pos - pos;
374                                         if( dlt >= 0 &&  dlt < lt ) { lt = dlt;  start = start_pos; }
375                                         else if( dlt < 0 && -dlt < rt ) { rt = -dlt;  end = start_pos; }
376                                         if( drt >= 0 &&  drt < rt ) { rt = drt;  end = end_pos; }
377                                         else if( drt < 0 && -drt < lt ) { lt = -drt; start = end_pos; }
378                                 }
379                         }
380                 }
381                 mwindow->gui->lock_window("AssetVIcon::popup_button_press");
382                 VWindow *vwindow = mwindow->get_viewer(1, 0);
383                 vwindow->change_source(idxbl);
384                 mwindow->gui->unlock_window();
385                 EDL *vedl = vwindow->get_edl();
386                 vedl->set_inpoint(start);
387                 vedl->set_outpoint(end);
388                 vedl->local_session->set_selectionstart(start);
389                 vedl->local_session->set_selectionend(end);
390                 vwindow->update_position(CHANGE_NONE, 0, 1, 0);
391                 return 1;
392         }
393         if( y >= get_h()-bar_h ) {
394                 dragging = 1;
395                 if( !ctrl_down() && !shift_down() )
396                         return cursor_motion_event();
397                 Indexable *idxbl =
398                         picon->indexable ? picon->indexable :
399                         picon->edl ? picon->edl : 0;
400                 if( !idxbl ) return 0;
401                 double total_length = mwindow->edl->tracks->total_length();
402                 double pos = x * total_length / get_w();
403                 double start = 0, end = total_length;
404                 double lt = DBL_MAX, rt = DBL_MAX;
405                 for( Track *track=edl->tracks->first; track!=0; track=track->next ) {
406                         for( Edit *edit=track->edits->first; edit!=0; edit=edit->next ) {
407                                 Indexable *indexable = (Indexable *)edit->asset;
408                                 if( !indexable ) indexable = (Indexable *)edit->nested_edl;
409                                 if( !indexable ) continue;
410                                 if( indexable->id == idxbl->id ||
411                                     (!indexable->is_asset == !idxbl->is_asset &&
412                                      !strcmp(indexable->path, idxbl->path)) ) {
413                                         double start_pos = track->from_units(edit->startproject);
414                                         double end_pos = track->from_units(edit->startproject + edit->length);
415                                         double dlt = pos - start_pos, drt = end_pos - pos;
416                                         if( dlt >= 0 &&  dlt < lt ) { lt = dlt;  start = start_pos; }
417                                         else if( dlt < 0 && -dlt < rt ) { rt = -dlt;  end = start_pos; }
418                                         if( drt >= 0 &&  drt < rt ) { rt = drt;  end = end_pos; }
419                                         else if( drt < 0 && -drt < lt ) { lt = -drt; start = end_pos; }
420                                 }
421                         }
422                 }
423                 mwindow->gui->lock_window("AssetVIcon::popup_button_press");
424                 mwindow->select_point(!ctrl_down() && !shift_down() ? pos : start);
425                 edl->local_session->set_selectionstart(start);
426                 edl->local_session->set_selectionend(!shift_down() ? start : end);
427                 mwindow->zoom_sample(edl->local_session->zoom_sample);
428                 mwindow->gui->unlock_window();
429                 return 1;
430         }
431         return 0;
432 }
433
434 int AssetViewPopup::button_release_event()
435 {
436         if( !is_event_win() ) return 0;
437         dragging = 0;
438         return 1;
439 }
440
441 int AssetViewPopup::cursor_motion_event()
442 {
443         if( !is_event_win() ) return 0;
444         AssetVIconThread *avt = (AssetVIconThread *)vt;
445         if( !avt->vicon || draw_mode != ASSET_VIEW_MEDIA_MAP ) return 0;
446         if( !get_button_down() || get_buttonpress() != LEFT_BUTTON ||
447             ctrl_down() || alt_down() || shift_down() )
448                 return 0;
449         AssetVIcon *vicon = (AssetVIcon *)avt->vicon;
450         MWindow *mwindow = vicon->picon->mwindow;
451         EDL *edl = mwindow->edl;
452         if( dragging ) {
453                 int x = get_cursor_x();
454                 double total_length = edl->tracks->total_length();
455                 double pos = x * total_length / get_w();
456                 mwindow->gui->lock_window("AssetVIcon::popup_cursor_motion");
457                 mwindow->select_point(pos);
458                 mwindow->zoom_sample(edl->local_session->zoom_sample);
459                 mwindow->gui->unlock_window();
460                 return 1;
461         }
462         return 0;
463 }
464
465 void AssetViewPopup::draw_vframe(VFrame *vframe) 
466 {
467         switch( draw_mode ) {
468         case ASSET_VIEW_MEDIA:
469         case ASSET_VIEW_ICON:
470                 ViewPopup::draw_vframe(vframe);
471         case ASSET_VIEW_NONE:
472         default:
473                 return;
474         case ASSET_VIEW_MEDIA_MAP:
475                 break;
476         }
477         set_color(BLACK);
478         draw_box(0,0,get_w(),get_h());
479         int y1 = bar_h;
480         int y2 = get_h()-bar_h;
481         BC_WindowBase::draw_vframe(vframe, 0,y1, get_w(),y2-y1);
482         AssetVIconThread *avt = (AssetVIconThread *)vt;
483         AssetVIcon *vicon = (AssetVIcon *)avt->vicon;
484         AssetPicon *picon = (AssetPicon *)vicon->picon;
485         Indexable *idxbl =
486                 picon->indexable ? picon->indexable :
487                 picon->edl ? picon->edl : 0;
488         if( !idxbl ) return;
489         double sample_rate = idxbl->get_sample_rate();
490         double audio_length = sample_rate > 0 && idxbl->have_audio() ?
491                 idxbl->get_audio_samples() / sample_rate : 0;
492         double frame_rate = idxbl->get_frame_rate();
493         double video_length = frame_rate > 0 && idxbl->have_video() ?
494                 idxbl->get_video_frames() / frame_rate : 0;
495         double idxbl_length = bmax(audio_length, video_length);
496         if( !idxbl_length ) idxbl_length = 1;
497
498         EDL *edl = picon->mwindow->edl;
499         double total_length = edl->tracks->total_length();
500         if( !total_length ) total_length = 1;
501         for( Track *track=edl->tracks->first; track!=0; track=track->next ) {
502                 for( Edit *edit=track->edits->first; edit!=0; edit=edit->next ) {
503                         Indexable *indexable = (Indexable *)edit->asset;
504                         if( !indexable ) indexable = (Indexable *)edit->nested_edl;
505                         if( !indexable ) continue;
506                         if( indexable->id == idxbl->id ||
507                             (!indexable->is_asset == !idxbl->is_asset &&
508                              !strcmp(indexable->path, idxbl->path)) ) {
509                                 double pos1 = track->from_units(edit->startsource);
510                                 double pos2 = track->from_units(edit->startsource + edit->length);
511                                 double xscale = get_w() / idxbl_length;
512                                 int ex1 = pos1 * xscale, ex2 = pos2 * xscale;
513                                 set_color(WHITE);
514                                 draw_box(ex1,0, ex2-ex1,y1);
515                                 set_color(BLACK);
516                                 draw_line(ex1,0, ex1,y1);
517                                 draw_line(ex2,0, ex2,y1);
518                                 pos1 = track->from_units(edit->startproject);
519                                 pos2 = track->from_units(edit->startproject + edit->length);
520                                 xscale = get_w() / total_length;
521                                 int px1 = pos1 * xscale, px2 = pos2 * xscale;
522                                 set_color(RED);
523                                 draw_box(px1,y2, px2-px1,get_h()-y2);
524                                 set_color(BLACK);
525                                 draw_line(px1,y2, px1,get_h()-1);
526                                 draw_line(px2,y2, px2,get_h()-1);
527
528                                 set_color(YELLOW);
529                                 draw_line(ex1,y1, px1,y2);
530                                 draw_line(ex2,y1, px2,y2);
531                         }
532                 }
533         }
534 }
535
536
537 AssetVIconThread::AssetVIconThread(AWindowGUI *gui, Preferences *preferences)
538  : VIconThread(gui->asset_list, preferences->vicon_size * 16/9, preferences->vicon_size,
539         4*preferences->awindow_picon_h * 16/9, 4*preferences->awindow_picon_h)
540 {
541         this->gui = gui;
542         draw_mode = ASSET_VIEW_NONE;
543         int vicon_cmodel = BC_RGB8;
544         switch( preferences->vicon_color_mode ) {
545         case VICON_COLOR_MODE_LOW:   vicon_cmodel = BC_RGB8;    break;
546         case VICON_COLOR_MODE_MED:   vicon_cmodel = BC_RGB565;  break;
547         case VICON_COLOR_MODE_HIGH:  vicon_cmodel = BC_RGB888;  break;
548         }
549         this->vicon_cmodel = vicon_cmodel;
550 }
551
552 AssetVIconThread::~AssetVIconThread()
553 {
554 }
555
556 void AssetVIconThread::set_view_popup(AssetVIcon *v, int draw_mode)
557 {
558         gui->stop_vicon_drawing();
559         int mode = !v ? ASSET_VIEW_NONE :
560                 draw_mode >= 0 ? draw_mode :
561                 this->draw_mode;
562         this->vicon = v;
563         this->draw_mode = mode;
564         gui->start_vicon_drawing();
565 }
566
567 ViewPopup *AssetVIconThread::new_view_window()
568 {
569         BC_WindowBase *parent = wdw->get_parent();
570         XineramaScreenInfo *info = parent->get_xinerama_info(-1);
571         int cx = info ? info->x_org + info->width/2 : parent->get_root_w(0)/2;
572         int cy = info ? info->y_org + info->height/2 : parent->get_root_h(0)/2;
573         int vx = viewing->get_vx(), rx = 0;
574         int vy = viewing->get_vy(), ry = 0;
575         wdw->get_root_coordinates(vx, vy, &rx, &ry);
576         rx += (rx >= cx ? -view_w : viewing->w);
577         ry += (ry >= cy ? -view_h : viewing->h);
578         AssetViewPopup *popup = new AssetViewPopup(this, draw_mode,
579                 rx, ry, view_w, view_h);
580         if( draw_mode == ASSET_VIEW_MEDIA_MAP )
581                 vicon->playing_audio = -1;
582         wdw->set_active_subwindow(popup);
583         return popup;
584 }
585
586
587 AWindowFolderItem::AWindowFolderItem()
588  : BC_ListBoxItem()
589 {
590         parent = 0;
591 }
592
593 AWindowFolderItem::AWindowFolderItem(const char *text, int color)
594  : BC_ListBoxItem(text, color)
595 {
596         parent = 0;
597 }
598
599 AWindowFolderItem::AWindowFolderItem(const char *text, BC_Pixmap *icon, int color)
600  : BC_ListBoxItem(text, icon, color)
601 {
602         parent = 0;
603 }
604
605 AssetPicon *AWindowFolderItem::get_picon()
606 {
607         AWindowFolderItem *item = this;
608         while( item->parent ) { item = (AWindowFolderItem*)item->parent; }
609         return (AssetPicon*)item;
610 }
611
612 int AWindowFolderSubItems::matches(const char *text)
613 {
614         int i = names.size();
615         while( --i >= 0 && strcmp(names[i], text) );
616         if( i < 0 ) {
617                 ArrayList<BC_ListBoxItem *> *sublist = get_sublist();
618                 i = sublist ? sublist->size() : 0;
619                 while( --i >= 0 ) {
620                         AWindowFolderSubItems *item = (AWindowFolderSubItems *)sublist->get(i);
621                         if( item->matches(text) ) break;
622                 }
623         }
624         return i >= 0 ? 1 : 0;
625 }
626
627
628 AssetPicon::AssetPicon(MWindow *mwindow,
629         AWindowGUI *gui, Indexable *indexable)
630  : AWindowFolderItem()
631 {
632         reset();
633         this->mwindow = mwindow;
634         this->gui = gui;
635         this->indexable = indexable;
636         indexable->add_user();
637         this->id = indexable->id;
638 }
639
640 AssetPicon::AssetPicon(MWindow *mwindow,
641         AWindowGUI *gui, EDL *edl)
642  : AWindowFolderItem()
643 {
644         reset();
645         this->mwindow = mwindow;
646         this->gui = gui;
647         this->edl = edl;
648         edl->add_user();
649         this->id = edl->id;
650 }
651
652 AssetPicon::AssetPicon(MWindow *mwindow,
653         AWindowGUI *gui, int folder, int persist)
654  : AWindowFolderItem(_(AWindowGUI::folder_names[folder]),
655         folder>=0 && folder<AWINDOW_FOLDERS ?
656                 gui->folder_icons[folder] : gui->folder_icon)
657 {
658         reset();
659         foldernum = folder;
660         this->mwindow = mwindow;
661         this->gui = gui;
662         persistent = persist;
663 }
664
665 AssetPicon::AssetPicon(MWindow *mwindow,
666         AWindowGUI *gui, int folder, const char *title)
667  : AWindowFolderItem(title, gui->folder_icon)
668 {
669         reset();
670         foldernum = folder;
671         this->mwindow = mwindow;
672         this->gui = gui;
673         persistent = 0;
674 }
675
676 AssetPicon::AssetPicon(MWindow *mwindow,
677         AWindowGUI *gui, PluginServer *plugin)
678  : AWindowFolderItem()
679 {
680         reset();
681         this->mwindow = mwindow;
682         this->gui = gui;
683         this->plugin = plugin;
684 }
685
686 AssetPicon::AssetPicon(MWindow *mwindow,
687         AWindowGUI *gui, Label *label)
688  : AWindowFolderItem()
689 {
690         reset();
691         this->mwindow = mwindow;
692         this->gui = gui;
693         this->label = label;
694         indexable = 0;
695         icon = 0;
696         id = 0;
697 }
698
699 AssetPicon::~AssetPicon()
700 {
701         if( vicon ) vicon->remove_user();
702         delete vicon_frame;
703         if( indexable ) indexable->remove_user();
704         if( edl ) edl->remove_user();
705         if( icon && !gui->protected_pixmap(icon) ) {
706                 delete icon;
707                 if( !plugin ) delete icon_vframe;
708         }
709 }
710
711 void AssetPicon::draw_hue_bar(VFrame *frame, double duration)
712 {
713         float t = duration > 1 ? (log(duration) / log(3600.f)) : 0;
714         if( t > 1 ) t = 1;
715         float h = 300 * t, s = 1., v = 1.;
716         float r, g, b; // duration, 0..1hr == hue red..magenta
717         HSV::hsv_to_rgb(r,g,b, h,s,v);
718         int ih = frame->get_h()/8, iw = frame->get_w();
719         int ir = r * 256;  CLAMP(ir, 0,255);
720         int ig = g * 256;  CLAMP(ig, 0,255);
721         int ib = b * 256;  CLAMP(ib, 0,255);
722         unsigned char **rows = frame->get_rows();
723         for( int y=0; y<ih; ++y ) {
724                 unsigned char *rp = rows[y];
725                 for( int x=0; x<iw; rp+=3,++x ) {
726                         rp[0] = ir;  rp[1] = ig;  rp[2] = ib;
727                 }
728         }
729 }
730
731 void AssetPicon::draw_wave(VFrame *frame, double *dp, int len,
732                 int base_color, int line_color, int x, int y, int w, int h)
733 {
734         int h1 = h-1, h2 = h/2, iy = h2;
735         int rgb_color = frame->pixel_rgb;
736         for( int ix=0,x1=0,x2=0; ix<w; ++ix,x1=x2 ) {
737                 double min = *dp, max = min;
738                 x2 = (len * (ix+1))/w;
739                 for( int i=x1; i<x2; ++i ) {
740                         double value = *dp++;
741                         if( value < min ) min = value;
742                         if( value > max ) max = value;
743                 }
744                 int ctr = (min + max) / 2;
745                 int y0 = (int)(h2 - ctr*h2);  CLAMP(y0, 0,h1);
746                 int y1 = (int)(h2 - min*h2);  CLAMP(y1, 0,h1);
747                 int y2 = (int)(h2 - max*h2);  CLAMP(y2, 0,h1);
748                 frame->pixel_rgb = line_color;
749                 frame->draw_line(ix+x,y1+y, ix+x,y2+y);
750                 frame->pixel_rgb = base_color;
751                 frame->draw_line(ix+x,iy+y, ix+x,y0+y);
752                 iy = y0;
753         }
754         frame->pixel_rgb = rgb_color;
755 }
756
757 void AssetPicon::reset()
758 {
759         plugin = 0;
760         label = 0;
761         indexable = 0;
762         edl = 0;
763         parent = 0;
764         sub_items = 0;
765         foldernum = AW_NO_FOLDER;
766         sort_key = -1;
767         icon = 0;
768         icon_vframe = 0;
769         vicon = 0;
770         vicon_frame = 0;
771         in_use = 1;
772         comments_time = 0;
773         id = 0;
774         persistent = 0;
775 }
776
777 void AssetPicon::open_render_engine(EDL *edl, int is_audio)
778 {
779         TransportCommand command;
780         command.command = is_audio ? NORMAL_FWD : CURRENT_FRAME;
781         command.get_edl()->copy_all(edl);
782         command.change_type = CHANGE_ALL;
783         command.realtime = 0;
784         render_engine = new RenderEngine(0, mwindow->preferences, 0, 0);
785         render_engine->set_vcache(mwindow->video_cache);
786         render_engine->set_acache(mwindow->audio_cache);
787         render_engine->arm_command(&command);
788 }
789 void AssetPicon::close_render_engine()
790 {
791         delete render_engine;  render_engine = 0;
792 }
793 void AssetPicon::render_video(int64_t pos, VFrame *vfrm)
794 {
795         if( !render_engine || !render_engine->vrender ) return;
796         render_engine->vrender->process_buffer(vfrm, pos, 0);
797 }
798 void AssetPicon::render_audio(int64_t pos, Samples **samples, int len)
799 {
800         if( !render_engine || !render_engine->arender ) return;
801         render_engine->arender->process_buffer(samples, len, pos);
802 }
803
804 void AssetPicon::create_objects()
805 {
806         FileSystem fs;
807         char name[BCTEXTLEN];
808         int pixmap_w, pixmap_h;
809
810         int picon_h = mwindow->preferences->awindow_picon_h;
811         pixmap_h = picon_h * BC_WindowBase::get_resources()->icon_scale;
812
813         if( indexable ) {
814                 fs.extract_name(name, indexable->path);
815                 set_text(name);
816         }
817         else if( edl ) {
818                 set_text(strcpy(name, edl->local_session->clip_title));
819                 set_text(name);
820         }
821
822         if( indexable && indexable->is_asset ) {
823                 Asset *asset = (Asset*)indexable;
824                 if( asset->video_data ) {
825                         if( mwindow->preferences->use_thumbnails ) {
826                                 gui->unlock_window();
827                                 File *file = mwindow->video_cache->check_out(asset,
828                                         mwindow->edl,
829                                         1);
830
831                                 if( file ) {
832                                         int height = asset->height > 0 ? asset->height : 1;
833                                         pixmap_w = pixmap_h * asset->width / height;
834
835                                         file->set_layer(0);
836                                         file->set_video_position(0, 0);
837
838                                         if( gui->temp_picon &&
839                                                 (gui->temp_picon->get_w() != asset->width ||
840                                                 gui->temp_picon->get_h() != asset->height) ) {
841                                                 delete gui->temp_picon;
842                                                 gui->temp_picon = 0;
843                                         }
844
845                                         if( !gui->temp_picon ) {
846                                                 gui->temp_picon = new VFrame(0, -1,
847                                                         asset->width, asset->height,
848                                                         BC_RGB888, -1);
849                                         }
850                                         { char string[BCTEXTLEN];
851                                         sprintf(string, _("Reading %s"), name);
852                                         mwindow->gui->lock_window("AssetPicon::create_objects");
853                                         mwindow->gui->show_message(string);
854                                         mwindow->gui->unlock_window(); }
855                                         file->read_frame(gui->temp_picon);
856                                         mwindow->video_cache->check_in(asset);
857
858                                         gui->lock_window("AssetPicon::create_objects 0");
859                                         icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
860                                         icon->draw_vframe(gui->temp_picon,
861                                                 0, 0, pixmap_w, pixmap_h, 0, 0);
862                                         icon_vframe = new VFrame(0,
863                                                 -1, pixmap_w, pixmap_h, BC_RGB888, -1);
864                                         icon_vframe->transfer_from(gui->temp_picon);
865                                         if( asset->folder_no == AW_MEDIA_FOLDER ||
866                                             asset->folder_no == AW_PROXY_FOLDER ) {
867 // vicon images
868                                                 double framerate = asset->get_frame_rate();
869                                                 if( !framerate ) framerate = VICON_RATE;
870                                                 int64_t frames = asset->get_video_frames();
871                                                 double secs = frames / framerate;
872                                                 if( secs > 5 ) secs = 5;
873                                                 int64_t length = secs * gui->vicon_thread->refresh_rate;
874                                                 vicon = new AssetVIcon(this, pixmap_w, pixmap_h, framerate, length);
875                                                 if( asset->audio_data && secs > 0 ) {
876                                                         gui->unlock_window();
877                                                         int audio_len = VICON_SAMPLE_RATE*secs+0.5;
878                                                         vicon->init_audio(audio_len*sizeof(vicon_audio_t));
879                                                         vicon->load_audio();
880                                                         gui->lock_window("AssetPicon::create_objects 1");
881                                                 }
882                                                 gui->vicon_thread->add_vicon(vicon);
883                                         }
884                                 }
885                                 else {
886                                         eprintf("Unable to open %s\nin asset: %s",asset->path, get_text());
887                                         gui->lock_window("AssetPicon::create_objects 2");
888                                         icon = gui->video_icon;
889                                         icon_vframe = gui->video_vframe;
890                                 }
891                         }
892                         else {
893                                 icon = gui->video_icon;
894                                 icon_vframe = gui->video_vframe;
895                         }
896                 }
897                 else
898                 if( asset->audio_data ) {
899                         if( mwindow->preferences->use_thumbnails ) {
900                                 gui->unlock_window();
901                                 File *file = mwindow->audio_cache->check_out(asset,
902                                         mwindow->edl,
903                                         1);
904                                 if( file ) {
905                                         pixmap_w = pixmap_h * 16/9;
906                                         icon_vframe = new VFrame(0,
907                                                 -1, pixmap_w, pixmap_h, BC_RGB888, -1);
908                                         icon_vframe->clear_frame();
909                                         { char string[BCTEXTLEN];
910                                         sprintf(string, _("Reading %s"), name);
911                                         mwindow->gui->lock_window("AssetPicon::create_objects 3");
912                                         mwindow->gui->show_message(string);
913                                         mwindow->gui->unlock_window(); }
914                                         int sample_rate = asset->get_sample_rate();
915                                         int channels = asset->get_audio_channels();
916                                         if( channels > 2 ) channels = 2;
917                                         int64_t audio_samples = asset->get_audio_samples();
918                                         double duration = (double)audio_samples / sample_rate;
919                                         draw_hue_bar(icon_vframe, duration);
920                                         int bfrsz = sample_rate;
921                                         Samples samples(bfrsz);
922                                         static int line_colors[2] = { GREEN, YELLOW };
923                                         static int base_colors[2] = { RED, PINK };
924                                         for( int i=channels; --i>=0; ) {
925                                                 file->set_channel(i);
926                                                 file->set_audio_position(0);
927                                                 file->read_samples(&samples, bfrsz);
928                                                 draw_wave(icon_vframe, samples.get_data(), bfrsz,
929                                                         base_colors[i], line_colors[i]);
930                                         }
931                                         mwindow->audio_cache->check_in(asset);
932                                         if( asset->folder_no == AW_MEDIA_FOLDER ) {
933                                                 double secs = duration;
934                                                 if( secs > 5 ) secs = 5;
935                                                 double refresh_rate = gui->vicon_thread->refresh_rate;
936                                                 int64_t length = secs * refresh_rate;
937                                                 vicon = new AssetVIcon(this, pixmap_w, pixmap_h, refresh_rate, length);
938                                                 int audio_len = VICON_SAMPLE_RATE*secs+0.5;
939                                                 vicon->init_audio(audio_len*sizeof(vicon_audio_t));
940                                                 vicon->load_audio();
941                                                 gui->vicon_thread->add_vicon(vicon);
942                                         }
943                                         gui->lock_window("AssetPicon::create_objects 4");
944                                         icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
945                                         icon->draw_vframe(icon_vframe,
946                                                 0, 0, pixmap_w, pixmap_h, 0, 0);
947                                 }
948                                 else {
949                                         eprintf("Unable to open %s\nin asset: %s",asset->path, get_text());
950                                         gui->lock_window("AssetPicon::create_objects 5");
951                                         icon = gui->audio_icon;
952                                         icon_vframe = gui->audio_vframe;
953                                 }
954                         }
955                         else {
956                                 icon = gui->audio_icon;
957                                 icon_vframe = gui->audio_vframe;
958                         }
959
960                 }
961                 struct stat st;
962                 comments_time = !stat(asset->path, &st) ? st.st_mtime : 0;
963         }
964         else
965         if( indexable && !indexable->is_asset ) {
966                 icon = gui->video_icon;
967                 icon_vframe = gui->video_vframe;
968         }
969         else
970         if( edl ) {
971                 if( edl->tracks->playable_video_tracks() ) {
972                         if( mwindow->preferences->use_thumbnails ) {
973                                 gui->unlock_window();
974                                 AssetVIconThread *avt = gui->vicon_thread;
975                                 char clip_icon_path[BCTEXTLEN];
976                                 char *clip_icon = edl->local_session->clip_icon;
977                                 VFrame *vframe = 0;
978                                 if( clip_icon[0] ) {
979                                         snprintf(clip_icon_path, sizeof(clip_icon_path),
980                                                 "%s/%s", File::get_config_path(), clip_icon);
981                                         vframe = VFramePng::vframe_png(clip_icon_path);
982                                 }
983                                 if( vframe &&
984                                     ( vframe->get_w() != avt->vw || vframe->get_h() != avt->vh ) ) {
985                                         delete vframe;  vframe = 0;
986                                 }
987                                 int edl_h = edl->get_h(), edl_w = edl->get_w();
988                                 int height = edl_h > 0 ? edl_h : 1;
989                                 int width = edl_w > 0 ? edl_w : 1;
990                                 int color_model = edl->session->color_model;
991                                 if( !vframe ) {
992 //printf("render clip: %s\n", name);
993                                         VFrame::get_temp(gui->temp_picon, width, height, color_model);
994                                         char string[BCTEXTLEN];
995                                         sprintf(string, _("Rendering %s"), name);
996                                         mwindow->gui->lock_window("AssetPicon::create_objects");
997                                         mwindow->gui->show_message(string);
998                                         mwindow->gui->unlock_window();
999                                         open_render_engine(edl, 0);
1000                                         render_video(0, gui->temp_picon);
1001                                         close_render_engine();
1002                                         vframe = new VFrame(avt->vw, avt->vh, BC_RGB888);
1003                                         vframe->transfer_from(gui->temp_picon);
1004                                         if( clip_icon[0] )
1005                                                 vframe->write_png(clip_icon_path);
1006                                 }
1007                                 pixmap_w = pixmap_h * width / height;
1008                                 vicon = new AssetVIcon(this, pixmap_w, pixmap_h, VICON_RATE, 1);
1009                                 vicon->add_image(vframe, avt->vw, avt->vh, avt->vicon_cmodel);
1010                                 icon_vframe = new VFrame(pixmap_w, pixmap_h, BC_RGB888);
1011                                 icon_vframe->transfer_from(vframe);
1012                                 delete vframe;
1013                                 gui->lock_window("AssetPicon::create_objects 0");
1014                                 icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
1015                                 icon->draw_vframe(icon_vframe,
1016                                         0, 0, pixmap_w, pixmap_h, 0, 0);
1017                         }
1018                         else {
1019                                 icon = gui->clip_icon;
1020                                 icon_vframe = gui->clip_vframe;
1021                         }
1022                 }
1023                 else
1024                 if( edl->tracks->playable_audio_tracks() ) {
1025                         if( mwindow->preferences->use_thumbnails ) {
1026                                 gui->unlock_window();
1027                                 char clip_icon_path[BCTEXTLEN];
1028                                 char *clip_icon = edl->local_session->clip_icon;
1029                                 if( clip_icon[0] ) {
1030                                         snprintf(clip_icon_path, sizeof(clip_icon_path),
1031                                                 "%s/%s", File::get_config_path(), clip_icon);
1032                                         icon_vframe = VFramePng::vframe_png(clip_icon_path);
1033                                 }
1034                                 if( !icon_vframe ) {
1035                                         pixmap_w = pixmap_h * 16/9;
1036                                         icon_vframe = new VFrame(0,
1037                                                 -1, pixmap_w, pixmap_h, BC_RGB888, -1);
1038                                         icon_vframe->clear_frame();
1039                                         char string[BCTEXTLEN];
1040                                         sprintf(string, _("Rendering %s"), name);
1041                                         mwindow->gui->lock_window("AssetPicon::create_objects 3");
1042                                         mwindow->gui->show_message(string);
1043                                         mwindow->gui->unlock_window();
1044                                         int sample_rate = edl->get_sample_rate();
1045                                         int channels = edl->get_audio_channels();
1046                                         if( channels > 2 ) channels = 2;
1047                                         int64_t audio_samples = edl->get_audio_samples();
1048                                         double duration = (double)audio_samples / sample_rate;
1049                                         draw_hue_bar(icon_vframe, duration);
1050                                         Samples *samples[MAX_CHANNELS];
1051                                         int bfrsz = sample_rate;
1052                                         for( int i=0; i<MAX_CHANNELS; ++i )
1053                                                 samples[i] = i<channels ? new Samples(bfrsz) : 0;
1054                                         open_render_engine(edl, 1);
1055                                         render_audio(0, samples, bfrsz);
1056                                         close_render_engine();
1057                                         gui->lock_window("AssetPicon::create_objects 4");
1058                                         static int line_colors[2] = { GREEN, YELLOW };
1059                                         static int base_colors[2] = { RED, PINK };
1060                                         for( int i=channels; --i>=0; ) {
1061                                                 draw_wave(icon_vframe, samples[i]->get_data(), bfrsz,
1062                                                         base_colors[i], line_colors[i]);
1063                                         }
1064                                         for( int i=0; i<channels; ++i ) delete samples[i];
1065                                         if( clip_icon[0] ) icon_vframe->write_png(clip_icon_path);
1066                                 }
1067                                 else {
1068                                         pixmap_w = icon_vframe->get_w();
1069                                         pixmap_h = icon_vframe->get_h();
1070                                 }
1071                                 icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
1072                                 icon->draw_vframe(icon_vframe,
1073                                         0, 0, pixmap_w, pixmap_h, 0, 0);
1074                         }
1075                         else {
1076                                 icon = gui->clip_icon;
1077                                 icon_vframe = gui->clip_vframe;
1078                         }
1079                 }
1080         }
1081         else
1082         if( plugin ) {
1083                 strcpy(name, _(plugin->title));
1084                 set_text(name);
1085                 icon_vframe = plugin->get_picon();
1086                 if( icon_vframe )
1087                         icon = gui->create_pixmap(icon_vframe);
1088                 else if( plugin->audio ) {
1089                         if( plugin->transition ) {
1090                                 icon = gui->atransition_icon;
1091                                 icon_vframe = gui->atransition_vframe;
1092                         }
1093                         else if( plugin->is_ffmpeg() ) {
1094                                 icon = gui->ff_aud_icon;
1095                                 icon_vframe = gui->ff_aud_vframe;
1096                         }
1097                         else if( plugin->is_ladspa() ) {
1098                                 icon = gui->ladspa_icon;
1099                                 icon_vframe = gui->ladspa_vframe;
1100                         }
1101                         else {
1102                                 icon = gui->aeffect_icon;
1103                                 icon_vframe = gui->aeffect_vframe;
1104                         }
1105                 }
1106                 else if( plugin->video ) {
1107                         if( plugin->transition ) {
1108                                 icon = gui->vtransition_icon;
1109                                 icon_vframe = gui->vtransition_vframe;
1110                         }
1111                         else if( plugin->is_ffmpeg() ) {
1112                                 icon = gui->ff_vid_icon;
1113                                 icon_vframe = gui->ff_vid_vframe;
1114                         }
1115                         else {
1116                                 icon = gui->veffect_icon;
1117                                 icon_vframe = gui->veffect_vframe;
1118                         }
1119                 }
1120         }
1121         else
1122         if( label ) {
1123                 Units::totext(name,
1124                               label->position,
1125                               mwindow->edl->session->time_format,
1126                               mwindow->edl->session->sample_rate,
1127                               mwindow->edl->session->frame_rate,
1128                               mwindow->edl->session->frames_per_foot);
1129                 set_text(name);
1130                 icon = gui->label_icon;
1131                 icon_vframe = gui->label_vframe;
1132         }
1133         if( !icon ) {
1134                 icon = gui->file_icon;
1135                 icon_vframe = BC_WindowBase::get_resources()->type_to_icon[ICON_UNKNOWN];
1136         }
1137         set_icon(icon);
1138         set_icon_vframe(icon_vframe);
1139 }
1140
1141 AWindowGUI::AWindowGUI(MWindow *mwindow, AWindow *awindow)
1142  : BC_Window(_(PROGRAM_NAME ": Resources"),
1143         mwindow->session->awindow_x, mwindow->session->awindow_y,
1144         mwindow->session->awindow_w, mwindow->session->awindow_h,
1145         100, 100, 1, 1, 1)
1146 {
1147         this->mwindow = mwindow;
1148         this->awindow = awindow;
1149
1150         file_vframe = 0;                file_icon = 0;
1151         folder_vframe = 0;              folder_icon = 0;
1152         audio_vframe = 0;               audio_icon = 0;
1153         video_vframe = 0;               video_icon = 0;
1154         label_vframe = 0;               label_icon = 0;
1155
1156         atransition_vframe = 0;         atransition_icon = 0;
1157         vtransition_vframe = 0;         vtransition_icon = 0;
1158         aeffect_vframe = 0;             aeffect_icon = 0;
1159         ladspa_vframe = 0;              ladspa_icon = 0;
1160         veffect_vframe = 0;             veffect_icon = 0;
1161         ff_aud_vframe = 0;              ff_aud_icon = 0;
1162         ff_vid_vframe = 0;              ff_vid_icon = 0;
1163
1164         aeffect_folder_vframe = 0;      aeffect_folder_icon = 0;
1165         atransition_folder_vframe = 0;  atransition_folder_icon = 0;
1166         clip_folder_vframe = 0;         clip_folder_icon = 0;
1167         label_folder_vframe = 0;        label_folder_icon = 0;
1168         media_folder_vframe = 0;        media_folder_icon = 0;
1169         proxy_folder_vframe = 0;        proxy_folder_icon = 0;
1170         veffect_folder_vframe = 0;      veffect_folder_icon = 0;
1171         vtransition_folder_vframe = 0;  vtransition_folder_icon = 0;
1172
1173         ladspa_vframe = 0;              ladspa_icon = 0;
1174         ff_aud_vframe = 0;              ff_aud_icon = 0;
1175         ff_vid_vframe = 0;              ff_vid_icon = 0;
1176
1177         clip_vframe = 0;                clip_icon = 0;
1178         atransition_vframe = 0;         atransition_icon = 0;
1179         vtransition_vframe = 0;         vtransition_icon = 0;
1180         aeffect_vframe = 0;             aeffect_icon = 0;
1181         veffect_vframe = 0;             veffect_icon = 0;
1182
1183         plugin_visibility = ((uint64_t)1<<(8*sizeof(uint64_t)-1))-1;
1184         asset_menu = 0;
1185         effectlist_menu = 0;
1186         assetlist_menu = 0;
1187         cliplist_menu = 0;
1188         proxylist_menu = 0;
1189         labellist_menu = 0;
1190         folderlist_menu = 0;
1191         temp_picon = 0;
1192         search_text = 0;
1193         allow_iconlisting = 1;
1194         remove_plugin = 0;
1195         vicon_thread = 0;
1196         vicon_audio = 0;
1197         vicon_drawing = 1;
1198         displayed_folder = AW_NO_FOLDER;
1199         new_folder_thread = 0;
1200         modify_folder_thread = 0;
1201         folder_lock = new Mutex("AWindowGUI::folder_lock");
1202 }
1203
1204 AWindowGUI::~AWindowGUI()
1205 {
1206         assets.remove_all_objects();
1207         folders.remove_all_objects();
1208         aeffects.remove_all_objects();
1209         veffects.remove_all_objects();
1210         atransitions.remove_all_objects();
1211         vtransitions.remove_all_objects();
1212         labellist.remove_all_objects();
1213         displayed_assets[1].remove_all_objects();
1214
1215         delete new_folder_thread;
1216         delete modify_folder_thread;
1217         delete vicon_thread;
1218         delete vicon_audio;
1219
1220         delete search_text;
1221         delete temp_picon;
1222         delete remove_plugin;
1223
1224         delete file_vframe;             delete file_icon;
1225         delete folder_vframe;           delete folder_icon;
1226         delete audio_vframe;            delete audio_icon;
1227         delete video_vframe;            delete video_icon;
1228         delete label_vframe;            delete label_icon;
1229         delete clip_vframe;             delete clip_icon;
1230         delete aeffect_folder_vframe;   delete aeffect_folder_icon;
1231         delete atransition_folder_vframe; delete atransition_folder_icon;
1232         delete veffect_folder_vframe;   delete veffect_folder_icon;
1233         delete vtransition_folder_vframe; delete vtransition_folder_icon;
1234         delete clip_folder_vframe;      delete clip_folder_icon;
1235         delete label_folder_vframe;     delete label_folder_icon;
1236         delete media_folder_vframe;     delete media_folder_icon;
1237         delete proxy_folder_vframe;     delete proxy_folder_icon;
1238         delete ladspa_vframe;           delete ladspa_icon;
1239         delete ff_aud_vframe;           delete ff_aud_icon;
1240         delete ff_vid_vframe;           delete ff_vid_icon;
1241         delete atransition_vframe;      delete atransition_icon;
1242         delete vtransition_vframe;      delete vtransition_icon;
1243         delete aeffect_vframe;          delete aeffect_icon;
1244         delete veffect_vframe;          delete veffect_icon;
1245         delete folder_lock;
1246 }
1247
1248 bool AWindowGUI::protected_pixmap(BC_Pixmap *icon)
1249 {
1250         return  icon == file_icon ||
1251                 icon == folder_icon ||
1252                 icon == audio_icon ||
1253                 icon == video_icon ||
1254                 icon == clip_icon ||
1255                 icon == label_icon ||
1256                 icon == vtransition_icon ||
1257                 icon == atransition_icon ||
1258                 icon == veffect_icon ||
1259                 icon == aeffect_icon ||
1260                 icon == ladspa_icon ||
1261                 icon == ff_aud_icon ||
1262                 icon == ff_vid_icon ||
1263                 icon == aeffect_folder_icon ||
1264                 icon == veffect_folder_icon ||
1265                 icon == atransition_folder_icon ||
1266                 icon == vtransition_folder_icon ||
1267                 icon == label_folder_icon ||
1268                 icon == clip_folder_icon ||
1269                 icon == media_folder_icon ||
1270                 icon == proxy_folder_icon;
1271 }
1272
1273 VFrame *AWindowGUI::get_picon(const char *name, const char *plugin_icons)
1274 {
1275         char png_path[BCTEXTLEN];
1276         char *pp = png_path, *ep = pp + sizeof(png_path)-1;
1277         snprintf(pp, ep-pp, "%s/picon/%s/%s.png",
1278                 File::get_plugin_path(), plugin_icons, name);
1279         if( access(png_path, R_OK) ) return 0;
1280         return VFramePng::vframe_png(png_path,0,0);
1281 }
1282
1283 VFrame *AWindowGUI::get_picon(const char *name)
1284 {
1285         VFrame *vframe = get_picon(name, mwindow->preferences->plugin_icons);
1286         if( !vframe ) {
1287                 char png_name[BCSTRLEN], *pp = png_name, *ep = pp + sizeof(png_name)-1;
1288                 snprintf(pp, ep-pp, "%s.png", name);
1289                 unsigned char *data = mwindow->theme->get_image_data(png_name);
1290                 if( data ) vframe = new VFramePng(data, 0.);
1291         }
1292         return vframe;
1293 }
1294
1295 void AWindowGUI::resource_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn, int idx)
1296 {
1297         vfrm = get_picon(fn);
1298         if( !vfrm ) vfrm = BC_WindowBase::get_resources()->type_to_icon[idx];
1299         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
1300 }
1301 void AWindowGUI::theme_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn)
1302 {
1303         vfrm = get_picon(fn);
1304         if( !vfrm ) vfrm = mwindow->theme->get_image(fn);
1305         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
1306 }
1307 void AWindowGUI::plugin_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn, unsigned char *png)
1308 {
1309         vfrm = get_picon(fn);
1310         if( !vfrm ) vfrm = new VFramePng(png);
1311         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
1312 }
1313
1314 void AWindowGUI::create_objects()
1315 {
1316         lock_window("AWindowGUI::create_objects");
1317         asset_titles[0] = C_("Title");
1318         asset_titles[1] = _("Comments");
1319
1320         set_icon(mwindow->theme->get_image("awindow_icon"));
1321
1322         resource_icon(file_vframe,   file_icon,   "film_icon",   ICON_UNKNOWN);
1323         resource_icon(folder_vframe, folder_icon, "folder_icon", ICON_FOLDER);
1324         resource_icon(audio_vframe,  audio_icon,  "audio_icon",  ICON_SOUND);
1325         resource_icon(video_vframe,  video_icon,  "video_icon",  ICON_FILM);
1326         resource_icon(label_vframe,  label_icon,  "label_icon",  ICON_LABEL);
1327
1328         theme_icon(aeffect_folder_vframe,      aeffect_folder_icon,     "aeffect_folder");
1329         theme_icon(atransition_folder_vframe,  atransition_folder_icon, "atransition_folder");
1330         theme_icon(clip_folder_vframe,         clip_folder_icon,        "clip_folder");
1331         theme_icon(label_folder_vframe,        label_folder_icon,       "label_folder");
1332         theme_icon(media_folder_vframe,        media_folder_icon,       "media_folder");
1333         theme_icon(proxy_folder_vframe,        proxy_folder_icon,       "proxy_folder");
1334         theme_icon(veffect_folder_vframe,      veffect_folder_icon,     "veffect_folder");
1335         theme_icon(vtransition_folder_vframe,  vtransition_folder_icon, "vtransition_folder");
1336
1337         folder_icons[AW_AEFFECT_FOLDER] = aeffect_folder_icon;
1338         folder_icons[AW_VEFFECT_FOLDER] = veffect_folder_icon;
1339         folder_icons[AW_ATRANSITION_FOLDER] = atransition_folder_icon;
1340         folder_icons[AW_VTRANSITION_FOLDER] = vtransition_folder_icon;
1341         folder_icons[AW_LABEL_FOLDER] = label_folder_icon;
1342         folder_icons[AW_CLIP_FOLDER] = clip_folder_icon;
1343         folder_icons[AW_MEDIA_FOLDER] = media_folder_icon;
1344         folder_icons[AW_PROXY_FOLDER] = proxy_folder_icon;
1345
1346         theme_icon(clip_vframe,        clip_icon,        "clip_icon");
1347         theme_icon(atransition_vframe, atransition_icon, "atransition_icon");
1348         theme_icon(vtransition_vframe, vtransition_icon, "vtransition_icon");
1349         theme_icon(aeffect_vframe,     aeffect_icon,     "aeffect_icon");
1350         theme_icon(veffect_vframe,     veffect_icon,     "veffect_icon");
1351
1352         plugin_icon(ladspa_vframe, ladspa_icon, "lad_picon", lad_picon_png);
1353         plugin_icon(ff_aud_vframe, ff_aud_icon, "ff_audio",  ff_audio_png);
1354         plugin_icon(ff_vid_vframe, ff_vid_icon, "ff_video",  ff_video_png);
1355         folder_lock->lock("AWindowGUI::create_objects");
1356 // Mandatory folders
1357         folders.append(new AssetPicon(mwindow, this, AW_AEFFECT_FOLDER, 1));
1358         folders.append(new AssetPicon(mwindow, this, AW_VEFFECT_FOLDER, 1));
1359         folders.append(new AssetPicon(mwindow, this, AW_ATRANSITION_FOLDER, 1));
1360         folders.append(new AssetPicon(mwindow, this, AW_VTRANSITION_FOLDER, 1));
1361         folders.append(new AssetPicon(mwindow, this, AW_LABEL_FOLDER, 1));
1362         folders.append(new AssetPicon(mwindow, this, AW_CLIP_FOLDER, 1));
1363         folders.append(new AssetPicon(mwindow, this, AW_PROXY_FOLDER, 1));
1364         folders.append(new AssetPicon(mwindow, this, AW_MEDIA_FOLDER, 1));
1365
1366         create_label_folder();
1367         folder_lock->unlock();
1368
1369         mwindow->theme->get_awindow_sizes(this);
1370         load_defaults(mwindow->defaults);
1371         new_folder_thread = new NewFolderThread(this);
1372         modify_folder_thread = new ModifyFolderThread(this);
1373
1374         int x1 = mwindow->theme->alist_x, y1 = mwindow->theme->alist_y;
1375         int w1 = mwindow->theme->alist_w, h1 = mwindow->theme->alist_h;
1376         search_text = new AWindowSearchText(mwindow, this, x1, y1+5);
1377         search_text->create_objects();
1378         int dy = search_text->get_h() + 10;
1379         y1 += dy;  h1 -= dy;
1380         add_subwindow(asset_list = new AWindowAssets(mwindow, this, x1, y1, w1, h1));
1381
1382         vicon_thread = new AssetVIconThread(this, mwindow->preferences);
1383         asset_list->update_vicon_area();
1384         vicon_thread->start();
1385         vicon_audio = new AssetVIconAudio(this);
1386
1387         add_subwindow(divider = new AWindowDivider(mwindow, this,
1388                 mwindow->theme->adivider_x, mwindow->theme->adivider_y,
1389                 mwindow->theme->adivider_w, mwindow->theme->adivider_h));
1390
1391         divider->set_cursor(HSEPARATE_CURSOR, 0, 0);
1392
1393         int fx = mwindow->theme->afolders_x, fy = mwindow->theme->afolders_y;
1394         int fw = mwindow->theme->afolders_w, fh = mwindow->theme->afolders_h;
1395         VFrame **images = mwindow->theme->get_image_set("playpatch_data");
1396         AVIconDrawing::calculate_geometry(this, images, &avicon_w, &avicon_h);
1397         add_subwindow(avicon_drawing = new AVIconDrawing(this, fw-avicon_w, fy, images));
1398         add_subwindow(add_tools = new AddTools(mwindow, this, fx, fy, _("Visibility")));
1399         add_tools->create_objects();
1400         fy += add_tools->get_h();  fh -= add_tools->get_h();
1401         add_subwindow(folder_list = new AWindowFolders(mwindow,
1402                 this, fx, fy, fw, fh));
1403         update_effects();
1404         folder_list->load_expanders();
1405
1406         //int x = mwindow->theme->abuttons_x;
1407         //int y = mwindow->theme->abuttons_y;
1408
1409         add_subwindow(asset_menu = new AssetPopup(mwindow, this));
1410         asset_menu->create_objects();
1411         add_subwindow(clip_menu = new ClipPopup(mwindow, this));
1412         clip_menu->create_objects();
1413         add_subwindow(label_menu = new LabelPopup(mwindow, this));
1414         label_menu->create_objects();
1415         add_subwindow(proxy_menu = new ProxyPopup(mwindow, this));
1416         proxy_menu->create_objects();
1417
1418         add_subwindow(effectlist_menu = new EffectListMenu(mwindow, this));
1419         effectlist_menu->create_objects();
1420         add_subwindow(assetlist_menu = new AssetListMenu(mwindow, this));
1421         assetlist_menu->create_objects();
1422         add_subwindow(cliplist_menu = new ClipListMenu(mwindow, this));
1423         cliplist_menu->create_objects();
1424         add_subwindow(labellist_menu = new LabelListMenu(mwindow, this));
1425         labellist_menu->create_objects();
1426         add_subwindow(proxylist_menu = new ProxyListMenu(mwindow, this));
1427         proxylist_menu->create_objects();
1428
1429         add_subwindow(folderlist_menu = new FolderListMenu(mwindow, this));
1430         folderlist_menu->create_objects();
1431
1432         create_custom_xatoms();
1433         unlock_window();
1434 }
1435
1436 int AWindowGUI::resize_event(int w, int h)
1437 {
1438         mwindow->session->awindow_x = get_x();
1439         mwindow->session->awindow_y = get_y();
1440         mwindow->session->awindow_w = w;
1441         mwindow->session->awindow_h = h;
1442
1443         mwindow->theme->get_awindow_sizes(this);
1444         mwindow->theme->draw_awindow_bg(this);
1445         reposition_objects();
1446
1447 //      int x = mwindow->theme->abuttons_x;
1448 //      int y = mwindow->theme->abuttons_y;
1449 //      new_bin->reposition_window(x, y);
1450 //      x += new_bin->get_w();
1451 //      delete_bin->reposition_window(x, y);
1452 //      x += delete_bin->get_w();
1453 //      rename_bin->reposition_window(x, y);
1454 //      x += rename_bin->get_w();
1455 //      delete_disk->reposition_window(x, y);
1456 //      x += delete_disk->get_w();
1457 //      delete_project->reposition_window(x, y);
1458 //      x += delete_project->get_w();
1459 //      info->reposition_window(x, y);
1460 //      x += info->get_w();
1461 //      redraw_index->reposition_window(x, y);
1462 //      x += redraw_index->get_w();
1463 //      paste->reposition_window(x, y);
1464 //      x += paste->get_w();
1465 //      append->reposition_window(x, y);
1466 //      x += append->get_w();
1467 //      view->reposition_window(x, y);
1468
1469         BC_WindowBase::resize_event(w, h);
1470         asset_list->update_vicon_area();
1471         return 1;
1472 }
1473
1474 int AWindowGUI::translation_event()
1475 {
1476         mwindow->session->awindow_x = get_x();
1477         mwindow->session->awindow_y = get_y();
1478         return 0;
1479 }
1480
1481 void AWindowGUI::reposition_objects()
1482 {
1483         int x1 = mwindow->theme->alist_x, y1 = mwindow->theme->alist_y;
1484         int w1 = mwindow->theme->alist_w, h1 = mwindow->theme->alist_h;
1485         search_text->reposition_window(x1, y1+5, w1);
1486         int dy = search_text->get_h() + 10;
1487         y1 += dy;  h1 -= dy;
1488         asset_list->reposition_window(x1, y1, w1, h1);
1489         divider->reposition_window(
1490                 mwindow->theme->adivider_x, mwindow->theme->adivider_y,
1491                 mwindow->theme->adivider_w, mwindow->theme->adivider_h);
1492         int fx = mwindow->theme->afolders_x, fy = mwindow->theme->afolders_y;
1493         int fw = mwindow->theme->afolders_w, fh = mwindow->theme->afolders_h;
1494         add_tools->resize_event(fw-avicon_w, add_tools->get_h());
1495         avicon_drawing->reposition_window(fw-avicon_w, fy);
1496         fy += add_tools->get_h();  fh -= add_tools->get_h();
1497         folder_list->reposition_window(fx, fy, fw, fh);
1498 }
1499
1500 int AWindowGUI::save_defaults(BC_Hash *defaults)
1501 {
1502         defaults->update("PLUGIN_VISIBILTY", plugin_visibility);
1503         defaults->update("VICON_DRAWING", vicon_drawing);
1504         return 0;
1505 }
1506
1507 int AWindowGUI::load_defaults(BC_Hash *defaults)
1508 {
1509         plugin_visibility = defaults->get("PLUGIN_VISIBILTY", plugin_visibility);
1510         vicon_drawing = defaults->get("VICON_DRAWING", vicon_drawing);
1511         return 0;
1512 }
1513
1514 int AWindowGUI::close_event()
1515 {
1516         hide_window();
1517         mwindow->session->show_awindow = 0;
1518         unlock_window();
1519
1520         mwindow->gui->lock_window("AWindowGUI::close_event");
1521         mwindow->gui->mainmenu->show_awindow->set_checked(0);
1522         mwindow->gui->unlock_window();
1523
1524         lock_window("AWindowGUI::close_event");
1525         save_defaults(mwindow->defaults);
1526         mwindow->save_defaults();
1527         return 1;
1528 }
1529
1530 void AWindowGUI::start_vicon_drawing()
1531 {
1532         if( !vicon_drawing || !vicon_thread->interrupted ) return;
1533         if( mwindow->edl->session->awindow_folder == AW_MEDIA_FOLDER ||
1534             mwindow->edl->session->awindow_folder == AW_PROXY_FOLDER ||
1535             mwindow->edl->session->awindow_folder == AW_CLIP_FOLDER ||
1536             mwindow->edl->session->awindow_folder >= AWINDOW_USER_FOLDERS ) {
1537                 switch( mwindow->edl->session->assetlist_format ) {
1538                 case ASSETS_ICONS:
1539                 case ASSETS_ICONS_PACKED:
1540                 case ASSETS_ICON_LIST:
1541                         asset_list->update_vicon_area();
1542                         vicon_thread->start_drawing();
1543                         break;
1544                 default:
1545                         break;
1546                 }
1547         }
1548 }
1549
1550 void AWindowGUI::stop_vicon_drawing()
1551 {
1552         if( vicon_thread->interrupted ) return;
1553         vicon_thread->stop_drawing();
1554 }
1555
1556 VFrame *AssetPicon::get_vicon_frame()
1557 {
1558         if( !vicon ) return 0;
1559         if( gui->vicon_thread->interrupted ) return 0;
1560         VFrame *frame = vicon->frame();
1561         if( !frame ) return 0;
1562         if( !vicon_frame )
1563                 vicon_frame = new VFrame(vicon->w, vicon->h, frame->get_color_model());
1564         vicon_frame->transfer_from(frame);
1565         return vicon_frame;
1566 }
1567
1568 int AWindowGUI::cycle_assetlist_format()
1569 {
1570         EDLSession *session = mwindow->edl->session;
1571         int format = ASSETS_TEXT;
1572         if( allow_iconlisting ) {
1573                 switch( session->assetlist_format ) {
1574                 case ASSETS_TEXT:
1575                         format = ASSETS_ICONS;
1576                         break;
1577                 case ASSETS_ICONS:
1578                         format = ASSETS_ICONS_PACKED;
1579                         break;
1580                 case ASSETS_ICONS_PACKED:
1581                         format = ASSETS_ICON_LIST;
1582                         break;
1583                 case ASSETS_ICON_LIST:
1584                         format = ASSETS_TEXT;
1585                         break;
1586                 }
1587         }
1588         stop_vicon_drawing();
1589         session->assetlist_format = format;
1590         asset_list->update_format(session->assetlist_format, 0);
1591         async_update_assets();
1592         start_vicon_drawing();
1593         return 1;
1594 }
1595
1596 AWindowRemovePluginGUI::
1597 AWindowRemovePluginGUI(AWindow *awindow, AWindowRemovePlugin *thread,
1598         int x, int y, PluginServer *plugin)
1599  : BC_Window(_(PROGRAM_NAME ": Remove plugin"), x,y, 500,200, 50, 50, 1, 0, 1, -1, "", 1)
1600 {
1601         this->awindow = awindow;
1602         this->thread = thread;
1603         this->plugin = plugin;
1604         VFrame *vframe = plugin->get_picon();
1605         icon = vframe ? create_pixmap(vframe) : 0;
1606         plugin_list.append(new BC_ListBoxItem(plugin->title, icon));
1607 }
1608
1609 AWindowRemovePluginGUI::
1610 ~AWindowRemovePluginGUI()
1611 {
1612         if( !awindow->gui->protected_pixmap(icon) )
1613                 delete icon;
1614         plugin_list.remove_all();
1615 }
1616
1617 void AWindowRemovePluginGUI::create_objects()
1618 {
1619         lock_window("AWindowRemovePluginGUI::create_objects");
1620         BC_Button *ok_button = new BC_OKButton(this);
1621         add_subwindow(ok_button);
1622         BC_Button *cancel_button = new BC_CancelButton(this);
1623         add_subwindow(cancel_button);
1624         int x = 10, y = 10;
1625         BC_Title *title = new BC_Title(x, y, _("remove plugin?"));
1626         add_subwindow(title);
1627         y += title->get_h() + 5;
1628         list = new BC_ListBox(x, y,
1629                 get_w() - 20, ok_button->get_y() - y - 5, LISTBOX_TEXT, &plugin_list,
1630                 0, 0, 1, 0, 0, LISTBOX_SINGLE, ICON_LEFT, 0);
1631         add_subwindow(list);
1632         show_window();
1633         unlock_window();
1634 }
1635
1636 int AWindowRemovePlugin::remove_plugin(PluginServer *plugin, ArrayList<BC_ListBoxItem*> &folder)
1637 {
1638         int ret = 0;
1639         for( int i=0; i<folder.size(); ) {
1640                 AssetPicon *picon = (AssetPicon *)folder[i];
1641                 if( picon->plugin == plugin ) {
1642                         folder.remove_object_number(i);
1643                         ++ret;
1644                         continue;
1645                 }
1646                 ++i;
1647         }
1648         return ret;
1649 }
1650
1651 void AWindowRemovePlugin::handle_close_event(int result)
1652 {
1653         if( !result ) {
1654                 printf(_("remove %s\n"), plugin->path);
1655                 awindow->gui->lock_window("AWindowRemovePlugin::handle_close_event");
1656                 ArrayList<BC_ListBoxItem*> *folder =
1657                         plugin->audio ? plugin->transition ?
1658                                 &awindow->gui->atransitions :
1659                                 &awindow->gui->aeffects :
1660                         plugin->video ?  plugin->transition ?
1661                                 &awindow->gui->vtransitions :
1662                                 &awindow->gui->veffects :
1663                         0;
1664                 if( folder ) remove_plugin(plugin, *folder);
1665                 MWindow *mwindow = awindow->mwindow;
1666                 awindow->gui->unlock_window();
1667                 char plugin_path[BCTEXTLEN];
1668                 strcpy(plugin_path, plugin->path);
1669                 mwindow->plugindb->remove(plugin);
1670                 remove(plugin_path);
1671                 char index_path[BCTEXTLEN];
1672                 mwindow->create_defaults_path(index_path, PLUGIN_FILE);
1673                 remove(index_path);
1674                 char picon_path[BCTEXTLEN];
1675                 FileSystem fs;
1676                 snprintf(picon_path, sizeof(picon_path), "%s/picon",
1677                         File::get_plugin_path());
1678                 char png_name[BCSTRLEN], png_path[BCTEXTLEN];
1679                 plugin->get_plugin_png_name(png_name);
1680                 fs.update(picon_path);
1681                 for( int i=0; i<fs.dir_list.total; ++i ) {
1682                         char *fs_path = fs.dir_list[i]->path;
1683                         if( !fs.is_dir(fs_path) ) continue;
1684                         snprintf(png_path, sizeof(picon_path), "%s/%s",
1685                                 fs_path, png_name);
1686                         remove(png_path);
1687                 }
1688                 delete plugin;  plugin = 0;
1689                 awindow->gui->async_update_assets();
1690         }
1691 }
1692
1693 AWindowRemovePlugin::
1694 AWindowRemovePlugin(AWindow *awindow, PluginServer *plugin)
1695  : BC_DialogThread()
1696 {
1697         this->awindow = awindow;
1698         this->plugin = plugin;
1699 }
1700
1701 AWindowRemovePlugin::
1702 ~AWindowRemovePlugin()
1703 {
1704         close_window();
1705 }
1706
1707 BC_Window* AWindowRemovePlugin::new_gui()
1708 {
1709         int x = awindow->gui->get_abs_cursor_x(0);
1710         int y = awindow->gui->get_abs_cursor_y(0);
1711         AWindowRemovePluginGUI *gui = new AWindowRemovePluginGUI(awindow, this, x, y, plugin);
1712         gui->create_objects();
1713         return gui;
1714 }
1715
1716 int AWindowGUI::keypress_event()
1717 {
1718         switch( get_keypress() ) {
1719         case 'w': case 'W':
1720                 if( ctrl_down() ) {
1721                         close_event();
1722                         return 1;
1723                 }
1724                 break;
1725         case 'o':
1726                 if( !ctrl_down() && !shift_down() ) {
1727                         assetlist_menu->load_file->handle_event();
1728                         return 1;
1729                 }
1730                 break;
1731         case 'v':
1732                 return cycle_assetlist_format();
1733         case DELETE:
1734                 if( shift_down() && ctrl_down() ) {
1735                         PluginServer* plugin = selected_plugin();
1736                         if( !plugin ) break;
1737                         remove_plugin = new AWindowRemovePlugin(awindow, plugin);
1738                         unlock_window();
1739                         remove_plugin->start();
1740                         lock_window("AWindowGUI::keypress_event 1");
1741                         return 1;
1742                 }
1743                 collect_assets();
1744                 if( shift_down() ) {
1745                         mwindow->awindow->asset_remove->start();
1746                         return 1;
1747                 }
1748                 unlock_window();
1749                 mwindow->remove_assets_from_project(1, 1,
1750                         mwindow->session->drag_assets,
1751                         mwindow->session->drag_clips);
1752                 lock_window("AWindowGUI::keypress_event 2");
1753                 return 1;
1754         case KEY_F1:
1755         case KEY_F2:
1756         case KEY_F3:
1757         case KEY_F4:
1758                 if( shift_down() && ctrl_down() ) {
1759                         resend_event(mwindow->gui);
1760                         return 1;
1761                 }
1762                 break;
1763         }
1764         return 0;
1765 }
1766
1767
1768
1769 int AWindowGUI::create_custom_xatoms()
1770 {
1771         UpdateAssetsXAtom = create_xatom("CWINDOWGUI_UPDATE_ASSETS");
1772         return 0;
1773 }
1774 int AWindowGUI::receive_custom_xatoms(xatom_event *event)
1775 {
1776         if( event->message_type == UpdateAssetsXAtom ) {
1777                 update_assets();
1778                 return 1;
1779         }
1780         return 0;
1781 }
1782
1783 void AWindowGUI::async_update_assets()
1784 {
1785         xatom_event event;
1786         event.message_type = UpdateAssetsXAtom;
1787         send_custom_xatom(&event);
1788 }
1789
1790
1791 void AWindowGUI::update_folder_list()
1792 {
1793         for( int i = 0; i < folders.total; i++ ) {
1794                 AssetPicon *picon = (AssetPicon*)folders.values[i];
1795                 picon->in_use = 0;
1796         }
1797
1798 // Search assets for folders
1799         for( int i = 0; i < mwindow->edl->folders.total; i++ ) {
1800                 BinFolder *bin_folder = mwindow->edl->folders[i];
1801                 int exists = 0;
1802
1803                 for( int j = 0; j < folders.total; j++ ) {
1804                         AssetPicon *picon = (AssetPicon*)folders[j];
1805                         if( !strcasecmp(picon->get_text(), bin_folder->title) ) {
1806                                 exists = 1;
1807                                 picon->in_use = 1;
1808                                 break;
1809                         }
1810                 }
1811
1812                 if( !exists ) {
1813                         const char *title = bin_folder->title;
1814                         int folder = bin_folder->awindow_folder;
1815                         AssetPicon *picon = new AssetPicon(mwindow, this, folder, title);
1816                         picon->create_objects();
1817                         folders.append(picon);
1818                 }
1819         }
1820
1821 // Delete unused non-persistent folders
1822         int do_autoplace = 0;
1823         for( int i=folders.total; --i>=0; ) {
1824                 AssetPicon *picon = (AssetPicon*)folders.values[i];
1825                 if( !picon->in_use && !picon->persistent ) {
1826                         delete picon;
1827                         folders.remove_number(i);
1828                         do_autoplace = 1;
1829                 }
1830         }
1831         if( do_autoplace )
1832                 folder_list->set_autoplacement(&folders, 0, 1);
1833 }
1834
1835 void AWindowGUI::create_persistent_folder(ArrayList<BC_ListBoxItem*> *output,
1836         int do_audio, int do_video, int is_realtime, int is_transition)
1837 {
1838         ArrayList<PluginServer*> plugin_list;
1839 // Get pointers to plugindb entries
1840         mwindow->search_plugindb(do_audio, do_video, is_realtime, is_transition,
1841                         0, plugin_list);
1842
1843         for( int i = 0; i < plugin_list.total; i++ ) {
1844                 PluginServer *server = plugin_list.values[i];
1845                 int visible = plugin_visibility & (1<<server->dir_idx);
1846                 if( !visible ) continue;
1847 // Create new listitem
1848                 AssetPicon *picon = new AssetPicon(mwindow, this, server);
1849                 picon->create_objects();
1850                 output->append(picon);
1851         }
1852 }
1853
1854 void AWindowGUI::create_label_folder()
1855 {
1856         Label *current;
1857         for( current = mwindow->edl->labels->first; current; current = NEXT ) {
1858                 AssetPicon *picon = new AssetPicon(mwindow, this, current);
1859                 picon->create_objects();
1860                 labellist.append(picon);
1861         }
1862 }
1863
1864
1865 void AWindowGUI::update_asset_list()
1866 {
1867         ArrayList<AssetPicon *> new_assets;
1868         for( int i = 0; i < assets.total; i++ ) {
1869                 AssetPicon *picon = (AssetPicon*)assets.values[i];
1870                 picon->in_use = 0;
1871         }
1872
1873         mwindow->gui->lock_window("AWindowGUI::update_asset_list");
1874 // Synchronize EDL clips
1875         for( int i=0; i<mwindow->edl->clips.size(); ++i ) {
1876                 int exists = 0;
1877
1878 // Look for clip in existing listitems
1879                 for( int j = 0; j < assets.total && !exists; j++ ) {
1880                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1881
1882                         if( picon->id == mwindow->edl->clips[i]->id ) {
1883                                 picon->edl = mwindow->edl->clips[i];
1884                                 picon->set_text(mwindow->edl->clips[i]->local_session->clip_title);
1885                                 exists = 1;
1886                                 picon->in_use = 1;
1887                         }
1888                 }
1889
1890 // Create new listitem
1891                 if( !exists ) {
1892                         AssetPicon *picon = new AssetPicon(mwindow,
1893                                 this, mwindow->edl->clips[i]);
1894                         new_assets.append(picon);
1895                 }
1896         }
1897
1898 // Synchronize EDL assets
1899         for( Asset *current=mwindow->edl->assets->first; current; current=NEXT ) {
1900                 int exists = 0;
1901
1902 // Look for asset in existing listitems
1903                 for( int j = 0; j < assets.total && !exists; j++ ) {
1904                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1905
1906                         if( picon->id == current->id ) {
1907                                 picon->indexable = current;
1908                                 picon->in_use = 1;
1909                                 exists = 1;
1910                         }
1911                 }
1912
1913 // Create new listitem
1914                 if( !exists ) {
1915                         AssetPicon *picon = new AssetPicon(mwindow,
1916                                 this, current);
1917                         new_assets.append(picon);
1918                 }
1919         }
1920
1921 // Synchronize nested EDLs
1922         for( int i=0; i<mwindow->edl->nested_edls.size(); ++i ) {
1923                 int exists = 0;
1924                 EDL *nested_edl = mwindow->edl->nested_edls[i];
1925
1926 // Look for asset in existing listitems
1927                 for( int j=0; j<assets.total && !exists; ++j ) {
1928                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1929
1930                         if( picon->id == nested_edl->id ) {
1931                                 picon->indexable = nested_edl;
1932                                 picon->in_use = 1;
1933                                 exists = 1;
1934                         }
1935                 }
1936
1937 // Create new listitem
1938                 if( !exists ) {
1939                         AssetPicon *picon = new AssetPicon(mwindow,
1940                                 this, (Indexable*)nested_edl);
1941                         new_assets.append(picon);
1942                 }
1943         }
1944         mwindow->gui->unlock_window();
1945
1946         for( int i=0; i<new_assets.size(); ++i ) {
1947                 AssetPicon *picon = new_assets[i];
1948                 picon->create_objects();
1949                 if( picon->indexable )
1950                         picon->foldernum = AW_MEDIA_FOLDER;
1951                 else if( picon->edl )
1952                         picon->foldernum = AW_CLIP_FOLDER;
1953                 assets.append(picon);
1954         }
1955
1956         mwindow->gui->lock_window();
1957         mwindow->gui->default_message();
1958         mwindow->gui->unlock_window();
1959
1960         for( int i = assets.size() - 1; i >= 0; i-- ) {
1961                 AssetPicon *picon = (AssetPicon*)assets.get(i);
1962                 if( !picon->in_use ) {
1963                         delete picon;
1964                         assets.remove_number(i);
1965                         continue;
1966                 }
1967                 if( picon->indexable && picon->indexable->is_asset ) {
1968                         struct stat st;
1969                         picon->comments_time = !stat(picon->indexable->path, &st) ?
1970                                 st.st_mtime : 0;
1971                 }
1972         }
1973 }
1974
1975 void AWindowGUI::update_picon(Indexable *indexable)
1976 {
1977         VIcon *vicon = 0;
1978         for( int i = 0; i < assets.total; i++ ) {
1979                 AssetPicon *picon = (AssetPicon*)assets.values[i];
1980                 if( picon->indexable == indexable ||
1981                     picon->edl == (EDL *)indexable ) {
1982                         char name[BCTEXTLEN];
1983                         FileSystem fs;
1984                         fs.extract_name(name, indexable->path);
1985                         picon->set_text(name);
1986                         vicon = picon->vicon;
1987                         break;
1988                 }
1989         }
1990         if( vicon ) {
1991                 stop_vicon_drawing();
1992                 vicon->clear_images();
1993                 vicon->reset(indexable->get_frame_rate());
1994                 start_vicon_drawing();
1995         }
1996 }
1997
1998 void AWindowGUI::sort_assets()
1999 {
2000         folder_lock->lock("AWindowGUI::sort_assets");
2001         switch( mwindow->edl->session->awindow_folder ) {
2002         case AW_AEFFECT_FOLDER:
2003                 sort_picons(&aeffects);
2004                 break;
2005         case AW_VEFFECT_FOLDER:
2006                 sort_picons(&veffects);
2007                 break;
2008         case AW_ATRANSITION_FOLDER:
2009                 sort_picons(&atransitions);
2010                 break;
2011         case AW_VTRANSITION_FOLDER:
2012                 sort_picons(&vtransitions);
2013                 break;
2014         case AW_LABEL_FOLDER:
2015                 sort_picons(&labellist);
2016                 break;
2017         default:
2018                 sort_picons(&assets);
2019                 break;
2020         }
2021 // reset xyposition
2022         asset_list->update_format(asset_list->get_format(), 0);
2023         folder_lock->unlock();
2024         update_assets();
2025 }
2026
2027 void AWindowGUI::sort_folders()
2028 {
2029         folder_lock->lock("AWindowGUI::update_assets");
2030 //      folder_list->collapse_recursive(&folders, 0);
2031         folder_list->set_autoplacement(&folders, 0, 1);
2032         sort_picons(&folders);
2033         folder_list->update_format(folder_list->get_format(), 0);
2034         folder_lock->unlock();
2035         update_assets();
2036 }
2037
2038 EDL *AWindowGUI::collect_proxy(Indexable *indexable)
2039 {
2040         Asset *proxy_asset = (Asset *)indexable;
2041         char path[BCTEXTLEN];
2042         int proxy_scale = mwindow->edl->session->proxy_scale;
2043         ProxyRender::from_proxy_path(path, proxy_asset, proxy_scale);
2044         Asset *unproxy_asset = mwindow->edl->assets->get_asset(path);
2045         if( !unproxy_asset || !unproxy_asset->layers ) return 0;
2046 // make a clip from proxy video tracks and unproxy audio tracks
2047         EDL *proxy_edl = new EDL(mwindow->edl);
2048         proxy_edl->create_objects();
2049         proxy_edl->set_path(proxy_asset->path);
2050         FileSystem fs;  fs.extract_name(path, proxy_asset->path);
2051         strcpy(proxy_edl->local_session->clip_title, path);
2052         strcpy(proxy_edl->local_session->clip_notes, _("Proxy clip"));
2053         proxy_edl->session->video_tracks = proxy_asset->layers;
2054         proxy_edl->session->audio_tracks = unproxy_asset->channels;
2055         proxy_edl->create_default_tracks();
2056         double length = proxy_asset->frame_rate > 0 ?
2057                 ( proxy_asset->video_length >= 0 ?
2058                         ( proxy_asset->video_length / proxy_asset->frame_rate ) :
2059                         ( proxy_edl->session->si_useduration ?
2060                                 proxy_edl->session->si_duration :
2061                                 1.0 / proxy_asset->frame_rate ) ) :
2062                 1.0 / proxy_edl->session->frame_rate;
2063         Track *current = proxy_edl->tracks->first;
2064         for( int vtrack=0; current; current=NEXT ) {
2065                 if( current->data_type != TRACK_VIDEO ) continue;
2066                 current->insert_asset(proxy_asset, 0, length, 0, vtrack++);
2067         }
2068         length = (double)unproxy_asset->audio_length / unproxy_asset->sample_rate;
2069         current = proxy_edl->tracks->first;
2070         for( int atrack=0; current; current=NEXT ) {
2071                 if( current->data_type != TRACK_AUDIO ) continue;
2072                 current->insert_asset(unproxy_asset, 0, length, 0, atrack++);
2073         }
2074         proxy_edl->folder_no = AW_PROXY_FOLDER;
2075         return proxy_edl;
2076 }
2077
2078
2079 void AWindowGUI::collect_assets(int proxy)
2080 {
2081         mwindow->session->drag_assets->remove_all();
2082         mwindow->session->drag_clips->remove_all();
2083         int i = 0;  AssetPicon *result;
2084         while( (result = (AssetPicon*)asset_list->get_selection(0, i++)) != 0 ) {
2085                 Indexable *indexable = result->indexable;
2086                 if( proxy && indexable && indexable->is_asset &&
2087                     indexable->folder_no == AW_PROXY_FOLDER ) {
2088                         EDL *drag_edl = collect_proxy(indexable);
2089                         if( drag_edl ) mwindow->session->drag_clips->append(drag_edl);
2090                         continue;
2091                 }
2092                 if( indexable ) {
2093                         mwindow->session->drag_assets->append(indexable);
2094                         continue;
2095                 }
2096                 if( result->edl ) {
2097                         mwindow->session->drag_clips->append(result->edl);
2098                         continue;
2099                 }
2100         }
2101 }
2102
2103 void AWindowGUI::copy_picons(AssetPicon *picon, ArrayList<BC_ListBoxItem*> *src)
2104 {
2105 // Remove current pointers
2106         ArrayList<BC_ListBoxItem*> *dst = displayed_assets;
2107         dst[0].remove_all();
2108         dst[1].remove_all_objects();
2109
2110         AWindowFolderSubItems *sub_items = picon ? picon->sub_items : 0;
2111         int folder = mwindow->edl->session->awindow_folder;
2112         BinFolder *bin_folder = folder < AWINDOW_USER_FOLDERS ? 0 :
2113                 mwindow->edl->get_folder(folder);
2114
2115 // Create new pointers
2116         for( int i = 0; i < src->total; i++ ) {
2117                 int visible = folder >= AW_CLIP_FOLDER ? 0 : 1;
2118                 picon = (AssetPicon*)src->values[i];
2119                 picon->sort_key = -1;
2120                 if( !visible && bin_folder ) {
2121                         Indexable *idxbl = bin_folder->is_clips ? (Indexable *)picon->edl :
2122                             picon->indexable ? picon->indexable :
2123                             picon->edl ? picon->edl->get_proxy_asset() : 0;
2124                         if( idxbl ) {
2125                                 picon->sort_key = mwindow->edl->folders.matches_indexable(folder, idxbl);
2126                                 if( picon->sort_key < 0 ) continue;
2127                                 visible = 1;
2128                         }
2129                 }
2130                 if( !visible && picon->indexable && picon->indexable->folder_no == folder )
2131                         visible = 1;
2132                 if( !visible && picon->edl && picon->edl->folder_no == folder )
2133                         visible = 1;
2134                 if( visible && sub_items ) {
2135                         if( !sub_items->matches(picon->get_text()) )
2136                                 visible = 0;
2137                 }
2138                 if( visible ) {
2139                         const char *text = search_text->get_text();
2140                         if( text && text[0] )
2141                                 visible = bstrcasestr(picon->get_text(), text) ? 1 : 0;
2142                 }
2143                 if( visible && picon->vicon && picon->vicon->hidden )
2144                         picon->vicon->hidden = 0;
2145                 if( visible ) {
2146                         BC_ListBoxItem *item2, *item1;
2147                         dst[0].append(item1 = picon);
2148                         if( picon->edl )
2149                                 dst[1].append(item2 = new BC_ListBoxItem(picon->edl->local_session->clip_notes));
2150                         else
2151                         if( picon->label )
2152                                 dst[1].append(item2 = new BC_ListBoxItem(picon->label->textstr));
2153                         else if( picon->comments_time ) {
2154                                 char date_time[BCSTRLEN];
2155                                 struct tm stm;  localtime_r(&picon->comments_time, &stm);
2156                                 sprintf(date_time,"%04d.%02d.%02d %02d:%02d:%02d",
2157                                          stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
2158                                          stm.tm_hour, stm.tm_min, stm.tm_sec);
2159                                 dst[1].append(item2 = new BC_ListBoxItem(date_time));
2160                         }
2161                         else
2162                                 dst[1].append(item2 = new BC_ListBoxItem(""));
2163                         item1->set_autoplace_text(1);  item1->set_autoplace_icon(1);
2164                         item2->set_autoplace_text(1);  item2->set_autoplace_icon(1);
2165                 }
2166         }
2167 }
2168
2169 void AWindowGUI::sort_picons(ArrayList<BC_ListBoxItem*> *src)
2170 {
2171         int done = 0, changed = 0;
2172         while( !done ) {
2173                 done = 1;
2174                 for( int i=0; i<src->total-1; ++i ) {
2175                         AssetPicon *item1 = (AssetPicon *)src->values[i];
2176                         AssetPicon *item2 = (AssetPicon *)src->values[i + 1];
2177                         double v = item2->sort_key - item1->sort_key;
2178                         if( v > 0 ) continue;
2179                         if( v == 0 ) {
2180                                 const char *cp1 = item1->get_text();
2181                                 const char *bp1 = strrchr(cp1, '/');
2182                                 if( bp1 ) cp1 = bp1 + 1;
2183                                 const char *cp2 = item2->get_text();
2184                                 const char *bp2 = strrchr(cp2, '/');
2185                                 if( bp2 ) cp2 = bp2 + 1;
2186                                 if( strcmp(cp2, cp1) >= 0 ) continue;
2187                         }
2188                         src->values[i + 1] = item1;
2189                         src->values[i] = item2;
2190                         done = 0;  changed = 1;
2191                 }
2192         }
2193         if( changed ) {
2194                 for( int i=0; i<src->total; ++i ) {
2195                         AssetPicon *item = (AssetPicon *)src->values[i];
2196                         item->set_autoplace_icon(1);
2197                         item->set_autoplace_text(1);
2198                 }
2199         }
2200 }
2201
2202 void AWindowGUI::filter_displayed_assets()
2203 {
2204         //allow_iconlisting = 1;
2205         asset_titles[0] = C_("Title");
2206         asset_titles[1] = _("Comments");
2207         AssetPicon *picon = 0;
2208         int selected_folder = mwindow->edl->session->awindow_folder;
2209         // Ensure the current folder icon is highlighted
2210         for( int i = 0; i < folders.total; i++ ) {
2211                 AssetPicon *folder_item = (AssetPicon *)folders.values[i];
2212                 int selected = folder_item->foldernum == selected_folder ? 1 : 0;
2213                 folder_item->set_selected(selected);
2214                 if( selected ) picon = folder_item;
2215         }
2216
2217         ArrayList<BC_ListBoxItem*> *src = &assets;
2218         switch( selected_folder ) {
2219         case AW_AEFFECT_FOLDER:  src = &aeffects;  break;
2220         case AW_VEFFECT_FOLDER:  src = &veffects;  break;
2221         case AW_ATRANSITION_FOLDER:  src = &atransitions;  break;
2222         case AW_VTRANSITION_FOLDER:  src = &vtransitions;  break;
2223         case AW_LABEL_FOLDER:  src = &labellist;
2224                 asset_titles[0] = _("Time Stamps");
2225                 asset_titles[1] = C_("Title");
2226                 //allow_iconlisting = 0;
2227                 break;
2228         }
2229         copy_picons(picon, src);
2230 }
2231
2232
2233 void AWindowGUI::update_assets()
2234 {
2235         stop_vicon_drawing();
2236         folder_lock->lock("AWindowGUI::update_assets");
2237         update_folder_list();
2238         update_asset_list();
2239         labellist.remove_all_objects();
2240         create_label_folder();
2241
2242         if( displayed_folder != mwindow->edl->session->awindow_folder )
2243                 search_text->clear();
2244         vicon_thread->hide_vicons();
2245         filter_displayed_assets();
2246         folder_lock->unlock();
2247
2248         if( mwindow->edl->session->folderlist_format != folder_list->get_format() ) {
2249                 folder_list->update_format(mwindow->edl->session->folderlist_format, 0);
2250         }
2251         int folder_xposition = folder_list->get_xposition();
2252         int folder_yposition = folder_list->get_yposition();
2253         folder_list->update(&folders, 0, 0, 1, folder_xposition, folder_yposition, -1);
2254
2255         if( mwindow->edl->session->assetlist_format != asset_list->get_format() ) {
2256                 asset_list->update_format(mwindow->edl->session->assetlist_format, 0);
2257         }
2258         int asset_xposition = asset_list->get_xposition();
2259         int asset_yposition = asset_list->get_yposition();
2260         if( displayed_folder != mwindow->edl->session->awindow_folder ) {
2261                 displayed_folder = mwindow->edl->session->awindow_folder;
2262                 asset_xposition = asset_yposition = 0;
2263         }
2264         asset_list->update(displayed_assets, asset_titles,
2265                 mwindow->edl->session->asset_columns, ASSET_COLUMNS,
2266                 asset_xposition, asset_yposition, -1, 0);
2267         asset_list->center_selection();
2268
2269         flush();
2270         start_vicon_drawing();
2271         return;
2272 }
2273
2274 void AWindowGUI::update_effects()
2275 {
2276         aeffects.remove_all_objects();
2277         create_persistent_folder(&aeffects, 1, 0, 1, 0);
2278         veffects.remove_all_objects();
2279         create_persistent_folder(&veffects, 0, 1, 1, 0);
2280         atransitions.remove_all_objects();
2281         create_persistent_folder(&atransitions, 1, 0, 0, 1);
2282         vtransitions.remove_all_objects();
2283         create_persistent_folder(&vtransitions, 0, 1, 0, 1);
2284 }
2285
2286 int AWindowGUI::drag_motion()
2287 {
2288         if( get_hidden() ) return 0;
2289
2290         int result = 0;
2291         return result;
2292 }
2293
2294 int AWindowGUI::drag_stop()
2295 {
2296         if( get_hidden() ) return 0;
2297         return 0;
2298 }
2299
2300 Indexable* AWindowGUI::selected_asset()
2301 {
2302         AssetPicon *picon = (AssetPicon*)asset_list->get_selection(0, 0);
2303         return picon ? picon->indexable : 0;
2304 }
2305
2306 PluginServer* AWindowGUI::selected_plugin()
2307 {
2308         AssetPicon *picon = (AssetPicon*)asset_list->get_selection(0, 0);
2309         return picon ? picon->plugin : 0;
2310 }
2311
2312 AssetPicon* AWindowGUI::selected_folder()
2313 {
2314         AssetPicon *picon = (AssetPicon*)folder_list->get_selection(0, 0);
2315         return picon;
2316 }
2317
2318
2319
2320
2321
2322
2323
2324
2325 AWindowDivider::AWindowDivider(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
2326  : BC_SubWindow(x, y, w, h)
2327 {
2328         this->mwindow = mwindow;
2329         this->gui = gui;
2330 }
2331 AWindowDivider::~AWindowDivider()
2332 {
2333 }
2334
2335 int AWindowDivider::button_press_event()
2336 {
2337         if( is_event_win() && cursor_inside() ) {
2338                 mwindow->session->current_operation = DRAG_PARTITION;
2339                 return 1;
2340         }
2341         return 0;
2342 }
2343
2344 int AWindowDivider::cursor_motion_event()
2345 {
2346         if( mwindow->session->current_operation == DRAG_PARTITION ) {
2347                 int wmin = 25;
2348                 int wmax = mwindow->session->awindow_w - mwindow->theme->adivider_w - wmin;
2349                 int fw = gui->get_relative_cursor_x();
2350                 if( fw > wmax ) fw = wmax;
2351                 if( fw < wmin ) fw = wmin;
2352                 mwindow->session->afolders_w = fw;
2353                 mwindow->theme->get_awindow_sizes(gui);
2354                 gui->reposition_objects();
2355                 gui->flush();
2356         }
2357         return 0;
2358 }
2359
2360 int AWindowDivider::button_release_event()
2361 {
2362         if( mwindow->session->current_operation == DRAG_PARTITION ) {
2363                 mwindow->session->current_operation = NO_OPERATION;
2364                 return 1;
2365         }
2366         return 0;
2367 }
2368
2369
2370
2371
2372
2373
2374 AWindowFolders::AWindowFolders(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
2375  : BC_ListBox(x, y, w, h,
2376                 mwindow->edl->session->folderlist_format == FOLDERS_ICONS ?
2377                         LISTBOX_ICONS : LISTBOX_TEXT,
2378                 &gui->folders,    // Each column has an ArrayList of BC_ListBoxItems.
2379                 0,                // Titles for columns.  Set to 0 for no titles
2380                 0,                // width of each column
2381                 1,                // Total columns.
2382                 0,                // Pixel of top of window.
2383                 0,                // If this listbox is a popup window
2384                 LISTBOX_SINGLE,   // Select one item or multiple items
2385                 ICON_TOP,         // Position of icon relative to text of each item
2386                 1)                // Allow drags
2387 {
2388         this->mwindow = mwindow;
2389         this->gui = gui;
2390         set_drag_scroll(0);
2391         last_item0 = 0;
2392         last_item1 = 0;
2393 }
2394
2395 AWindowFolders::~AWindowFolders()
2396 {
2397 }
2398
2399 int AWindowFolders::selection_changed()
2400 {
2401         AWindowFolderItem *item0 = (AWindowFolderItem*)get_selection(0, 0);
2402         AWindowFolderItem *item1 = (AWindowFolderItem*)get_selection(0, 1);
2403 // prefer expanded entry
2404         AWindowFolderItem *item = item1 ? item1 : item0;
2405         if( item0 && item1 && last_item0 == item0 && last_item1 == item1 ) {
2406                 item1->set_selected(0);
2407                 item1 = 0;
2408                 item = item0;
2409         }
2410         last_item0 = item0;
2411         last_item1 = item1;
2412         if( item ) {
2413                 AssetPicon *picon = item->get_picon();
2414                 picon->sub_items = (AWindowFolderSubItems*)(!item->parent ? 0 : item);
2415
2416                 gui->stop_vicon_drawing();
2417
2418                 if( get_button_down() && get_buttonpress() == RIGHT_BUTTON ) {
2419                         gui->folderlist_menu->update_titles();
2420                         gui->folderlist_menu->activate_menu();
2421                 }
2422
2423                 mwindow->edl->session->awindow_folder = picon->foldernum;
2424                 gui->asset_list->draw_background();
2425                 gui->async_update_assets();
2426
2427                 gui->start_vicon_drawing();
2428         }
2429         return 1;
2430 }
2431
2432 int AWindowFolders::button_press_event()
2433 {
2434         int result = BC_ListBox::button_press_event();
2435
2436         if( !result ) {
2437                 if( get_buttonpress() == RIGHT_BUTTON &&
2438                     is_event_win() && cursor_inside() ) {
2439                         gui->folderlist_menu->update_titles();
2440                         gui->folderlist_menu->activate_menu();
2441                         result = 1;
2442                 }
2443         }
2444
2445         return result;
2446 }
2447
2448 int AWindowFolders::drag_stop()
2449 {
2450         int result = 0;
2451         if( get_hidden() ) return 0;
2452         if( mwindow->session->current_operation == DRAG_ASSET &&
2453             gui->folder_list->cursor_above() ) { // check user folder
2454                 int item_no = gui->folder_list->get_cursor_data_item_no();
2455                 AssetPicon *picon = (AssetPicon *)(item_no < 0 ? 0 : gui->folders[item_no]);
2456                 if( picon && picon->foldernum >= AWINDOW_USER_FOLDERS ) {
2457                         BinFolder *folder = mwindow->edl->get_folder(picon->foldernum);
2458                         ArrayList<Indexable *> *drags = folder->is_clips ?
2459                                 ((ArrayList<Indexable *> *)mwindow->session->drag_clips) :
2460                                 ((ArrayList<Indexable *> *)mwindow->session->drag_assets);
2461                         if( folder && drags && !folder->add_patterns(drags, shift_down()) )
2462                                 flicker(1,30);
2463                         mwindow->session->current_operation = ::NO_OPERATION;
2464                         result = 1;
2465                 }
2466         }
2467         return result;
2468 }
2469
2470 AWindowFolderSubItems::AWindowFolderSubItems(AWindowFolderItem *parent, const char *text)
2471  : AWindowFolderItem(text)
2472 {
2473         this->parent = parent;
2474 }
2475
2476 int AWindowFolders::load_expanders()
2477 {
2478         char expanders_path[BCTEXTLEN];
2479         mwindow->create_defaults_path(expanders_path, EXPANDERS_FILE);
2480         FILE *fp = fopen(expanders_path, "r");
2481         if( !fp ) {
2482                 snprintf(expanders_path, sizeof(expanders_path), "%s/%s",
2483                         File::get_cindat_path(), EXPANDERS_FILE);
2484                 fp = fopen(expanders_path, "r");
2485         }
2486
2487         if( !fp ) return 1;
2488         const char tab = '\t';
2489         char line[BCTEXTLEN];   line[0] = 0;
2490         AWindowFolderItem *item = 0, *parent;
2491         AWindowFolderSubItems *sub_items = 0;
2492         int k = 0;
2493         while( fgets(line,sizeof(line),fp) ) {
2494                 if( line[0] == '#' ) continue;
2495                 int i = strlen(line);
2496                 if( i > 0 && line[i-1] == '\n' ) line[--i] = 0;
2497                 if( i == 0 ) continue;
2498                 i = 0;
2499                 for( char *cp=line; *cp==tab; ++cp ) ++i;
2500                 if( i == 0 ) {
2501                         int i = gui->folders.size();
2502                         while( --i >= 0 ) {
2503                                 AssetPicon *folder = (AssetPicon *)gui->folders[i];
2504                                 if( !strcmp(folder->get_text(),_(line)) ) break;
2505                         }
2506                         item = (AWindowFolderItem*)(i >= 0 ? gui->folders[i] : 0);
2507                         sub_items = 0;
2508                         k = 0;
2509                         continue;
2510                 }
2511                 if( i > k+1 ) continue;
2512                 if( i == k+1 ) {
2513                         if( line[i] != '-' && sub_items ) {
2514                                 sub_items->names.append(cstrdup(_(&line[i])));
2515                                 continue;
2516                         }
2517                         parent = item;
2518                         k = i;
2519                 }
2520                 else {
2521                         while( i < k ) {
2522                                 item = item->parent;
2523                                 --k;
2524                         }
2525                         parent = item->parent;
2526                 }
2527                 ArrayList<BC_ListBoxItem*> *sublist = parent->get_sublist();
2528                 if( !sublist ) sublist = parent->new_sublist(1);
2529                 sub_items = new AWindowFolderSubItems(parent, &line[i]);
2530                 sublist->append(item = sub_items);
2531         }
2532         fclose(fp);
2533         return 0;
2534 }
2535
2536
2537 AWindowAssets::AWindowAssets(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
2538  : BC_ListBox(x, y, w, h, !gui->allow_iconlisting ? LISTBOX_TEXT :
2539                 mwindow->edl->session->assetlist_format == ASSETS_ICONS ? LISTBOX_ICONS :
2540                 mwindow->edl->session->assetlist_format == ASSETS_ICONS_PACKED ? LISTBOX_ICONS_PACKED :
2541                 mwindow->edl->session->assetlist_format == ASSETS_ICON_LIST ? LISTBOX_ICON_LIST :
2542                         LISTBOX_TEXT,
2543                 &gui->assets,     // Each column has an ArrayList of BC_ListBoxItems.
2544                 gui->asset_titles,// Titles for columns.  Set to 0 for no titles
2545                 mwindow->edl->session->asset_columns, // width of each column
2546                 1,                // Total columns.
2547                 0,                // Pixel of top of window.
2548                 0,                // If this listbox is a popup window
2549                 LISTBOX_MULTIPLE, // Select one item or multiple items
2550                 ICON_TOP,         // Position of icon relative to text of each item
2551                 -1)               // Allow drags, require shift for scrolling
2552 {
2553         this->mwindow = mwindow;
2554         this->gui = gui;
2555         set_drag_scroll(0);
2556         set_scroll_stretch(1, 1);
2557 }
2558
2559 AWindowAssets::~AWindowAssets()
2560 {
2561 }
2562
2563 int AWindowAssets::button_press_event()
2564 {
2565         AssetVIconThread *avt = gui->vicon_thread;
2566         if( avt->draw_mode != ASSET_VIEW_NONE && is_event_win() ) {
2567                 int dir = 1, button = get_buttonpress();
2568                 switch( button ) {
2569                 case WHEEL_DOWN: dir = -1;  // fall thru
2570                 case WHEEL_UP: {
2571                         int x = get_cursor_x(), y = get_cursor_y();
2572                         if( avt->cursor_inside(x, y) && avt->view_win )
2573                                 return avt->view_win->zoom_scale(dir);
2574                         return 1; }
2575                 }
2576         }
2577
2578         int result = BC_ListBox::button_press_event();
2579
2580         if( !result && get_buttonpress() == RIGHT_BUTTON &&
2581             is_event_win() && cursor_inside() ) {
2582                 BC_ListBox::deactivate_selection();
2583                 int folder = mwindow->edl->session->awindow_folder;
2584                 switch( folder ) {
2585                 case AW_AEFFECT_FOLDER:
2586                 case AW_VEFFECT_FOLDER:
2587                 case AW_ATRANSITION_FOLDER:
2588                 case AW_VTRANSITION_FOLDER:
2589                         gui->effectlist_menu->update();
2590                         gui->effectlist_menu->activate_menu();
2591                         break;
2592                 case AW_LABEL_FOLDER:
2593                         gui->labellist_menu->update();
2594                         gui->labellist_menu->activate_menu();
2595                         break;
2596                 case AW_CLIP_FOLDER:
2597                         gui->cliplist_menu->update();
2598                         gui->cliplist_menu->activate_menu();
2599                         break;
2600                 case AW_PROXY_FOLDER:
2601                         gui->proxylist_menu->update();
2602                         gui->proxylist_menu->activate_menu();
2603                         break;
2604                 default:
2605                 case AW_MEDIA_FOLDER: {
2606                         int shots =  folder==AW_MEDIA_FOLDER || folder>=AWINDOW_USER_FOLDERS;
2607                         gui->assetlist_menu->update_titles(shots);
2608                         gui->assetlist_menu->activate_menu();
2609                         break; }
2610                 }
2611                 result = 1;
2612         }
2613
2614         return result;
2615 }
2616
2617
2618 int AWindowAssets::handle_event()
2619 {
2620         AssetPicon *asset_picon = (AssetPicon *)get_selection(0, 0);
2621         if( !asset_picon ) return 0;
2622         Indexable *picon_idxbl = asset_picon->indexable;
2623         EDL *picon_edl = asset_picon->edl;
2624         int proxy = 0;
2625         VWindow *vwindow = 0;
2626         switch( mwindow->edl->session->awindow_folder ) {
2627         case AW_AEFFECT_FOLDER:
2628         case AW_VEFFECT_FOLDER:
2629         case AW_ATRANSITION_FOLDER:
2630         case AW_VTRANSITION_FOLDER: return 1;
2631         case AW_PROXY_FOLDER:
2632                 proxy = 1; // fall thru
2633         default:
2634                 if( mwindow->vwindows.size() > DEFAULT_VWINDOW )
2635                         vwindow = mwindow->vwindows.get(DEFAULT_VWINDOW);
2636                 break;
2637         }
2638         if( !vwindow || !vwindow->is_running() ) return 1;
2639         if( proxy && picon_idxbl ) {
2640                 picon_edl = gui->collect_proxy(picon_idxbl);
2641                 picon_idxbl = 0;
2642         }
2643
2644         if( picon_idxbl ) vwindow->change_source(picon_idxbl);
2645         else if( picon_edl ) vwindow->change_source(picon_edl);
2646         return 1;
2647 }
2648
2649 int AWindowAssets::selection_changed()
2650 {
2651 // Show popup window
2652         AssetPicon *item;
2653         int folder = mwindow->edl->session->awindow_folder;
2654         if( get_button_down() && get_buttonpress() == RIGHT_BUTTON &&
2655             (item = (AssetPicon*)get_selection(0, 0)) ) {
2656                 switch( folder ) {
2657                 case AW_AEFFECT_FOLDER:
2658                 case AW_VEFFECT_FOLDER:
2659                 case AW_ATRANSITION_FOLDER:
2660                 case AW_VTRANSITION_FOLDER:
2661                         gui->effectlist_menu->update();
2662                         gui->effectlist_menu->activate_menu();
2663                         break;
2664                 case AW_LABEL_FOLDER:
2665                         if( !item->label ) break;
2666                         gui->label_menu->activate_menu();
2667                         break;
2668                 case AW_CLIP_FOLDER:
2669                         if( !item->indexable && !item->edl ) break;
2670                         gui->clip_menu->update();
2671                         gui->clip_menu->activate_menu();
2672                         break;
2673                 case AW_PROXY_FOLDER:
2674                         if( !item->indexable && !item->edl ) break;
2675                         gui->proxy_menu->update();
2676                         gui->proxy_menu->activate_menu();
2677                         break;
2678                 default:
2679                         if( !item->indexable && !item->edl ) break;
2680                         gui->asset_menu->update();
2681                         gui->asset_menu->activate_menu();
2682                         break;
2683                 }
2684
2685                 deactivate_selection();
2686         }
2687         else if( gui->vicon_drawing && get_button_down() &&
2688                 (item = (AssetPicon*)get_selection(0, 0)) != 0 ) {
2689                 switch( folder ) {
2690                 case AW_MEDIA_FOLDER:
2691                 case AW_PROXY_FOLDER:
2692                 case AWINDOW_USER_FOLDERS:
2693                         if( get_buttonpress() == LEFT_BUTTON ||
2694                             get_buttonpress() == MIDDLE_BUTTON ) {
2695                                 AssetVIcon *vicon = 0;
2696                                 if( !gui->vicon_thread->vicon )
2697                                         vicon = item->vicon;
2698                                 int draw_mode = vicon && get_buttonpress() == MIDDLE_BUTTON ?
2699                                         ASSET_VIEW_MEDIA_MAP : ASSET_VIEW_MEDIA;
2700                                 gui->vicon_thread->set_view_popup(vicon, draw_mode);
2701                         }
2702                         break;
2703                 case AW_CLIP_FOLDER:
2704                         if( get_buttonpress() == LEFT_BUTTON ) {
2705                                 AssetVIcon *vicon = 0;
2706                                 if( !gui->vicon_thread->vicon )
2707                                         vicon = item->vicon;
2708                                 gui->vicon_thread->set_view_popup(vicon, ASSET_VIEW_ICON);
2709                         }
2710                         break;
2711                 }
2712         }
2713         return 1;
2714 }
2715
2716 void AWindowAssets::draw_background()
2717 {
2718         clear_box(0,0,get_w(),get_h(),get_bg_surface());
2719         set_color(BC_WindowBase::get_resources()->audiovideo_color);
2720         set_font(LARGEFONT);
2721         int folder = mwindow->edl->session->awindow_folder;
2722         const char *title = mwindow->edl->get_folder_name(folder);
2723         draw_text(get_w() - get_text_width(LARGEFONT, title) - 4, 30,
2724                 title, -1, get_bg_surface());
2725 }
2726
2727 int AWindowAssets::drag_start_event()
2728 {
2729         int collect_pluginservers = 0;
2730         int collect_assets = 0, proxy = 0;
2731
2732         if( BC_ListBox::drag_start_event() ) {
2733                 switch( mwindow->edl->session->awindow_folder ) {
2734                 case AW_AEFFECT_FOLDER:
2735                         mwindow->session->current_operation = DRAG_AEFFECT;
2736                         collect_pluginservers = 1;
2737                         break;
2738                 case AW_VEFFECT_FOLDER:
2739                         mwindow->session->current_operation = DRAG_VEFFECT;
2740                         collect_pluginservers = 1;
2741                         break;
2742                 case AW_ATRANSITION_FOLDER:
2743                         mwindow->session->current_operation = DRAG_ATRANSITION;
2744                         collect_pluginservers = 1;
2745                         break;
2746                 case AW_VTRANSITION_FOLDER:
2747                         mwindow->session->current_operation = DRAG_VTRANSITION;
2748                         collect_pluginservers = 1;
2749                         break;
2750                 case AW_LABEL_FOLDER:
2751                         // do nothing!
2752                         break;
2753                 case AW_PROXY_FOLDER:
2754                         proxy = 1; // fall thru
2755                 case AW_MEDIA_FOLDER:
2756                 default:
2757                         mwindow->session->current_operation = DRAG_ASSET;
2758                         collect_assets = 1;
2759                         break;
2760                 }
2761
2762                 if( collect_pluginservers ) {
2763                         int i = 0;
2764                         mwindow->session->drag_pluginservers->remove_all();
2765                         while(1)
2766                         {
2767                                 AssetPicon *result = (AssetPicon*)get_selection(0, i++);
2768                                 if( !result ) break;
2769
2770                                 mwindow->session->drag_pluginservers->append(result->plugin);
2771                         }
2772                 }
2773
2774                 if( collect_assets ) {
2775                         gui->collect_assets(proxy);
2776                 }
2777
2778                 return 1;
2779         }
2780         return 0;
2781 }
2782
2783 int AWindowAssets::drag_motion_event()
2784 {
2785         BC_ListBox::drag_motion_event();
2786         unlock_window();
2787
2788         mwindow->gui->lock_window("AWindowAssets::drag_motion_event");
2789         mwindow->gui->drag_motion();
2790         mwindow->gui->unlock_window();
2791
2792         for( int i = 0; i < mwindow->vwindows.size(); i++ ) {
2793                 VWindow *vwindow = mwindow->vwindows.get(i);
2794                 if( !vwindow->is_running() ) continue;
2795                 vwindow->gui->lock_window("AWindowAssets::drag_motion_event");
2796                 vwindow->gui->drag_motion();
2797                 vwindow->gui->unlock_window();
2798         }
2799
2800         mwindow->cwindow->gui->lock_window("AWindowAssets::drag_motion_event");
2801         mwindow->cwindow->gui->drag_motion();
2802         mwindow->cwindow->gui->unlock_window();
2803
2804         lock_window("AWindowAssets::drag_motion_event");
2805         if( mwindow->session->current_operation == DRAG_ASSET &&
2806             gui->folder_list->cursor_above() ) { // highlight user folder
2807                 BC_ListBoxItem *item = 0;
2808                 int item_no = gui->folder_list->get_cursor_data_item_no(&item);
2809                 if( item_no >= 0 ) {
2810                         AssetPicon *folder = (AssetPicon *)gui->folders[item_no];
2811                         if( folder->foldernum < AWINDOW_USER_FOLDERS ) item_no = -1;
2812                 }
2813                 if( item_no >= 0 )
2814                         item_no = gui->folder_list->item_to_index(&gui->folders, item);
2815                 int folder_xposition = gui->folder_list->get_xposition();
2816                 int folder_yposition = gui->folder_list->get_yposition();
2817                 gui->folder_list->update(&gui->folders, 0, 0, 1,
2818                         folder_xposition, folder_yposition, item_no, 0, 1);
2819         }
2820         return 0;
2821 }
2822
2823 int AWindowAssets::drag_stop_event()
2824 {
2825         int result = 0;
2826
2827         result = gui->drag_stop();
2828
2829         unlock_window();
2830
2831         if( !result ) {
2832                 mwindow->gui->lock_window("AWindowAssets::drag_stop_event");
2833                 result = mwindow->gui->drag_stop();
2834                 mwindow->gui->unlock_window();
2835         }
2836
2837         if( !result ) {
2838                 for( int i = 0; !result && i < mwindow->vwindows.size(); i++ ) {
2839                         VWindow *vwindow = mwindow->vwindows.get(i);
2840                         if( !vwindow ) continue;
2841                         if( !vwindow->is_running() ) continue;
2842                         if( vwindow->gui->is_hidden() ) continue;
2843                         vwindow->gui->lock_window("AWindowAssets::drag_stop_event");
2844                         if( vwindow->gui->cursor_above() &&
2845                             vwindow->gui->get_cursor_over_window() ) {
2846                                 result = vwindow->gui->drag_stop();
2847                         }
2848                         vwindow->gui->unlock_window();
2849                 }
2850         }
2851
2852         if( !result ) {
2853                 mwindow->cwindow->gui->lock_window("AWindowAssets::drag_stop_event");
2854                 result = mwindow->cwindow->gui->drag_stop();
2855                 mwindow->cwindow->gui->unlock_window();
2856         }
2857
2858         lock_window("AWindowAssets::drag_stop_event");
2859         if( !result ) {
2860                 result = gui->folder_list->drag_stop();
2861         }
2862
2863
2864         if( result )
2865                 get_drag_popup()->set_animation(0);
2866
2867         BC_ListBox::drag_stop_event();
2868 // since NO_OPERATION is also defined in listbox, we have to reach for global scope...
2869         mwindow->session->current_operation = ::NO_OPERATION;
2870
2871         return 1;
2872 }
2873
2874 int AWindowAssets::column_resize_event()
2875 {
2876         mwindow->edl->session->asset_columns[0] = get_column_width(0);
2877         mwindow->edl->session->asset_columns[1] = get_column_width(1);
2878         return 1;
2879 }
2880
2881 int AWindowAssets::focus_in_event()
2882 {
2883         int ret = BC_ListBox::focus_in_event();
2884         gui->start_vicon_drawing();
2885         return ret;
2886 }
2887
2888 int AWindowAssets::focus_out_event()
2889 {
2890         gui->stop_vicon_drawing();
2891         return BC_ListBox::focus_out_event();
2892 }
2893
2894 void AWindowAssets::update_vicon_area()
2895 {
2896         int x0 = 0, x1 = get_w();
2897         int y0 = get_title_h();
2898         int y1 = get_h();
2899         if( is_highlighted() ) {
2900                 x0 += LISTBOX_BORDER;  x1 -= LISTBOX_BORDER;
2901                 y0 += LISTBOX_BORDER;  y1 -= LISTBOX_BORDER;
2902         }
2903         gui->vicon_thread->set_drawing_area(x0,y0, x1,y1);
2904 }
2905
2906 int AWindowAssets::mouse_over_event(int no)
2907 {
2908         if( gui->vicon_thread->viewing &&
2909             no >= 0 && no < gui->displayed_assets[0].size() ) {
2910                 AssetPicon *picon = (AssetPicon *)gui->displayed_assets[0][no];
2911                 gui->vicon_thread->set_view_popup(picon->vicon);
2912         }
2913         return 0;
2914 }
2915
2916
2917 AWindowSearchTextBox::AWindowSearchTextBox(AWindowSearchText *search_text, int x, int y, int w)
2918  : BC_TextBox(x, y, w, 1, "")
2919 {
2920         this->search_text = search_text;
2921 }
2922
2923 int AWindowSearchTextBox::handle_event()
2924 {
2925         return search_text->handle_event();
2926 }
2927
2928 AWindowSearchText::AWindowSearchText(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2929 {
2930         this->mwindow = mwindow;
2931         this->gui = gui;
2932         this->x = x;
2933         this->y = y;
2934 }
2935
2936 void AWindowSearchText::create_objects()
2937 {
2938         int x1 = x, y1 = y, margin = 10;
2939         gui->add_subwindow(text_title = new BC_Title(x1, y1, _("Search:")));
2940         x1 += text_title->get_w() + margin;
2941         int w1 = gui->get_w() - x1 - 2*margin;
2942         gui->add_subwindow(text_box = new AWindowSearchTextBox(this, x1, y1, w1));
2943 }
2944
2945 int AWindowSearchText::handle_event()
2946 {
2947         gui->async_update_assets();
2948         return&nbs