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