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