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