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