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