Credit ffmpeg team with upgrade to 6.1
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / mwindowedit.C
1 /*
2  * CINELERRA
3  * Copyright (C) 1997-2012 Adam Williams <broadcast at earthling dot net>
4  * Copyright (C) 2003-2016 Cinelerra CV contributors
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 "assets.h"
24 #include "awindowgui.h"
25 #include "awindow.h"
26 #include "bcsignals.h"
27 #include "cache.h"
28 #include "clip.h"
29 #include "clipedit.h"
30 #include "commercials.h"
31 #include "convert.h"
32 #include "cplayback.h"
33 #include "ctimebar.h"
34 #include "cwindow.h"
35 #include "cwindowgui.h"
36 #include "bchash.h"
37 #include "edl.h"
38 #include "edlsession.h"
39 #include "filesystem.h"
40 #include "filexml.h"
41 #include "floatauto.h"
42 #include "floatautos.h"
43 #include "gwindow.h"
44 #include "gwindowgui.h"
45 #include "keyframe.h"
46 #include "keyframes.h"
47 #include "language.h"
48 #include "labels.h"
49 #include "levelwindow.h"
50 #include "localsession.h"
51 #include "mainclock.h"
52 #include "maincursor.h"
53 #include "mainerror.h"
54 #include "mainindexes.h"
55 #include "mainmenu.h"
56 #include "mainsession.h"
57 #include "mainundo.h"
58 #include "maskautos.h"
59 #include "mtimebar.h"
60 #include "mwindowgui.h"
61 #include "mwindow.h"
62 #include "panauto.h"
63 #include "patchbay.h"
64 #include "playbackengine.h"
65 #include "pluginset.h"
66 #include "recordlabel.h"
67 #include "samplescroll.h"
68 #include "trackcanvas.h"
69 #include "track.h"
70 #include "trackscroll.h"
71 #include "tracks.h"
72 #include "transition.h"
73 #include "transportque.h"
74 #include "units.h"
75 #include "undostackitem.h"
76 #include "vplayback.h"
77 #include "vwindow.h"
78 #include "vwindowgui.h"
79 #include "zoombar.h"
80 #include "zwindow.h"
81 #include "automation.h"
82 #include "maskautos.h"
83
84 #include <string.h>
85
86 void MWindow::add_audio_track_entry(int above, Track *dst)
87 {
88         undo_before();
89         Track *track = add_audio_track(above, dst);
90         track->master = 1;
91         save_backup();
92         undo_after(_("add track"), LOAD_ALL);
93
94         restart_brender();
95         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
96         gui->activate_timeline();
97         cwindow->refresh_frame(CHANGE_EDL);
98 }
99
100 void MWindow::add_video_track_entry(int above, Track *dst)
101 {
102         undo_before();
103         Track *track = add_video_track(above, dst);
104         track->master = 1;
105         undo_after(_("add track"), LOAD_ALL);
106
107         restart_brender();
108
109         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
110         gui->activate_timeline();
111         cwindow->refresh_frame(CHANGE_EDL);
112         save_backup();
113 }
114
115 void MWindow::add_subttl_track_entry(int above, Track *dst)
116 {
117         undo_before();
118         Track *track = add_subttl_track(above, dst);
119         track->master = 1;
120         undo_after(_("add track"), LOAD_ALL);
121
122         restart_brender();
123
124         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
125         gui->activate_timeline();
126         cwindow->refresh_frame(CHANGE_EDL);
127         save_backup();
128 }
129
130
131 Track *MWindow::add_audio_track(int above, Track *dst)
132 {
133         Track *track = edl->tracks->add_audio_track(above, dst);
134         edl->tracks->update_y_pixels(theme);
135         save_backup();
136         return track;
137 }
138
139 Track *MWindow::add_video_track(int above, Track *dst)
140 {
141         Track *track = edl->tracks->add_video_track(above, dst);
142         edl->tracks->update_y_pixels(theme);
143         save_backup();
144         return track;
145 }
146
147 Track *MWindow::add_subttl_track(int above, Track *dst)
148 {
149         Track *track = edl->tracks->add_subttl_track(above, dst);
150         edl->tracks->update_y_pixels(theme);
151         save_backup();
152         return track;
153 }
154
155 void MWindow::asset_to_all()
156 {
157         if( !session->drag_assets->size() ) return;
158         Indexable *indexable = session->drag_assets->get(0);
159
160 //      if( indexable->have_video() )
161         {
162                 int w, h;
163
164                 undo_before();
165
166 // Get w and h
167                 w = indexable->get_w();
168                 h = indexable->get_h();
169                 double new_framerate = session->drag_assets->get(0)->get_frame_rate();
170                 double old_framerate = edl->session->frame_rate;
171                 int old_samplerate = edl->session->sample_rate;
172                 int new_samplerate = session->drag_assets->get(0)->get_sample_rate();
173
174
175                 if( indexable->have_video() ) {
176                         edl->session->output_w = w;
177                         edl->session->output_h = h;
178                         edl->session->frame_rate = new_framerate;
179                         create_aspect_ratio(
180                                 edl->session->aspect_w,
181                                 edl->session->aspect_h,
182                                 w, h);
183
184                         for( Track *current=edl->tracks->first; current; current=NEXT ) {
185                                 if( current->data_type == TRACK_VIDEO /* &&
186                                         current->is_armed() */  ) {
187                                         current->track_w = w;
188                                         current->track_h = h;
189                                 }
190                         }
191
192 #ifdef GLx4
193                         if( ((edl->session->output_w % 4) ||
194                                 (edl->session->output_h % 4)) &&
195                                 edl->session->playback_config->vconfig->driver == PLAYBACK_X11_GL ) {
196                                 MainError::show_error(
197                                         _("This project's dimensions are not multiples of 4 so\n"
198                                         "it can't be rendered by OpenGL."));
199                         }
200 #endif
201 // Get aspect ratio
202                         if( defaults->get("AUTOASPECT", 0) ) {
203                                 create_aspect_ratio(
204                                         edl->session->aspect_w,
205                                         edl->session->aspect_h,
206                                         w, h);
207                         }
208                 }
209
210                 if( indexable->have_audio() ) {
211                         edl->session->sample_rate = new_samplerate;
212                         edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
213                         edl->resample(old_samplerate, new_samplerate, TRACK_AUDIO);
214                 }
215
216                 save_backup();
217
218                 undo_after(_("asset to all"), LOAD_ALL);
219                 restart_brender();
220                 gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
221                 sync_parameters(CHANGE_ALL);
222         }
223 }
224
225 void MWindow::asset_to_size()
226 {
227         if( !session->drag_assets->size() ) return;
228         Indexable *indexable = session->drag_assets->get(0);
229
230         if( indexable->have_video() ) {
231                 int w, h;
232                 undo_before();
233
234 // Get w and h
235                 w = indexable->get_w();
236                 h = indexable->get_h();
237                 edl->session->output_w = w;
238                 edl->session->output_h = h;
239 #ifdef GLx4
240                 if( ((edl->session->output_w % 4) ||
241                         (edl->session->output_h % 4)) &&
242                         edl->session->playback_config->vconfig->driver == PLAYBACK_X11_GL ) {
243                         MainError::show_error(
244                                 _("This project's dimensions are not multiples of 4 so\n"
245                                 "it can't be rendered by OpenGL."));
246                 }
247 #endif
248 // Get aspect ratio
249                 if( defaults->get("AUTOASPECT", 0) ) {
250                         create_aspect_ratio(edl->session->aspect_w,
251                                 edl->session->aspect_h,
252                                 w,
253                                 h);
254                 }
255
256                 save_backup();
257
258                 undo_after(_("asset to size"), LOAD_ALL);
259                 restart_brender();
260                 sync_parameters(CHANGE_ALL);
261         }
262 }
263
264
265 void MWindow::asset_to_rate()
266 {
267         if( session->drag_assets->size() &&
268                 session->drag_assets->get(0)->have_video() ) {
269                 double new_framerate = session->drag_assets->get(0)->get_frame_rate();
270                 double old_framerate = edl->session->frame_rate;
271                 undo_before();
272
273                 edl->session->frame_rate = new_framerate;
274                 edl->resample(old_framerate, new_framerate, TRACK_VIDEO);
275
276                 save_backup();
277
278                 undo_after(_("asset to rate"), LOAD_ALL);
279                 restart_brender();
280                 gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
281                 sync_parameters(CHANGE_ALL);
282         }
283 }
284
285
286 void MWindow::clear_entry()
287 {
288         undo_before();
289         clear(1);
290
291         edl->optimize();
292         save_backup();
293         undo_after(_("clear"),
294                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
295
296         restart_brender();
297         update_plugin_guis();
298         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
299         cwindow->update(1, 0, 0, 0, 1);
300         cwindow->refresh_frame(CHANGE_EDL);
301 }
302
303 void MWindow::clear(int clear_handle)
304 {
305         double start = edl->local_session->get_selectionstart();
306         double end = edl->local_session->get_selectionend();
307         if( clear_handle || !EQUIV(start, end) ) {
308                 edl->clear(start,
309                         end,
310                         edl->session->labels_follow_edits,
311                         edl->session->plugins_follow_edits,
312                         edl->session->autos_follow_edits);
313         }
314 }
315
316 void MWindow::update_gui(int changed_edl)
317 {
318         restart_brender();
319         update_plugin_guis();
320         if( changed_edl ) {
321                 gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
322                 cwindow->update(1, 0, 0, 0, 1);
323                 cwindow->refresh_frame(CHANGE_EDL);
324         }
325         else {
326                 gui->draw_overlays(1);
327                 sync_parameters(CHANGE_PARAMS);
328                 gui->update_patchbay();
329                 cwindow->update(1, 0, 0);
330         }
331 }
332
333 void MWindow::set_automation_mode(int mode)
334 {
335         undo_before();
336         speed_before();
337         edl->tracks->set_automation_mode(
338                 edl->local_session->get_selectionstart(),
339                 edl->local_session->get_selectionend(),
340                 mode);
341         int changed_edl = speed_after(1, 1);
342         save_backup();
343         char string[BCSTRLEN];
344         sprintf(string,"set %s", FloatAuto::curve_name(mode));
345         undo_after(string,
346                 !changed_edl ? LOAD_AUTOMATION :
347                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
348         update_gui(changed_edl);
349 }
350
351 void MWindow::clear_automation()
352 {
353         undo_before();
354         speed_before();
355         edl->tracks->clear_automation(edl->local_session->get_selectionstart(),
356                 edl->local_session->get_selectionend());
357         int changed_edl = speed_after(1, 1);
358         save_backup();
359         undo_after(_("clear keyframes"),
360                 !changed_edl ? LOAD_AUTOMATION :
361                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
362         update_gui(changed_edl);
363 }
364
365 int MWindow::clear_default_keyframe()
366 {
367         undo_before();
368         speed_before();
369         edl->tracks->clear_default_keyframe();
370         int changed_edl = speed_after(1, 1);
371         save_backup();
372         undo_after(_("clear default keyframe"),
373                 !changed_edl ? LOAD_AUTOMATION :
374                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
375         update_gui(changed_edl);
376         return 0;
377 }
378
379 void MWindow::clear_labels()
380 {
381         undo_before();
382         clear_labels(edl->local_session->get_selectionstart(),
383                 edl->local_session->get_selectionend());
384         undo_after(_("clear labels"), LOAD_TIMEBAR);
385
386         gui->update_timebar(1);
387         cwindow->update(0, 0, 0, 0, 1);
388         save_backup();
389 }
390
391 int MWindow::clear_labels(double start, double end)
392 {
393         if( start == end ) {
394                 start = 0;
395                 end = edl->tracks->total_length();
396         }
397         edl->labels->clear(start, end, 0);
398         return 0;
399 }
400
401 void MWindow::clear_hard_edges()
402 {
403         undo_before();
404         clear_hard_edges(edl->local_session->get_selectionstart(),
405                 edl->local_session->get_selectionend());
406         edl->optimize();
407         save_backup();
408         undo_after(_("clear hard edges"), LOAD_EDITS);
409         restart_brender();
410         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
411         cwindow->refresh_frame(CHANGE_EDL);
412 }
413
414 int MWindow::clear_hard_edges(double start, double end)
415 {
416         if( start == end ) {
417                 start = 0;
418                 end = edl->tracks->total_length();
419         }
420         edl->clear_hard_edges(start, end);
421         return 0;
422 }
423
424 void MWindow::clear_select()
425 {
426         edl->tracks->clear_selected_edits();
427         gui->draw_overlays(1);
428 }
429
430 void MWindow::select_edits(int v)
431 {
432         double start = edl->local_session->get_selectionstart();
433         double end = edl->local_session->get_selectionend();
434         edl->tracks->select_edits(start, end, v);
435         gui->draw_overlays(1);
436 }
437
438 void MWindow::concatenate_tracks()
439 {
440         undo_before();
441         edl->tracks->concatenate_tracks(edl->session->plugins_follow_edits,
442                 edl->session->autos_follow_edits);
443         save_backup();
444         undo_after(_("concatenate tracks"), LOAD_EDITS);
445
446         restart_brender();
447         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
448         cwindow->refresh_frame(CHANGE_EDL);
449 }
450
451
452 int MWindow::copy_flags(int copy_flags)
453 {
454         if( !edl->session->labels_follow_edits )
455                 copy_flags &= ~COPY_LABELS;
456         if( !edl->session->autos_follow_edits )
457                 copy_flags &= ~COPY_AUTOS;
458         if( !edl->session->plugins_follow_edits )
459                 copy_flags &= ~COPY_PLUGINS;
460         return copy_flags;
461 }
462
463 void MWindow::copy()
464 {
465         copy(edl->local_session->get_selectionstart(),
466                 edl->local_session->get_selectionend());
467 }
468
469 int MWindow::copy(double start, double end)
470 {
471         if( start == end ) return 1;
472
473         FileXML file;
474         edl->copy(copy_flags(), start, end, &file, "", 1);
475         const char *file_string = file.string();
476         long file_length = strlen(file_string);
477         gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
478         gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
479         save_backup();
480         return 0;
481 }
482
483 int MWindow::copy_automation()
484 {
485         FileXML file;
486         double start = edl->local_session->get_selectionstart();
487         double end = edl->local_session->get_selectionend();
488         edl->tracks->copy_automation(start, end, &file, 0, 1);
489         const char *file_string = file.string();
490         long file_length = strlen(file_string);
491         gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
492         gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
493         return 0;
494 }
495
496 int MWindow::copy_default_keyframe()
497 {
498         FileXML file;
499         double start = edl->local_session->get_selectionstart();
500         double end = edl->local_session->get_selectionend();
501         edl->tracks->copy_automation(start, end, &file, 1, 0);
502         const char *file_string = file.string();
503         long file_length = strlen(file_string);
504         gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
505         gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
506         return 0;
507 }
508
509 // Uses cropping coordinates in edl session to crop and translate video.
510 // We modify the projector since camera automation depends on the track size.
511 void MWindow::crop_video(int mode)
512 {
513         undo_before();
514 // Clamp EDL crop region
515         if( edl->session->crop_x1 > edl->session->crop_x2 ) {
516                 edl->session->crop_x1 ^= edl->session->crop_x2;
517                 edl->session->crop_x2 ^= edl->session->crop_x1;
518                 edl->session->crop_x1 ^= edl->session->crop_x2;
519         }
520         if( edl->session->crop_y1 > edl->session->crop_y2 ) {
521                 edl->session->crop_y1 ^= edl->session->crop_y2;
522                 edl->session->crop_y2 ^= edl->session->crop_y1;
523                 edl->session->crop_y1 ^= edl->session->crop_y2;
524         }
525         switch( mode ) {
526         case CROP_REFORMAT: {
527                 float ctr_x = edl->session->output_w / 2.;
528                 float ctr_y = edl->session->output_h / 2.;
529                 float new_x = (edl->session->crop_x1 + edl->session->crop_x2) / 2.;
530                 float new_y = (edl->session->crop_y1 + edl->session->crop_y2) / 2.;
531                 float dx = -(new_x - ctr_x), dy = -(new_y - ctr_y);
532                 edl->tracks->translate_projector(dx, dy, 1);
533
534                 edl->session->output_w = edl->session->crop_x2 - edl->session->crop_x1;
535                 edl->session->output_h = edl->session->crop_y2 - edl->session->crop_y1;
536                 edl->session->crop_x1 = edl->session->crop_y1 = 0;
537                 edl->session->crop_x2 = edl->session->output_w;
538                 edl->session->crop_y2 = edl->session->output_h;
539                 break; }
540         case CROP_RESIZE: {
541                 float old_w = edl->session->output_w;
542                 float old_h = edl->session->output_h;
543                 float new_w = edl->session->crop_x2 - edl->session->crop_x1;
544                 float new_h = edl->session->crop_y2 - edl->session->crop_y1;
545                 if( !new_w ) new_w = 1;
546                 if( !new_h ) new_h = 1;
547                 float xzoom = old_w / new_w, yzoom = old_h / new_h;
548                 float new_z = bmin(xzoom, yzoom);
549                 float new_x = (edl->session->crop_x1 + edl->session->crop_x2) / 2.;
550                 float new_y = (edl->session->crop_y1 + edl->session->crop_y2) / 2.;
551                 edl->tracks->crop_resize(new_x, new_y, new_z);
552
553                 edl->session->crop_x1 = 0;
554                 edl->session->crop_y1 = 0;
555                 edl->session->crop_x2 = edl->session->output_w;
556                 edl->session->crop_y2 = edl->session->output_h;
557                 break; }
558         case CROP_SHRINK: {
559                 float old_w = edl->session->output_w;
560                 float old_h = edl->session->output_h;
561                 float new_w = edl->session->crop_x2 - edl->session->crop_x1;
562                 float new_h = edl->session->crop_y2 - edl->session->crop_y1;
563                 if( !new_w ) new_w = 1;
564                 if( !new_h ) new_h = 1;
565                 float xzoom = old_w / new_w, yzoom = old_h / new_h;
566                 float new_z = bmin(xzoom, yzoom);
567
568                 float new_x = (edl->session->crop_x1 + edl->session->crop_x2) / 2.;
569                 float new_y = (edl->session->crop_y1 + edl->session->crop_y2) / 2.;
570                 edl->tracks->crop_shrink(new_x, new_y, new_z);
571                 break; }
572         }
573
574 // Recalculate aspect ratio
575         if( defaults->get("AUTOASPECT", 0) ) {
576                 create_aspect_ratio(edl->session->aspect_w,
577                         edl->session->aspect_h,
578                         edl->session->output_w,
579                         edl->session->output_h);
580         }
581
582         undo_after(_("crop"), LOAD_ALL);
583
584         restart_brender();
585         cwindow->refresh_frame(CHANGE_ALL);
586         save_backup();
587 }
588
589 void MWindow::cut()
590 {
591         double start = edl->local_session->get_selectionstart();
592         double end = edl->local_session->get_selectionend();
593         if( EQUIV(start,end) )
594                 blade(start);
595         else
596                 cut(start, end);
597 }
598
599 void MWindow::blade(double position)
600 {
601         undo_before();
602         edl->blade(position);
603         edl->optimize();
604         save_backup();
605         undo_after(_("blade"), LOAD_EDITS | LOAD_TIMEBAR);
606         restart_brender();
607         update_plugin_guis();
608         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
609         cwindow->update(1, 0, 0, 0, 1);
610         awindow->gui->async_update_assets();
611         cwindow->refresh_frame(CHANGE_EDL);
612 }
613
614 void MWindow::cut(double start, double end, double new_position)
615 {
616         undo_before();
617         copy(start, end);
618         edl->clear(start, end,
619                 edl->session->labels_follow_edits,
620                 edl->session->plugins_follow_edits,
621                 edl->session->autos_follow_edits);
622
623         edl->optimize();
624         save_backup();
625         undo_after(_("split | cut"), LOAD_EDITS | LOAD_TIMEBAR);
626         if( new_position >= 0 ) {
627                 edl->local_session->set_selectionstart(new_position);
628                 edl->local_session->set_selectionend(new_position);
629         }
630         restart_brender();
631         update_plugin_guis();
632         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
633         cwindow->update(1, 0, 0, 0, 1);
634         awindow->gui->async_update_assets();
635         cwindow->refresh_frame(CHANGE_EDL);
636 }
637
638 void MWindow::cut_left_edit()
639 {
640         double start_pos = edl->local_session->get_selectionstart(1);
641         double position = edl->prev_edit(start_pos);
642         if( position < start_pos )
643                 cut(position, start_pos, position);
644 }
645
646 void MWindow::cut_right_edit()
647 {
648         double end_pos = edl->local_session->get_selectionend(1);
649         double position = edl->next_edit(end_pos);
650         if( end_pos < position )
651                 cut(end_pos, position, end_pos);
652 }
653
654 void MWindow::cut_left_label()
655 {
656         double start_pos = edl->local_session->get_selectionstart(1);
657         Label *left_label = edl->labels->prev_label(start_pos);
658         if( !left_label ) return;
659         double position = left_label->position;
660         if( position < start_pos )
661                 cut(position, start_pos, position);
662 }
663
664 void MWindow::cut_right_label()
665 {
666         double end_pos = edl->local_session->get_selectionend(1);
667         Label *right_label = edl->labels->next_label(end_pos);
668         if( !right_label ) return;
669         double position = right_label->position;
670         if( end_pos < position )
671                 cut(end_pos, position, end_pos);
672 }
673
674 int MWindow::cut_automation()
675 {
676         undo_before();
677         speed_before();
678         copy_automation();
679         edl->tracks->clear_automation(edl->local_session->get_selectionstart(),
680                 edl->local_session->get_selectionend());
681         int changed_edl = speed_after(1, 1);
682         save_backup();
683         undo_after(_("cut keyframes"),
684                 !changed_edl ? LOAD_AUTOMATION :
685                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
686         update_gui(changed_edl);
687         return 0;
688 }
689
690 int MWindow::cut_default_keyframe()
691 {
692
693         undo_before();
694         speed_before();
695         copy_default_keyframe();
696         edl->tracks->clear_default_keyframe();
697         int changed_edl = speed_after(1, 1);
698         save_backup();
699         undo_after(_("cut default keyframe"),
700                 !changed_edl ? LOAD_AUTOMATION :
701                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
702         update_gui(changed_edl);
703         return 0;
704 }
705
706
707 void MWindow::delete_tracks()
708 {
709         undo_before();
710         edl->tracks->delete_tracks();
711         undo_after(_("delete tracks"), LOAD_ALL);
712         save_backup();
713
714         restart_brender();
715         update_plugin_states();
716
717         gui->update(1, NORMAL_DRAW, 1, 0, 1, 0, 0);
718         cwindow->refresh_frame(CHANGE_EDL);
719 }
720
721 void MWindow::delete_track(Track *track)
722 {
723         undo_before();
724         edl->tracks->delete_track(track);
725         undo_after(_("delete track"), LOAD_ALL);
726
727         restart_brender();
728         update_plugin_states();
729
730         gui->update(1, NORMAL_DRAW, 1, 0, 1, 0, 0);
731         cwindow->refresh_frame(CHANGE_EDL);
732         save_backup();
733 }
734
735
736 // Insert data from clipboard
737 void MWindow::insert(double position, FileXML *file,
738         int edit_labels, int edit_plugins, int edit_autos,
739         EDL *parent_edl, Track *first_track, int overwrite)
740 {
741 // For clipboard pasting make the new edl use a separate session
742 // from the master EDL.  Then it can be resampled to the master rates.
743 // For splice, overwrite, and dragging need same session to get the assets.
744         EDL *edl = new EDL(parent_edl);
745         ArrayList<EDL*> new_edls;
746         uint32_t load_flags = LOAD_ALL;
747
748
749         new_edls.append(edl);
750         edl->create_objects();
751
752
753
754
755         if( parent_edl ) load_flags &= ~LOAD_SESSION;
756         if( !edl->session->autos_follow_edits ) load_flags &= ~LOAD_AUTOMATION;
757         if( !edl->session->labels_follow_edits ) load_flags &= ~LOAD_TIMEBAR;
758
759         edl->load_xml(file, load_flags);
760
761
762 //printf("MWindow::insert %f\n", edl->local_session->clipboard_length);
763
764
765
766         paste_edls(&new_edls, LOADMODE_PASTE, first_track, position,
767                 edit_labels, edit_plugins, edit_autos, overwrite);
768 // if( vwindow->edl )
769 // printf("MWindow::insert 5 %f %f\n",
770 // vwindow->edl->local_session->in_point,
771 // vwindow->edl->local_session->out_point);
772         new_edls.remove_all();
773         edl->Garbage::remove_user();
774 //printf("MWindow::insert 6 %p\n", vwindow->get_edl());
775 }
776
777 void MWindow::insert_effects_canvas(Track *dest_track, double start, double length)
778 {
779         undo_before();
780
781         ArrayList<SharedLocation> shared_locations;
782         PluginSet *pluginset = session->pluginset_highlighted;
783         int gang = edl->local_session->gang_tracks != GANG_NONE ? 1 : 0;
784         int data_type = dest_track->data_type;
785         int first_track = 1;
786
787         for( Track *track=dest_track; track; track=track->next ) {
788                 if( gang && track->master && !first_track ) break;
789                 if( track->data_type != data_type ) continue;
790                 if( !track->is_armed() ) continue;
791                 int module = edl->tracks->number_of(track);
792                 for( int i=0; i<session->drag_pluginservers->total; ++i ) {
793                         PluginServer *plugin = session->drag_pluginservers->values[i];
794                         int shared = gang; // && plugin->multichannel ? 1 : 0;
795                         int plugin_type = !first_track && shared ?
796                                 PLUGIN_SHAREDPLUGIN : PLUGIN_STANDALONE;
797                         SharedLocation *shared_location = !first_track ?
798                                 &shared_locations[i] : &shared_locations.append();
799                         insert_effect(plugin->title, shared_location, track,
800                                         pluginset, start, length, plugin_type);
801                         if( first_track && shared ) {
802                                 shared_location->module = module;
803                                 shared_location->plugin = pluginset ?
804                                         track->plugin_set.number_of(pluginset) :
805                                         track->plugin_set.total-1 ;
806                         }
807                 }
808                 if( !gang ) break;
809                 first_track = 0;
810                 pluginset = 0;
811         }
812
813         save_backup();
814         undo_after(_("insert effect"), LOAD_EDITS | LOAD_PATCHES);
815         restart_brender();
816         sync_parameters(CHANGE_EDL);
817 // GUI updated in TrackCanvas, after current_operations are reset
818 }
819
820 void MWindow::insert_effects_cwindow(Track *dest_track)
821 {
822         if( !dest_track ) return;
823
824         double start = 0;
825         double length = dest_track->get_length();
826
827         if( edl->local_session->get_selectionend() >
828                 edl->local_session->get_selectionstart() ) {
829                 start = edl->local_session->get_selectionstart();
830                 length = edl->local_session->get_selectionend() -
831                         edl->local_session->get_selectionstart();
832         }
833
834         insert_effects_canvas(dest_track, start, length);
835         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
836 }
837
838 void MWindow::insert_effect(char *title, SharedLocation *shared_location,
839                 int data_type, int plugin_type, int single_standalone)
840 {
841         Track *current = edl->tracks->first;
842         SharedLocation shared_location_local;
843         shared_location_local.copy_from(shared_location);
844         int first_track = 1;
845         double start_pos = edl->local_session->get_selectionstart();
846         double end_pos = edl->local_session->get_selectionend();
847         for( ; current; current=NEXT ) {
848                 if( current->data_type != data_type ) continue;
849                 if( !current->is_armed() ) continue;
850                 double start = start_pos, end = end_pos;
851                 if( plugin_type == PLUGIN_STANDALONE && start >= end ) {
852                         start = 0;
853                         end = current->get_length();
854                 }
855                 double length = end - start;
856                 insert_effect(title, &shared_location_local,
857                                 current, 0, start, length, plugin_type);
858                 if( first_track ) {
859                         if( plugin_type == PLUGIN_STANDALONE && single_standalone ) {
860                                 plugin_type = PLUGIN_SHAREDPLUGIN;
861                                 shared_location_local.module = edl->tracks->number_of(current);
862                                 shared_location_local.plugin = current->plugin_set.total - 1;
863                                 start_pos = start;  end_pos = end;
864                         }
865                         first_track = 0;
866                 }
867         }
868 }
869
870 void MWindow::insert_effect(char *title,
871                 SharedLocation *shared_location, Track *track, PluginSet *plugin_set,
872                 double start, double length, int plugin_type)
873 {
874         KeyFrame *default_keyframe = 0;
875         PluginServer *server = 0;
876 // Get default keyframe
877         if( plugin_type == PLUGIN_STANDALONE ) {
878                 default_keyframe = new KeyFrame;
879                 server = new PluginServer(*scan_plugindb(title, track->data_type));
880
881                 server->open_plugin(0, preferences, edl, 0);
882                 server->save_data(default_keyframe);
883         }
884 // Insert plugin object
885         track->insert_effect(title, shared_location, default_keyframe,
886                         plugin_set, start, length, plugin_type);
887         track->optimize();
888
889         if( plugin_type == PLUGIN_STANDALONE ) {
890                 server->close_plugin();
891                 delete server;
892                 delete default_keyframe;
893         }
894 }
895
896 int MWindow::modify_edithandles()
897 {
898         undo_before();
899         int handle_mode = edl->session->edit_handle_mode[session->drag_button];
900         edl->modify_edithandles(session->drag_start,
901                 session->drag_position, session->drag_handle, handle_mode,
902                 edl->session->labels_follow_edits,
903                 edl->session->plugins_follow_edits,
904                 edl->session->autos_follow_edits,
905                 session->drag_edit->group_id);
906         finish_modify_handles();
907 //printf("MWindow::modify_handles 1\n");
908         return 0;
909 }
910
911 int MWindow::modify_pluginhandles()
912 {
913         undo_before();
914
915         edl->modify_pluginhandles(session->drag_start,
916                 session->drag_position,
917                 session->drag_handle,
918                 edl->session->edit_handle_mode[session->drag_button],
919                 edl->session->labels_follow_edits,
920                 edl->session->autos_follow_edits,
921                 session->trim_edits);
922
923         finish_modify_handles();
924
925         return 0;
926 }
927
928
929 // Common to edithandles and plugin handles
930 void MWindow::finish_modify_handles()
931 {
932         int edit_mode = edl->session->edit_handle_mode[session->drag_button];
933         double position = -1;
934         switch( edit_mode ) {
935         case MOVE_RIPPLE:
936                 position = !session->drag_handle ?
937                         session->drag_start : session->drag_position;
938                 break;
939         case MOVE_ROLL:
940         case MOVE_SLIDE:
941                 position = session->drag_position;
942                 break;
943         case MOVE_SLIP:
944         case MOVE_EDGE:
945                 position = session->drag_start;
946                 break;
947         }
948         if( position >= 0 ) {
949                 edl->local_session->set_selectionstart(position);
950                 edl->local_session->set_selectionend(position);
951         }
952         undo_after(_("drag handle"), LOAD_EDITS | LOAD_TIMEBAR);
953
954         save_backup();
955         restart_brender();
956         sync_parameters(CHANGE_EDL);
957         update_plugin_guis();
958         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
959 // label list can be modified
960         awindow->gui->async_update_assets();
961         cwindow->update(1, 0, 0, 0, 1);
962 }
963
964 int MWindow::modify_transnhandles()
965 {
966         gui->reset_default_message();
967         gui->default_message();
968         Transition *transition = session->drag_transition;
969         if( !transition ) return 1;
970         int64_t length = transition->length;
971         Track *track = transition->edit->track;
972         int64_t start_pos = track->to_units(session->drag_start, 0);
973         int64_t end_pos = track->to_units(session->drag_position, 0);
974         length += end_pos - start_pos;
975         if( length < 0 ) length = 0;
976         if( length == transition->length ) return 0;
977
978         undo_before();
979         transition->length = length;
980         undo_after(_("trans handle"), LOAD_EDITS);
981
982         save_backup();
983         restart_brender();
984         sync_parameters(CHANGE_EDL);
985         update_plugin_guis();
986         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
987         cwindow->update(1, 0, 0, 0, 1);
988
989         return 0;
990 }
991
992 void MWindow::match_output_size(Track *track)
993 {
994         undo_before();
995         track->track_w = edl->session->output_w;
996         track->track_h = edl->session->output_h;
997         save_backup();
998         undo_after(_("match output size"), LOAD_ALL);
999
1000         restart_brender();
1001         sync_parameters(CHANGE_EDL);
1002 }
1003
1004
1005 void MWindow::delete_edit(Edit *edit, const char *msg, int collapse)
1006 {
1007         ArrayList<Edit*> edits;
1008         edits.append(edit);
1009         delete_edits(&edits, msg, collapse);
1010 }
1011
1012 void MWindow::delete_edits(ArrayList<Edit*> *edits, const char *msg, int collapse)
1013 {
1014         if( !edits->size() ) return;
1015         undo_before();
1016         if( edl->session->labels_follow_edits )
1017                 edl->delete_edit_labels(edits, collapse);
1018         edl->delete_edits(edits, collapse);
1019         edl->optimize();
1020         save_backup();
1021         undo_after(msg, LOAD_EDITS);
1022
1023         restart_brender();
1024         cwindow->refresh_frame(CHANGE_EDL);
1025         update_plugin_guis();
1026         gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
1027 }
1028
1029 void MWindow::delete_edits(int collapse)
1030 {
1031         ArrayList<Edit*> edits;
1032         edl->tracks->get_selected_edits(&edits);
1033         delete_edits(&edits,_("del edit"), collapse);
1034 }
1035
1036 // collapse - delete from timeline, not collapse replace with silence
1037 // packed - omit unselected from selection, unpacked - replace unselected with silence
1038 void MWindow::cut_selected_edits(int collapse, int packed)
1039 {
1040         selected_edits_to_clipboard(packed);
1041         ArrayList<Edit*> edits;
1042         edl->tracks->get_selected_edits(&edits);
1043         delete_edits(&edits, _("cut edit"), collapse);
1044 }
1045
1046
1047 void MWindow::move_edits(ArrayList<Edit*> *edits,
1048                 Track *track, double position, int mode)
1049 {
1050         undo_before();
1051 // lockout timebar labels update
1052 //  labels can be deleted with tooltip repeater running
1053         cwindow->gui->lock_window("Tracks::move_edits");
1054         edl->tracks->move_edits(edits, track, position,
1055                 edl->session->labels_follow_edits,
1056                 edl->session->plugins_follow_edits,
1057                 edl->session->autos_follow_edits, mode);
1058         cwindow->gui->timebar->update(1);
1059         cwindow->gui->unlock_window();
1060
1061         save_backup();
1062         undo_after(_("move edit"), LOAD_ALL);
1063
1064         restart_brender();
1065         cwindow->refresh_frame(CHANGE_EDL);
1066
1067         update_plugin_guis();
1068         gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
1069 }
1070
1071 void MWindow::selected_edits_to_clipboard(int packed)
1072 {
1073         EDL *new_edl = edl->selected_edits_to_clip(packed, 0, 0,
1074                 edl->session->labels_follow_edits,
1075                 edl->session->autos_follow_edits,
1076                 edl->session->plugins_follow_edits);
1077         if( !new_edl ) return;
1078         FileXML file;
1079         new_edl->copy(COPY_EDL, &file, "", 1);
1080         const char *file_string = file.string();
1081         long file_length = strlen(file_string);
1082         gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
1083         gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
1084         new_edl->remove_user();
1085 }
1086
1087 void MWindow::paste_clipboard(Track *first_track, double position, int overwrite,
1088                 int edit_edits, int edit_labels, int edit_autos, int edit_plugins)
1089 {
1090         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
1091         if( !len ) return;
1092         char *string = new char[len];
1093         gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
1094         FileXML file;
1095         file.read_from_string(string);
1096         delete [] string;
1097         EDL *clip = new EDL();
1098         clip->create_objects();
1099         if( !clip->load_xml(&file, LOAD_ALL) ) {
1100                 undo_before();
1101                 edl->paste_edits(clip, first_track, position, overwrite,
1102                         edit_edits, edit_labels, edit_autos, edit_plugins);
1103                 save_backup();
1104                 undo_after(_("paste clip"), LOAD_ALL);
1105                 restart_brender();
1106                 cwindow->refresh_frame(CHANGE_EDL);
1107
1108                 update_plugin_guis();
1109                 gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
1110         }
1111         clip->remove_user();
1112 }
1113
1114 void MWindow::move_group(EDL *group, Track *first_track, double position, int overwrite)
1115 {
1116         undo_before();
1117 // lockout timebar labels update
1118 //  labels can be deleted with tooltip repeater running
1119         cwindow->gui->lock_window("Tracks::move_group");
1120
1121         ArrayList<Edit *>edits;
1122         edl->tracks->get_selected_edits(&edits);
1123         if( edl->session->labels_follow_edits )
1124                 edl->delete_edit_labels(&edits, 0);
1125         edl->delete_edits(&edits, 0);
1126         edl->paste_edits(group, first_track, position, overwrite, 1,
1127                 edl->session->labels_follow_edits,
1128                 edl->session->autos_follow_edits,
1129                 edl->session->plugins_follow_edits);
1130         cwindow->gui->timebar->update(1);
1131         cwindow->gui->unlock_window();
1132 // big debate over whether to do this, must either clear selected, or no tweaking
1133 //      edl->tracks->clear_selected_edits();
1134
1135         save_backup();
1136         undo_after(_("move group"), LOAD_ALL);
1137         restart_brender();
1138         cwindow->refresh_frame(CHANGE_EDL);
1139
1140         update_plugin_guis();
1141         gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
1142 }
1143
1144 void MWindow::move_effect(Plugin *plugin, Track *track, int64_t position)
1145 {
1146         undo_before();
1147         edl->tracks->move_effect(plugin, track, position);
1148         save_backup();
1149         undo_after(_("paste effect"), LOAD_ALL);
1150
1151         restart_brender();
1152         cwindow->refresh_frame(CHANGE_EDL);
1153         update_plugin_guis();
1154         gui->update(1, NORMAL_DRAW, 0, 0, 0, 0, 0);
1155 }
1156
1157 void MWindow::move_effect(Plugin *plugin, PluginSet *plugin_set, int64_t position)
1158 {
1159         undo_before();
1160         edl->tracks->move_effect(plugin, plugin_set, position);
1161         save_backup();
1162         undo_after(_("move effect"), LOAD_ALL);
1163
1164         restart_brender();
1165         cwindow->refresh_frame(CHANGE_EDL);
1166         update_plugin_guis();
1167         gui->update(1, NORMAL_DRAW, 0, 0, 0, 0, 0);
1168 }
1169
1170 void MWindow::move_plugins_up(PluginSet *plugin_set)
1171 {
1172
1173         undo_before();
1174         plugin_set->track->move_plugins_up(plugin_set);
1175
1176         save_backup();
1177         undo_after(_("move effect up"), LOAD_ALL);
1178         restart_brender();
1179         gui->update(1, NORMAL_DRAW, 0, 0, 0, 0, 0);
1180         sync_parameters(CHANGE_EDL);
1181 }
1182
1183 void MWindow::move_plugins_down(PluginSet *plugin_set)
1184 {
1185         undo_before();
1186
1187         plugin_set->track->move_plugins_down(plugin_set);
1188
1189         save_backup();
1190         undo_after(_("move effect down"), LOAD_ALL);
1191         restart_brender();
1192         gui->update(1, NORMAL_DRAW, 0, 0, 0, 0, 0);
1193         sync_parameters(CHANGE_EDL);
1194 }
1195
1196 void MWindow::roll_track_down(Track *track)
1197 {
1198         undo_before();
1199         edl->tracks->roll_track_down(track);
1200         save_backup();
1201         undo_after(_("move track down"), LOAD_ALL);
1202
1203         restart_brender();
1204         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1205         sync_parameters(CHANGE_EDL);
1206         save_backup();
1207 }
1208
1209 void MWindow::roll_tracks_down()
1210 {
1211         undo_before();
1212         edl->tracks->roll_tracks_down();
1213         save_backup();
1214         undo_after(_("move tracks down"), LOAD_ALL);
1215
1216         restart_brender();
1217         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1218         sync_parameters(CHANGE_EDL);
1219         save_backup();
1220 }
1221
1222 void MWindow::roll_track_up(Track *track)
1223 {
1224         undo_before();
1225         edl->tracks->roll_track_up(track);
1226         save_backup();
1227         undo_after(_("move track up"), LOAD_ALL);
1228         restart_brender();
1229         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1230         sync_parameters(CHANGE_EDL);
1231         save_backup();
1232 }
1233
1234 void MWindow::roll_tracks_up()
1235 {
1236         undo_before();
1237         edl->tracks->roll_tracks_up();
1238         save_backup();
1239         undo_after(_("move tracks up"), LOAD_ALL);
1240         restart_brender();
1241         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1242         sync_parameters(CHANGE_EDL);
1243 }
1244
1245
1246 void MWindow::move_track_down(Track *track)
1247 {
1248         undo_before();
1249         edl->tracks->move_track_down(track);
1250         save_backup();
1251         undo_after(_("swap track down"), LOAD_ALL);
1252
1253         restart_brender();
1254         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1255         sync_parameters(CHANGE_EDL);
1256         save_backup();
1257 }
1258
1259 void MWindow::move_tracks_down()
1260 {
1261         undo_before();
1262         edl->tracks->move_tracks_down();
1263         save_backup();
1264         undo_after(_("swap tracks down"), LOAD_ALL);
1265
1266         restart_brender();
1267         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1268         sync_parameters(CHANGE_EDL);
1269         save_backup();
1270 }
1271
1272 void MWindow::move_track_up(Track *track)
1273 {
1274         undo_before();
1275         edl->tracks->move_track_up(track);
1276         save_backup();
1277         undo_after(_("swap track up"), LOAD_ALL);
1278         restart_brender();
1279         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1280         sync_parameters(CHANGE_EDL);
1281         save_backup();
1282 }
1283
1284 void MWindow::move_tracks_up()
1285 {
1286         undo_before();
1287         edl->tracks->move_tracks_up();
1288         save_backup();
1289         undo_after(_("swap tracks up"), LOAD_ALL);
1290         restart_brender();
1291         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
1292         sync_parameters(CHANGE_EDL);
1293 }
1294
1295
1296 void MWindow::mute_selection()
1297 {
1298         double start = edl->local_session->get_selectionstart();
1299         double end = edl->local_session->get_selectionend();
1300         if( start != end ) {
1301                 undo_before();
1302                 edl->clear(start, end, 0,
1303                         edl->session->plugins_follow_edits,
1304                         edl->session->autos_follow_edits);
1305                 edl->local_session->set_selectionend(end);
1306                 edl->local_session->set_selectionstart(start);
1307                 edl->paste_silence(start, end, 0,
1308                         edl->session->plugins_follow_edits,
1309                         edl->session->autos_follow_edits);
1310
1311                 save_backup();
1312                 undo_after(_("mute"), LOAD_EDITS);
1313
1314                 restart_brender();
1315                 update_plugin_guis();
1316                 gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
1317                 cwindow->refresh_frame(CHANGE_EDL);
1318         }
1319 }
1320
1321
1322 void MWindow::overwrite(EDL *source, int all)
1323 {
1324         FileXML file;
1325
1326         LocalSession *src = source->local_session;
1327         double src_start = all ? 0 :
1328                 src->inpoint_valid() ? src->get_inpoint() :
1329                 src->outpoint_valid() ? 0 :
1330                         src->get_selectionstart();
1331         double src_end = all ? source->tracks->total_length() :
1332                 src->outpoint_valid() ? src->get_outpoint() :
1333                 src->inpoint_valid() ? source->tracks->total_length() :
1334                         src->get_selectionend();
1335         double overwrite_len = src_end - src_start;
1336         double dst_start = edl->local_session->get_selectionstart();
1337         double dst_len = edl->local_session->get_selectionend() - dst_start;
1338
1339         undo_before();
1340         if( !EQUIV(dst_len, 0) && (dst_len < overwrite_len) ) {
1341 // in/out points or selection present and shorter than overwrite range
1342 // shorten the copy range
1343                 overwrite_len = dst_len;
1344         }
1345
1346         source->copy(copy_flags(), src_start, src_start + overwrite_len, &file, "", 1);
1347
1348 // HACK around paste_edl get_start/endselection on its own
1349 // so we need to clear only when not using both io points
1350 // FIXME: need to write simple overwrite_edl to be used for overwrite function
1351         if( edl->local_session->get_inpoint() < 0 ||
1352             edl->local_session->get_outpoint() < 0 )
1353                 edl->clear(dst_start, dst_start + overwrite_len,
1354                                 edl->session->labels_follow_edits,
1355                                 edl->session->plugins_follow_edits,
1356                                 edl->session->autos_follow_edits);
1357
1358         paste(dst_start, dst_start + overwrite_len, &file,
1359                                 edl->session->labels_follow_edits,
1360                                 edl->session->plugins_follow_edits,
1361                                 edl->session->autos_follow_edits, 0, 0);
1362
1363         edl->local_session->set_selectionstart(dst_start + overwrite_len);
1364         edl->local_session->set_selectionend(dst_start + overwrite_len);
1365
1366         save_backup();
1367         undo_after(_("overwrite"),
1368                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1369
1370         restart_brender();
1371         update_plugin_guis();
1372         gui->update(1, NORMAL_DRAW, 1, 1, 0, 1, 0);
1373         sync_parameters(CHANGE_EDL);
1374 }
1375
1376 // For splice and overwrite
1377 int MWindow::paste(double start, double end, FileXML *file,
1378         int edit_labels, int edit_plugins, int edit_autos,
1379         Track *first_track, int overwrite)
1380 {
1381         clear(0);
1382
1383 // Want to insert with assets shared with the master EDL.
1384         insert(start, file,
1385                 edit_labels, edit_plugins, edit_autos,
1386                 edl, first_track, overwrite);
1387
1388         return 0;
1389 }
1390
1391 // For editing using insertion point
1392 void MWindow::paste()
1393 {
1394         paste(edl->local_session->get_selectionstart(), 0, 1, 0);
1395 }
1396
1397 void MWindow::paste(double start, Track *first_track, int clear_selection, int overwrite)
1398 {
1399         //double end = edl->local_session->get_selectionend();
1400         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
1401
1402         if( len ) {
1403                 char *string = new char[len];
1404                 undo_before();
1405                 gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
1406                 FileXML file;
1407                 file.read_from_string(string);
1408                 if( clear_selection ) clear(0);
1409
1410                 insert(start, &file,
1411                         edl->session->labels_follow_edits,
1412                         edl->session->plugins_follow_edits,
1413                         edl->session->autos_follow_edits,
1414                         0, first_track, overwrite);
1415
1416                 edl->optimize();
1417                 delete [] string;
1418
1419                 save_backup();
1420
1421                 undo_after(_("paste"),
1422                                 LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1423                 restart_brender();
1424                 update_plugin_guis();
1425                 gui->update(1, FORCE_REDRAW, 1, 1, 0, 1, 0);
1426                 awindow->gui->async_update_assets();
1427                 sync_parameters(CHANGE_EDL);
1428         }
1429
1430 }
1431
1432 int MWindow::paste_assets(double position, Track *dest_track, int overwrite)
1433 {
1434         int result = 0;
1435         undo_before();
1436
1437         if( session->drag_assets->total ) {
1438                 load_assets(session->drag_assets,
1439                         position, LOADMODE_PASTE, dest_track, 0,
1440                         edl->session->labels_follow_edits,
1441                         edl->session->plugins_follow_edits,
1442                         edl->session->autos_follow_edits,
1443                         overwrite);
1444                 result = 1;
1445         }
1446
1447         if( session->drag_clips->total ) {
1448                 paste_edls(session->drag_clips,
1449                         LOADMODE_PASTE, dest_track, position,
1450                         edl->session->labels_follow_edits,
1451                         edl->session->plugins_follow_edits,
1452                         edl->session->autos_follow_edits,
1453                         overwrite);
1454                 result = 1;
1455         }
1456
1457         save_backup();
1458
1459         undo_after(_("paste assets"),
1460                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1461         restart_brender();
1462         gui->update(1, FORCE_REDRAW, 1, 0, 0, 1, 0);
1463         sync_parameters(CHANGE_EDL);
1464         return result;
1465 }
1466
1467 void MWindow::load_assets(ArrayList<Indexable*> *new_assets,
1468         double position, int load_mode, Track *first_track, RecordLabels *labels,
1469         int edit_labels, int edit_plugins, int edit_autos, int overwrite)
1470 {
1471         if( load_mode == LOADMODE_RESOURCESONLY )
1472                 load_mode = LOADMODE_ASSETSONLY;
1473 const int debug = 0;
1474 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
1475         if( position < 0 )
1476                 position = edl->local_session->get_selectionstart();
1477
1478         ArrayList<EDL*> new_edls;
1479         for( int i=0; i<new_assets->total; ++i ) {
1480                 Indexable *indexable = new_assets->get(i);
1481                 if( indexable->is_asset ) {
1482                         remove_from_caches(indexable);
1483                 }
1484                 EDL *new_edl = new EDL;
1485                 new_edl->create_objects();
1486                 new_edl->copy_session(edl);
1487                 if( !indexable->is_asset ) {
1488                         EDL *nested_edl = (EDL*)indexable;
1489                         new_edl->create_nested(nested_edl);
1490                         new_edl->set_path(indexable->path);
1491                 }
1492                 else {
1493                         Asset *asset = (Asset*)indexable;
1494                         asset_to_edl(new_edl, asset);
1495                 }
1496                 new_edls.append(new_edl);
1497
1498                 if( labels ) {
1499                         for( RecordLabel *label=labels->first; label; label=label->next ) {
1500                                 new_edl->labels->toggle_label(label->position, label->position);
1501                         }
1502                 }
1503         }
1504 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
1505
1506         paste_edls(&new_edls, load_mode, first_track, position,
1507                 edit_labels, edit_plugins, edit_autos, overwrite);
1508 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
1509
1510         save_backup();
1511         for( int i=0; i<new_edls.size(); ++i )
1512                 new_edls.get(i)->Garbage::remove_user();
1513
1514 if( debug ) printf("MWindow::load_assets %d\n", __LINE__);
1515 }
1516
1517 int MWindow::paste_automation()
1518 {
1519         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
1520
1521         if( len ) {
1522                 undo_before();
1523                 speed_before();
1524                 char *string = new char[len];
1525                 gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
1526                 FileXML file;
1527                 file.read_from_string(string);
1528                 delete [] string;
1529                 double start = edl->local_session->get_selectionstart();
1530                 double end = edl->local_session->get_selectionend();
1531                 edl->tracks->clear_automation(start, end);
1532                 edl->tracks->paste_automation(start, &file, 0, 1,
1533                         edl->session->typeless_keyframes);
1534                 int changed_edl = speed_after(1, 0);
1535                 save_backup();
1536                 undo_after(_("paste keyframes"),
1537                         !changed_edl ? LOAD_AUTOMATION :
1538                                 LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1539                 update_gui(changed_edl);
1540         }
1541
1542         return 0;
1543 }
1544
1545 int MWindow::paste_default_keyframe()
1546 {
1547         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
1548
1549         if( len ) {
1550                 undo_before();
1551                 speed_before();
1552                 char *string = new char[len];
1553                 gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
1554                 FileXML file;
1555                 file.read_from_string(string);
1556                 delete [] string;
1557                 double start = edl->local_session->get_selectionstart();
1558                 edl->tracks->paste_automation(start, &file, 1, 0,
1559                         edl->session->typeless_keyframes);
1560 //              edl->tracks->paste_default_keyframe(&file);
1561                 int changed_edl = speed_after(1, 1);
1562                 undo_after(_("paste default keyframe"),
1563                         !changed_edl ? LOAD_AUTOMATION :
1564                                 LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1565                 save_backup();
1566                 update_gui(changed_edl);
1567         }
1568
1569         return 0;
1570 }
1571
1572
1573 // Insert edls with project deletion and index file generation.
1574 int MWindow::paste_edls(ArrayList<EDL*> *new_edls, int load_mode,
1575         Track *first_track, double current_position,
1576         int edit_labels, int edit_plugins, int edit_autos,
1577         int overwrite)
1578 {
1579
1580         ArrayList<Track*> destination_tracks;
1581         int need_new_tracks = 0;
1582
1583 //PRINT_TRACE
1584         if( !new_edls->total ) return 0;
1585
1586 //PRINT_TRACE
1587 //      double original_length = edl->tracks->total_length();
1588 //      double original_preview_end = edl->local_session->preview_end;
1589 //PRINT_TRACE
1590
1591 // Delete current project
1592         if( load_mode == LOADMODE_REPLACE ||
1593             load_mode == LOADMODE_REPLACE_CONCATENATE ) {
1594                 reset_caches(1);
1595                 edl->save_defaults(defaults);
1596                 hide_plugins();
1597                 edl->Garbage::remove_user();
1598                 edl = new EDL;
1599                 edl->create_objects();
1600                 edl->copy_session(new_edls->values[0]);
1601                 edl->copy_mixers(new_edls->values[0]);
1602                 gui->mainmenu->update_toggles(0);
1603                 gui->unlock_window();
1604                 gwindow->gui->update_toggles(1);
1605                 gui->lock_window("MWindow::paste_edls");
1606
1607 // Insert labels for certain modes constitutively
1608                 edit_labels = 1;
1609                 edit_plugins = 1;
1610                 edit_autos = 1;
1611 // Force reset of preview
1612 //              original_length = 0;
1613 //              original_preview_end = -1;
1614         }
1615
1616
1617 //PRINT_TRACE
1618
1619 // Create new tracks in master EDL
1620         if( load_mode == LOADMODE_REPLACE ||
1621             load_mode == LOADMODE_REPLACE_CONCATENATE ||
1622             load_mode == LOADMODE_NEW_TRACKS ) {
1623
1624                 need_new_tracks = 1;
1625                 for( int i=0; i<new_edls->total; ++i ) {
1626                         EDL *new_edl = new_edls->values[i];
1627                         int first_track = 1;
1628                         for( Track *current=new_edl->tracks->first; current; current=NEXT ) {
1629                                 switch( current->data_type ) {
1630                                 case TRACK_VIDEO:
1631                                         edl->tracks->add_video_track(0, 0);
1632                                         if( current->draw ) edl->tracks->last->draw = 1;
1633                                         break;
1634                                 case TRACK_AUDIO:
1635                                         edl->tracks->add_audio_track(0, 0);
1636                                         break;
1637                                 case TRACK_SUBTITLE:
1638                                         edl->tracks->add_subttl_track(0, 0);
1639                                         break;
1640                                 default:
1641                                         continue;
1642                                 }
1643                                 if( first_track ) {
1644                                         edl->tracks->last->master = 1;
1645                                         first_track = 0;
1646                                 }
1647 // re-label only if not already labeled
1648                                 if( new_edl->local_session->asset2edl )
1649                                         strcpy(current->title, edl->tracks->last->title);
1650                                 destination_tracks.append(edl->tracks->last);
1651                         }
1652
1653 // Base track count on first EDL only for concatenation
1654                         if( load_mode == LOADMODE_REPLACE_CONCATENATE ) break;
1655                 }
1656                 edl->session->highlighted_track = edl->tracks->total() - 1;
1657         }
1658         else
1659 // Recycle existing tracks of master EDL
1660         if( load_mode == LOADMODE_CONCATENATE ||
1661             load_mode == LOADMODE_PASTE ) {
1662                 Track *current = first_track ? first_track : edl->tracks->first;
1663                 for( ; current; current=NEXT ) {
1664                         if( current->is_armed() ) {
1665                                 destination_tracks.append(current);
1666                         }
1667                 }
1668 //PRINT_TRACE
1669         }
1670 //PRINT_TRACE
1671         int destination_track = 0;
1672         double *paste_position = new double[destination_tracks.total];
1673
1674 // Iterate through the edls
1675         for( int i=0; i<new_edls->total; ++i ) {
1676
1677                 EDL *new_edl = new_edls->values[i];
1678                 double edl_length = new_edl->local_session->clipboard_length ?
1679                         new_edl->local_session->clipboard_length :
1680                         new_edl->tracks->total_length();
1681 // printf("MWindow::paste_edls 2 %f %f\n",
1682 // new_edl->local_session->clipboard_length,
1683 // new_edl->tracks->total_length());
1684 // new_edl->dump();
1685 //PRINT_TRACE
1686
1687 // Convert EDL to master rates
1688                 new_edl->resample(new_edl->session->sample_rate,
1689                         edl->session->sample_rate,
1690                         TRACK_AUDIO);
1691                 new_edl->resample(new_edl->session->frame_rate,
1692                         edl->session->frame_rate,
1693                         TRACK_VIDEO);
1694 //PRINT_TRACE
1695 // Add assets and prepare index files
1696                 for( Asset *new_asset=new_edl->assets->first;
1697                      new_asset; new_asset=new_asset->next ) {
1698                         mainindexes->add_indexable(new_asset);
1699                 }
1700 // Capture index file status from mainindex test
1701                 edl->update_assets(new_edl);
1702 //PRINT_TRACE
1703 // Get starting point of insertion.  Need this to paste labels.
1704                 switch( load_mode ) {
1705                 case LOADMODE_NOTHING:
1706                         continue;
1707                 case LOADMODE_REPLACE:
1708                         current_position = 0;
1709                         break;
1710                 case LOADMODE_NEW_TRACKS:
1711                         if( !overwrite )
1712                                 current_position = 0;
1713                         break;
1714
1715                 case LOADMODE_CONCATENATE:
1716                 case LOADMODE_REPLACE_CONCATENATE:
1717                         destination_track = 0;
1718                         if( destination_tracks.total )
1719                                 current_position = destination_tracks.values[0]->get_length();
1720                         else
1721                                 current_position = 0;
1722                         break;
1723
1724                 case LOADMODE_PASTE:
1725                         destination_track = 0;
1726                         if( i == 0 ) {
1727                                 for( int j=0; j<destination_tracks.total; ++j ) {
1728                                         paste_position[j] = (current_position >= 0) ?
1729                                                 current_position :
1730                                                 edl->local_session->get_selectionstart();
1731                                 }
1732                         }
1733                         break;
1734
1735                 case LOADMODE_RESOURCESONLY:
1736                         edl->add_clip(new_edl);
1737                         break;
1738                 }
1739 // Insert edl
1740                 if( load_mode != LOADMODE_RESOURCESONLY &&
1741                     load_mode != LOADMODE_ASSETSONLY ) {
1742 // Insert labels
1743                         if( edit_labels ) {
1744                                 if( load_mode == LOADMODE_PASTE )
1745                                         edl->labels->insert_labels(new_edl->labels,
1746                                                 destination_tracks.total ? paste_position[0] : 0.0,
1747                                                 edl_length, 1);
1748                                 else
1749                                         edl->labels->insert_labels(new_edl->labels, current_position,
1750                                                 edl_length, 1);
1751                         }
1752                         double total_length = new_edl->tracks->total_length();
1753                         for( Track *new_track=new_edl->tracks->first;
1754                              new_track; new_track=new_track->next ) {
1755 // Get destination track of same type as new_track
1756                                 for( int k = 0;
1757                                      k < destination_tracks.total &&
1758                                      destination_tracks.values[destination_track]->data_type != new_track->data_type;
1759                                      ++k, ++destination_track ) {
1760                                         if( destination_track >= destination_tracks.total - 1 )
1761                                                 destination_track = 0;
1762                                 }
1763
1764 // Insert data into destination track
1765                                 if( destination_track < destination_tracks.total &&
1766                                     destination_tracks.values[destination_track]->data_type == new_track->data_type ) {
1767                                         Track *track = destination_tracks.values[destination_track];
1768 // Replace default keyframes if first EDL and new tracks were created.
1769 // This means data copied from one track and pasted to another won't retain
1770 // the camera position unless it's a keyframe.  If it did, previous data in the
1771 // track might get unknowingly corrupted.  Ideally we would detect when differing
1772 // default keyframes existed and create discrete keyframes for both.
1773                                         int replace_default = (i == 0) && need_new_tracks;
1774 // master tracks are the first track in each new edl when new tracks are created
1775                                         int master = track->master;
1776 //printf("MWindow::paste_edls 1 %d\n", replace_default);
1777 // Insert new track at current position
1778                                         switch( load_mode ) {
1779                                         case LOADMODE_REPLACE_CONCATENATE:
1780                                         case LOADMODE_CONCATENATE:
1781                                                 current_position = track->get_length();
1782                                                 break;
1783
1784                                         case LOADMODE_PASTE:
1785                                                 current_position = paste_position[destination_track];
1786                                                 paste_position[destination_track] += new_track->get_length();
1787                                                 break;
1788                                         }
1789                                         if( overwrite ) {
1790                                                 double length = overwrite >= 0 ?
1791                                                         new_track->get_length() : total_length;
1792                                                 track->clear(current_position,
1793                                                         current_position + length,
1794                                                         1, // edit edits
1795                                                         edit_labels, edit_plugins, edit_autos,
1796                                                         0); // trim edits
1797                                         }
1798 //PRINT_TRACE
1799                                         track->insert_track(new_track, current_position, replace_default,
1800                                                 edit_plugins, edit_autos, edl_length);
1801                                         if( master ) track->master = 1;
1802 //PRINT_TRACE
1803                                 }
1804
1805 // Get next destination track
1806                                 destination_track++;
1807                                 if( destination_track >= destination_tracks.total )
1808                                         destination_track = 0;
1809                         }
1810                 }
1811
1812                 if( load_mode == LOADMODE_PASTE )
1813                         current_position += edl_length;
1814         }
1815
1816
1817 // Move loading of clips and vwindow to the end - this fixes some
1818 // strange issue, for index not being shown
1819 // Assume any paste operation from the same EDL won't contain any clips.
1820 // If it did it would duplicate every clip here.
1821         for( int i=0; i<new_edls->total; ++i ) {
1822                 EDL *new_edl = new_edls->get(i);
1823
1824                 for( int j=0; j<new_edl->clips.size(); ++j ) {
1825                         edl->add_clip(new_edl->clips[j]);
1826                 }
1827                 for( int j=0; j<new_edl->nested_edls.size(); ++j ) {
1828                         edl->nested_edls.get_nested(new_edl->nested_edls[j]);
1829                 }
1830
1831                 if( new_edl->total_vwindow_edls() ) {
1832 //                      if( edl->vwindow_edl )
1833 //                              edl->vwindow_edl->Garbage::remove_user();
1834 //                      edl->vwindow_edl = new EDL(edl);
1835 //                      edl->vwindow_edl->create_objects();
1836 //                      edl->vwindow_edl->copy_all(new_edl->vwindow_edl);
1837
1838                         for( int j=0; j<new_edl->total_vwindow_edls(); ++j ) {
1839                                 EDL *vwindow_edl = new EDL(edl);
1840                                 vwindow_edl->create_objects();
1841                                 vwindow_edl->copy_all(new_edl->get_vwindow_edl(j));
1842                                 edl->append_vwindow_edl(vwindow_edl, 0);
1843                         }
1844                 }
1845         }
1846
1847         if( paste_position ) delete [] paste_position;
1848
1849 // This is already done in load_filenames and everything else that uses paste_edls
1850 //      update_project(load_mode);
1851
1852 // Fix preview range
1853 //      if( EQUIV(original_length, original_preview_end) )
1854 //      {
1855 //              edl->local_session->preview_end = edl->tracks->total_length();
1856 //      }
1857
1858 // Start examining next batch of index files
1859         mainindexes->start_build();
1860
1861 // Don't save a backup after loading since the loaded file is on disk already.
1862 //PRINT_TRACE
1863         return 0;
1864 }
1865
1866 void MWindow::paste_silence()
1867 {
1868         double start = edl->local_session->get_selectionstart();
1869         double end = edl->local_session->get_selectionend();
1870         if( EQUIV(start, end) ) {
1871                 if( edl->session->frame_rate > 0 )
1872                         end += 1./edl->session->frame_rate;
1873         }
1874         undo_before(_("silence"), this);
1875         edl->paste_silence(start, end,
1876                 edl->session->labels_follow_edits,
1877                 edl->session->plugins_follow_edits,
1878                 edl->session->autos_follow_edits);
1879         edl->optimize();
1880         save_backup();
1881         undo_after(_("silence"),
1882                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
1883
1884         update_plugin_guis();
1885         restart_brender();
1886         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
1887         cwindow->update(1, 0, 0, 0, 1);
1888         cwindow->refresh_frame(CHANGE_EDL);
1889 }
1890
1891 void MWindow::detach_transition(Transition *transition)
1892 {
1893         undo_before();
1894         hide_plugin(transition, 1);
1895         int is_video = (transition->edit->track->data_type == TRACK_VIDEO);
1896         transition->edit->detach_transition();
1897         save_backup();
1898         undo_after(_("detach transition"), LOAD_ALL);
1899
1900         if( is_video ) restart_brender();
1901         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
1902         sync_parameters(CHANGE_EDL);
1903 }
1904
1905 void MWindow::detach_transitions()
1906 {
1907         gui->lock_window("MWindow::detach_transitions 1");
1908
1909         undo_before();
1910         double start = edl->local_session->get_selectionstart();
1911         double end = edl->local_session->get_selectionend();
1912         edl->tracks->clear_transitions(start, end);
1913
1914         save_backup();
1915         undo_after(_("detach transitions"), LOAD_EDITS);
1916
1917         sync_parameters(CHANGE_EDL);
1918         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
1919         gui->unlock_window();
1920 }
1921
1922 void MWindow::paste_transition()
1923 {
1924 // Only the first transition gets dropped.
1925         PluginServer *server = session->drag_pluginservers->values[0];
1926
1927         undo_before();
1928         edl->tracks->paste_transition(server, session->edit_highlighted);
1929         save_backup();
1930         undo_after(_("transition"), LOAD_EDITS);
1931
1932         if( server->video ) restart_brender();
1933         sync_parameters(CHANGE_ALL);
1934 }
1935
1936 void MWindow::paste_transitions(int track_type, char *title)
1937 {
1938         gui->lock_window("MWindow::detach_transitions 1");
1939
1940         undo_before();
1941         double start = edl->local_session->get_selectionstart();
1942         double end = edl->local_session->get_selectionend();
1943         edl->tracks->paste_transitions(start, end, track_type, title);
1944         save_backup();
1945         undo_after(_("attach transitions"), LOAD_EDITS);
1946
1947         sync_parameters(CHANGE_EDL);
1948         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
1949         gui->unlock_window();
1950 }
1951
1952 void MWindow::paste_transition_cwindow(Track *dest_track)
1953 {
1954         PluginServer *server = session->drag_pluginservers->values[0];
1955         undo_before();
1956         edl->tracks->paste_video_transition(server, 1);
1957         save_backup();
1958         undo_after(_("transition"), LOAD_EDITS);
1959         restart_brender();
1960         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
1961         sync_parameters(CHANGE_ALL);
1962 }
1963
1964 void MWindow::paste_audio_transition()
1965 {
1966         PluginServer *server = scan_plugindb(edl->session->default_atransition,
1967                 TRACK_AUDIO);
1968         if( !server ) {
1969                 char string[BCTEXTLEN];
1970                 sprintf(string, _("No default transition %s found."), edl->session->default_atransition);
1971                 gui->show_message(string);
1972                 return;
1973         }
1974
1975         undo_before();
1976         edl->tracks->paste_audio_transition(server);
1977         save_backup();
1978         undo_after(_("transition"), LOAD_EDITS);
1979
1980         sync_parameters(CHANGE_EDL);
1981         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
1982 }
1983
1984 void MWindow::paste_video_transition()
1985 {
1986         PluginServer *server = scan_plugindb(edl->session->default_vtransition,
1987                 TRACK_VIDEO);
1988         if( !server ) {
1989                 char string[BCTEXTLEN];
1990                 sprintf(string, _("No default transition %s found."), edl->session->default_vtransition);
1991                 gui->show_message(string);
1992                 return;
1993         }
1994
1995         undo_before();
1996
1997         edl->tracks->paste_video_transition(server);
1998         save_backup();
1999         undo_after(_("transition"), LOAD_EDITS);
2000
2001         sync_parameters(CHANGE_EDL);
2002         restart_brender();
2003         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
2004 }
2005
2006 void MWindow::shuffle_edits()
2007 {
2008         gui->lock_window("MWindow::shuffle_edits 1");
2009
2010         undo_before();
2011         double start = edl->local_session->get_selectionstart();
2012         double end = edl->local_session->get_selectionend();
2013
2014         edl->tracks->shuffle_edits(start, end);
2015
2016         save_backup();
2017         undo_after(_("shuffle edits"), LOAD_EDITS | LOAD_TIMEBAR);
2018
2019         sync_parameters(CHANGE_EDL);
2020         restart_brender();
2021         gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
2022         gui->unlock_window();
2023 }
2024
2025 void MWindow::reverse_edits()
2026 {
2027         gui->lock_window("MWindow::reverse_edits 1");
2028
2029         undo_before();
2030         double start = edl->local_session->get_selectionstart();
2031         double end = edl->local_session->get_selectionend();
2032
2033         edl->tracks->reverse_edits(start, end);
2034
2035         save_backup();
2036         undo_after(_("reverse edits"), LOAD_EDITS | LOAD_TIMEBAR);
2037
2038         sync_parameters(CHANGE_EDL);
2039         restart_brender();
2040         gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
2041         gui->unlock_window();
2042 }
2043
2044 void MWindow::align_edits()
2045 {
2046         gui->lock_window("MWindow::align_edits 1");
2047
2048         undo_before();
2049         double start = edl->local_session->get_selectionstart();
2050         double end = edl->local_session->get_selectionend();
2051
2052         edl->tracks->align_edits(start, end);
2053
2054         save_backup();
2055         undo_after(_("align edits"), LOAD_EDITS | LOAD_TIMEBAR);
2056
2057         sync_parameters(CHANGE_EDL);
2058         restart_brender();
2059         gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
2060         gui->unlock_window();
2061 }
2062
2063 void MWindow::set_edit_length(double length)
2064 {
2065         gui->lock_window("MWindow::set_edit_length 1");
2066
2067         undo_before();
2068         double start = edl->local_session->get_selectionstart();
2069         double end = edl->local_session->get_selectionend();
2070
2071         edl->tracks->set_edit_length(start, end, length);
2072
2073         save_backup();
2074         undo_after(_("edit length"), LOAD_EDITS | LOAD_TIMEBAR);
2075
2076         sync_parameters(CHANGE_EDL);
2077         restart_brender();
2078         gui->update(0, NORMAL_DRAW, 1, 0, 0, 0, 0);
2079         gui->unlock_window();
2080 }
2081
2082
2083 void MWindow::set_transition_length(Transition *transition, double length)
2084 {
2085         gui->lock_window("MWindow::set_transition_length 1");
2086
2087         undo_before();
2088         //double start = edl->local_session->get_selectionstart();
2089         //double end = edl->local_session->get_selectionend();
2090
2091         edl->tracks->set_transition_length(transition, length);
2092
2093         save_backup();
2094         undo_after(_("transition length"), LOAD_EDITS);
2095
2096         edl->session->default_transition_length = length;
2097         sync_parameters(CHANGE_PARAMS);
2098         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
2099         gui->unlock_window();
2100 }
2101
2102 void MWindow::set_transition_length(double length)
2103 {
2104         gui->lock_window("MWindow::set_transition_length 2");
2105
2106         undo_before();
2107         double start = edl->local_session->get_selectionstart();
2108         double end = edl->local_session->get_selectionend();
2109
2110         edl->tracks->set_transition_length(start, end, length);
2111
2112         save_backup();
2113         undo_after(_("transition length"), LOAD_EDITS);
2114
2115         edl->session->default_transition_length = length;
2116         sync_parameters(CHANGE_PARAMS);
2117         restart_brender();
2118         gui->update(0, NORMAL_DRAW, 0, 0, 0, 0, 0);
2119         gui->unlock_window();
2120 }
2121
2122
2123 void MWindow::redo_entry(BC_WindowBase *calling_window_gui)
2124 {
2125         calling_window_gui->unlock_window();
2126         stop_playback(0);
2127         if( undo->redo_load_flags() & LOAD_SESSION )
2128                 close_mixers();
2129
2130         cwindow->gui->lock_window("MWindow::redo_entry 1");
2131         for( int i=0; i<vwindows.size(); ++i ) {
2132                 if( vwindows.get(i)->is_running() ) {
2133                         if( calling_window_gui != vwindows.get(i)->gui ) {
2134                                 vwindows.get(i)->gui->lock_window("MWindow::redo_entry 2");
2135                         }
2136                 }
2137         }
2138         gui->lock_window("MWindow::redo_entry 3");
2139
2140         undo->redo();
2141
2142         save_backup();
2143         restart_brender();
2144         update_plugin_states();
2145         update_plugin_guis();
2146
2147         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 1);
2148         gui->update_proxy_toggle();
2149         gui->unlock_window();
2150         cwindow->gui->unlock_window();
2151         cwindow->update(1, 1, 1, 1, 1);
2152
2153         for( int i=0; i < vwindows.size(); ++i ) {
2154                 if( vwindows.get(i)->is_running() ) {
2155                         if( calling_window_gui != vwindows.get(i)->gui ) {
2156                                 vwindows.get(i)->gui->unlock_window();
2157                         }
2158                 }
2159         }
2160
2161         awindow->gui->async_update_assets();
2162
2163         cwindow->refresh_frame(CHANGE_ALL);
2164         calling_window_gui->lock_window("MWindow::redo_entry 4");
2165 }
2166
2167
2168 void MWindow::resize_track(Track *track, int w, int h)
2169 {
2170         undo_before();
2171 // We have to move all maskpoints so they do not move in relation to image areas
2172         ((MaskAutos*)track->automation->autos[AUTOMATION_MASK])->translate_masks(
2173                 (w - track->track_w) / 2,
2174                 (h - track->track_h) / 2);
2175         track->track_w = w;
2176         track->track_h = h;
2177         undo_after(_("resize track"), LOAD_ALL);
2178         save_backup();
2179
2180         restart_brender();
2181         sync_parameters(CHANGE_EDL);
2182 }
2183
2184
2185 void MWindow::set_inpoint()
2186 {
2187         undo_before();
2188         edl->set_inpoint(edl->local_session->get_selectionstart(1));
2189         save_backup();
2190         undo_after(_("in point"), LOAD_TIMEBAR);
2191         gui->update_timebar(1);
2192
2193         cwindow->gui->lock_window("MWindow::set_inpoint 2");
2194         cwindow->gui->timebar->update(1);
2195         cwindow->gui->unlock_window();
2196 }
2197
2198 void MWindow::set_outpoint()
2199 {
2200         undo_before();
2201         edl->set_outpoint(edl->local_session->get_selectionend(1));
2202         save_backup();
2203         undo_after(_("out point"), LOAD_TIMEBAR);
2204
2205         gui->update_timebar(1);
2206         cwindow->gui->lock_window("MWindow::set_outpoint 2");
2207         cwindow->gui->timebar->update(1);
2208         cwindow->gui->unlock_window();
2209 }
2210
2211 void MWindow::unset_inoutpoint()
2212 {
2213         undo_before();
2214         edl->unset_inoutpoint();
2215         save_backup();
2216         undo_after(_("clear in/out"), LOAD_TIMEBAR);
2217
2218         gui->update_timebar(1);
2219         cwindow->gui->lock_window("MWindow::unset_inoutpoint 2");
2220         cwindow->gui->timebar->update(1);
2221         cwindow->gui->unlock_window();
2222 }
2223
2224 void MWindow::splice(EDL *source, int all)
2225 {
2226         FileXML file;
2227         LocalSession *src = source->local_session;
2228
2229         undo_before();
2230         double source_start = all ? 0 :
2231                 src->inpoint_valid() ? src->get_inpoint() :
2232                 src->outpoint_valid() ? 0 : src->get_selectionstart();
2233         double source_end = all ? source->tracks->total_length() :
2234                 src->outpoint_valid() ? src->get_outpoint() :
2235                 src->inpoint_valid() ? source->tracks->total_length() :
2236                         src->get_selectionend();
2237         source->copy(COPY_EDL, source_start, source_end, &file, "", 1);
2238 //file.dump();
2239         double start = edl->local_session->get_selectionstart();
2240         //double end = edl->local_session->get_selectionend();
2241
2242         paste(start, start, &file,
2243                 edl->session->labels_follow_edits,
2244                 edl->session->plugins_follow_edits,
2245                 edl->session->autos_follow_edits,
2246                 0, 0);
2247
2248 // Position at end of clip
2249         edl->local_session->set_selectionstart(start + source_end - source_start);
2250         edl->local_session->set_selectionend(start + source_end - source_start);
2251
2252         save_backup();
2253         undo_after(_("splice"),
2254                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
2255         update_plugin_guis();
2256         restart_brender();
2257         gui->update(1, NORMAL_DRAW, 1, 1, 0, 1, 0);
2258         sync_parameters(CHANGE_EDL);
2259 }
2260
2261 void MWindow::save_clip(EDL *new_edl, const char *txt)
2262 {
2263         new_edl->local_session->set_selectionstart(0);
2264         new_edl->local_session->set_selectionend(0);
2265         sprintf(new_edl->local_session->clip_title, _("Clip %d"),
2266                 session->clip_number++);
2267         char duration[BCTEXTLEN];
2268         Units::totext(duration, new_edl->tracks->total_length(),
2269                 new_edl->session->time_format,
2270                 new_edl->session->sample_rate,
2271                 new_edl->session->frame_rate,
2272                 new_edl->session->frames_per_foot);
2273
2274         Track *track = new_edl->tracks->first;
2275         const char *path = edl->path;
2276         for( ; (!path || !*path) && track; track=track->next ) {
2277                 if( !track->is_armed() ) continue;
2278                 Edit *edit = track->edits->first;
2279                 if( !edit ) continue;
2280                 Indexable *indexable = edit->get_source();
2281                 if( !indexable ) continue;
2282                 path = indexable->path;
2283         }
2284
2285         time_t now;  time(&now);
2286         struct tm dtm;   localtime_r(&now, &dtm);
2287         char *cp = new_edl->local_session->clip_notes;
2288         char *ep = cp + sizeof(new_edl->local_session->clip_notes)-1;
2289         if( txt && *txt )
2290                 cp += snprintf(cp, ep-cp, "%s", txt);
2291         cp += snprintf(cp, ep-cp,
2292                 "%02d/%02d/%02d %02d:%02d:%02d,  +%s\n",
2293                 dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
2294                 dtm.tm_hour, dtm.tm_min, dtm.tm_sec, duration);
2295         if( path && *path ) {
2296                 FileSystem fs;
2297                 char title[BCTEXTLEN];
2298                 fs.extract_name(title, path);
2299                 cp += snprintf(cp, ep-cp, "%s", title);
2300         }
2301         sprintf(new_edl->local_session->clip_icon,
2302                 "clip_%02d%02d%02d-%02d%02d%02d-%d.png",
2303                 dtm.tm_year+1900, dtm.tm_mon+1, dtm.tm_mday,
2304                 dtm.tm_hour, dtm.tm_min, dtm.tm_sec,
2305                 new_edl->id);
2306         new_edl->folder_no = AW_CLIP_FOLDER;
2307         edl->update_assets(new_edl);
2308         int cur_x, cur_y;
2309         gui->get_abs_cursor(cur_x, cur_y, 0);
2310         gui->unlock_window();
2311
2312         awindow->clip_edit->create_clip(new_edl, cur_x, cur_y);
2313         new_edl->remove_user();
2314
2315         gui->lock_window("MWindow::save_clip");
2316         save_backup();
2317 }
2318
2319 void MWindow::to_clip(EDL *edl, const char *txt, int all)
2320 {
2321         FileXML file;
2322         LocalSession *src = edl->local_session;
2323
2324         gui->lock_window("MWindow::to_clip 1");
2325         double start = all ? 0 :
2326                 src->inpoint_valid() ? src->get_inpoint() :
2327                 src->outpoint_valid() ? 0 : src->get_selectionstart();
2328         double end = all ? edl->tracks->total_length() :
2329                 src->outpoint_valid() ? src->get_outpoint() :
2330                 src->inpoint_valid() ? edl->tracks->total_length() :
2331                         src->get_selectionend();
2332         if( EQUIV(end, start) ) {
2333                 start = 0;
2334                 end = edl->tracks->total_length();
2335         }
2336
2337 // Don't copy all since we don't want the clips twice.
2338         edl->copy(copy_flags(), start, end, &file, "", 1);
2339
2340         EDL *new_edl = new EDL(edl);
2341         new_edl->create_objects();
2342         new_edl->load_xml(&file, LOAD_ALL);
2343         save_clip(new_edl, txt);
2344         gui->unlock_window();
2345 }
2346
2347 int MWindow::toggle_label()
2348 {
2349         double position1, position2;
2350         undo_before();
2351
2352         position1 = edl->local_session->get_selectionstart(1);
2353         position2 = edl->local_session->get_selectionend(1);
2354         position1 = edl->align_to_frame(position1, 0);
2355         position2 = edl->align_to_frame(position2, 0);
2356
2357         edl->labels->toggle_label(position1, position2);
2358         save_backup();
2359
2360         gui->update_timebar(0);
2361         gui->activate_timeline();
2362         gui->flush();
2363
2364         cwindow->gui->lock_window("MWindow::toggle_label 2");
2365         cwindow->gui->timebar->update(1);
2366         cwindow->gui->unlock_window();
2367         awindow->gui->async_update_assets();
2368
2369         undo_after(_("label"), LOAD_TIMEBAR);
2370         return 0;
2371 }
2372
2373 void MWindow::trim_selection()
2374 {
2375         undo_before();
2376
2377
2378         edl->trim_selection(edl->local_session->get_selectionstart(),
2379                 edl->local_session->get_selectionend(),
2380                 edl->session->labels_follow_edits,
2381                 edl->session->plugins_follow_edits,
2382                 edl->session->autos_follow_edits);
2383
2384         save_backup();
2385         undo_after(_("trim selection"),
2386                         LOAD_AUTOMATION + LOAD_EDITS + LOAD_TIMEBAR);
2387         update_plugin_guis();
2388         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
2389         cwindow->update(1, 0, 0, 0, 1);
2390         awindow->gui->async_update_assets();
2391         restart_brender();
2392         cwindow->refresh_frame(CHANGE_EDL);
2393 }
2394
2395
2396 void MWindow::undo_entry(BC_WindowBase *calling_window_gui)
2397 {
2398         calling_window_gui->unlock_window();
2399         stop_playback(0);
2400         if( undo->undo_load_flags() & LOAD_SESSION )
2401                 close_mixers();
2402
2403         cwindow->gui->lock_window("MWindow::undo_entry 1");
2404         for( int i=0; i<vwindows.size(); ++i ) {
2405                 if( vwindows.get(i)->is_running() ) {
2406                         if( calling_window_gui != vwindows.get(i)->gui ) {
2407                                 vwindows.get(i)->gui->lock_window("MWindow::undo_entry 4");
2408                         }
2409                 }
2410         }
2411         gui->lock_window("MWindow::undo_entry 2");
2412
2413         undo->undo();
2414
2415         save_backup();
2416         restart_brender();
2417         update_plugin_states();
2418         update_plugin_guis();
2419
2420         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 1);
2421         gui->update_proxy_toggle();
2422         gui->unlock_window();
2423         cwindow->gui->unlock_window();
2424         cwindow->update(1, 1, 1, 1, 1);
2425
2426         for( int i=0; i<vwindows.size(); ++i ) {
2427                 if( vwindows.get(i)->is_running() ) {
2428                         if( calling_window_gui != vwindows.get(i)->gui ) {
2429                                 vwindows.get(i)->gui->unlock_window();
2430                         }
2431                 }
2432         }
2433
2434         awindow->gui->async_update_assets();
2435
2436         cwindow->refresh_frame(CHANGE_ALL);
2437         calling_window_gui->lock_window("MWindow::undo_entry 4");
2438 }
2439
2440
2441 void MWindow::new_folder(const char *new_folder, int is_clips)
2442 {
2443         undo_before();
2444         if( edl->new_folder(new_folder, is_clips) ) {
2445                 MainError::show_error(_("create new folder failed"));
2446         }
2447         undo_after(_("new folder"), LOAD_ALL);
2448         awindow->gui->async_update_assets();
2449 }
2450
2451 void MWindow::delete_folder(char *folder)
2452 {
2453         undo_before();
2454         if( edl->delete_folder(folder) < 0 ) {
2455                 MainError::show_error(_("delete folder failed"));
2456         }
2457         undo_after(_("del folder"), LOAD_ALL);
2458         awindow->gui->async_update_assets();
2459 }
2460
2461 void MWindow::select_point(double position)
2462 {
2463         gui->unlock_window();
2464         gui->stop_drawing();
2465         cwindow->stop_playback(0);
2466         gui->lock_window("MWindow::select_point");
2467
2468         edl->local_session->set_selectionstart(position);
2469         edl->local_session->set_selectionend(position);
2470
2471 // Que the CWindow
2472         cwindow->update(1, 0, 0, 0, 1);
2473
2474         update_plugin_guis();
2475         gui->update_patchbay();
2476         gui->hide_cursor(0);
2477         gui->draw_cursor(0);
2478         gui->mainclock->update(edl->local_session->get_selectionstart(1));
2479         gui->zoombar->update();
2480         gui->update_timebar(0);
2481         gui->flash_canvas(0);
2482         gui->flush();
2483 }
2484
2485
2486
2487
2488 void MWindow::map_audio(int pattern)
2489 {
2490         undo_before();
2491         remap_audio(pattern);
2492         undo_after(
2493                 pattern == MWindow::AUDIO_1_TO_1 ? _("map 1:1") : _("map 5.1:2"),
2494                 LOAD_AUTOMATION);
2495         sync_parameters(CHANGE_PARAMS);
2496         gui->update(0, NORMAL_DRAW, 0, 0, 1, 0, 0);
2497 }
2498
2499 void MWindow::remap_audio(int pattern)
2500 {
2501         int current_channel = 0;
2502         int current_track = 0;
2503         for( Track *current=edl->tracks->first; current; current=NEXT ) {
2504                 if( current->data_type == TRACK_AUDIO &&
2505                         current->is_armed() ) {
2506                         Autos *pan_autos = current->automation->autos[AUTOMATION_PAN];
2507                         PanAuto *pan_auto = (PanAuto*)pan_autos->get_auto_for_editing(-1);
2508
2509                         for( int i=0; i < MAXCHANNELS; ++i ) {
2510                                 pan_auto->values[i] = 0.0;
2511                         }
2512
2513                         if( pattern == MWindow::AUDIO_1_TO_1 ) {
2514                                 pan_auto->values[current_channel] = 1.0;
2515                         }
2516                         else
2517                         if( pattern == MWindow::AUDIO_5_1_TO_2 ) {
2518                                 switch( current_track ) {
2519                                 case 0:
2520                                 case 4:
2521                                         pan_auto->values[0] = 1;
2522                                         break;
2523                                 case 1:
2524                                 case 5:
2525                                         pan_auto->values[1] = 1;
2526                                         break;
2527                                 case 2:
2528                                 case 3:
2529                                         pan_auto->values[0] = 0.5;
2530                                         pan_auto->values[1] = 0.5;
2531                                         break;
2532                                 }
2533                         }
2534
2535                         BC_Pan::calculate_stick_position(edl->session->audio_channels,
2536                                 edl->session->achannel_positions, pan_auto->values,
2537                                 MAX_PAN, PAN_RADIUS, pan_auto->handle_x, pan_auto->handle_y);
2538
2539                         current_channel++;
2540                         current_track++;
2541                         if( current_channel >= edl->session->audio_channels )
2542                                 current_channel = 0;
2543                 }
2544         }
2545 }
2546
2547
2548 void MWindow::rescale_proxy(EDL *clip, int orig_scale, int new_scale)
2549 {
2550         edl->rescale_proxy(orig_scale, new_scale);
2551 }
2552
2553 void MWindow::add_proxy(ArrayList<Indexable*> *orig_assets, ArrayList<Indexable*> *proxy_assets)
2554 {
2555         edl->add_proxy(orig_assets, proxy_assets);
2556 }
2557
2558 void MWindow::start_convert(Asset *format_asset, const char *suffix,
2559                 float beep, int to_proxy, int remove_originals)
2560 {
2561         if( !convert_render )
2562                 convert_render = new ConvertRender(this);
2563         convert_render->set_format(format_asset, suffix, to_proxy);
2564         int found = convert_render->find_convertable_assets(edl);
2565         if( convert_render->needed_idxbls.size() > 0 )
2566                 convert_render->start_convert(beep, remove_originals);
2567         else if( found > 0 )
2568                 finish_convert(remove_originals);
2569         else if( found < 0 )
2570                 eprintf(_("convert assets format error"));
2571         else
2572                 eprintf(_("No convertable assets found"));
2573 }
2574
2575 void MWindow::finish_convert(int remove_originals)
2576 {
2577         gui->lock_window("MWindow::finish_convert");
2578         undo_before();
2579         edl->replace_assets(
2580                 convert_render->orig_idxbls,
2581                 convert_render->orig_copies);
2582         if( remove_originals ) {
2583                 remove_assets_from_project(0, 0, 0,
2584                         &convert_render->orig_idxbls, 0);
2585         }
2586         save_backup();
2587         undo_after(_("convert"), LOAD_ALL);
2588
2589         update_plugin_guis();
2590         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
2591         cwindow->update(1, 0, 0, 0, 1);
2592         awindow->gui->async_update_assets();
2593         cwindow->refresh_frame(CHANGE_EDL);
2594         gui->unlock_window();
2595 }
2596
2597 void MWindow::cut_commercials()
2598 {
2599 #ifdef HAVE_COMMERCIAL
2600         undo_before();
2601         commercials->scan_media();
2602         edl->optimize();
2603         save_backup();
2604         undo_after(_("cut ads"), LOAD_EDITS | LOAD_TIMEBAR);
2605
2606         restart_brender();
2607         update_plugin_guis();
2608         gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
2609         cwindow->update(1, 0, 0, 0, 1);
2610         cwindow->refresh_frame(CHANGE_EDL);
2611 #endif
2612 }
2613
2614 int MWindow::normalize_speed(EDL *old_edl, EDL *new_edl, int edit_speed)
2615 {
2616         int edit_plugins = edl->session->plugins_follow_edits;
2617         int edit_autos = edl->session->autos_follow_edits;
2618         int edit_labels = edl->session->labels_follow_edits;
2619         if( !edit_autos ) edit_speed = 0;
2620         int result = 0, first_track = 1;
2621         Track *old_track = old_edl->tracks->first;
2622         Track *new_track = new_edl->tracks->first;
2623         for( ; old_track && new_track; old_track=old_track->next, new_track=new_track->next ) {
2624                 if( old_track->data_type != new_track->data_type ) continue;
2625                 FloatAutos *old_speeds = (FloatAutos *)old_track->automation->autos[AUTOMATION_SPEED];
2626                 FloatAutos *new_speeds = (FloatAutos *)new_track->automation->autos[AUTOMATION_SPEED];
2627                 if( !old_speeds || !new_speeds ) continue;
2628                 FloatAuto *old_speed = (FloatAuto *)old_speeds->first;
2629                 FloatAuto *new_speed = (FloatAuto *)new_speeds->first;
2630                 while( old_speed && new_speed && old_speed->equals(new_speed) ) {
2631                         old_speed = (FloatAuto *)old_speed->next;
2632                         new_speed = (FloatAuto *)new_speed->next;
2633                 }
2634                 if( !old_speed && !new_speed ) continue;
2635                 result = 1;
2636                 if( edit_speed ) {
2637                         Autos *old_autos = old_track->automation->autos[AUTOMATION_SPEED];
2638                         Autos *new_autos = new_track->automation->autos[AUTOMATION_SPEED];
2639                         Auto *old_auto = old_autos ? old_autos->first : 0;
2640                         for( ; old_auto; old_auto=old_auto->next ) {
2641                                 Auto *new_auto = new_autos->get_auto(old_auto->orig_id);
2642                                 if( !new_auto ) continue;
2643                                 int64_t auto_pos = old_auto->position;
2644                                 double orig_pos = old_speeds->automation_integral(0, auto_pos, PLAY_FORWARD);
2645                                 auto_pos = new_track->frame_align(new_speeds->speed_position(orig_pos), 1);
2646                                 new_auto->position = auto_pos;
2647                         }
2648                 }
2649                 Edit *old_edit = old_track->edits->first;
2650                 for( ; old_edit; old_edit=old_edit->next ) {
2651                         Edit *new_edit = new_track->edits->get_edit(old_edit->orig_id);
2652                         if( !new_edit ) continue;
2653                         int64_t edit_start = old_edit->startproject;
2654                         int64_t edit_end = edit_start + old_edit->length;
2655                         double orig_start = old_speeds->automation_integral(0, edit_start, PLAY_FORWARD);
2656                         double orig_end   = old_speeds->automation_integral(0, edit_end, PLAY_FORWARD);
2657                         edit_start = new_track->frame_align(new_speeds->speed_position(orig_start), 1);
2658                         edit_end = new_track->frame_align(new_speeds->speed_position(orig_end), 1);
2659                         new_edit->startproject = edit_start;
2660                         new_edit->length = edit_end - edit_start;
2661                 }
2662                 if( first_track && old_track->is_armed() ) {
2663                         Labels *old_labels = old_edl->labels;
2664                         Labels *new_labels = new_edl->labels;
2665                         if( edit_labels && old_labels && new_labels ) {
2666                                 Label *old_label = old_labels->first;
2667                                 for( ; old_label; old_label=old_label->next ) {
2668                                         Label *new_label = new_labels->get_label(old_label->orig_id);
2669                                         if( !new_label ) continue;
2670                                         int64_t label_pos = old_track->to_units(old_label->position, 1);
2671                                         double orig_pos = old_speeds->automation_integral(0, label_pos, PLAY_FORWARD);
2672                                         label_pos = new_track->frame_align(new_speeds->speed_position(orig_pos), 1);
2673                                         new_label->position = new_track->from_units(label_pos);
2674                                 }
2675                         }
2676                         first_track = 0;
2677                 }
2678                 if( edit_plugins ) {
2679                         int old_size = old_track->plugin_set.size();
2680                         int new_size = new_track->plugin_set.size();
2681                         int n = bmin(old_size, new_size);
2682                         for( int i=0; i<n; ++i ) {
2683                                 PluginSet *old_plugin_set = old_track->plugin_set[i];
2684                                 if( !old_plugin_set ) continue;
2685                                 PluginSet *new_plugin_set = new_track->plugin_set[i];
2686                                 if( !new_plugin_set ) continue;
2687                                 Plugin *old_plugin = (Plugin *)old_plugin_set->first;
2688                                 for( ; old_plugin; old_plugin=(Plugin *)old_plugin->next ) {
2689                                         Plugin *new_plugin = (Plugin *)new_plugin_set->get_edit(old_plugin->orig_id);
2690                                         if( !new_plugin ) continue;
2691                                         int64_t plugin_start = old_plugin->startproject;
2692                                         int64_t plugin_end = plugin_start + old_plugin->length;
2693                                         double orig_start = old_speeds->automation_integral(0, plugin_start, PLAY_FORWARD);
2694                                         double orig_end   = old_speeds->automation_integral(0, plugin_end, PLAY_FORWARD);
2695                                         plugin_start = new_track->frame_align(new_speeds->speed_position(orig_start), 1);
2696                                         plugin_end = new_track->frame_align(new_speeds->speed_position(orig_end), 1);
2697                                         new_plugin->startproject = plugin_start;
2698                                         new_plugin->length = plugin_end - plugin_start;
2699                                         if( edit_autos ) {
2700                                                 KeyFrames *old_keyframes = old_plugin->keyframes;
2701                                                 if( !old_keyframes ) continue;
2702                                                 KeyFrames *new_keyframes = new_plugin->keyframes;
2703                                                 if( !new_keyframes ) continue;
2704                                                 Auto *old_auto = old_keyframes->first;
2705                                                 for( ; old_auto; old_auto=old_auto->next ) {
2706                                                         Auto *new_auto = new_keyframes->get_auto(old_auto->orig_id);
2707                                                         if( !new_auto ) continue;
2708                                                         int64_t auto_pos = old_auto->position;
2709                                                         double orig_pos = old_speeds->automation_integral(0, auto_pos, PLAY_FORWARD);
2710                                                         auto_pos = new_track->frame_align(new_speeds->speed_position(orig_pos), 1);
2711                                                         new_auto->position = auto_pos;
2712                                                         old_auto = old_auto->next;
2713                                                 }
2714                                         }
2715                                 }
2716                         }
2717                 }
2718                 if( edit_autos ) { // speed must be last
2719                         for( int i=0; i<AUTOMATION_SPEED; ++i ) {
2720                                 Autos *old_autos = old_track->automation->autos[i];
2721                                 if( !old_autos ) continue;
2722                                 Autos *new_autos = new_track->automation->autos[i];
2723                                 if( !new_autos ) continue;
2724                                 Auto *old_auto = old_autos->first;
2725                                 for( ; old_auto; old_auto=old_auto->next ) {
2726                                         Auto *new_auto = new_autos->get_auto(old_auto->orig_id);
2727                                         if( !new_auto ) continue;
2728                                         int64_t auto_pos = old_auto->position;
2729                                         double orig_pos = old_speeds->automation_integral(0, auto_pos, PLAY_FORWARD);
2730                                         auto_pos = new_track->frame_align(new_speeds->speed_position(orig_pos), 1);
2731                                         new_auto->position = auto_pos;
2732                                 }
2733                         }
2734                 }
2735         }
2736         return result;
2737 }
2738
2739 void MWindow::speed_before()
2740 {
2741         if( !speed_edl ) {
2742                 speed_edl = new EDL;
2743                 speed_edl->create_objects();
2744         }
2745         speed_edl->copy_all(edl);
2746 }
2747
2748 int MWindow::speed_after(int done, int edit_speed)
2749 {
2750         int result = 0;
2751         if( speed_edl ) {
2752                 if( done >= 0 )
2753                         result = normalize_speed(speed_edl, edl, edit_speed);
2754                 if( done != 0 ) {
2755                         speed_edl->remove_user();
2756                         speed_edl = 0;
2757                 }
2758         }
2759         return result;
2760 }
2761
2762 void MWindow::collect_effects()
2763 {
2764         FileXML file;
2765         const char *file_string = "";
2766         EDL *group = 0;
2767         int ret = edl->collect_effects(group);
2768         switch( ret ) {
2769         case COLLECT_EFFECTS_RECORD:
2770                 eprintf(_("Selected edit track not armed."));
2771                 break;
2772         case COLLECT_EFFECTS_MULTIPLE:
2773                 eprintf(_("More than one edit selected on a track."));
2774                 break;
2775         case COLLECT_EFFECTS_MISSING:
2776                 eprintf(_("No effects under selected edit."));
2777                 break;
2778         case COLLECT_EFFECTS_EMPTY:
2779                 eprintf(_("No edits selected."));
2780                 break;
2781         case COLLECT_EFFECTS_MASTER:
2782                 eprintf(_("Shared effect added without master."));
2783                 break;
2784         case 0:
2785                 group->save_xml(&file, "");
2786                 file_string = file.string();
2787                 group->remove_user();
2788         }
2789         long file_length = strlen(file_string);
2790         gui->to_clipboard(file_string, file_length, BC_PRIMARY_SELECTION);
2791         gui->to_clipboard(file_string, file_length, SECONDARY_SELECTION);
2792 }
2793
2794 void MWindow::paste_effects()
2795 {
2796         char *string = 0;
2797         int64_t len = gui->clipboard_len(BC_PRIMARY_SELECTION);
2798         if( len ) {
2799                 string = new char[len];
2800                 gui->from_clipboard(string, len, BC_PRIMARY_SELECTION);
2801         }
2802         if( !string || !string[0] ) {
2803                 eprintf(_("Error clipboard buffer empty."));
2804                 return;
2805         }
2806         FileXML file;
2807         file.read_from_string(string);
2808         EDL *group = new EDL();
2809         group->create_objects();
2810         if( !group->load_xml(&file, LOAD_ALL) ) {
2811                 undo_before();
2812                 int ret = edl->insert_effects(group);
2813                 switch( ret ) {
2814                 case INSERT_EFFECTS_RECORD:
2815                         eprintf(_("Selected edit track not armed."));
2816                         break;
2817                 case INSERT_EFFECTS_TYPE:
2818                         eprintf(_("Track type mismatched."));
2819                         break;
2820                 case INSERT_EFFECTS_MULTIPLE:
2821                         eprintf(_("More than one edit selected on a track."));
2822                         break;
2823                 case INSERT_EFFECTS_MISSING:
2824                         eprintf(_("Too few target edits to add group effects."));
2825                         break;
2826                 case INSERT_EFFECTS_EXTRA:
2827                         eprintf(_("Too many target edits to add group effects."));
2828                         break;
2829                 case INSERT_EFFECTS_MASTER:
2830                         eprintf(_("Shared effect added without master."));
2831                         break;
2832                 case 0:
2833                         break;
2834                 }
2835                 save_backup();
2836                 undo_after(_("paste effects"), LOAD_ALL);
2837                 restart_brender();
2838                 cwindow->refresh_frame(CHANGE_EDL);
2839                 update_plugin_guis();
2840                 gui->update(1, NORMAL_DRAW, 1, 0, 0, 0, 0);
2841         }
2842         else
2843                 eprintf(_("Error loading clip from clipboard buffer."));
2844         delete [] string;
2845         group->remove_user();
2846 }
2847
2848 void MWindow::align_timecodes()
2849 {
2850         undo_before();
2851         double offset = edl->tracks->align_timecodes();
2852         set_timecode_offset(offset);
2853         save_backup();
2854         undo_after(_("align timecodes"), LOAD_ALL);
2855         restart_brender();
2856         cwindow->refresh_frame(CHANGE_EDL);
2857         update_plugin_guis();
2858 }
2859
2860
2861 int MWindow::masters_to_mixers()
2862 {
2863         Track *master_track = edl->tracks->first;
2864         while( master_track && !master_track->master )
2865                 master_track = master_track->next;
2866         while( master_track ) { // test for track/mixer conflicts
2867                 int failed = 0;
2868                 Track *mixer_last = master_track;
2869                 Track *track = master_track->next;
2870                 for( ; track && !track->master; track=track->next )
2871                         mixer_last = track;
2872                 Track *next_track = track;
2873                 if( !master_track->armed ) {
2874                         master_track = next_track;
2875                         continue;
2876                 }
2877                 Mixer *master_mixer = 0;
2878                 for( int i=0, n=edl->mixers.size(); i<n; ++i ) {
2879                         if( master_track->index_in(edl->mixers[i]) >= 0 ) {
2880                                 master_mixer = edl->mixers[i];
2881                                 break;
2882                         }
2883                 }
2884                 if( master_mixer ) { // existing mixer track group
2885                         for( track=master_track; !failed && track; track=track->next ) {
2886                                 if( track->index_in(master_mixer) < 0 ) {
2887                                         eprintf("Mixer: %s missing track: %s",
2888                                                 master_mixer->title, track->title);
2889                                         failed = 1;
2890                                 }
2891                                 if( track == mixer_last ) break;
2892                         }
2893                         for( int i=0, n=master_mixer->mixer_ids.size(); !failed && i<n; ++i ) {
2894                                 int mixer_id = master_mixer->mixer_ids[i], found = 0;
2895                                 for( track=master_track; track; track=track->next ) {
2896                                         if( track->mixer_id == mixer_id ) {
2897                                                 found = 1;
2898                                                 break;
2899                                         }
2900                                         if( track == mixer_last ) break;
2901                                 }
2902                                 if( !found ) {
2903                                         eprintf("Mixer: %s track missing: %s",
2904                                                 master_mixer->title, track->title);
2905                                         failed = 1;
2906                                 }
2907                         }
2908                 }
2909                 else { // create mixer
2910                         for( track=master_track->next; !failed && track; track=track->next ) {
2911                                 for( int i=0, n=edl->mixers.size(); !failed && i<n; ++i ) {
2912                                         Mixer *mixer = edl->mixers[i];
2913                                         if( track->index_in(mixer) >= 0 ) {
2914                                                 eprintf("Track: %s already exists in mixer: %s",
2915                                                         track->title, mixer->title);
2916                                                 failed = 1;
2917                                                 break;
2918                                         }
2919                                 }
2920                                 if( track == mixer_last ) break;
2921                         }
2922                         if( !failed ) { // new mixer
2923                                 ZWindow *zwindow = get_mixer(master_mixer);
2924                                 zwindow->set_title(master_track->title);
2925                                 sprintf(master_track->title, _("Mixer %d"), zwindow->idx);
2926                                 for( track=master_track; track; track=track->next ) {
2927                                         track->play = track->armed = 0;
2928                                         master_mixer->mixer_ids.append(track->get_mixer_id());
2929                                         if( track == mixer_last ) break;
2930                                 }
2931                                 zwindow->start();
2932                         }
2933                 }
2934                 master_track = next_track;
2935         }
2936         return 0;
2937 }
2938
2939 void MWindow::mix_masters()
2940 {
2941         undo_before();
2942         masters_to_mixers();
2943         undo_after(_("mix masters"), LOAD_ALL);
2944
2945         restart_brender();
2946         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
2947         gui->activate_timeline();
2948         cwindow->refresh_frame(CHANGE_EDL);
2949         save_backup();
2950 }
2951
2952 void MWindow::create_keyframes(int mask, int mode)
2953 {
2954         undo_before();
2955         double start = edl->local_session->get_selectionstart();
2956         edl->tracks->create_keyframes(start, mask, mode);
2957         double end = edl->local_session->get_selectionend();
2958         if( end != start )
2959                 edl->tracks->create_keyframes(end, mask, mode);
2960         undo_after(_("create kyfrms"), LOAD_AUTOMATION);
2961
2962         restart_brender();
2963         gui->update(1, NORMAL_DRAW, 0, 0, 1, 0, 0);
2964         gui->activate_timeline();
2965         cwindow->refresh_frame(CHANGE_EDL);
2966         save_backup();
2967 }
2968