upgrade to ffmpeg 4.2, rework mask for speedup
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / clippopup.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 "assetedit.h"
23 #include "clippopup.h"
24 #include "assetremove.h"
25 #include "awindow.h"
26 #include "awindowgui.h"
27 #include "bcsignals.h"
28 #include "clipedit.h"
29 #include "clipedls.h"
30 #include "cwindow.h"
31 #include "cwindowgui.h"
32 #include "edit.h"
33 #include "edits.h"
34 #include "edl.h"
35 #include "edlsession.h"
36 #include "filexml.h"
37 #include "language.h"
38 #include "localsession.h"
39 #include "mainerror.h"
40 #include "mainindexes.h"
41 #include "mainsession.h"
42 #include "mwindow.h"
43 #include "mwindowgui.h"
44 #include "track.h"
45 #include "tracks.h"
46 #include "vwindow.h"
47 #include "vwindowgui.h"
48
49
50
51 ClipPopup::ClipPopup(MWindow *mwindow, AWindowGUI *gui)
52  : BC_PopupMenu(0, 0, 0, "", 0)
53 {
54         this->mwindow = mwindow;
55         this->gui = gui;
56 }
57
58 ClipPopup::~ClipPopup()
59 {
60 }
61
62 void ClipPopup::create_objects()
63 {
64         BC_MenuItem *menu_item;
65         BC_SubMenu *submenu;
66         add_item(info = new ClipPopupInfo(mwindow, this));
67         add_item(format = new AWindowListFormat(mwindow, gui));
68         add_item(new ClipPopupSort(mwindow, this));
69         add_item(view = new ClipPopupView(mwindow, this));
70         add_item(view_window = new ClipPopupViewWindow(mwindow, this));
71         add_item(new ClipPopupCopy(mwindow, this));
72         add_item(new ClipPopupNest(mwindow, this));
73         add_item(new ClipPopupUnNest(mwindow, this));
74         add_item(new ClipPopupPaste(mwindow, this));
75         add_item(menu_item = new BC_MenuItem(_("Match...")));
76         menu_item->add_submenu(submenu = new BC_SubMenu());
77         submenu->add_submenuitem(new ClipMatchSize(mwindow, this));
78         submenu->add_submenuitem(new ClipMatchRate(mwindow, this));
79         submenu->add_submenuitem(new ClipMatchAll(mwindow, this));
80         add_item(new ClipPopupDelete(mwindow, this));
81 }
82
83 void ClipPopup::paste_assets()
84 {
85 // Collect items into the drag vectors for temporary storage
86         gui->lock_window("ClipPopup::paste_assets");
87         mwindow->gui->lock_window("ClipPopup::paste_assets");
88         mwindow->cwindow->gui->lock_window("ClipPopup::paste_assets");
89
90         gui->collect_assets();
91         mwindow->paste_assets(mwindow->edl->local_session->get_selectionstart(1),
92                 mwindow->edl->tracks->first,
93                 0);   // do not overwrite
94
95         gui->unlock_window();
96         mwindow->gui->unlock_window();
97         mwindow->cwindow->gui->unlock_window();
98 }
99
100 void ClipPopup::match_size()
101 {
102 // Collect items into the drag vectors for temporary storage
103         gui->collect_assets();
104         mwindow->gui->lock_window("ClipPopup::match_size");
105         mwindow->asset_to_size();
106         mwindow->gui->unlock_window();
107 }
108
109 void ClipPopup::match_rate()
110 {
111 // Collect items into the drag vectors for temporary storage
112         gui->collect_assets();
113         mwindow->gui->lock_window("ClipPopup::match_rate");
114         mwindow->asset_to_rate();
115         mwindow->gui->unlock_window();
116 }
117
118 void ClipPopup::match_all()
119 {
120 // Collect items into the drag vectors for temporary storage
121         gui->collect_assets();
122         mwindow->gui->lock_window("ClipPopup::match_rate");
123         mwindow->asset_to_all();
124         mwindow->gui->unlock_window();
125 }
126
127 int ClipPopup::update()
128 {
129         format->update();
130         gui->collect_assets();
131         return 0;
132 }
133
134
135 ClipPopupInfo::ClipPopupInfo(MWindow *mwindow, ClipPopup *popup)
136  : BC_MenuItem(_("Info..."))
137 {
138         this->mwindow = mwindow;
139         this->popup = popup;
140 }
141
142 ClipPopupInfo::~ClipPopupInfo()
143 {
144 }
145
146 int ClipPopupInfo::handle_event()
147 {
148         int cur_x, cur_y;
149         popup->gui->get_abs_cursor(cur_x, cur_y, 0);
150
151         if( mwindow->session->drag_assets->total ) {
152                 AssetEdit *asset_edit = mwindow->awindow->get_asset_editor();
153                 asset_edit->edit_asset(
154                         mwindow->session->drag_assets->values[0], cur_x, cur_y);
155         }
156         else
157         if( mwindow->session->drag_clips->total ) {
158                 popup->gui->awindow->clip_edit->edit_clip(
159                         mwindow->session->drag_clips->values[0], cur_x, cur_y);
160         }
161         return 1;
162 }
163
164
165 ClipPopupSort::ClipPopupSort(MWindow *mwindow, ClipPopup *popup)
166  : BC_MenuItem(_("Sort items"))
167 {
168         this->mwindow = mwindow;
169         this->popup = popup;
170 }
171
172 ClipPopupSort::~ClipPopupSort()
173 {
174 }
175
176 int ClipPopupSort::handle_event()
177 {
178         mwindow->awindow->gui->sort_assets();
179         return 1;
180 }
181
182
183 ClipPopupView::ClipPopupView(MWindow *mwindow, ClipPopup *popup)
184  : BC_MenuItem(_("View"))
185 {
186         this->mwindow = mwindow;
187         this->popup = popup;
188 }
189
190 ClipPopupView::~ClipPopupView()
191 {
192 }
193
194 int ClipPopupView::handle_event()
195 {
196         VWindow *vwindow = mwindow->get_viewer(1, DEFAULT_VWINDOW);
197
198         if( mwindow->session->drag_assets->total )
199                 vwindow->change_source(
200                         mwindow->session->drag_assets->values[0]);
201         else
202         if( mwindow->session->drag_clips->total )
203                 vwindow->change_source(
204                         mwindow->session->drag_clips->values[0]);
205
206         return 1;
207 }
208
209
210 ClipPopupViewWindow::ClipPopupViewWindow(MWindow *mwindow, ClipPopup *popup)
211  : BC_MenuItem(_("View in new window"))
212 {
213         this->mwindow = mwindow;
214         this->popup = popup;
215 }
216
217 ClipPopupViewWindow::~ClipPopupViewWindow()
218 {
219 }
220
221 int ClipPopupViewWindow::handle_event()
222 {
223         for( int i=0; i<mwindow->session->drag_assets->size(); ++i ) {
224                 VWindow *vwindow = mwindow->get_viewer(1);
225                 vwindow->gui->lock_window("ClipPopupView::handle_event 1");
226                 vwindow->change_source(mwindow->session->drag_assets->get(i));
227                 vwindow->gui->unlock_window();
228         }
229         for( int i=0; i<mwindow->session->drag_clips->size(); ++i ) {
230                 VWindow *vwindow = mwindow->get_viewer(1);
231                 vwindow->gui->lock_window("ClipPopupView::handle_event 2");
232                 vwindow->change_source(mwindow->session->drag_clips->get(i));
233                 vwindow->gui->unlock_window();
234         }
235         return 1;
236 }
237
238
239 ClipPopupCopy::ClipPopupCopy(MWindow *mwindow, ClipPopup *popup)
240  : BC_MenuItem(_("Copy"))
241 {
242         this->mwindow = mwindow;
243         this->popup = popup;
244 }
245 ClipPopupCopy::~ClipPopupCopy()
246 {
247 }
248
249 int ClipPopupCopy::handle_event()
250 {
251         MWindowGUI *gui = mwindow->gui;
252         gui->lock_window("ClipPopupCopy::handle_event");
253         if( mwindow->session->drag_clips->total > 0 ) {
254                 EDL *edl = mwindow->session->drag_clips->values[0];
255                 EDL *copy_edl = new EDL; // no parent or assets wont be copied
256                 copy_edl->create_objects();
257                 copy_edl->copy_all(edl);
258                 FileXML file;
259                 double start = 0, end = edl->tracks->total_length();
260                 copy_edl->copy(COPY_EDL, start, end, &file, "", 1);
261                 copy_edl->remove_user();
262                 const char *file_string = file.string();
263                 long file_length = strlen(file_string);
264                 gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
265                 gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
266         }
267         gui->unlock_window(); 
268         return 1;
269 }
270
271
272 ClipPopupPaste::ClipPopupPaste(MWindow *mwindow, ClipPopup *popup)
273  : BC_MenuItem(_("Paste"))
274 {
275         this->mwindow = mwindow;
276         this->popup = popup;
277 }
278
279 ClipPopupPaste::~ClipPopupPaste()
280 {
281 }
282
283 int ClipPopupPaste::handle_event()
284 {
285         popup->paste_assets();
286         return 1;
287 }
288
289
290 ClipMatchSize::ClipMatchSize(MWindow *mwindow, ClipPopup *popup)
291  : BC_MenuItem(_("Match project size"))
292 {
293         this->mwindow = mwindow;
294         this->popup = popup;
295 }
296
297 int ClipMatchSize::handle_event()
298 {
299         popup->match_size();
300         return 1;
301 }
302
303
304 ClipMatchRate::ClipMatchRate(MWindow *mwindow, ClipPopup *popup)
305  : BC_MenuItem(_("Match frame rate"))
306 {
307         this->mwindow = mwindow;
308         this->popup = popup;
309 }
310
311 int ClipMatchRate::handle_event()
312 {
313         popup->match_rate();
314         return 1;
315 }
316
317
318 ClipMatchAll::ClipMatchAll(MWindow *mwindow, ClipPopup *popup)
319  : BC_MenuItem(_("Match all"))
320 {
321         this->mwindow = mwindow;
322         this->popup = popup;
323 }
324
325 int ClipMatchAll::handle_event()
326 {
327         popup->match_all();
328         return 1;
329 }
330
331
332 ClipPopupDelete::ClipPopupDelete(MWindow *mwindow, ClipPopup *popup)
333  : BC_MenuItem(_("Delete"))
334 {
335         this->mwindow = mwindow;
336         this->popup = popup;
337 }
338
339
340 ClipPopupDelete::~ClipPopupDelete()
341 {
342 }
343
344 int ClipPopupDelete::handle_event()
345 {
346         popup->gui->unlock_window();
347         mwindow->remove_assets_from_project(1, 1,
348                 mwindow->session->drag_assets,
349                 mwindow->session->drag_clips);
350         popup->gui->lock_window("ClipPopupDelete::handle_event");
351         return 1;
352 }
353
354
355 ClipPasteToFolder::ClipPasteToFolder(MWindow *mwindow)
356  : BC_MenuItem(_("Paste Clip"))
357 {
358         this->mwindow = mwindow;
359 }
360
361 int ClipPasteToFolder::handle_event()
362 {
363         MWindowGUI *gui = mwindow->gui;
364         gui->lock_window("ClipPasteToFolder::handle_event 1");
365         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
366         if( len ) {
367                 char *string = new char[len];
368                 gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
369                 const char *clip_header = "<EDL VERSION=";
370                 if( !strncmp(clip_header, string, strlen(clip_header)) ) {
371                         FileXML file;
372                         file.read_from_string(string);
373                         EDL *edl = mwindow->edl;
374                         EDL *new_edl = new EDL(mwindow->edl);
375                         new_edl->create_objects();
376                         new_edl->load_xml(&file, LOAD_ALL);
377                         edl->update_assets(new_edl);
378                         mwindow->save_clip(new_edl, _("paste clip: "));
379                 }
380                 else {
381                         char *cp = strchr(string, '\n');
382                         if( cp-string < 32 ) *cp = 0;
383                         else if( len > 32 ) string[32] = 0;
384                         eprintf("paste buffer is not EDL:\n%s", string);
385                 }
386                 delete [] string;
387         }
388         else {
389                 eprintf("paste buffer empty");
390         }
391         gui->unlock_window();
392         return 1;
393 }
394
395
396 ClipListMenu::ClipListMenu(MWindow *mwindow, AWindowGUI *gui)
397  : BC_PopupMenu(0, 0, 0, "", 0)
398 {
399         this->mwindow = mwindow;
400         this->gui = gui;
401 }
402
403 ClipListMenu::~ClipListMenu()
404 {
405 }
406
407 void ClipListMenu::create_objects()
408 {
409         add_item(format = new AWindowListFormat(mwindow, gui));
410         add_item(new AWindowListSort(mwindow, gui));
411         add_item(new ClipPasteToFolder(mwindow));
412         update();
413 }
414
415 void ClipListMenu::update()
416 {
417         format->update();
418 }
419
420
421 ClipPopupNest::ClipPopupNest(MWindow *mwindow, ClipPopup *popup)
422  : BC_MenuItem(_("Nest"))
423 {
424         this->mwindow = mwindow;
425         this->popup = popup;
426 }
427 ClipPopupNest::~ClipPopupNest()
428 {
429 }
430
431 int ClipPopupNest::handle_event()
432 {
433         MWindowGUI *gui = mwindow->gui;
434         gui->lock_window("ClipPopupNest::handle_event 1");
435         if( mwindow->edl->session->proxy_scale != 1 ) {
436                 eprintf("Nesting not allowed when proxy scale != 1");
437                 return 1;
438         }
439         int clips_total = mwindow->session->drag_clips->total;
440         for( int i=0; i<clips_total; ++i ) {
441                 EDL *edl = mwindow->edl;
442                 time_t dt;      time(&dt);
443                 struct tm dtm;  localtime_r(&dt, &dtm);
444                 char path[BCSTRLEN];
445                 sprintf(path, _("Nested_%02d%02d%02d-%02d%02d%02d"),
446                         dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
447                         dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
448                 EDL *clip = mwindow->session->drag_clips->values[i];
449                 EDL *nested = edl->new_nested(clip, path);
450                 EDL *new_clip = edl->create_nested_clip(nested);
451                 new_clip->folder_no = AW_CLIP_FOLDER;
452                 sprintf(new_clip->local_session->clip_icon,
453                         "clip_%02d%02d%02d-%02d%02d%02d.png",
454                         dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
455                         dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
456                 snprintf(new_clip->local_session->clip_title,
457                         sizeof(new_clip->local_session->clip_title),
458                         _("Nested: %s"), clip->local_session->clip_title);
459                 strcpy(new_clip->local_session->clip_notes,
460                 clip->local_session->clip_notes);
461                 int idx = edl->clips.number_of(clip);
462                 if( idx >= 0 ) {
463                         edl->clips[idx] = new_clip;
464                         clip->remove_user();
465                 }
466                 else
467                         edl->clips.append(new_clip);
468                 mwindow->mainindexes->add_next_asset(0, nested);
469         }
470         mwindow->mainindexes->start_build();
471         popup->gui->async_update_assets();
472         gui->unlock_window();
473         return 1;
474 }
475
476
477 ClipPopupUnNest::ClipPopupUnNest(MWindow *mwindow, ClipPopup *popup)
478  : BC_MenuItem(_("UnNest"))
479 {
480         this->mwindow = mwindow;
481         this->popup = popup;
482 }
483 ClipPopupUnNest::~ClipPopupUnNest()
484 {
485 }
486
487 int ClipPopupUnNest::handle_event()
488 {
489         EDL *nested_edl = 0;
490         MWindowGUI *gui = mwindow->gui;
491         gui->lock_window("ClipPopupUnNest::handle_event 1");
492         int clips_total = mwindow->session->drag_clips->total;
493         for( int i=0; i<clips_total; ++i ) {
494                 EDL *clip = mwindow->session->drag_clips->values[i];
495                 Track *track = clip->tracks->first;
496                 Edit *edit = track ? track->edits->first : 0;
497                 nested_edl = edit && !edit->next && !edit->asset ? edit->nested_edl : 0;
498                 while( nested_edl && (track=track->next)!=0 ) {
499                         Edit *edit = track->edits->first;
500                         if( !edit || edit->next ||
501                             ( edit->nested_edl != nested_edl &&
502                               strcmp(edit->nested_edl->path, nested_edl->path) ) )
503                                 nested_edl = 0;
504                 }
505                 if( nested_edl ) {
506                         EDL *edl = mwindow->edl;
507                         EDL *new_clip = new EDL(edl);
508                         new_clip->create_objects();
509                         new_clip->copy_all(nested_edl);
510                         new_clip->folder_no = AW_CLIP_FOLDER;
511                         int idx = edl->clips.number_of(clip);
512                         if( idx >= 0 ) {
513                                 edl->clips[idx] = new_clip;
514                                 clip->remove_user();
515                         }
516                         else
517                                 edl->clips.append(new_clip);
518                         popup->gui->async_update_assets();
519                 }
520         }
521         gui->unlock_window();
522         return 1;
523 }
524