first vaguely working version using PresentationInfo
[ardour.git] / gtk2_ardour / editor_ops.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <limits>
28 #include <map>
29 #include <set>
30
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
38
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
42
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/boost_debug.h"
46 #include "ardour/dB.h"
47 #include "ardour/location.h"
48 #include "ardour/midi_region.h"
49 #include "ardour/midi_track.h"
50 #include "ardour/operations.h"
51 #include "ardour/playlist_factory.h"
52 #include "ardour/profile.h"
53 #include "ardour/quantize.h"
54 #include "ardour/legatize.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/reverse.h"
57 #include "ardour/session.h"
58 #include "ardour/session_playlists.h"
59 #include "ardour/strip_silence.h"
60 #include "ardour/transient_detector.h"
61 #include "ardour/transpose.h"
62
63 #include "canvas/canvas.h"
64
65 #include "actions.h"
66 #include "audio_region_view.h"
67 #include "audio_streamview.h"
68 #include "audio_time_axis.h"
69 #include "automation_region_view.h"
70 #include "automation_time_axis.h"
71 #include "control_point.h"
72 #include "debug.h"
73 #include "editing.h"
74 #include "editor.h"
75 #include "editor_cursors.h"
76 #include "editor_drag.h"
77 #include "editor_regions.h"
78 #include "editor_routes.h"
79 #include "gui_thread.h"
80 #include "insert_remove_time_dialog.h"
81 #include "interthread_progress_window.h"
82 #include "item_counts.h"
83 #include "keyboard.h"
84 #include "midi_region_view.h"
85 #include "mixer_strip.h"
86 #include "mouse_cursors.h"
87 #include "normalize_dialog.h"
88 #include "note.h"
89 #include "paste_context.h"
90 #include "patch_change_dialog.h"
91 #include "quantize_dialog.h"
92 #include "region_gain_line.h"
93 #include "rgb_macros.h"
94 #include "route_time_axis.h"
95 #include "selection.h"
96 #include "selection_templates.h"
97 #include "streamview.h"
98 #include "strip_silence_dialog.h"
99 #include "time_axis_view.h"
100 #include "timers.h"
101 #include "transpose_dialog.h"
102 #include "transform_dialog.h"
103 #include "ui_config.h"
104
105 #include "i18n.h"
106
107 using namespace std;
108 using namespace ARDOUR;
109 using namespace PBD;
110 using namespace Gtk;
111 using namespace Gtkmm2ext;
112 using namespace Editing;
113 using Gtkmm2ext::Keyboard;
114
115 /***********************************************************************
116   Editor operations
117  ***********************************************************************/
118
119 void
120 Editor::undo (uint32_t n)
121 {
122         if (_drags->active ()) {
123                 _drags->abort ();
124         }
125
126         if (_session) {
127                 _session->undo (n);
128                 if (_session->undo_depth() == 0) {
129                         undo_action->set_sensitive(false);
130                 }
131                 redo_action->set_sensitive(true);
132                 begin_selection_op_history ();
133         }
134 }
135
136 void
137 Editor::redo (uint32_t n)
138 {
139         if (_drags->active ()) {
140                 _drags->abort ();
141         }
142
143         if (_session) {
144                 _session->redo (n);
145                 if (_session->redo_depth() == 0) {
146                         redo_action->set_sensitive(false);
147                 }
148                 undo_action->set_sensitive(true);
149                 begin_selection_op_history ();
150         }
151 }
152
153 void
154 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
155 {
156         bool frozen = false;
157
158         RegionSelection pre_selected_regions = selection->regions;
159         bool working_on_selection = !pre_selected_regions.empty();
160
161         list<boost::shared_ptr<Playlist> > used_playlists;
162         list<RouteTimeAxisView*> used_trackviews;
163
164         if (regions.empty()) {
165                 return;
166         }
167
168         begin_reversible_command (_("split"));
169
170         // if splitting a single region, and snap-to is using
171         // region boundaries, don't pay attention to them
172
173         if (regions.size() == 1) {
174                 switch (_snap_type) {
175                 case SnapToRegionStart:
176                 case SnapToRegionSync:
177                 case SnapToRegionEnd:
178                         break;
179                 default:
180                         snap_to (where);
181                 }
182         } else {
183                 snap_to (where);
184
185                 frozen = true;
186                 EditorFreeze(); /* Emit Signal */
187         }
188
189         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
190
191                 RegionSelection::iterator tmp;
192
193                 /* XXX this test needs to be more complicated, to make sure we really
194                    have something to split.
195                 */
196
197                 if (!(*a)->region()->covers (where)) {
198                         ++a;
199                         continue;
200                 }
201
202                 tmp = a;
203                 ++tmp;
204
205                 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
206
207                 if (!pl) {
208                         a = tmp;
209                         continue;
210                 }
211
212                 if (!pl->frozen()) {
213                         /* we haven't seen this playlist before */
214
215                         /* remember used playlists so we can thaw them later */
216                         used_playlists.push_back(pl);
217
218                         TimeAxisView& tv = (*a)->get_time_axis_view();
219                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
220                         if (rtv) {
221                                 used_trackviews.push_back (rtv);
222                         }
223                         pl->freeze();
224                 }
225
226
227                 if (pl) {
228                         pl->clear_changes ();
229                         pl->split_region ((*a)->region(), where);
230                         _session->add_command (new StatefulDiffCommand (pl));
231                 }
232
233                 a = tmp;
234         }
235
236         latest_regionviews.clear ();
237
238         vector<sigc::connection> region_added_connections;
239
240         for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
241                 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
242         }
243
244         while (used_playlists.size() > 0) {
245                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
246                 (*i)->thaw();
247                 used_playlists.pop_front();
248         }
249
250         for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
251                 (*c).disconnect ();
252         }
253
254         if (frozen){
255                 EditorThaw(); /* Emit Signal */
256         }
257
258         if (working_on_selection) {
259                 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
260
261                 _ignore_follow_edits = true;  // a split will change the region selection in mysterious ways;  it's not practical or wanted to follow this edit
262                 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
263                 /* There are three classes of regions that we might want selected after
264                    splitting selected regions:
265                     - regions selected before the split operation, and unaffected by it
266                     - newly-created regions before the split
267                     - newly-created regions after the split
268                  */
269
270                 if (rsas & Existing) {
271                         // region selections that existed before the split.
272                         selection->add ( pre_selected_regions );
273                 }
274
275                 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
276                         if ((*ri)->region()->position() < where) {
277                                 // new regions created before the split
278                                 if (rsas & NewlyCreatedLeft) {
279                                         selection->add (*ri);
280                                 }
281                         } else {
282                                 // new regions created after the split
283                                 if (rsas & NewlyCreatedRight) {
284                                         selection->add (*ri);
285                                 }
286                         }
287                 }
288                 _ignore_follow_edits = false;
289         } else {
290                 _ignore_follow_edits = true;
291                 if( working_on_selection ) {
292                         selection->add (latest_regionviews);  //these are the new regions created after the split
293                 }
294                 _ignore_follow_edits = false;
295         }
296
297         commit_reversible_command ();
298 }
299
300 /** Move one extreme of the current range selection.  If more than one range is selected,
301  *  the start of the earliest range or the end of the latest range is moved.
302  *
303  *  @param move_end true to move the end of the current range selection, false to move
304  *  the start.
305  *  @param next true to move the extreme to the next region boundary, false to move to
306  *  the previous.
307  */
308 void
309 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
310 {
311         if (selection->time.start() == selection->time.end_frame()) {
312                 return;
313         }
314
315         framepos_t start = selection->time.start ();
316         framepos_t end = selection->time.end_frame ();
317
318         /* the position of the thing we may move */
319         framepos_t pos = move_end ? end : start;
320         int dir = next ? 1 : -1;
321
322         /* so we don't find the current region again */
323         if (dir > 0 || pos > 0) {
324                 pos += dir;
325         }
326
327         framepos_t const target = get_region_boundary (pos, dir, true, false);
328         if (target < 0) {
329                 return;
330         }
331
332         if (move_end) {
333                 end = target;
334         } else {
335                 start = target;
336         }
337
338         if (end < start) {
339                 return;
340         }
341
342         begin_reversible_selection_op (_("alter selection"));
343         selection->set_preserving_all_ranges (start, end);
344         commit_reversible_selection_op ();
345 }
346
347 bool
348 Editor::nudge_forward_release (GdkEventButton* ev)
349 {
350         if (ev->state & Keyboard::PrimaryModifier) {
351                 nudge_forward (false, true);
352         } else {
353                 nudge_forward (false, false);
354         }
355         return false;
356 }
357
358 bool
359 Editor::nudge_backward_release (GdkEventButton* ev)
360 {
361         if (ev->state & Keyboard::PrimaryModifier) {
362                 nudge_backward (false, true);
363         } else {
364                 nudge_backward (false, false);
365         }
366         return false;
367 }
368
369
370 void
371 Editor::nudge_forward (bool next, bool force_playhead)
372 {
373         framepos_t distance;
374         framepos_t next_distance;
375
376         if (!_session) {
377                 return;
378         }
379
380         RegionSelection rs = get_regions_from_selection_and_entered ();
381
382         if (!force_playhead && !rs.empty()) {
383
384                 begin_reversible_command (_("nudge regions forward"));
385
386                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
387                         boost::shared_ptr<Region> r ((*i)->region());
388
389                         distance = get_nudge_distance (r->position(), next_distance);
390
391                         if (next) {
392                                 distance = next_distance;
393                         }
394
395                         r->clear_changes ();
396                         r->set_position (r->position() + distance);
397                         _session->add_command (new StatefulDiffCommand (r));
398                 }
399
400                 commit_reversible_command ();
401
402
403         } else if (!force_playhead && !selection->markers.empty()) {
404
405                 bool is_start;
406                 bool in_command = false;
407
408                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
409
410                         Location* loc = find_location_from_marker ((*i), is_start);
411
412                         if (loc) {
413
414                                 XMLNode& before (loc->get_state());
415
416                                 if (is_start) {
417                                         distance = get_nudge_distance (loc->start(), next_distance);
418                                         if (next) {
419                                                 distance = next_distance;
420                                         }
421                                         if (max_framepos - distance > loc->start() + loc->length()) {
422                                                 loc->set_start (loc->start() + distance);
423                                         } else {
424                                                 loc->set_start (max_framepos - loc->length());
425                                         }
426                                 } else {
427                                         distance = get_nudge_distance (loc->end(), next_distance);
428                                         if (next) {
429                                                 distance = next_distance;
430                                         }
431                                         if (max_framepos - distance > loc->end()) {
432                                                 loc->set_end (loc->end() + distance);
433                                         } else {
434                                                 loc->set_end (max_framepos);
435                                         }
436                                 }
437                                 if (!in_command) {
438                                         begin_reversible_command (_("nudge location forward"));
439                                         in_command = true;
440                                 }
441                                 XMLNode& after (loc->get_state());
442                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
443                         }
444                 }
445
446                 if (in_command) {
447                         commit_reversible_command ();
448                 }
449         } else {
450                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
451                 _session->request_locate (playhead_cursor->current_frame () + distance);
452         }
453 }
454
455 void
456 Editor::nudge_backward (bool next, bool force_playhead)
457 {
458         framepos_t distance;
459         framepos_t next_distance;
460
461         if (!_session) {
462                 return;
463         }
464
465         RegionSelection rs = get_regions_from_selection_and_entered ();
466
467         if (!force_playhead && !rs.empty()) {
468
469                 begin_reversible_command (_("nudge regions backward"));
470
471                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
472                         boost::shared_ptr<Region> r ((*i)->region());
473
474                         distance = get_nudge_distance (r->position(), next_distance);
475
476                         if (next) {
477                                 distance = next_distance;
478                         }
479
480                         r->clear_changes ();
481
482                         if (r->position() > distance) {
483                                 r->set_position (r->position() - distance);
484                         } else {
485                                 r->set_position (0);
486                         }
487                         _session->add_command (new StatefulDiffCommand (r));
488                 }
489
490                 commit_reversible_command ();
491
492         } else if (!force_playhead && !selection->markers.empty()) {
493
494                 bool is_start;
495                 bool in_command = false;
496
497                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
498
499                         Location* loc = find_location_from_marker ((*i), is_start);
500
501                         if (loc) {
502
503                                 XMLNode& before (loc->get_state());
504
505                                 if (is_start) {
506                                         distance = get_nudge_distance (loc->start(), next_distance);
507                                         if (next) {
508                                                 distance = next_distance;
509                                         }
510                                         if (distance < loc->start()) {
511                                                 loc->set_start (loc->start() - distance);
512                                         } else {
513                                                 loc->set_start (0);
514                                         }
515                                 } else {
516                                         distance = get_nudge_distance (loc->end(), next_distance);
517
518                                         if (next) {
519                                                 distance = next_distance;
520                                         }
521
522                                         if (distance < loc->end() - loc->length()) {
523                                                 loc->set_end (loc->end() - distance);
524                                         } else {
525                                                 loc->set_end (loc->length());
526                                         }
527                                 }
528                                 if (!in_command) {
529                                         begin_reversible_command (_("nudge location forward"));
530                                         in_command = true;
531                                 }
532                                 XMLNode& after (loc->get_state());
533                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
534                         }
535                 }
536                 if (in_command) {
537                         commit_reversible_command ();
538                 }
539
540         } else {
541
542                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
543
544                 if (playhead_cursor->current_frame () > distance) {
545                         _session->request_locate (playhead_cursor->current_frame () - distance);
546                 } else {
547                         _session->goto_start();
548                 }
549         }
550 }
551
552 void
553 Editor::nudge_forward_capture_offset ()
554 {
555         RegionSelection rs = get_regions_from_selection_and_entered ();
556
557         if (!_session || rs.empty()) {
558                 return;
559         }
560
561         begin_reversible_command (_("nudge forward"));
562
563         framepos_t const distance = _session->worst_output_latency();
564
565         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
566                 boost::shared_ptr<Region> r ((*i)->region());
567
568                 r->clear_changes ();
569                 r->set_position (r->position() + distance);
570                 _session->add_command(new StatefulDiffCommand (r));
571         }
572
573         commit_reversible_command ();
574 }
575
576 void
577 Editor::nudge_backward_capture_offset ()
578 {
579         RegionSelection rs = get_regions_from_selection_and_entered ();
580
581         if (!_session || rs.empty()) {
582                 return;
583         }
584
585         begin_reversible_command (_("nudge backward"));
586
587         framepos_t const distance = _session->worst_output_latency();
588
589         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
590                 boost::shared_ptr<Region> r ((*i)->region());
591
592                 r->clear_changes ();
593
594                 if (r->position() > distance) {
595                         r->set_position (r->position() - distance);
596                 } else {
597                         r->set_position (0);
598                 }
599                 _session->add_command(new StatefulDiffCommand (r));
600         }
601
602         commit_reversible_command ();
603 }
604
605 struct RegionSelectionPositionSorter {
606         bool operator() (RegionView* a, RegionView* b) {
607                 return a->region()->position() < b->region()->position();
608         }
609 };
610
611 void
612 Editor::sequence_regions ()
613 {
614         framepos_t r_end;
615         framepos_t r_end_prev;
616
617         int iCount=0;
618
619         if (!_session) {
620                 return;
621         }
622
623         RegionSelection rs = get_regions_from_selection_and_entered ();
624         rs.sort(RegionSelectionPositionSorter());
625
626         if (!rs.empty()) {
627
628                 bool in_command = false;
629
630                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
631                         boost::shared_ptr<Region> r ((*i)->region());
632
633                         r->clear_changes();
634
635                         if(r->locked())
636                         {
637                                 continue;
638                         }
639                         if(r->position_locked())
640                         {
641                                 continue;
642                         }
643                         if(iCount>0)
644                         {
645                                 r_end_prev=r_end;
646                                 r->set_position(r_end_prev);
647                         }
648
649                         if (!in_command) {
650                                 begin_reversible_command (_("sequence regions"));
651                                 in_command = true;
652                         }
653                         _session->add_command (new StatefulDiffCommand (r));
654
655                         r_end=r->position() + r->length();
656
657                         iCount++;
658                 }
659
660                 if (in_command) {
661                         commit_reversible_command ();
662                 }
663         }
664 }
665
666
667 /* DISPLAY MOTION */
668
669 void
670 Editor::move_to_start ()
671 {
672         _session->goto_start ();
673 }
674
675 void
676 Editor::move_to_end ()
677 {
678
679         _session->request_locate (_session->current_end_frame());
680 }
681
682 void
683 Editor::build_region_boundary_cache ()
684 {
685         framepos_t pos = 0;
686         vector<RegionPoint> interesting_points;
687         boost::shared_ptr<Region> r;
688         TrackViewList tracks;
689         bool at_end = false;
690
691         region_boundary_cache.clear ();
692
693         if (_session == 0) {
694                 return;
695         }
696
697         switch (_snap_type) {
698         case SnapToRegionStart:
699                 interesting_points.push_back (Start);
700                 break;
701         case SnapToRegionEnd:
702                 interesting_points.push_back (End);
703                 break;
704         case SnapToRegionSync:
705                 interesting_points.push_back (SyncPoint);
706                 break;
707         case SnapToRegionBoundary:
708                 interesting_points.push_back (Start);
709                 interesting_points.push_back (End);
710                 break;
711         default:
712                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
713                 abort(); /*NOTREACHED*/
714                 return;
715         }
716
717         TimeAxisView *ontrack = 0;
718         TrackViewList tlist;
719
720         if (!selection->tracks.empty()) {
721                 tlist = selection->tracks.filter_to_unique_playlists ();
722         } else {
723                 tlist = track_views.filter_to_unique_playlists ();
724         }
725
726         while (pos < _session->current_end_frame() && !at_end) {
727
728                 framepos_t rpos;
729                 framepos_t lpos = max_framepos;
730
731                 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
732
733                         if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
734                                 if (*p == interesting_points.back()) {
735                                         at_end = true;
736                                 }
737                                 /* move to next point type */
738                                 continue;
739                         }
740
741                         switch (*p) {
742                         case Start:
743                                 rpos = r->first_frame();
744                                 break;
745
746                         case End:
747                                 rpos = r->last_frame();
748                                 break;
749
750                         case SyncPoint:
751                                 rpos = r->sync_position ();
752                                 break;
753
754                         default:
755                                 break;
756                         }
757
758                         float speed = 1.0f;
759                         RouteTimeAxisView *rtav;
760
761                         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
762                                 if (rtav->track() != 0) {
763                                         speed = rtav->track()->speed();
764                                 }
765                         }
766
767                         rpos = track_frame_to_session_frame (rpos, speed);
768
769                         if (rpos < lpos) {
770                                 lpos = rpos;
771                         }
772
773                         /* prevent duplicates, but we don't use set<> because we want to be able
774                            to sort later.
775                         */
776
777                         vector<framepos_t>::iterator ri;
778
779                         for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
780                                 if (*ri == rpos) {
781                                         break;
782                                 }
783                         }
784
785                         if (ri == region_boundary_cache.end()) {
786                                 region_boundary_cache.push_back (rpos);
787                         }
788                 }
789
790                 pos = lpos + 1;
791         }
792
793         /* finally sort to be sure that the order is correct */
794
795         sort (region_boundary_cache.begin(), region_boundary_cache.end());
796 }
797
798 boost::shared_ptr<Region>
799 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
800 {
801         TrackViewList::iterator i;
802         framepos_t closest = max_framepos;
803         boost::shared_ptr<Region> ret;
804         framepos_t rpos = 0;
805
806         float track_speed;
807         framepos_t track_frame;
808         RouteTimeAxisView *rtav;
809
810         for (i = tracks.begin(); i != tracks.end(); ++i) {
811
812                 framecnt_t distance;
813                 boost::shared_ptr<Region> r;
814
815                 track_speed = 1.0f;
816                 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
817                         if (rtav->track()!=0)
818                                 track_speed = rtav->track()->speed();
819                 }
820
821                 track_frame = session_frame_to_track_frame(frame, track_speed);
822
823                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
824                         continue;
825                 }
826
827                 switch (point) {
828                 case Start:
829                         rpos = r->first_frame ();
830                         break;
831
832                 case End:
833                         rpos = r->last_frame ();
834                         break;
835
836                 case SyncPoint:
837                         rpos = r->sync_position ();
838                         break;
839                 }
840
841                 // rpos is a "track frame", converting it to "_session frame"
842                 rpos = track_frame_to_session_frame(rpos, track_speed);
843
844                 if (rpos > frame) {
845                         distance = rpos - frame;
846                 } else {
847                         distance = frame - rpos;
848                 }
849
850                 if (distance < closest) {
851                         closest = distance;
852                         if (ontrack != 0)
853                                 *ontrack = (*i);
854                         ret = r;
855                 }
856         }
857
858         return ret;
859 }
860
861 framepos_t
862 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
863 {
864         framecnt_t distance = max_framepos;
865         framepos_t current_nearest = -1;
866
867         for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
868                 framepos_t contender;
869                 framecnt_t d;
870
871                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
872
873                 if (!rtv) {
874                         continue;
875                 }
876
877                 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
878                         continue;
879                 }
880
881                 d = ::llabs (pos - contender);
882
883                 if (d < distance) {
884                         current_nearest = contender;
885                         distance = d;
886                 }
887         }
888
889         return current_nearest;
890 }
891
892 framepos_t
893 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
894 {
895         framepos_t target;
896         TrackViewList tvl;
897
898         if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
899
900                 if (!selection->tracks.empty()) {
901
902                         target = find_next_region_boundary (pos, dir, selection->tracks);
903
904                 } else {
905
906                         if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
907                                 get_onscreen_tracks (tvl);
908                                 target = find_next_region_boundary (pos, dir, tvl);
909                         } else {
910                                 target = find_next_region_boundary (pos, dir, track_views);
911                         }
912                 }
913
914         } else {
915
916                 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
917                         get_onscreen_tracks (tvl);
918                         target = find_next_region_boundary (pos, dir, tvl);
919                 } else {
920                         target = find_next_region_boundary (pos, dir, track_views);
921                 }
922         }
923
924         return target;
925 }
926
927 void
928 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
929 {
930         framepos_t pos = playhead_cursor->current_frame ();
931         framepos_t target;
932
933         if (!_session) {
934                 return;
935         }
936
937         // so we don't find the current region again..
938         if (dir > 0 || pos > 0) {
939                 pos += dir;
940         }
941
942         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
943                 return;
944         }
945
946         _session->request_locate (target);
947 }
948
949 void
950 Editor::cursor_to_next_region_boundary (bool with_selection)
951 {
952         cursor_to_region_boundary (with_selection, 1);
953 }
954
955 void
956 Editor::cursor_to_previous_region_boundary (bool with_selection)
957 {
958         cursor_to_region_boundary (with_selection, -1);
959 }
960
961 void
962 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
963 {
964         boost::shared_ptr<Region> r;
965         framepos_t pos = cursor->current_frame ();
966
967         if (!_session) {
968                 return;
969         }
970
971         TimeAxisView *ontrack = 0;
972
973         // so we don't find the current region again..
974         if (dir>0 || pos>0)
975                 pos+=dir;
976
977         if (!selection->tracks.empty()) {
978
979                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
980
981         } else if (clicked_axisview) {
982
983                 TrackViewList t;
984                 t.push_back (clicked_axisview);
985
986                 r = find_next_region (pos, point, dir, t, &ontrack);
987
988         } else {
989
990                 r = find_next_region (pos, point, dir, track_views, &ontrack);
991         }
992
993         if (r == 0) {
994                 return;
995         }
996
997         switch (point) {
998         case Start:
999                 pos = r->first_frame ();
1000                 break;
1001
1002         case End:
1003                 pos = r->last_frame ();
1004                 break;
1005
1006         case SyncPoint:
1007                 pos = r->sync_position ();
1008                 break;
1009         }
1010
1011         float speed = 1.0f;
1012         RouteTimeAxisView *rtav;
1013
1014         if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
1015                 if (rtav->track() != 0) {
1016                         speed = rtav->track()->speed();
1017                 }
1018         }
1019
1020         pos = track_frame_to_session_frame(pos, speed);
1021
1022         if (cursor == playhead_cursor) {
1023                 _session->request_locate (pos);
1024         } else {
1025                 cursor->set_position (pos);
1026         }
1027 }
1028
1029 void
1030 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1031 {
1032         cursor_to_region_point (cursor, point, 1);
1033 }
1034
1035 void
1036 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1037 {
1038         cursor_to_region_point (cursor, point, -1);
1039 }
1040
1041 void
1042 Editor::cursor_to_selection_start (EditorCursor *cursor)
1043 {
1044         framepos_t pos = 0;
1045
1046         switch (mouse_mode) {
1047         case MouseObject:
1048                 if (!selection->regions.empty()) {
1049                         pos = selection->regions.start();
1050                 }
1051                 break;
1052
1053         case MouseRange:
1054                 if (!selection->time.empty()) {
1055                         pos = selection->time.start ();
1056                 }
1057                 break;
1058
1059         default:
1060                 return;
1061         }
1062
1063         if (cursor == playhead_cursor) {
1064                 _session->request_locate (pos);
1065         } else {
1066                 cursor->set_position (pos);
1067         }
1068 }
1069
1070 void
1071 Editor::cursor_to_selection_end (EditorCursor *cursor)
1072 {
1073         framepos_t pos = 0;
1074
1075         switch (mouse_mode) {
1076         case MouseObject:
1077                 if (!selection->regions.empty()) {
1078                         pos = selection->regions.end_frame();
1079                 }
1080                 break;
1081
1082         case MouseRange:
1083                 if (!selection->time.empty()) {
1084                         pos = selection->time.end_frame ();
1085                 }
1086                 break;
1087
1088         default:
1089                 return;
1090         }
1091
1092         if (cursor == playhead_cursor) {
1093                 _session->request_locate (pos);
1094         } else {
1095                 cursor->set_position (pos);
1096         }
1097 }
1098
1099 void
1100 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1101 {
1102         framepos_t target;
1103         Location* loc;
1104         bool ignored;
1105
1106         if (!_session) {
1107                 return;
1108         }
1109
1110         if (selection->markers.empty()) {
1111                 framepos_t mouse;
1112                 bool ignored;
1113
1114                 if (!mouse_frame (mouse, ignored)) {
1115                         return;
1116                 }
1117
1118                 add_location_mark (mouse);
1119         }
1120
1121         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1122                 return;
1123         }
1124
1125         framepos_t pos = loc->start();
1126
1127         // so we don't find the current region again..
1128         if (dir > 0 || pos > 0) {
1129                 pos += dir;
1130         }
1131
1132         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1133                 return;
1134         }
1135
1136         loc->move_to (target);
1137 }
1138
1139 void
1140 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1141 {
1142         selected_marker_to_region_boundary (with_selection, 1);
1143 }
1144
1145 void
1146 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1147 {
1148         selected_marker_to_region_boundary (with_selection, -1);
1149 }
1150
1151 void
1152 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1153 {
1154         boost::shared_ptr<Region> r;
1155         framepos_t pos;
1156         Location* loc;
1157         bool ignored;
1158
1159         if (!_session || selection->markers.empty()) {
1160                 return;
1161         }
1162
1163         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1164                 return;
1165         }
1166
1167         TimeAxisView *ontrack = 0;
1168
1169         pos = loc->start();
1170
1171         // so we don't find the current region again..
1172         if (dir>0 || pos>0)
1173                 pos+=dir;
1174
1175         if (!selection->tracks.empty()) {
1176
1177                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1178
1179         } else {
1180
1181                 r = find_next_region (pos, point, dir, track_views, &ontrack);
1182         }
1183
1184         if (r == 0) {
1185                 return;
1186         }
1187
1188         switch (point) {
1189         case Start:
1190                 pos = r->first_frame ();
1191                 break;
1192
1193         case End:
1194                 pos = r->last_frame ();
1195                 break;
1196
1197         case SyncPoint:
1198                 pos = r->adjust_to_sync (r->first_frame());
1199                 break;
1200         }
1201
1202         float speed = 1.0f;
1203         RouteTimeAxisView *rtav;
1204
1205         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1206                 if (rtav->track() != 0) {
1207                         speed = rtav->track()->speed();
1208                 }
1209         }
1210
1211         pos = track_frame_to_session_frame(pos, speed);
1212
1213         loc->move_to (pos);
1214 }
1215
1216 void
1217 Editor::selected_marker_to_next_region_point (RegionPoint point)
1218 {
1219         selected_marker_to_region_point (point, 1);
1220 }
1221
1222 void
1223 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1224 {
1225         selected_marker_to_region_point (point, -1);
1226 }
1227
1228 void
1229 Editor::selected_marker_to_selection_start ()
1230 {
1231         framepos_t pos = 0;
1232         Location* loc;
1233         bool ignored;
1234
1235         if (!_session || selection->markers.empty()) {
1236                 return;
1237         }
1238
1239         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1240                 return;
1241         }
1242
1243         switch (mouse_mode) {
1244         case MouseObject:
1245                 if (!selection->regions.empty()) {
1246                         pos = selection->regions.start();
1247                 }
1248                 break;
1249
1250         case MouseRange:
1251                 if (!selection->time.empty()) {
1252                         pos = selection->time.start ();
1253                 }
1254                 break;
1255
1256         default:
1257                 return;
1258         }
1259
1260         loc->move_to (pos);
1261 }
1262
1263 void
1264 Editor::selected_marker_to_selection_end ()
1265 {
1266         framepos_t pos = 0;
1267         Location* loc;
1268         bool ignored;
1269
1270         if (!_session || selection->markers.empty()) {
1271                 return;
1272         }
1273
1274         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1275                 return;
1276         }
1277
1278         switch (mouse_mode) {
1279         case MouseObject:
1280                 if (!selection->regions.empty()) {
1281                         pos = selection->regions.end_frame();
1282                 }
1283                 break;
1284
1285         case MouseRange:
1286                 if (!selection->time.empty()) {
1287                         pos = selection->time.end_frame ();
1288                 }
1289                 break;
1290
1291         default:
1292                 return;
1293         }
1294
1295         loc->move_to (pos);
1296 }
1297
1298 void
1299 Editor::scroll_playhead (bool forward)
1300 {
1301         framepos_t pos = playhead_cursor->current_frame ();
1302         framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1303
1304         if (forward) {
1305                 if (pos == max_framepos) {
1306                         return;
1307                 }
1308
1309                 if (pos < max_framepos - delta) {
1310                         pos += delta ;
1311                 } else {
1312                         pos = max_framepos;
1313                 }
1314
1315         } else {
1316
1317                 if (pos == 0) {
1318                         return;
1319                 }
1320
1321                 if (pos > delta) {
1322                         pos -= delta;
1323                 } else {
1324                         pos = 0;
1325                 }
1326         }
1327
1328         _session->request_locate (pos);
1329 }
1330
1331 void
1332 Editor::cursor_align (bool playhead_to_edit)
1333 {
1334         if (!_session) {
1335                 return;
1336         }
1337
1338         if (playhead_to_edit) {
1339
1340                 if (selection->markers.empty()) {
1341                         return;
1342                 }
1343
1344                 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1345
1346         } else {
1347                 /* move selected markers to playhead */
1348
1349                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1350                         bool ignored;
1351
1352                         Location* loc = find_location_from_marker (*i, ignored);
1353
1354                         if (loc->is_mark()) {
1355                                 loc->set_start (playhead_cursor->current_frame ());
1356                         } else {
1357                                 loc->set (playhead_cursor->current_frame (),
1358                                           playhead_cursor->current_frame () + loc->length());
1359                         }
1360                 }
1361         }
1362 }
1363
1364 void
1365 Editor::scroll_backward (float pages)
1366 {
1367         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1368         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1369
1370         framepos_t frame;
1371         if (leftmost_frame < cnt) {
1372                 frame = 0;
1373         } else {
1374                 frame = leftmost_frame - cnt;
1375         }
1376
1377         reset_x_origin (frame);
1378 }
1379
1380 void
1381 Editor::scroll_forward (float pages)
1382 {
1383         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1384         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1385
1386         framepos_t frame;
1387         if (max_framepos - cnt < leftmost_frame) {
1388                 frame = max_framepos - cnt;
1389         } else {
1390                 frame = leftmost_frame + cnt;
1391         }
1392
1393         reset_x_origin (frame);
1394 }
1395
1396 void
1397 Editor::scroll_tracks_down ()
1398 {
1399         double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1400         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1402         }
1403
1404         vertical_adjustment.set_value (vert_value);
1405 }
1406
1407 void
1408 Editor::scroll_tracks_up ()
1409 {
1410         vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1411 }
1412
1413 void
1414 Editor::scroll_tracks_down_line ()
1415 {
1416         double vert_value = vertical_adjustment.get_value() + 60;
1417
1418         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1419                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1420         }
1421
1422         vertical_adjustment.set_value (vert_value);
1423 }
1424
1425 void
1426 Editor::scroll_tracks_up_line ()
1427 {
1428         reset_y_origin (vertical_adjustment.get_value() - 60);
1429 }
1430
1431 bool
1432 Editor::scroll_down_one_track (bool skip_child_views)
1433 {
1434         TrackViewList::reverse_iterator next = track_views.rend();
1435         const double top_of_trackviews = vertical_adjustment.get_value();
1436
1437         for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1438                 if ((*t)->hidden()) {
1439                         continue;
1440                 }
1441
1442                 /* If this is the upper-most visible trackview, we want to display
1443                  * the one above it (next)
1444                  *
1445                  * Note that covers_y_position() is recursive and includes child views
1446                  */
1447                 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1448
1449                 if (res.first) {
1450                         if (skip_child_views) {
1451                                 break;
1452                         }
1453                         /* automation lane (one level, non-recursive)
1454                          *
1455                          * - if no automation lane exists -> move to next tack
1456                          * - if the first (here: bottom-most) matches -> move to next tack
1457                          * - if no y-axis match is found -> the current track is at the top
1458                          *     -> move to last (here: top-most) automation lane
1459                          */
1460                         TimeAxisView::Children kids = (*t)->get_child_list();
1461                         TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1462
1463                         for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1464                                 if ((*ci)->hidden()) {
1465                                         continue;
1466                                 }
1467
1468                                 std::pair<TimeAxisView*,double> dev;
1469                                 dev = (*ci)->covers_y_position (top_of_trackviews);
1470                                 if (dev.first) {
1471                                         /* some automation lane is currently at the top */
1472                                         if (ci == kids.rbegin()) {
1473                                                 /* first (bottom-most) autmation lane is at the top.
1474                                                  * -> move to next track
1475                                                  */
1476                                                 nkid = kids.rend();
1477                                         }
1478                                         break;
1479                                 }
1480                                 nkid = ci;
1481                         }
1482
1483                         if (nkid != kids.rend()) {
1484                                 ensure_time_axis_view_is_visible (**nkid, true);
1485                                 return true;
1486                         }
1487                         break;
1488                 }
1489                 next = t;
1490         }
1491
1492         /* move to the track below the first one that covers the */
1493
1494         if (next != track_views.rend()) {
1495                 ensure_time_axis_view_is_visible (**next, true);
1496                 return true;
1497         }
1498
1499         return false;
1500 }
1501
1502 bool
1503 Editor::scroll_up_one_track (bool skip_child_views)
1504 {
1505         TrackViewList::iterator prev = track_views.end();
1506         double top_of_trackviews = vertical_adjustment.get_value ();
1507
1508         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1509
1510                 if ((*t)->hidden()) {
1511                         continue;
1512                 }
1513
1514                 /* find the trackview at the top of the trackview group
1515                  *
1516                  * Note that covers_y_position() is recursive and includes child views
1517                  */
1518                 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1519
1520                 if (res.first) {
1521                         if (skip_child_views) {
1522                                 break;
1523                         }
1524                         /* automation lane (one level, non-recursive)
1525                          *
1526                          * - if no automation lane exists -> move to prev tack
1527                          * - if no y-axis match is found -> the current track is at the top -> move to prev track
1528                          *     (actually last automation lane of previous track, see below)
1529                          * - if first (top-most) lane is at the top -> move to this track
1530                          * - else move up one lane
1531                          */
1532                         TimeAxisView::Children kids = (*t)->get_child_list();
1533                         TimeAxisView::Children::iterator pkid = kids.end();
1534
1535                         for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1536                                 if ((*ci)->hidden()) {
1537                                         continue;
1538                                 }
1539
1540                                 std::pair<TimeAxisView*,double> dev;
1541                                 dev = (*ci)->covers_y_position (top_of_trackviews);
1542                                 if (dev.first) {
1543                                         /* some automation lane is currently at the top */
1544                                         if (ci == kids.begin()) {
1545                                                 /* first (top-most) autmation lane is at the top.
1546                                                  * jump directly to this track's top
1547                                                  */
1548                                                 ensure_time_axis_view_is_visible (**t, true);
1549                                                 return true;
1550                                         }
1551                                         else if (pkid != kids.end()) {
1552                                                 /* some other automation lane is at the top.
1553                                                  * move up to prev automation lane.
1554                                                  */
1555                                                 ensure_time_axis_view_is_visible (**pkid, true);
1556                                                 return true;
1557                                         }
1558                                         assert(0); // not reached
1559                                         break;
1560                                 }
1561                                 pkid = ci;
1562                         }
1563                         break;
1564                 }
1565
1566                 prev = t;
1567         }
1568
1569         if (prev != track_views.end()) {
1570                 // move to bottom-most automation-lane of the previous track
1571                 TimeAxisView::Children kids = (*prev)->get_child_list();
1572                 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1573                 if (!skip_child_views) {
1574                         // find the last visible lane
1575                         for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1576                                 if (!(*ci)->hidden()) {
1577                                         pkid = ci;
1578                                         break;
1579                                 }
1580                         }
1581                 }
1582                 if (pkid != kids.rend()) {
1583                         ensure_time_axis_view_is_visible (**pkid, true);
1584                 } else  {
1585                         ensure_time_axis_view_is_visible (**prev, true);
1586                 }
1587                 return true;
1588         }
1589
1590         return false;
1591 }
1592
1593 void
1594 Editor::scroll_left_step ()
1595 {
1596         framepos_t xdelta = (current_page_samples() / 8);
1597
1598         if (leftmost_frame > xdelta) {
1599                 reset_x_origin (leftmost_frame - xdelta);
1600         } else {
1601                 reset_x_origin (0);
1602         }
1603 }
1604
1605
1606 void
1607 Editor::scroll_right_step ()
1608 {
1609         framepos_t xdelta = (current_page_samples() / 8);
1610
1611         if (max_framepos - xdelta > leftmost_frame) {
1612                 reset_x_origin (leftmost_frame + xdelta);
1613         } else {
1614                 reset_x_origin (max_framepos - current_page_samples());
1615         }
1616 }
1617
1618 void
1619 Editor::scroll_left_half_page ()
1620 {
1621         framepos_t xdelta = (current_page_samples() / 2);
1622         if (leftmost_frame > xdelta) {
1623                 reset_x_origin (leftmost_frame - xdelta);
1624         } else {
1625                 reset_x_origin (0);
1626         }
1627 }
1628
1629 void
1630 Editor::scroll_right_half_page ()
1631 {
1632         framepos_t xdelta = (current_page_samples() / 2);
1633         if (max_framepos - xdelta > leftmost_frame) {
1634                 reset_x_origin (leftmost_frame + xdelta);
1635         } else {
1636                 reset_x_origin (max_framepos - current_page_samples());
1637         }
1638 }
1639
1640 /* ZOOM */
1641
1642 void
1643 Editor::tav_zoom_step (bool coarser)
1644 {
1645         DisplaySuspender ds;
1646
1647         TrackViewList* ts;
1648
1649         if (selection->tracks.empty()) {
1650                 ts = &track_views;
1651         } else {
1652                 ts = &selection->tracks;
1653         }
1654
1655         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1656                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1657                         tv->step_height (coarser);
1658         }
1659 }
1660
1661 void
1662 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1663 {
1664         DisplaySuspender ds;
1665
1666         TrackViewList* ts;
1667
1668         if (selection->tracks.empty() || force_all) {
1669                 ts = &track_views;
1670         } else {
1671                 ts = &selection->tracks;
1672         }
1673
1674         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1675                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1676                 uint32_t h = tv->current_height ();
1677
1678                 if (coarser) {
1679                         if (h > 5) {
1680                                 h -= 5; // pixels
1681                                 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1682                                         tv->set_height (h);
1683                                 }
1684                         }
1685                 } else {
1686                         tv->set_height (h + 5);
1687                 }
1688         }
1689 }
1690
1691 void
1692 Editor::temporal_zoom_step_mouse_focus (bool coarser)
1693 {
1694         Editing::ZoomFocus temp_focus = zoom_focus;
1695         zoom_focus = Editing::ZoomFocusMouse;
1696         temporal_zoom_step (coarser);
1697         zoom_focus = temp_focus;
1698 }
1699
1700 void
1701 Editor::temporal_zoom_step (bool coarser)
1702 {
1703         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1704
1705         framecnt_t nspp = samples_per_pixel;
1706
1707         if (coarser) {
1708                 nspp *= 2;
1709         } else {
1710                 nspp /= 2;
1711         }
1712
1713         temporal_zoom (nspp);
1714 }
1715
1716 void
1717 Editor::temporal_zoom (framecnt_t fpp)
1718 {
1719         if (!_session) {
1720                 return;
1721         }
1722
1723         framepos_t current_page = current_page_samples();
1724         framepos_t current_leftmost = leftmost_frame;
1725         framepos_t current_rightmost;
1726         framepos_t current_center;
1727         framepos_t new_page_size;
1728         framepos_t half_page_size;
1729         framepos_t leftmost_after_zoom = 0;
1730         framepos_t where;
1731         bool in_track_canvas;
1732         framecnt_t nfpp;
1733         double l;
1734
1735         if (fpp == samples_per_pixel) {
1736                 return;
1737         }
1738
1739         // Imposing an arbitrary limit to zoom out as too much zoom out produces
1740         // segfaults for lack of memory. If somebody decides this is not high enough I
1741         // believe it can be raisen to higher values but some limit must be in place.
1742         //
1743         // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1744         // all of which is used for the editor track displays. The whole day
1745         // would be 4147200000 samples, so 2592000 samples per pixel.
1746
1747         nfpp = min (fpp, (framecnt_t) 2592000);
1748         nfpp = max ((framecnt_t) 1, nfpp);
1749
1750         new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1751         half_page_size = new_page_size / 2;
1752
1753         switch (zoom_focus) {
1754         case ZoomFocusLeft:
1755                 leftmost_after_zoom = current_leftmost;
1756                 break;
1757
1758         case ZoomFocusRight:
1759                 current_rightmost = leftmost_frame + current_page;
1760                 if (current_rightmost < new_page_size) {
1761                         leftmost_after_zoom = 0;
1762                 } else {
1763                         leftmost_after_zoom = current_rightmost - new_page_size;
1764                 }
1765                 break;
1766
1767         case ZoomFocusCenter:
1768                 current_center = current_leftmost + (current_page/2);
1769                 if (current_center < half_page_size) {
1770                         leftmost_after_zoom = 0;
1771                 } else {
1772                         leftmost_after_zoom = current_center - half_page_size;
1773                 }
1774                 break;
1775
1776         case ZoomFocusPlayhead:
1777                 /* centre playhead */
1778                 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1779
1780                 if (l < 0) {
1781                         leftmost_after_zoom = 0;
1782                 } else if (l > max_framepos) {
1783                         leftmost_after_zoom = max_framepos - new_page_size;
1784                 } else {
1785                         leftmost_after_zoom = (framepos_t) l;
1786                 }
1787                 break;
1788
1789         case ZoomFocusMouse:
1790                 /* try to keep the mouse over the same point in the display */
1791
1792                 if (!mouse_frame (where, in_track_canvas)) {
1793                         /* use playhead instead */
1794                         where = playhead_cursor->current_frame ();
1795
1796                         if (where < half_page_size) {
1797                                 leftmost_after_zoom = 0;
1798                         } else {
1799                                 leftmost_after_zoom = where - half_page_size;
1800                         }
1801
1802                 } else {
1803
1804                         l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1805
1806                         if (l < 0) {
1807                                 leftmost_after_zoom = 0;
1808                         } else if (l > max_framepos) {
1809                                 leftmost_after_zoom = max_framepos - new_page_size;
1810                         } else {
1811                                 leftmost_after_zoom = (framepos_t) l;
1812                         }
1813                 }
1814
1815                 break;
1816
1817         case ZoomFocusEdit:
1818                 /* try to keep the edit point in the same place */
1819                 where = get_preferred_edit_position ();
1820
1821                 if (where > 0) {
1822
1823                         double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1824
1825                         if (l < 0) {
1826                                 leftmost_after_zoom = 0;
1827                         } else if (l > max_framepos) {
1828                                 leftmost_after_zoom = max_framepos - new_page_size;
1829                         } else {
1830                                 leftmost_after_zoom = (framepos_t) l;
1831                         }
1832
1833                 } else {
1834                         /* edit point not defined */
1835                         return;
1836                 }
1837                 break;
1838
1839         }
1840
1841         // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1842
1843         reposition_and_zoom (leftmost_after_zoom, nfpp);
1844 }
1845
1846 void
1847 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1848 {
1849         /* this func helps make sure we leave a little space
1850            at each end of the editor so that the zoom doesn't fit the region
1851            precisely to the screen.
1852         */
1853
1854         GdkScreen* screen = gdk_screen_get_default ();
1855         const gint pixwidth = gdk_screen_get_width (screen);
1856         const gint mmwidth = gdk_screen_get_width_mm (screen);
1857         const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1858         const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1859
1860         const framepos_t range = end - start;
1861         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1862         const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1863
1864         if (start > extra_samples) {
1865                 start -= extra_samples;
1866         } else {
1867                 start = 0;
1868         }
1869
1870         if (max_framepos - extra_samples > end) {
1871                 end += extra_samples;
1872         } else {
1873                 end = max_framepos;
1874         }
1875 }
1876
1877 void
1878 Editor::temporal_zoom_region (bool both_axes)
1879 {
1880         framepos_t start = max_framepos;
1881         framepos_t end = 0;
1882         set<TimeAxisView*> tracks;
1883
1884         if ( !get_selection_extents(start, end) )
1885                 return;
1886
1887         calc_extra_zoom_edges (start, end);
1888
1889         /* if we're zooming on both axes we need to save track heights etc.
1890          */
1891
1892         undo_visual_stack.push_back (current_visual_state (both_axes));
1893
1894         PBD::Unwinder<bool> nsv (no_save_visual, true);
1895
1896         temporal_zoom_by_frame (start, end);
1897
1898         if (both_axes) {
1899                 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1900
1901                 /* set visible track heights appropriately */
1902
1903                 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1904                         (*t)->set_height (per_track_height);
1905                 }
1906
1907                 /* hide irrelevant tracks */
1908
1909                 DisplaySuspender ds;
1910
1911                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1912                         if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1913                                 hide_track_in_display (*i);
1914                         }
1915                 }
1916
1917                 vertical_adjustment.set_value (0.0);
1918         }
1919
1920         redo_visual_stack.push_back (current_visual_state (both_axes));
1921 }
1922
1923
1924 bool
1925 Editor::get_selection_extents (framepos_t &start, framepos_t &end) const
1926 {
1927         start = max_framepos;
1928         end = 0;
1929         bool ret = true;
1930
1931         //ToDo:  if notes are selected, set extents to that selection
1932
1933         //ToDo:  if control points are selected, set extents to that selection
1934
1935         if ( !selection->regions.empty() ) {
1936                 RegionSelection rs = get_regions_from_selection_and_entered ();
1937
1938                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1939
1940                         if ((*i)->region()->position() < start) {
1941                                 start = (*i)->region()->position();
1942                         }
1943
1944                         if ((*i)->region()->last_frame() + 1 > end) {
1945                                 end = (*i)->region()->last_frame() + 1;
1946                         }
1947                 }
1948
1949         } else if (!selection->time.empty()) {
1950                 start = selection->time.start();
1951                 end = selection->time.end_frame();
1952         } else
1953                 ret = false;  //no selection found
1954
1955         //range check
1956         if ((start == 0 && end == 0) || end < start) {
1957                 ret = false;
1958         }
1959
1960         return ret;
1961 }
1962
1963
1964 void
1965 Editor::temporal_zoom_selection (bool both_axes)
1966 {
1967         if (!selection) return;
1968
1969         //ToDo:  if notes are selected, zoom to that
1970
1971         //ToDo:  if control points are selected, zoom to that
1972
1973         //if region(s) are selected, zoom to that
1974         if ( !selection->regions.empty() )
1975                 temporal_zoom_region (both_axes);
1976
1977         //if a range is selected, zoom to that
1978         if (!selection->time.empty()) {
1979
1980                 framepos_t start,  end;
1981                 if (get_selection_extents (start, end)) {
1982                         calc_extra_zoom_edges(start, end);
1983                         temporal_zoom_by_frame (start, end);
1984                 }
1985
1986                 if (both_axes)
1987                         fit_selection();
1988         }
1989
1990 }
1991
1992 void
1993 Editor::temporal_zoom_session ()
1994 {
1995         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1996
1997         if (_session) {
1998                 framecnt_t start = _session->current_start_frame();
1999                 framecnt_t end = _session->current_end_frame();
2000
2001                 if (_session->actively_recording () ) {
2002                         framepos_t cur = playhead_cursor->current_frame ();
2003                         if (cur > end) {
2004                                 /* recording beyond the end marker; zoom out
2005                                  * by 5 seconds more so that if 'follow
2006                                  * playhead' is active we don't immediately
2007                                  * scroll.
2008                                  */
2009                                 end = cur + _session->frame_rate() * 5;
2010                         }
2011                 }
2012
2013                 if ((start == 0 && end == 0) || end < start) {
2014                         return;
2015                 }
2016
2017                 calc_extra_zoom_edges(start, end);
2018
2019                 temporal_zoom_by_frame (start, end);
2020         }
2021 }
2022
2023 void
2024 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
2025 {
2026         if (!_session) return;
2027
2028         if ((start == 0 && end == 0) || end < start) {
2029                 return;
2030         }
2031
2032         framepos_t range = end - start;
2033
2034         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
2035
2036         framepos_t new_page = range;
2037         framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
2038         framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
2039
2040         if (new_leftmost > middle) {
2041                 new_leftmost = 0;
2042         }
2043
2044         if (new_leftmost < 0) {
2045                 new_leftmost = 0;
2046         }
2047
2048         reposition_and_zoom (new_leftmost, new_fpp);
2049 }
2050
2051 void
2052 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
2053 {
2054         if (!_session) {
2055                 return;
2056         }
2057
2058         framecnt_t range_before = frame - leftmost_frame;
2059         framecnt_t new_spp;
2060
2061         if (coarser) {
2062                 if (samples_per_pixel <= 1) {
2063                         new_spp = 2;
2064                 } else {
2065                         new_spp = samples_per_pixel + (samples_per_pixel/2);
2066                 }
2067                 range_before += range_before/2;
2068         } else {
2069                 if (samples_per_pixel >= 1) {
2070                         new_spp = samples_per_pixel - (samples_per_pixel/2);
2071                 } else {
2072                         /* could bail out here since we cannot zoom any finer,
2073                            but leave that to the equality test below
2074                         */
2075                         new_spp = samples_per_pixel;
2076                 }
2077
2078                 range_before -= range_before/2;
2079         }
2080
2081         if (new_spp == samples_per_pixel)  {
2082                 return;
2083         }
2084
2085         /* zoom focus is automatically taken as @param frame when this
2086            method is used.
2087         */
2088
2089         framepos_t new_leftmost = frame - (framepos_t)range_before;
2090
2091         if (new_leftmost > frame) {
2092                 new_leftmost = 0;
2093         }
2094
2095         if (new_leftmost < 0) {
2096                 new_leftmost = 0;
2097         }
2098
2099         reposition_and_zoom (new_leftmost, new_spp);
2100 }
2101
2102
2103 bool
2104 Editor::choose_new_marker_name(string &name) {
2105
2106         if (!UIConfiguration::instance().get_name_new_markers()) {
2107                 /* don't prompt user for a new name */
2108                 return true;
2109         }
2110
2111         ArdourPrompter dialog (true);
2112
2113         dialog.set_prompt (_("New Name:"));
2114
2115         dialog.set_title (_("New Location Marker"));
2116
2117         dialog.set_name ("MarkNameWindow");
2118         dialog.set_size_request (250, -1);
2119         dialog.set_position (Gtk::WIN_POS_MOUSE);
2120
2121         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2122         dialog.set_initial_text (name);
2123
2124         dialog.show ();
2125
2126         switch (dialog.run ()) {
2127         case RESPONSE_ACCEPT:
2128                 break;
2129         default:
2130                 return false;
2131         }
2132
2133         dialog.get_result(name);
2134         return true;
2135
2136 }
2137
2138
2139 void
2140 Editor::add_location_from_selection ()
2141 {
2142         string rangename;
2143
2144         if (selection->time.empty()) {
2145                 return;
2146         }
2147
2148         if (_session == 0 || clicked_axisview == 0) {
2149                 return;
2150         }
2151
2152         framepos_t start = selection->time[clicked_selection].start;
2153         framepos_t end = selection->time[clicked_selection].end;
2154
2155         _session->locations()->next_available_name(rangename,"selection");
2156         Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2157
2158         begin_reversible_command (_("add marker"));
2159
2160         XMLNode &before = _session->locations()->get_state();
2161         _session->locations()->add (location, true);
2162         XMLNode &after = _session->locations()->get_state();
2163         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2164
2165         commit_reversible_command ();
2166 }
2167
2168 void
2169 Editor::add_location_mark (framepos_t where)
2170 {
2171         string markername;
2172
2173         select_new_marker = true;
2174
2175         _session->locations()->next_available_name(markername,"mark");
2176         if (!choose_new_marker_name(markername)) {
2177                 return;
2178         }
2179         Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2180         begin_reversible_command (_("add marker"));
2181
2182         XMLNode &before = _session->locations()->get_state();
2183         _session->locations()->add (location, true);
2184         XMLNode &after = _session->locations()->get_state();
2185         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2186
2187         commit_reversible_command ();
2188 }
2189
2190 void
2191 Editor::set_session_start_from_playhead ()
2192 {
2193         if (!_session)
2194                 return;
2195
2196         Location* loc;
2197         if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
2198                 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2199         } else {
2200                 XMLNode &before = loc->get_state();
2201
2202                 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2203
2204                 XMLNode &after = loc->get_state();
2205
2206                 begin_reversible_command (_("Set session start"));
2207
2208                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2209
2210                 commit_reversible_command ();
2211         }
2212 }
2213
2214 void
2215 Editor::set_session_end_from_playhead ()
2216 {
2217         if (!_session)
2218                 return;
2219
2220         Location* loc;
2221         if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
2222                 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2223         } else {
2224                 XMLNode &before = loc->get_state();
2225
2226                 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2227
2228                 XMLNode &after = loc->get_state();
2229
2230                 begin_reversible_command (_("Set session start"));
2231
2232                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2233
2234                 commit_reversible_command ();
2235         }
2236 }
2237
2238 void
2239 Editor::add_location_from_playhead_cursor ()
2240 {
2241         add_location_mark (_session->audible_frame());
2242 }
2243
2244 void
2245 Editor::remove_location_at_playhead_cursor ()
2246 {
2247         if (_session) {
2248                 //set up for undo
2249                 XMLNode &before = _session->locations()->get_state();
2250                 bool removed = false;
2251
2252                 //find location(s) at this time
2253                 Locations::LocationList locs;
2254                 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2255                 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2256                         if ((*i)->is_mark()) {
2257                                 _session->locations()->remove (*i);
2258                                 removed = true;
2259                         }
2260                 }
2261
2262                 //store undo
2263                 if (removed) {
2264                         begin_reversible_command (_("remove marker"));
2265                         XMLNode &after = _session->locations()->get_state();
2266                         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2267                         commit_reversible_command ();
2268                 }
2269         }
2270 }
2271
2272 /** Add a range marker around each selected region */
2273 void
2274 Editor::add_locations_from_region ()
2275 {
2276         RegionSelection rs = get_regions_from_selection_and_entered ();
2277
2278         if (rs.empty()) {
2279                 return;
2280         }
2281         bool commit = false;
2282
2283         XMLNode &before = _session->locations()->get_state();
2284
2285         for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2286
2287                 boost::shared_ptr<Region> region = (*i)->region ();
2288
2289                 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2290
2291                 _session->locations()->add (location, true);
2292                 commit = true;
2293         }
2294
2295         if (commit) {
2296                 begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2297                 XMLNode &after = _session->locations()->get_state();
2298                 _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2299                 commit_reversible_command ();
2300         }
2301 }
2302
2303 /** Add a single range marker around all selected regions */
2304 void
2305 Editor::add_location_from_region ()
2306 {
2307         RegionSelection rs = get_regions_from_selection_and_entered ();
2308
2309         if (rs.empty()) {
2310                 return;
2311         }
2312
2313         XMLNode &before = _session->locations()->get_state();
2314
2315         string markername;
2316
2317         if (rs.size() > 1) {
2318                 _session->locations()->next_available_name(markername, "regions");
2319         } else {
2320                 RegionView* rv = *(rs.begin());
2321                 boost::shared_ptr<Region> region = rv->region();
2322                 markername = region->name();
2323         }
2324
2325         if (!choose_new_marker_name(markername)) {
2326                 return;
2327         }
2328
2329         // single range spanning all selected
2330         Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2331         _session->locations()->add (location, true);
2332
2333         begin_reversible_command (_("add marker"));
2334         XMLNode &after = _session->locations()->get_state();
2335         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2336         commit_reversible_command ();
2337 }
2338
2339 /* MARKS */
2340
2341 void
2342 Editor::jump_forward_to_mark ()
2343 {
2344         if (!_session) {
2345                 return;
2346         }
2347
2348         framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2349
2350         if (pos < 0) {
2351                 return;
2352         }
2353
2354         _session->request_locate (pos, _session->transport_rolling());
2355 }
2356
2357 void
2358 Editor::jump_backward_to_mark ()
2359 {
2360         if (!_session) {
2361                 return;
2362         }
2363
2364         framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2365
2366         if (pos < 0) {
2367                 return;
2368         }
2369
2370         _session->request_locate (pos, _session->transport_rolling());
2371 }
2372
2373 void
2374 Editor::set_mark ()
2375 {
2376         framepos_t const pos = _session->audible_frame ();
2377
2378         string markername;
2379         _session->locations()->next_available_name (markername, "mark");
2380
2381         if (!choose_new_marker_name (markername)) {
2382                 return;
2383         }
2384
2385         _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2386 }
2387
2388 void
2389 Editor::clear_markers ()
2390 {
2391         if (_session) {
2392                 begin_reversible_command (_("clear markers"));
2393
2394                 XMLNode &before = _session->locations()->get_state();
2395                 _session->locations()->clear_markers ();
2396                 XMLNode &after = _session->locations()->get_state();
2397                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2398
2399                 commit_reversible_command ();
2400         }
2401 }
2402
2403 void
2404 Editor::clear_ranges ()
2405 {
2406         if (_session) {
2407                 begin_reversible_command (_("clear ranges"));
2408
2409                 XMLNode &before = _session->locations()->get_state();
2410
2411                 _session->locations()->clear_ranges ();
2412
2413                 XMLNode &after = _session->locations()->get_state();
2414                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2415
2416                 commit_reversible_command ();
2417         }
2418 }
2419
2420 void
2421 Editor::clear_locations ()
2422 {
2423         begin_reversible_command (_("clear locations"));
2424
2425         XMLNode &before = _session->locations()->get_state();
2426         _session->locations()->clear ();
2427         XMLNode &after = _session->locations()->get_state();
2428         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2429
2430         commit_reversible_command ();
2431 }
2432
2433 void
2434 Editor::unhide_markers ()
2435 {
2436         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2437                 Location *l = (*i).first;
2438                 if (l->is_hidden() && l->is_mark()) {
2439                         l->set_hidden(false, this);
2440                 }
2441         }
2442 }
2443
2444 void
2445 Editor::unhide_ranges ()
2446 {
2447         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2448                 Location *l = (*i).first;
2449                 if (l->is_hidden() && l->is_range_marker()) {
2450                         l->set_hidden(false, this);
2451                 }
2452         }
2453 }
2454
2455 /* INSERT/REPLACE */
2456
2457 void
2458 Editor::insert_region_list_selection (float times)
2459 {
2460         RouteTimeAxisView *tv = 0;
2461         boost::shared_ptr<Playlist> playlist;
2462
2463         if (clicked_routeview != 0) {
2464                 tv = clicked_routeview;
2465         } else if (!selection->tracks.empty()) {
2466                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2467                         return;
2468                 }
2469         } else if (entered_track != 0) {
2470                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2471                         return;
2472                 }
2473         } else {
2474                 return;
2475         }
2476
2477         if ((playlist = tv->playlist()) == 0) {
2478                 return;
2479         }
2480
2481         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2482         if (region == 0) {
2483                 return;
2484         }
2485
2486         begin_reversible_command (_("insert region"));
2487         playlist->clear_changes ();
2488         playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2489         if (Config->get_edit_mode() == Ripple)
2490                 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2491
2492         _session->add_command(new StatefulDiffCommand (playlist));
2493         commit_reversible_command ();
2494 }
2495
2496 /* BUILT-IN EFFECTS */
2497
2498 void
2499 Editor::reverse_selection ()
2500 {
2501
2502 }
2503
2504 /* GAIN ENVELOPE EDITING */
2505
2506 void
2507 Editor::edit_envelope ()
2508 {
2509 }
2510
2511 /* PLAYBACK */
2512
2513 void
2514 Editor::transition_to_rolling (bool fwd)
2515 {
2516         if (!_session) {
2517                 return;
2518         }
2519
2520         if (_session->config.get_external_sync()) {
2521                 switch (Config->get_sync_source()) {
2522                 case Engine:
2523                         break;
2524                 default:
2525                         /* transport controlled by the master */
2526                         return;
2527                 }
2528         }
2529
2530         if (_session->is_auditioning()) {
2531                 _session->cancel_audition ();
2532                 return;
2533         }
2534
2535         _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2536 }
2537
2538 void
2539 Editor::play_from_start ()
2540 {
2541         _session->request_locate (_session->current_start_frame(), true);
2542 }
2543
2544 void
2545 Editor::play_from_edit_point ()
2546 {
2547         _session->request_locate (get_preferred_edit_position(), true);
2548 }
2549
2550 void
2551 Editor::play_from_edit_point_and_return ()
2552 {
2553         framepos_t start_frame;
2554         framepos_t return_frame;
2555
2556         start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2557
2558         if (_session->transport_rolling()) {
2559                 _session->request_locate (start_frame, false);
2560                 return;
2561         }
2562
2563         /* don't reset the return frame if its already set */
2564
2565         if ((return_frame = _session->requested_return_frame()) < 0) {
2566                 return_frame = _session->audible_frame();
2567         }
2568
2569         if (start_frame >= 0) {
2570                 _session->request_roll_at_and_return (start_frame, return_frame);
2571         }
2572 }
2573
2574 void
2575 Editor::play_selection ()
2576 {
2577         framepos_t start, end;
2578         if (!get_selection_extents ( start, end))
2579                 return;
2580
2581         AudioRange ar (start, end, 0);
2582         list<AudioRange> lar;
2583         lar.push_back (ar);
2584
2585         _session->request_play_range (&lar, true);
2586 }
2587
2588 framepos_t
2589 Editor::get_preroll ()
2590 {
2591         return Config->get_preroll_seconds() * _session->frame_rate();
2592 }
2593
2594
2595 void
2596 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2597 {
2598         if ( _session->transport_rolling() || !UIConfiguration::instance().get_follow_edits() || _ignore_follow_edits || _session->config.get_external_sync() )
2599                 return;
2600
2601         location -= get_preroll();
2602
2603         //don't try to locate before the beginning of time
2604         if ( location < 0 )
2605                 location = 0;
2606
2607         //if follow_playhead is on, keep the playhead on the screen
2608         if ( _follow_playhead )
2609                 if ( location < leftmost_frame )
2610                         location = leftmost_frame;
2611
2612         _session->request_locate( location );
2613 }
2614
2615 void
2616 Editor::play_with_preroll ()
2617 {
2618         {
2619                 framepos_t preroll = get_preroll();
2620
2621                 framepos_t start, end;
2622                 if (!get_selection_extents ( start, end))
2623                         return;
2624
2625                 if (start > preroll)
2626                         start = start - preroll;
2627
2628                 end = end + preroll;  //"post-roll"
2629
2630                 AudioRange ar (start, end, 0);
2631                 list<AudioRange> lar;
2632                 lar.push_back (ar);
2633
2634                 _session->request_play_range (&lar, true);
2635         }
2636 }
2637
2638 void
2639 Editor::play_location (Location& location)
2640 {
2641         if (location.start() <= location.end()) {
2642                 return;
2643         }
2644
2645         _session->request_bounded_roll (location.start(), location.end());
2646 }
2647
2648 void
2649 Editor::loop_location (Location& location)
2650 {
2651         if (location.start() <= location.end()) {
2652                 return;
2653         }
2654
2655         Location* tll;
2656
2657         if ((tll = transport_loop_location()) != 0) {
2658                 tll->set (location.start(), location.end());
2659
2660                 // enable looping, reposition and start rolling
2661                 _session->request_locate (tll->start(), true);
2662                 _session->request_play_loop (true);
2663         }
2664 }
2665
2666 void
2667 Editor::do_layer_operation (LayerOperation op)
2668 {
2669         if (selection->regions.empty ()) {
2670                 return;
2671         }
2672
2673         bool const multiple = selection->regions.size() > 1;
2674         switch (op) {
2675         case Raise:
2676                 if (multiple) {
2677                         begin_reversible_command (_("raise regions"));
2678                 } else {
2679                         begin_reversible_command (_("raise region"));
2680                 }
2681                 break;
2682
2683         case RaiseToTop:
2684                 if (multiple) {
2685                         begin_reversible_command (_("raise regions to top"));
2686                 } else {
2687                         begin_reversible_command (_("raise region to top"));
2688                 }
2689                 break;
2690
2691         case Lower:
2692                 if (multiple) {
2693                         begin_reversible_command (_("lower regions"));
2694                 } else {
2695                         begin_reversible_command (_("lower region"));
2696                 }
2697                 break;
2698
2699         case LowerToBottom:
2700                 if (multiple) {
2701                         begin_reversible_command (_("lower regions to bottom"));
2702                 } else {
2703                         begin_reversible_command (_("lower region"));
2704                 }
2705                 break;
2706         }
2707
2708         set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2709         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2710                 (*i)->clear_owned_changes ();
2711         }
2712
2713         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2714                 boost::shared_ptr<Region> r = (*i)->region ();
2715                 switch (op) {
2716                 case Raise:
2717                         r->raise ();
2718                         break;
2719                 case RaiseToTop:
2720                         r->raise_to_top ();
2721                         break;
2722                 case Lower:
2723                         r->lower ();
2724                         break;
2725                 case LowerToBottom:
2726                         r->lower_to_bottom ();
2727                 }
2728         }
2729
2730         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2731                 vector<Command*> cmds;
2732                 (*i)->rdiff (cmds);
2733                 _session->add_commands (cmds);
2734         }
2735
2736         commit_reversible_command ();
2737 }
2738
2739 void
2740 Editor::raise_region ()
2741 {
2742         do_layer_operation (Raise);
2743 }
2744
2745 void
2746 Editor::raise_region_to_top ()
2747 {
2748         do_layer_operation (RaiseToTop);
2749 }
2750
2751 void
2752 Editor::lower_region ()
2753 {
2754         do_layer_operation (Lower);
2755 }
2756
2757 void
2758 Editor::lower_region_to_bottom ()
2759 {
2760         do_layer_operation (LowerToBottom);
2761 }
2762
2763 /** Show the region editor for the selected regions */
2764 void
2765 Editor::show_region_properties ()
2766 {
2767         selection->foreach_regionview (&RegionView::show_region_editor);
2768 }
2769
2770 /** Show the midi list editor for the selected MIDI regions */
2771 void
2772 Editor::show_midi_list_editor ()
2773 {
2774         selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2775 }
2776
2777 void
2778 Editor::rename_region ()
2779 {
2780         RegionSelection rs = get_regions_from_selection_and_entered ();
2781
2782         if (rs.empty()) {
2783                 return;
2784         }
2785
2786         ArdourDialog d (_("Rename Region"), true, false);
2787         Entry entry;
2788         Label label (_("New name:"));
2789         HBox hbox;
2790
2791         hbox.set_spacing (6);
2792         hbox.pack_start (label, false, false);
2793         hbox.pack_start (entry, true, true);
2794
2795         d.get_vbox()->set_border_width (12);
2796         d.get_vbox()->pack_start (hbox, false, false);
2797
2798         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2799         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2800
2801         d.set_size_request (300, -1);
2802
2803         entry.set_text (rs.front()->region()->name());
2804         entry.select_region (0, -1);
2805
2806         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2807
2808         d.show_all ();
2809
2810         entry.grab_focus();
2811
2812         int const ret = d.run();
2813
2814         d.hide ();
2815
2816         if (ret != RESPONSE_OK) {
2817                 return;
2818         }
2819
2820         std::string str = entry.get_text();
2821         strip_whitespace_edges (str);
2822         if (!str.empty()) {
2823                 rs.front()->region()->set_name (str);
2824                 _regions->redisplay ();
2825         }
2826 }
2827
2828 /** Start an audition of the first selected region */
2829 void
2830 Editor::play_edit_range ()
2831 {
2832         framepos_t start, end;
2833
2834         if (get_edit_op_range (start, end)) {
2835                 _session->request_bounded_roll (start, end);
2836         }
2837 }
2838
2839 void
2840 Editor::play_selected_region ()
2841 {
2842         framepos_t start = max_framepos;
2843         framepos_t end = 0;
2844
2845         RegionSelection rs = get_regions_from_selection_and_entered ();
2846
2847         if (rs.empty()) {
2848                 return;
2849         }
2850
2851         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2852                 if ((*i)->region()->position() < start) {
2853                         start = (*i)->region()->position();
2854                 }
2855                 if ((*i)->region()->last_frame() + 1 > end) {
2856                         end = (*i)->region()->last_frame() + 1;
2857                 }
2858         }
2859
2860         _session->request_bounded_roll (start, end);
2861 }
2862
2863 void
2864 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2865 {
2866         _session->audition_region (region);
2867 }
2868
2869 void
2870 Editor::region_from_selection ()
2871 {
2872         if (clicked_axisview == 0) {
2873                 return;
2874         }
2875
2876         if (selection->time.empty()) {
2877                 return;
2878         }
2879
2880         framepos_t start = selection->time[clicked_selection].start;
2881         framepos_t end = selection->time[clicked_selection].end;
2882
2883         TrackViewList tracks = get_tracks_for_range_action ();
2884
2885         framepos_t selection_cnt = end - start + 1;
2886
2887         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2888                 boost::shared_ptr<Region> current;
2889                 boost::shared_ptr<Playlist> pl;
2890                 framepos_t internal_start;
2891                 string new_name;
2892
2893                 if ((pl = (*i)->playlist()) == 0) {
2894                         continue;
2895                 }
2896
2897                 if ((current = pl->top_region_at (start)) == 0) {
2898                         continue;
2899                 }
2900
2901                 internal_start = start - current->position();
2902                 RegionFactory::region_name (new_name, current->name(), true);
2903
2904                 PropertyList plist;
2905
2906                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2907                 plist.add (ARDOUR::Properties::length, selection_cnt);
2908                 plist.add (ARDOUR::Properties::name, new_name);
2909                 plist.add (ARDOUR::Properties::layer, 0);
2910
2911                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2912         }
2913 }
2914
2915 void
2916 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2917 {
2918         if (selection->time.empty() || selection->tracks.empty()) {
2919                 return;
2920         }
2921
2922         framepos_t start, end;
2923         if (clicked_selection) {
2924                 start = selection->time[clicked_selection].start;
2925                 end = selection->time[clicked_selection].end;
2926         } else {
2927                 start = selection->time.start();
2928                 end = selection->time.end_frame();
2929         }
2930
2931         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2932         sort_track_selection (ts);
2933
2934         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2935                 boost::shared_ptr<Region> current;
2936                 boost::shared_ptr<Playlist> playlist;
2937                 framepos_t internal_start;
2938                 string new_name;
2939
2940                 if ((playlist = (*i)->playlist()) == 0) {
2941                         continue;
2942                 }
2943
2944                 if ((current = playlist->top_region_at(start)) == 0) {
2945                         continue;
2946                 }
2947
2948                 internal_start = start - current->position();
2949                 RegionFactory::region_name (new_name, current->name(), true);
2950
2951                 PropertyList plist;
2952
2953                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2954                 plist.add (ARDOUR::Properties::length, end - start + 1);
2955                 plist.add (ARDOUR::Properties::name, new_name);
2956
2957                 new_regions.push_back (RegionFactory::create (current, plist));
2958         }
2959 }
2960
2961 void
2962 Editor::split_multichannel_region ()
2963 {
2964         RegionSelection rs = get_regions_from_selection_and_entered ();
2965
2966         if (rs.empty()) {
2967                 return;
2968         }
2969
2970         vector< boost::shared_ptr<Region> > v;
2971
2972         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2973                 (*x)->region()->separate_by_channel (*_session, v);
2974         }
2975 }
2976
2977 void
2978 Editor::new_region_from_selection ()
2979 {
2980         region_from_selection ();
2981         cancel_selection ();
2982 }
2983
2984 static void
2985 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2986 {
2987         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2988         // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2989         case Evoral::OverlapNone:
2990                 break;
2991         default:
2992                 rs->push_back (rv);
2993         }
2994 }
2995
2996 /** Return either:
2997  *    - selected tracks, or if there are none...
2998  *    - tracks containing selected regions, or if there are none...
2999  *    - all tracks
3000  * @return tracks.
3001  */
3002 TrackViewList
3003 Editor::get_tracks_for_range_action () const
3004 {
3005         TrackViewList t;
3006
3007         if (selection->tracks.empty()) {
3008
3009                 /* use tracks with selected regions */
3010
3011                 RegionSelection rs = selection->regions;
3012
3013                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3014                         TimeAxisView* tv = &(*i)->get_time_axis_view();
3015
3016                         if (!t.contains (tv)) {
3017                                 t.push_back (tv);
3018                         }
3019                 }
3020
3021                 if (t.empty()) {
3022                         /* no regions and no tracks: use all tracks */
3023                         t = track_views;
3024                 }
3025
3026         } else {
3027
3028                 t = selection->tracks;
3029         }
3030
3031         return t.filter_to_unique_playlists();
3032 }
3033
3034 void
3035 Editor::separate_regions_between (const TimeSelection& ts)
3036 {
3037         bool in_command = false;
3038         boost::shared_ptr<Playlist> playlist;
3039         RegionSelection new_selection;
3040
3041         TrackViewList tmptracks = get_tracks_for_range_action ();
3042         sort_track_selection (tmptracks);
3043
3044         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3045
3046                 RouteTimeAxisView* rtv;
3047
3048                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3049
3050                         if (rtv->is_track()) {
3051
3052                                 /* no edits to destructive tracks */
3053
3054                                 if (rtv->track()->destructive()) {
3055                                         continue;
3056                                 }
3057
3058                                 if ((playlist = rtv->playlist()) != 0) {
3059
3060                                         playlist->clear_changes ();
3061
3062                                         /* XXX need to consider musical time selections here at some point */
3063
3064                                         double speed = rtv->track()->speed();
3065
3066
3067                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3068
3069                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3070                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3071
3072                                                 latest_regionviews.clear ();
3073
3074                                                 playlist->partition ((framepos_t)((*t).start * speed),
3075                                                                 (framepos_t)((*t).end * speed), false);
3076
3077                                                 c.disconnect ();
3078
3079                                                 if (!latest_regionviews.empty()) {
3080
3081                                                         rtv->view()->foreach_regionview (sigc::bind (
3082                                                                                 sigc::ptr_fun (add_if_covered),
3083                                                                                 &(*t), &new_selection));
3084
3085                                                         if (!in_command) {
3086                                                                 begin_reversible_command (_("separate"));
3087                                                                 in_command = true;
3088                                                         }
3089
3090                                                         /* pick up changes to existing regions */
3091
3092                                                         vector<Command*> cmds;
3093                                                         playlist->rdiff (cmds);
3094                                                         _session->add_commands (cmds);
3095
3096                                                         /* pick up changes to the playlist itself (adds/removes)
3097                                                          */
3098
3099                                                         _session->add_command(new StatefulDiffCommand (playlist));
3100                                                 }
3101                                         }
3102                                 }
3103                         }
3104                 }
3105         }
3106
3107         if (in_command) {
3108 //              selection->set (new_selection);
3109
3110                 commit_reversible_command ();
3111         }
3112 }
3113
3114 struct PlaylistState {
3115     boost::shared_ptr<Playlist> playlist;
3116     XMLNode*  before;
3117 };
3118
3119 /** Take tracks from get_tracks_for_range_action and cut any regions
3120  *  on those tracks so that the tracks are empty over the time
3121  *  selection.
3122  */
3123 void
3124 Editor::separate_region_from_selection ()
3125 {
3126         /* preferentially use *all* ranges in the time selection if we're in range mode
3127            to allow discontiguous operation, since get_edit_op_range() currently
3128            returns a single range.
3129         */
3130
3131         if (!selection->time.empty()) {
3132
3133                 separate_regions_between (selection->time);
3134
3135         } else {
3136
3137                 framepos_t start;
3138                 framepos_t end;
3139
3140                 if (get_edit_op_range (start, end)) {
3141
3142                         AudioRange ar (start, end, 1);
3143                         TimeSelection ts;
3144                         ts.push_back (ar);
3145
3146                         separate_regions_between (ts);
3147                 }
3148         }
3149 }
3150
3151 void
3152 Editor::separate_region_from_punch ()
3153 {
3154         Location* loc  = _session->locations()->auto_punch_location();
3155         if (loc) {
3156                 separate_regions_using_location (*loc);
3157         }
3158 }
3159
3160 void
3161 Editor::separate_region_from_loop ()
3162 {
3163         Location* loc  = _session->locations()->auto_loop_location();
3164         if (loc) {
3165                 separate_regions_using_location (*loc);
3166         }
3167 }
3168
3169 void
3170 Editor::separate_regions_using_location (Location& loc)
3171 {
3172         if (loc.is_mark()) {
3173                 return;
3174         }
3175
3176         AudioRange ar (loc.start(), loc.end(), 1);
3177         TimeSelection ts;
3178
3179         ts.push_back (ar);
3180
3181         separate_regions_between (ts);
3182 }
3183
3184 /** Separate regions under the selected region */
3185 void
3186 Editor::separate_under_selected_regions ()
3187 {
3188         vector<PlaylistState> playlists;
3189
3190         RegionSelection rs;
3191
3192         rs = get_regions_from_selection_and_entered();
3193
3194         if (!_session || rs.empty()) {
3195                 return;
3196         }
3197
3198         begin_reversible_command (_("separate region under"));
3199
3200         list<boost::shared_ptr<Region> > regions_to_remove;
3201
3202         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3203                 // we can't just remove the region(s) in this loop because
3204                 // this removes them from the RegionSelection, and they thus
3205                 // disappear from underneath the iterator, and the ++i above
3206                 // SEGVs in a puzzling fashion.
3207
3208                 // so, first iterate over the regions to be removed from rs and
3209                 // add them to the regions_to_remove list, and then
3210                 // iterate over the list to actually remove them.
3211
3212                 regions_to_remove.push_back ((*i)->region());
3213         }
3214
3215         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3216
3217                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3218
3219                 if (!playlist) {
3220                         // is this check necessary?
3221                         continue;
3222                 }
3223
3224                 vector<PlaylistState>::iterator i;
3225
3226                 //only take state if this is a new playlist.
3227                 for (i = playlists.begin(); i != playlists.end(); ++i) {
3228                         if ((*i).playlist == playlist) {
3229                                 break;
3230                         }
3231                 }
3232
3233                 if (i == playlists.end()) {
3234
3235                         PlaylistState before;
3236                         before.playlist = playlist;
3237                         before.before = &playlist->get_state();
3238
3239                         playlist->freeze ();
3240                         playlists.push_back(before);
3241                 }
3242
3243                 //Partition on the region bounds
3244                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3245
3246                 //Re-add region that was just removed due to the partition operation
3247                 playlist->add_region( (*rl), (*rl)->first_frame() );
3248         }
3249
3250         vector<PlaylistState>::iterator pl;
3251
3252         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3253                 (*pl).playlist->thaw ();
3254                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3255         }
3256
3257         commit_reversible_command ();
3258 }
3259
3260 void
3261 Editor::crop_region_to_selection ()
3262 {
3263         if (!selection->time.empty()) {
3264
3265                 crop_region_to (selection->time.start(), selection->time.end_frame());
3266
3267         } else {
3268
3269                 framepos_t start;
3270                 framepos_t end;
3271
3272                 if (get_edit_op_range (start, end)) {
3273                         crop_region_to (start, end);
3274                 }
3275         }
3276
3277 }
3278
3279 void
3280 Editor::crop_region_to (framepos_t start, framepos_t end)
3281 {
3282         vector<boost::shared_ptr<Playlist> > playlists;
3283         boost::shared_ptr<Playlist> playlist;
3284         TrackViewList ts;
3285
3286         if (selection->tracks.empty()) {
3287                 ts = track_views.filter_to_unique_playlists();
3288         } else {
3289                 ts = selection->tracks.filter_to_unique_playlists ();
3290         }
3291
3292         sort_track_selection (ts);
3293
3294         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3295
3296                 RouteTimeAxisView* rtv;
3297
3298                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3299
3300                         boost::shared_ptr<Track> t = rtv->track();
3301
3302                         if (t != 0 && ! t->destructive()) {
3303
3304                                 if ((playlist = rtv->playlist()) != 0) {
3305                                         playlists.push_back (playlist);
3306                                 }
3307                         }
3308                 }
3309         }
3310
3311         if (playlists.empty()) {
3312                 return;
3313         }
3314
3315         framepos_t pos;
3316         framepos_t new_start;
3317         framepos_t new_end;
3318         framecnt_t new_length;
3319         bool in_command = false;
3320
3321         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3322
3323                 /* Only the top regions at start and end have to be cropped */
3324                 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3325                 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3326
3327                 vector<boost::shared_ptr<Region> > regions;
3328
3329                 if (region_at_start != 0) {
3330                         regions.push_back (region_at_start);
3331                 }
3332                 if (region_at_end != 0) {
3333                         regions.push_back (region_at_end);
3334                 }
3335
3336                 /* now adjust lengths */
3337                 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3338
3339                         pos = (*i)->position();
3340                         new_start = max (start, pos);
3341                         if (max_framepos - pos > (*i)->length()) {
3342                                 new_end = pos + (*i)->length() - 1;
3343                         } else {
3344                                 new_end = max_framepos;
3345                         }
3346                         new_end = min (end, new_end);
3347                         new_length = new_end - new_start + 1;
3348
3349                         if(!in_command) {
3350                                 begin_reversible_command (_("trim to selection"));
3351                                 in_command = true;
3352                         }
3353                         (*i)->clear_changes ();
3354                         (*i)->trim_to (new_start, new_length);
3355                         _session->add_command (new StatefulDiffCommand (*i));
3356                 }
3357         }
3358
3359         if (in_command) {
3360                 commit_reversible_command ();
3361         }
3362 }
3363
3364 void
3365 Editor::region_fill_track ()
3366 {
3367         boost::shared_ptr<Playlist> playlist;
3368         RegionSelection regions = get_regions_from_selection_and_entered ();
3369         RegionSelection foo;
3370
3371         framepos_t const end = _session->current_end_frame ();
3372
3373         if (regions.empty () || regions.end_frame () + 1 >= end) {
3374                 return;
3375         }
3376
3377         framepos_t const start_frame = regions.start ();
3378         framepos_t const end_frame = regions.end_frame ();
3379         framecnt_t const gap = end_frame - start_frame + 1;
3380
3381         begin_reversible_command (Operations::region_fill);
3382
3383         selection->clear_regions ();
3384
3385         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3386
3387                 boost::shared_ptr<Region> r ((*i)->region());
3388
3389                 TimeAxisView& tv = (*i)->get_time_axis_view();
3390                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3391                 latest_regionviews.clear ();
3392                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3393
3394                 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3395                 playlist = (*i)->region()->playlist();
3396                 playlist->clear_changes ();
3397                 playlist->duplicate_until (r, position, gap, end);
3398                 _session->add_command(new StatefulDiffCommand (playlist));
3399
3400                 c.disconnect ();
3401
3402                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3403         }
3404
3405         if (!foo.empty()) {
3406                 selection->set (foo);
3407         }
3408
3409         commit_reversible_command ();
3410 }
3411
3412 void
3413 Editor::set_region_sync_position ()
3414 {
3415         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3416 }
3417
3418 void
3419 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3420 {
3421         bool in_command = false;
3422
3423         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3424
3425                 if (!(*r)->region()->covers (where)) {
3426                         continue;
3427                 }
3428
3429                 boost::shared_ptr<Region> region ((*r)->region());
3430
3431                 if (!in_command) {
3432                         begin_reversible_command (_("set sync point"));
3433                         in_command = true;
3434                 }
3435
3436                 region->clear_changes ();
3437                 region->set_sync_position (where);
3438                 _session->add_command(new StatefulDiffCommand (region));
3439         }
3440
3441         if (in_command) {
3442                 commit_reversible_command ();
3443         }
3444 }
3445
3446 /** Remove the sync positions of the selection */
3447 void
3448 Editor::remove_region_sync ()
3449 {
3450         RegionSelection rs = get_regions_from_selection_and_entered ();
3451
3452         if (rs.empty()) {
3453                 return;
3454         }
3455
3456         begin_reversible_command (_("remove region sync"));
3457
3458         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3459
3460                 (*i)->region()->clear_changes ();
3461                 (*i)->region()->clear_sync_position ();
3462                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3463         }
3464
3465         commit_reversible_command ();
3466 }
3467
3468 void
3469 Editor::naturalize_region ()
3470 {
3471         RegionSelection rs = get_regions_from_selection_and_entered ();
3472
3473         if (rs.empty()) {
3474                 return;
3475         }
3476
3477         if (rs.size() > 1) {
3478                 begin_reversible_command (_("move regions to original position"));
3479         } else {
3480                 begin_reversible_command (_("move region to original position"));
3481         }
3482
3483         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3484                 (*i)->region()->clear_changes ();
3485                 (*i)->region()->move_to_natural_position ();
3486                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3487         }
3488
3489         commit_reversible_command ();
3490 }
3491
3492 void
3493 Editor::align_regions (RegionPoint what)
3494 {
3495         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3496
3497         if (rs.empty()) {
3498                 return;
3499         }
3500
3501         begin_reversible_command (_("align selection"));
3502
3503         framepos_t const position = get_preferred_edit_position ();
3504
3505         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3506                 align_region_internal ((*i)->region(), what, position);
3507         }
3508
3509         commit_reversible_command ();
3510 }
3511
3512 struct RegionSortByTime {
3513     bool operator() (const RegionView* a, const RegionView* b) {
3514             return a->region()->position() < b->region()->position();
3515     }
3516 };
3517
3518 void
3519 Editor::align_regions_relative (RegionPoint point)
3520 {
3521         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3522
3523         if (rs.empty()) {
3524                 return;
3525         }
3526
3527         framepos_t const position = get_preferred_edit_position ();
3528
3529         framepos_t distance = 0;
3530         framepos_t pos = 0;
3531         int dir = 1;
3532
3533         list<RegionView*> sorted;
3534         rs.by_position (sorted);
3535
3536         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3537
3538         switch (point) {
3539         case Start:
3540                 pos = position;
3541                 if (position > r->position()) {
3542                         distance = position - r->position();
3543                 } else {
3544                         distance = r->position() - position;
3545                         dir = -1;
3546                 }
3547                 break;
3548
3549         case End:
3550                 if (position > r->last_frame()) {
3551                         distance = position - r->last_frame();
3552                         pos = r->position() + distance;
3553                 } else {
3554                         distance = r->last_frame() - position;
3555                         pos = r->position() - distance;
3556                         dir = -1;
3557                 }
3558                 break;
3559
3560         case SyncPoint:
3561                 pos = r->adjust_to_sync (position);
3562                 if (pos > r->position()) {
3563                         distance = pos - r->position();
3564                 } else {
3565                         distance = r->position() - pos;
3566                         dir = -1;
3567                 }
3568                 break;
3569         }
3570
3571         if (pos == r->position()) {
3572                 return;
3573         }
3574
3575         begin_reversible_command (_("align selection (relative)"));
3576
3577         /* move first one specially */
3578
3579         r->clear_changes ();
3580         r->set_position (pos);
3581         _session->add_command(new StatefulDiffCommand (r));
3582
3583         /* move rest by the same amount */
3584
3585         sorted.pop_front();
3586
3587         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3588
3589                 boost::shared_ptr<Region> region ((*i)->region());
3590
3591                 region->clear_changes ();
3592
3593                 if (dir > 0) {
3594                         region->set_position (region->position() + distance);
3595                 } else {
3596                         region->set_position (region->position() - distance);
3597                 }
3598
3599                 _session->add_command(new StatefulDiffCommand (region));
3600
3601         }
3602
3603         commit_reversible_command ();
3604 }
3605
3606 void
3607 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3608 {
3609         begin_reversible_command (_("align region"));
3610         align_region_internal (region, point, position);
3611         commit_reversible_command ();
3612 }
3613
3614 void
3615 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3616 {
3617         region->clear_changes ();
3618
3619         switch (point) {
3620         case SyncPoint:
3621                 region->set_position (region->adjust_to_sync (position));
3622                 break;
3623
3624         case End:
3625                 if (position > region->length()) {
3626                         region->set_position (position - region->length());
3627                 }
3628                 break;
3629
3630         case Start:
3631                 region->set_position (position);
3632                 break;
3633         }
3634
3635         _session->add_command(new StatefulDiffCommand (region));
3636 }
3637
3638 void
3639 Editor::trim_region_front ()
3640 {
3641         trim_region (true);
3642 }
3643
3644 void
3645 Editor::trim_region_back ()
3646 {
3647         trim_region (false);
3648 }
3649
3650 void
3651 Editor::trim_region (bool front)
3652 {
3653         framepos_t where = get_preferred_edit_position();
3654         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3655
3656         if (rs.empty()) {
3657                 return;
3658         }
3659
3660         begin_reversible_command (front ? _("trim front") : _("trim back"));
3661
3662         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3663                 if (!(*i)->region()->locked()) {
3664
3665                         (*i)->region()->clear_changes ();
3666
3667                         if (front) {
3668                                 (*i)->region()->trim_front (where);
3669                                 maybe_locate_with_edit_preroll ( where );
3670                         } else {
3671                                 (*i)->region()->trim_end (where);
3672                                 maybe_locate_with_edit_preroll ( where );
3673                         }
3674
3675                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3676                 }
3677         }
3678
3679         commit_reversible_command ();
3680 }
3681
3682 /** Trim the end of the selected regions to the position of the edit cursor */
3683 void
3684 Editor::trim_region_to_loop ()
3685 {
3686         Location* loc = _session->locations()->auto_loop_location();
3687         if (!loc) {
3688                 return;
3689         }
3690         trim_region_to_location (*loc, _("trim to loop"));
3691 }
3692
3693 void
3694 Editor::trim_region_to_punch ()
3695 {
3696         Location* loc = _session->locations()->auto_punch_location();
3697         if (!loc) {
3698                 return;
3699         }
3700         trim_region_to_location (*loc, _("trim to punch"));
3701 }
3702
3703 void
3704 Editor::trim_region_to_location (const Location& loc, const char* str)
3705 {
3706         RegionSelection rs = get_regions_from_selection_and_entered ();
3707         bool in_command = false;
3708
3709         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3710                 RegionView* rv = (*x);
3711
3712                 /* require region to span proposed trim */
3713                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3714                 case Evoral::OverlapInternal:
3715                         break;
3716                 default:
3717                         continue;
3718                 }
3719
3720                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3721                 if (!tav) {
3722                         return;
3723                 }
3724
3725                 float speed = 1.0;
3726                 framepos_t start;
3727                 framepos_t end;
3728
3729                 if (tav->track() != 0) {
3730                         speed = tav->track()->speed();
3731                 }
3732
3733                 start = session_frame_to_track_frame (loc.start(), speed);
3734                 end = session_frame_to_track_frame (loc.end(), speed);
3735
3736                 rv->region()->clear_changes ();
3737                 rv->region()->trim_to (start, (end - start));
3738
3739                 if (!in_command) {
3740                         begin_reversible_command (str);
3741                         in_command = true;
3742                 }
3743                 _session->add_command(new StatefulDiffCommand (rv->region()));
3744         }
3745
3746         if (in_command) {
3747                 commit_reversible_command ();
3748         }
3749 }
3750
3751 void
3752 Editor::trim_region_to_previous_region_end ()
3753 {
3754         return trim_to_region(false);
3755 }
3756
3757 void
3758 Editor::trim_region_to_next_region_start ()
3759 {
3760         return trim_to_region(true);
3761 }
3762
3763 void
3764 Editor::trim_to_region(bool forward)
3765 {
3766         RegionSelection rs = get_regions_from_selection_and_entered ();
3767         bool in_command = false;
3768
3769         boost::shared_ptr<Region> next_region;
3770
3771         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3772
3773                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3774
3775                 if (!arv) {
3776                         continue;
3777                 }
3778
3779                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3780
3781                 if (!atav) {
3782                         continue;
3783                 }
3784
3785                 float speed = 1.0;
3786
3787                 if (atav->track() != 0) {
3788                         speed = atav->track()->speed();
3789                 }
3790
3791
3792                 boost::shared_ptr<Region> region = arv->region();
3793                 boost::shared_ptr<Playlist> playlist (region->playlist());
3794
3795                 region->clear_changes ();
3796
3797                 if (forward) {
3798
3799                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3800
3801                     if (!next_region) {
3802                         continue;
3803                     }
3804
3805                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3806                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3807                 }
3808                 else {
3809
3810                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3811
3812                     if(!next_region){
3813                         continue;
3814                     }
3815
3816                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3817
3818                     arv->region_changed (ARDOUR::bounds_change);
3819                 }
3820
3821                 if (!in_command) {
3822                         begin_reversible_command (_("trim to region"));
3823                         in_command = true;
3824                 }
3825                 _session->add_command(new StatefulDiffCommand (region));
3826         }
3827
3828         if (in_command) {
3829                 commit_reversible_command ();
3830         }
3831 }
3832
3833 void
3834 Editor::unfreeze_route ()
3835 {
3836         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3837                 return;
3838         }
3839
3840         clicked_routeview->track()->unfreeze ();
3841 }
3842
3843 void*
3844 Editor::_freeze_thread (void* arg)
3845 {
3846         return static_cast<Editor*>(arg)->freeze_thread ();
3847 }
3848
3849 void*
3850 Editor::freeze_thread ()
3851 {
3852         /* create event pool because we may need to talk to the session */
3853         SessionEvent::create_per_thread_pool ("freeze events", 64);
3854         /* create per-thread buffers for process() tree to use */
3855         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3856         current_interthread_info->done = true;
3857         return 0;
3858 }
3859
3860 void
3861 Editor::freeze_route ()
3862 {
3863         if (!_session) {
3864                 return;
3865         }
3866
3867         /* stop transport before we start. this is important */
3868
3869         _session->request_transport_speed (0.0);
3870
3871         /* wait for just a little while, because the above call is asynchronous */
3872
3873         Glib::usleep (250000);
3874
3875         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3876                 return;
3877         }
3878
3879         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3880                 MessageDialog d (
3881                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3882                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3883                         );
3884                 d.set_title (_("Cannot freeze"));
3885                 d.run ();
3886                 return;
3887         }
3888
3889         if (clicked_routeview->track()->has_external_redirects()) {
3890                 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3891                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3892                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3893
3894                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3895                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3896                 d.set_title (_("Freeze Limits"));
3897
3898                 int response = d.run ();
3899
3900                 switch (response) {
3901                 case Gtk::RESPONSE_CANCEL:
3902                         return;
3903                 default:
3904                         break;
3905                 }
3906         }
3907
3908         InterThreadInfo itt;
3909         current_interthread_info = &itt;
3910
3911         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3912
3913         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3914
3915         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3916
3917         while (!itt.done && !itt.cancel) {
3918                 gtk_main_iteration ();
3919         }
3920
3921         pthread_join (itt.thread, 0);
3922         current_interthread_info = 0;
3923 }
3924
3925 void
3926 Editor::bounce_range_selection (bool replace, bool enable_processing)
3927 {
3928         if (selection->time.empty()) {
3929                 return;
3930         }
3931
3932         TrackSelection views = selection->tracks;
3933
3934         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3935
3936                 if (enable_processing) {
3937
3938                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3939
3940                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3941                                 MessageDialog d (
3942                                         _("You can't perform this operation because the processing of the signal "
3943                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3944                                           "You can do this without processing, which is a different operation.")
3945                                         );
3946                                 d.set_title (_("Cannot bounce"));
3947                                 d.run ();
3948                                 return;
3949                         }
3950                 }
3951         }
3952
3953         framepos_t start = selection->time[clicked_selection].start;
3954         framepos_t end = selection->time[clicked_selection].end;
3955         framepos_t cnt = end - start + 1;
3956         bool in_command = false;
3957
3958         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3959
3960                 RouteTimeAxisView* rtv;
3961
3962                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3963                         continue;
3964                 }
3965
3966                 boost::shared_ptr<Playlist> playlist;
3967
3968                 if ((playlist = rtv->playlist()) == 0) {
3969                         continue;
3970                 }
3971
3972                 InterThreadInfo itt;
3973
3974                 playlist->clear_changes ();
3975                 playlist->clear_owned_changes ();
3976
3977                 boost::shared_ptr<Region> r;
3978
3979                 if (enable_processing) {
3980                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3981                 } else {
3982                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3983                 }
3984
3985                 if (!r) {
3986                         continue;
3987                 }
3988
3989                 if (replace) {
3990                         list<AudioRange> ranges;
3991                         ranges.push_back (AudioRange (start, start+cnt, 0));
3992                         playlist->cut (ranges); // discard result
3993                         playlist->add_region (r, start);
3994                 }
3995
3996                 if (!in_command) {
3997                         begin_reversible_command (_("bounce range"));
3998                         in_command = true;
3999                 }
4000                 vector<Command*> cmds;
4001                 playlist->rdiff (cmds);
4002                 _session->add_commands (cmds);
4003
4004                 _session->add_command (new StatefulDiffCommand (playlist));
4005         }
4006
4007         if (in_command) {
4008                 commit_reversible_command ();
4009         }
4010 }
4011
4012 /** Delete selected regions, automation points or a time range */
4013 void
4014 Editor::delete_ ()
4015 {
4016         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4017         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4018         bool deleted = false;
4019         if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4020                 deleted = current_mixer_strip->delete_processors ();
4021
4022         if (!deleted)
4023                 cut_copy (Delete);
4024 }
4025
4026 /** Cut selected regions, automation points or a time range */
4027 void
4028 Editor::cut ()
4029 {
4030         cut_copy (Cut);
4031 }
4032
4033 /** Copy selected regions, automation points or a time range */
4034 void
4035 Editor::copy ()
4036 {
4037         cut_copy (Copy);
4038 }
4039
4040
4041 /** @return true if a Cut, Copy or Clear is possible */
4042 bool
4043 Editor::can_cut_copy () const
4044 {
4045         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4046                 return true;
4047
4048         return false;
4049 }
4050
4051
4052 /** Cut, copy or clear selected regions, automation points or a time range.
4053  * @param op Operation (Delete, Cut, Copy or Clear)
4054  */
4055 void
4056 Editor::cut_copy (CutCopyOp op)
4057 {
4058         /* only cancel selection if cut/copy is successful.*/
4059
4060         string opname;
4061
4062         switch (op) {
4063         case Delete:
4064                 opname = _("delete");
4065                 break;
4066         case Cut:
4067                 opname = _("cut");
4068                 break;
4069         case Copy:
4070                 opname = _("copy");
4071                 break;
4072         case Clear:
4073                 opname = _("clear");
4074                 break;
4075         }
4076
4077         /* if we're deleting something, and the mouse is still pressed,
4078            the thing we started a drag for will be gone when we release
4079            the mouse button(s). avoid this. see part 2 at the end of
4080            this function.
4081         */
4082
4083         if (op == Delete || op == Cut || op == Clear) {
4084                 if (_drags->active ()) {
4085                         _drags->abort ();
4086                 }
4087         }
4088
4089         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
4090                 cut_buffer->clear ();
4091
4092         if (entered_marker) {
4093
4094                 /* cut/delete op while pointing at a marker */
4095
4096                 bool ignored;
4097                 Location* loc = find_location_from_marker (entered_marker, ignored);
4098
4099                 if (_session && loc) {
4100                         entered_marker = NULL;
4101                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4102                 }
4103
4104                 _drags->abort ();
4105                 return;
4106         }
4107
4108         switch (mouse_mode) {
4109         case MouseDraw:
4110         case MouseContent:
4111                 begin_reversible_command (opname + ' ' + X_("MIDI"));
4112                 cut_copy_midi (op);
4113                 commit_reversible_command ();
4114                 return;
4115         default:
4116                 break;
4117         }
4118
4119         bool did_edit = false;
4120
4121         if (!selection->regions.empty() || !selection->points.empty()) {
4122                 begin_reversible_command (opname + ' ' + _("objects"));
4123                 did_edit = true;
4124
4125                 if (!selection->regions.empty()) {
4126                         cut_copy_regions (op, selection->regions);
4127
4128                         if (op == Cut || op == Delete) {
4129                                 selection->clear_regions ();
4130                         }
4131                 }
4132
4133                 if (!selection->points.empty()) {
4134                         cut_copy_points (op);
4135
4136                         if (op == Cut || op == Delete) {
4137                                 selection->clear_points ();
4138                         }
4139                 }
4140         } else if (selection->time.empty()) {
4141                 framepos_t start, end;
4142                 /* no time selection, see if we can get an edit range
4143                    and use that.
4144                 */
4145                 if (get_edit_op_range (start, end)) {
4146                         selection->set (start, end);
4147                 }
4148         } else if (!selection->time.empty()) {
4149                 begin_reversible_command (opname + ' ' + _("range"));
4150
4151                 did_edit = true;
4152                 cut_copy_ranges (op);
4153
4154                 if (op == Cut || op == Delete) {
4155                         selection->clear_time ();
4156                 }
4157         }
4158
4159         if (did_edit) {
4160                 /* reset repeated paste state */
4161                 paste_count    = 0;
4162                 last_paste_pos = 0;
4163                 commit_reversible_command ();
4164         }
4165
4166         if (op == Delete || op == Cut || op == Clear) {
4167                 _drags->abort ();
4168         }
4169 }
4170
4171 struct AutomationRecord {
4172         AutomationRecord () : state (0) , line(NULL) {}
4173         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4174
4175         XMLNode* state; ///< state before any operation
4176         const AutomationLine* line; ///< line this came from
4177         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4178 };
4179
4180 /** Cut, copy or clear selected automation points.
4181  *  @param op Operation (Cut, Copy or Clear)
4182  */
4183 void
4184 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4185 {
4186         if (selection->points.empty ()) {
4187                 return;
4188         }
4189
4190         /* XXX: not ideal, as there may be more than one track involved in the point selection */
4191         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4192
4193         /* Keep a record of the AutomationLists that we end up using in this operation */
4194         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4195         Lists lists;
4196
4197         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4198         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4199                 const AutomationLine&                   line = (*i)->line();
4200                 const boost::shared_ptr<AutomationList> al   = line.the_list();
4201                 if (lists.find (al) == lists.end ()) {
4202                         /* We haven't seen this list yet, so make a record for it.  This includes
4203                            taking a copy of its current state, in case this is needed for undo later.
4204                         */
4205                         lists[al] = AutomationRecord (&al->get_state (), &line);
4206                 }
4207         }
4208
4209         if (op == Cut || op == Copy) {
4210                 /* This operation will involve putting things in the cut buffer, so create an empty
4211                    ControlList for each of our source lists to put the cut buffer data in.
4212                 */
4213                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4214                         i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4215                 }
4216
4217                 /* Add all selected points to the relevant copy ControlLists */
4218                 framepos_t start = std::numeric_limits<framepos_t>::max();
4219                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4220                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4221                         AutomationList::const_iterator    j  = (*i)->model();
4222
4223                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4224                         if (midi) {
4225                                 /* Update earliest MIDI start time in beats */
4226                                 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4227                         } else {
4228                                 /* Update earliest session start time in frames */
4229                                 start = std::min(start, (*i)->line().session_position(j));
4230                         }
4231                 }
4232
4233                 /* Snap start time backwards, so copy/paste is snap aligned. */
4234                 if (midi) {
4235                         if (earliest == Evoral::Beats::max()) {
4236                                 earliest = Evoral::Beats();  // Weird... don't offset
4237                         }
4238                         earliest.round_down_to_beat();
4239                 } else {
4240                         if (start == std::numeric_limits<double>::max()) {
4241                                 start = 0;  // Weird... don't offset
4242                         }
4243                         snap_to(start, RoundDownMaybe);
4244                 }
4245
4246                 const double line_offset = midi ? earliest.to_double() : start;
4247                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4248                         /* Correct this copy list so that it is relative to the earliest
4249                            start time, so relative ordering between points is preserved
4250                            when copying from several lists and the paste starts at the
4251                            earliest copied piece of data. */
4252                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4253                                 (*j)->when -= line_offset;
4254                         }
4255
4256                         /* And add it to the cut buffer */
4257                         cut_buffer->add (i->second.copy);
4258                 }
4259         }
4260
4261         if (op == Delete || op == Cut) {
4262                 /* This operation needs to remove things from the main AutomationList, so do that now */
4263
4264                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4265                         i->first->freeze ();
4266                 }
4267
4268                 /* Remove each selected point from its AutomationList */
4269                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4270                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4271                         al->erase ((*i)->model ());
4272                 }
4273
4274                 /* Thaw the lists and add undo records for them */
4275                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4276                         boost::shared_ptr<AutomationList> al = i->first;
4277                         al->thaw ();
4278                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4279                 }
4280         }
4281 }
4282
4283 /** Cut, copy or clear selected automation points.
4284  * @param op Operation (Cut, Copy or Clear)
4285  */
4286 void
4287 Editor::cut_copy_midi (CutCopyOp op)
4288 {
4289         Evoral::Beats earliest = Evoral::Beats::max();
4290         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4291                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4292                 if (mrv) {
4293                         if (!mrv->selection().empty()) {
4294                                 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4295                         }
4296                         mrv->cut_copy_clear (op);
4297
4298                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4299                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4300                 }
4301         }
4302
4303         if (!selection->points.empty()) {
4304                 cut_copy_points (op, earliest, true);
4305                 if (op == Cut || op == Delete) {
4306                         selection->clear_points ();
4307                 }
4308         }
4309 }
4310
4311 struct lt_playlist {
4312     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4313             return a.playlist < b.playlist;
4314     }
4315 };
4316
4317 struct PlaylistMapping {
4318     TimeAxisView* tv;
4319     boost::shared_ptr<Playlist> pl;
4320
4321     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4322 };
4323
4324 /** Remove `clicked_regionview' */
4325 void
4326 Editor::remove_clicked_region ()
4327 {
4328         if (clicked_routeview == 0 || clicked_regionview == 0) {
4329                 return;
4330         }
4331
4332         begin_reversible_command (_("remove region"));
4333
4334         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4335
4336         playlist->clear_changes ();
4337         playlist->clear_owned_changes ();
4338         playlist->remove_region (clicked_regionview->region());
4339         if (Config->get_edit_mode() == Ripple)
4340                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4341
4342         /* We might have removed regions, which alters other regions' layering_index,
4343            so we need to do a recursive diff here.
4344         */
4345         vector<Command*> cmds;
4346         playlist->rdiff (cmds);
4347         _session->add_commands (cmds);
4348
4349         _session->add_command(new StatefulDiffCommand (playlist));
4350         commit_reversible_command ();
4351 }
4352
4353
4354 /** Remove the selected regions */
4355 void
4356 Editor::remove_selected_regions ()
4357 {
4358         RegionSelection rs = get_regions_from_selection_and_entered ();
4359
4360         if (!_session || rs.empty()) {
4361                 return;
4362         }
4363
4364         list<boost::shared_ptr<Region> > regions_to_remove;
4365
4366         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4367                 // we can't just remove the region(s) in this loop because
4368                 // this removes them from the RegionSelection, and they thus
4369                 // disappear from underneath the iterator, and the ++i above
4370                 // SEGVs in a puzzling fashion.
4371
4372                 // so, first iterate over the regions to be removed from rs and
4373                 // add them to the regions_to_remove list, and then
4374                 // iterate over the list to actually remove them.
4375
4376                 regions_to_remove.push_back ((*i)->region());
4377         }
4378
4379         vector<boost::shared_ptr<Playlist> > playlists;
4380
4381         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4382
4383                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4384
4385                 if (!playlist) {
4386                         // is this check necessary?
4387                         continue;
4388                 }
4389
4390                 /* get_regions_from_selection_and_entered() guarantees that
4391                    the playlists involved are unique, so there is no need
4392                    to check here.
4393                 */
4394
4395                 playlists.push_back (playlist);
4396
4397                 playlist->clear_changes ();
4398                 playlist->clear_owned_changes ();
4399                 playlist->freeze ();
4400                 playlist->remove_region (*rl);
4401                 if (Config->get_edit_mode() == Ripple)
4402                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4403
4404         }
4405
4406         vector<boost::shared_ptr<Playlist> >::iterator pl;
4407         bool in_command = false;
4408
4409         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4410                 (*pl)->thaw ();
4411
4412                 /* We might have removed regions, which alters other regions' layering_index,
4413                    so we need to do a recursive diff here.
4414                 */
4415
4416                 if (!in_command) {
4417                         begin_reversible_command (_("remove region"));
4418                         in_command = true;
4419                 }
4420                 vector<Command*> cmds;
4421                 (*pl)->rdiff (cmds);
4422                 _session->add_commands (cmds);
4423
4424                 _session->add_command(new StatefulDiffCommand (*pl));
4425         }
4426
4427         if (in_command) {
4428                 commit_reversible_command ();
4429         }
4430 }
4431
4432 /** Cut, copy or clear selected regions.
4433  * @param op Operation (Cut, Copy or Clear)
4434  */
4435 void
4436 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4437 {
4438         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4439            a map when we want ordered access to both elements. i think.
4440         */
4441
4442         vector<PlaylistMapping> pmap;
4443
4444         framepos_t first_position = max_framepos;
4445
4446         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4447         FreezeList freezelist;
4448
4449         /* get ordering correct before we cut/copy */
4450
4451         rs.sort_by_position_and_track ();
4452
4453         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4454
4455                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4456
4457                 if (op == Cut || op == Clear || op == Delete) {
4458                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4459
4460                         if (pl) {
4461                                 FreezeList::iterator fl;
4462
4463                                 // only take state if this is a new playlist.
4464                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4465                                         if ((*fl) == pl) {
4466                                                 break;
4467                                         }
4468                                 }
4469
4470                                 if (fl == freezelist.end()) {
4471                                         pl->clear_changes();
4472                                         pl->clear_owned_changes ();
4473                                         pl->freeze ();
4474                                         freezelist.insert (pl);
4475                                 }
4476                         }
4477                 }
4478
4479                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4480                 vector<PlaylistMapping>::iterator z;
4481
4482                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4483                         if ((*z).tv == tv) {
4484                                 break;
4485                         }
4486                 }
4487
4488                 if (z == pmap.end()) {
4489                         pmap.push_back (PlaylistMapping (tv));
4490                 }
4491         }
4492
4493         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4494
4495                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4496
4497                 if (!pl) {
4498                         /* region not yet associated with a playlist (e.g. unfinished
4499                            capture pass.
4500                         */
4501                         ++x;
4502                         continue;
4503                 }
4504
4505                 TimeAxisView& tv = (*x)->get_time_axis_view();
4506                 boost::shared_ptr<Playlist> npl;
4507                 RegionSelection::iterator tmp;
4508
4509                 tmp = x;
4510                 ++tmp;
4511
4512                 if (op != Delete) {
4513
4514                         vector<PlaylistMapping>::iterator z;
4515
4516                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4517                                 if ((*z).tv == &tv) {
4518                                         break;
4519                                 }
4520                         }
4521
4522                         assert (z != pmap.end());
4523
4524                         if (!(*z).pl) {
4525                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4526                                 npl->freeze();
4527                                 (*z).pl = npl;
4528                         } else {
4529                                 npl = (*z).pl;
4530                         }
4531                 }
4532
4533                 boost::shared_ptr<Region> r = (*x)->region();
4534                 boost::shared_ptr<Region> _xx;
4535
4536                 assert (r != 0);
4537
4538                 switch (op) {
4539                 case Delete:
4540                         pl->remove_region (r);
4541                         if (Config->get_edit_mode() == Ripple)
4542                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4543                         break;
4544
4545                 case Cut:
4546                         _xx = RegionFactory::create (r);
4547                         npl->add_region (_xx, r->position() - first_position);
4548                         pl->remove_region (r);
4549                         if (Config->get_edit_mode() == Ripple)
4550                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4551                         break;
4552
4553                 case Copy:
4554                         /* copy region before adding, so we're not putting same object into two different playlists */
4555                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4556                         break;
4557
4558                 case Clear:
4559                         pl->remove_region (r);
4560                         if (Config->get_edit_mode() == Ripple)
4561                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4562                         break;
4563                 }
4564
4565                 x = tmp;
4566         }
4567
4568         if (op != Delete) {
4569
4570                 list<boost::shared_ptr<Playlist> > foo;
4571
4572                 /* the pmap is in the same order as the tracks in which selected regions occurred */
4573
4574                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4575                         if ((*i).pl) {
4576                                 (*i).pl->thaw();
4577                                 foo.push_back ((*i).pl);
4578                         }
4579                 }
4580
4581                 if (!foo.empty()) {
4582                         cut_buffer->set (foo);
4583                 }
4584
4585                 if (pmap.empty()) {
4586                         _last_cut_copy_source_track = 0;
4587                 } else {
4588                         _last_cut_copy_source_track = pmap.front().tv;
4589                 }
4590         }
4591
4592         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4593                 (*pl)->thaw ();
4594
4595                 /* We might have removed regions, which alters other regions' layering_index,
4596                    so we need to do a recursive diff here.
4597                 */
4598                 vector<Command*> cmds;
4599                 (*pl)->rdiff (cmds);
4600                 _session->add_commands (cmds);
4601
4602                 _session->add_command (new StatefulDiffCommand (*pl));
4603         }
4604 }
4605
4606 void
4607 Editor::cut_copy_ranges (CutCopyOp op)
4608 {
4609         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4610
4611         /* Sort the track selection now, so that it if is used, the playlists
4612            selected by the calls below to cut_copy_clear are in the order that
4613            their tracks appear in the editor.  This makes things like paste
4614            of ranges work properly.
4615         */
4616
4617         sort_track_selection (ts);
4618
4619         if (ts.empty()) {
4620                 if (!entered_track) {
4621                         return;
4622                 }
4623                 ts.push_back (entered_track);
4624         }
4625
4626         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4627                 (*i)->cut_copy_clear (*selection, op);
4628         }
4629 }
4630
4631 void
4632 Editor::paste (float times, bool from_context)
4633 {
4634         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4635
4636         paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4637 }
4638
4639 void
4640 Editor::mouse_paste ()
4641 {
4642         framepos_t where;
4643         bool ignored;
4644
4645         if (!mouse_frame (where, ignored)) {
4646                 return;
4647         }
4648
4649         snap_to (where);
4650         paste_internal (where, 1);
4651 }
4652
4653 void
4654 Editor::paste_internal (framepos_t position, float times)
4655 {
4656         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4657
4658         if (cut_buffer->empty(internal_editing())) {
4659                 return;
4660         }
4661
4662         if (position == max_framepos) {
4663                 position = get_preferred_edit_position();
4664                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4665         }
4666
4667         if (position == last_paste_pos) {
4668                 /* repeated paste in the same position */
4669                 ++paste_count;
4670         } else {
4671                 /* paste in new location, reset repeated paste state */
4672                 paste_count = 0;
4673                 last_paste_pos = position;
4674         }
4675
4676         /* get everything in the correct order */
4677
4678         TrackViewList ts;
4679         if (!selection->tracks.empty()) {
4680                 /* If there is a track selection, paste into exactly those tracks and
4681                    only those tracks.  This allows the user to be explicit and override
4682                    the below "do the reasonable thing" logic. */
4683                 ts = selection->tracks.filter_to_unique_playlists ();
4684                 sort_track_selection (ts);
4685         } else {
4686                 /* Figure out which track to base the paste at. */
4687                 TimeAxisView* base_track = NULL;
4688                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4689                         /* With the mouse edit point, paste onto the track under the mouse. */
4690                         base_track = entered_track;
4691                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4692                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4693                         base_track = &entered_regionview->get_time_axis_view();
4694                 } else if (_last_cut_copy_source_track) {
4695                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4696                         base_track = _last_cut_copy_source_track;
4697                 } else {
4698                         /* This is "impossible" since we've copied... well, do nothing. */
4699                         return;
4700                 }
4701
4702                 /* Walk up to parent if necessary, so base track is a route. */
4703                 while (base_track->get_parent()) {
4704                         base_track = base_track->get_parent();
4705                 }
4706
4707                 /* Add base track and all tracks below it.  The paste logic will select
4708                    the appropriate object types from the cut buffer in relative order. */
4709                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4710                         if ((*i)->order() >= base_track->order()) {
4711                                 ts.push_back(*i);
4712                         }
4713                 }
4714
4715                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4716                 sort_track_selection (ts);
4717
4718                 /* Add automation children of each track in order, for pasting several lines. */
4719                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4720                         /* Add any automation children for pasting several lines */
4721                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4722                         if (!rtv) {
4723                                 continue;
4724                         }
4725
4726                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4727                         const ATracks& atracks = rtv->automation_tracks();
4728                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4729                                 i = ts.insert(i, a->second.get());
4730                                 ++i;
4731                         }
4732                 }
4733
4734                 /* We now have a list of trackviews starting at base_track, including
4735                    automation children, in the order shown in the editor, e.g. R1,
4736                    R1.A1, R1.A2, R2, R2.A1, ... */
4737         }
4738
4739         begin_reversible_command (Operations::paste);
4740
4741         if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4742             dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4743             /* Only one line copied, and one automation track selected.  Do a
4744                "greedy" paste from one automation type to another. */
4745
4746             PasteContext ctx(paste_count, times, ItemCounts(), true);
4747             ts.front()->paste (position, *cut_buffer, ctx);
4748
4749         } else {
4750
4751                 /* Paste into tracks */
4752
4753                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4754                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4755                         (*i)->paste (position, *cut_buffer, ctx);
4756                 }
4757         }
4758
4759         commit_reversible_command ();
4760 }
4761
4762 void
4763 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4764 {
4765         if (regions.empty ()) {
4766                 return;
4767         }
4768
4769         boost::shared_ptr<Playlist> playlist;
4770         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4771         RegionSelection foo;
4772
4773         framepos_t const start_frame = regions.start ();
4774         framepos_t const end_frame = regions.end_frame ();
4775         framecnt_t const gap = end_frame - start_frame + 1;
4776
4777         begin_reversible_command (Operations::duplicate_region);
4778
4779         selection->clear_regions ();
4780
4781         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4782
4783                 boost::shared_ptr<Region> r ((*i)->region());
4784
4785                 TimeAxisView& tv = (*i)->get_time_axis_view();
4786                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4787                 latest_regionviews.clear ();
4788                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4789
4790                 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4791                 playlist = (*i)->region()->playlist();
4792                 playlist->clear_changes ();
4793                 playlist->duplicate (r, position, gap, times);
4794                 _session->add_command(new StatefulDiffCommand (playlist));
4795
4796                 c.disconnect ();
4797
4798                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4799         }
4800
4801         if (!foo.empty()) {
4802                 selection->set (foo);
4803         }
4804
4805         commit_reversible_command ();
4806 }
4807
4808 void
4809 Editor::duplicate_selection (float times)
4810 {
4811         if (selection->time.empty() || selection->tracks.empty()) {
4812                 return;
4813         }
4814
4815         boost::shared_ptr<Playlist> playlist;
4816
4817         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4818
4819         bool in_command = false;
4820
4821         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4822                 if ((playlist = (*i)->playlist()) == 0) {
4823                         continue;
4824                 }
4825                 playlist->clear_changes ();
4826
4827                 if (clicked_selection) {
4828                         playlist->duplicate_range (selection->time[clicked_selection], times);
4829                 } else {
4830                         playlist->duplicate_ranges (selection->time, times);
4831                 }
4832
4833                 if (!in_command) {
4834                         begin_reversible_command (_("duplicate range selection"));
4835                         in_command = true;
4836                 }
4837                 _session->add_command (new StatefulDiffCommand (playlist));
4838
4839         }
4840
4841         if (in_command) {
4842                 // now "move" range selection to after the current range selection
4843                 framecnt_t distance = 0;
4844
4845                 if (clicked_selection) {
4846                         distance = selection->time[clicked_selection].end -
4847                                    selection->time[clicked_selection].start;
4848                 } else {
4849                         distance = selection->time.end_frame() - selection->time.start();
4850                 }
4851
4852                 selection->move_time (distance);
4853
4854                 commit_reversible_command ();
4855         }
4856 }
4857
4858 /** Reset all selected points to the relevant default value */
4859 void
4860 Editor::reset_point_selection ()
4861 {
4862         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4863                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4864                 (*j)->value = (*i)->line().the_list()->default_value ();
4865         }
4866 }
4867
4868 void
4869 Editor::center_playhead ()
4870 {
4871         float const page = _visible_canvas_width * samples_per_pixel;
4872         center_screen_internal (playhead_cursor->current_frame (), page);
4873 }
4874
4875 void
4876 Editor::center_edit_point ()
4877 {
4878         float const page = _visible_canvas_width * samples_per_pixel;
4879         center_screen_internal (get_preferred_edit_position(), page);
4880 }
4881
4882 /** Caller must begin and commit a reversible command */
4883 void
4884 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4885 {
4886         playlist->clear_changes ();
4887         playlist->clear ();
4888         _session->add_command (new StatefulDiffCommand (playlist));
4889 }
4890
4891 void
4892 Editor::nudge_track (bool use_edit, bool forwards)
4893 {
4894         boost::shared_ptr<Playlist> playlist;
4895         framepos_t distance;
4896         framepos_t next_distance;
4897         framepos_t start;
4898
4899         if (use_edit) {
4900                 start = get_preferred_edit_position();
4901         } else {
4902                 start = 0;
4903         }
4904
4905         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4906                 return;
4907         }
4908
4909         if (selection->tracks.empty()) {
4910                 return;
4911         }
4912
4913         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4914         bool in_command = false;
4915
4916         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4917
4918                 if ((playlist = (*i)->playlist()) == 0) {
4919                         continue;
4920                 }
4921
4922                 playlist->clear_changes ();
4923                 playlist->clear_owned_changes ();
4924
4925                 playlist->nudge_after (start, distance, forwards);
4926
4927                 if (!in_command) {
4928                         begin_reversible_command (_("nudge track"));
4929                         in_command = true;
4930                 }
4931                 vector<Command*> cmds;
4932
4933                 playlist->rdiff (cmds);
4934                 _session->add_commands (cmds);
4935
4936                 _session->add_command (new StatefulDiffCommand (playlist));
4937         }
4938
4939         if (in_command) {
4940                 commit_reversible_command ();
4941         }
4942 }
4943
4944 void
4945 Editor::remove_last_capture ()
4946 {
4947         vector<string> choices;
4948         string prompt;
4949
4950         if (!_session) {
4951                 return;
4952         }
4953
4954         if (Config->get_verify_remove_last_capture()) {
4955                 prompt  = _("Do you really want to destroy the last capture?"
4956                             "\n(This is destructive and cannot be undone)");
4957
4958                 choices.push_back (_("No, do nothing."));
4959                 choices.push_back (_("Yes, destroy it."));
4960
4961                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4962
4963                 if (prompter.run () == 1) {
4964                         _session->remove_last_capture ();
4965                         _regions->redisplay ();
4966                 }
4967
4968         } else {
4969                 _session->remove_last_capture();
4970                 _regions->redisplay ();
4971         }
4972 }
4973
4974 void
4975 Editor::normalize_region ()
4976 {
4977         if (!_session) {
4978                 return;
4979         }
4980
4981         RegionSelection rs = get_regions_from_selection_and_entered ();
4982
4983         if (rs.empty()) {
4984                 return;
4985         }
4986
4987         NormalizeDialog dialog (rs.size() > 1);
4988
4989         if (dialog.run () == RESPONSE_CANCEL) {
4990                 return;
4991         }
4992
4993         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4994         gdk_flush ();
4995
4996         /* XXX: should really only count audio regions here */
4997         int const regions = rs.size ();
4998
4999         /* Make a list of the selected audio regions' maximum amplitudes, and also
5000            obtain the maximum amplitude of them all.
5001         */
5002         list<double> max_amps;
5003         double max_amp = 0;
5004         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5005                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5006                 if (arv) {
5007                         dialog.descend (1.0 / regions);
5008                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
5009
5010                         if (a == -1) {
5011                                 /* the user cancelled the operation */
5012                                 return;
5013                         }
5014
5015                         max_amps.push_back (a);
5016                         max_amp = max (max_amp, a);
5017                         dialog.ascend ();
5018                 }
5019         }
5020
5021         list<double>::const_iterator a = max_amps.begin ();
5022         bool in_command = false;
5023
5024         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5025                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5026                 if (!arv) {
5027                         continue;
5028                 }
5029
5030                 arv->region()->clear_changes ();
5031
5032                 double const amp = dialog.normalize_individually() ? *a : max_amp;
5033
5034                 arv->audio_region()->normalize (amp, dialog.target ());
5035
5036                 if (!in_command) {
5037                         begin_reversible_command (_("normalize"));
5038                         in_command = true;
5039                 }
5040                 _session->add_command (new StatefulDiffCommand (arv->region()));
5041
5042                 ++a;
5043         }
5044
5045         if (in_command) {
5046                 commit_reversible_command ();
5047         }
5048 }
5049
5050
5051 void
5052 Editor::reset_region_scale_amplitude ()
5053 {
5054         if (!_session) {
5055                 return;
5056         }
5057
5058         RegionSelection rs = get_regions_from_selection_and_entered ();
5059
5060         if (rs.empty()) {
5061                 return;
5062         }
5063
5064         bool in_command = false;
5065
5066         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5067                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5068                 if (!arv)
5069                         continue;
5070                 arv->region()->clear_changes ();
5071                 arv->audio_region()->set_scale_amplitude (1.0f);
5072
5073                 if(!in_command) {
5074                                 begin_reversible_command ("reset gain");
5075                                 in_command = true;
5076                 }
5077                 _session->add_command (new StatefulDiffCommand (arv->region()));
5078         }
5079
5080         if (in_command) {
5081                 commit_reversible_command ();
5082         }
5083 }
5084
5085 void
5086 Editor::adjust_region_gain (bool up)
5087 {
5088         RegionSelection rs = get_regions_from_selection_and_entered ();
5089
5090         if (!_session || rs.empty()) {
5091                 return;
5092         }
5093
5094         bool in_command = false;
5095
5096         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5097                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5098                 if (!arv) {
5099                         continue;
5100                 }
5101
5102                 arv->region()->clear_changes ();
5103
5104                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5105
5106                 if (up) {
5107                         dB += 1;
5108                 } else {
5109                         dB -= 1;
5110                 }
5111
5112                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5113
5114                 if (!in_command) {
5115                                 begin_reversible_command ("adjust region gain");
5116                                 in_command = true;
5117                 }
5118                 _session->add_command (new StatefulDiffCommand (arv->region()));
5119         }
5120
5121         if (in_command) {
5122                 commit_reversible_command ();
5123         }
5124 }
5125
5126
5127 void
5128 Editor::reverse_region ()
5129 {
5130         if (!_session) {
5131                 return;
5132         }
5133
5134         Reverse rev (*_session);
5135         apply_filter (rev, _("reverse regions"));
5136 }
5137
5138 void
5139 Editor::strip_region_silence ()
5140 {
5141         if (!_session) {
5142                 return;
5143         }
5144
5145         RegionSelection rs = get_regions_from_selection_and_entered ();
5146
5147         if (rs.empty()) {
5148                 return;
5149         }
5150
5151         std::list<RegionView*> audio_only;
5152
5153         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5154                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5155                 if (arv) {
5156                         audio_only.push_back (arv);
5157                 }
5158         }
5159
5160         assert (!audio_only.empty());
5161
5162         StripSilenceDialog d (_session, audio_only);
5163         int const r = d.run ();
5164
5165         d.drop_rects ();
5166
5167         if (r == Gtk::RESPONSE_OK) {
5168                 ARDOUR::AudioIntervalMap silences;
5169                 d.silences (silences);
5170                 StripSilence s (*_session, silences, d.fade_length());
5171
5172                 apply_filter (s, _("strip silence"), &d);
5173         }
5174 }
5175
5176 Command*
5177 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5178 {
5179         Evoral::Sequence<Evoral::Beats>::Notes selected;
5180         mrv.selection_as_notelist (selected, true);
5181
5182         vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5183         v.push_back (selected);
5184
5185         framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5186         Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5187
5188         return op (mrv.midi_region()->model(), pos_beats, v);
5189 }
5190
5191 void
5192 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5193 {
5194         if (rs.empty()) {
5195                 return;
5196         }
5197
5198         bool in_command = false;
5199
5200         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5201                 RegionSelection::const_iterator tmp = r;
5202                 ++tmp;
5203
5204                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5205
5206                 if (mrv) {
5207                         Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5208                         if (cmd) {
5209                                 if (!in_command) {
5210                                         begin_reversible_command (op.name ());
5211                                         in_command = true;
5212                                 }
5213                                 (*cmd)();
5214                                 _session->add_command (cmd);
5215                         }
5216                 }
5217
5218                 r = tmp;
5219         }
5220
5221         if (in_command) {
5222                 commit_reversible_command ();
5223         }
5224 }
5225
5226 void
5227 Editor::fork_region ()
5228 {
5229         RegionSelection rs = get_regions_from_selection_and_entered ();
5230
5231         if (rs.empty()) {
5232                 return;
5233         }
5234
5235         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5236         bool in_command = false;
5237
5238         gdk_flush ();
5239
5240         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5241                 RegionSelection::iterator tmp = r;
5242                 ++tmp;
5243
5244                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5245
5246                 if (mrv) {
5247                         try {
5248                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5249                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5250                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5251
5252                                 if (!in_command) {
5253                                         begin_reversible_command (_("Fork Region(s)"));
5254                                         in_command = true;
5255                                 }
5256                                 playlist->clear_changes ();
5257                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5258                                 _session->add_command(new StatefulDiffCommand (playlist));
5259                         } catch (...) {
5260                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5261                         }
5262                 }
5263
5264                 r = tmp;
5265         }
5266
5267         if (in_command) {
5268                 commit_reversible_command ();
5269         }
5270 }
5271
5272 void
5273 Editor::quantize_region ()
5274 {
5275         if (_session) {
5276                 quantize_regions(get_regions_from_selection_and_entered ());
5277         }
5278 }
5279
5280 void
5281 Editor::quantize_regions (const RegionSelection& rs)
5282 {
5283         if (rs.n_midi_regions() == 0) {
5284                 return;
5285         }
5286
5287         if (!quantize_dialog) {
5288                 quantize_dialog = new QuantizeDialog (*this);
5289         }
5290
5291         quantize_dialog->present ();
5292         const int r = quantize_dialog->run ();
5293         quantize_dialog->hide ();
5294
5295         if (r == Gtk::RESPONSE_OK) {
5296                 Quantize quant (quantize_dialog->snap_start(),
5297                                 quantize_dialog->snap_end(),
5298                                 quantize_dialog->start_grid_size(),
5299                                 quantize_dialog->end_grid_size(),
5300                                 quantize_dialog->strength(),
5301                                 quantize_dialog->swing(),
5302                                 quantize_dialog->threshold());
5303
5304                 apply_midi_note_edit_op (quant, rs);
5305         }
5306 }
5307
5308 void
5309 Editor::legatize_region (bool shrink_only)
5310 {
5311         if (_session) {
5312                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5313         }
5314 }
5315
5316 void
5317 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5318 {
5319         if (rs.n_midi_regions() == 0) {
5320                 return;
5321         }
5322
5323         Legatize legatize(shrink_only);
5324         apply_midi_note_edit_op (legatize, rs);
5325 }
5326
5327 void
5328 Editor::transform_region ()
5329 {
5330         if (_session) {
5331                 transform_regions(get_regions_from_selection_and_entered ());
5332         }
5333 }
5334
5335 void
5336 Editor::transform_regions (const RegionSelection& rs)
5337 {
5338         if (rs.n_midi_regions() == 0) {
5339                 return;
5340         }
5341
5342         TransformDialog td;
5343
5344         td.present();
5345         const int r = td.run();
5346         td.hide();
5347
5348         if (r == Gtk::RESPONSE_OK) {
5349                 Transform transform(td.get());
5350                 apply_midi_note_edit_op(transform, rs);
5351         }
5352 }
5353
5354 void
5355 Editor::transpose_region ()
5356 {
5357         if (_session) {
5358                 transpose_regions(get_regions_from_selection_and_entered ());
5359         }
5360 }
5361
5362 void
5363 Editor::transpose_regions (const RegionSelection& rs)
5364 {
5365         if (rs.n_midi_regions() == 0) {
5366                 return;
5367         }
5368
5369         TransposeDialog d;
5370         int const r = d.run ();
5371
5372         if (r == RESPONSE_ACCEPT) {
5373                 Transpose transpose(d.semitones ());
5374                 apply_midi_note_edit_op (transpose, rs);
5375         }
5376 }
5377
5378 void
5379 Editor::insert_patch_change (bool from_context)
5380 {
5381         RegionSelection rs = get_regions_from_selection_and_entered ();
5382
5383         if (rs.empty ()) {
5384                 return;
5385         }
5386
5387         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5388
5389         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5390            there may be more than one, but the PatchChangeDialog can only offer
5391            one set of patch menus.
5392         */
5393         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5394
5395         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5396         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5397
5398         if (d.run() == RESPONSE_CANCEL) {
5399                 return;
5400         }
5401
5402         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5403                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5404                 if (mrv) {
5405                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5406                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5407                         }
5408                 }
5409         }
5410 }
5411
5412 void
5413 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5414 {
5415         RegionSelection rs = get_regions_from_selection_and_entered ();
5416
5417         if (rs.empty()) {
5418                 return;
5419         }
5420
5421         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5422         bool in_command = false;
5423
5424         gdk_flush ();
5425
5426         int n = 0;
5427         int const N = rs.size ();
5428
5429         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5430                 RegionSelection::iterator tmp = r;
5431                 ++tmp;
5432
5433                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5434                 if (arv) {
5435                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5436
5437                         if (progress) {
5438                                 progress->descend (1.0 / N);
5439                         }
5440
5441                         if (arv->audio_region()->apply (filter, progress) == 0) {
5442
5443                                 playlist->clear_changes ();
5444                                 playlist->clear_owned_changes ();
5445
5446                                 if (!in_command) {
5447                                         begin_reversible_command (command);
5448                                         in_command = true;
5449                                 }
5450
5451                                 if (filter.results.empty ()) {
5452
5453                                         /* no regions returned; remove the old one */
5454                                         playlist->remove_region (arv->region ());
5455
5456                                 } else {
5457
5458                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5459
5460                                         /* first region replaces the old one */
5461                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5462                                         ++res;
5463
5464                                         /* add the rest */
5465                                         while (res != filter.results.end()) {
5466                                                 playlist->add_region (*res, (*res)->position());
5467                                                 ++res;
5468                                         }
5469
5470                                 }
5471
5472                                 /* We might have removed regions, which alters other regions' layering_index,
5473                                    so we need to do a recursive diff here.
5474                                 */
5475                                 vector<Command*> cmds;
5476                                 playlist->rdiff (cmds);
5477                                 _session->add_commands (cmds);
5478
5479                                 _session->add_command(new StatefulDiffCommand (playlist));
5480                         }
5481
5482                         if (progress) {
5483                                 progress->ascend ();
5484                         }
5485                 }
5486
5487                 r = tmp;
5488                 ++n;
5489         }
5490
5491         if (in_command) {
5492                 commit_reversible_command ();
5493         }
5494 }
5495
5496 void
5497 Editor::external_edit_region ()
5498 {
5499         /* more to come */
5500 }
5501
5502 void
5503 Editor::reset_region_gain_envelopes ()
5504 {
5505         RegionSelection rs = get_regions_from_selection_and_entered ();
5506
5507         if (!_session || rs.empty()) {
5508                 return;
5509         }
5510
5511         bool in_command = false;
5512
5513         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5514                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5515                 if (arv) {
5516                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5517                         XMLNode& before (alist->get_state());
5518
5519                         arv->audio_region()->set_default_envelope ();
5520
5521                         if (!in_command) {
5522                                 begin_reversible_command (_("reset region gain"));
5523                                 in_command = true;
5524                         }
5525                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5526                 }
5527         }
5528
5529         if (in_command) {
5530                 commit_reversible_command ();
5531         }
5532 }
5533
5534 void
5535 Editor::set_region_gain_visibility (RegionView* rv)
5536 {
5537         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5538         if (arv) {
5539                 arv->update_envelope_visibility();
5540         }
5541 }
5542
5543 void
5544 Editor::set_gain_envelope_visibility ()
5545 {
5546         if (!_session) {
5547                 return;
5548         }
5549
5550         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5551                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5552                 if (v) {
5553                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5554                 }
5555         }
5556 }
5557
5558 void
5559 Editor::toggle_gain_envelope_active ()
5560 {
5561         if (_ignore_region_action) {
5562                 return;
5563         }
5564
5565         RegionSelection rs = get_regions_from_selection_and_entered ();
5566
5567         if (!_session || rs.empty()) {
5568                 return;
5569         }
5570
5571         bool in_command = false;
5572
5573         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5574                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5575                 if (arv) {
5576                         arv->region()->clear_changes ();
5577                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5578
5579                         if (!in_command) {
5580                                 begin_reversible_command (_("region gain envelope active"));
5581                                 in_command = true;
5582                         }
5583                         _session->add_command (new StatefulDiffCommand (arv->region()));
5584                 }
5585         }
5586
5587         if (in_command) {
5588                 commit_reversible_command ();
5589         }
5590 }
5591
5592 void
5593 Editor::toggle_region_lock ()
5594 {
5595         if (_ignore_region_action) {
5596                 return;
5597         }
5598
5599         RegionSelection rs = get_regions_from_selection_and_entered ();
5600
5601         if (!_session || rs.empty()) {
5602                 return;
5603         }
5604
5605         begin_reversible_command (_("toggle region lock"));
5606
5607         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5608                 (*i)->region()->clear_changes ();
5609                 (*i)->region()->set_locked (!(*i)->region()->locked());
5610                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5611         }
5612
5613         commit_reversible_command ();
5614 }
5615
5616 void
5617 Editor::toggle_region_video_lock ()
5618 {
5619         if (_ignore_region_action) {
5620                 return;
5621         }
5622
5623         RegionSelection rs = get_regions_from_selection_and_entered ();
5624
5625         if (!_session || rs.empty()) {
5626                 return;
5627         }
5628
5629         begin_reversible_command (_("Toggle Video Lock"));
5630
5631         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5632                 (*i)->region()->clear_changes ();
5633                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5634                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5635         }
5636
5637         commit_reversible_command ();
5638 }
5639
5640 void
5641 Editor::toggle_region_lock_style ()
5642 {
5643         if (_ignore_region_action) {
5644                 return;
5645         }
5646
5647         RegionSelection rs = get_regions_from_selection_and_entered ();
5648
5649         if (!_session || rs.empty()) {
5650                 return;
5651         }
5652
5653         begin_reversible_command (_("region lock style"));
5654
5655         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5656                 (*i)->region()->clear_changes ();
5657                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5658                 (*i)->region()->set_position_lock_style (ns);
5659                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5660         }
5661
5662         commit_reversible_command ();
5663 }
5664
5665 void
5666 Editor::toggle_opaque_region ()
5667 {
5668         if (_ignore_region_action) {
5669                 return;
5670         }
5671
5672         RegionSelection rs = get_regions_from_selection_and_entered ();
5673
5674         if (!_session || rs.empty()) {
5675                 return;
5676         }
5677
5678         begin_reversible_command (_("change region opacity"));
5679
5680         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5681                 (*i)->region()->clear_changes ();
5682                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5683                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5684         }
5685
5686         commit_reversible_command ();
5687 }
5688
5689 void
5690 Editor::toggle_record_enable ()
5691 {
5692         bool new_state = false;
5693         bool first = true;
5694         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5695                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5696                 if (!rtav)
5697                         continue;
5698                 if (!rtav->is_track())
5699                         continue;
5700
5701                 if (first) {
5702                         new_state = !rtav->track()->rec_enable_control()->get_value();
5703                         first = false;
5704                 }
5705
5706                 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5707         }
5708 }
5709
5710 void
5711 Editor::toggle_solo ()
5712 {
5713         bool new_state = false;
5714         bool first = true;
5715         boost::shared_ptr<ControlList> cl (new ControlList);
5716
5717         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5718                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5719
5720                 if (!rtav) {
5721                         continue;
5722                 }
5723
5724                 if (first) {
5725                         new_state = !rtav->route()->soloed ();
5726                         first = false;
5727                 }
5728
5729                 cl->push_back (rtav->route()->solo_control());
5730         }
5731
5732         _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5733 }
5734
5735 void
5736 Editor::toggle_mute ()
5737 {
5738         bool new_state = false;
5739         bool first = true;
5740         boost::shared_ptr<RouteList> rl (new RouteList);
5741
5742         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5743                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5744
5745                 if (!rtav) {
5746                         continue;
5747                 }
5748
5749                 if (first) {
5750                         new_state = !rtav->route()->muted();
5751                         first = false;
5752                 }
5753
5754                 rl->push_back (rtav->route());
5755         }
5756
5757         _session->set_controls (route_list_to_control_list (rl, &Route::mute_control), new_state, Controllable::UseGroup);
5758 }
5759
5760 void
5761 Editor::toggle_solo_isolate ()
5762 {
5763 }
5764
5765
5766 void
5767 Editor::fade_range ()
5768 {
5769         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5770
5771         begin_reversible_command (_("fade range"));
5772
5773         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5774                 (*i)->fade_range (selection->time);
5775         }
5776
5777         commit_reversible_command ();
5778 }
5779
5780
5781 void
5782 Editor::set_fade_length (bool in)
5783 {
5784         RegionSelection rs = get_regions_from_selection_and_entered ();
5785
5786         if (rs.empty()) {
5787                 return;
5788         }
5789
5790         /* we need a region to measure the offset from the start */
5791
5792         RegionView* rv = rs.front ();
5793
5794         framepos_t pos = get_preferred_edit_position();
5795         framepos_t len;
5796         char const * cmd;
5797
5798         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5799                 /* edit point is outside the relevant region */
5800                 return;
5801         }
5802
5803         if (in) {
5804                 if (pos <= rv->region()->position()) {
5805                         /* can't do it */
5806                         return;
5807                 }
5808                 len = pos - rv->region()->position();
5809                 cmd = _("set fade in length");
5810         } else {
5811                 if (pos >= rv->region()->last_frame()) {
5812                         /* can't do it */
5813                         return;
5814                 }
5815                 len = rv->region()->last_frame() - pos;
5816                 cmd = _("set fade out length");
5817         }
5818
5819         bool in_command = false;
5820
5821         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5822                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5823
5824                 if (!tmp) {
5825                         continue;
5826                 }
5827
5828                 boost::shared_ptr<AutomationList> alist;
5829                 if (in) {
5830                         alist = tmp->audio_region()->fade_in();
5831                 } else {
5832                         alist = tmp->audio_region()->fade_out();
5833                 }
5834
5835                 XMLNode &before = alist->get_state();
5836
5837                 if (in) {
5838                         tmp->audio_region()->set_fade_in_length (len);
5839                         tmp->audio_region()->set_fade_in_active (true);
5840                 } else {
5841                         tmp->audio_region()->set_fade_out_length (len);
5842                         tmp->audio_region()->set_fade_out_active (true);
5843                 }
5844
5845                 if (!in_command) {
5846                         begin_reversible_command (cmd);
5847                         in_command = true;
5848                 }
5849                 XMLNode &after = alist->get_state();
5850                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5851         }
5852
5853         if (in_command) {
5854                 commit_reversible_command ();
5855         }
5856 }
5857
5858 void
5859 Editor::set_fade_in_shape (FadeShape shape)
5860 {
5861         RegionSelection rs = get_regions_from_selection_and_entered ();
5862
5863         if (rs.empty()) {
5864                 return;
5865         }
5866         bool in_command = false;
5867
5868         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5869                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5870
5871                 if (!tmp) {
5872                         continue;
5873                 }
5874
5875                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5876                 XMLNode &before = alist->get_state();
5877
5878                 tmp->audio_region()->set_fade_in_shape (shape);
5879
5880                 if (!in_command) {
5881                         begin_reversible_command (_("set fade in shape"));
5882                         in_command = true;
5883                 }
5884                 XMLNode &after = alist->get_state();
5885                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5886         }
5887
5888         if (in_command) {
5889                 commit_reversible_command ();
5890         }
5891 }
5892
5893 void
5894 Editor::set_fade_out_shape (FadeShape shape)
5895 {
5896         RegionSelection rs = get_regions_from_selection_and_entered ();
5897
5898         if (rs.empty()) {
5899                 return;
5900         }
5901         bool in_command = false;
5902
5903         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5904                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5905
5906                 if (!tmp) {
5907                         continue;
5908                 }
5909
5910                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5911                 XMLNode &before = alist->get_state();
5912
5913                 tmp->audio_region()->set_fade_out_shape (shape);
5914
5915                 if(!in_command) {
5916                         begin_reversible_command (_("set fade out shape"));
5917                         in_command = true;
5918                 }
5919                 XMLNode &after = alist->get_state();
5920                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5921         }
5922
5923         if (in_command) {
5924                 commit_reversible_command ();
5925         }
5926 }
5927
5928 void
5929 Editor::set_fade_in_active (bool yn)
5930 {
5931         RegionSelection rs = get_regions_from_selection_and_entered ();
5932
5933         if (rs.empty()) {
5934                 return;
5935         }
5936         bool in_command = false;
5937
5938         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5939                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5940
5941                 if (!tmp) {
5942                         continue;
5943                 }
5944
5945
5946                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5947
5948                 ar->clear_changes ();
5949                 ar->set_fade_in_active (yn);
5950
5951                 if (!in_command) {
5952                         begin_reversible_command (_("set fade in active"));
5953                         in_command = true;
5954                 }
5955                 _session->add_command (new StatefulDiffCommand (ar));
5956         }
5957
5958         if (in_command) {
5959                 commit_reversible_command ();
5960         }
5961 }
5962
5963 void
5964 Editor::set_fade_out_active (bool yn)
5965 {
5966         RegionSelection rs = get_regions_from_selection_and_entered ();
5967
5968         if (rs.empty()) {
5969                 return;
5970         }
5971         bool in_command = false;
5972
5973         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5974                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5975
5976                 if (!tmp) {
5977                         continue;
5978                 }
5979
5980                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5981
5982                 ar->clear_changes ();
5983                 ar->set_fade_out_active (yn);
5984
5985                 if (!in_command) {
5986                         begin_reversible_command (_("set fade out active"));
5987                         in_command = true;
5988                 }
5989                 _session->add_command(new StatefulDiffCommand (ar));
5990         }
5991
5992         if (in_command) {
5993                 commit_reversible_command ();
5994         }
5995 }
5996
5997 void
5998 Editor::toggle_region_fades (int dir)
5999 {
6000         if (_ignore_region_action) {
6001                 return;
6002         }
6003
6004         boost::shared_ptr<AudioRegion> ar;
6005         bool yn = false;
6006
6007         RegionSelection rs = get_regions_from_selection_and_entered ();
6008
6009         if (rs.empty()) {
6010                 return;
6011         }
6012
6013         RegionSelection::iterator i;
6014         for (i = rs.begin(); i != rs.end(); ++i) {
6015                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6016                         if (dir == -1) {
6017                                 yn = ar->fade_out_active ();
6018                         } else {
6019                                 yn = ar->fade_in_active ();
6020                         }
6021                         break;
6022                 }
6023         }
6024
6025         if (i == rs.end()) {
6026                 return;
6027         }
6028
6029         /* XXX should this undo-able? */
6030         bool in_command = false;
6031
6032         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6033                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6034                         continue;
6035                 }
6036                 ar->clear_changes ();
6037
6038                 if (dir == 1 || dir == 0) {
6039                         ar->set_fade_in_active (!yn);
6040                 }
6041
6042                 if (dir == -1 || dir == 0) {
6043                         ar->set_fade_out_active (!yn);
6044                 }
6045                 if (!in_command) {
6046                         begin_reversible_command (_("toggle fade active"));
6047                         in_command = true;
6048                 }
6049                 _session->add_command(new StatefulDiffCommand (ar));
6050         }
6051
6052         if (in_command) {
6053                 commit_reversible_command ();
6054         }
6055 }
6056
6057
6058 /** Update region fade visibility after its configuration has been changed */
6059 void
6060 Editor::update_region_fade_visibility ()
6061 {
6062         bool _fade_visibility = _session->config.get_show_region_fades ();
6063
6064         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6065                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6066                 if (v) {
6067                         if (_fade_visibility) {
6068                                 v->audio_view()->show_all_fades ();
6069                         } else {
6070                                 v->audio_view()->hide_all_fades ();
6071                         }
6072                 }
6073         }
6074 }
6075
6076 void
6077 Editor::set_edit_point ()
6078 {
6079         framepos_t where;
6080         bool ignored;
6081
6082         if (!mouse_frame (where, ignored)) {
6083                 return;
6084         }
6085
6086         snap_to (where);
6087
6088         if (selection->markers.empty()) {
6089
6090                 mouse_add_new_marker (where);
6091
6092         } else {
6093                 bool ignored;
6094
6095                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6096
6097                 if (loc) {
6098                         loc->move_to (where);
6099                 }
6100         }
6101 }
6102
6103 void
6104 Editor::set_playhead_cursor ()
6105 {
6106         if (entered_marker) {
6107                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6108         } else {
6109                 framepos_t where;
6110                 bool ignored;
6111
6112                 if (!mouse_frame (where, ignored)) {
6113                         return;
6114                 }
6115
6116                 snap_to (where);
6117
6118                 if (_session) {
6119                         _session->request_locate (where, _session->transport_rolling());
6120                 }
6121         }
6122
6123         if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6124                 cancel_time_selection();
6125         }
6126 }
6127
6128 void
6129 Editor::split_region ()
6130 {
6131         if (_drags->active ()) {
6132                 return;
6133         }
6134
6135         //if a range is selected, separate it
6136         if ( !selection->time.empty()) {
6137                 separate_regions_between (selection->time);
6138                 return;
6139         }
6140
6141         //if no range was selected, try to find some regions to split
6142         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
6143
6144                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6145
6146                 framepos_t where = get_preferred_edit_position ();
6147
6148                 if (rs.empty()) {
6149                         return;
6150                 }
6151
6152                 split_regions_at (where, rs);
6153         }
6154 }
6155
6156 void
6157 Editor::select_next_route()
6158 {
6159         if (selection->tracks.empty()) {
6160                 selection->set (track_views.front());
6161                 return;
6162         }
6163
6164         TimeAxisView* current = selection->tracks.front();
6165
6166         RouteUI *rui;
6167         do {
6168                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6169                         if (*i == current) {
6170                                 ++i;
6171                                 if (i != track_views.end()) {
6172                                         current = (*i);
6173                                 } else {
6174                                         current = (*(track_views.begin()));
6175                                         //selection->set (*(track_views.begin()));
6176                                 }
6177                                 break;
6178                         }
6179                 }
6180                 rui = dynamic_cast<RouteUI *>(current);
6181         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6182
6183         selection->set(current);
6184
6185         ensure_time_axis_view_is_visible (*current, false);
6186 }
6187
6188 void
6189 Editor::select_prev_route()
6190 {
6191         if (selection->tracks.empty()) {
6192                 selection->set (track_views.front());
6193                 return;
6194         }
6195
6196         TimeAxisView* current = selection->tracks.front();
6197
6198         RouteUI *rui;
6199         do {
6200                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6201                         if (*i == current) {
6202                                 ++i;
6203                                 if (i != track_views.rend()) {
6204                                         current = (*i);
6205                                 } else {
6206                                         current = *(track_views.rbegin());
6207                                 }
6208                                 break;
6209                         }
6210                 }
6211                 rui = dynamic_cast<RouteUI *>(current);
6212         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6213
6214         selection->set (current);
6215
6216         ensure_time_axis_view_is_visible (*current, false);
6217 }
6218
6219 void
6220 Editor::set_loop_from_selection (bool play)
6221 {
6222         if (_session == 0) {
6223                 return;
6224         }
6225
6226         framepos_t start, end;
6227         if (!get_selection_extents ( start, end))
6228                 return;
6229
6230         set_loop_range (start, end,  _("set loop range from selection"));
6231
6232         if (play) {
6233                 _session->request_play_loop (true, true);
6234         }
6235 }
6236
6237 void
6238 Editor::set_loop_from_region (bool play)
6239 {
6240         framepos_t start, end;
6241         if (!get_selection_extents ( start, end))
6242                 return;
6243
6244         set_loop_range (start, end, _("set loop range from region"));
6245
6246         if (play) {
6247                 _session->request_locate (start, true);
6248                 _session->request_play_loop (true);
6249         }
6250 }
6251
6252 void
6253 Editor::set_punch_from_selection ()
6254 {
6255         if (_session == 0) {
6256                 return;
6257         }
6258
6259         framepos_t start, end;
6260         if (!get_selection_extents ( start, end))
6261                 return;
6262
6263         set_punch_range (start, end,  _("set punch range from selection"));
6264 }
6265
6266 void
6267 Editor::set_session_extents_from_selection ()
6268 {
6269         if (_session == 0) {
6270                 return;
6271         }
6272
6273         framepos_t start, end;
6274         if (!get_selection_extents ( start, end))
6275                 return;
6276
6277         Location* loc;
6278         if ((loc = _session->locations()->session_range_location()) == 0) {
6279                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
6280         } else {
6281                 XMLNode &before = loc->get_state();
6282
6283                 _session->set_session_extents ( start, end );
6284
6285                 XMLNode &after = loc->get_state();
6286
6287                 begin_reversible_command (_("set session start/end from selection"));
6288
6289                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6290
6291                 commit_reversible_command ();
6292         }
6293 }
6294
6295 void
6296 Editor::set_punch_start_from_edit_point ()
6297 {
6298         if (_session) {
6299
6300                 framepos_t start = 0;
6301                 framepos_t end = max_framepos;
6302
6303                 //use the existing punch end, if any
6304                 Location* tpl = transport_punch_location();
6305                 if (tpl) {
6306                         end = tpl->end();
6307                 }
6308
6309                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6310                         start = _session->audible_frame();
6311                 } else {
6312                         start = get_preferred_edit_position();
6313                 }
6314
6315                 //snap the selection start/end
6316                 snap_to(start);
6317
6318                 //if there's not already a sensible selection endpoint, go "forever"
6319                 if ( start > end ) {
6320                         end = max_framepos;
6321                 }
6322
6323                 set_punch_range (start, end, _("set punch start from EP"));
6324         }
6325
6326 }
6327
6328 void
6329 Editor::set_punch_end_from_edit_point ()
6330 {
6331         if (_session) {
6332
6333                 framepos_t start = 0;
6334                 framepos_t end = max_framepos;
6335
6336                 //use the existing punch start, if any
6337                 Location* tpl = transport_punch_location();
6338                 if (tpl) {
6339                         start = tpl->start();
6340                 }
6341
6342                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6343                         end = _session->audible_frame();
6344                 } else {
6345                         end = get_preferred_edit_position();
6346                 }
6347
6348                 //snap the selection start/end
6349                 snap_to(end);
6350
6351                 set_punch_range (start, end, _("set punch end from EP"));
6352
6353         }
6354 }
6355
6356 void
6357 Editor::set_loop_start_from_edit_point ()
6358 {
6359         if (_session) {
6360
6361                 framepos_t start = 0;
6362                 framepos_t end = max_framepos;
6363
6364                 //use the existing loop end, if any
6365                 Location* tpl = transport_loop_location();
6366                 if (tpl) {
6367                         end = tpl->end();
6368                 }
6369
6370                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6371                         start = _session->audible_frame();
6372                 } else {
6373                         start = get_preferred_edit_position();
6374                 }
6375
6376                 //snap the selection start/end
6377                 snap_to(start);
6378
6379                 //if there's not already a sensible selection endpoint, go "forever"
6380                 if ( start > end ) {
6381                         end = max_framepos;
6382                 }
6383
6384                 set_loop_range (start, end, _("set loop start from EP"));
6385         }
6386
6387 }
6388
6389 void
6390 Editor::set_loop_end_from_edit_point ()
6391 {
6392         if (_session) {
6393
6394                 framepos_t start = 0;
6395                 framepos_t end = max_framepos;
6396
6397                 //use the existing loop start, if any
6398                 Location* tpl = transport_loop_location();
6399                 if (tpl) {
6400                         start = tpl->start();
6401                 }
6402
6403                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6404                         end = _session->audible_frame();
6405                 } else {
6406                         end = get_preferred_edit_position();
6407                 }
6408
6409                 //snap the selection start/end
6410                 snap_to(end);
6411
6412                 set_loop_range (start, end, _("set loop end from EP"));
6413         }
6414 }
6415
6416 void
6417 Editor::set_punch_from_region ()
6418 {
6419         framepos_t start, end;
6420         if (!get_selection_extents ( start, end))
6421                 return;
6422
6423         set_punch_range (start, end, _("set punch range from region"));
6424 }
6425
6426 void
6427 Editor::pitch_shift_region ()
6428 {
6429         RegionSelection rs = get_regions_from_selection_and_entered ();
6430
6431         RegionSelection audio_rs;
6432         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6433                 if (dynamic_cast<AudioRegionView*> (*i)) {
6434                         audio_rs.push_back (*i);
6435                 }
6436         }
6437
6438         if (audio_rs.empty()) {
6439                 return;
6440         }
6441
6442         pitch_shift (audio_rs, 1.2);
6443 }
6444
6445 void
6446 Editor::set_tempo_from_region ()
6447 {
6448         RegionSelection rs = get_regions_from_selection_and_entered ();
6449
6450         if (!_session || rs.empty()) {
6451                 return;
6452         }
6453
6454         RegionView* rv = rs.front();
6455
6456         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6457 }
6458
6459 void
6460 Editor::use_range_as_bar ()
6461 {
6462         framepos_t start, end;
6463         if (get_edit_op_range (start, end)) {
6464                 define_one_bar (start, end);
6465         }
6466 }
6467
6468 void
6469 Editor::define_one_bar (framepos_t start, framepos_t end)
6470 {
6471         framepos_t length = end - start;
6472
6473         const Meter& m (_session->tempo_map().meter_at_frame (start));
6474
6475         /* length = 1 bar */
6476
6477         /* We're going to deliver a constant tempo here,
6478            so we can use frames per beat to determine length.
6479            now we want frames per beat.
6480            we have frames per bar, and beats per bar, so ...
6481         */
6482
6483         /* XXXX METER MATH */
6484
6485         double frames_per_beat = length / m.divisions_per_bar();
6486
6487         /* beats per minute = */
6488
6489         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6490
6491         /* now decide whether to:
6492
6493             (a) set global tempo
6494             (b) add a new tempo marker
6495
6496         */
6497
6498         const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6499
6500         bool do_global = false;
6501
6502         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6503
6504                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6505                    at the start, or create a new marker
6506                 */
6507
6508                 vector<string> options;
6509                 options.push_back (_("Cancel"));
6510                 options.push_back (_("Add new marker"));
6511                 options.push_back (_("Set global tempo"));
6512
6513                 Choice c (
6514                         _("Define one bar"),
6515                         _("Do you want to set the global tempo or add a new tempo marker?"),
6516                         options
6517                         );
6518
6519                 c.set_default_response (2);
6520
6521                 switch (c.run()) {
6522                 case 0:
6523                         return;
6524
6525                 case 2:
6526                         do_global = true;
6527                         break;
6528
6529                 default:
6530                         do_global = false;
6531                 }
6532
6533         } else {
6534
6535                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6536                    if the marker is at the region starter, change it, otherwise add
6537                    a new tempo marker
6538                 */
6539         }
6540
6541         begin_reversible_command (_("set tempo from region"));
6542         XMLNode& before (_session->tempo_map().get_state());
6543
6544         if (do_global) {
6545                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6546         } else if (t.frame() == start) {
6547                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6548         } else {
6549                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), 0.0, start, TempoSection::Constant, AudioTime);
6550         }
6551
6552         XMLNode& after (_session->tempo_map().get_state());
6553
6554         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6555         commit_reversible_command ();
6556 }
6557
6558 void
6559 Editor::split_region_at_transients ()
6560 {
6561         AnalysisFeatureList positions;
6562
6563         RegionSelection rs = get_regions_from_selection_and_entered ();
6564
6565         if (!_session || rs.empty()) {
6566                 return;
6567         }
6568
6569         begin_reversible_command (_("split regions"));
6570
6571         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6572
6573                 RegionSelection::iterator tmp;
6574
6575                 tmp = i;
6576                 ++tmp;
6577
6578                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6579
6580                 if (ar) {
6581                         ar->transients (positions);
6582                         split_region_at_points ((*i)->region(), positions, true);
6583                         positions.clear ();
6584                 }
6585
6586                 i = tmp;
6587         }
6588
6589         commit_reversible_command ();
6590
6591 }
6592
6593 void
6594 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6595 {
6596         bool use_rhythmic_rodent = false;
6597
6598         boost::shared_ptr<Playlist> pl = r->playlist();
6599
6600         list<boost::shared_ptr<Region> > new_regions;
6601
6602         if (!pl) {
6603                 return;
6604         }
6605
6606         if (positions.empty()) {
6607                 return;
6608         }
6609
6610         if (positions.size() > 20 && can_ferret) {
6611                 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6612                 MessageDialog msg (msgstr,
6613                                    false,
6614                                    Gtk::MESSAGE_INFO,
6615                                    Gtk::BUTTONS_OK_CANCEL);
6616
6617                 if (can_ferret) {
6618                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6619                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6620                 } else {
6621                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6622                 }
6623
6624                 msg.set_title (_("Excessive split?"));
6625                 msg.present ();
6626
6627                 int response = msg.run();
6628                 msg.hide ();
6629
6630                 switch (response) {
6631                 case RESPONSE_OK:
6632                         break;
6633                 case RESPONSE_APPLY:
6634                         use_rhythmic_rodent = true;
6635                         break;
6636                 default:
6637                         return;
6638                 }
6639         }
6640
6641         if (use_rhythmic_rodent) {
6642                 show_rhythm_ferret ();
6643                 return;
6644         }
6645
6646         AnalysisFeatureList::const_iterator x;
6647
6648         pl->clear_changes ();
6649         pl->clear_owned_changes ();
6650
6651         x = positions.begin();
6652
6653         if (x == positions.end()) {
6654                 return;
6655         }
6656
6657         pl->freeze ();
6658         pl->remove_region (r);
6659
6660         framepos_t pos = 0;
6661
6662         framepos_t rstart = r->first_frame ();
6663         framepos_t rend = r->last_frame ();
6664
6665         while (x != positions.end()) {
6666
6667                 /* deal with positons that are out of scope of present region bounds */
6668                 if (*x <= rstart || *x > rend) {
6669                         ++x;
6670                         continue;
6671                 }
6672
6673                 /* file start = original start + how far we from the initial position ?  */
6674
6675                 framepos_t file_start = r->start() + pos;
6676
6677                 /* length = next position - current position */
6678
6679                 framepos_t len = (*x) - pos - rstart;
6680
6681                 /* XXX we do we really want to allow even single-sample regions?
6682                  * shouldn't we have some kind of lower limit on region size?
6683                  */
6684
6685                 if (len <= 0) {
6686                         break;
6687                 }
6688
6689                 string new_name;
6690
6691                 if (RegionFactory::region_name (new_name, r->name())) {
6692                         break;
6693                 }
6694
6695                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6696
6697                 PropertyList plist;
6698
6699                 plist.add (ARDOUR::Properties::start, file_start);
6700                 plist.add (ARDOUR::Properties::length, len);
6701                 plist.add (ARDOUR::Properties::name, new_name);
6702                 plist.add (ARDOUR::Properties::layer, 0);
6703                 // TODO set transients_offset
6704
6705                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6706                 /* because we set annouce to false, manually add the new region to the
6707                  * RegionFactory map
6708                  */
6709                 RegionFactory::map_add (nr);
6710
6711                 pl->add_region (nr, rstart + pos);
6712
6713                 if (select_new) {
6714                         new_regions.push_front(nr);
6715                 }
6716
6717                 pos += len;
6718                 ++x;
6719         }
6720
6721         string new_name;
6722
6723         RegionFactory::region_name (new_name, r->name());
6724
6725         /* Add the final region */
6726         PropertyList plist;
6727
6728         plist.add (ARDOUR::Properties::start, r->start() + pos);
6729         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6730         plist.add (ARDOUR::Properties::name, new_name);
6731         plist.add (ARDOUR::Properties::layer, 0);
6732
6733         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6734         /* because we set annouce to false, manually add the new region to the
6735            RegionFactory map
6736         */
6737         RegionFactory::map_add (nr);
6738         pl->add_region (nr, r->position() + pos);
6739
6740         if (select_new) {
6741                 new_regions.push_front(nr);
6742         }
6743
6744         pl->thaw ();
6745
6746         /* We might have removed regions, which alters other regions' layering_index,
6747            so we need to do a recursive diff here.
6748         */
6749         vector<Command*> cmds;
6750         pl->rdiff (cmds);
6751         _session->add_commands (cmds);
6752
6753         _session->add_command (new StatefulDiffCommand (pl));
6754
6755         if (select_new) {
6756
6757                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6758                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6759                 }
6760         }
6761 }
6762
6763 void
6764 Editor::place_transient()
6765 {
6766         if (!_session) {
6767                 return;
6768         }
6769
6770         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6771
6772         if (rs.empty()) {
6773                 return;
6774         }
6775
6776         framepos_t where = get_preferred_edit_position();
6777
6778         begin_reversible_command (_("place transient"));
6779
6780         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6781                 (*r)->region()->add_transient(where);
6782         }
6783
6784         commit_reversible_command ();
6785 }
6786
6787 void
6788 Editor::remove_transient(ArdourCanvas::Item* item)
6789 {
6790         if (!_session) {
6791                 return;
6792         }
6793
6794         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6795         assert (_line);
6796
6797         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6798         _arv->remove_transient (*(float*) _line->get_data ("position"));
6799 }
6800
6801 void
6802 Editor::snap_regions_to_grid ()
6803 {
6804         list <boost::shared_ptr<Playlist > > used_playlists;
6805
6806         RegionSelection rs = get_regions_from_selection_and_entered ();
6807
6808         if (!_session || rs.empty()) {
6809                 return;
6810         }
6811
6812         begin_reversible_command (_("snap regions to grid"));
6813
6814         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6815
6816                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6817
6818                 if (!pl->frozen()) {
6819                         /* we haven't seen this playlist before */
6820
6821                         /* remember used playlists so we can thaw them later */
6822                         used_playlists.push_back(pl);
6823                         pl->freeze();
6824                 }
6825
6826                 framepos_t start_frame = (*r)->region()->first_frame ();
6827                 snap_to (start_frame);
6828                 (*r)->region()->set_position (start_frame);
6829         }
6830
6831         while (used_playlists.size() > 0) {
6832                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6833                 (*i)->thaw();
6834                 used_playlists.pop_front();
6835         }
6836
6837         commit_reversible_command ();
6838 }
6839
6840 void
6841 Editor::close_region_gaps ()
6842 {
6843         list <boost::shared_ptr<Playlist > > used_playlists;
6844
6845         RegionSelection rs = get_regions_from_selection_and_entered ();
6846
6847         if (!_session || rs.empty()) {
6848                 return;
6849         }
6850
6851         Dialog dialog (_("Close Region Gaps"));
6852
6853         Table table (2, 3);
6854         table.set_spacings (12);
6855         table.set_border_width (12);
6856         Label* l = manage (left_aligned_label (_("Crossfade length")));
6857         table.attach (*l, 0, 1, 0, 1);
6858
6859         SpinButton spin_crossfade (1, 0);
6860         spin_crossfade.set_range (0, 15);
6861         spin_crossfade.set_increments (1, 1);
6862         spin_crossfade.set_value (5);
6863         table.attach (spin_crossfade, 1, 2, 0, 1);
6864
6865         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6866
6867         l = manage (left_aligned_label (_("Pull-back length")));
6868         table.attach (*l, 0, 1, 1, 2);
6869
6870         SpinButton spin_pullback (1, 0);
6871         spin_pullback.set_range (0, 100);
6872         spin_pullback.set_increments (1, 1);
6873         spin_pullback.set_value(30);
6874         table.attach (spin_pullback, 1, 2, 1, 2);
6875
6876         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6877
6878         dialog.get_vbox()->pack_start (table);
6879         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6880         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6881         dialog.show_all ();
6882
6883         if (dialog.run () == RESPONSE_CANCEL) {
6884                 return;
6885         }
6886
6887         framepos_t crossfade_len = spin_crossfade.get_value();
6888         framepos_t pull_back_frames = spin_pullback.get_value();
6889
6890         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6891         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6892
6893         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6894
6895         begin_reversible_command (_("close region gaps"));
6896
6897         int idx = 0;
6898         boost::shared_ptr<Region> last_region;
6899
6900         rs.sort_by_position_and_track();
6901
6902         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6903
6904                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6905
6906                 if (!pl->frozen()) {
6907                         /* we haven't seen this playlist before */
6908
6909                         /* remember used playlists so we can thaw them later */
6910                         used_playlists.push_back(pl);
6911                         pl->freeze();
6912                 }
6913
6914                 framepos_t position = (*r)->region()->position();
6915
6916                 if (idx == 0 || position < last_region->position()){
6917                         last_region = (*r)->region();
6918                         idx++;
6919                         continue;
6920                 }
6921
6922                 (*r)->region()->trim_front( (position - pull_back_frames));
6923                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6924
6925                 last_region = (*r)->region();
6926
6927                 idx++;
6928         }
6929
6930         while (used_playlists.size() > 0) {
6931                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6932                 (*i)->thaw();
6933                 used_playlists.pop_front();
6934         }
6935
6936         commit_reversible_command ();
6937 }
6938
6939 void
6940 Editor::tab_to_transient (bool forward)
6941 {
6942         AnalysisFeatureList positions;
6943
6944         RegionSelection rs = get_regions_from_selection_and_entered ();
6945
6946         if (!_session) {
6947                 return;
6948         }
6949
6950         framepos_t pos = _session->audible_frame ();
6951
6952         if (!selection->tracks.empty()) {
6953
6954                 /* don't waste time searching for transients in duplicate playlists.
6955                  */
6956
6957                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6958
6959                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6960
6961                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6962
6963                         if (rtv) {
6964                                 boost::shared_ptr<Track> tr = rtv->track();
6965                                 if (tr) {
6966                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6967                                         if (pl) {
6968                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6969
6970                                                 if (result >= 0) {
6971                                                         positions.push_back (result);
6972                                                 }
6973                                         }
6974                                 }
6975                         }
6976                 }
6977
6978         } else {
6979
6980                 if (rs.empty()) {
6981                         return;
6982                 }
6983
6984                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6985                         (*r)->region()->get_transients (positions);
6986                 }
6987         }
6988
6989         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6990
6991         if (forward) {
6992                 AnalysisFeatureList::iterator x;
6993
6994                 for (x = positions.begin(); x != positions.end(); ++x) {
6995                         if ((*x) > pos) {
6996                                 break;
6997                         }
6998                 }
6999
7000                 if (x != positions.end ()) {
7001                         _session->request_locate (*x);
7002                 }
7003
7004         } else {
7005                 AnalysisFeatureList::reverse_iterator x;
7006
7007                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7008                         if ((*x) < pos) {
7009                                 break;
7010                         }
7011                 }
7012
7013                 if (x != positions.rend ()) {
7014                         _session->request_locate (*x);
7015                 }
7016         }
7017 }
7018
7019 void
7020 Editor::playhead_forward_to_grid ()
7021 {
7022         if (!_session) {
7023                 return;
7024         }
7025
7026         framepos_t pos = playhead_cursor->current_frame ();
7027         if (pos < max_framepos - 1) {
7028                 pos += 2;
7029                 snap_to_internal (pos, RoundUpAlways, false);
7030                 _session->request_locate (pos);
7031         }
7032 }
7033
7034
7035 void
7036 Editor::playhead_backward_to_grid ()
7037 {
7038         if (!_session) {
7039                 return;
7040         }
7041
7042         framepos_t pos = playhead_cursor->current_frame ();
7043         if (pos > 2) {
7044                 pos -= 2;
7045                 snap_to_internal (pos, RoundDownAlways, false);
7046                 _session->request_locate (pos);
7047         }
7048 }
7049
7050 void
7051 Editor::set_track_height (Height h)
7052 {
7053         TrackSelection& ts (selection->tracks);
7054
7055         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7056                 (*x)->set_height_enum (h);
7057         }
7058 }
7059
7060 void
7061 Editor::toggle_tracks_active ()
7062 {
7063         TrackSelection& ts (selection->tracks);
7064         bool first = true;
7065         bool target = false;
7066
7067         if (ts.empty()) {
7068                 return;
7069         }
7070
7071         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7072                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7073
7074                 if (rtv) {
7075                         if (first) {
7076                                 target = !rtv->_route->active();
7077                                 first = false;
7078                         }
7079                         rtv->_route->set_active (target, this);
7080                 }
7081         }
7082 }
7083
7084 void
7085 Editor::remove_tracks ()
7086 {
7087         /* this will delete GUI objects that may be the subject of an event
7088            handler in which this method is called. Defer actual deletion to the
7089            next idle callback, when all event handling is finished.
7090         */
7091         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7092 }
7093
7094 bool
7095 Editor::idle_remove_tracks ()
7096 {
7097         Session::StateProtector sp (_session);
7098         _remove_tracks ();
7099         return false; /* do not call again */
7100 }
7101
7102 void
7103 Editor::_remove_tracks ()
7104 {
7105         TrackSelection& ts (selection->tracks);
7106
7107         if (ts.empty()) {
7108                 return;
7109         }
7110
7111         vector<string> choices;
7112         string prompt;
7113         int ntracks = 0;
7114         int nbusses = 0;
7115         const char* trackstr;
7116         const char* busstr;
7117         vector<boost::shared_ptr<Route> > routes;
7118         bool special_bus = false;
7119
7120         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7121                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7122                 if (!rtv) {
7123                         continue;
7124                 }
7125                 if (rtv->is_track()) {
7126                         ntracks++;
7127                 } else {
7128                         nbusses++;
7129                 }
7130                 routes.push_back (rtv->_route);
7131
7132                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7133                         special_bus = true;
7134                 }
7135         }
7136
7137         if (special_bus && !Config->get_allow_special_bus_removal()) {
7138                 MessageDialog msg (_("That would be bad news ...."),
7139                                    false,
7140                                    Gtk::MESSAGE_INFO,
7141                                    Gtk::BUTTONS_OK);
7142                 msg.set_secondary_text (string_compose (_(
7143                                                                 "Removing the master or monitor bus is such a bad idea\n\
7144 that %1 is not going to allow it.\n\
7145 \n\
7146 If you really want to do this sort of thing\n\
7147 edit your ardour.rc file to set the\n\
7148 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7149
7150                 msg.present ();
7151                 msg.run ();
7152                 return;
7153         }
7154
7155         if (ntracks + nbusses == 0) {
7156                 return;
7157         }
7158
7159         trackstr = P_("track", "tracks", ntracks);
7160         busstr = P_("bus", "busses", nbusses);
7161
7162         if (ntracks) {
7163                 if (nbusses) {
7164                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7165                                                     "(You may also lose the playlists associated with the %2)\n\n"
7166                                                     "This action cannot be undone, and the session file will be overwritten!"),
7167                                                   ntracks, trackstr, nbusses, busstr);
7168                 } else {
7169                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
7170                                                     "(You may also lose the playlists associated with the %2)\n\n"
7171                                                     "This action cannot be undone, and the session file will be overwritten!"),
7172                                                   ntracks, trackstr);
7173                 }
7174         } else if (nbusses) {
7175                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
7176                                             "This action cannot be undone, and the session file will be overwritten"),
7177                                           nbusses, busstr);
7178         }
7179
7180         choices.push_back (_("No, do nothing."));
7181         if (ntracks + nbusses > 1) {
7182                 choices.push_back (_("Yes, remove them."));
7183         } else {
7184                 choices.push_back (_("Yes, remove it."));
7185         }
7186
7187         string title;
7188         if (ntracks) {
7189                 title = string_compose (_("Remove %1"), trackstr);
7190         } else {
7191                 title = string_compose (_("Remove %1"), busstr);
7192         }
7193
7194         Choice prompter (title, prompt, choices);
7195
7196         if (prompter.run () != 1) {
7197                 return;
7198         }
7199
7200         {
7201                 DisplaySuspender ds;
7202                 boost::shared_ptr<RouteList> rl (new RouteList);
7203                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7204                         rl->push_back (*x);
7205                 }
7206                 _session->remove_routes (rl);
7207         }
7208         /* TrackSelection and RouteList leave scope,
7209          * destructors are called,
7210          * diskstream drops references, save_state is called (again for every track)
7211          */
7212 }
7213
7214 void
7215 Editor::do_insert_time ()
7216 {
7217         if (selection->tracks.empty()) {
7218                 return;
7219         }
7220
7221         InsertRemoveTimeDialog d (*this);
7222         int response = d.run ();
7223
7224         if (response != RESPONSE_OK) {
7225                 return;
7226         }
7227
7228         if (d.distance() == 0) {
7229                 return;
7230         }
7231
7232         insert_time (
7233                 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7234                 d.distance(),
7235                 d.intersected_region_action (),
7236                 d.all_playlists(),
7237                 d.move_glued(),
7238                 d.move_markers(),
7239                 d.move_glued_markers(),
7240                 d.move_locked_markers(),
7241                 d.move_tempos()
7242                 );
7243 }
7244
7245 void
7246 Editor::insert_time (
7247         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7248         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7249         )
7250 {
7251
7252         if (Config->get_edit_mode() == Lock) {
7253                 return;
7254         }
7255         bool in_command = false;
7256
7257         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7258
7259         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7260
7261                 /* regions */
7262
7263                 /* don't operate on any playlist more than once, which could
7264                  * happen if "all playlists" is enabled, but there is more
7265                  * than 1 track using playlists "from" a given track.
7266                  */
7267
7268                 set<boost::shared_ptr<Playlist> > pl;
7269
7270                 if (all_playlists) {
7271                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7272                         if (rtav && rtav->track ()) {
7273                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7274                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7275                                         pl.insert (*p);
7276                                 }
7277                         }
7278                 } else {
7279                         if ((*x)->playlist ()) {
7280                                 pl.insert ((*x)->playlist ());
7281                         }
7282                 }
7283
7284                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7285
7286                         (*i)->clear_changes ();
7287                         (*i)->clear_owned_changes ();
7288
7289                         if (opt == SplitIntersected) {
7290                                 (*i)->split (pos);
7291                         }
7292
7293                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7294
7295                         if (!in_command) {
7296                                 begin_reversible_command (_("insert time"));
7297                                 in_command = true;
7298                         }
7299                         vector<Command*> cmds;
7300                         (*i)->rdiff (cmds);
7301                         _session->add_commands (cmds);
7302
7303                         _session->add_command (new StatefulDiffCommand (*i));
7304                 }
7305
7306                 /* automation */
7307                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7308                 if (rtav) {
7309                         if (!in_command) {
7310                                 begin_reversible_command (_("insert time"));
7311                                 in_command = true;
7312                         }
7313                         rtav->route ()->shift (pos, frames);
7314                 }
7315         }
7316
7317         /* markers */
7318         if (markers_too) {
7319                 bool moved = false;
7320                 XMLNode& before (_session->locations()->get_state());
7321                 Locations::LocationList copy (_session->locations()->list());
7322
7323                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7324
7325                         Locations::LocationList::const_iterator tmp;
7326
7327                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7328                                 bool const was_locked = (*i)->locked ();
7329                                 if (locked_markers_too) {
7330                                         (*i)->unlock ();
7331                                 }
7332
7333                                 if ((*i)->start() >= pos) {
7334                                         // move end first, in case we're moving by more than the length of the range
7335                                         if (!(*i)->is_mark()) {
7336                                                 (*i)->set_end ((*i)->end() + frames);
7337                                         }
7338                                         (*i)->set_start ((*i)->start() + frames);
7339                                         moved = true;
7340                                 }
7341
7342                                 if (was_locked) {
7343                                         (*i)->lock ();
7344                                 }
7345                         }
7346                 }
7347
7348                 if (moved) {
7349                         if (!in_command) {
7350                                 begin_reversible_command (_("insert time"));
7351                                 in_command = true;
7352                         }
7353                         XMLNode& after (_session->locations()->get_state());
7354                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7355                 }
7356         }
7357
7358         if (tempo_too) {
7359                 if (!in_command) {
7360                         begin_reversible_command (_("insert time"));
7361                         in_command = true;
7362                 }
7363                 XMLNode& before (_session->tempo_map().get_state());
7364                 _session->tempo_map().insert_time (pos, frames);
7365                 XMLNode& after (_session->tempo_map().get_state());
7366                 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7367         }
7368
7369         if (in_command) {
7370                 commit_reversible_command ();
7371         }
7372 }
7373
7374 void
7375 Editor::do_remove_time ()
7376 {
7377         if (selection->tracks.empty()) {
7378                 return;
7379         }
7380
7381         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7382         InsertRemoveTimeDialog d (*this, true);
7383
7384         int response = d.run ();
7385
7386         if (response != RESPONSE_OK) {
7387                 return;
7388         }
7389
7390         framecnt_t distance = d.distance();
7391
7392         if (distance == 0) {
7393                 return;
7394         }
7395
7396         remove_time (
7397                 pos,
7398                 distance,
7399                 SplitIntersected,
7400                 d.move_glued(),
7401                 d.move_markers(),
7402                 d.move_glued_markers(),
7403                 d.move_locked_markers(),
7404                 d.move_tempos()
7405         );
7406 }
7407
7408 void
7409 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7410                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7411 {
7412         if (Config->get_edit_mode() == Lock) {
7413                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7414                 return;
7415         }
7416         bool in_command = false;
7417
7418         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7419                 /* regions */
7420                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7421
7422                 if (pl) {
7423
7424                         XMLNode &before = pl->get_state();
7425
7426                         std::list<AudioRange> rl;
7427                         AudioRange ar(pos, pos+frames, 0);
7428                         rl.push_back(ar);
7429                         pl->cut (rl);
7430                         pl->shift (pos, -frames, true, ignore_music_glue);
7431
7432                         if (!in_command) {
7433                                 begin_reversible_command (_("remove time"));
7434                                 in_command = true;
7435                         }
7436                         XMLNode &after = pl->get_state();
7437
7438                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7439                 }
7440
7441                 /* automation */
7442                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7443                 if (rtav) {
7444                         if (!in_command) {
7445                                 begin_reversible_command (_("remove time"));
7446                                 in_command = true;
7447                         }
7448                         rtav->route ()->shift (pos, -frames);
7449                 }
7450         }
7451
7452         std::list<Location*> loc_kill_list;
7453
7454         /* markers */
7455         if (markers_too) {
7456                 bool moved = false;
7457                 XMLNode& before (_session->locations()->get_state());
7458                 Locations::LocationList copy (_session->locations()->list());
7459
7460                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7461                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7462
7463                                 bool const was_locked = (*i)->locked ();
7464                                 if (locked_markers_too) {
7465                                         (*i)->unlock ();
7466                                 }
7467
7468                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7469                                         if ((*i)->end() >= pos
7470                                         && (*i)->end() < pos+frames
7471                                         && (*i)->start() >= pos
7472                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7473                                                 moved = true;
7474                                                 loc_kill_list.push_back(*i);
7475                                         } else {  // only start or end is included, try to do the right thing
7476                                                 // move start before moving end, to avoid trying to move the end to before the start
7477                                                 // if we're removing more time than the length of the range
7478                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7479                                                         // start is within cut
7480                                                         (*i)->set_start (pos);  // bring the start marker to the beginning of the cut
7481                                                         moved = true;
7482                                                 } else if ((*i)->start() >= pos+frames) {
7483                                                         // start (and thus entire range) lies beyond end of cut
7484                                                         (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7485                                                         moved = true;
7486                                                 }
7487                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7488                                                         // end is inside cut
7489                                                         (*i)->set_end (pos);  // bring the end to the cut
7490                                                         moved = true;
7491                                                 } else if ((*i)->end() >= pos+frames) {
7492                                                         // end is beyond end of cut
7493                                                         (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7494                                                         moved = true;
7495                                                 }
7496
7497                                         }
7498                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7499                                         loc_kill_list.push_back(*i);
7500                                         moved = true;
7501                                 } else if ((*i)->start() >= pos) {
7502                                         (*i)->set_start ((*i)->start() -frames);
7503                                         moved = true;
7504                                 }
7505
7506                                 if (was_locked) {
7507                                         (*i)->lock ();
7508                                 }
7509                         }
7510                 }
7511
7512                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7513                         _session->locations()->remove( *i );
7514                 }
7515
7516                 if (moved) {
7517                         if (!in_command) {
7518                                 begin_reversible_command (_("remove time"));
7519                                 in_command = true;
7520                         }
7521                         XMLNode& after (_session->locations()->get_state());
7522                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7523                 }
7524         }
7525
7526         if (tempo_too) {
7527                 XMLNode& before (_session->tempo_map().get_state());
7528
7529                 if (_session->tempo_map().remove_time (pos, frames) ) {
7530                         if (!in_command) {
7531                                 begin_reversible_command (_("remove time"));
7532                                 in_command = true;
7533                         }
7534                         XMLNode& after (_session->tempo_map().get_state());
7535                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7536                 }
7537         }
7538
7539         if (in_command) {
7540                 commit_reversible_command ();
7541         }
7542 }
7543
7544 void
7545 Editor::fit_selection ()
7546 {
7547         if (!selection->tracks.empty()) {
7548                 fit_tracks (selection->tracks);
7549         } else {
7550                 TrackViewList tvl;
7551
7552                 /* no selected tracks - use tracks with selected regions */
7553
7554                 if (!selection->regions.empty()) {
7555                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7556                                 tvl.push_back (&(*r)->get_time_axis_view ());
7557                         }
7558
7559                         if (!tvl.empty()) {
7560                                 fit_tracks (tvl);
7561                         }
7562                 } else if (internal_editing()) {
7563                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7564                            the entered track
7565                         */
7566                         if (entered_track) {
7567                                 tvl.push_back (entered_track);
7568                                 fit_tracks (tvl);
7569                         }
7570                 }
7571         }
7572
7573 }
7574
7575 void
7576 Editor::fit_tracks (TrackViewList & tracks)
7577 {
7578         if (tracks.empty()) {
7579                 return;
7580         }
7581
7582         uint32_t child_heights = 0;
7583         int visible_tracks = 0;
7584
7585         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7586
7587                 if (!(*t)->marked_for_display()) {
7588                         continue;
7589                 }
7590
7591                 child_heights += (*t)->effective_height() - (*t)->current_height();
7592                 ++visible_tracks;
7593         }
7594
7595         /* compute the per-track height from:
7596
7597            total canvas visible height -
7598                  height that will be taken by visible children of selected
7599                  tracks - height of the ruler/hscroll area
7600         */
7601         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7602         double first_y_pos = DBL_MAX;
7603
7604         if (h < TimeAxisView::preset_height (HeightSmall)) {
7605                 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7606                 /* too small to be displayed */
7607                 return;
7608         }
7609
7610         undo_visual_stack.push_back (current_visual_state (true));
7611         PBD::Unwinder<bool> nsv (no_save_visual, true);
7612
7613         /* build a list of all tracks, including children */
7614
7615         TrackViewList all;
7616         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7617                 all.push_back (*i);
7618                 TimeAxisView::Children c = (*i)->get_child_list ();
7619                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7620                         all.push_back (j->get());
7621                 }
7622         }
7623
7624
7625         // find selection range.
7626         // if someone knows how to user TrackViewList::iterator for this
7627         // I'm all ears.
7628         int selected_top = -1;
7629         int selected_bottom = -1;
7630         int i = 0;
7631         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7632                 if ((*t)->marked_for_display ()) {
7633                         if (tracks.contains(*t)) {
7634                                 if (selected_top == -1) {
7635                                         selected_top = i;
7636                                 }
7637                                 selected_bottom = i;
7638                         }
7639                 }
7640         }
7641
7642         i = 0;
7643         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7644                 if ((*t)->marked_for_display ()) {
7645                         if (tracks.contains(*t)) {
7646                                 (*t)->set_height (h);
7647                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7648                         } else {
7649                                 if (i > selected_top && i < selected_bottom) {
7650                                         hide_track_in_display (*t);
7651                                 }
7652                         }
7653                 }
7654         }
7655
7656         /*
7657            set the controls_layout height now, because waiting for its size
7658            request signal handler will cause the vertical adjustment setting to fail
7659         */
7660
7661         controls_layout.property_height () = _full_canvas_height;
7662         vertical_adjustment.set_value (first_y_pos);
7663
7664         redo_visual_stack.push_back (current_visual_state (true));
7665
7666         visible_tracks_selector.set_text (_("Sel"));
7667 }
7668
7669 void
7670 Editor::save_visual_state (uint32_t n)
7671 {
7672         while (visual_states.size() <= n) {
7673                 visual_states.push_back (0);
7674         }
7675
7676         if (visual_states[n] != 0) {
7677                 delete visual_states[n];
7678         }
7679
7680         visual_states[n] = current_visual_state (true);
7681         gdk_beep ();
7682 }
7683
7684 void
7685 Editor::goto_visual_state (uint32_t n)
7686 {
7687         if (visual_states.size() <= n) {
7688                 return;
7689         }
7690
7691         if (visual_states[n] == 0) {
7692                 return;
7693         }
7694
7695         use_visual_state (*visual_states[n]);
7696 }
7697
7698 void
7699 Editor::start_visual_state_op (uint32_t n)
7700 {
7701         save_visual_state (n);
7702
7703         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7704         char buf[32];
7705         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7706         pup->set_text (buf);
7707         pup->touch();
7708 }
7709
7710 void
7711 Editor::cancel_visual_state_op (uint32_t n)
7712 {
7713         goto_visual_state (n);
7714 }
7715
7716 void
7717 Editor::toggle_region_mute ()
7718 {
7719         if (_ignore_region_action) {
7720                 return;
7721         }
7722
7723         RegionSelection rs = get_regions_from_selection_and_entered ();
7724
7725         if (rs.empty ()) {
7726                 return;
7727         }
7728
7729         if (rs.size() > 1) {
7730                 begin_reversible_command (_("mute regions"));
7731         } else {
7732                 begin_reversible_command (_("mute region"));
7733         }
7734
7735         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7736
7737                 (*i)->region()->playlist()->clear_changes ();
7738                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7739                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7740
7741         }
7742
7743         commit_reversible_command ();
7744 }
7745
7746 void
7747 Editor::combine_regions ()
7748 {
7749         /* foreach track with selected regions, take all selected regions
7750            and join them into a new region containing the subregions (as a
7751            playlist)
7752         */
7753
7754         typedef set<RouteTimeAxisView*> RTVS;
7755         RTVS tracks;
7756
7757         if (selection->regions.empty()) {
7758                 return;
7759         }
7760
7761         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7762                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7763
7764                 if (rtv) {
7765                         tracks.insert (rtv);
7766                 }
7767         }
7768
7769         begin_reversible_command (_("combine regions"));
7770
7771         vector<RegionView*> new_selection;
7772
7773         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7774                 RegionView* rv;
7775
7776                 if ((rv = (*i)->combine_regions ()) != 0) {
7777                         new_selection.push_back (rv);
7778                 }
7779         }
7780
7781         selection->clear_regions ();
7782         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7783                 selection->add (*i);
7784         }
7785
7786         commit_reversible_command ();
7787 }
7788
7789 void
7790 Editor::uncombine_regions ()
7791 {
7792         typedef set<RouteTimeAxisView*> RTVS;
7793         RTVS tracks;
7794
7795         if (selection->regions.empty()) {
7796                 return;
7797         }
7798
7799         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7800                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7801
7802                 if (rtv) {
7803                         tracks.insert (rtv);
7804                 }
7805         }
7806
7807         begin_reversible_command (_("uncombine regions"));
7808
7809         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7810                 (*i)->uncombine_regions ();
7811         }
7812
7813         commit_reversible_command ();
7814 }
7815
7816 void
7817 Editor::toggle_midi_input_active (bool flip_others)
7818 {
7819         bool onoff = false;
7820         boost::shared_ptr<RouteList> rl (new RouteList);
7821
7822         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7823                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7824
7825                 if (!rtav) {
7826                         continue;
7827                 }
7828
7829                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7830
7831                 if (mt) {
7832                         rl->push_back (rtav->route());
7833                         onoff = !mt->input_active();
7834                 }
7835         }
7836
7837         _session->set_exclusive_input_active (rl, onoff, flip_others);
7838 }
7839
7840 void
7841 Editor::lock ()
7842 {
7843         if (!lock_dialog) {
7844                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7845
7846                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7847                 lock_dialog->get_vbox()->pack_start (*padlock);
7848
7849                 ArdourButton* b = manage (new ArdourButton);
7850                 b->set_name ("lock button");
7851                 b->set_text (_("Click to unlock"));
7852                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7853                 lock_dialog->get_vbox()->pack_start (*b);
7854
7855                 lock_dialog->get_vbox()->show_all ();
7856                 lock_dialog->set_size_request (200, 200);
7857         }
7858
7859         delete _main_menu_disabler;
7860         _main_menu_disabler = new MainMenuDisabler;
7861
7862         lock_dialog->present ();
7863 }
7864
7865 void
7866 Editor::unlock ()
7867 {
7868         lock_dialog->hide ();
7869
7870         delete _main_menu_disabler;
7871         _main_menu_disabler = 0;
7872
7873         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7874                 start_lock_event_timing ();
7875         }
7876 }
7877
7878 void
7879 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7880 {
7881         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7882 }
7883
7884 void
7885 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7886 {
7887         Timers::TimerSuspender t;
7888         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7889         Gtkmm2ext::UI::instance()->flush_pending ();
7890 }
7891
7892 void
7893 Editor::bring_all_sources_into_session ()
7894 {
7895         if (!_session) {
7896                 return;
7897         }
7898
7899         Gtk::Label msg;
7900         ArdourDialog w (_("Moving embedded files into session folder"));
7901         w.get_vbox()->pack_start (msg);
7902         w.present ();
7903
7904         /* flush all pending GUI events because we're about to start copying
7905          * files
7906          */
7907
7908         Timers::TimerSuspender t;
7909         Gtkmm2ext::UI::instance()->flush_pending ();
7910
7911         cerr << " Do it\n";
7912
7913         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7914 }