rework undo compression, add shift viewer overwr/copy/clip/splice, fix paste edl...
[goodguy/history.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 "filexml.h"
36 #include "language.h"
37 #include "localsession.h"
38 #include "mainerror.h"
39 #include "mainindexes.h"
40 #include "mainsession.h"
41 #include "mwindow.h"
42 #include "mwindowgui.h"
43 #include "track.h"
44 #include "tracks.h"
45 #include "vwindow.h"
46 #include "vwindowgui.h"
47
48
49
50 ClipPopup::ClipPopup(MWindow *mwindow, AWindowGUI *gui)
51  : BC_PopupMenu(0, 0, 0, "", 0)
52 {
53         this->mwindow = mwindow;
54         this->gui = gui;
55 }
56
57 ClipPopup::~ClipPopup()
58 {
59 }
60
61 void ClipPopup::create_objects()
62 {
63         BC_MenuItem *menu_item;
64         BC_SubMenu *submenu;
65         add_item(info = new ClipPopupInfo(mwindow, this));
66         add_item(format = new AWindowListFormat(mwindow, gui));
67         add_item(new ClipPopupSort(mwindow, this));
68         add_item(view = new ClipPopupView(mwindow, this));
69         add_item(view_window = new ClipPopupViewWindow(mwindow, this));
70         add_item(new ClipPopupCopy(mwindow, this));
71         add_item(new ClipPopupNest(mwindow, this));
72         add_item(new ClipPopupUnNest(mwindow, this));
73         add_item(new ClipPopupPaste(mwindow, this));
74         add_item(menu_item = new BC_MenuItem(_("Match...")));
75         menu_item->add_submenu(submenu = new BC_SubMenu());
76         submenu->add_submenuitem(new ClipMatchSize(mwindow, this));
77         submenu->add_submenuitem(new ClipMatchRate(mwindow, this));
78         submenu->add_submenuitem(new ClipMatchAll(mwindow, this));
79         add_item(new ClipPopupDelete(mwindow, this));
80 }
81
82 void ClipPopup::paste_assets()
83 {
84 // Collect items into the drag vectors for temporary storage
85         gui->lock_window("ClipPopup::paste_assets");
86         mwindow->gui->lock_window("ClipPopup::paste_assets");
87         mwindow->cwindow->gui->lock_window("ClipPopup::paste_assets");
88
89         gui->collect_assets();
90         mwindow->paste_assets(mwindow->edl->local_session->get_selectionstart(1),
91                 mwindow->edl->tracks->first,
92                 0);   // do not overwrite
93
94         gui->unlock_window();
95         mwindow->gui->unlock_window();
96         mwindow->cwindow->gui->unlock_window();
97 }
98
99 void ClipPopup::match_size()
100 {
101 // Collect items into the drag vectors for temporary storage
102         gui->collect_assets();
103         mwindow->gui->lock_window("ClipPopup::match_size");
104         mwindow->asset_to_size();
105         mwindow->gui->unlock_window();
106 }
107
108 void ClipPopup::match_rate()
109 {
110 // Collect items into the drag vectors for temporary storage
111         gui->collect_assets();
112         mwindow->gui->lock_window("ClipPopup::match_rate");
113         mwindow->asset_to_rate();
114         mwindow->gui->unlock_window();
115 }
116
117 void ClipPopup::match_all()
118 {
119 // Collect items into the drag vectors for temporary storage
120         gui->collect_assets();
121         mwindow->gui->lock_window("ClipPopup::match_rate");
122         mwindow->asset_to_all();
123         mwindow->gui->unlock_window();
124 }
125
126 int ClipPopup::update()
127 {
128         format->update();
129         gui->collect_assets();
130         return 0;
131 }
132
133
134 ClipPopupInfo::ClipPopupInfo(MWindow *mwindow, ClipPopup *popup)
135  : BC_MenuItem(_("Info..."))
136 {
137         this->mwindow = mwindow;
138         this->popup = popup;
139 }
140
141 ClipPopupInfo::~ClipPopupInfo()
142 {
143 }
144
145 int ClipPopupInfo::handle_event()
146 {
147         int cur_x, cur_y;
148         popup->gui->get_abs_cursor(cur_x, cur_y, 0);
149
150         if( mwindow->session->drag_assets->total ) {
151                 AssetEdit *asset_edit = mwindow->awindow->get_asset_editor();
152                 asset_edit->edit_asset(
153                         mwindow->session->drag_assets->values[0], cur_x, cur_y);
154         }
155         else
156         if( mwindow->session->drag_clips->total ) {
157                 popup->gui->awindow->clip_edit->edit_clip(
158                         mwindow->session->drag_clips->values[0], cur_x, cur_y);
159         }
160         return 1;
161 }
162
163
164 ClipPopupSort::ClipPopupSort(MWindow *mwindow, ClipPopup *popup)
165  : BC_MenuItem(_("Sort items"))
166 {
167         this->mwindow = mwindow;
168         this->popup = popup;
169 }
170
171 ClipPopupSort::~ClipPopupSort()
172 {
173 }
174
175 int ClipPopupSort::handle_event()
176 {
177         mwindow->awindow->gui->sort_assets(0);
178         return 1;
179 }
180
181
182 ClipPopupView::ClipPopupView(MWindow *mwindow, ClipPopup *popup)
183  : BC_MenuItem(_("View"))
184 {
185         this->mwindow = mwindow;
186         this->popup = popup;
187 }
188
189 ClipPopupView::~ClipPopupView()
190 {
191 }
192
193 int ClipPopupView::handle_event()
194 {
195         VWindow *vwindow = mwindow->get_viewer(1, DEFAULT_VWINDOW);
196
197         if( mwindow->session->drag_assets->total )
198                 vwindow->change_source(
199                         mwindow->session->drag_assets->values[0]);
200         else
201         if( mwindow->session->drag_clips->total )
202                 vwindow->change_source(
203                         mwindow->session->drag_clips->values[0]);
204
205         return 1;
206 }
207
208
209 ClipPopupViewWindow::ClipPopupViewWindow(MWindow *mwindow, ClipPopup *popup)
210  : BC_MenuItem(_("View in new window"))
211 {
212         this->mwindow = mwindow;
213         this->popup = popup;
214 }
215
216 ClipPopupViewWindow::~ClipPopupViewWindow()
217 {
218 }
219
220 int ClipPopupViewWindow::handle_event()
221 {
222 // Find window with nothing
223         VWindow *vwindow = mwindow->get_viewer(1);
224
225 // TODO: create new vwindow or change current vwindow
226         vwindow->gui->lock_window("ClipPopupView::handle_event");
227
228         if( mwindow->session->drag_assets->total )
229                 vwindow->change_source(
230                         mwindow->session->drag_assets->values[0]);
231         else
232         if( mwindow->session->drag_clips->total )
233                 vwindow->change_source(
234                         mwindow->session->drag_clips->values[0]);
235
236         vwindow->gui->unlock_window();
237         return 1;
238 }
239
240
241 ClipPopupCopy::ClipPopupCopy(MWindow *mwindow, ClipPopup *popup)
242  : BC_MenuItem(_("Copy"))
243 {
244         this->mwindow = mwindow;
245         this->popup = popup;
246 }
247 ClipPopupCopy::~ClipPopupCopy()
248 {
249 }
250
251 int ClipPopupCopy::handle_event()
252 {
253         MWindowGUI *gui = mwindow->gui;
254         gui->lock_window("ClipPopupCopy::handle_event");
255         if( mwindow->session->drag_clips->total > 0 ) {
256                 EDL *edl = mwindow->session->drag_clips->values[0];
257                 EDL *copy_edl = new EDL; // no parent or assets wont be copied
258                 copy_edl->create_objects();
259                 copy_edl->copy_all(edl);
260                 FileXML file;
261                 double start = 0, end = edl->tracks->total_length();
262                 copy_edl->copy(start, end, 1, &file, "", 1);
263                 copy_edl->remove_user();
264                 const char *file_string = file.string();
265                 long file_length = strlen(file_string);
266                 gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
267                 gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
268         }
269         gui->unlock_window(); 
270         return 1;
271 }
272
273
274 ClipPopupPaste::ClipPopupPaste(MWindow *mwindow, ClipPopup *popup)
275  : BC_MenuItem(_("Paste"))
276 {
277         this->mwindow = mwindow;
278         this->popup = popup;
279 }
280
281 ClipPopupPaste::~ClipPopupPaste()
282 {
283 }
284
285 int ClipPopupPaste::handle_event()
286 {
287         popup->paste_assets();
288         return 1;
289 }
290
291
292 ClipMatchSize::ClipMatchSize(MWindow *mwindow, ClipPopup *popup)
293  : BC_MenuItem(_("Match project size"))
294 {
295         this->mwindow = mwindow;
296         this->popup = popup;
297 }
298
299 int ClipMatchSize::handle_event()
300 {
301         popup->match_size();
302         return 1;
303 }
304
305
306 ClipMatchRate::ClipMatchRate(MWindow *mwindow, ClipPopup *popup)
307  : BC_MenuItem(_("Match frame rate"))
308 {
309         this->mwindow = mwindow;
310         this->popup = popup;
311 }
312
313 int ClipMatchRate::handle_event()
314 {
315         popup->match_rate();
316         return 1;
317 }
318
319
320 ClipMatchAll::ClipMatchAll(MWindow *mwindow, ClipPopup *popup)
321  : BC_MenuItem(_("Match all"))
322 {
323         this->mwindow = mwindow;
324         this->popup = popup;
325 }
326
327 int ClipMatchAll::handle_event()
328 {
329         popup->match_all();
330         return 1;
331 }
332
333
334 ClipPopupDelete::ClipPopupDelete(MWindow *mwindow, ClipPopup *popup)
335  : BC_MenuItem(_("Delete"))
336 {
337         this->mwindow = mwindow;
338         this->popup = popup;
339 }
340
341
342 ClipPopupDelete::~ClipPopupDelete()
343 {
344 }
345
346 int ClipPopupDelete::handle_event()
347 {
348         mwindow->remove_assets_from_project(1, 1,
349                 mwindow->session->drag_assets,
350                 mwindow->session->drag_clips);
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->session->drag_clips->total > 0 ) {
436                 EDL *edl = mwindow->edl;
437                 EDL *clip = mwindow->session->drag_clips->values[0];
438                 EDL *clip_edl = new EDL;  // no parent for nested clip
439                 clip_edl->create_objects();
440                 clip_edl->copy_all(clip);
441                 EDL *new_clip = new EDL(edl);
442                 new_clip->create_objects();
443                 new_clip->awindow_folder = AW_CLIP_FOLDER;
444                 snprintf(new_clip->local_session->clip_title,
445                         sizeof(new_clip->local_session->clip_title),
446                         _("Nested: %s"), clip->local_session->clip_title);
447                 strcpy(new_clip->local_session->clip_notes,
448                         clip->local_session->clip_notes);
449                 time_t dt;      time(&dt);
450                 struct tm dtm;  localtime_r(&dt, &dtm);
451                 char path[BCSTRLEN];
452                 sprintf(path, _("Nested_%02d%02d%02d-%02d%02d%02d"),
453                         dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
454                         dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
455                 clip_edl->set_path(path);
456                 sprintf(new_clip->local_session->clip_icon,
457                         "clip_%02d%02d%02d-%02d%02d%02d.png",
458                         dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
459                         dtm.tm_hour, dtm.tm_min, dtm.tm_sec);
460                 new_clip->set_path(path);
461                 new_clip->to_nested(clip_edl);
462                 int idx = edl->clips.number_of(clip);
463                 if( idx >= 0 ) {
464                         edl->clips[idx] = new_clip;
465                         clip->remove_user();
466                 }
467                 else
468                         edl->clips.append(new_clip);
469                 mwindow->mainindexes->add_next_asset(0, clip_edl);
470                 mwindow->mainindexes->start_build();
471                 clip_edl->remove_user();
472                 popup->gui->async_update_assets();
473         }
474         gui->unlock_window();
475         return 1;
476 }
477
478
479 ClipPopupUnNest::ClipPopupUnNest(MWindow *mwindow, ClipPopup *popup)
480  : BC_MenuItem(_("UnNest"))
481 {
482         this->mwindow = mwindow;
483         this->popup = popup;
484 }
485 ClipPopupUnNest::~ClipPopupUnNest()
486 {
487 }
488
489 int ClipPopupUnNest::handle_event()
490 {
491         EDL *nested_edl = 0;
492         MWindowGUI *gui = mwindow->gui;
493         gui->lock_window("ClipPopupUnNest::handle_event 1");
494         if( mwindow->session->drag_clips->total > 0 ) {
495                 EDL *clip = mwindow->session->drag_clips->values[0];
496                 Track *track = clip->tracks->first;
497                 Edit *edit = track ? track->edits->first : 0;
498                 nested_edl = edit && !edit->next && !edit->asset ? edit->nested_edl : 0;
499                 while( nested_edl && (track=track->next)!=0 ) {
500                         Edit *edit = track->edits->first;
501                         if( !edit || edit->next || edit->nested_edl != nested_edl )
502                                 nested_edl = 0;
503                 }
504                 if( nested_edl ) {
505                         EDL *edl = mwindow->edl;
506                         EDL *new_clip = new EDL(edl);
507                         new_clip->create_objects();
508                         new_clip->copy_all(nested_edl);
509                         new_clip->awindow_folder = AW_CLIP_FOLDER;
510                         int idx = edl->clips.number_of(clip);
511                         if( idx >= 0 ) {
512                                 edl->clips[idx] = new_clip;
513                                 clip->remove_user();
514                         }
515                         else
516                                 edl->clips.append(new_clip);
517                         popup->gui->async_update_assets();
518                 }
519         }
520         gui->unlock_window();
521         return 1;
522 }
523