nested clips, big rework and cleanup, sams new icons, leaks and tweaks
[goodguy/history.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 "asset.h"
23 #include "assetedit.h"
24 #include "assetpopup.h"
25 #include "assets.h"
26 #include "audiodevice.h"
27 #include "awindowgui.h"
28 #include "awindow.h"
29 #include "bccmodels.h"
30 #include "bcsignals.h"
31 #include "bchash.h"
32 #include "cache.h"
33 #include "cstrdup.h"
34 #include "clip.h"
35 #include "clipedls.h"
36 #include "clippopup.h"
37 #include "cursors.h"
38 #include "cwindowgui.h"
39 #include "cwindow.h"
40 #include "edl.h"
41 #include "edlsession.h"
42 #include "effectlist.h"
43 #include "file.h"
44 #include "filesystem.h"
45 #include "folderlistmenu.h"
46 #include "indexable.h"
47 #include "keys.h"
48 #include "language.h"
49 #include "labels.h"
50 #include "labelpopup.h"
51 #include "localsession.h"
52 #include "mainmenu.h"
53 #include "mainsession.h"
54 #include "mwindowgui.h"
55 #include "mwindow.h"
56 #include "newfolder.h"
57 #include "preferences.h"
58 #include "samples.h"
59 #include "theme.h"
60 #include "vframe.h"
61 #include "vicon.h"
62 #include "vwindowgui.h"
63 #include "vwindow.h"
64
65 #include "data/lad_picon_png.h"
66 #include "data/ff_audio_png.h"
67 #include "data/ff_video_png.h"
68
69 #include<stdio.h>
70 #include<unistd.h>
71 #include<fcntl.h>
72
73
74 const char *AWindowGUI::folder_names[] =
75 {
76         N_("Audio Effects"),
77         N_("Video Effects"),
78         N_("Audio Transitions"),
79         N_("Video Transitions"),
80         N_("Labels"),
81         N_("Clips"),
82         N_("Media"),
83         N_("Proxy"),
84 };
85
86
87 AssetVIcon::AssetVIcon(AssetPicon *picon, int w, int h, double framerate, int64_t length)
88  : VIcon(w, h, framerate)
89 {
90         this->picon = picon;
91         this->length = length;
92         temp = 0;
93 }
94
95 AssetVIcon::~AssetVIcon()
96 {
97         delete temp;
98 }
99
100 VFrame *AssetVIcon::frame()
101 {
102         Asset *asset = (Asset *)picon->indexable;
103         if( !asset->video_data && audio_data && audio_size && length > 0 ) {
104                 if( !temp ) temp = new VFrame(0, -1, vw, vh, BC_RGB888, -1);
105                 temp->clear_frame();
106                 int sample_rate = asset->get_sample_rate();
107                 int64_t audio_samples = asset->get_audio_samples();
108                 double duration = (double)audio_samples / sample_rate;
109                 picon->draw_hue_bar(temp, duration);
110                 int secs = length / frame_rate + 0.5;
111                 if( !secs ) secs = 1;
112                 int bfrsz = VICON_SAMPLE_RATE;
113                 int samples = audio_size/sizeof(vicon_audio_t);
114                 double line_pos = (double)seq_no/(length-1);
115                 int audio_pos = samples * line_pos * (secs-1)/secs;
116                 vicon_audio_t *audio_data = ((vicon_audio_t *)this->audio_data) + audio_pos;
117                 static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
118                 double data[bfrsz], sample_scale = 1./mx;
119                 int len = samples - audio_pos;
120                 if( len > bfrsz ) len = bfrsz;
121                 int i = 0;
122                 while( i < len ) data[i++] = *audio_data++ * sample_scale;
123                 while( i < bfrsz ) data[i++] = 0;
124                 picon->draw_wave(temp, data, bfrsz, RED, GREEN);
125                 int x = (vw-1) * line_pos;
126                 temp->pixel_rgb = RED;
127                 temp->draw_line(x,0, x,vh);
128                 return temp;
129         }
130         if( seq_no >= images.size() ) {
131                 MWindow *mwindow = picon->mwindow;
132                 File *file = mwindow->video_cache->check_out(asset, mwindow->edl, 1);
133                 if( !file ) return 0;
134                 if( temp && (temp->get_w() != asset->width || temp->get_h() != asset->height) ) {
135                         delete temp;  temp = 0;
136                 }
137                 if( !temp )
138                         temp = new VFrame(0, -1, asset->width, asset->height, BC_RGB888, -1);
139                 int ww = picon->gui->vicon_thread->view_w;
140                 int hh = picon->gui->vicon_thread->view_h;
141                 while( seq_no >= images.size() ) {
142                         file->set_layer(0);
143                         int64_t pos = images.size() / picon->gui->vicon_thread->refresh_rate * frame_rate;
144                         file->set_video_position(pos,0);
145                         if( file->read_frame(temp) ) temp->clear_frame();
146                         add_image(temp, ww, hh, BC_RGB8);
147                 }
148                 mwindow->video_cache->check_in(asset);
149         }
150         return *images[seq_no];
151 }
152
153 int64_t AssetVIcon::set_seq_no(int64_t no)
154 {
155         if( no >= length ) no = 0;
156         return seq_no = no;
157 }
158
159 int AssetVIcon::get_vx()
160 {
161         BC_ListBox *lbox = picon->gui->asset_list;
162         return lbox->get_item_x(picon);
163 }
164 int AssetVIcon::get_vy()
165 {
166         BC_ListBox *lbox = picon->gui->asset_list;
167         return lbox->get_item_y(picon) + lbox->get_title_h();
168 }
169
170 void AssetVIcon::load_audio()
171 {
172         MWindow *mwindow = picon->mwindow;
173         Asset *asset = (Asset *)picon->indexable;
174         File *file = mwindow->audio_cache->check_out(asset, mwindow->edl, 1);
175         int channels = asset->get_audio_channels();
176         if( channels > 2 ) channels = 2;
177         int sample_rate = asset->get_sample_rate();
178         int bfrsz = sample_rate;
179         Samples samples(bfrsz);
180         double time_scale = (double)sample_rate / VICON_SAMPLE_RATE;
181         vicon_audio_t *audio_data = (vicon_audio_t *)this->audio_data;
182         static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
183         double sample_scale = (double)mx / channels;
184         int audio_pos = 0, audio_len = audio_size/sizeof(vicon_audio_t);
185         while( audio_pos < audio_len ) {
186                 int64_t pos = audio_pos * time_scale;
187                 for( int ch=0; ch<channels; ++ch ) {
188                         file->set_channel(ch);
189                         file->set_audio_position(pos);
190                         file->read_samples(&samples, bfrsz);
191                         double *data = samples.get_data();
192                         for( int64_t k=audio_pos; k<audio_len; ++k ) {
193                                 int i = k * time_scale - pos;
194                                 if( i >= bfrsz ) break;
195                                 int v = audio_data[k] + data[i] * sample_scale;
196                                 audio_data[k] = CLIP(v, -mx,mx);
197                         }
198                 }
199                 audio_pos = (pos + bfrsz) / time_scale;
200         }
201         mwindow->audio_cache->check_in(asset);
202 }
203
204
205 AssetVIconAudio::AssetVIconAudio(AWindowGUI *gui)
206  : Thread(1, 0, 0)
207 {
208         this->gui = gui;
209         audio = new AudioDevice(gui->mwindow);
210         interrupted = 0;
211         vicon = 0;
212 }
213 AssetVIconAudio::~AssetVIconAudio()
214 {
215         delete audio;
216 }
217
218 void AssetVIconAudio::run()
219 {
220         int channels = 2;
221         int64_t bfrsz = VICON_SAMPLE_RATE;
222         MWindow *mwindow = gui->mwindow;
223         EDL *edl = mwindow->edl;
224         EDLSession *session = edl->session;
225         AudioOutConfig *aconfig = session->playback_config->aconfig;
226         audio->open_output(aconfig, VICON_SAMPLE_RATE, bfrsz, channels, 0);
227         audio->start_playback();
228         double out0[bfrsz], out1[bfrsz], *out[2] = { out0, out1 };
229         vicon_audio_t *audio_data = (vicon_audio_t *)vicon->audio_data;
230         static const int mx = (1<<(8*sizeof(*audio_data)-1)) - 1;
231
232         int audio_len = vicon->audio_size/sizeof(vicon_audio_t);
233         while( !interrupted ) {
234                 int len = audio_len - audio_pos;
235                 if( len <= 0 ) break;
236                 if( len > bfrsz ) len = bfrsz;
237                 int k = audio_pos;
238                 for( int i=0; i<len; ++i,++k )
239                         out0[i] = out1[i] = (double)audio_data[k] / mx;
240                 audio_pos = k;
241                 audio->write_buffer(out, channels, len);
242         }
243
244         if( !interrupted )
245                 audio->set_last_buffer();
246         audio->stop_audio(interrupted ? 0 : 1);
247         audio->close_all();
248 }
249
250 void AssetVIconAudio::start(AssetVIcon *vicon)
251 {
252         if( running() ) return;
253         interrupted = 0;
254         audio_pos = 0;
255         this->vicon = vicon;
256         Thread::start();
257 }
258
259 void AssetVIconAudio::stop(int wait)
260 {
261         if( running() && !interrupted ) {
262                 interrupted = 1;
263                 audio->stop_audio(wait);
264         }
265         Thread::join();
266         if( vicon ) {
267                 vicon->playing_audio = 0;
268                 vicon = 0;
269         }
270 }
271
272 void AssetVIcon::start_audio()
273 {
274         picon->gui->vicon_audio->stop(0);
275         playing_audio = 1;
276         picon->gui->vicon_audio->start(this);
277 }
278
279 void AssetVIcon::stop_audio()
280 {
281         picon->gui->vicon_audio->stop(0);
282         playing_audio = 0;
283 }
284
285 AssetPicon::AssetPicon(MWindow *mwindow,
286         AWindowGUI *gui, Indexable *indexable)
287  : BC_ListBoxItem()
288 {
289         reset();
290         this->mwindow = mwindow;
291         this->gui = gui;
292         this->indexable = indexable;
293         indexable->add_user();
294         this->id = indexable->id;
295 }
296
297 AssetPicon::AssetPicon(MWindow *mwindow,
298         AWindowGUI *gui, EDL *edl)
299  : BC_ListBoxItem()
300 {
301         reset();
302         this->mwindow = mwindow;
303         this->gui = gui;
304         this->edl = edl;
305         edl->add_user();
306         this->id = edl->id;
307 }
308
309 AssetPicon::AssetPicon(MWindow *mwindow,
310         AWindowGUI *gui, int folder, int persist)
311  : BC_ListBoxItem(_(AWindowGUI::folder_names[folder]),
312         folder>=0 && folder<AWINDOW_FOLDERS ?
313                 gui->folder_icons[folder]: gui->folder_icon)
314 {
315         reset();
316         foldernum = folder;
317         this->mwindow = mwindow;
318         this->gui = gui;
319         persistent = persist;
320 }
321
322 AssetPicon::AssetPicon(MWindow *mwindow,
323         AWindowGUI *gui, PluginServer *plugin)
324  : BC_ListBoxItem()
325 {
326         reset();
327         this->mwindow = mwindow;
328         this->gui = gui;
329         this->plugin = plugin;
330 }
331
332 AssetPicon::AssetPicon(MWindow *mwindow,
333         AWindowGUI *gui, Label *label)
334  : BC_ListBoxItem()
335 {
336         reset();
337         this->mwindow = mwindow;
338         this->gui = gui;
339         this->label = label;
340         indexable = 0;
341         icon = 0;
342         id = 0;
343 }
344
345 AssetPicon::~AssetPicon()
346 {
347         if( vicon )
348                 gui->vicon_thread->del_vicon(vicon);
349         if( indexable ) indexable->remove_user();
350         if( edl ) edl->remove_user();
351         if( icon && !gui->protected_pixmap(icon) ) {
352                 delete icon;
353                 if( !plugin ) delete icon_vframe;
354         }
355 }
356
357 void AssetPicon::draw_hue_bar(VFrame *frame, double duration)
358 {
359         float t = duration > 1 ? (log(duration) / log(3600.f)) : 0;
360         if( t > 1 ) t = 1;
361         float h = 300 * t, s = 1., v = 1.;
362         float r, g, b; // duration, 0..1hr == hue red..magenta
363         HSV::hsv_to_rgb(r,g,b, h,s,v);
364         int ih = frame->get_h()/8, iw = frame->get_w();
365         int ir = r * 256;  CLAMP(ir, 0,255);
366         int ig = g * 256;  CLAMP(ig, 0,255);
367         int ib = b * 256;  CLAMP(ib, 0,255);
368         unsigned char **rows = frame->get_rows();
369         for( int y=0; y<ih; ++y ) {
370                 unsigned char *rp = rows[y];
371                 for( int x=0; x<iw; rp+=3,++x ) {
372                         rp[0] = ir;  rp[1] = ig;  rp[2] = ib;
373                 }
374         }
375 }
376
377 void AssetPicon::draw_wave(VFrame *frame, double *dp, int len, int base_color, int line_color)
378 {
379         int w = frame->get_w(), h = frame->get_h();
380         int h1 = h-1, h2 = h/2, y = h2;
381         int rgb_color = frame->pixel_rgb;
382         for( int x=0,x1=0,x2=0; x<w; ++x,x1=x2 ) {
383                 double min = *dp, max = min;
384                 x2 = (len * (x+1))/w;
385                 for( int i=x1; i<x2; ++i ) {
386                         double value = *dp++;
387                         if( value < min ) min = value;
388                         if( value > max ) max = value;
389                 }
390                 int ctr = (min + max) / 2;
391                 int y0 = (int)(h2 - ctr*h2);  CLAMP(y0, 0,h1);
392                 int y1 = (int)(h2 - min*h2);  CLAMP(y1, 0,h1);
393                 int y2 = (int)(h2 - max*h2);  CLAMP(y2, 0,h1);
394                 frame->pixel_rgb = line_color;
395                 frame->draw_line(x,y1, x,y2);
396                 frame->pixel_rgb = base_color;
397                 frame->draw_line(x,y, x,y0);
398                 y = y0;
399         }
400         frame->pixel_rgb = rgb_color;
401 }
402
403 void AssetPicon::reset()
404 {
405         plugin = 0;
406         label = 0;
407         indexable = 0;
408         edl = 0;
409         foldernum = AW_NO_FOLDER;
410         icon = 0;
411         icon_vframe = 0;
412         vicon = 0;
413         in_use = 1;
414         mtime = 0;
415         id = 0;
416         persistent = 0;
417 }
418
419 void AssetPicon::create_objects()
420 {
421         FileSystem fs;
422         char name[BCTEXTLEN];
423         int pixmap_w, pixmap_h;
424
425         pixmap_h = 50 * BC_WindowBase::get_resources()->icon_scale;
426
427         if( indexable ) {
428                 fs.extract_name(name, indexable->path);
429                 set_text(name);
430         }
431
432         if( indexable && indexable->is_asset ) {
433                 Asset *asset = (Asset*)indexable;
434                 if( asset->video_data ) {
435                         if( mwindow->preferences->use_thumbnails ) {
436                                 gui->unlock_window();
437                                 File *file = mwindow->video_cache->check_out(asset,
438                                         mwindow->edl,
439                                         1);
440
441                                 if( file ) {
442                                         int height = asset->height > 0 ? asset->height : 1;
443                                         pixmap_w = pixmap_h * asset->width / height;
444
445                                         file->set_layer(0);
446                                         file->set_video_position(0, 0);
447
448                                         if( gui->temp_picon &&
449                                                 (gui->temp_picon->get_w() != asset->width ||
450                                                 gui->temp_picon->get_h() != asset->height) ) {
451                                                 delete gui->temp_picon;
452                                                 gui->temp_picon = 0;
453                                         }
454
455                                         if( !gui->temp_picon ) {
456                                                 gui->temp_picon = new VFrame(0, -1,
457                                                         asset->width, asset->height,
458                                                         BC_RGB888, -1);
459                                         }
460                                         { char string[BCTEXTLEN];
461                                         sprintf(string, _("Reading %s"), name);
462                                         mwindow->gui->lock_window("AssetPicon::create_objects");
463                                         mwindow->gui->show_message(string);
464                                         mwindow->gui->unlock_window(); }
465                                         file->read_frame(gui->temp_picon);
466                                         mwindow->video_cache->check_in(asset);
467
468                                         gui->lock_window("AssetPicon::create_objects 0");
469                                         icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
470                                         icon->draw_vframe(gui->temp_picon,
471                                                 0, 0, pixmap_w, pixmap_h, 0, 0);
472                                         icon_vframe = new VFrame(0,
473                                                 -1, pixmap_w, pixmap_h, BC_RGB888, -1);
474                                         icon_vframe->transfer_from(gui->temp_picon);
475                                         if( asset->awindow_folder == AW_MEDIA_FOLDER ) {
476 // vicon images
477                                                 double framerate = asset->get_frame_rate();
478                                                 if( !framerate ) framerate = VICON_RATE;
479                                                 int64_t frames = asset->get_video_frames();
480                                                 double secs = frames / framerate;
481                                                 if( secs > 5 ) secs = 5;
482                                                 int64_t length = secs * gui->vicon_thread->refresh_rate;
483                                                 vicon = new AssetVIcon(this, pixmap_w, pixmap_h, framerate, length);
484                                                 if( asset->audio_data && secs > 0 ) {
485                                                         gui->unlock_window();
486                                                         int audio_len = VICON_SAMPLE_RATE*secs+0.5;
487                                                         vicon->init_audio(audio_len*sizeof(vicon_audio_t));
488                                                         vicon->load_audio();
489                                                         gui->lock_window("AssetPicon::create_objects 1");
490                                                 }
491                                                 gui->vicon_thread->add_vicon(vicon);
492                                         }
493
494                                 }
495                                 else {
496                                         gui->lock_window("AssetPicon::create_objects 2");
497                                         icon = gui->video_icon;
498                                         icon_vframe = gui->video_vframe;
499                                 }
500                         }
501                         else {
502                                 icon = gui->video_icon;
503                                 icon_vframe = gui->video_vframe;
504                         }
505                 }
506                 else
507                 if( asset->audio_data ) {
508                         if( mwindow->preferences->use_thumbnails ) {
509                                 gui->unlock_window();
510                                 File *file = mwindow->audio_cache->check_out(asset,
511                                         mwindow->edl,
512                                         1);
513                                 if( file ) {
514                                         pixmap_w = pixmap_h * 16/9;
515                                         icon_vframe = new VFrame(0,
516                                                 -1, pixmap_w, pixmap_h, BC_RGB888, -1);
517                                         { char string[BCTEXTLEN];
518                                         sprintf(string, _("Reading %s"), name);
519                                         mwindow->gui->lock_window("AssetPicon::create_objects 3");
520                                         mwindow->gui->show_message(string);
521                                         mwindow->gui->unlock_window(); }
522                                         int sample_rate = asset->get_sample_rate();
523                                         int channels = asset->get_audio_channels();
524                                         if( channels > 2 ) channels = 2;
525                                         int64_t audio_samples = asset->get_audio_samples();
526                                         double duration = (double)audio_samples / sample_rate;
527                                         draw_hue_bar(icon_vframe, duration);
528                                         int bfrsz = sample_rate;
529                                         Samples samples(bfrsz);
530                                         static int line_colors[2] = { GREEN, YELLOW };
531                                         static int base_colors[2] = { RED, PINK };
532                                         for( int i=channels; --i>=0; ) {
533                                                 file->set_channel(i);
534                                                 file->set_audio_position(0);
535                                                 file->read_samples(&samples, bfrsz);
536                                                 draw_wave(icon_vframe, samples.get_data(), bfrsz,
537                                                         base_colors[i], line_colors[i]);
538                                         }
539                                         mwindow->audio_cache->check_in(asset);
540                                         if( asset->awindow_folder == AW_MEDIA_FOLDER ) {
541                                                 double secs = duration;
542                                                 if( secs > 5 ) secs = 5;
543                                                 double refresh_rate = gui->vicon_thread->refresh_rate;
544                                                 int64_t length = secs * refresh_rate;
545                                                 vicon = new AssetVIcon(this, pixmap_w, pixmap_h, refresh_rate, length);
546                                                 int audio_len = VICON_SAMPLE_RATE*secs+0.5;
547                                                 vicon->init_audio(audio_len*sizeof(vicon_audio_t));
548                                                 vicon->load_audio();
549                                                 gui->vicon_thread->add_vicon(vicon);
550                                         }
551                                         gui->lock_window("AssetPicon::create_objects 4");
552                                         icon = new BC_Pixmap(gui, pixmap_w, pixmap_h);
553                                         icon->draw_vframe(icon_vframe,
554                                                 0, 0, pixmap_w, pixmap_h, 0, 0);
555                                 }
556                                 else {
557                                         gui->lock_window("AssetPicon::create_objects 5");
558                                         icon = gui->audio_icon;
559                                         icon_vframe = gui->audio_vframe;
560                                 }
561                         }
562                         else {
563                                 icon = gui->audio_icon;
564                                 icon_vframe = gui->audio_vframe;
565                         }
566
567                 }
568                 struct stat st;
569                 mtime = !stat(asset->path, &st) ? st.st_mtime : 0;
570         }
571         else
572         if( indexable && !indexable->is_asset ) {
573                 icon = gui->video_icon;
574                 icon_vframe = gui->video_vframe;
575         }
576         else
577         if( edl ) {
578                 set_text(strcpy(name, edl->local_session->clip_title));
579                 icon = gui->clip_icon;
580                 icon_vframe = gui->clip_vframe;
581         }
582         else
583         if( plugin ) {
584                 strcpy(name, _(plugin->title));
585                 set_text(name);
586                 icon_vframe = plugin->get_picon();
587                 if( icon_vframe )
588                         icon = gui->create_pixmap(icon_vframe);
589                 else if( plugin->audio ) {
590                         if( plugin->transition ) {
591                                 icon = gui->atransition_icon;
592                                 icon_vframe = gui->atransition_vframe;
593                         }
594                         else if( plugin->is_ffmpeg() ) {
595                                 icon = gui->ff_aud_icon;
596                                 icon_vframe = gui->ff_aud_vframe;
597                         }
598                         else if( plugin->is_ladspa() ) {
599                                 icon = gui->ladspa_icon;
600                                 icon_vframe = gui->ladspa_vframe;
601                         }
602                         else {
603                                 icon = gui->aeffect_icon;
604                                 icon_vframe = gui->aeffect_vframe;
605                         }
606                 }
607                 else if( plugin->video ) {
608                         if( plugin->transition ) {
609                                 icon = gui->vtransition_icon;
610                                 icon_vframe = gui->vtransition_vframe;
611                         }
612                         else if( plugin->is_ffmpeg() ) {
613                                 icon = gui->ff_vid_icon;
614                                 icon_vframe = gui->ff_vid_vframe;
615                         }
616                         else {
617                                 icon = gui->veffect_icon;
618                                 icon_vframe = gui->veffect_vframe;
619                         }
620                 }
621         }
622         else
623         if( label ) {
624                 Units::totext(name,
625                               label->position,
626                               mwindow->edl->session->time_format,
627                               mwindow->edl->session->sample_rate,
628                               mwindow->edl->session->frame_rate,
629                               mwindow->edl->session->frames_per_foot);
630                 set_text(name);
631                 icon = gui->label_icon;
632                 icon_vframe = gui->label_vframe;
633         }
634         if( !icon ) {
635                 icon = gui->file_icon;
636                 icon_vframe = BC_WindowBase::get_resources()->type_to_icon[ICON_UNKNOWN];
637         }
638         set_icon(icon);
639         set_icon_vframe(icon_vframe);
640 }
641
642 AWindowGUI::AWindowGUI(MWindow *mwindow, AWindow *awindow)
643  : BC_Window(_(PROGRAM_NAME ": Resources"),
644         mwindow->session->awindow_x, mwindow->session->awindow_y,
645         mwindow->session->awindow_w, mwindow->session->awindow_h,
646         100, 100, 1, 1, 1)
647 {
648         this->mwindow = mwindow;
649         this->awindow = awindow;
650
651         file_vframe = 0;                file_icon = 0;
652         folder_vframe = 0;              folder_icon = 0;
653         audio_vframe = 0;               audio_icon = 0;
654         video_vframe = 0;               video_icon = 0;
655         label_vframe = 0;               label_icon = 0;
656
657         atransition_vframe = 0;         atransition_icon = 0;
658         vtransition_vframe = 0;         vtransition_icon = 0;
659         aeffect_vframe = 0;             aeffect_icon = 0;
660         ladspa_vframe = 0;              ladspa_icon = 0;
661         veffect_vframe = 0;             veffect_icon = 0;
662         ff_aud_vframe = 0;              ff_aud_icon = 0;
663         ff_vid_vframe = 0;              ff_vid_icon = 0;
664
665         aeffect_folder_vframe = 0;      aeffect_folder_icon = 0;
666         atransition_folder_vframe = 0;  atransition_folder_icon = 0;
667         clip_folder_vframe = 0;         clip_folder_icon = 0;
668         label_folder_vframe = 0;        label_folder_icon = 0;
669         media_folder_vframe = 0;        media_folder_icon = 0;
670         proxy_folder_vframe = 0;        proxy_folder_icon = 0;
671         veffect_folder_vframe = 0;      veffect_folder_icon = 0;
672         vtransition_folder_vframe = 0;  vtransition_folder_icon = 0;
673
674         ladspa_vframe = 0;              ladspa_icon = 0;
675         ff_aud_vframe = 0;              ff_aud_icon = 0;
676         ff_vid_vframe = 0;              ff_vid_icon = 0;
677
678         clip_vframe = 0;                clip_icon = 0;
679         atransition_vframe = 0;         atransition_icon = 0;
680         vtransition_vframe = 0;         vtransition_icon = 0;
681         aeffect_vframe = 0;             aeffect_icon = 0;
682         veffect_vframe = 0;             veffect_icon = 0;
683
684         plugin_visibility = ((uint64_t)1<<(8*sizeof(uint64_t)-1))-1;
685         newfolder_thread = 0;
686         asset_menu = 0;
687         effectlist_menu = 0;
688         assetlist_menu = 0;
689         cliplist_menu = 0;
690         labellist_menu = 0;
691         folderlist_menu = 0;
692         temp_picon = 0;
693         search_text = 0;
694         allow_iconlisting = 1;
695         remove_plugin = 0;
696         vicon_thread = 0;
697         vicon_audio = 0;
698         vicon_drawing = 1;
699         displayed_folder = AW_NO_FOLDER;
700 }
701
702 AWindowGUI::~AWindowGUI()
703 {
704         assets.remove_all_objects();
705         folders.remove_all_objects();
706         aeffects.remove_all_objects();
707         veffects.remove_all_objects();
708         atransitions.remove_all_objects();
709         vtransitions.remove_all_objects();
710         labellist.remove_all_objects();
711         displayed_assets[1].remove_all_objects();
712
713         delete vicon_thread;
714         delete vicon_audio;
715         delete newfolder_thread;
716
717         delete asset_menu;
718         delete clip_menu;
719         delete label_menu;
720         delete effectlist_menu;
721         delete assetlist_menu;
722         delete cliplist_menu;
723         delete labellist_menu;
724         delete folderlist_menu;
725         delete search_text;
726         delete temp_picon;
727         delete remove_plugin;
728
729         delete file_vframe;             delete file_icon;
730         delete folder_vframe;           delete folder_icon;
731         delete audio_vframe;            delete audio_icon;
732         delete video_vframe;            delete video_icon;
733         delete label_vframe;            delete label_icon;
734         delete clip_vframe;             delete clip_icon;
735         delete aeffect_folder_vframe;   delete aeffect_folder_icon;
736         delete atransition_folder_vframe; delete atransition_folder_icon;
737         delete veffect_folder_vframe;   delete veffect_folder_icon;
738         delete vtransition_folder_vframe; delete vtransition_folder_icon;
739         delete clip_folder_vframe;      delete clip_folder_icon;
740         delete label_folder_vframe;     delete label_folder_icon;
741         delete media_folder_vframe;     delete media_folder_icon;
742         delete proxy_folder_vframe;     delete proxy_folder_icon;
743         delete ladspa_vframe;           delete ladspa_icon;
744         delete ff_aud_vframe;           delete ff_aud_icon;
745         delete ff_vid_vframe;           delete ff_vid_icon;
746         delete atransition_vframe;      delete atransition_icon;
747         delete vtransition_vframe;      delete vtransition_icon;
748         delete aeffect_vframe;          delete aeffect_icon;
749         delete veffect_vframe;          delete veffect_icon;
750 }
751
752 bool AWindowGUI::protected_pixmap(BC_Pixmap *icon)
753 {
754         return  icon == file_icon ||
755                 icon == folder_icon ||
756                 icon == audio_icon ||
757                 icon == video_icon ||
758                 icon == clip_icon ||
759                 icon == label_icon ||
760                 icon == vtransition_icon ||
761                 icon == atransition_icon ||
762                 icon == veffect_icon ||
763                 icon == aeffect_icon ||
764                 icon == ladspa_icon ||
765                 icon == ff_aud_icon ||
766                 icon == ff_vid_icon ||
767                 icon == aeffect_folder_icon ||
768                 icon == veffect_folder_icon ||
769                 icon == atransition_folder_icon ||
770                 icon == vtransition_folder_icon ||
771                 icon == label_folder_icon ||
772                 icon == clip_folder_icon ||
773                 icon == media_folder_icon ||
774                 icon == proxy_folder_icon;
775 }
776
777 VFrame *AWindowGUI::get_picon(const char *name, const char *plugin_icons)
778 {
779         char png_path[BCTEXTLEN];
780         char *pp = png_path, *ep = pp + sizeof(png_path)-1;
781         snprintf(pp, ep-pp, "%s/picon/%s/%s.png",
782                 File::get_plugin_path(), plugin_icons, name);
783         if( access(png_path, R_OK) ) return 0;
784         return VFramePng::vframe_png(png_path,0,0);
785 }
786
787 VFrame *AWindowGUI::get_picon(const char *name)
788 {
789         VFrame *vframe = get_picon(name, mwindow->preferences->plugin_icons);
790         if( !vframe ) {
791                 char png_name[BCSTRLEN], *pp = png_name, *ep = pp + sizeof(png_name)-1;
792                 snprintf(pp, ep-pp, "%s.png", name);
793                 unsigned char *data = mwindow->theme->get_image_data(png_name);
794                 if( data ) vframe = new VFramePng(data, 0.);
795         }
796         return vframe;
797 }
798
799 void AWindowGUI::resource_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn, int idx)
800 {
801         vfrm = get_picon(fn);
802         if( !vfrm ) vfrm = BC_WindowBase::get_resources()->type_to_icon[idx];
803         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
804 }
805 void AWindowGUI::theme_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn)
806 {
807         vfrm = get_picon(fn);
808         if( !vfrm ) vfrm = mwindow->theme->get_image(fn);
809         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
810 }
811 void AWindowGUI::plugin_icon(VFrame *&vfrm, BC_Pixmap *&icon, const char *fn, unsigned char *png)
812 {
813         vfrm = get_picon(fn);
814         if( !vfrm ) vfrm = new VFramePng(png);
815         icon = new BC_Pixmap(this, vfrm, PIXMAP_ALPHA);
816 }
817
818 void AWindowGUI::create_objects()
819 {
820         lock_window("AWindowGUI::create_objects");
821         asset_titles[0] = C_("Title");
822         asset_titles[1] = _("Comments");
823
824         set_icon(mwindow->theme->get_image("awindow_icon"));
825
826         resource_icon(file_vframe,   file_icon,   "film_icon",   ICON_UNKNOWN);
827         resource_icon(folder_vframe, folder_icon, "folder_icon", ICON_FOLDER);
828         resource_icon(audio_vframe,  audio_icon,  "audio_icon",  ICON_SOUND);
829         resource_icon(video_vframe,  video_icon,  "video_icon",  ICON_FILM);
830         resource_icon(label_vframe,  label_icon,  "label_icon",  ICON_LABEL);
831
832         theme_icon(aeffect_folder_vframe,      aeffect_folder_icon,     "aeffect_folder");
833         theme_icon(atransition_folder_vframe,  atransition_folder_icon, "atransition_folder");
834         theme_icon(clip_folder_vframe,         clip_folder_icon,        "clip_folder");
835         theme_icon(label_folder_vframe,        label_folder_icon,       "label_folder");
836         theme_icon(media_folder_vframe,        media_folder_icon,       "media_folder");
837         theme_icon(proxy_folder_vframe,        proxy_folder_icon,       "proxy_folder");
838         theme_icon(veffect_folder_vframe,      veffect_folder_icon,     "veffect_folder");
839         theme_icon(vtransition_folder_vframe,  vtransition_folder_icon, "vtransition_folder");
840
841         folder_icons[AW_AEFFECT_FOLDER] = aeffect_folder_icon;
842         folder_icons[AW_VEFFECT_FOLDER] = veffect_folder_icon;
843         folder_icons[AW_ATRANSITION_FOLDER] = atransition_folder_icon;
844         folder_icons[AW_VTRANSITION_FOLDER] = vtransition_folder_icon;
845         folder_icons[AW_LABEL_FOLDER] = label_folder_icon;
846         folder_icons[AW_CLIP_FOLDER] = clip_folder_icon;
847         folder_icons[AW_MEDIA_FOLDER] = media_folder_icon;
848         folder_icons[AW_PROXY_FOLDER] = proxy_folder_icon;
849
850         theme_icon(clip_vframe,        clip_icon,        "clip_icon");
851         theme_icon(atransition_vframe, atransition_icon, "atransition_icon");
852         theme_icon(vtransition_vframe, vtransition_icon, "vtransition_icon");
853         theme_icon(aeffect_vframe,     aeffect_icon,     "aeffect_icon");
854         theme_icon(veffect_vframe,     veffect_icon,     "veffect_icon");
855
856         plugin_icon(ladspa_vframe, ladspa_icon, "lad_picon", lad_picon_png);
857         plugin_icon(ff_aud_vframe, ff_aud_icon, "ff_audio",  ff_audio_png);
858         plugin_icon(ff_vid_vframe, ff_vid_icon, "ff_video",  ff_video_png);
859
860 // Mandatory folders
861         folders.append(new AssetPicon(mwindow, this, AW_AEFFECT_FOLDER, 1));
862         folders.append(new AssetPicon(mwindow, this, AW_VEFFECT_FOLDER, 1));
863         folders.append(new AssetPicon(mwindow, this, AW_ATRANSITION_FOLDER, 1));
864         folders.append(new AssetPicon(mwindow, this, AW_VTRANSITION_FOLDER, 1));
865         folders.append(new AssetPicon(mwindow, this, AW_LABEL_FOLDER, 1));
866         folders.append(new AssetPicon(mwindow, this, AW_CLIP_FOLDER, 1));
867         folders.append(new AssetPicon(mwindow, this, AW_PROXY_FOLDER, 1));
868         folders.append(new AssetPicon(mwindow, this, AW_MEDIA_FOLDER, 1));
869
870         create_label_folder();
871
872         mwindow->theme->get_awindow_sizes(this);
873         load_defaults(mwindow->defaults);
874
875         int x1 = mwindow->theme->alist_x, y1 = mwindow->theme->alist_y;
876         int w1 = mwindow->theme->alist_w, h1 = mwindow->theme->alist_h;
877         search_text = new AWindowSearchText(mwindow, this, x1, y1+5);
878         search_text->create_objects();
879         int dy = search_text->get_h() + 10;
880         y1 += dy;  h1 -= dy;
881         add_subwindow(asset_list = new AWindowAssets(mwindow, this, x1, y1, w1, h1));
882
883         vicon_thread = new VIconThread(asset_list);
884         vicon_thread->start();
885         vicon_audio = new AssetVIconAudio(this);
886
887         add_subwindow(divider = new AWindowDivider(mwindow, this,
888                 mwindow->theme->adivider_x, mwindow->theme->adivider_y,
889                 mwindow->theme->adivider_w, mwindow->theme->adivider_h));
890
891         divider->set_cursor(HSEPARATE_CURSOR, 0, 0);
892
893         int fx = mwindow->theme->afolders_x, fy = mwindow->theme->afolders_y;
894         int fw = mwindow->theme->afolders_w, fh = mwindow->theme->afolders_h;
895         VFrame **images = mwindow->theme->get_image_set("playpatch_data");
896         AVIconDrawing::calculate_geometry(this, images, &avicon_w, &avicon_h);
897         add_subwindow(avicon_drawing = new AVIconDrawing(this, fw-avicon_w, fy, images));
898         add_subwindow(add_tools = new AddTools(mwindow, this, fx, fy, _("Visibility")));
899         add_tools->create_objects();
900         fy += add_tools->get_h();  fh -= add_tools->get_h();
901         add_subwindow(folder_list = new AWindowFolders(mwindow,
902                 this, fx, fy, fw, fh));
903         update_effects();
904
905         //int x = mwindow->theme->abuttons_x;
906         //int y = mwindow->theme->abuttons_y;
907
908
909         newfolder_thread = new NewFolderThread(mwindow, this);
910
911         add_subwindow(asset_menu = new AssetPopup(mwindow, this));
912         asset_menu->create_objects();
913         add_subwindow(clip_menu = new ClipPopup(mwindow, this));
914         clip_menu->create_objects();
915         add_subwindow(label_menu = new LabelPopup(mwindow, this));
916         label_menu->create_objects();
917
918         add_subwindow(effectlist_menu = new EffectListMenu(mwindow, this));
919         effectlist_menu->create_objects();
920         add_subwindow(assetlist_menu = new AssetListMenu(mwindow, this));
921         assetlist_menu->create_objects();
922         add_subwindow(cliplist_menu = new ClipListMenu(mwindow, this));
923         cliplist_menu->create_objects();
924         add_subwindow(labellist_menu = new LabelListMenu(mwindow, this));
925         labellist_menu->create_objects();
926
927         add_subwindow(folderlist_menu = new FolderListMenu(mwindow, this));
928         folderlist_menu->create_objects();
929
930         create_custom_xatoms();
931         unlock_window();
932 }
933
934 int AWindowGUI::resize_event(int w, int h)
935 {
936         mwindow->session->awindow_x = get_x();
937         mwindow->session->awindow_y = get_y();
938         mwindow->session->awindow_w = w;
939         mwindow->session->awindow_h = h;
940
941         mwindow->theme->get_awindow_sizes(this);
942         mwindow->theme->draw_awindow_bg(this);
943         reposition_objects();
944
945 //      int x = mwindow->theme->abuttons_x;
946 //      int y = mwindow->theme->abuttons_y;
947 //      new_bin->reposition_window(x, y);
948 //      x += new_bin->get_w();
949 //      delete_bin->reposition_window(x, y);
950 //      x += delete_bin->get_w();
951 //      rename_bin->reposition_window(x, y);
952 //      x += rename_bin->get_w();
953 //      delete_disk->reposition_window(x, y);
954 //      x += delete_disk->get_w();
955 //      delete_project->reposition_window(x, y);
956 //      x += delete_project->get_w();
957 //      info->reposition_window(x, y);
958 //      x += info->get_w();
959 //      redraw_index->reposition_window(x, y);
960 //      x += redraw_index->get_w();
961 //      paste->reposition_window(x, y);
962 //      x += paste->get_w();
963 //      append->reposition_window(x, y);
964 //      x += append->get_w();
965 //      view->reposition_window(x, y);
966
967         BC_WindowBase::resize_event(w, h);
968         return 1;
969 }
970
971 int AWindowGUI::translation_event()
972 {
973         mwindow->session->awindow_x = get_x();
974         mwindow->session->awindow_y = get_y();
975         return 0;
976 }
977
978 void AWindowGUI::reposition_objects()
979 {
980         int x1 = mwindow->theme->alist_x, y1 = mwindow->theme->alist_y;
981         int w1 = mwindow->theme->alist_w, h1 = mwindow->theme->alist_h;
982         search_text->reposition_window(x1, y1+5, w1);
983         int dy = search_text->get_h() + 10;
984         y1 += dy;  h1 -= dy;
985         asset_list->reposition_window(x1, y1, w1, h1);
986         divider->reposition_window(
987                 mwindow->theme->adivider_x, mwindow->theme->adivider_y,
988                 mwindow->theme->adivider_w, mwindow->theme->adivider_h);
989         int fx = mwindow->theme->afolders_x, fy = mwindow->theme->afolders_y;
990         int fw = mwindow->theme->afolders_w, fh = mwindow->theme->afolders_h;
991         add_tools->resize_event(fw-avicon_w, add_tools->get_h());
992         avicon_drawing->reposition_window(fw-avicon_w, fy);
993         fy += add_tools->get_h();  fh -= add_tools->get_h();
994         folder_list->reposition_window(fx, fy, fw, fh);
995 }
996
997 int AWindowGUI::save_defaults(BC_Hash *defaults)
998 {
999         defaults->update("PLUGIN_VISIBILTY", plugin_visibility);
1000         defaults->update("VICON_DRAWING", vicon_drawing);
1001         return 0;
1002 }
1003
1004 int AWindowGUI::load_defaults(BC_Hash *defaults)
1005 {
1006         plugin_visibility = defaults->get("PLUGIN_VISIBILTY", plugin_visibility);
1007         vicon_drawing = defaults->get("VICON_DRAWING", vicon_drawing);
1008         return 0;
1009 }
1010
1011 int AWindowGUI::close_event()
1012 {
1013         hide_window();
1014         mwindow->session->show_awindow = 0;
1015         unlock_window();
1016
1017         mwindow->gui->lock_window("AWindowGUI::close_event");
1018         mwindow->gui->mainmenu->show_awindow->set_checked(0);
1019         mwindow->gui->unlock_window();
1020
1021         lock_window("AWindowGUI::close_event");
1022         save_defaults(mwindow->defaults);
1023         mwindow->save_defaults();
1024         return 1;
1025 }
1026
1027 void AWindowGUI::start_vicon_drawing()
1028 {
1029         if( !vicon_drawing ) return;
1030         if( mwindow->edl->session->awindow_folder != AW_MEDIA_FOLDER ) return;
1031         if( mwindow->edl->session->assetlist_format != ASSETS_ICONS ) return;
1032         vicon_thread->start_drawing();
1033 }
1034
1035 void AWindowGUI::stop_vicon_drawing()
1036 {
1037         vicon_thread->stop_drawing();
1038 }
1039
1040 AWindowRemovePluginGUI::
1041 AWindowRemovePluginGUI(AWindow *awindow, AWindowRemovePlugin *thread,
1042         int x, int y, PluginServer *plugin)
1043  : BC_Window(_(PROGRAM_NAME ": Remove plugin"), x,y, 500,200, 50, 50, 1, 0, 1, -1, "", 1)
1044 {
1045         this->awindow = awindow;
1046         this->thread = thread;
1047         this->plugin = plugin;
1048         VFrame *vframe = plugin->get_picon();
1049         icon = vframe ? create_pixmap(vframe) : 0;
1050         plugin_list.append(new BC_ListBoxItem(plugin->title, icon));
1051 }
1052
1053 AWindowRemovePluginGUI::
1054 ~AWindowRemovePluginGUI()
1055 {
1056         if( !awindow->gui->protected_pixmap(icon) )
1057                 delete icon;
1058         plugin_list.remove_all();
1059 }
1060
1061 void AWindowRemovePluginGUI::create_objects()
1062 {
1063         BC_Button *ok_button = new BC_OKButton(this);
1064         add_subwindow(ok_button);
1065         BC_Button *cancel_button = new BC_CancelButton(this);
1066         add_subwindow(cancel_button);
1067         int x = 10, y = 10;
1068         BC_Title *title = new BC_Title(x, y, _("remove plugin?"));
1069         add_subwindow(title);
1070         y += title->get_h() + 5;
1071         list = new BC_ListBox(x, y,
1072                 get_w() - 20, ok_button->get_y() - y - 5, LISTBOX_TEXT, &plugin_list,
1073                 0, 0, 1, 0, 0, LISTBOX_SINGLE, ICON_LEFT, 0);
1074         add_subwindow(list);
1075         show_window();
1076 }
1077
1078 int AWindowRemovePlugin::remove_plugin(PluginServer *plugin, ArrayList<BC_ListBoxItem*> &folder)
1079 {
1080         int ret = 0;
1081         for( int i=0; i<folder.size(); ) {
1082                 AssetPicon *picon = (AssetPicon *)folder[i];
1083                 if( picon->plugin == plugin ) {
1084                         folder.remove_object_number(i);
1085                         ++ret;
1086                         continue;
1087                 }
1088                 ++i;
1089         }
1090         return ret;
1091 }
1092
1093 void AWindowRemovePlugin::handle_close_event(int result)
1094 {
1095         if( !result ) {
1096                 printf(_("remove %s\n"), plugin->path);
1097                 awindow->gui->lock_window("AWindowRemovePlugin::handle_close_event");
1098                 ArrayList<BC_ListBoxItem*> *folder =
1099                         plugin->audio ? plugin->transition ?
1100                                 &awindow->gui->atransitions :
1101                                 &awindow->gui->aeffects :
1102                         plugin->video ?  plugin->transition ?
1103                                 &awindow->gui->vtransitions :
1104                                 &awindow->gui->veffects :
1105                         0;
1106                 if( folder ) remove_plugin(plugin, *folder);
1107                 MWindow *mwindow = awindow->mwindow;
1108                 awindow->gui->unlock_window();
1109                 char plugin_path[BCTEXTLEN];
1110                 strcpy(plugin_path, plugin->path);
1111                 mwindow->plugindb->remove(plugin);
1112                 remove(plugin_path);
1113                 char index_path[BCTEXTLEN];
1114                 mwindow->create_defaults_path(index_path, PLUGIN_FILE);
1115                 remove(index_path);
1116                 char picon_path[BCTEXTLEN];
1117                 FileSystem fs;
1118                 snprintf(picon_path, sizeof(picon_path), "%s/picon",
1119                         File::get_plugin_path());
1120                 char png_name[BCSTRLEN], png_path[BCTEXTLEN];
1121                 plugin->get_plugin_png_name(png_name);
1122                 fs.update(picon_path);
1123                 for( int i=0; i<fs.dir_list.total; ++i ) {
1124                         char *fs_path = fs.dir_list[i]->path;
1125                         if( !fs.is_dir(fs_path) ) continue;
1126                         snprintf(png_path, sizeof(picon_path), "%s/%s",
1127                                 fs_path, png_name);
1128                         remove(png_path);
1129                 }
1130                 delete plugin;  plugin = 0;
1131                 awindow->gui->async_update_assets();
1132         }
1133 }
1134
1135 AWindowRemovePlugin::
1136 AWindowRemovePlugin(AWindow *awindow, PluginServer *plugin)
1137  : BC_DialogThread()
1138 {
1139         this->awindow = awindow;
1140         this->plugin = plugin;
1141 }
1142
1143 AWindowRemovePlugin::
1144 ~AWindowRemovePlugin()
1145 {
1146         close_window();
1147 }
1148
1149 BC_Window* AWindowRemovePlugin::new_gui()
1150 {
1151         int x = awindow->gui->get_abs_cursor_x(0);
1152         int y = awindow->gui->get_abs_cursor_y(0);
1153         AWindowRemovePluginGUI *gui = new AWindowRemovePluginGUI(awindow, this, x, y, plugin);
1154         gui->create_objects();
1155         return gui;
1156 }
1157
1158 int AWindowGUI::keypress_event()
1159 {
1160         switch( get_keypress() ) {
1161         case 'w': case 'W':
1162                 if( ctrl_down() ) {
1163                         close_event();
1164                         return 1;
1165                 }
1166                 break;
1167         case DELETE:
1168                 if( shift_down() ) {
1169                         PluginServer* plugin = selected_plugin();
1170                         if( !plugin ) break;
1171                         remove_plugin = new AWindowRemovePlugin(awindow, plugin);
1172                         unlock_window();
1173                         remove_plugin->start();
1174                         lock_window();
1175                 }
1176         }
1177         return 0;
1178 }
1179
1180
1181
1182 int AWindowGUI::create_custom_xatoms()
1183 {
1184         UpdateAssetsXAtom = create_xatom("CWINDOWGUI_UPDATE_ASSETS");
1185         return 0;
1186 }
1187 int AWindowGUI::recieve_custom_xatoms(xatom_event *event)
1188 {
1189         if( event->message_type == UpdateAssetsXAtom ) {
1190                 update_assets();
1191                 return 1;
1192         }
1193         return 0;
1194 }
1195
1196 void AWindowGUI::async_update_assets()
1197 {
1198         xatom_event event;
1199         event.message_type = UpdateAssetsXAtom;
1200         send_custom_xatom(&event);
1201 }
1202
1203
1204 void AWindowGUI::update_folder_list()
1205 {
1206         for( int i = 0; i < folders.total; i++ ) {
1207                 AssetPicon *picon = (AssetPicon*)folders.values[i];
1208                 picon->in_use = 0;
1209         }
1210
1211 // Search assets for folders
1212         for( int i = 0; i < mwindow->edl->folders.total; i++ ) {
1213                 const char *folder = mwindow->edl->folders.values[i];
1214                 int exists = 0;
1215
1216                 for( int j = 0; j < folders.total; j++ ) {
1217                         AssetPicon *picon = (AssetPicon*)folders.values[j];
1218                         if( !strcasecmp(picon->get_text(), folder) ) {
1219                                 exists = 1;
1220                                 picon->in_use = 1;
1221                                 break;
1222                         }
1223                 }
1224
1225                 if( !exists ) {
1226                         int aw_folder = folder_number(folder);
1227                         if( aw_folder >= 0 ) {
1228                                 AssetPicon *picon = new AssetPicon(mwindow, this, aw_folder, 1);
1229                                 picon->create_objects();
1230                                 folders.append(picon);
1231                         }
1232                 }
1233         }
1234
1235 // Delete unused non-persistent folders
1236         for( int i=folders.total; --i>=0; ) {
1237                 AssetPicon *picon = (AssetPicon*)folders.values[i];
1238                 if( !picon->in_use && !picon->persistent ) {
1239                         delete picon;
1240                         folders.remove_number(i);
1241                 }
1242         }
1243 }
1244
1245 void AWindowGUI::create_persistent_folder(ArrayList<BC_ListBoxItem*> *output,
1246         int do_audio, int do_video, int is_realtime, int is_transition)
1247 {
1248         ArrayList<PluginServer*> plugin_list;
1249 // Get pointers to plugindb entries
1250         mwindow->search_plugindb(do_audio, do_video, is_realtime, is_transition,
1251                         0, plugin_list);
1252
1253         for( int i = 0; i < plugin_list.total; i++ ) {
1254                 PluginServer *server = plugin_list.values[i];
1255                 int visible = plugin_visibility & (1<<server->dir_idx);
1256                 if( !visible ) continue;
1257 // Create new listitem
1258                 AssetPicon *picon = new AssetPicon(mwindow, this, server);
1259                 picon->create_objects();
1260                 output->append(picon);
1261         }
1262 }
1263
1264 void AWindowGUI::create_label_folder()
1265 {
1266         Label *current;
1267         for( current = mwindow->edl->labels->first; current; current = NEXT ) {
1268                 AssetPicon *picon = new AssetPicon(mwindow, this, current);
1269                 picon->create_objects();
1270                 labellist.append(picon);
1271         }
1272 }
1273
1274
1275 void AWindowGUI::update_asset_list()
1276 {
1277         for( int i = 0; i < assets.total; i++ ) {
1278                 AssetPicon *picon = (AssetPicon*)assets.values[i];
1279                 picon->in_use = 0;
1280         }
1281
1282 // Synchronize EDL clips
1283         for( int i=0; i<mwindow->edl->clips.size(); ++i ) {
1284                 int exists = 0;
1285
1286 // Look for clip in existing listitems
1287                 for( int j = 0; j < assets.total && !exists; j++ ) {
1288                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1289
1290                         if( picon->id == mwindow->edl->clips[i]->id ) {
1291                                 picon->edl = mwindow->edl->clips[i];
1292                                 picon->set_text(mwindow->edl->clips[i]->local_session->clip_title);
1293                                 exists = 1;
1294                                 picon->in_use = 1;
1295                         }
1296                 }
1297
1298 // Create new listitem
1299                 if( !exists ) {
1300                         AssetPicon *picon = new AssetPicon(mwindow,
1301                                 this, mwindow->edl->clips[i]);
1302                         picon->create_objects();
1303                         assets.append(picon);
1304                 }
1305         }
1306
1307 // Synchronize EDL assets
1308         for( Asset *current=mwindow->edl->assets->first; current; current=NEXT ) {
1309                 int exists = 0;
1310
1311 // Look for asset in existing listitems
1312                 for( int j = 0; j < assets.total && !exists; j++ ) {
1313                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1314
1315                         if( picon->id == current->id ) {
1316                                 picon->indexable = current;
1317                                 picon->in_use = 1;
1318                                 exists = 1;
1319                         }
1320                 }
1321
1322 // Create new listitem
1323                 if( !exists ) {
1324                         AssetPicon *picon = new AssetPicon(mwindow,
1325                                 this, current);
1326                         picon->create_objects();
1327                         assets.append(picon);
1328                 }
1329         }
1330
1331         mwindow->gui->lock_window("AWindowGUI::update_asset_list");
1332         mwindow->gui->default_message();
1333         mwindow->gui->unlock_window();
1334
1335 // Synchronize nested EDLs
1336         for( int i=0; i<mwindow->edl->nested_edls.size(); ++i ) {
1337                 int exists = 0;
1338                 EDL *nested_edl = mwindow->edl->nested_edls[i];
1339
1340 // Look for asset in existing listitems
1341                 for( int j=0; j<assets.total && !exists; ++j ) {
1342                         AssetPicon *picon = (AssetPicon*)assets.values[j];
1343
1344                         if( picon->id == nested_edl->id ) {
1345                                 picon->indexable = nested_edl;
1346                                 picon->in_use = 1;
1347                                 exists = 1;
1348                         }
1349                 }
1350
1351 // Create new listitem
1352                 if( !exists ) {
1353                         AssetPicon *picon = new AssetPicon(mwindow,
1354                                 this, (Indexable*)nested_edl);
1355                         picon->create_objects();
1356                         assets.append(picon);
1357                 }
1358         }
1359
1360         for( int i = assets.size() - 1; i >= 0; i-- ) {
1361                 AssetPicon *picon = (AssetPicon*)assets.get(i);
1362                 if( !picon->in_use ) {
1363                         delete picon;
1364                         assets.remove_number(i);
1365                         continue;
1366                 }
1367                 if( !picon->indexable || !picon->indexable->is_asset ) continue;
1368                 struct stat st;
1369                 picon->mtime = !stat(picon->indexable->path, &st) ? st.st_mtime : 0;
1370         }
1371 }
1372
1373 void AWindowGUI::update_picon(Indexable *indexable)
1374 {
1375         VIcon *vicon = 0;
1376         for( int i = 0; i < assets.total; i++ ) {
1377                 AssetPicon *picon = (AssetPicon*)assets.values[i];
1378                 if( picon->indexable == indexable ||
1379                     picon->edl == (EDL *)indexable ) {
1380                         char name[BCTEXTLEN];
1381                         FileSystem fs;
1382                         fs.extract_name(name, indexable->path);
1383                         picon->set_text(name);
1384                         vicon = picon->vicon;
1385                         break;
1386                 }
1387         }
1388         if( vicon ) {
1389                 stop_vicon_drawing();
1390                 vicon->clear_images();
1391                 vicon->reset(indexable->get_frame_rate());
1392                 start_vicon_drawing();
1393         }
1394 }
1395
1396 void AWindowGUI::sort_assets(int use_mtime)
1397 {
1398         switch( mwindow->edl->session->awindow_folder ) {
1399         case AW_AEFFECT_FOLDER:
1400                 sort_picons(&aeffects);
1401                 break;
1402         case AW_VEFFECT_FOLDER:
1403                 sort_picons(&veffects);
1404                 break;
1405         case AW_ATRANSITION_FOLDER:
1406                 sort_picons(&atransitions);
1407                 break;
1408         case AW_VTRANSITION_FOLDER:
1409                 sort_picons(&vtransitions);
1410                 break;
1411         case AW_LABEL_FOLDER:
1412                 sort_picons(&labellist);
1413                 break;
1414         default:
1415                 sort_picons(&assets, use_mtime);
1416         }
1417 // reset xyposition
1418         asset_list->update_format(asset_list->get_format(), 0);
1419         update_assets();
1420 }
1421
1422 void AWindowGUI::sort_folders()
1423 {
1424         sort_picons(&folders);
1425         folder_list->update_format(folder_list->get_format(), 0);
1426         update_assets();
1427 }
1428
1429 void AWindowGUI::collect_assets()
1430 {
1431         int i = 0;
1432         mwindow->session->drag_assets->remove_all();
1433         mwindow->session->drag_clips->remove_all();
1434         while(1)
1435         {
1436                 AssetPicon *result = (AssetPicon*)asset_list->get_selection(0, i++);
1437                 if( !result ) break;
1438
1439                 if( result->indexable ) mwindow->session->drag_assets->append(result->indexable);
1440                 if( result->edl ) mwindow->session->drag_clips->append(result->edl);
1441         }
1442 }
1443
1444 void AWindowGUI::copy_picons(ArrayList<BC_ListBoxItem*> *dst,
1445         ArrayList<BC_ListBoxItem*> *src, int folder)
1446 {
1447 // Remove current pointers
1448         dst[0].remove_all();
1449         dst[1].remove_all_objects();
1450
1451 // Create new pointers
1452         for( int i = 0; i < src->total; i++ ) {
1453                 AssetPicon *picon = (AssetPicon*)src->values[i];
1454                 if( folder < 0 ||
1455                     (picon->indexable && picon->indexable->awindow_folder == folder) ||
1456                     (picon->edl && picon->edl->local_session->awindow_folder == folder) ) {
1457                         const char *text = search_text->get_text();
1458                         int hidden = text && text[0] && !bstrcasestr(picon->get_text(), text);
1459                         if( picon->vicon ) picon->vicon->hidden = hidden;
1460                         if( hidden ) continue;
1461                         BC_ListBoxItem *item2, *item1;
1462                         dst[0].append(item1 = picon);
1463                         if( picon->edl )
1464                                 dst[1].append(item2 = new BC_ListBoxItem(picon->edl->local_session->clip_notes));
1465                         else
1466                         if( picon->label && picon->label->textstr )
1467                                 dst[1].append(item2 = new BC_ListBoxItem(picon->label->textstr));
1468                         else if( picon->mtime ) {
1469                                 char date_time[BCSTRLEN];
1470                                 struct tm stm;  localtime_r(&picon->mtime, &stm);
1471                                 sprintf(date_time,"%04d.%02d.%02d %02d:%02d:%02d",
1472                                          stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
1473                                          stm.tm_hour, stm.tm_min, stm.tm_sec);
1474                                 dst[1].append(item2 = new BC_ListBoxItem(date_time));
1475                         }
1476                         else
1477                                 dst[1].append(item2 = new BC_ListBoxItem(""));
1478                         item1->set_autoplace_text(1);  item1->set_autoplace_icon(1);
1479                         item2->set_autoplace_text(1);  item2->set_autoplace_icon(1);
1480                 }
1481         }
1482 }
1483
1484 void AWindowGUI::sort_picons(ArrayList<BC_ListBoxItem*> *src, int use_mtime)
1485 {
1486         int done = 0, changed = 0;
1487         while( !done ) {
1488                 done = 1;
1489                 for( int i=0; i<src->total-1; ++i ) {
1490                         AssetPicon *item1 = (AssetPicon *)src->values[i];
1491                         AssetPicon *item2 = (AssetPicon *)src->values[i + 1];
1492                         if( use_mtime ? item1->mtime > item2->mtime :
1493                             strcmp(item1->get_text(), item2->get_text()) > 0 ) {
1494                                 src->values[i + 1] = item1;
1495                                 src->values[i] = item2;
1496                                 done = 0;  changed = 1;
1497                         }
1498                 }
1499         }
1500         if( changed ) {
1501                 for( int i=0; i<src->total; ++i ) {
1502                         AssetPicon *item = (AssetPicon *)src->values[i];
1503                         item->set_autoplace_icon(1);
1504                         item->set_autoplace_text(1);
1505                 }
1506         }
1507 }
1508
1509
1510 void AWindowGUI::filter_displayed_assets()
1511 {
1512         //allow_iconlisting = 1;
1513         asset_titles[0] = C_("Title");
1514         asset_titles[1] = _("Comments");
1515
1516         switch( mwindow->edl->session->awindow_folder ) {
1517         case AW_AEFFECT_FOLDER:
1518                 copy_picons(displayed_assets, &aeffects, AW_NO_FOLDER);
1519                 break;
1520         case AW_VEFFECT_FOLDER:
1521                 copy_picons(displayed_assets, &veffects, AW_NO_FOLDER);
1522                 break;
1523         case AW_ATRANSITION_FOLDER:
1524                 copy_picons(displayed_assets, &atransitions, AW_NO_FOLDER);
1525                 break;
1526         case AW_VTRANSITION_FOLDER:
1527                 copy_picons(displayed_assets, &vtransitions, AW_NO_FOLDER);
1528                 break;
1529         case AW_LABEL_FOLDER:
1530                 copy_picons(displayed_assets, &labellist, AW_NO_FOLDER);
1531                 asset_titles[0] = _("Time Stamps");
1532                 asset_titles[1] = C_("Title");
1533                 //allow_iconlisting = 0;
1534                 break;
1535         default:
1536                 copy_picons(displayed_assets, &assets, mwindow->edl->session->awindow_folder);
1537                 break;
1538         }
1539
1540         // Ensure the current folder icon is highlighted
1541         int selected_folder = mwindow->edl->session->awindow_folder;
1542         for( int i = 0; i < folders.total; i++ ) {
1543                 AssetPicon *folder_item = (AssetPicon *)folders.values[i];
1544                 int selected = folder_item->foldernum == selected_folder ? 1 : 0;
1545                 folder_item->set_selected(selected);
1546         }
1547 }
1548
1549
1550 void AWindowGUI::update_assets()
1551 {
1552         stop_vicon_drawing();
1553         update_folder_list();
1554         update_asset_list();
1555         labellist.remove_all_objects();
1556         create_label_folder();
1557
1558         if( displayed_folder != mwindow->edl->session->awindow_folder )
1559                 search_text->clear();
1560         filter_displayed_assets();
1561
1562         if( mwindow->edl->session->folderlist_format != folder_list->get_format() ) {
1563                 folder_list->update_format(mwindow->edl->session->folderlist_format, 0);
1564         }
1565         int folder_xposition = folder_list->get_xposition();
1566         int folder_yposition = folder_list->get_yposition();
1567         folder_list->update(&folders, 0, 0, 1, folder_xposition, folder_yposition, -1);
1568
1569         if( mwindow->edl->session->assetlist_format != asset_list->get_format() ) {
1570                 asset_list->update_format(mwindow->edl->session->assetlist_format, 0);
1571         }
1572         int asset_xposition = asset_list->get_xposition();
1573         int asset_yposition = asset_list->get_yposition();
1574         if( displayed_folder != mwindow->edl->session->awindow_folder ) {
1575                 displayed_folder = mwindow->edl->session->awindow_folder;
1576                 asset_xposition = asset_yposition = 0;
1577         }
1578         asset_list->update(displayed_assets, asset_titles,
1579                 mwindow->edl->session->asset_columns, ASSET_COLUMNS,
1580                 asset_xposition, asset_yposition, -1, 0);
1581         asset_list->center_selection();
1582
1583         flush();
1584         start_vicon_drawing();
1585         return;
1586 }
1587
1588 void AWindowGUI::update_effects()
1589 {
1590         aeffects.remove_all_objects();
1591         create_persistent_folder(&aeffects, 1, 0, 1, 0);
1592         veffects.remove_all_objects();
1593         create_persistent_folder(&veffects, 0, 1, 1, 0);
1594         atransitions.remove_all_objects();
1595         create_persistent_folder(&atransitions, 1, 0, 0, 1);
1596         vtransitions.remove_all_objects();
1597         create_persistent_folder(&vtransitions, 0, 1, 0, 1);
1598 }
1599
1600 int AWindowGUI::folder_number(const char *name)
1601 {
1602         for( int i = 0; i < AWINDOW_FOLDERS; i++ ) {
1603                 if( !strcasecmp(name, folder_names[i]) ) return i;
1604         }
1605         return AW_NO_FOLDER;
1606 }
1607
1608 int AWindowGUI::drag_motion()
1609 {
1610         if( get_hidden() ) return 0;
1611
1612         int result = 0;
1613         return result;
1614 }
1615
1616 int AWindowGUI::drag_stop()
1617 {
1618         if( get_hidden() ) return 0;
1619
1620         return 0;
1621 }
1622
1623 Indexable* AWindowGUI::selected_asset()
1624 {
1625         AssetPicon *picon = (AssetPicon*)asset_list->get_selection(0, 0);
1626         return picon ? picon->indexable : 0;
1627 }
1628
1629 PluginServer* AWindowGUI::selected_plugin()
1630 {
1631         AssetPicon *picon = (AssetPicon*)asset_list->get_selection(0, 0);
1632         return picon ? picon->plugin : 0;
1633 }
1634
1635 AssetPicon* AWindowGUI::selected_folder()
1636 {
1637         AssetPicon *picon = (AssetPicon*)folder_list->get_selection(0, 0);
1638         return picon;
1639 }
1640
1641
1642
1643
1644
1645
1646
1647
1648 AWindowDivider::AWindowDivider(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
1649  : BC_SubWindow(x, y, w, h)
1650 {
1651         this->mwindow = mwindow;
1652         this->gui = gui;
1653 }
1654 AWindowDivider::~AWindowDivider()
1655 {
1656 }
1657
1658 int AWindowDivider::button_press_event()
1659 {
1660         if( is_event_win() && cursor_inside() ) {
1661                 mwindow->session->current_operation = DRAG_PARTITION;
1662                 return 1;
1663         }
1664         return 0;
1665 }
1666
1667 int AWindowDivider::cursor_motion_event()
1668 {
1669         if( mwindow->session->current_operation == DRAG_PARTITION ) {
1670                 int wmin = 25;
1671                 int wmax = mwindow->session->awindow_w - mwindow->theme->adivider_w - wmin;
1672                 int fw = gui->get_relative_cursor_x();
1673                 if( fw > wmax ) fw = wmax;
1674                 if( fw < wmin ) fw = wmin;
1675                 mwindow->session->afolders_w = fw;
1676                 mwindow->theme->get_awindow_sizes(gui);
1677                 gui->reposition_objects();
1678                 gui->flush();
1679         }
1680         return 0;
1681 }
1682
1683 int AWindowDivider::button_release_event()
1684 {
1685         if( mwindow->session->current_operation == DRAG_PARTITION ) {
1686                 mwindow->session->current_operation = NO_OPERATION;
1687                 return 1;
1688         }
1689         return 0;
1690 }
1691
1692
1693
1694
1695
1696
1697 AWindowFolders::AWindowFolders(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
1698  : BC_ListBox(x, y, w, h,
1699                 mwindow->edl->session->folderlist_format == ASSETS_ICONS ?
1700                         LISTBOX_ICONS : LISTBOX_TEXT,
1701                 &gui->folders,    // Each column has an ArrayList of BC_ListBoxItems.
1702                 0,                // Titles for columns.  Set to 0 for no titles
1703                 0,                // width of each column
1704                 1,                // Total columns.
1705                 0,                // Pixel of top of window.
1706                 0,                // If this listbox is a popup window
1707                 LISTBOX_SINGLE,   // Select one item or multiple items
1708                 ICON_TOP,         // Position of icon relative to text of each item
1709                 1)                // Allow drags
1710 {
1711         this->mwindow = mwindow;
1712         this->gui = gui;
1713         set_drag_scroll(0);
1714 }
1715
1716 AWindowFolders::~AWindowFolders()
1717 {
1718 }
1719
1720 int AWindowFolders::selection_changed()
1721 {
1722         AssetPicon *picon = (AssetPicon*)get_selection(0, 0);
1723         if( picon ) {
1724                 gui->stop_vicon_drawing();
1725
1726                 if( get_button_down() && get_buttonpress() == 3 ) {
1727                         gui->folderlist_menu->update_titles();
1728                         gui->folderlist_menu->activate_menu();
1729                 }
1730
1731                 mwindow->edl->session->awindow_folder = picon->foldernum;
1732                 gui->asset_list->draw_background();
1733                 gui->async_update_assets();
1734
1735                 gui->start_vicon_drawing();
1736         }
1737         return 1;
1738 }
1739
1740 int AWindowFolders::button_press_event()
1741 {
1742         int result = 0;
1743
1744         result = BC_ListBox::button_press_event();
1745
1746         if( !result ) {
1747                 if( get_buttonpress() == 3 && is_event_win() && cursor_inside() ) {
1748                         gui->folderlist_menu->update_titles();
1749                         gui->folderlist_menu->activate_menu();
1750                         result = 1;
1751                 }
1752         }
1753
1754
1755         return result;
1756 }
1757
1758
1759
1760
1761
1762
1763
1764 AWindowAssets::AWindowAssets(MWindow *mwindow, AWindowGUI *gui, int x, int y, int w, int h)
1765  : BC_ListBox(x, y, w, h,
1766                 (mwindow->edl->session->assetlist_format == ASSETS_ICONS && gui->allow_iconlisting ) ?
1767                         LISTBOX_ICONS : LISTBOX_TEXT,
1768                 &gui->assets,     // Each column has an ArrayList of BC_ListBoxItems.
1769                 gui->asset_titles,// Titles for columns.  Set to 0 for no titles
1770                 mwindow->edl->session->asset_columns, // width of each column
1771                 1,                // Total columns.
1772                 0,                // Pixel of top of window.
1773                 0,                // If this listbox is a popup window
1774                 LISTBOX_MULTIPLE, // Select one item or multiple items
1775                 ICON_TOP,         // Position of icon relative to text of each item
1776                 -1)               // Allow drags, require shift for scrolling
1777 {
1778         this->mwindow = mwindow;
1779         this->gui = gui;
1780         set_drag_scroll(0);
1781         set_scroll_stretch(1, 1);
1782 }
1783
1784 AWindowAssets::~AWindowAssets()
1785 {
1786 }
1787
1788 int AWindowAssets::button_press_event()
1789 {
1790         int result = 0;
1791
1792         result = BC_ListBox::button_press_event();
1793
1794         if( !result && get_buttonpress() == 3 && is_event_win() && cursor_inside() ) {
1795                 BC_ListBox::deactivate_selection();
1796                 int folder = mwindow->edl->session->awindow_folder;
1797                 switch( folder ) {
1798                 case AW_AEFFECT_FOLDER:
1799                 case AW_VEFFECT_FOLDER:
1800                 case AW_ATRANSITION_FOLDER:
1801                 case AW_VTRANSITION_FOLDER:
1802                         gui->effectlist_menu->update();
1803                         gui->effectlist_menu->activate_menu();
1804                         break;
1805                 case AW_LABEL_FOLDER:
1806                         gui->labellist_menu->update();
1807                         gui->labellist_menu->activate_menu();
1808                         break;
1809                 case AW_CLIP_FOLDER:
1810                         gui->cliplist_menu->update();
1811                         gui->cliplist_menu->activate_menu();
1812                         break;
1813                 case AW_MEDIA_FOLDER:
1814                 case AW_PROXY_FOLDER:
1815                         gui->assetlist_menu->update_titles(folder==AW_MEDIA_FOLDER);
1816                         gui->assetlist_menu->activate_menu();
1817                         break;
1818                 }
1819                 result = 1;
1820         }
1821
1822         return result;
1823 }
1824
1825
1826 int AWindowAssets::handle_event()
1827 {
1828         AssetPicon *asset_picon = (AssetPicon *)get_selection(0, 0);
1829         if( !asset_picon ) return 0;
1830         switch( mwindow->edl->session->awindow_folder ) {
1831         case AW_AEFFECT_FOLDER:
1832         case AW_VEFFECT_FOLDER:
1833         case AW_ATRANSITION_FOLDER:
1834         case AW_VTRANSITION_FOLDER: return 1;
1835         }
1836         VWindow *vwindow = mwindow->vwindows.size() > DEFAULT_VWINDOW ?
1837                 mwindow->vwindows.get(DEFAULT_VWINDOW) : 0;
1838         if( !vwindow || !vwindow->is_running() ) return 1;
1839
1840         if( asset_picon->indexable )
1841                 vwindow->change_source(asset_picon->indexable);
1842         else if( asset_picon->edl )
1843                 vwindow->change_source(asset_picon->edl);
1844         return 1;
1845 }
1846
1847 int AWindowAssets::selection_changed()
1848 {
1849 // Show popup window
1850         AssetPicon *item;
1851         if( get_button_down() && get_buttonpress() == 3 &&
1852             (item = (AssetPicon*)get_selection(0, 0)) ) {
1853                 int folder = mwindow->edl->session->awindow_folder;
1854                 switch( folder ) {
1855                 case AW_AEFFECT_FOLDER:
1856                 case AW_VEFFECT_FOLDER:
1857                 case AW_ATRANSITION_FOLDER:
1858                 case AW_VTRANSITION_FOLDER:
1859                         gui->effectlist_menu->update();
1860                         gui->effectlist_menu->activate_menu();
1861                         break;
1862                 case AW_LABEL_FOLDER:
1863                         if( !item->label ) break;
1864                         gui->label_menu->activate_menu();
1865                         break;
1866                 case AW_CLIP_FOLDER:
1867                         if( !item->indexable && !item->edl ) break;
1868                         gui->clip_menu->update();
1869                         gui->clip_menu->activate_menu();
1870                         break;
1871                 default:
1872                         if( !item->indexable && !item->edl ) break;
1873                         gui->asset_menu->update();
1874                         gui->asset_menu->activate_menu();
1875                         break;
1876                 }
1877
1878                 BC_ListBox::deactivate_selection();
1879                 return 1;
1880         }
1881         else if( gui->vicon_drawing &&
1882                  get_button_down() && get_buttonpress() == 1 &&
1883                  (item = (AssetPicon*)get_selection(0, 0)) ) {
1884                 VIcon *vicon = 0;
1885                 if( !gui->vicon_thread->viewing ) {
1886                         vicon = item->vicon;
1887                 }
1888                 gui->vicon_thread->set_view_popup(vicon);
1889
1890         }
1891         return 0;
1892 }
1893
1894 void AWindowAssets::draw_background()
1895 {
1896         clear_box(0,0,get_w(),get_h(),get_bg_surface());
1897         set_color(BC_WindowBase::get_resources()->audiovideo_color);
1898         set_font(LARGEFONT);
1899         int aw_folder = mwindow->edl->session->awindow_folder;
1900         if( aw_folder < 0 ) return;
1901         const char *aw_name = _(AWindowGUI::folder_names[aw_folder]);
1902         draw_text(get_w() - get_text_width(LARGEFONT, aw_name) - 4, 30,
1903                 aw_name, -1, get_bg_surface());
1904 }
1905
1906 int AWindowAssets::drag_start_event()
1907 {
1908         int collect_pluginservers = 0;
1909         int collect_assets = 0;
1910
1911         if( BC_ListBox::drag_start_event() ) {
1912                 switch( mwindow->edl->session->awindow_folder ) {
1913                 case AW_AEFFECT_FOLDER:
1914                         mwindow->session->current_operation = DRAG_AEFFECT;
1915                         collect_pluginservers = 1;
1916                         break;
1917                 case AW_VEFFECT_FOLDER:
1918                         mwindow->session->current_operation = DRAG_VEFFECT;
1919                         collect_pluginservers = 1;
1920                         break;
1921                 case AW_ATRANSITION_FOLDER:
1922                         mwindow->session->current_operation = DRAG_ATRANSITION;
1923                         collect_pluginservers = 1;
1924                         break;
1925                 case AW_VTRANSITION_FOLDER:
1926                         mwindow->session->current_operation = DRAG_VTRANSITION;
1927                         collect_pluginservers = 1;
1928                         break;
1929                 case AW_LABEL_FOLDER:
1930                         // do nothing!
1931                         break;
1932                 default:
1933                         mwindow->session->current_operation = DRAG_ASSET;
1934                         collect_assets = 1;
1935                         break;
1936                 }
1937
1938                 if( collect_pluginservers ) {
1939                         int i = 0;
1940                         mwindow->session->drag_pluginservers->remove_all();
1941                         while(1)
1942                         {
1943                                 AssetPicon *result = (AssetPicon*)get_selection(0, i++);
1944                                 if( !result ) break;
1945
1946                                 mwindow->session->drag_pluginservers->append(result->plugin);
1947                         }
1948                 }
1949
1950                 if( collect_assets ) {
1951                         gui->collect_assets();
1952                 }
1953
1954                 return 1;
1955         }
1956         return 0;
1957 }
1958
1959 int AWindowAssets::drag_motion_event()
1960 {
1961         BC_ListBox::drag_motion_event();
1962         unlock_window();
1963
1964         mwindow->gui->lock_window("AWindowAssets::drag_motion_event");
1965         mwindow->gui->drag_motion();
1966         mwindow->gui->unlock_window();
1967
1968         for( int i = 0; i < mwindow->vwindows.size(); i++ ) {
1969                 VWindow *vwindow = mwindow->vwindows.get(i);
1970                 if( !vwindow->is_running() ) continue;
1971                 vwindow->gui->lock_window("AWindowAssets::drag_motion_event");
1972                 vwindow->gui->drag_motion();
1973                 vwindow->gui->unlock_window();
1974         }
1975
1976         mwindow->cwindow->gui->lock_window("AWindowAssets::drag_motion_event");
1977         mwindow->cwindow->gui->drag_motion();
1978         mwindow->cwindow->gui->unlock_window();
1979
1980         lock_window("AWindowAssets::drag_motion_event");
1981         return 0;
1982 }
1983
1984 int AWindowAssets::drag_stop_event()
1985 {
1986         int result = 0;
1987
1988         result = gui->drag_stop();
1989
1990         unlock_window();
1991
1992         if( !result ) {
1993                 mwindow->gui->lock_window("AWindowAssets::drag_stop_event");
1994                 result = mwindow->gui->drag_stop();
1995                 mwindow->gui->unlock_window();
1996         }
1997
1998         if( !result ) {
1999                 for( int i = 0; !result && i < mwindow->vwindows.size(); i++ ) {
2000                         VWindow *vwindow = mwindow->vwindows.get(i);
2001                         if( !vwindow ) continue;
2002                         if( !vwindow->is_running() ) continue;
2003                         if( vwindow->gui->is_hidden() ) continue;
2004                         vwindow->gui->lock_window("AWindowAssets::drag_stop_event");
2005                         if( vwindow->gui->cursor_above() &&
2006                             vwindow->gui->get_cursor_over_window() ) {
2007                                 result = vwindow->gui->drag_stop();
2008                         }
2009                         vwindow->gui->unlock_window();
2010                 }
2011         }
2012
2013         if( !result ) {
2014                 mwindow->cwindow->gui->lock_window("AWindowAssets::drag_stop_event");
2015                 result = mwindow->cwindow->gui->drag_stop();
2016                 mwindow->cwindow->gui->unlock_window();
2017         }
2018
2019         lock_window("AWindowAssets::drag_stop_event");
2020
2021         if( result )
2022                 get_drag_popup()->set_animation(0);
2023
2024         BC_ListBox::drag_stop_event();
2025 // since NO_OPERATION is also defined in listbox, we have to reach for global scope...
2026         mwindow->session->current_operation = ::NO_OPERATION;
2027         return 1;
2028 }
2029
2030 int AWindowAssets::column_resize_event()
2031 {
2032         mwindow->edl->session->asset_columns[0] = get_column_width(0);
2033         mwindow->edl->session->asset_columns[1] = get_column_width(1);
2034         return 1;
2035 }
2036
2037 int AWindowAssets::focus_in_event()
2038 {
2039         gui->start_vicon_drawing();
2040         return 0;
2041 }
2042
2043 int AWindowAssets::focus_out_event()
2044 {
2045         gui->stop_vicon_drawing();
2046         return BC_ListBox::focus_out_event();
2047 }
2048
2049 AWindowSearchTextBox::AWindowSearchTextBox(AWindowSearchText *search_text, int x, int y, int w)
2050  : BC_TextBox(x, y, w, 1, "")
2051 {
2052         this->search_text = search_text;
2053 }
2054
2055 int AWindowSearchTextBox::handle_event()
2056 {
2057         return search_text->handle_event();
2058 }
2059
2060 AWindowSearchText::AWindowSearchText(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2061 {
2062         this->mwindow = mwindow;
2063         this->gui = gui;
2064         this->x = x;
2065         this->y = y;
2066 }
2067
2068 void AWindowSearchText::create_objects()
2069 {
2070         int x1 = x, y1 = y, margin = 10;
2071         gui->add_subwindow(text_title = new BC_Title(x1, y1, _("Search:")));
2072         x1 += text_title->get_w() + margin;
2073         int w1 = gui->get_w() - x1 - 2*margin;
2074         gui->add_subwindow(text_box = new AWindowSearchTextBox(this, x1, y1, w1));
2075 }
2076
2077 int AWindowSearchText::handle_event()
2078 {
2079         gui->async_update_assets();
2080         return 1;
2081 }
2082
2083 int AWindowSearchText::get_w()
2084 {
2085         return text_box->get_w() + text_title->get_w() + 10;
2086 }
2087
2088 int AWindowSearchText::get_h()
2089 {
2090         return bmax(text_box->get_h(),text_title->get_h());
2091 }
2092
2093 void AWindowSearchText::reposition_window(int x, int y, int w)
2094 {
2095         int x1 = x, y1 = y, margin = 10;
2096         text_title->reposition_window(x1, y1);
2097         x1 += text_title->get_w() + margin;
2098         int w1 = gui->get_w() - x1 - 2*margin;
2099         text_box->reposition_window(x1, y1, w1);
2100 }
2101
2102 const char *AWindowSearchText::get_text()
2103 {
2104         return text_box->get_text();
2105 }
2106
2107 void AWindowSearchText::clear()
2108 {
2109         text_box->update("");
2110 }
2111
2112 AWindowNewFolder::AWindowNewFolder(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2113  : BC_Button(x, y, mwindow->theme->newbin_data)
2114 {
2115         this->mwindow = mwindow;
2116         this->gui = gui;
2117         set_tooltip(_("New bin"));
2118 }
2119
2120 int AWindowNewFolder::handle_event()
2121 {
2122         gui->newfolder_thread->start_new_folder();
2123         return 1;
2124 }
2125
2126 AWindowDeleteFolder::AWindowDeleteFolder(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2127  : BC_Button(x, y, mwindow->theme->deletebin_data)
2128 {
2129         this->mwindow = mwindow;
2130         this->gui = gui;
2131         set_tooltip(_("Delete bin"));
2132 }
2133
2134 int AWindowDeleteFolder::handle_event()
2135 {
2136         if( gui->folder_list->get_selection(0, 0) ) {
2137                 BC_ListBoxItem *folder = gui->folder_list->get_selection(0, 0);
2138                 mwindow->delete_folder(folder->get_text());
2139         }
2140         return 1;
2141 }
2142
2143 AWindowRenameFolder::AWindowRenameFolder(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2144  : BC_Button(x, y, mwindow->theme->renamebin_data)
2145 {
2146         this->mwindow = mwindow;
2147         this->gui = gui;
2148         set_tooltip(_("Rename bin"));
2149 }
2150
2151 int AWindowRenameFolder::handle_event()
2152 {
2153         return 1;
2154 }
2155
2156 AWindowDeleteDisk::AWindowDeleteDisk(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2157  : BC_Button(x, y, mwindow->theme->deletedisk_data)
2158 {
2159         this->mwindow = mwindow;
2160         this->gui = gui;
2161         set_tooltip(_("Delete asset from disk"));
2162 }
2163
2164 int AWindowDeleteDisk::handle_event()
2165 {
2166         return 1;
2167 }
2168
2169 AWindowDeleteProject::AWindowDeleteProject(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2170  : BC_Button(x, y, mwindow->theme->deleteproject_data)
2171 {
2172         this->mwindow = mwindow;
2173         this->gui = gui;
2174         set_tooltip(_("Delete asset from project"));
2175 }
2176
2177 int AWindowDeleteProject::handle_event()
2178 {
2179         return 1;
2180 }
2181
2182 // AWindowInfo::AWindowInfo(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2183 //  : BC_Button(x, y, mwindow->theme->infoasset_data)
2184 // {
2185 //      this->mwindow = mwindow;
2186 //      this->gui = gui;
2187 //      set_tooltip(_("Edit information on asset"));
2188 // }
2189 // 
2190 // int AWindowInfo::handle_event()
2191 // {
2192 //      int cur_x, cur_y;
2193 //      gui->get_abs_cursor(cur_x, cur_y, 0);
2194 //      gui->awindow->asset_edit->edit_asset(gui->selected_asset(), cur_x, cur_y);
2195 //      return 1;
2196 // }
2197
2198 AWindowRedrawIndex::AWindowRedrawIndex(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2199  : BC_Button(x, y, mwindow->theme->redrawindex_data)
2200 {
2201         this->mwindow = mwindow;
2202         this->gui = gui;
2203         set_tooltip(_("Redraw index"));
2204 }
2205
2206 int AWindowRedrawIndex::handle_event()
2207 {
2208         return 1;
2209 }
2210
2211 AWindowPaste::AWindowPaste(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2212  : BC_Button(x, y, mwindow->theme->pasteasset_data)
2213 {
2214         this->mwindow = mwindow;
2215         this->gui = gui;
2216         set_tooltip(_("Paste asset on recordable tracks"));
2217 }
2218
2219 int AWindowPaste::handle_event()
2220 {
2221         return 1;
2222 }
2223
2224 AWindowAppend::AWindowAppend(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2225  : BC_Button(x, y, mwindow->theme->appendasset_data)
2226 {
2227         this->mwindow = mwindow;
2228         this->gui = gui;
2229         set_tooltip(_("Append asset in new tracks"));
2230 }
2231
2232 int AWindowAppend::handle_event()
2233 {
2234         return 1;
2235 }
2236
2237 AWindowView::AWindowView(MWindow *mwindow, AWindowGUI *gui, int x, int y)
2238  : BC_Button(x, y, mwindow->theme->viewasset_data)
2239 {
2240         this->mwindow = mwindow;
2241         this->gui = gui;
2242         set_tooltip(_("View asset"));
2243 }
2244
2245 int AWindowView::handle_event()
2246 {
2247         return 1;
2248 }
2249
2250 AddTools::AddTools(MWindow *mwindow, AWindowGUI *gui, int x, int y, const char *title)
2251  : BC_PopupMenu(x, y, BC_Title::calculate_w(gui, title, MEDIUMFONT)+8, title, -1, 0, 4)
2252 {
2253         this->mwindow = mwindow;
2254         this->gui = gui;
2255 }
2256
2257 void AddTools::create_objects()
2258 {
2259         uint64_t vis = 0;
2260         add_item(new AddPluginItem(this, "ladspa", PLUGIN_LADSPA_ID));
2261         vis |= 1 << PLUGIN_LADSPA_ID;
2262         add_item(new AddPluginItem(this, "ffmpeg", PLUGIN_FFMPEG_ID));
2263         vis |= 1 << PLUGIN_FFMPEG_ID;
2264         for( int i=0; i<MWindow::plugindb->size(); ++i ) {
2265                 PluginServer *plugin = MWindow::plugindb->get(i);
2266                 if( !plugin->audio && !plugin->video ) continue;
2267                 int idx = plugin->dir_idx;
2268                 uint32_t msk = 1 << idx;
2269                 if( (msk & vis) != 0 ) continue;
2270                 vis |= msk;
2271                 char parent[BCTEXTLEN];
2272                 strcpy(parent, plugin->path);
2273                 char *bp = strrchr(parent, '/');
2274                 if( bp ) { *bp = 0;  bp = strrchr(parent, '/'); }
2275                 if( !bp ) bp = parent; else ++bp;
2276                 add_item(new AddPluginItem(this, bp, idx));
2277         }
2278 }
2279
2280 #if 0
2281 // plugin_dirs list from toplevel makefile include plugin_defs
2282 N_("ladspa")
2283 N_("ffmpeg")
2284 N_("audio_tools")
2285 N_("audio_transitions")
2286 N_("blending")
2287 N_("colors")
2288 N_("exotic")
2289 N_("transforms")
2290 N_("tv_effects")
2291 N_("video_tools")
2292 N_("video_transitions")
2293 #endif
2294
2295 AddPluginItem::AddPluginItem(AddTools *menu, char const *text, int idx)
2296  : BC_MenuItem(_(text))
2297 {
2298         this->menu = menu;
2299         this->idx = idx;
2300         uint64_t msk = (uint64_t)1 << idx, vis = menu->gui->plugin_visibility;
2301         int chk = (msk & vis) ? 1 : 0;
2302         set_checked(chk);
2303 }
2304
2305 int AddPluginItem::handle_event()
2306 {
2307         int chk = get_checked() ^ 1;
2308         set_checked(chk);
2309         uint64_t msk = (uint64_t)1 << idx, vis = menu->gui->plugin_visibility;
2310         menu->gui->plugin_visibility = chk ? vis | msk : vis & ~msk;
2311         menu->gui->update_effects();
2312         menu->gui->save_defaults(menu->mwindow->defaults);
2313         menu->gui->async_update_assets();
2314         return 1;
2315 }
2316
2317 AVIconDrawing::AVIconDrawing(AWindowGUI *agui, int x, int y, VFrame **images)
2318  : BC_Toggle(x, y, images, agui->vicon_drawing)
2319 {
2320         this->agui = agui;
2321         set_tooltip(_("draw vicons"));
2322 }
2323
2324 void AVIconDrawing::calculate_geometry(AWindowGUI *agui, VFrame **images, int *ww, int *hh)
2325 {
2326         int text_line = -1, toggle_x = -1, toggle_y = -1;
2327         int text_x = -1, text_y = -1, text_w = -1, text_h = -1;
2328         BC_Toggle::calculate_extents(agui, images, 1,
2329                 &text_line, ww, hh, &toggle_x, &toggle_y,
2330                 &text_x, &text_y, &text_w, &text_h, "", MEDIUMFONT);
2331 }
2332
2333 AVIconDrawing::~AVIconDrawing()
2334 {
2335 }
2336
2337 int AVIconDrawing::handle_event()
2338 {
2339         agui->vicon_drawing = get_value();
2340         if( agui->vicon_drawing )
2341                 agui->start_vicon_drawing();
2342         else
2343                 agui->stop_vicon_drawing();
2344         return 1;
2345 }
2346
2347
2348 AWindowListFormat::AWindowListFormat(MWindow *mwindow, AWindowGUI *gui)
2349  : BC_MenuItem("")
2350 {
2351         this->mwindow = mwindow;
2352         this->gui = gui;
2353 }
2354
2355 int AWindowListFormat::handle_event()
2356 {
2357         gui->stop_vicon_drawing();
2358
2359         EDLSession *session = mwindow->edl->session;
2360         switch( session->assetlist_format ) {
2361         case ASSETS_TEXT:
2362                 session->assetlist_format = ASSETS_ICONS;
2363                 break;
2364         case ASSETS_ICONS:
2365                 session->assetlist_format = ASSETS_TEXT;
2366                 break;
2367         }
2368
2369         gui->asset_list->update_format(session->assetlist_format, 1);
2370         if( !mwindow->awindow->gui->allow_iconlisting ) {
2371                 mwindow->edl->session->assetlist_format = ASSETS_TEXT;
2372         }
2373
2374         gui->start_vicon_drawing();
2375         return 1;
2376 }
2377
2378 void AWindowListFormat::update()
2379 {
2380         set_text(mwindow->edl->session->assetlist_format == ASSETS_TEXT ?
2381                 (char*)_("Display icons") : (char*)_("Display text"));
2382 }
2383
2384 AWindowListSort::AWindowListSort(MWindow *mwindow, AWindowGUI *gui)
2385  : BC_MenuItem(_("Sort items"))
2386 {
2387         this->mwindow = mwindow;
2388         this->gui = gui;
2389 }
2390
2391 int AWindowListSort::handle_event()
2392 {
2393         gui->sort_assets(0);
2394         return 1;
2395 }
2396