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  : BC_DragBox(mwindow->gui)
1026 {
1027         this->mwindow = mwindow;
1028 }
1029
1030 GrabshotThread::~GrabshotThread()
1031 {
1032 }
1033
1034 void GrabshotThread::start(GrabshotMenuItem *menu_item)
1035 {
1036         mode = menu_item->mode;
1037         start_drag();
1038 }
1039
1040 int GrabshotThread::handle_done_event(int x0, int y0, int x1, int y1)
1041 {
1042         int cx = x0,    cy = y0;
1043         int cw = x1-x0, ch = y1-y0;
1044
1045         Preferences *preferences = mwindow->preferences;
1046         char filename[BCTEXTLEN], snapshot_path[BCTEXTLEN];
1047         static const char *exts[] = { "png", "jpg", "tif", "ppm" };
1048         time_t tt;     time(&tt);
1049         struct tm tm;  localtime_r(&tt,&tm);
1050         File::getenv_path(snapshot_path, preferences->snapshot_path);
1051         snprintf(filename,sizeof(filename),"%s/%s_%04d%02d%02d-%02d%02d%02d.%s",
1052                 snapshot_path, _("grab"),
1053                 1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,
1054                 tm.tm_hour,tm.tm_min,tm.tm_sec, exts[mode]);
1055         char *asset_path = FileSystem::basepath(filename);
1056         Asset *asset = new Asset(asset_path);
1057         delete [] asset_path;
1058         switch( mode ) {
1059         case GRABSHOT_PNG:
1060                 asset->format = FILE_PNG;
1061                 asset->png_use_alpha = 1;
1062                 break;
1063         case GRABSHOT_JPEG:
1064                 asset->format = FILE_JPEG;
1065                 asset->jpeg_quality = 90;
1066                 break;
1067         case GRABSHOT_TIFF:
1068                 asset->format = FILE_TIFF;
1069                 asset->tiff_cmodel = 0;
1070                 asset->tiff_compression = 0;
1071                 break;
1072         case GRABSHOT_PPM:
1073                 asset->format = FILE_PPM;
1074                 break;
1075         }
1076
1077 // no odd dimensions
1078         int rw = mwindow->gui->get_root_w(0);
1079         int rh = mwindow->gui->get_root_h(0);
1080         if( cx < 0 ) { cw += cx;  cx = 0; }
1081         if( cy < 0 ) { ch += cy;  cy = 0; }
1082         if( cx+cw > rw ) cw = rw-cx;
1083         if( cy+ch > rh ) ch = rh-cy;
1084         if( !cw || !ch ) return 0;
1085
1086         VFrame vframe(cw,ch, BC_RGB888);
1087         if( cx+cw < rw ) ++cw;
1088         if( cy+ch < rh ) ++ch;
1089         BC_Capture capture_bitmap(cw,ch, 0);
1090         capture_bitmap.capture_frame(&vframe, cx,cy);
1091
1092         asset->width = vframe.get_w();
1093         asset->height = vframe.get_h();
1094         asset->audio_data = 0;
1095         asset->video_data = 1;
1096         asset->video_length = 1;
1097         asset->layers = 1;
1098
1099         File file;
1100         int fcolor_model = mwindow->edl->session->color_model;
1101         int processors = preferences->project_smp + 1;
1102         if( processors > 8 ) processors = 8;
1103         file.set_processors(processors);
1104         int ret = file.open_file(preferences, asset, 0, 1);
1105         if( !ret ) {
1106                 file.start_video_thread(1, fcolor_model,
1107                         processors > 1 ? 2 : 1, 0);
1108                 VFrame ***frames = file.get_video_buffer();
1109                 VFrame *frame = frames[0][0];
1110                 frame->transfer_from(&vframe);
1111                 ret = file.write_video_buffer(1);
1112                 file.close_file();
1113         }
1114         if( !ret ) {
1115                 asset->folder_no = AW_MEDIA_FOLDER;
1116                 mwindow->edl->assets->append(asset);
1117                 mwindow->awindow->gui->async_update_assets();
1118         }
1119         else {
1120                 eprintf(_("grabshot render failed"));
1121                 asset->remove_user();
1122         }
1123
1124         return 1;
1125 }
1126