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