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