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