no longer need ffmpeg patch0 which was for Termux
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / assetpopup.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 "assetremove.h"
26 #include "assets.h"
27 #include "awindow.h"
28 #include "awindowgui.h"
29 #include "bccapture.h"
30 #include "bcdisplayinfo.h"
31 #include "bcsignals.h"
32 #include "cache.h"
33 #include "clipedit.h"
34 #include "cstrdup.h"
35 #include "cwindow.h"
36 #include "cwindowgui.h"
37 #include "edl.h"
38 #include "edlsession.h"
39 #include "file.h"
40 #include "filesystem.h"
41 #include "filexml.h"
42 #include "language.h"
43 #include "loadfile.h"
44 #include "localsession.h"
45 #include "mainerror.h"
46 #include "mainindexes.h"
47 #include "mainmenu.h"
48 #include "mainsession.h"
49 #include "mwindow.h"
50 #include "mwindowgui.h"
51 #include "preferences.h"
52 #include "renderengine.h"
53 #include "tracks.h"
54 #include "transportque.h"
55 #include "vframe.h"
56 #include "vrender.h"
57 #include "vwindow.h"
58 #include "vwindowgui.h"
59 #include "zwindow.h"
60
61
62 AssetPopup::AssetPopup(MWindow *mwindow, AWindowGUI *gui)
63  : BC_PopupMenu(0, 0, 0, "", 0)
64 {
65         this->mwindow = mwindow;
66         this->gui = gui;
67 }
68
69 AssetPopup::~AssetPopup()
70 {
71 }
72
73 void AssetPopup::create_objects()
74 {
75         BC_MenuItem *menu_item;
76         BC_SubMenu *submenu;
77         add_item(info = new AssetPopupInfo(mwindow, this));
78         add_item(format = new AWindowListFormat(mwindow, gui));
79         add_item(open_edl = new AssetPopupOpenEDL(mwindow, this));
80         add_item(close_edl = new AssetPopupCloseEDL(mwindow, gui));
81         add_item(to_clip = new AssetPopupToClip(mwindow, this));
82         add_item(sort = new AssetPopupSort(mwindow, this));
83         add_item(index = new AssetPopupBuildIndex(mwindow, this));
84         add_item(view = new AssetPopupView(mwindow, this));
85         add_item(view_window = new AssetPopupViewWindow(mwindow, this));
86         add_item(open_mixer = new AssetPopupOpenMixer(mwindow, this));
87         add_item(insert_mixer = new AssetPopupInsertMixer(mwindow, this));
88         add_item(paste = new AssetPopupPaste(mwindow, this));
89         add_item(menu_item = new BC_MenuItem(_("Match...")));
90         menu_item->add_submenu(submenu = new BC_SubMenu());
91         submenu->add_submenuitem(new AssetMatchSize(mwindow, this));
92         submenu->add_submenuitem(new AssetMatchRate(mwindow, this));
93         submenu->add_submenuitem(new AssetMatchAll(mwindow, this));
94         add_item(menu_item = new BC_MenuItem(_("Remove...")));
95         menu_item->add_submenu(submenu = new BC_SubMenu());
96         submenu->add_submenuitem(new AssetPopupProjectRemove(mwindow, this));
97         submenu->add_submenuitem(new AssetPopupDiskRemove(mwindow, this));
98 }
99
100 void AssetPopup::paste_assets()
101 {
102         int proxy = mwindow->edl->session->awindow_folder == AW_PROXY_FOLDER ? 1 : 0;
103         gui->collect_assets(proxy);
104 // Collect items into the drag vectors for temporary storage
105         gui->unlock_window();
106         mwindow->gui->lock_window("AssetPopup::paste_assets");
107         mwindow->paste_assets(mwindow->edl->local_session->get_selectionstart(1),
108                 mwindow->edl->tracks->first, 0);   // do not overwrite
109         mwindow->gui->unlock_window();
110         gui->lock_window("AssetPopup::paste_assets");
111 }
112
113 void AssetPopup::match_size()
114 {
115 // Collect items into the drag vectors for temporary storage
116         gui->collect_assets();
117         mwindow->gui->lock_window("AssetPopup::match_size");
118         mwindow->asset_to_size();
119         mwindow->gui->unlock_window();
120 }
121
122 void AssetPopup::match_rate()
123 {
124 // Collect items into the drag vectors for temporary storage
125         gui->collect_assets();
126         mwindow->gui->lock_window("AssetPopup::match_rate");
127         mwindow->asset_to_rate();
128         mwindow->gui->unlock_window();
129 }
130
131 void AssetPopup::match_all()
132 {
133 // Collect items into the drag vectors for temporary storage
134         gui->collect_assets();
135         mwindow->gui->lock_window("AssetPopup::match_rate");
136         mwindow->asset_to_all();
137         mwindow->gui->unlock_window();
138 }
139
140 int AssetPopup::update()
141 {
142         format->update();
143         int proxy = mwindow->edl->session->awindow_folder == AW_PROXY_FOLDER ? 1 : 0;
144         gui->collect_assets(proxy);
145         int enable_open = 0;
146         int assets_total = mwindow->session->drag_assets->size();
147         Indexable *idxbl = !assets_total ? 0 :
148                 mwindow->session->drag_assets->get(0);
149         if( idxbl ) {
150                 if( idxbl->is_asset ) {
151                         Asset *asset = (Asset *)idxbl;
152                         if( asset->format == FILE_REF )
153                                 enable_open = 1;
154                 }
155                 else
156                         enable_open = 1;
157         }
158         open_edl->set_enabled(enable_open);
159         int enable_close = mwindow->stack.size() > 0 ? 1 : 0;
160         close_edl->set_enabled(enable_close);
161         int enable_clip = 0;
162         for( int i=0; !enable_clip && i<assets_total; ++i ) {
163                 Indexable *idxbl = mwindow->session->drag_assets->get(i);
164                 if( !idxbl->is_asset ) enable_clip = 1;
165         }
166         to_clip->set_enabled(enable_clip);
167         return 0;
168 }
169
170
171 AssetPopupInfo::AssetPopupInfo(MWindow *mwindow, AssetPopup *popup)
172  : BC_MenuItem(_("Info..."))
173 {
174         this->mwindow = mwindow;
175         this->popup = popup;
176 }
177
178 AssetPopupInfo::~AssetPopupInfo()
179 {
180 }
181
182 int AssetPopupInfo::handle_event()
183 {
184         int cur_x, cur_y;
185         popup->gui->get_abs_cursor(cur_x, cur_y);
186         int n = mwindow->session->drag_assets->size();
187         if( n > 0 ) {
188                 int xs30 = xS(30), ys30 = yS(30);
189                 for( int i=0; i<n; ++i ) {
190                         AssetEdit *asset_edit = mwindow->awindow->get_asset_editor();
191                         asset_edit->edit_asset(
192                                 mwindow->session->drag_assets->values[i], cur_x-xs30*i, cur_y-ys30*i);
193                 }
194         }
195         else if( mwindow->session->drag_clips->size() ) {
196                 popup->gui->awindow->clip_edit->edit_clip(
197                         mwindow->session->drag_clips->values[0], cur_x, cur_y);
198         }
199         return 1;
200 }
201
202
203 AssetPopupOpenEDL::AssetPopupOpenEDL(MWindow *mwindow, AssetPopup *popup)
204  : BC_MenuItem(_("Open EDL"))
205 {
206         this->mwindow = mwindow;
207         this->popup = popup;
208 }
209 AssetPopupOpenEDL::~AssetPopupOpenEDL()
210 {
211 }
212
213 int AssetPopupOpenEDL::handle_event()
214 {
215         int assets_total = mwindow->session->drag_assets->size();
216         if( !assets_total ) return 1;
217         popup->unlock_window();
218         EDL *edl = 0;
219         Indexable *idxbl = mwindow->session->drag_assets->get(0);
220         if( idxbl->is_asset ) {
221                 Asset *asset = (Asset *)idxbl;
222                 if( asset->format == FILE_REF ) {
223                         FileXML xml_file;
224                         const char *filename = asset->path;
225                         if( xml_file.read_from_file(filename, 1) ) {
226                                 eprintf(_("Error: unable to open:\n  %s"), filename);
227                                 return 1;
228                         }
229                         edl = new EDL;
230                         edl->create_objects();
231                         if( edl->load_xml(&xml_file, LOAD_ALL) ) {
232                                 eprintf(_("Error: unable to load:\n  %s"), filename);
233                                 edl->remove_user();
234                                 return 1;
235                         }
236                 }
237         }
238         else {
239                 edl = (EDL *)idxbl;
240         }
241         if( edl )
242                 mwindow->stack_push(edl, idxbl);
243         else
244                 eprintf(_("media is not EDL:\n%s"), idxbl->path);
245         popup->lock_window("AssetPopupOpenEDL::handle_event");
246         return 1;
247 }
248
249 AssetPopupCloseEDL::AssetPopupCloseEDL(MWindow *mwindow, AWindowGUI *gui)
250  : BC_MenuItem(_("Close EDL"))
251 {
252         this->mwindow = mwindow;
253         this->gui = gui;
254 }
255 AssetPopupCloseEDL::~AssetPopupCloseEDL()
256 {
257 }
258
259 int AssetPopupCloseEDL::handle_event()
260 {
261         gui->unlock_window();
262         mwindow->gui->lock_window("AssetPopupCloseEDL::handle_event");
263         mwindow->stack_pop();
264         mwindow->gui->unlock_window();
265         gui->lock_window("AssetPopupCloseEDL::handle_event");
266         return 1;
267 }
268
269
270 AssetPopupToClip::AssetPopupToClip(MWindow *mwindow, AssetPopup *popup)
271  : BC_MenuItem(_("EDL to clip"))
272 {
273         this->mwindow = mwindow;
274         this->popup = popup;
275 }
276
277 AssetPopupToClip::~AssetPopupToClip()
278 {
279 }
280
281 int AssetPopupToClip::handle_event()
282 {
283         mwindow->media_to_clip();
284         return 1;
285 }
286
287
288 AssetPopupBuildIndex::AssetPopupBuildIndex(MWindow *mwindow, AssetPopup *popup)
289  : BC_MenuItem(_("Rebuild index"))
290 {
291         this->mwindow = mwindow;
292         this->popup = popup;
293 }
294
295 AssetPopupBuildIndex::~AssetPopupBuildIndex()
296 {
297 }
298
299 int AssetPopupBuildIndex::handle_event()
300 {
301         popup->unlock_window();
302 //printf("AssetPopupBuildIndex::handle_event 1\n");
303         mwindow->rebuild_indices();
304         popup->lock_window("AssetPopupBuildIndex::handle_event");
305         return 1;
306 }
307
308
309 AssetPopupSort::AssetPopupSort(MWindow *mwindow, AssetPopup *popup)
310  : BC_MenuItem(_("Sort"))
311 {
312         this->mwindow = mwindow;
313         this->popup = popup;
314 }
315
316 AssetPopupSort::~AssetPopupSort()
317 {
318 }
319
320 int AssetPopupSort::handle_event()
321 {
322         mwindow->awindow->gui->sort_assets();
323         return 1;
324 }
325
326
327 AssetPopupView::AssetPopupView(MWindow *mwindow, AssetPopup *popup)
328  : BC_MenuItem(_("View"))
329 {
330         this->mwindow = mwindow;
331         this->popup = popup;
332 }
333
334 AssetPopupView::~AssetPopupView()
335 {
336 }
337
338 int AssetPopupView::handle_event()
339 {
340         VWindow *vwindow = mwindow->get_viewer(1, DEFAULT_VWINDOW);
341
342         if( mwindow->session->drag_assets->total )
343                 vwindow->change_source(
344                         mwindow->session->drag_assets->values[0]);
345         else
346         if( mwindow->session->drag_clips->total )
347                 vwindow->change_source(
348                         mwindow->session->drag_clips->values[0]);
349
350         return 1;
351 }
352
353
354 AssetPopupViewWindow::AssetPopupViewWindow(MWindow *mwindow, AssetPopup *popup)
355  : BC_MenuItem(_("View in new window"))
356 {
357         this->mwindow = mwindow;
358         this->popup = popup;
359 }
360
361 AssetPopupViewWindow::~AssetPopupViewWindow()
362 {
363 }
364
365 int AssetPopupViewWindow::handle_event()
366 {
367         for( int i=0; i<mwindow->session->drag_assets->size(); ++i ) {
368                 VWindow *vwindow = mwindow->get_viewer(1);
369                 vwindow->gui->lock_window("AssetPopupView::handle_event 1");
370                 vwindow->change_source(mwindow->session->drag_assets->get(i));
371                 vwindow->gui->unlock_window();
372         }
373         for( int i=0; i<mwindow->session->drag_clips->size(); ++i ) {
374                 VWindow *vwindow = mwindow->get_viewer(1);
375                 vwindow->gui->lock_window("AssetPopupView::handle_event 2");
376                 vwindow->change_source(mwindow->session->drag_clips->get(i));
377                 vwindow->gui->unlock_window();
378         }
379         return 1;
380 }
381
382 AssetPopupOpenMixer::AssetPopupOpenMixer(MWindow *mwindow, AssetPopup *popup)
383  : BC_MenuItem(_("Open Mixers"))
384 {
385         this->mwindow = mwindow;
386         this->popup = popup;
387 }
388
389 AssetPopupOpenMixer::~AssetPopupOpenMixer()
390 {
391 }
392
393 int AssetPopupOpenMixer::handle_event()
394 {
395         popup->unlock_window();
396         mwindow->gui->lock_window("AssetPopupOpenMixer::handle_event");
397         mwindow->create_mixers();
398         mwindow->gui->unlock_window();
399         popup->lock_window("AssetPopupOpenMixer::handle_event");
400         return 1;
401 }
402
403 AssetPopupInsertMixer::AssetPopupInsertMixer(MWindow *mwindow, AssetPopup *popup)
404  : BC_MenuItem(_("Insert Mixers"))
405 {
406         this->mwindow = mwindow;
407         this->popup = popup;
408 }
409
410 AssetPopupInsertMixer::~AssetPopupInsertMixer()
411 {
412 }
413
414 int AssetPopupInsertMixer::handle_event()
415 {
416         popup->unlock_window();
417         mwindow->gui->lock_window("AssetPopupInsertMixer::handle_event");
418         mwindow->create_mixers(-1);
419         mwindow->gui->unlock_window();
420         popup->lock_window("AssetPopupInsertMixer::handle_event");
421         return 1;
422 }
423
424 AssetPopupPaste::AssetPopupPaste(MWindow *mwindow, AssetPopup *popup)
425  : BC_MenuItem(C_("Paste"))
426 {
427         this->mwindow = mwindow;
428         this->popup = popup;
429 }
430
431 AssetPopupPaste::~AssetPopupPaste()
432 {
433 }
434
435 int AssetPopupPaste::handle_event()
436 {
437         popup->paste_assets();
438         return 1;
439 }
440
441
442 AssetMatchSize::AssetMatchSize(MWindow *mwindow, AssetPopup *popup)
443  : BC_MenuItem(_("Match project size"))
444 {
445         this->mwindow = mwindow;
446         this->popup = popup;
447 }
448
449 int AssetMatchSize::handle_event()
450 {
451         popup->match_size();
452         return 1;
453 }
454
455 AssetMatchRate::AssetMatchRate(MWindow *mwindow, AssetPopup *popup)
456  : BC_MenuItem(_("Match frame rate"))
457 {
458         this->mwindow = mwindow;
459         this->popup = popup;
460 }
461
462 int AssetMatchRate::handle_event()
463 {
464         popup->match_rate();
465         return 1;
466 }
467
468 AssetMatchAll::AssetMatchAll(MWindow *mwindow, AssetPopup *popup)
469  : BC_MenuItem(_("Match all"))
470 {
471         this->mwindow = mwindow;
472         this->popup = popup;
473 }
474
475 int AssetMatchAll::handle_event()
476 {
477         popup->match_all();
478         return 1;
479 }
480
481
482 AssetPopupProjectRemove::AssetPopupProjectRemove(MWindow *mwindow, AssetPopup *popup)
483  : BC_MenuItem(_("Remove from project"))
484 {
485         this->mwindow = mwindow;
486         this->popup = popup;
487 }
488
489 AssetPopupProjectRemove::~AssetPopupProjectRemove()
490 {
491 }
492
493 int AssetPopupProjectRemove::handle_event()
494 {
495         popup->gui->unlock_window();
496         mwindow->remove_assets_from_project(1, 1, 1,
497                 mwindow->session->drag_assets, 0);
498         popup->gui->lock_window("AssetPopupProjectRemove::handle_event");
499         return 1;
500 }
501
502
503 AssetPopupDiskRemove::AssetPopupDiskRemove(MWindow *mwindow, AssetPopup *popup)
504  : BC_MenuItem(_("Remove from disk"))
505 {
506         this->mwindow = mwindow;
507         this->popup = popup;
508 }
509
510
511 AssetPopupDiskRemove::~AssetPopupDiskRemove()
512 {
513 }
514
515 int AssetPopupDiskRemove::handle_event()
516 {
517         mwindow->awindow->asset_remove->start();
518         return 1;
519 }
520
521
522 AssetListMenu::AssetListMenu(MWindow *mwindow, AWindowGUI *gui)
523  : BC_PopupMenu(0, 0, 0, "", 0)
524 {
525         this->mwindow = mwindow;
526         this->gui = gui;
527 }
528
529 AssetListMenu::~AssetListMenu()
530 {
531 }
532
533 void AssetListMenu::create_objects()
534 {
535         add_item(load_file = new AssetPopupLoadFile(mwindow, gui));
536         add_item(format = new AWindowListFormat(mwindow, gui));
537         add_item(close_edl = new AssetPopupCloseEDL(mwindow, gui));
538         add_item(select_used = new AssetSelectUsed(mwindow, gui));
539         BC_SubMenu *submenu;
540         select_used->add_submenu(submenu = new BC_SubMenu());
541         submenu->add_submenuitem(new AssetSelectUsedItem(select_used, _("All"), SELECT_ALL));
542         submenu->add_submenuitem(new AssetSelectUsedItem(select_used, _("Used"), SELECT_USED));
543         submenu->add_submenuitem(new AssetSelectUsedItem(select_used, _("Unused"), SELECT_UNUSED));
544         submenu->add_submenuitem(new AssetSelectUsedItem(select_used, _("None"), SELECT_NONE));
545         add_item(new AWindowListSort(mwindow, gui));
546         add_item(new AssetListCopy(mwindow, gui));
547         add_item(new AssetListPaste(mwindow, gui));
548         SnapshotSubMenu *snapshot_submenu;
549         add_item(asset_snapshot = new AssetSnapshot(mwindow, this));
550         asset_snapshot->add_submenu(snapshot_submenu = new SnapshotSubMenu(asset_snapshot));
551         snapshot_submenu->add_submenuitem(new SnapshotMenuItem(snapshot_submenu, _("png"),  SNAPSHOT_PNG));
552         snapshot_submenu->add_submenuitem(new SnapshotMenuItem(snapshot_submenu, _("jpeg"), SNAPSHOT_JPEG));
553         snapshot_submenu->add_submenuitem(new SnapshotMenuItem(snapshot_submenu, _("tiff"), SNAPSHOT_TIFF));
554         snapshot_submenu->add_submenuitem(new SnapshotMenuItem(snapshot_submenu, _("ppm"),  SNAPSHOT_PPM));
555         GrabshotSubMenu *grabshot_submenu;
556         add_item(asset_grabshot = new AssetGrabshot(mwindow, this));
557         asset_grabshot->add_submenu(grabshot_submenu = new GrabshotSubMenu(asset_grabshot));
558         grabshot_submenu->add_submenuitem(new GrabshotMenuItem(grabshot_submenu, _("png"),  GRABSHOT_PNG));
559         grabshot_submenu->add_submenuitem(new GrabshotMenuItem(grabshot_submenu, _("jpeg"), GRABSHOT_JPEG));
560         grabshot_submenu->add_submenuitem(new GrabshotMenuItem(grabshot_submenu, _("tiff"), GRABSHOT_TIFF));
561         grabshot_submenu->add_submenuitem(new GrabshotMenuItem(grabshot_submenu, _("ppm"),  GRABSHOT_PPM));
562         update_titles(1);
563 }
564
565 AssetPopupLoadFile::AssetPopupLoadFile(MWindow *mwindow, AWindowGUI *gui)
566  : BC_MenuItem(_("Load files..."), "o", 'o')
567 {
568         this->mwindow = mwindow;
569         this->gui = gui;
570 }
571
572 AssetPopupLoadFile::~AssetPopupLoadFile()
573 {
574 }
575
576 int AssetPopupLoadFile::handle_event()
577 {
578         mwindow->gui->mainmenu->load_file->thread->start();
579         return 1;
580 }
581
582 void AssetListMenu::update_titles(int shots)
583 {
584         format->update();
585         int enable_close = mwindow->stack.size() > 0 ? 1 : 0;
586         close_edl->set_enabled(enable_close);
587         asset_snapshot->set_enabled(shots);
588         asset_grabshot->set_enabled(shots);
589 }
590
591 AssetListCopy::AssetListCopy(MWindow *mwindow, AWindowGUI *gui)
592  : BC_MenuItem(_("Copy file list"))
593 {
594         this->mwindow = mwindow;
595         this->gui = gui;
596         copy_dialog = 0;
597 }
598 AssetListCopy::~AssetListCopy()
599 {
600         delete copy_dialog;
601 }
602
603 int AssetListCopy::handle_event()
604 {
605         int len = 0;
606         MWindowGUI *gui = mwindow->gui;
607         gui->lock_window("AssetListCopy::handle_event");
608         mwindow->awindow->gui->collect_assets();
609         int n = mwindow->session->drag_assets->total;
610         for( int i=0; i<n; ++i ) {
611                 Indexable *indexable = mwindow->session->drag_assets->values[i];
612                 const char *path = indexable->path;
613                 if( !*path ) continue;
614                 len += strlen(path) + 1;
615         }
616         char *text = new char[len+1], *cp = text;
617         for( int i=0; i<n; ++i ) {
618                 Indexable *indexable = mwindow->session->drag_assets->values[i];
619                 const char *path = indexable->path;
620                 if( !*path ) continue;
621                 cp += sprintf(cp, "%s\n", path);
622         }
623         *cp = 0;
624         int cur_x, cur_y;
625         gui->get_abs_cursor(cur_x, cur_y, 0);
626         gui->unlock_window(); 
627
628         if( n ) {
629                 if( !copy_dialog )
630                         copy_dialog = new AssetCopyDialog(this);
631                 copy_dialog->start(text, cur_x, cur_y);
632         }
633         else {
634                 eprintf(_("Nothing selected"));
635                 delete [] text;
636         }
637         return 1;
638 }
639
640 AssetCopyDialog::AssetCopyDialog(AssetListCopy *copy)
641  : BC_DialogThread()
642 {
643         this->copy = copy;
644         copy_window = 0;
645 }
646
647 void AssetCopyDialog::start(char *text, int x, int y)
648 {
649         close_window();
650         this->text = text;
651         this->x = x;  this->y = y;
652         BC_DialogThread::start();
653 }
654
655 AssetCopyDialog::~AssetCopyDialog()
656 {
657         close_window();
658 }
659
660 BC_Window* AssetCopyDialog::new_gui()
661 {
662         BC_DisplayInfo display_info;
663
664         copy_window = new AssetCopyWindow(this);
665         copy_window->create_objects();
666         return copy_window;
667 }
668
669 void AssetCopyDialog::handle_done_event(int result)
670 {
671         delete [] text;  text = 0;
672 }
673
674 void AssetCopyDialog::handle_close_event(int result)
675 {
676         copy_window = 0;
677 }
678
679 #define ACW_W xS(500)
680 #define ACW_H yS(200)
681
682 AssetCopyWindow::AssetCopyWindow(AssetCopyDialog *copy_dialog)
683  : BC_Window(_(PROGRAM_NAME ": Copy File List"),
684         copy_dialog->x - ACW_W/2, copy_dialog->y - ACW_H/2,
685         ACW_W, ACW_H, ACW_W, ACW_H, 1, 0, 1)
686 {
687         this->copy_dialog = copy_dialog;
688 }
689
690 AssetCopyWindow::~AssetCopyWindow()
691 {
692 }
693
694 void AssetCopyWindow::create_objects()
695 {
696         lock_window("AssetCopyWindow::create_objects");
697         BC_Title *title;
698         int xs10 = xS(10);
699         int ys5 = yS(5), ys10 = yS(10);
700         int x = xs10, y = ys10;
701         add_subwindow(title = new BC_Title(x, y, _("List of asset paths:")));
702         y += title->get_h() + ys5;
703         int text_w = get_w() - x - 10;
704         int text_h = get_h() - y - BC_OKButton::calculate_h() - ys5;
705         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
706         char *text = copy_dialog->text;
707         int len = strlen(text) + BCTEXTLEN;
708         file_list = new BC_ScrollTextBox(this, x, y, text_w, text_rows, text, len);
709         file_list->create_objects();
710
711         add_subwindow(new BC_OKButton(this));
712         show_window();
713         unlock_window();
714 }
715
716 int AssetCopyWindow::resize_event(int w, int h)
717 {
718         int fx = file_list->get_x(), fy = file_list->get_y();
719         int text_w = w - fx - xS(10);
720         int text_h = h - fy - BC_OKButton::calculate_h() - yS(5);
721         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
722         file_list->reposition_window(fx, fy, text_w, text_rows);
723         return 0;
724 }
725
726 AssetListPaste::AssetListPaste(MWindow *mwindow, AWindowGUI *gui)
727  : BC_MenuItem(_("Paste file list"))
728 {
729         this->mwindow = mwindow;
730         this->gui = gui;
731         paste_dialog = 0;
732 }
733 AssetListPaste::~AssetListPaste()
734 {
735         delete paste_dialog;
736 }
737
738 int AssetListPaste::handle_event()
739 {
740         if( !paste_dialog )
741                 paste_dialog = new AssetPasteDialog(this);
742         else
743                 paste_dialog->close_window();
744         int cur_x, cur_y;
745         gui->get_abs_cursor(cur_x, cur_y, 0);
746         paste_dialog->start(cur_x, cur_y);
747         return 1;
748 }
749
750 AssetPasteDialog::AssetPasteDialog(AssetListPaste *paste)
751  : BC_DialogThread()
752 {
753         this->paste = paste;
754         paste_window = 0;
755 }
756
757 AssetPasteDialog::~AssetPasteDialog()
758 {
759         close_window();
760 }
761
762 BC_Window* AssetPasteDialog::new_gui()
763 {
764         paste_window = new AssetPasteWindow(this);
765         paste_window->create_objects();
766         return paste_window;
767 }
768
769 void AssetPasteDialog::handle_done_event(int result)
770 {
771         if( result ) return;
772         const char *bp = paste_window->file_list->get_text(), *ep = bp+strlen(bp);
773         ArrayList<char*> path_list;
774         path_list.set_array_delete();
775
776         for( const char *cp=bp; cp<ep && *cp; ) {
777                 const char *dp = strchr(cp, '\n');
778                 if( !dp ) dp = ep;
779                 char path[BCTEXTLEN], *pp = path;
780                 int len = sizeof(path)-1;
781                 while( --len>0 && cp<dp ) *pp++ = *cp++;
782                 if( *cp ) ++cp;
783                 *pp = 0;
784                 if( !strlen(path) ) continue;
785                 path_list.append(cstrdup(path));
786         }
787         if( !path_list.size() ) return;
788
789         MWindow *mwindow = paste->mwindow;
790         mwindow->interrupt_indexes();
791         mwindow->gui->lock_window("AssetPasteDialog::handle_done_event");
792         result = mwindow->load_filenames(&path_list,
793                 LOADMODE_RESOURCESONLY, LOADMODE_EDL_CLIP, 0);
794         mwindow->gui->unlock_window();
795         path_list.remove_all_objects();
796         mwindow->save_backup();
797         mwindow->restart_brender();
798         mwindow->session->changes_made = 1;
799 }
800
801 void AssetPasteDialog::handle_close_event(int result)
802 {
803         paste_window = 0;
804 }
805
806 void AssetPasteDialog::start(int x, int y)
807 {
808         this->x = x;  this->y = y;
809         BC_DialogThread::start();
810 }
811
812 #define APW_W xS(500)
813 #define APW_H yS(200)
814
815 AssetPasteWindow::AssetPasteWindow(AssetPasteDialog *paste_dialog)
816  : BC_Window(_(PROGRAM_NAME ": Paste File List"),
817         paste_dialog->x - APW_W/2, paste_dialog->y - APW_H/2,
818         APW_W, APW_H, APW_W, APW_H, 1, 0, 1)
819 {
820         this->paste_dialog = paste_dialog;
821 }
822
823 AssetPasteWindow::~AssetPasteWindow()
824 {
825 }
826
827 void AssetPasteWindow::create_objects()
828 {
829         lock_window("AssetPasteWindow::create_objects()");
830         BC_Title *title;
831         int xs10 = xS(10);
832         int ys5 = yS(5), ys10 = yS(10);
833         int x = xs10, y = ys10;
834         add_subwindow(title = new BC_Title(x, y, _("Enter list of asset paths:")));
835         y += title->get_h() + ys5;
836         int text_w = get_w() - x - xs10;
837         int text_h = get_h() - y - BC_OKButton::calculate_h() - ys5;
838         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
839         file_list = new BC_ScrollTextBox(this, x, y, text_w, text_rows, (char*)0, 65536);
840         file_list->create_objects();
841         add_subwindow(new BC_OKButton(this));
842         add_subwindow(new BC_CancelButton(this));
843         show_window();
844         unlock_window();
845 }
846
847 int AssetPasteWindow::resize_event(int w, int h)
848 {
849         int fx = file_list->get_x(), fy = file_list->get_y();
850         int text_w = w - fx - xS(10);
851         int text_h = h - fy - BC_OKButton::calculate_h() - yS(5);
852         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
853         file_list->reposition_window(fx, fy, text_w, text_rows);
854         return 0;
855 }
856
857
858
859 AssetSnapshot::AssetSnapshot(MWindow *mwindow, AssetListMenu *asset_list_menu)
860  : BC_MenuItem(_("Snapshot..."))
861 {
862         this->mwindow = mwindow;
863         this->asset_list_menu = asset_list_menu;
864 }
865
866 AssetSnapshot::~AssetSnapshot()
867 {
868 }
869
870 SnapshotSubMenu::SnapshotSubMenu(AssetSnapshot *asset_snapshot)
871 {
872         this->asset_snapshot = asset_snapshot;
873 }
874
875 SnapshotSubMenu::~SnapshotSubMenu()
876 {
877 }
878
879 SnapshotMenuItem::SnapshotMenuItem(SnapshotSubMenu *submenu, const char *text, int mode)
880  : BC_MenuItem(text)
881 {
882         this->submenu = submenu;
883         this->mode = mode;
884 }
885
886 SnapshotMenuItem::~SnapshotMenuItem()
887 {
888 }
889
890 int SnapshotMenuItem::handle_event()
891 {
892         MWindow *mwindow = submenu->asset_snapshot->mwindow;
893         EDL *edl = mwindow->edl;
894         if( !edl->have_video() ) return 1;
895
896         Preferences *preferences = mwindow->preferences;
897         char filename[BCTEXTLEN], snapshot_path[BCTEXTLEN];
898         static const char *exts[] = { "png", "jpg", "tif", "ppm" };
899         time_t tt;     time(&tt);
900         struct tm tm;  localtime_r(&tt,&tm);
901         File::getenv_path(snapshot_path, preferences->snapshot_path);
902         snprintf(filename,sizeof(filename),"%s/%s_%04d%02d%02d-%02d%02d%02d.%s",
903                 snapshot_path, _("snap"),
904                 1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,
905                 tm.tm_hour,tm.tm_min,tm.tm_sec, exts[mode]);
906         char *asset_path = FileSystem::basepath(filename);
907         Asset *asset = new Asset(asset_path);
908         delete [] asset_path;
909
910         int fw = edl->get_w(), fh = edl->get_h();
911         int fcolor_model = edl->session->color_model;
912
913         switch( mode ) {
914         case SNAPSHOT_PNG:
915                 asset->format = FILE_PNG;
916                 asset->png_use_alpha = 1;
917                 break;
918         case SNAPSHOT_JPEG:
919                 asset->format = FILE_JPEG;
920                 asset->jpeg_quality = 90;
921                 break;
922         case SNAPSHOT_TIFF:
923                 asset->format = FILE_TIFF;
924                 asset->tiff_cmodel = 0;
925                 asset->tiff_compression = 0;
926                 break;
927         case SNAPSHOT_PPM:
928                 asset->format = FILE_PPM;
929                 break;
930         }
931         asset->width = fw;
932         asset->height = fh;
933         asset->audio_data = 0;
934         asset->video_data = 1;
935         asset->video_length = 1;
936         asset->layers = 1;
937
938         File file;
939         int processors = preferences->project_smp + 1;
940         if( processors > 8 ) processors = 8;
941         file.set_processors(processors);
942         int ret = file.open_file(preferences, asset, 0, 1);
943         if( !ret ) {
944                 file.start_video_thread(1, fcolor_model,
945                         processors > 1 ? 2 : 1, 0);
946                 VFrame ***frames = file.get_video_buffer();
947                 VFrame *frame = frames[0][0];
948                 TransportCommand command;
949                 //command.command = audio_tracks ? NORMAL_FWD : CURRENT_FRAME;
950                 command.command = CURRENT_FRAME;
951                 command.get_edl()->copy_all(edl);
952                 command.change_type = CHANGE_ALL;
953                 command.realtime = 0;
954
955                 RenderEngine render_engine(0, preferences, 0, 0);
956                 CICache *video_cache = new CICache(preferences);
957                 render_engine.set_vcache(video_cache);
958                 render_engine.arm_command(&command);
959
960                 double position = edl->local_session->get_selectionstart(1);
961                 int64_t source_position = (int64_t)(position * edl->get_frame_rate());
962                 ret = !render_engine.vrender ? 1 :
963                         render_engine.vrender->process_buffer(frame, source_position, 0);
964                 if( !ret )
965                         ret = file.write_video_buffer(1);
966                 file.close_file();
967                 video_cache->remove_user();
968         }
969         if( !ret ) {
970                 asset->folder_no = AW_MEDIA_FOLDER;
971                 mwindow->edl->assets->append(asset);
972                 mwindow->awindow->gui->async_update_assets();
973         }
974         else {
975                 eprintf(_("snapshot render failed"));
976                 asset->remove_user();
977         }
978         return 1;
979 }
980
981
982 AssetGrabshot::AssetGrabshot(MWindow *mwindow, AssetListMenu *asset_list_menu)
983  : BC_MenuItem(_("Grabshot..."))
984 {
985         this->mwindow = mwindow;
986         this->asset_list_menu = asset_list_menu;
987 }
988
989 AssetGrabshot::~AssetGrabshot()
990 {
991 }
992
993 GrabshotSubMenu::GrabshotSubMenu(AssetGrabshot *asset_grabshot)
994 {
995         this->asset_grabshot = asset_grabshot;
996 }
997
998 GrabshotSubMenu::~GrabshotSubMenu()
999 {
1000 }
1001
1002 GrabshotMenuItem::GrabshotMenuItem(GrabshotSubMenu *submenu, const char *text, int mode)
1003  : BC_MenuItem(text)
1004 {
1005         this->submenu = submenu;
1006         this->mode = mode;
1007         grab_thread = 0;
1008 }
1009
1010 GrabshotMenuItem::~GrabshotMenuItem()
1011 {
1012         delete grab_thread;
1013 }
1014
1015 int GrabshotMenuItem::handle_event()
1016 {
1017         if( !grab_thread )
1018                 grab_thread = new GrabshotThread(submenu->asset_grabshot->mwindow);
1019         if( !grab_thread->running() )
1020                 grab_thread->start(this);
1021         return 1;
1022 }
1023
1024 GrabshotThread::GrabshotThread(MWindow *mwindow)
1025  : Thread(1, 0, 0)
1026 {
1027         this->mwindow = mwindow;
1028         popup = 0;
1029         done = -1;
1030 }
1031 GrabshotThread::~GrabshotThread()
1032 {
1033         delete popup;
1034 }
1035
1036 void GrabshotThread::start(GrabshotMenuItem *menu_item)
1037 {
1038         popup = new GrabshotPopup(this, menu_item->mode);
1039         popup->lock_window("GrabshotThread::start");
1040         for( int i=0; i<4; ++i )
1041                 edge[i] = new BC_Popup(mwindow->gui, 0,0, 1,1, ORANGE, 1);
1042         mwindow->gui->grab_buttons();
1043         mwindow->gui->grab_cursor();
1044         popup->grab(mwindow->gui);
1045         popup->create_objects();
1046         popup->show_window();
1047         popup->unlock_window();
1048         done = 0;
1049         Thread::start();
1050 }
1051
1052 void GrabshotThread::run()
1053 {
1054         popup->lock_window("GrabshotThread::run 0");
1055         while( !done ) {
1056                 popup->update();
1057                 popup->unlock_window();
1058                 enable_cancel();
1059                 Timer::delay(200);
1060                 disable_cancel();
1061                 popup->lock_window("GrabshotThread::run 1");
1062         }
1063         mwindow->gui->ungrab_cursor();
1064         mwindow->gui->ungrab_buttons();
1065         popup->ungrab(mwindow->gui);
1066         for( int i=0; i<4; ++i ) delete edge[i];
1067         popup->unlock_window();
1068         delete popup;  popup = 0;
1069 }
1070
1071 GrabshotPopup::GrabshotPopup(GrabshotThread *grab_thread, int mode)
1072  : BC_Popup(grab_thread->mwindow->gui, 0,0, 16,16, -1,1)
1073 {
1074         this->grab_thread = grab_thread;
1075         this->mode = mode;
1076         dragging = -1;
1077         grab_color = ORANGE;
1078         x0 = y0 = x1 = y1 = -1;
1079         lx0 = ly0 = lx1 = ly1 = -1;
1080 }
1081 GrabshotPopup::~GrabshotPopup()
1082 {
1083 }
1084
1085 int GrabshotPopup::grab_event(XEvent *event)
1086 {
1087         int cur_drag = dragging;
1088         switch( event->type ) {
1089         case ButtonPress:
1090                 if( cur_drag > 0 ) return 1;
1091                 x0 = event->xbutton.x_root;
1092                 y0 = event->xbutton.y_root;
1093                 if( !cur_drag ) {
1094                         draw_selection(-1);
1095                         if( event->xbutton.button == RIGHT_BUTTON ) break;
1096                         if( x0>=get_x() && x0<get_x()+get_w() &&
1097                             y0>=get_y() && y0<get_y()+get_h() ) break;
1098                 }
1099                 x1 = x0;  y1 = y0;
1100                 draw_selection(1);
1101                 dragging = 1;
1102                 return 1;
1103         case ButtonRelease:
1104                 dragging = 0;
1105         case MotionNotify:
1106                 if( cur_drag > 0 ) {
1107                         x1 = event->xbutton.x_root;
1108                         y1 = event->xbutton.y_root;
1109                         draw_selection(0);
1110                 }
1111                 return 1;
1112         default:
1113                 return 0;
1114         }
1115
1116         int cx = lx0,     cy = ly0;
1117         int cw = lx1-lx0, ch = ly1-ly0;
1118         hide_window();
1119         sync_display();
1120         grab_thread->done = 1;
1121
1122         MWindow *mwindow = grab_thread->mwindow;
1123         Preferences *preferences = mwindow->preferences;
1124         char filename[BCTEXTLEN], snapshot_path[BCTEXTLEN];
1125         static const char *exts[] = { "png", "jpg", "tif", "ppm" };
1126         time_t tt;     time(&tt);
1127         struct tm tm;  localtime_r(&tt,&tm);
1128         File::getenv_path(snapshot_path, preferences->snapshot_path);
1129         snprintf(filename,sizeof(filename),"%s/%s_%04d%02d%02d-%02d%02d%02d.%s",
1130                 snapshot_path, _("grab"),
1131                 1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,
1132                 tm.tm_hour,tm.tm_min,tm.tm_sec, exts[mode]);
1133         char *asset_path = FileSystem::basepath(filename);
1134         Asset *asset = new Asset(asset_path);
1135         delete [] asset_path;
1136         switch( mode ) {
1137         case GRABSHOT_PNG:
1138                 asset->format = FILE_PNG;
1139                 asset->png_use_alpha = 1;
1140                 break;
1141         case GRABSHOT_JPEG:
1142                 asset->format = FILE_JPEG;
1143                 asset->jpeg_quality = 90;
1144                 break;
1145         case GRABSHOT_TIFF:
1146                 asset->format = FILE_TIFF;
1147                 asset->tiff_cmodel = 0;
1148                 asset->tiff_compression = 0;
1149                 break;
1150         case GRABSHOT_PPM:
1151                 asset->format = FILE_PPM;
1152                 break;
1153         }
1154
1155 // no odd dimensions
1156         int rw = get_root_w(0), rh = get_root_h(0);
1157         if( cx < 0 ) { cw += cx;  cx = 0; }
1158         if( cy < 0 ) { ch += cy;  cy = 0; }
1159         if( cx+cw > rw ) cw = rw-cx;
1160         if( cy+ch > rh ) ch = rh-cy;
1161         if( !cw || !ch ) return 1;
1162
1163         VFrame vframe(cw,ch, BC_RGB888);
1164         if( cx+cw < rw ) ++cw;
1165         if( cy+ch < rh ) ++ch;
1166         BC_Capture capture_bitmap(cw,ch, 0);
1167         capture_bitmap.capture_frame(&vframe, cx,cy);
1168
1169         asset->width = vframe.get_w();
1170         asset->height = vframe.get_h();
1171         asset->audio_data = 0;
1172         asset->video_data = 1;
1173         asset->video_length = 1;
1174         asset->layers = 1;
1175
1176         File file;
1177         int fcolor_model = mwindow->edl->session->color_model;
1178         int processors = preferences->project_smp + 1;
1179         if( processors > 8 ) processors = 8;
1180         file.set_processors(processors);
1181         int ret = file.open_file(preferences, asset, 0, 1);
1182         if( !ret ) {
1183                 file.start_video_thread(1, fcolor_model,
1184                         processors > 1 ? 2 : 1, 0);
1185                 VFrame ***frames = file.get_video_buffer();
1186                 VFrame *frame = frames[0][0];
1187                 frame->transfer_from(&vframe);
1188                 ret = file.write_video_buffer(1);
1189                 file.close_file();
1190         }
1191         if( !ret ) {
1192                 asset->folder_no = AW_MEDIA_FOLDER;
1193                 mwindow->edl->assets->append(asset);
1194                 mwindow->awindow->gui->async_update_assets();
1195         }
1196         else {
1197                 eprintf(_("grabshot render failed"));
1198                 asset->remove_user();
1199         }
1200
1201         return 1;
1202 }
1203
1204 void GrabshotPopup::update()
1205 {
1206         set_color(grab_color ^= GREEN);
1207         draw_box(0,0, get_w(),get_h());
1208         flash(1);
1209 }
1210
1211 void GrabshotPopup::draw_selection(int show)
1212 {
1213         if( show < 0 ) {
1214                 for( int i=0; i<4; ++i ) hide_window(0);
1215                 flush();
1216                 return;
1217         }
1218
1219         int nx0 = x0 < x1 ? x0 : x1;
1220         int nx1 = x0 < x1 ? x1 : x0;
1221         int ny0 = y0 < y1 ? y0 : y1;
1222         int ny1 = y0 < y1 ? y1 : y0;
1223         lx0 = nx0;  lx1 = nx1;  ly0 = ny0;  ly1 = ny1;
1224
1225         --nx0;  --ny0;
1226         BC_Popup **edge = grab_thread->edge;
1227         edge[0]->reposition_window(nx0,ny0, nx1-nx0, 1);
1228         edge[1]->reposition_window(nx1,ny0, 1, ny1-ny0);
1229         edge[2]->reposition_window(nx0,ny1, nx1-nx0, 1);
1230         edge[3]->reposition_window(nx0,ny0, 1, ny1-ny0);
1231
1232         if( show > 0 ) {
1233                 for( int i=0; i<4; ++i ) edge[i]->show_window(0);
1234         }
1235         flush();
1236 }
1237