minor improvements from Andrew
[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 // *** CONTEXT_HELP ***
689         context_help_set_keyword("Moving clips");
690 }
691
692 AssetCopyWindow::~AssetCopyWindow()
693 {
694 }
695
696 void AssetCopyWindow::create_objects()
697 {
698         lock_window("AssetCopyWindow::create_objects");
699         BC_Title *title;
700         int xs10 = xS(10);
701         int ys5 = yS(5), ys10 = yS(10);
702         int x = xs10, y = ys10;
703         add_subwindow(title = new BC_Title(x, y, _("List of asset paths:")));
704         y += title->get_h() + ys5;
705         int text_w = get_w() - x - 10;
706         int text_h = get_h() - y - BC_OKButton::calculate_h() - ys5;
707         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
708         char *text = copy_dialog->text;
709         int len = strlen(text) + BCTEXTLEN;
710         file_list = new BC_ScrollTextBox(this, x, y, text_w, text_rows, text, len);
711         file_list->create_objects();
712
713         add_subwindow(new BC_OKButton(this));
714         show_window();
715         unlock_window();
716 }
717
718 int AssetCopyWindow::resize_event(int w, int h)
719 {
720         int fx = file_list->get_x(), fy = file_list->get_y();
721         int text_w = w - fx - xS(10);
722         int text_h = h - fy - BC_OKButton::calculate_h() - yS(5);
723         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
724         file_list->reposition_window(fx, fy, text_w, text_rows);
725         return 0;
726 }
727
728 AssetListPaste::AssetListPaste(MWindow *mwindow, AWindowGUI *gui)
729  : BC_MenuItem(_("Paste file list"))
730 {
731         this->mwindow = mwindow;
732         this->gui = gui;
733         paste_dialog = 0;
734 }
735 AssetListPaste::~AssetListPaste()
736 {
737         delete paste_dialog;
738 }
739
740 int AssetListPaste::handle_event()
741 {
742         if( !paste_dialog )
743                 paste_dialog = new AssetPasteDialog(this);
744         else
745                 paste_dialog->close_window();
746         int cur_x, cur_y;
747         gui->get_abs_cursor(cur_x, cur_y, 0);
748         paste_dialog->start(cur_x, cur_y);
749         return 1;
750 }
751
752 AssetPasteDialog::AssetPasteDialog(AssetListPaste *paste)
753  : BC_DialogThread()
754 {
755         this->paste = paste;
756         paste_window = 0;
757 }
758
759 AssetPasteDialog::~AssetPasteDialog()
760 {
761         close_window();
762 }
763
764 BC_Window* AssetPasteDialog::new_gui()
765 {
766         paste_window = new AssetPasteWindow(this);
767         paste_window->create_objects();
768         return paste_window;
769 }
770
771 void AssetPasteDialog::handle_done_event(int result)
772 {
773         if( result ) return;
774         const char *bp = paste_window->file_list->get_text(), *ep = bp+strlen(bp);
775         ArrayList<char*> path_list;
776         path_list.set_array_delete();
777
778         for( const char *cp=bp; cp<ep && *cp; ) {
779                 const char *dp = strchr(cp, '\n');
780                 if( !dp ) dp = ep;
781                 char path[BCTEXTLEN], *pp = path;
782                 int len = sizeof(path)-1;
783                 while( --len>0 && cp<dp ) *pp++ = *cp++;
784                 if( *cp ) ++cp;
785                 *pp = 0;
786                 if( !strlen(path) ) continue;
787                 path_list.append(cstrdup(path));
788         }
789         if( !path_list.size() ) return;
790
791         MWindow *mwindow = paste->mwindow;
792         mwindow->interrupt_indexes();
793         mwindow->gui->lock_window("AssetPasteDialog::handle_done_event");
794         result = mwindow->load_filenames(&path_list,
795                 LOADMODE_RESOURCESONLY, LOADMODE_EDL_CLIP, 0);
796         mwindow->gui->unlock_window();
797         path_list.remove_all_objects();
798         mwindow->save_backup();
799         mwindow->restart_brender();
800         mwindow->session->changes_made = 1;
801 }
802
803 void AssetPasteDialog::handle_close_event(int result)
804 {
805         paste_window = 0;
806 }
807
808 void AssetPasteDialog::start(int x, int y)
809 {
810         this->x = x;  this->y = y;
811         BC_DialogThread::start();
812 }
813
814 #define APW_W xS(500)
815 #define APW_H yS(200)
816
817 AssetPasteWindow::AssetPasteWindow(AssetPasteDialog *paste_dialog)
818  : BC_Window(_(PROGRAM_NAME ": Paste File List"),
819         paste_dialog->x - APW_W/2, paste_dialog->y - APW_H/2,
820         APW_W, APW_H, APW_W, APW_H, 1, 0, 1)
821 {
822         this->paste_dialog = paste_dialog;
823 // *** CONTEXT_HELP ***
824         context_help_set_keyword("Moving clips");
825 }
826
827 AssetPasteWindow::~AssetPasteWindow()
828 {
829 }
830
831 void AssetPasteWindow::create_objects()
832 {
833         lock_window("AssetPasteWindow::create_objects()");
834         BC_Title *title;
835         int xs10 = xS(10);
836         int ys5 = yS(5), ys10 = yS(10);
837         int x = xs10, y = ys10;
838         add_subwindow(title = new BC_Title(x, y, _("Enter list of asset paths:")));
839         y += title->get_h() + ys5;
840         int text_w = get_w() - x - xs10;
841         int text_h = get_h() - y - BC_OKButton::calculate_h() - ys5;
842         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
843         file_list = new BC_ScrollTextBox(this, x, y, text_w, text_rows, (char*)0, 65536);
844         file_list->create_objects();
845         add_subwindow(new BC_OKButton(this));
846         add_subwindow(new BC_CancelButton(this));
847         show_window();
848         unlock_window();
849 }
850
851 int AssetPasteWindow::resize_event(int w, int h)
852 {
853         int fx = file_list->get_x(), fy = file_list->get_y();
854         int text_w = w - fx - xS(10);
855         int text_h = h - fy - BC_OKButton::calculate_h() - yS(5);
856         int text_rows = BC_TextBox::pixels_to_rows(this, MEDIUMFONT, text_h);
857         file_list->reposition_window(fx, fy, text_w, text_rows);
858         return 0;
859 }
860
861
862
863 AssetSnapshot::AssetSnapshot(MWindow *mwindow, AssetListMenu *asset_list_menu)
864  : BC_MenuItem(_("Snapshot..."))
865 {
866         this->mwindow = mwindow;
867         this->asset_list_menu = asset_list_menu;
868 }
869
870 AssetSnapshot::~AssetSnapshot()
871 {
872 }
873
874 SnapshotSubMenu::SnapshotSubMenu(AssetSnapshot *asset_snapshot)
875 {
876         this->asset_snapshot = asset_snapshot;
877 }
878
879 SnapshotSubMenu::~SnapshotSubMenu()
880 {
881 }
882
883 SnapshotMenuItem::SnapshotMenuItem(SnapshotSubMenu *submenu, const char *text, int mode)
884  : BC_MenuItem(text)
885 {
886         this->submenu = submenu;
887         this->mode = mode;
888 }
889
890 SnapshotMenuItem::~SnapshotMenuItem()
891 {
892 }
893
894 int SnapshotMenuItem::handle_event()
895 {
896         MWindow *mwindow = submenu->asset_snapshot->mwindow;
897         EDL *edl = mwindow->edl;
898         if( !edl->have_video() ) return 1;
899
900         Preferences *preferences = mwindow->preferences;
901         char filename[BCTEXTLEN], snapshot_path[BCTEXTLEN];
902         static const char *exts[] = { "png", "jpg", "tif", "ppm" };
903         time_t tt;     time(&tt);
904         struct tm tm;  localtime_r(&tt,&tm);
905         File::getenv_path(snapshot_path, preferences->snapshot_path);
906         snprintf(filename,sizeof(filename),"%s/%s_%04d%02d%02d-%02d%02d%02d.%s",
907                 snapshot_path, _("snap"),
908                 1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,
909                 tm.tm_hour,tm.tm_min,tm.tm_sec, exts[mode]);
910         char *asset_path = FileSystem::basepath(filename);
911         Asset *asset = new Asset(asset_path);
912         delete [] asset_path;
913
914         int fw = edl->get_w(), fh = edl->get_h();
915         int fcolor_model = edl->session->color_model;
916
917         switch( mode ) {
918         case SNAPSHOT_PNG:
919                 asset->format = FILE_PNG;
920                 asset->png_use_alpha = 1;
921                 break;
922         case SNAPSHOT_JPEG:
923                 asset->format = FILE_JPEG;
924                 asset->jpeg_quality = 90;
925                 break;
926         case SNAPSHOT_TIFF:
927                 asset->format = FILE_TIFF;
928                 asset->tiff_cmodel = 0;
929                 asset->tiff_compression = 0;
930                 break;
931         case SNAPSHOT_PPM:
932                 asset->format = FILE_PPM;
933                 break;
934         }
935         asset->width = fw;
936         asset->height = fh;
937         asset->audio_data = 0;
938         asset->video_data = 1;
939         asset->video_length = 1;
940         asset->layers = 1;
941
942         File file;
943         int processors = preferences->project_smp + 1;
944         if( processors > 8 ) processors = 8;
945         file.set_processors(processors);
946         int ret = file.open_file(preferences, asset, 0, 1);
947         if( !ret ) {
948                 file.start_video_thread(1, fcolor_model,
949                         processors > 1 ? 2 : 1, 0);
950                 VFrame ***frames = file.get_video_buffer();
951                 VFrame *frame = frames[0][0];
952                 TransportCommand command(preferences);
953                 //command.command = audio_tracks ? NORMAL_FWD : CURRENT_FRAME;
954                 command.command = CURRENT_FRAME;
955                 command.get_edl()->copy_all(edl);
956                 command.change_type = CHANGE_ALL;
957                 command.realtime = 0;
958
959                 RenderEngine render_engine(0, preferences, 0, 0);
960                 CICache *video_cache = new CICache(preferences);
961                 render_engine.set_vcache(video_cache);
962                 render_engine.arm_command(&command);
963
964                 double position = edl->local_session->get_selectionstart(1);
965                 int64_t source_position = (int64_t)(position * edl->get_frame_rate());
966                 ret = !render_engine.vrender ? 1 :
967                         render_engine.vrender->process_buffer(frame, source_position, 0);
968                 if( !ret )
969                         ret = file.write_video_buffer(1);
970                 file.close_file();
971                 video_cache->remove_user();
972         }
973         if( !ret ) {
974                 asset->folder_no = AW_MEDIA_FOLDER;
975                 mwindow->edl->assets->append(asset);
976                 mwindow->awindow->gui->async_update_assets();
977         }
978         else {
979                 eprintf(_("snapshot render failed"));
980                 asset->remove_user();
981         }
982         return 1;
983 }
984
985
986 AssetGrabshot::AssetGrabshot(MWindow *mwindow, AssetListMenu *asset_list_menu)
987  : BC_MenuItem(_("Grabshot..."))
988 {
989         this->mwindow = mwindow;
990         this->asset_list_menu = asset_list_menu;
991 }
992
993 AssetGrabshot::~AssetGrabshot()
994 {
995 }
996
997 GrabshotSubMenu::GrabshotSubMenu(AssetGrabshot *asset_grabshot)
998 {
999         this->asset_grabshot = asset_grabshot;
1000 }
1001
1002 GrabshotSubMenu::~GrabshotSubMenu()
1003 {
1004 }
1005
1006 GrabshotMenuItem::GrabshotMenuItem(GrabshotSubMenu *submenu, const char *text, int mode)
1007  : BC_MenuItem(text)
1008 {
1009         this->submenu = submenu;
1010         this->mode = mode;
1011         grab_thread = 0;
1012 }
1013
1014 GrabshotMenuItem::~GrabshotMenuItem()
1015 {
1016         delete grab_thread;
1017 }
1018
1019 int GrabshotMenuItem::handle_event()
1020 {
1021         if( !grab_thread )
1022                 grab_thread = new GrabshotThread(submenu->asset_grabshot->mwindow);
1023         if( !grab_thread->running() )
1024                 grab_thread->start(this);
1025         return 1;
1026 }
1027
1028 GrabshotThread::GrabshotThread(MWindow *mwindow)
1029  : BC_DragBox(mwindow->gui)
1030 {
1031         this->mwindow = mwindow;
1032 }
1033
1034 GrabshotThread::~GrabshotThread()
1035 {
1036 }
1037
1038 void GrabshotThread::start(GrabshotMenuItem *menu_item)
1039 {
1040         mode = menu_item->mode;
1041         start_drag();
1042 }
1043
1044 int GrabshotThread::handle_done_event(int x0, int y0, int x1, int y1)
1045 {
1046         int cx = x0,    cy = y0;
1047         int cw = x1-x0, ch = y1-y0;
1048
1049         Preferences *preferences = mwindow->preferences;
1050         char filename[BCTEXTLEN], snapshot_path[BCTEXTLEN];
1051         static const char *exts[] = { "png", "jpg", "tif", "ppm" };
1052         time_t tt;     time(&tt);
1053         struct tm tm;  localtime_r(&tt,&tm);
1054         File::getenv_path(snapshot_path, preferences->snapshot_path);
1055         snprintf(filename,sizeof(filename),"%s/%s_%04d%02d%02d-%02d%02d%02d.%s",
1056                 snapshot_path, _("grab"),
1057                 1900+tm.tm_year,1+tm.tm_mon,tm.tm_mday,
1058                 tm.tm_hour,tm.tm_min,tm.tm_sec, exts[mode]);
1059         char *asset_path = FileSystem::basepath(filename);
1060         Asset *asset = new Asset(asset_path);
1061         delete [] asset_path;
1062         switch( mode ) {
1063         case GRABSHOT_PNG:
1064                 asset->format = FILE_PNG;
1065                 asset->png_use_alpha = 1;
1066                 break;
1067         case GRABSHOT_JPEG:
1068                 asset->format = FILE_JPEG;
1069                 asset->jpeg_quality = 90;
1070                 break;
1071         case GRABSHOT_TIFF:
1072                 asset->format = FILE_TIFF;
1073                 asset->tiff_cmodel = 0;
1074                 asset->tiff_compression = 0;
1075                 break;
1076         case GRABSHOT_PPM:
1077                 asset->format = FILE_PPM;
1078                 break;
1079         }
1080
1081 // no odd dimensions
1082         int rw = mwindow->gui->get_root_w(0);
1083         int rh = mwindow->gui->get_root_h(0);
1084         if( cx < 0 ) { cw += cx;  cx = 0; }
1085         if( cy < 0 ) { ch += cy;  cy = 0; }
1086         if( cx+cw > rw ) cw = rw-cx;
1087         if( cy+ch > rh ) ch = rh-cy;
1088         if( !cw || !ch ) return 0;
1089
1090         VFrame vframe(cw,ch, BC_RGB888);
1091         if( cx+cw < rw ) ++cw;
1092         if( cy+ch < rh ) ++ch;
1093         BC_Capture capture_bitmap(cw,ch, 0);
1094         capture_bitmap.capture_frame(&vframe, cx,cy);
1095
1096         asset->width = vframe.get_w();
1097         asset->height = vframe.get_h();
1098         asset->audio_data = 0;
1099         asset->video_data = 1;
1100         asset->video_length = 1;
1101         asset->layers = 1;
1102
1103         File file;
1104         int fcolor_model = mwindow->edl->session->color_model;
1105         int processors = preferences->project_smp + 1;
1106         if( processors > 8 ) processors = 8;
1107         file.set_processors(processors);
1108         int ret = file.open_file(preferences, asset, 0, 1);
1109         if( !ret ) {
1110                 file.start_video_thread(1, fcolor_model,
1111                         processors > 1 ? 2 : 1, 0);
1112                 VFrame ***frames = file.get_video_buffer();
1113                 VFrame *frame = frames[0][0];
1114                 frame->transfer_from(&vframe);
1115                 ret = file.write_video_buffer(1);
1116                 file.close_file();
1117         }
1118         if( !ret ) {
1119                 asset->folder_no = AW_MEDIA_FOLDER;
1120                 mwindow->edl->assets->append(asset);
1121                 mwindow->awindow->gui->async_update_assets();
1122         }
1123         else {
1124                 eprintf(_("grabshot render failed"));
1125                 asset->remove_user();
1126         }
1127
1128         return 1;
1129 }
1130