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