use Tracks' MainMenuDisabler during session lock (could be improved with more RAII)
[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_remove_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::set_session_start_from_playhead ()
2119 {
2120         if (!_session)
2121                 return;
2122         
2123         Location* loc;
2124         if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
2125                 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2126         } else {
2127                 XMLNode &before = loc->get_state();
2128
2129                 _session->set_session_extents ( _session->audible_frame(), loc->end() );
2130
2131                 XMLNode &after = loc->get_state();
2132
2133                 begin_reversible_command (_("Set session start"));
2134                 
2135                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2136
2137                 commit_reversible_command ();
2138         }
2139 }
2140
2141 void
2142 Editor::set_session_end_from_playhead ()
2143 {
2144         if (!_session)
2145                 return;
2146         
2147         Location* loc;
2148         if ((loc = _session->locations()->session_range_location()) == 0) {  //should never happen
2149                 _session->set_session_extents ( _session->audible_frame(), _session->audible_frame() );
2150         } else {
2151                 XMLNode &before = loc->get_state();
2152
2153                 _session->set_session_extents ( loc->start(), _session->audible_frame() );
2154
2155                 XMLNode &after = loc->get_state();
2156
2157                 begin_reversible_command (_("Set session start"));
2158
2159                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
2160
2161                 commit_reversible_command ();
2162         }
2163 }
2164
2165 void
2166 Editor::add_location_from_playhead_cursor ()
2167 {
2168         add_location_mark (_session->audible_frame());
2169 }
2170
2171 void
2172 Editor::remove_location_at_playhead_cursor ()
2173 {
2174         if (_session) {
2175
2176                 //set up for undo
2177                 begin_reversible_command (_("remove marker"));
2178                 
2179                 XMLNode &before = _session->locations()->get_state();
2180                 bool removed = false;
2181
2182                 //find location(s) at this time
2183                 Locations::LocationList locs;
2184                 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
2185                 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
2186                         if ((*i)->is_mark()) {
2187                                 _session->locations()->remove (*i);
2188                                 removed = true;
2189                         }
2190                 }
2191                 
2192                 //store undo
2193                 if (removed) {
2194                         XMLNode &after = _session->locations()->get_state();
2195                         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2196                         
2197                         commit_reversible_command ();
2198                 }
2199         }
2200 }
2201
2202 /** Add a range marker around each selected region */
2203 void
2204 Editor::add_locations_from_region ()
2205 {
2206         RegionSelection rs = get_regions_from_selection_and_entered ();
2207
2208         if (rs.empty()) {
2209                 return;
2210         }
2211
2212         begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2213         
2214         XMLNode &before = _session->locations()->get_state();
2215
2216         for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2217
2218                 boost::shared_ptr<Region> region = (*i)->region ();
2219
2220                 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2221
2222                 _session->locations()->add (location, true);
2223         }
2224
2225         XMLNode &after = _session->locations()->get_state();
2226         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2227         
2228         commit_reversible_command ();
2229 }
2230
2231 /** Add a single range marker around all selected regions */
2232 void
2233 Editor::add_location_from_region ()
2234 {
2235         RegionSelection rs = get_regions_from_selection_and_entered ();
2236
2237         if (rs.empty()) {
2238                 return;
2239         }
2240
2241         begin_reversible_command (_("add marker"));
2242         
2243         XMLNode &before = _session->locations()->get_state();
2244
2245         string markername;
2246
2247         if (rs.size() > 1) {
2248                 _session->locations()->next_available_name(markername, "regions");
2249         } else {
2250                 RegionView* rv = *(rs.begin());
2251                 boost::shared_ptr<Region> region = rv->region();
2252                 markername = region->name();
2253         }
2254
2255         if (!choose_new_marker_name(markername)) {
2256                 return;
2257         }
2258
2259         // single range spanning all selected
2260         Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2261         _session->locations()->add (location, true);
2262
2263         XMLNode &after = _session->locations()->get_state();
2264         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2265         
2266         commit_reversible_command ();
2267 }
2268
2269 /* MARKS */
2270
2271 void
2272 Editor::jump_forward_to_mark ()
2273 {
2274         if (!_session) {
2275                 return;
2276         }
2277
2278         framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2279
2280         if (pos < 0) {
2281                 return;
2282         }
2283         
2284         _session->request_locate (pos, _session->transport_rolling());
2285 }
2286
2287 void
2288 Editor::jump_backward_to_mark ()
2289 {
2290         if (!_session) {
2291                 return;
2292         }
2293
2294         framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2295
2296         if (pos < 0) {
2297                 return;
2298         }
2299
2300         _session->request_locate (pos, _session->transport_rolling());
2301 }
2302
2303 void
2304 Editor::set_mark ()
2305 {
2306         framepos_t const pos = _session->audible_frame ();
2307
2308         string markername;
2309         _session->locations()->next_available_name (markername, "mark");
2310
2311         if (!choose_new_marker_name (markername)) {
2312                 return;
2313         }
2314
2315         _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2316 }
2317
2318 void
2319 Editor::clear_markers ()
2320 {
2321         if (_session) {
2322                 begin_reversible_command (_("clear markers"));
2323                 
2324                 XMLNode &before = _session->locations()->get_state();
2325                 _session->locations()->clear_markers ();
2326                 XMLNode &after = _session->locations()->get_state();
2327                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2328                 
2329                 commit_reversible_command ();
2330         }
2331 }
2332
2333 void
2334 Editor::clear_ranges ()
2335 {
2336         if (_session) {
2337                 begin_reversible_command (_("clear ranges"));
2338                 
2339                 XMLNode &before = _session->locations()->get_state();
2340
2341                 _session->locations()->clear_ranges ();
2342
2343                 XMLNode &after = _session->locations()->get_state();
2344                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2345                 
2346                 commit_reversible_command ();
2347         }
2348 }
2349
2350 void
2351 Editor::clear_locations ()
2352 {
2353         begin_reversible_command (_("clear locations"));
2354         
2355         XMLNode &before = _session->locations()->get_state();
2356         _session->locations()->clear ();
2357         XMLNode &after = _session->locations()->get_state();
2358         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2359         
2360         commit_reversible_command ();
2361 }
2362
2363 void
2364 Editor::unhide_markers ()
2365 {
2366         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2367                 Location *l = (*i).first;
2368                 if (l->is_hidden() && l->is_mark()) {
2369                         l->set_hidden(false, this);
2370                 }
2371         }
2372 }
2373
2374 void
2375 Editor::unhide_ranges ()
2376 {
2377         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2378                 Location *l = (*i).first;
2379                 if (l->is_hidden() && l->is_range_marker()) {
2380                         l->set_hidden(false, this);
2381                 }
2382         }
2383 }
2384
2385 /* INSERT/REPLACE */
2386
2387 void
2388 Editor::insert_region_list_selection (float times)
2389 {
2390         RouteTimeAxisView *tv = 0;
2391         boost::shared_ptr<Playlist> playlist;
2392
2393         if (clicked_routeview != 0) {
2394                 tv = clicked_routeview;
2395         } else if (!selection->tracks.empty()) {
2396                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2397                         return;
2398                 }
2399         } else if (entered_track != 0) {
2400                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2401                         return;
2402                 }
2403         } else {
2404                 return;
2405         }
2406
2407         if ((playlist = tv->playlist()) == 0) {
2408                 return;
2409         }
2410
2411         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2412         if (region == 0) {
2413                 return;
2414         }
2415
2416         begin_reversible_command (_("insert region"));
2417         playlist->clear_changes ();
2418         playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2419         if (Config->get_edit_mode() == Ripple)
2420                 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2421
2422         _session->add_command(new StatefulDiffCommand (playlist));
2423         commit_reversible_command ();
2424 }
2425
2426 /* BUILT-IN EFFECTS */
2427
2428 void
2429 Editor::reverse_selection ()
2430 {
2431
2432 }
2433
2434 /* GAIN ENVELOPE EDITING */
2435
2436 void
2437 Editor::edit_envelope ()
2438 {
2439 }
2440
2441 /* PLAYBACK */
2442
2443 void
2444 Editor::transition_to_rolling (bool fwd)
2445 {
2446         if (!_session) {
2447                 return;
2448         }
2449
2450         if (_session->config.get_external_sync()) {
2451                 switch (Config->get_sync_source()) {
2452                 case Engine:
2453                         break;
2454                 default:
2455                         /* transport controlled by the master */
2456                         return;
2457                 }
2458         }
2459
2460         if (_session->is_auditioning()) {
2461                 _session->cancel_audition ();
2462                 return;
2463         }
2464
2465         _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2466 }
2467
2468 void
2469 Editor::play_from_start ()
2470 {
2471         _session->request_locate (_session->current_start_frame(), true);
2472 }
2473
2474 void
2475 Editor::play_from_edit_point ()
2476 {
2477         _session->request_locate (get_preferred_edit_position(), true);
2478 }
2479
2480 void
2481 Editor::play_from_edit_point_and_return ()
2482 {
2483         framepos_t start_frame;
2484         framepos_t return_frame;
2485
2486         start_frame = get_preferred_edit_position ( EDIT_IGNORE_PHEAD );
2487
2488         if (_session->transport_rolling()) {
2489                 _session->request_locate (start_frame, false);
2490                 return;
2491         }
2492
2493         /* don't reset the return frame if its already set */
2494
2495         if ((return_frame = _session->requested_return_frame()) < 0) {
2496                 return_frame = _session->audible_frame();
2497         }
2498
2499         if (start_frame >= 0) {
2500                 _session->request_roll_at_and_return (start_frame, return_frame);
2501         }
2502 }
2503
2504 void
2505 Editor::play_selection ()
2506 {
2507         framepos_t start, end;
2508         if (!get_selection_extents ( start, end))
2509                 return;
2510
2511         AudioRange ar (start, end, 0);
2512         list<AudioRange> lar;
2513         lar.push_back (ar);
2514
2515         _session->request_play_range (&lar, true);
2516 }
2517
2518 framepos_t
2519 Editor::get_preroll ()
2520 {
2521         return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2522 }
2523
2524
2525 void
2526 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2527 {
2528         if ( _session->transport_rolling() || !ARDOUR_UI::config()->get_follow_edits() || _ignore_follow_edits )
2529                 return;
2530
2531         location -= get_preroll();
2532         
2533         //don't try to locate before the beginning of time
2534         if ( location < 0 ) 
2535                 location = 0;
2536                 
2537         //if follow_playhead is on, keep the playhead on the screen
2538         if ( _follow_playhead )
2539                 if ( location < leftmost_frame ) 
2540                         location = leftmost_frame;
2541
2542         _session->request_locate( location );
2543 }
2544
2545 void
2546 Editor::play_with_preroll ()
2547 {
2548         {
2549                 framepos_t preroll = get_preroll();
2550                 
2551                 framepos_t start, end;
2552                 if (!get_selection_extents ( start, end))
2553                         return;
2554
2555                 if (start > preroll)
2556                         start = start - preroll;
2557                 
2558                 end = end + preroll;  //"post-roll"
2559                 
2560                 AudioRange ar (start, end, 0);
2561                 list<AudioRange> lar;
2562                 lar.push_back (ar);
2563
2564                 _session->request_play_range (&lar, true);
2565         }
2566 }
2567
2568 void
2569 Editor::play_location (Location& location)
2570 {
2571         if (location.start() <= location.end()) {
2572                 return;
2573         }
2574
2575         _session->request_bounded_roll (location.start(), location.end());
2576 }
2577
2578 void
2579 Editor::loop_location (Location& location)
2580 {
2581         if (location.start() <= location.end()) {
2582                 return;
2583         }
2584
2585         Location* tll;
2586
2587         if ((tll = transport_loop_location()) != 0) {
2588                 tll->set (location.start(), location.end());
2589
2590                 // enable looping, reposition and start rolling
2591                 _session->request_locate (tll->start(), true);
2592                 _session->request_play_loop (true);
2593         }
2594 }
2595
2596 void
2597 Editor::do_layer_operation (LayerOperation op)
2598 {
2599         if (selection->regions.empty ()) {
2600                 return;
2601         }
2602
2603         bool const multiple = selection->regions.size() > 1;
2604         switch (op) {
2605         case Raise:
2606                 if (multiple) {
2607                         begin_reversible_command (_("raise regions"));
2608                 } else {
2609                         begin_reversible_command (_("raise region"));
2610                 }
2611                 break;
2612
2613         case RaiseToTop:
2614                 if (multiple) {
2615                         begin_reversible_command (_("raise regions to top"));
2616                 } else {
2617                         begin_reversible_command (_("raise region to top"));
2618                 }
2619                 break;
2620                 
2621         case Lower:
2622                 if (multiple) {
2623                         begin_reversible_command (_("lower regions"));
2624                 } else {
2625                         begin_reversible_command (_("lower region"));
2626                 }
2627                 break;
2628                 
2629         case LowerToBottom:
2630                 if (multiple) {
2631                         begin_reversible_command (_("lower regions to bottom"));
2632                 } else {
2633                         begin_reversible_command (_("lower region"));
2634                 }
2635                 break;
2636         }
2637
2638         set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2639         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2640                 (*i)->clear_owned_changes ();
2641         }
2642         
2643         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2644                 boost::shared_ptr<Region> r = (*i)->region ();
2645                 switch (op) {
2646                 case Raise:
2647                         r->raise ();
2648                         break;
2649                 case RaiseToTop:
2650                         r->raise_to_top ();
2651                         break;
2652                 case Lower:
2653                         r->lower ();
2654                         break;
2655                 case LowerToBottom:
2656                         r->lower_to_bottom ();
2657                 }
2658         }
2659
2660         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2661                 vector<Command*> cmds;
2662                 (*i)->rdiff (cmds);
2663                 _session->add_commands (cmds);
2664         }
2665         
2666         commit_reversible_command ();
2667 }
2668
2669 void
2670 Editor::raise_region ()
2671 {
2672         do_layer_operation (Raise);
2673 }
2674
2675 void
2676 Editor::raise_region_to_top ()
2677 {
2678         do_layer_operation (RaiseToTop);
2679 }
2680
2681 void
2682 Editor::lower_region ()
2683 {
2684         do_layer_operation (Lower);
2685 }
2686
2687 void
2688 Editor::lower_region_to_bottom ()
2689 {
2690         do_layer_operation (LowerToBottom);
2691 }
2692
2693 /** Show the region editor for the selected regions */
2694 void
2695 Editor::show_region_properties ()
2696 {
2697         selection->foreach_regionview (&RegionView::show_region_editor);
2698 }
2699
2700 /** Show the midi list editor for the selected MIDI regions */
2701 void
2702 Editor::show_midi_list_editor ()
2703 {
2704         selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2705 }
2706
2707 void
2708 Editor::rename_region ()
2709 {
2710         RegionSelection rs = get_regions_from_selection_and_entered ();
2711
2712         if (rs.empty()) {
2713                 return;
2714         }
2715
2716         ArdourDialog d (*this, _("Rename Region"), true, false);
2717         Entry entry;
2718         Label label (_("New name:"));
2719         HBox hbox;
2720
2721         hbox.set_spacing (6);
2722         hbox.pack_start (label, false, false);
2723         hbox.pack_start (entry, true, true);
2724
2725         d.get_vbox()->set_border_width (12);
2726         d.get_vbox()->pack_start (hbox, false, false);
2727
2728         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2729         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2730
2731         d.set_size_request (300, -1);
2732
2733         entry.set_text (rs.front()->region()->name());
2734         entry.select_region (0, -1);
2735
2736         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2737
2738         d.show_all ();
2739
2740         entry.grab_focus();
2741
2742         int const ret = d.run();
2743
2744         d.hide ();
2745
2746         if (ret != RESPONSE_OK) {
2747                 return;
2748         }
2749
2750         std::string str = entry.get_text();
2751         strip_whitespace_edges (str);
2752         if (!str.empty()) {
2753                 rs.front()->region()->set_name (str);
2754                 _regions->redisplay ();
2755         }
2756 }
2757
2758 void
2759 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2760 {
2761         if (_session->is_auditioning()) {
2762                 _session->cancel_audition ();
2763         }
2764
2765         // note: some potential for creativity here, because region doesn't
2766         // have to belong to the playlist that Route is handling
2767
2768         // bool was_soloed = route.soloed();
2769
2770         route.set_solo (true, this);
2771
2772         _session->request_bounded_roll (region->position(), region->position() + region->length());
2773
2774         /* XXX how to unset the solo state ? */
2775 }
2776
2777 /** Start an audition of the first selected region */
2778 void
2779 Editor::play_edit_range ()
2780 {
2781         framepos_t start, end;
2782
2783         if (get_edit_op_range (start, end)) {
2784                 _session->request_bounded_roll (start, end);
2785         }
2786 }
2787
2788 void
2789 Editor::play_selected_region ()
2790 {
2791         framepos_t start = max_framepos;
2792         framepos_t end = 0;
2793
2794         RegionSelection rs = get_regions_from_selection_and_entered ();
2795
2796         if (rs.empty()) {
2797                 return;
2798         }
2799
2800         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2801                 if ((*i)->region()->position() < start) {
2802                         start = (*i)->region()->position();
2803                 }
2804                 if ((*i)->region()->last_frame() + 1 > end) {
2805                         end = (*i)->region()->last_frame() + 1;
2806                 }
2807         }
2808
2809         _session->request_bounded_roll (start, end);
2810 }
2811
2812 void
2813 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2814 {
2815         _session->audition_region (region);
2816 }
2817
2818 void
2819 Editor::region_from_selection ()
2820 {
2821         if (clicked_axisview == 0) {
2822                 return;
2823         }
2824
2825         if (selection->time.empty()) {
2826                 return;
2827         }
2828
2829         framepos_t start = selection->time[clicked_selection].start;
2830         framepos_t end = selection->time[clicked_selection].end;
2831
2832         TrackViewList tracks = get_tracks_for_range_action ();
2833
2834         framepos_t selection_cnt = end - start + 1;
2835
2836         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2837                 boost::shared_ptr<Region> current;
2838                 boost::shared_ptr<Playlist> pl;
2839                 framepos_t internal_start;
2840                 string new_name;
2841
2842                 if ((pl = (*i)->playlist()) == 0) {
2843                         continue;
2844                 }
2845
2846                 if ((current = pl->top_region_at (start)) == 0) {
2847                         continue;
2848                 }
2849
2850                 internal_start = start - current->position();
2851                 RegionFactory::region_name (new_name, current->name(), true);
2852
2853                 PropertyList plist;
2854
2855                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2856                 plist.add (ARDOUR::Properties::length, selection_cnt);
2857                 plist.add (ARDOUR::Properties::name, new_name);
2858                 plist.add (ARDOUR::Properties::layer, 0);
2859
2860                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2861         }
2862 }
2863
2864 void
2865 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2866 {
2867         if (selection->time.empty() || selection->tracks.empty()) {
2868                 return;
2869         }
2870
2871         framepos_t start, end;
2872         if (clicked_selection) {
2873                 start = selection->time[clicked_selection].start;
2874                 end = selection->time[clicked_selection].end;
2875         } else {
2876                 start = selection->time.start();
2877                 end = selection->time.end_frame();
2878         }
2879
2880         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2881         sort_track_selection (ts);
2882
2883         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2884                 boost::shared_ptr<Region> current;
2885                 boost::shared_ptr<Playlist> playlist;
2886                 framepos_t internal_start;
2887                 string new_name;
2888
2889                 if ((playlist = (*i)->playlist()) == 0) {
2890                         continue;
2891                 }
2892
2893                 if ((current = playlist->top_region_at(start)) == 0) {
2894                         continue;
2895                 }
2896
2897                 internal_start = start - current->position();
2898                 RegionFactory::region_name (new_name, current->name(), true);
2899
2900                 PropertyList plist;
2901
2902                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2903                 plist.add (ARDOUR::Properties::length, end - start + 1);
2904                 plist.add (ARDOUR::Properties::name, new_name);
2905
2906                 new_regions.push_back (RegionFactory::create (current, plist));
2907         }
2908 }
2909
2910 void
2911 Editor::split_multichannel_region ()
2912 {
2913         RegionSelection rs = get_regions_from_selection_and_entered ();
2914
2915         if (rs.empty()) {
2916                 return;
2917         }
2918
2919         vector< boost::shared_ptr<Region> > v;
2920
2921         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2922                 (*x)->region()->separate_by_channel (*_session, v);
2923         }
2924 }
2925
2926 void
2927 Editor::new_region_from_selection ()
2928 {
2929         region_from_selection ();
2930         cancel_selection ();
2931 }
2932
2933 static void
2934 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2935 {
2936         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2937         // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2938         case Evoral::OverlapNone:
2939                 break;
2940         default:
2941                 rs->push_back (rv);
2942         }
2943 }
2944
2945 /** Return either:
2946  *    - selected tracks, or if there are none...
2947  *    - tracks containing selected regions, or if there are none...
2948  *    - all tracks
2949  * @return tracks.
2950  */
2951 TrackViewList
2952 Editor::get_tracks_for_range_action () const
2953 {
2954         TrackViewList t;
2955
2956         if (selection->tracks.empty()) {
2957
2958                 /* use tracks with selected regions */
2959
2960                 RegionSelection rs = selection->regions;
2961
2962                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2963                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2964
2965                         if (!t.contains (tv)) {
2966                                 t.push_back (tv);
2967                         }
2968                 }
2969
2970                 if (t.empty()) {
2971                         /* no regions and no tracks: use all tracks */
2972                         t = track_views;
2973                 }
2974
2975         } else {
2976
2977                 t = selection->tracks;
2978         }
2979
2980         return t.filter_to_unique_playlists();
2981 }
2982
2983 void
2984 Editor::separate_regions_between (const TimeSelection& ts)
2985 {
2986         bool in_command = false;
2987         boost::shared_ptr<Playlist> playlist;
2988         RegionSelection new_selection;
2989
2990         TrackViewList tmptracks = get_tracks_for_range_action ();
2991         sort_track_selection (tmptracks);
2992
2993         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2994
2995                 RouteTimeAxisView* rtv;
2996
2997                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2998
2999                         if (rtv->is_track()) {
3000
3001                                 /* no edits to destructive tracks */
3002
3003                                 if (rtv->track()->destructive()) {
3004                                         continue;
3005                                 }
3006
3007                                 if ((playlist = rtv->playlist()) != 0) {
3008
3009                                         playlist->clear_changes ();
3010
3011                                         /* XXX need to consider musical time selections here at some point */
3012
3013                                         double speed = rtv->track()->speed();
3014
3015
3016                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3017
3018                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3019                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3020
3021                                                 latest_regionviews.clear ();
3022
3023                                                 playlist->partition ((framepos_t)((*t).start * speed),
3024                                                                 (framepos_t)((*t).end * speed), false);
3025
3026                                                 c.disconnect ();
3027
3028                                                 if (!latest_regionviews.empty()) {
3029
3030                                                         rtv->view()->foreach_regionview (sigc::bind (
3031                                                                                 sigc::ptr_fun (add_if_covered),
3032                                                                                 &(*t), &new_selection));
3033
3034                                                         if (!in_command) {
3035                                                                 begin_reversible_command (_("separate"));
3036                                                                 in_command = true;
3037                                                         }
3038
3039                                                         /* pick up changes to existing regions */
3040
3041                                                         vector<Command*> cmds;
3042                                                         playlist->rdiff (cmds);
3043                                                         _session->add_commands (cmds);
3044
3045                                                         /* pick up changes to the playlist itself (adds/removes)
3046                                                          */
3047
3048                                                         _session->add_command(new StatefulDiffCommand (playlist));
3049                                                 }
3050                                         }
3051                                 }
3052                         }
3053                 }
3054         }
3055
3056         if (in_command) {
3057 //              selection->set (new_selection);
3058
3059                 commit_reversible_command ();
3060         }
3061 }
3062
3063 struct PlaylistState {
3064     boost::shared_ptr<Playlist> playlist;
3065     XMLNode*  before;
3066 };
3067
3068 /** Take tracks from get_tracks_for_range_action and cut any regions
3069  *  on those tracks so that the tracks are empty over the time
3070  *  selection.
3071  */
3072 void
3073 Editor::separate_region_from_selection ()
3074 {
3075         /* preferentially use *all* ranges in the time selection if we're in range mode
3076            to allow discontiguous operation, since get_edit_op_range() currently
3077            returns a single range.
3078         */
3079
3080         if (!selection->time.empty()) {
3081
3082                 separate_regions_between (selection->time);
3083
3084         } else {
3085
3086                 framepos_t start;
3087                 framepos_t end;
3088
3089                 if (get_edit_op_range (start, end)) {
3090
3091                         AudioRange ar (start, end, 1);
3092                         TimeSelection ts;
3093                         ts.push_back (ar);
3094
3095                         separate_regions_between (ts);
3096                 }
3097         }
3098 }
3099
3100 void
3101 Editor::separate_region_from_punch ()
3102 {
3103         Location* loc  = _session->locations()->auto_punch_location();
3104         if (loc) {
3105                 separate_regions_using_location (*loc);
3106         }
3107 }
3108
3109 void
3110 Editor::separate_region_from_loop ()
3111 {
3112         Location* loc  = _session->locations()->auto_loop_location();
3113         if (loc) {
3114                 separate_regions_using_location (*loc);
3115         }
3116 }
3117
3118 void
3119 Editor::separate_regions_using_location (Location& loc)
3120 {
3121         if (loc.is_mark()) {
3122                 return;
3123         }
3124
3125         AudioRange ar (loc.start(), loc.end(), 1);
3126         TimeSelection ts;
3127
3128         ts.push_back (ar);
3129
3130         separate_regions_between (ts);
3131 }
3132
3133 /** Separate regions under the selected region */
3134 void
3135 Editor::separate_under_selected_regions ()
3136 {
3137         vector<PlaylistState> playlists;
3138
3139         RegionSelection rs;
3140
3141         rs = get_regions_from_selection_and_entered();
3142
3143         if (!_session || rs.empty()) {
3144                 return;
3145         }
3146
3147         begin_reversible_command (_("separate region under"));
3148
3149         list<boost::shared_ptr<Region> > regions_to_remove;
3150
3151         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3152                 // we can't just remove the region(s) in this loop because
3153                 // this removes them from the RegionSelection, and they thus
3154                 // disappear from underneath the iterator, and the ++i above
3155                 // SEGVs in a puzzling fashion.
3156
3157                 // so, first iterate over the regions to be removed from rs and
3158                 // add them to the regions_to_remove list, and then
3159                 // iterate over the list to actually remove them.
3160
3161                 regions_to_remove.push_back ((*i)->region());
3162         }
3163
3164         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3165
3166                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3167
3168                 if (!playlist) {
3169                         // is this check necessary?
3170                         continue;
3171                 }
3172
3173                 vector<PlaylistState>::iterator i;
3174
3175                 //only take state if this is a new playlist.
3176                 for (i = playlists.begin(); i != playlists.end(); ++i) {
3177                         if ((*i).playlist == playlist) {
3178                                 break;
3179                         }
3180                 }
3181
3182                 if (i == playlists.end()) {
3183
3184                         PlaylistState before;
3185                         before.playlist = playlist;
3186                         before.before = &playlist->get_state();
3187
3188                         playlist->freeze ();
3189                         playlists.push_back(before);
3190                 }
3191
3192                 //Partition on the region bounds
3193                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3194
3195                 //Re-add region that was just removed due to the partition operation
3196                 playlist->add_region( (*rl), (*rl)->first_frame() );
3197         }
3198
3199         vector<PlaylistState>::iterator pl;
3200
3201         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3202                 (*pl).playlist->thaw ();
3203                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3204         }
3205
3206         commit_reversible_command ();
3207 }
3208
3209 void
3210 Editor::crop_region_to_selection ()
3211 {
3212         if (!selection->time.empty()) {
3213
3214                 crop_region_to (selection->time.start(), selection->time.end_frame());
3215
3216         } else {
3217
3218                 framepos_t start;
3219                 framepos_t end;
3220
3221                 if (get_edit_op_range (start, end)) {
3222                         crop_region_to (start, end);
3223                 }
3224         }
3225
3226 }
3227
3228 void
3229 Editor::crop_region_to (framepos_t start, framepos_t end)
3230 {
3231         vector<boost::shared_ptr<Playlist> > playlists;
3232         boost::shared_ptr<Playlist> playlist;
3233         TrackViewList ts;
3234
3235         if (selection->tracks.empty()) {
3236                 ts = track_views.filter_to_unique_playlists();
3237         } else {
3238                 ts = selection->tracks.filter_to_unique_playlists ();
3239         }
3240
3241         sort_track_selection (ts);
3242
3243         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3244
3245                 RouteTimeAxisView* rtv;
3246
3247                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3248
3249                         boost::shared_ptr<Track> t = rtv->track();
3250
3251                         if (t != 0 && ! t->destructive()) {
3252
3253                                 if ((playlist = rtv->playlist()) != 0) {
3254                                         playlists.push_back (playlist);
3255                                 }
3256                         }
3257                 }
3258         }
3259
3260         if (playlists.empty()) {
3261                 return;
3262         }
3263
3264         framepos_t the_start;
3265         framepos_t the_end;
3266         framepos_t cnt;
3267
3268         begin_reversible_command (_("trim to selection"));
3269
3270         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3271
3272                 boost::shared_ptr<Region> region;
3273
3274                 the_start = start;
3275
3276                 if ((region = (*i)->top_region_at(the_start)) == 0) {
3277                         continue;
3278                 }
3279
3280                 /* now adjust lengths to that we do the right thing
3281                    if the selection extends beyond the region
3282                 */
3283
3284                 the_start = max (the_start, (framepos_t) region->position());
3285                 if (max_framepos - the_start < region->length()) {
3286                         the_end = the_start + region->length() - 1;
3287                 } else {
3288                         the_end = max_framepos;
3289                 }
3290                 the_end = min (end, the_end);
3291                 cnt = the_end - the_start + 1;
3292
3293                 region->clear_changes ();
3294                 region->trim_to (the_start, cnt);
3295                 _session->add_command (new StatefulDiffCommand (region));
3296         }
3297
3298         commit_reversible_command ();
3299 }
3300
3301 void
3302 Editor::region_fill_track ()
3303 {
3304         RegionSelection rs = get_regions_from_selection_and_entered ();
3305
3306         if (!_session || rs.empty()) {
3307                 return;
3308         }
3309
3310         framepos_t const end = _session->current_end_frame ();
3311
3312         begin_reversible_command (Operations::region_fill);
3313
3314         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3315
3316                 boost::shared_ptr<Region> region ((*i)->region());
3317
3318                 boost::shared_ptr<Playlist> pl = region->playlist();
3319
3320                 if (end <= region->last_frame()) {
3321                         return;
3322                 }
3323
3324                 double times = (double) (end - region->last_frame()) / (double) region->length();
3325
3326                 if (times == 0) {
3327                         return;
3328                 }
3329
3330                 pl->clear_changes ();
3331                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3332                 _session->add_command (new StatefulDiffCommand (pl));
3333         }
3334
3335         commit_reversible_command ();
3336 }
3337
3338 void
3339 Editor::region_fill_selection ()
3340 {
3341         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3342                 return;
3343         }
3344
3345         if (selection->time.empty()) {
3346                 return;
3347         }
3348
3349         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3350         if (region == 0) {
3351                 return;
3352         }
3353
3354         framepos_t start = selection->time[clicked_selection].start;
3355         framepos_t end = selection->time[clicked_selection].end;
3356
3357         boost::shared_ptr<Playlist> playlist;
3358
3359         if (selection->tracks.empty()) {
3360                 return;
3361         }
3362
3363         framepos_t selection_length = end - start;
3364         float times = (float)selection_length / region->length();
3365
3366         begin_reversible_command (Operations::fill_selection);
3367
3368         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3369
3370         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3371
3372                 if ((playlist = (*i)->playlist()) == 0) {
3373                         continue;
3374                 }
3375
3376                 playlist->clear_changes ();
3377                 playlist->add_region (RegionFactory::create (region, true), start, times);
3378                 _session->add_command (new StatefulDiffCommand (playlist));
3379         }
3380
3381         commit_reversible_command ();
3382 }
3383
3384 void
3385 Editor::set_region_sync_position ()
3386 {
3387         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3388 }
3389
3390 void
3391 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3392 {
3393         bool in_command = false;
3394
3395         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3396
3397                 if (!(*r)->region()->covers (where)) {
3398                         continue;
3399                 }
3400
3401                 boost::shared_ptr<Region> region ((*r)->region());
3402
3403                 if (!in_command) {
3404                         begin_reversible_command (_("set sync point"));
3405                         in_command = true;
3406                 }
3407
3408                 region->clear_changes ();
3409                 region->set_sync_position (where);
3410                 _session->add_command(new StatefulDiffCommand (region));
3411         }
3412
3413         if (in_command) {
3414                 commit_reversible_command ();
3415         }
3416 }
3417
3418 /** Remove the sync positions of the selection */
3419 void
3420 Editor::remove_region_sync ()
3421 {
3422         RegionSelection rs = get_regions_from_selection_and_entered ();
3423
3424         if (rs.empty()) {
3425                 return;
3426         }
3427
3428         begin_reversible_command (_("remove region sync"));
3429
3430         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3431
3432                 (*i)->region()->clear_changes ();
3433                 (*i)->region()->clear_sync_position ();
3434                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3435         }
3436
3437         commit_reversible_command ();
3438 }
3439
3440 void
3441 Editor::naturalize_region ()
3442 {
3443         RegionSelection rs = get_regions_from_selection_and_entered ();
3444
3445         if (rs.empty()) {
3446                 return;
3447         }
3448
3449         if (rs.size() > 1) {
3450                 begin_reversible_command (_("move regions to original position"));
3451         } else {
3452                 begin_reversible_command (_("move region to original position"));
3453         }
3454
3455         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3456                 (*i)->region()->clear_changes ();
3457                 (*i)->region()->move_to_natural_position ();
3458                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3459         }
3460
3461         commit_reversible_command ();
3462 }
3463
3464 void
3465 Editor::align_regions (RegionPoint what)
3466 {
3467         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3468
3469         if (rs.empty()) {
3470                 return;
3471         }
3472
3473         begin_reversible_command (_("align selection"));
3474
3475         framepos_t const position = get_preferred_edit_position ();
3476
3477         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3478                 align_region_internal ((*i)->region(), what, position);
3479         }
3480
3481         commit_reversible_command ();
3482 }
3483
3484 struct RegionSortByTime {
3485     bool operator() (const RegionView* a, const RegionView* b) {
3486             return a->region()->position() < b->region()->position();
3487     }
3488 };
3489
3490 void
3491 Editor::align_regions_relative (RegionPoint point)
3492 {
3493         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3494
3495         if (rs.empty()) {
3496                 return;
3497         }
3498
3499         framepos_t const position = get_preferred_edit_position ();
3500
3501         framepos_t distance = 0;
3502         framepos_t pos = 0;
3503         int dir = 1;
3504
3505         list<RegionView*> sorted;
3506         rs.by_position (sorted);
3507
3508         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3509
3510         switch (point) {
3511         case Start:
3512                 pos = position;
3513                 if (position > r->position()) {
3514                         distance = position - r->position();
3515                 } else {
3516                         distance = r->position() - position;
3517                         dir = -1;
3518                 }
3519                 break;
3520
3521         case End:
3522                 if (position > r->last_frame()) {
3523                         distance = position - r->last_frame();
3524                         pos = r->position() + distance;
3525                 } else {
3526                         distance = r->last_frame() - position;
3527                         pos = r->position() - distance;
3528                         dir = -1;
3529                 }
3530                 break;
3531
3532         case SyncPoint:
3533                 pos = r->adjust_to_sync (position);
3534                 if (pos > r->position()) {
3535                         distance = pos - r->position();
3536                 } else {
3537                         distance = r->position() - pos;
3538                         dir = -1;
3539                 }
3540                 break;
3541         }
3542
3543         if (pos == r->position()) {
3544                 return;
3545         }
3546
3547         begin_reversible_command (_("align selection (relative)"));
3548
3549         /* move first one specially */
3550
3551         r->clear_changes ();
3552         r->set_position (pos);
3553         _session->add_command(new StatefulDiffCommand (r));
3554
3555         /* move rest by the same amount */
3556
3557         sorted.pop_front();
3558
3559         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3560
3561                 boost::shared_ptr<Region> region ((*i)->region());
3562
3563                 region->clear_changes ();
3564
3565                 if (dir > 0) {
3566                         region->set_position (region->position() + distance);
3567                 } else {
3568                         region->set_position (region->position() - distance);
3569                 }
3570
3571                 _session->add_command(new StatefulDiffCommand (region));
3572
3573         }
3574
3575         commit_reversible_command ();
3576 }
3577
3578 void
3579 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3580 {
3581         begin_reversible_command (_("align region"));
3582         align_region_internal (region, point, position);
3583         commit_reversible_command ();
3584 }
3585
3586 void
3587 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3588 {
3589         region->clear_changes ();
3590
3591         switch (point) {
3592         case SyncPoint:
3593                 region->set_position (region->adjust_to_sync (position));
3594                 break;
3595
3596         case End:
3597                 if (position > region->length()) {
3598                         region->set_position (position - region->length());
3599                 }
3600                 break;
3601
3602         case Start:
3603                 region->set_position (position);
3604                 break;
3605         }
3606
3607         _session->add_command(new StatefulDiffCommand (region));
3608 }
3609
3610 void
3611 Editor::trim_region_front ()
3612 {
3613         trim_region (true);
3614 }
3615
3616 void
3617 Editor::trim_region_back ()
3618 {
3619         trim_region (false);
3620 }
3621
3622 void
3623 Editor::trim_region (bool front)
3624 {
3625         framepos_t where = get_preferred_edit_position();
3626         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3627
3628         if (rs.empty()) {
3629                 return;
3630         }
3631
3632         begin_reversible_command (front ? _("trim front") : _("trim back"));
3633
3634         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3635                 if (!(*i)->region()->locked()) {
3636
3637                         (*i)->region()->clear_changes ();
3638
3639                         if (front) {
3640                                 (*i)->region()->trim_front (where);
3641                                 maybe_locate_with_edit_preroll ( where );
3642                         } else {
3643                                 (*i)->region()->trim_end (where);
3644                                 maybe_locate_with_edit_preroll ( where );
3645                         }
3646
3647                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3648                 }
3649         }
3650
3651         commit_reversible_command ();
3652 }
3653
3654 /** Trim the end of the selected regions to the position of the edit cursor */
3655 void
3656 Editor::trim_region_to_loop ()
3657 {
3658         Location* loc = _session->locations()->auto_loop_location();
3659         if (!loc) {
3660                 return;
3661         }
3662         trim_region_to_location (*loc, _("trim to loop"));
3663 }
3664
3665 void
3666 Editor::trim_region_to_punch ()
3667 {
3668         Location* loc = _session->locations()->auto_punch_location();
3669         if (!loc) {
3670                 return;
3671         }
3672         trim_region_to_location (*loc, _("trim to punch"));
3673 }
3674
3675 void
3676 Editor::trim_region_to_location (const Location& loc, const char* str)
3677 {
3678         RegionSelection rs = get_regions_from_selection_and_entered ();
3679
3680         begin_reversible_command (str);
3681
3682         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3683                 RegionView* rv = (*x);
3684
3685                 /* require region to span proposed trim */
3686                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3687                 case Evoral::OverlapInternal:
3688                         break;
3689                 default:
3690                         continue;
3691                 }
3692
3693                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3694                 if (!tav) {
3695                         return;
3696                 }
3697
3698                 float speed = 1.0;
3699                 framepos_t start;
3700                 framepos_t end;
3701
3702                 if (tav->track() != 0) {
3703                         speed = tav->track()->speed();
3704                 }
3705
3706                 start = session_frame_to_track_frame (loc.start(), speed);
3707                 end = session_frame_to_track_frame (loc.end(), speed);
3708
3709                 rv->region()->clear_changes ();
3710                 rv->region()->trim_to (start, (end - start));
3711                 _session->add_command(new StatefulDiffCommand (rv->region()));
3712         }
3713
3714         commit_reversible_command ();
3715 }
3716
3717 void
3718 Editor::trim_region_to_previous_region_end ()
3719 {
3720         return trim_to_region(false);
3721 }
3722
3723 void
3724 Editor::trim_region_to_next_region_start ()
3725 {
3726         return trim_to_region(true);
3727 }
3728
3729 void
3730 Editor::trim_to_region(bool forward)
3731 {
3732         RegionSelection rs = get_regions_from_selection_and_entered ();
3733
3734         begin_reversible_command (_("trim to region"));
3735
3736         boost::shared_ptr<Region> next_region;
3737
3738         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3739
3740                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3741
3742                 if (!arv) {
3743                         continue;
3744                 }
3745
3746                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3747
3748                 if (!atav) {
3749                         return;
3750                 }
3751
3752                 float speed = 1.0;
3753
3754                 if (atav->track() != 0) {
3755                         speed = atav->track()->speed();
3756                 }
3757
3758
3759                 boost::shared_ptr<Region> region = arv->region();
3760                 boost::shared_ptr<Playlist> playlist (region->playlist());
3761
3762                 region->clear_changes ();
3763
3764                 if (forward) {
3765
3766                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3767
3768                     if (!next_region) {
3769                         continue;
3770                     }
3771
3772                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3773                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3774                 }
3775                 else {
3776
3777                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3778
3779                     if(!next_region){
3780                         continue;
3781                     }
3782
3783                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3784
3785                     arv->region_changed (ARDOUR::bounds_change);
3786                 }
3787
3788                 _session->add_command(new StatefulDiffCommand (region));
3789         }
3790
3791         commit_reversible_command ();
3792 }
3793
3794 void
3795 Editor::unfreeze_route ()
3796 {
3797         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3798                 return;
3799         }
3800
3801         clicked_routeview->track()->unfreeze ();
3802 }
3803
3804 void*
3805 Editor::_freeze_thread (void* arg)
3806 {
3807         return static_cast<Editor*>(arg)->freeze_thread ();
3808 }
3809
3810 void*
3811 Editor::freeze_thread ()
3812 {
3813         /* create event pool because we may need to talk to the session */
3814         SessionEvent::create_per_thread_pool ("freeze events", 64);
3815         /* create per-thread buffers for process() tree to use */
3816         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3817         current_interthread_info->done = true;
3818         return 0;
3819 }
3820
3821 void
3822 Editor::freeze_route ()
3823 {
3824         if (!_session) {
3825                 return;
3826         }
3827
3828         /* stop transport before we start. this is important */
3829
3830         _session->request_transport_speed (0.0);
3831         
3832         /* wait for just a little while, because the above call is asynchronous */
3833
3834         Glib::usleep (250000);
3835
3836         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3837                 return;
3838         }
3839
3840         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3841                 MessageDialog d (
3842                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3843                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3844                         );
3845                 d.set_title (_("Cannot freeze"));
3846                 d.run ();
3847                 return;
3848         }
3849
3850         if (clicked_routeview->track()->has_external_redirects()) {
3851                 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"
3852                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3853                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3854
3855                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3856                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3857                 d.set_title (_("Freeze Limits"));
3858
3859                 int response = d.run ();
3860
3861                 switch (response) {
3862                 case Gtk::RESPONSE_CANCEL:
3863                         return;
3864                 default:
3865                         break;
3866                 }
3867         }
3868
3869         InterThreadInfo itt;
3870         current_interthread_info = &itt;
3871
3872         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3873
3874         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3875
3876         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3877
3878         while (!itt.done && !itt.cancel) {
3879                 gtk_main_iteration ();
3880         }
3881
3882         current_interthread_info = 0;
3883 }
3884
3885 void
3886 Editor::bounce_range_selection (bool replace, bool enable_processing)
3887 {
3888         if (selection->time.empty()) {
3889                 return;
3890         }
3891
3892         TrackSelection views = selection->tracks;
3893
3894         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3895
3896                 if (enable_processing) {
3897
3898                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3899
3900                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3901                                 MessageDialog d (
3902                                         _("You can't perform this operation because the processing of the signal "
3903                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3904                                           "You can do this without processing, which is a different operation.")
3905                                         );
3906                                 d.set_title (_("Cannot bounce"));
3907                                 d.run ();
3908                                 return;
3909                         }
3910                 }
3911         }
3912
3913         framepos_t start = selection->time[clicked_selection].start;
3914         framepos_t end = selection->time[clicked_selection].end;
3915         framepos_t cnt = end - start + 1;
3916
3917         begin_reversible_command (_("bounce range"));
3918
3919         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3920
3921                 RouteTimeAxisView* rtv;
3922
3923                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3924                         continue;
3925                 }
3926
3927                 boost::shared_ptr<Playlist> playlist;
3928
3929                 if ((playlist = rtv->playlist()) == 0) {
3930                         return;
3931                 }
3932
3933                 InterThreadInfo itt;
3934
3935                 playlist->clear_changes ();
3936                 playlist->clear_owned_changes ();
3937
3938                 boost::shared_ptr<Region> r;
3939
3940                 if (enable_processing) {
3941                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3942                 } else {
3943                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3944                 }
3945
3946                 if (!r) {
3947                         continue;
3948                 }
3949
3950                 if (replace) {
3951                         list<AudioRange> ranges;
3952                         ranges.push_back (AudioRange (start, start+cnt, 0));
3953                         playlist->cut (ranges); // discard result
3954                         playlist->add_region (r, start);
3955                 }
3956
3957                 vector<Command*> cmds;
3958                 playlist->rdiff (cmds);
3959                 _session->add_commands (cmds);
3960
3961                 _session->add_command (new StatefulDiffCommand (playlist));
3962         }
3963
3964         commit_reversible_command ();
3965 }
3966
3967 /** Delete selected regions, automation points or a time range */
3968 void
3969 Editor::delete_ ()
3970 {
3971         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3972         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3973         bool deleted = false;
3974         if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3975                 deleted = current_mixer_strip->delete_processors ();
3976
3977         if (!deleted)
3978                 cut_copy (Delete);
3979 }
3980
3981 /** Cut selected regions, automation points or a time range */
3982 void
3983 Editor::cut ()
3984 {
3985         cut_copy (Cut);
3986 }
3987
3988 /** Copy selected regions, automation points or a time range */
3989 void
3990 Editor::copy ()
3991 {
3992         cut_copy (Copy);
3993 }
3994
3995
3996 /** @return true if a Cut, Copy or Clear is possible */
3997 bool
3998 Editor::can_cut_copy () const
3999 {
4000         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4001                 return true;
4002
4003         return false;
4004 }
4005
4006
4007 /** Cut, copy or clear selected regions, automation points or a time range.
4008  * @param op Operation (Delete, Cut, Copy or Clear)
4009  */
4010 void
4011 Editor::cut_copy (CutCopyOp op)
4012 {
4013         /* only cancel selection if cut/copy is successful.*/
4014
4015         string opname;
4016
4017         switch (op) {
4018         case Delete:
4019                 opname = _("delete");
4020                 break;
4021         case Cut:
4022                 opname = _("cut");
4023                 break;
4024         case Copy:
4025                 opname = _("copy");
4026                 break;
4027         case Clear:
4028                 opname = _("clear");
4029                 break;
4030         }
4031
4032         /* if we're deleting something, and the mouse is still pressed,
4033            the thing we started a drag for will be gone when we release
4034            the mouse button(s). avoid this. see part 2 at the end of
4035            this function.
4036         */
4037
4038         if (op == Delete || op == Cut || op == Clear) {
4039                 if (_drags->active ()) {
4040                         _drags->abort ();
4041                 }
4042         }
4043
4044         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
4045                 cut_buffer->clear ();
4046
4047         if (entered_marker) {
4048
4049                 /* cut/delete op while pointing at a marker */
4050
4051                 bool ignored;
4052                 Location* loc = find_location_from_marker (entered_marker, ignored);
4053
4054                 if (_session && loc) {
4055                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4056                 }
4057
4058                 _drags->abort ();
4059                 return;
4060         }
4061
4062         switch (mouse_mode) {
4063         case MouseDraw:
4064         case MouseContent:
4065                 begin_reversible_command (opname + ' ' + X_("MIDI"));
4066                 cut_copy_midi (op);
4067                 commit_reversible_command ();
4068                 return;
4069         default:
4070                 break;
4071         }
4072
4073         bool did_edit = false;
4074
4075         if (!selection->regions.empty() || !selection->points.empty()) {
4076                 begin_reversible_command (opname + ' ' + _("objects"));
4077                 did_edit = true;
4078
4079                 if (!selection->regions.empty()) {
4080                         cut_copy_regions (op, selection->regions);
4081                         
4082                         if (op == Cut || op == Delete) {
4083                                 selection->clear_regions ();
4084                         }
4085                 }
4086                 
4087                 if (!selection->points.empty()) {
4088                         cut_copy_points (op);
4089                         
4090                         if (op == Cut || op == Delete) {
4091                                 selection->clear_points ();
4092                         }
4093                 }
4094         } else if (selection->time.empty()) {
4095                 framepos_t start, end;
4096                 /* no time selection, see if we can get an edit range
4097                    and use that.
4098                 */
4099                 if (get_edit_op_range (start, end)) {
4100                         selection->set (start, end);
4101                 }
4102         } else if (!selection->time.empty()) {
4103                 begin_reversible_command (opname + ' ' + _("range"));
4104
4105                 did_edit = true;
4106                 cut_copy_ranges (op);
4107                 
4108                 if (op == Cut || op == Delete) {
4109                         selection->clear_time ();
4110                 }
4111         }
4112         
4113         if (did_edit) {
4114                 /* reset repeated paste state */
4115                 paste_count    = 0;
4116                 last_paste_pos = 0;
4117                 commit_reversible_command ();   
4118         }
4119         
4120         if (op == Delete || op == Cut || op == Clear) {
4121                 _drags->abort ();
4122         }
4123 }
4124
4125 struct AutomationRecord {
4126         AutomationRecord () : state (0) , line(NULL) {}
4127         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4128         
4129         XMLNode* state; ///< state before any operation
4130         const AutomationLine* line; ///< line this came from
4131         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4132 };
4133
4134 /** Cut, copy or clear selected automation points.
4135  *  @param op Operation (Cut, Copy or Clear)
4136  */
4137 void
4138 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4139 {
4140         if (selection->points.empty ()) {
4141                 return;
4142         }
4143
4144         /* XXX: not ideal, as there may be more than one track involved in the point selection */
4145         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4146
4147         /* Keep a record of the AutomationLists that we end up using in this operation */
4148         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4149         Lists lists;
4150
4151         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4152         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4153                 const AutomationLine&                   line = (*i)->line();
4154                 const boost::shared_ptr<AutomationList> al   = line.the_list();
4155                 if (lists.find (al) == lists.end ()) {
4156                         /* We haven't seen this list yet, so make a record for it.  This includes
4157                            taking a copy of its current state, in case this is needed for undo later.
4158                         */
4159                         lists[al] = AutomationRecord (&al->get_state (), &line);
4160                 }
4161         }
4162
4163         if (op == Cut || op == Copy) {
4164                 /* This operation will involve putting things in the cut buffer, so create an empty
4165                    ControlList for each of our source lists to put the cut buffer data in.
4166                 */
4167                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4168                         i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4169                 }
4170
4171                 /* Add all selected points to the relevant copy ControlLists */
4172                 framepos_t start = std::numeric_limits<framepos_t>::max();
4173                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4174                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4175                         AutomationList::const_iterator    j  = (*i)->model();
4176
4177                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4178                         if (midi) {
4179                                 /* Update earliest MIDI start time in beats */
4180                                 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4181                         } else {
4182                                 /* Update earliest session start time in frames */
4183                                 start = std::min(start, (*i)->line().session_position(j));
4184                         }
4185                 }
4186
4187                 /* Snap start time backwards, so copy/paste is snap aligned. */
4188                 if (midi) {
4189                         if (earliest == Evoral::Beats::max()) {
4190                                 earliest = Evoral::Beats();  // Weird... don't offset
4191                         }
4192                         earliest.round_down_to_beat();
4193                 } else {
4194                         if (start == std::numeric_limits<double>::max()) {
4195                                 start = 0;  // Weird... don't offset
4196                         }
4197                         snap_to(start, RoundDownMaybe);
4198                 }
4199
4200                 const double line_offset = midi ? earliest.to_double() : start;
4201                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4202                         /* Correct this copy list so that it is relative to the earliest
4203                            start time, so relative ordering between points is preserved
4204                            when copying from several lists and the paste starts at the
4205                            earliest copied piece of data. */
4206                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4207                                 (*j)->when -= line_offset;
4208                         }
4209
4210                         /* And add it to the cut buffer */
4211                         cut_buffer->add (i->second.copy);
4212                 }
4213         }
4214                 
4215         if (op == Delete || op == Cut) {
4216                 /* This operation needs to remove things from the main AutomationList, so do that now */
4217                 
4218                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4219                         i->first->freeze ();
4220                 }
4221
4222                 /* Remove each selected point from its AutomationList */
4223                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4224                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4225                         al->erase ((*i)->model ());
4226                 }
4227
4228                 /* Thaw the lists and add undo records for them */
4229                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4230                         boost::shared_ptr<AutomationList> al = i->first;
4231                         al->thaw ();
4232                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4233                 }
4234         }
4235 }
4236
4237 /** Cut, copy or clear selected automation points.
4238  * @param op Operation (Cut, Copy or Clear)
4239  */
4240 void
4241 Editor::cut_copy_midi (CutCopyOp op)
4242 {
4243         Evoral::Beats earliest = Evoral::Beats::max();
4244         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4245                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4246                 if (mrv) {
4247                         if (!mrv->selection().empty()) {
4248                                 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4249                         }
4250                         mrv->cut_copy_clear (op);
4251
4252                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4253                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4254                 }
4255         }
4256
4257         if (!selection->points.empty()) {
4258                 cut_copy_points (op, earliest, true);
4259                 if (op == Cut || op == Delete) {
4260                         selection->clear_points ();
4261                 }
4262         }
4263 }
4264
4265 struct lt_playlist {
4266     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4267             return a.playlist < b.playlist;
4268     }
4269 };
4270
4271 struct PlaylistMapping {
4272     TimeAxisView* tv;
4273     boost::shared_ptr<Playlist> pl;
4274
4275     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4276 };
4277
4278 /** Remove `clicked_regionview' */
4279 void
4280 Editor::remove_clicked_region ()
4281 {
4282         if (clicked_routeview == 0 || clicked_regionview == 0) {
4283                 return;
4284         }
4285
4286         begin_reversible_command (_("remove region"));
4287
4288         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4289
4290         playlist->clear_changes ();
4291         playlist->clear_owned_changes ();
4292         playlist->remove_region (clicked_regionview->region());
4293         if (Config->get_edit_mode() == Ripple)
4294                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4295
4296         /* We might have removed regions, which alters other regions' layering_index,
4297            so we need to do a recursive diff here.
4298         */
4299         vector<Command*> cmds;
4300         playlist->rdiff (cmds);
4301         _session->add_commands (cmds);
4302         
4303         _session->add_command(new StatefulDiffCommand (playlist));
4304         commit_reversible_command ();
4305 }
4306
4307
4308 /** Remove the selected regions */
4309 void
4310 Editor::remove_selected_regions ()
4311 {
4312         RegionSelection rs = get_regions_from_selection_and_entered ();
4313
4314         if (!_session || rs.empty()) {
4315                 return;
4316         }
4317
4318         begin_reversible_command (_("remove region"));
4319
4320         list<boost::shared_ptr<Region> > regions_to_remove;
4321
4322         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4323                 // we can't just remove the region(s) in this loop because
4324                 // this removes them from the RegionSelection, and they thus
4325                 // disappear from underneath the iterator, and the ++i above
4326                 // SEGVs in a puzzling fashion.
4327
4328                 // so, first iterate over the regions to be removed from rs and
4329                 // add them to the regions_to_remove list, and then
4330                 // iterate over the list to actually remove them.
4331
4332                 regions_to_remove.push_back ((*i)->region());
4333         }
4334
4335         vector<boost::shared_ptr<Playlist> > playlists;
4336
4337         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4338
4339                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4340
4341                 if (!playlist) {
4342                         // is this check necessary?
4343                         continue;
4344                 }
4345
4346                 /* get_regions_from_selection_and_entered() guarantees that
4347                    the playlists involved are unique, so there is no need
4348                    to check here.
4349                 */
4350
4351                 playlists.push_back (playlist);
4352
4353                 playlist->clear_changes ();
4354                 playlist->clear_owned_changes ();
4355                 playlist->freeze ();
4356                 playlist->remove_region (*rl);
4357                 if (Config->get_edit_mode() == Ripple)
4358                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4359
4360         }
4361
4362         vector<boost::shared_ptr<Playlist> >::iterator pl;
4363
4364         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4365                 (*pl)->thaw ();
4366
4367                 /* We might have removed regions, which alters other regions' layering_index,
4368                    so we need to do a recursive diff here.
4369                 */
4370                 vector<Command*> cmds;
4371                 (*pl)->rdiff (cmds);
4372                 _session->add_commands (cmds);
4373                 
4374                 _session->add_command(new StatefulDiffCommand (*pl));
4375         }
4376
4377         commit_reversible_command ();
4378 }
4379
4380 /** Cut, copy or clear selected regions.
4381  * @param op Operation (Cut, Copy or Clear)
4382  */
4383 void
4384 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4385 {
4386         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4387            a map when we want ordered access to both elements. i think.
4388         */
4389
4390         vector<PlaylistMapping> pmap;
4391
4392         framepos_t first_position = max_framepos;
4393
4394         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4395         FreezeList freezelist;
4396
4397         /* get ordering correct before we cut/copy */
4398
4399         rs.sort_by_position_and_track ();
4400
4401         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4402
4403                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4404
4405                 if (op == Cut || op == Clear || op == Delete) {
4406                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4407
4408                         if (pl) {
4409                                 FreezeList::iterator fl;
4410
4411                                 // only take state if this is a new playlist.
4412                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4413                                         if ((*fl) == pl) {
4414                                                 break;
4415                                         }
4416                                 }
4417
4418                                 if (fl == freezelist.end()) {
4419                                         pl->clear_changes();
4420                                         pl->clear_owned_changes ();
4421                                         pl->freeze ();
4422                                         freezelist.insert (pl);
4423                                 }
4424                         }
4425                 }
4426
4427                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4428                 vector<PlaylistMapping>::iterator z;
4429
4430                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4431                         if ((*z).tv == tv) {
4432                                 break;
4433                         }
4434                 }
4435
4436                 if (z == pmap.end()) {
4437                         pmap.push_back (PlaylistMapping (tv));
4438                 }
4439         }
4440
4441         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4442
4443                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4444
4445                 if (!pl) {
4446                         /* region not yet associated with a playlist (e.g. unfinished
4447                            capture pass.
4448                         */
4449                         ++x;
4450                         continue;
4451                 }
4452
4453                 TimeAxisView& tv = (*x)->get_time_axis_view();
4454                 boost::shared_ptr<Playlist> npl;
4455                 RegionSelection::iterator tmp;
4456
4457                 tmp = x;
4458                 ++tmp;
4459
4460                 if (op != Delete) {
4461
4462                         vector<PlaylistMapping>::iterator z;
4463                         
4464                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4465                                 if ((*z).tv == &tv) {
4466                                         break;
4467                                 }
4468                         }
4469                         
4470                         assert (z != pmap.end());
4471                         
4472                         if (!(*z).pl) {
4473                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4474                                 npl->freeze();
4475                                 (*z).pl = npl;
4476                         } else {
4477                                 npl = (*z).pl;
4478                         }
4479                 }
4480
4481                 boost::shared_ptr<Region> r = (*x)->region();
4482                 boost::shared_ptr<Region> _xx;
4483
4484                 assert (r != 0);
4485
4486                 switch (op) {
4487                 case Delete:
4488                         pl->remove_region (r);
4489                         if (Config->get_edit_mode() == Ripple)
4490                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4491                         break;
4492                         
4493                 case Cut:
4494                         _xx = RegionFactory::create (r);
4495                         npl->add_region (_xx, r->position() - first_position);
4496                         pl->remove_region (r);
4497                         if (Config->get_edit_mode() == Ripple)
4498                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4499                         break;
4500
4501                 case Copy:
4502                         /* copy region before adding, so we're not putting same object into two different playlists */
4503                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4504                         break;
4505
4506                 case Clear:
4507                         pl->remove_region (r);
4508                         if (Config->get_edit_mode() == Ripple)
4509                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4510                         break;
4511                 }
4512
4513                 x = tmp;
4514         }
4515
4516         if (op != Delete) {
4517
4518                 list<boost::shared_ptr<Playlist> > foo;
4519                 
4520                 /* the pmap is in the same order as the tracks in which selected regions occured */
4521                 
4522                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4523                         if ((*i).pl) {
4524                                 (*i).pl->thaw();
4525                                 foo.push_back ((*i).pl);
4526                         }
4527                 }
4528                 
4529                 if (!foo.empty()) {
4530                         cut_buffer->set (foo);
4531                 }
4532                 
4533                 if (pmap.empty()) {
4534                         _last_cut_copy_source_track = 0;
4535                 } else {
4536                         _last_cut_copy_source_track = pmap.front().tv;
4537                 }
4538         }
4539
4540         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4541                 (*pl)->thaw ();
4542
4543                 /* We might have removed regions, which alters other regions' layering_index,
4544                    so we need to do a recursive diff here.
4545                 */
4546                 vector<Command*> cmds;
4547                 (*pl)->rdiff (cmds);
4548                 _session->add_commands (cmds);
4549                 
4550                 _session->add_command (new StatefulDiffCommand (*pl));
4551         }
4552 }
4553
4554 void
4555 Editor::cut_copy_ranges (CutCopyOp op)
4556 {
4557         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4558
4559         /* Sort the track selection now, so that it if is used, the playlists
4560            selected by the calls below to cut_copy_clear are in the order that
4561            their tracks appear in the editor.  This makes things like paste
4562            of ranges work properly.
4563         */
4564
4565         sort_track_selection (ts);
4566
4567         if (ts.empty()) {
4568                 if (!entered_track) {
4569                         return;
4570                 }
4571                 ts.push_back (entered_track);
4572         } 
4573
4574         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4575                 (*i)->cut_copy_clear (*selection, op);
4576         }
4577 }
4578
4579 void
4580 Editor::paste (float times, bool from_context)
4581 {
4582         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4583
4584         paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4585 }
4586
4587 void
4588 Editor::mouse_paste ()
4589 {
4590         framepos_t where;
4591         bool ignored;
4592
4593         if (!mouse_frame (where, ignored)) {
4594                 return;
4595         }
4596
4597         snap_to (where);
4598         paste_internal (where, 1);
4599 }
4600
4601 void
4602 Editor::paste_internal (framepos_t position, float times)
4603 {
4604         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4605
4606         if (cut_buffer->empty(internal_editing())) {
4607                 return;
4608         }
4609
4610         if (position == max_framepos) {
4611                 position = get_preferred_edit_position();
4612                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4613         }
4614
4615         if (position == last_paste_pos) {
4616                 /* repeated paste in the same position */
4617                 ++paste_count;
4618         } else {
4619                 /* paste in new location, reset repeated paste state */
4620                 paste_count = 0;
4621                 last_paste_pos = position;
4622         }
4623
4624         /* get everything in the correct order */
4625
4626         TrackViewList ts;
4627         if (!selection->tracks.empty()) {
4628                 /* If there is a track selection, paste into exactly those tracks and
4629                    only those tracks.  This allows the user to be explicit and override
4630                    the below "do the reasonable thing" logic. */
4631                 ts = selection->tracks.filter_to_unique_playlists ();
4632                 sort_track_selection (ts);
4633         } else {
4634                 /* Figure out which track to base the paste at. */
4635                 TimeAxisView* base_track = NULL;
4636                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4637                         /* With the mouse edit point, paste onto the track under the mouse. */
4638                         base_track = entered_track;
4639                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4640                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4641                         base_track = &entered_regionview->get_time_axis_view();
4642                 } else if (_last_cut_copy_source_track) {
4643                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4644                         base_track = _last_cut_copy_source_track;
4645                 } else {
4646                         /* This is "impossible" since we've copied... well, do nothing. */
4647                         return;
4648                 }
4649
4650                 /* Walk up to parent if necessary, so base track is a route. */
4651                 while (base_track->get_parent()) {
4652                         base_track = base_track->get_parent();
4653                 }
4654
4655                 /* Add base track and all tracks below it.  The paste logic will select
4656                    the appropriate object types from the cut buffer in relative order. */
4657                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4658                         if ((*i)->order() >= base_track->order()) {
4659                                 ts.push_back(*i);
4660                         }
4661                 }
4662
4663                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4664                 sort_track_selection (ts);
4665
4666                 /* Add automation children of each track in order, for pasting several lines. */
4667                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4668                         /* Add any automation children for pasting several lines */
4669                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4670                         if (!rtv) {
4671                                 continue;
4672                         }
4673
4674                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4675                         const ATracks& atracks = rtv->automation_tracks();
4676                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4677                                 i = ts.insert(i, a->second.get());
4678                                 ++i;
4679                         }
4680                 }
4681
4682                 /* We now have a list of trackviews starting at base_track, including
4683                    automation children, in the order shown in the editor, e.g. R1,
4684                    R1.A1, R1.A2, R2, R2.A1, ... */
4685         }
4686
4687         begin_reversible_command (Operations::paste);
4688
4689         if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4690             dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4691             /* Only one line copied, and one automation track selected.  Do a
4692                "greedy" paste from one automation type to another. */
4693
4694             PasteContext ctx(paste_count, times, ItemCounts(), true);
4695             ts.front()->paste (position, *cut_buffer, ctx);
4696
4697         } else {
4698
4699                 /* Paste into tracks */
4700
4701                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4702                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4703                         (*i)->paste (position, *cut_buffer, ctx);
4704                 }
4705         }
4706
4707         commit_reversible_command ();
4708 }
4709
4710 void
4711 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4712 {
4713         boost::shared_ptr<Playlist> playlist;
4714         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4715         RegionSelection foo;
4716
4717         framepos_t const start_frame = regions.start ();
4718         framepos_t const end_frame = regions.end_frame ();
4719
4720         begin_reversible_command (Operations::duplicate_region);
4721
4722         selection->clear_regions ();
4723
4724         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4725
4726                 boost::shared_ptr<Region> r ((*i)->region());
4727
4728                 TimeAxisView& tv = (*i)->get_time_axis_view();
4729                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4730                 latest_regionviews.clear ();
4731                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4732
4733                 playlist = (*i)->region()->playlist();
4734                 playlist->clear_changes ();
4735                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4736                 _session->add_command(new StatefulDiffCommand (playlist));
4737
4738                 c.disconnect ();
4739
4740                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4741         }
4742
4743         if (!foo.empty()) {
4744                 selection->set (foo);
4745         }
4746
4747         commit_reversible_command ();
4748 }
4749
4750 void
4751 Editor::duplicate_selection (float times)
4752 {
4753         if (selection->time.empty() || selection->tracks.empty()) {
4754                 return;
4755         }
4756
4757         boost::shared_ptr<Playlist> playlist;
4758         vector<boost::shared_ptr<Region> > new_regions;
4759         vector<boost::shared_ptr<Region> >::iterator ri;
4760
4761         create_region_from_selection (new_regions);
4762
4763         if (new_regions.empty()) {
4764                 return;
4765         }
4766
4767         begin_reversible_command (_("duplicate selection"));
4768
4769         ri = new_regions.begin();
4770
4771         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4772
4773         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4774                 if ((playlist = (*i)->playlist()) == 0) {
4775                         continue;
4776                 }
4777                 playlist->clear_changes ();
4778                 framepos_t end;
4779                 if (clicked_selection) {
4780                         end = selection->time[clicked_selection].end;
4781                 } else {
4782                         end = selection->time.end_frame();
4783                 }
4784                 playlist->duplicate (*ri, end, times);
4785                 _session->add_command (new StatefulDiffCommand (playlist));
4786
4787                 ++ri;
4788                 if (ri == new_regions.end()) {
4789                         --ri;
4790                 }
4791         }
4792
4793         commit_reversible_command ();
4794 }
4795
4796 /** Reset all selected points to the relevant default value */
4797 void
4798 Editor::reset_point_selection ()
4799 {
4800         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4801                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4802                 (*j)->value = (*i)->line().the_list()->default_value ();
4803         }
4804 }
4805
4806 void
4807 Editor::center_playhead ()
4808 {
4809         float const page = _visible_canvas_width * samples_per_pixel;
4810         center_screen_internal (playhead_cursor->current_frame (), page);
4811 }
4812
4813 void
4814 Editor::center_edit_point ()
4815 {
4816         float const page = _visible_canvas_width * samples_per_pixel;
4817         center_screen_internal (get_preferred_edit_position(), page);
4818 }
4819
4820 /** Caller must begin and commit a reversible command */
4821 void
4822 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4823 {
4824         playlist->clear_changes ();
4825         playlist->clear ();
4826         _session->add_command (new StatefulDiffCommand (playlist));
4827 }
4828
4829 void
4830 Editor::nudge_track (bool use_edit, bool forwards)
4831 {
4832         boost::shared_ptr<Playlist> playlist;
4833         framepos_t distance;
4834         framepos_t next_distance;
4835         framepos_t start;
4836
4837         if (use_edit) {
4838                 start = get_preferred_edit_position();
4839         } else {
4840                 start = 0;
4841         }
4842
4843         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4844                 return;
4845         }
4846
4847         if (selection->tracks.empty()) {
4848                 return;
4849         }
4850
4851         begin_reversible_command (_("nudge track"));
4852
4853         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4854
4855         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4856
4857                 if ((playlist = (*i)->playlist()) == 0) {
4858                         continue;
4859                 }
4860
4861                 playlist->clear_changes ();
4862                 playlist->clear_owned_changes ();
4863
4864                 playlist->nudge_after (start, distance, forwards);
4865
4866                 vector<Command*> cmds;
4867
4868                 playlist->rdiff (cmds);
4869                 _session->add_commands (cmds);
4870
4871                 _session->add_command (new StatefulDiffCommand (playlist));
4872         }
4873
4874         commit_reversible_command ();
4875 }
4876
4877 void
4878 Editor::remove_last_capture ()
4879 {
4880         vector<string> choices;
4881         string prompt;
4882
4883         if (!_session) {
4884                 return;
4885         }
4886
4887         if (Config->get_verify_remove_last_capture()) {
4888                 prompt  = _("Do you really want to destroy the last capture?"
4889                             "\n(This is destructive and cannot be undone)");
4890
4891                 choices.push_back (_("No, do nothing."));
4892                 choices.push_back (_("Yes, destroy it."));
4893
4894                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4895
4896                 if (prompter.run () == 1) {
4897                         _session->remove_last_capture ();
4898                         _regions->redisplay ();
4899                 }
4900
4901         } else {
4902                 _session->remove_last_capture();
4903                 _regions->redisplay ();
4904         }
4905 }
4906
4907 void
4908 Editor::normalize_region ()
4909 {
4910         if (!_session) {
4911                 return;
4912         }
4913
4914         RegionSelection rs = get_regions_from_selection_and_entered ();
4915
4916         if (rs.empty()) {
4917                 return;
4918         }
4919
4920         NormalizeDialog dialog (rs.size() > 1);
4921
4922         if (dialog.run () == RESPONSE_CANCEL) {
4923                 return;
4924         }
4925
4926         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4927         gdk_flush ();
4928
4929         /* XXX: should really only count audio regions here */
4930         int const regions = rs.size ();
4931
4932         /* Make a list of the selected audio regions' maximum amplitudes, and also
4933            obtain the maximum amplitude of them all.
4934         */
4935         list<double> max_amps;
4936         double max_amp = 0;
4937         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4938                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4939                 if (arv) {
4940                         dialog.descend (1.0 / regions);
4941                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4942
4943                         if (a == -1) {
4944                                 /* the user cancelled the operation */
4945                                 return;
4946                         }
4947
4948                         max_amps.push_back (a);
4949                         max_amp = max (max_amp, a);
4950                         dialog.ascend ();
4951                 }
4952         }
4953
4954         begin_reversible_command (_("normalize"));
4955
4956         list<double>::const_iterator a = max_amps.begin ();
4957
4958         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4959                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4960                 if (!arv) {
4961                         continue;
4962                 }
4963
4964                 arv->region()->clear_changes ();
4965
4966                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4967
4968                 arv->audio_region()->normalize (amp, dialog.target ());
4969                 _session->add_command (new StatefulDiffCommand (arv->region()));
4970
4971                 ++a;
4972         }
4973
4974         commit_reversible_command ();
4975 }
4976
4977
4978 void
4979 Editor::reset_region_scale_amplitude ()
4980 {
4981         if (!_session) {
4982                 return;
4983         }
4984
4985         RegionSelection rs = get_regions_from_selection_and_entered ();
4986
4987         if (rs.empty()) {
4988                 return;
4989         }
4990
4991         begin_reversible_command ("reset gain");
4992
4993         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4994                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4995                 if (!arv)
4996                         continue;
4997                 arv->region()->clear_changes ();
4998                 arv->audio_region()->set_scale_amplitude (1.0f);
4999                 _session->add_command (new StatefulDiffCommand (arv->region()));
5000         }
5001
5002         commit_reversible_command ();
5003 }
5004
5005 void
5006 Editor::adjust_region_gain (bool up)
5007 {
5008         RegionSelection rs = get_regions_from_selection_and_entered ();
5009
5010         if (!_session || rs.empty()) {
5011                 return;
5012         }
5013
5014         begin_reversible_command ("adjust region gain");
5015
5016         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5017                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5018                 if (!arv) {
5019                         continue;
5020                 }
5021
5022                 arv->region()->clear_changes ();
5023
5024                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5025
5026                 if (up) {
5027                         dB += 1;
5028                 } else {
5029                         dB -= 1;
5030                 }
5031
5032                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5033                 _session->add_command (new StatefulDiffCommand (arv->region()));
5034         }
5035
5036         commit_reversible_command ();
5037 }
5038
5039
5040 void
5041 Editor::reverse_region ()
5042 {
5043         if (!_session) {
5044                 return;
5045         }
5046
5047         Reverse rev (*_session);
5048         apply_filter (rev, _("reverse regions"));
5049 }
5050
5051 void
5052 Editor::strip_region_silence ()
5053 {
5054         if (!_session) {
5055                 return;
5056         }
5057
5058         RegionSelection rs = get_regions_from_selection_and_entered ();
5059
5060         if (rs.empty()) {
5061                 return;
5062         }
5063
5064         std::list<RegionView*> audio_only;
5065
5066         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5067                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5068                 if (arv) {
5069                         audio_only.push_back (arv);
5070                 }
5071         }
5072
5073         StripSilenceDialog d (_session, audio_only);
5074         int const r = d.run ();
5075
5076         d.drop_rects ();
5077
5078         if (r == Gtk::RESPONSE_OK) {
5079                 ARDOUR::AudioIntervalMap silences;
5080                 d.silences (silences);
5081                 StripSilence s (*_session, silences, d.fade_length());
5082                 apply_filter (s, _("strip silence"), &d);
5083         }
5084 }
5085
5086 Command*
5087 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5088 {
5089         Evoral::Sequence<Evoral::Beats>::Notes selected;
5090         mrv.selection_as_notelist (selected, true);
5091
5092         vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5093         v.push_back (selected);
5094
5095         framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5096         Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5097
5098         return op (mrv.midi_region()->model(), pos_beats, v);
5099 }
5100
5101 void
5102 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5103 {
5104         if (rs.empty()) {
5105                 return;
5106         }
5107
5108         begin_reversible_command (op.name ());
5109
5110         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5111                 RegionSelection::const_iterator tmp = r;
5112                 ++tmp;
5113
5114                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5115
5116                 if (mrv) {
5117                         Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5118                         if (cmd) {
5119                                 (*cmd)();
5120                                 _session->add_command (cmd);
5121                         }
5122                 }
5123
5124                 r = tmp;
5125         }
5126
5127         commit_reversible_command ();
5128 }
5129
5130 void
5131 Editor::fork_region ()
5132 {
5133         RegionSelection rs = get_regions_from_selection_and_entered ();
5134
5135         if (rs.empty()) {
5136                 return;
5137         }
5138
5139         begin_reversible_command (_("Fork Region(s)"));
5140
5141         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5142         gdk_flush ();
5143
5144         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5145                 RegionSelection::iterator tmp = r;
5146                 ++tmp;
5147
5148                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5149
5150                 if (mrv) {
5151                         try {
5152                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5153                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5154                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5155                                 
5156                                 playlist->clear_changes ();
5157                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5158                                 _session->add_command(new StatefulDiffCommand (playlist));
5159                         } catch (...) {
5160                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5161                         }
5162                 }
5163
5164                 r = tmp;
5165         }
5166
5167         commit_reversible_command ();
5168 }
5169
5170 void
5171 Editor::quantize_region ()
5172 {
5173         if (_session) {
5174                 quantize_regions(get_regions_from_selection_and_entered ());
5175         }
5176 }
5177
5178 void
5179 Editor::quantize_regions (const RegionSelection& rs)
5180 {
5181         if (rs.n_midi_regions() == 0) {
5182                 return;
5183         }
5184
5185         if (!quantize_dialog) {
5186                 quantize_dialog = new QuantizeDialog (*this);
5187         }
5188
5189         quantize_dialog->present ();
5190         const int r = quantize_dialog->run ();
5191         quantize_dialog->hide ();
5192
5193         if (r == Gtk::RESPONSE_OK) {
5194                 Quantize quant (quantize_dialog->snap_start(),
5195                                 quantize_dialog->snap_end(),
5196                                 quantize_dialog->start_grid_size(),
5197                                 quantize_dialog->end_grid_size(),
5198                                 quantize_dialog->strength(),
5199                                 quantize_dialog->swing(),
5200                                 quantize_dialog->threshold());
5201
5202                 apply_midi_note_edit_op (quant, rs);
5203         }
5204 }
5205
5206 void
5207 Editor::legatize_region (bool shrink_only)
5208 {
5209         if (_session) {
5210                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5211         }
5212 }
5213
5214 void
5215 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5216 {
5217         if (rs.n_midi_regions() == 0) {
5218                 return;
5219         }
5220
5221         Legatize legatize(shrink_only);
5222         apply_midi_note_edit_op (legatize, rs);
5223 }
5224
5225 void
5226 Editor::transform_region ()
5227 {
5228         if (_session) {
5229                 transform_regions(get_regions_from_selection_and_entered ());
5230         }
5231 }
5232
5233 void
5234 Editor::transform_regions (const RegionSelection& rs)
5235 {
5236         if (rs.n_midi_regions() == 0) {
5237                 return;
5238         }
5239
5240         TransformDialog* td = new TransformDialog();
5241
5242         td->present();
5243         const int r = td->run();
5244         td->hide();
5245
5246         if (r == Gtk::RESPONSE_OK) {
5247                 Transform transform(td->get());
5248                 apply_midi_note_edit_op(transform, rs);
5249         }
5250 }
5251
5252 void
5253 Editor::insert_patch_change (bool from_context)
5254 {
5255         RegionSelection rs = get_regions_from_selection_and_entered ();
5256
5257         if (rs.empty ()) {
5258                 return;
5259         }
5260
5261         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5262
5263         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5264            there may be more than one, but the PatchChangeDialog can only offer
5265            one set of patch menus.
5266         */
5267         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5268
5269         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5270         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5271
5272         if (d.run() == RESPONSE_CANCEL) {
5273                 return;
5274         }
5275
5276         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5277                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5278                 if (mrv) {
5279                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5280                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5281                         }
5282                 }
5283         }
5284 }
5285
5286 void
5287 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5288 {
5289         RegionSelection rs = get_regions_from_selection_and_entered ();
5290
5291         if (rs.empty()) {
5292                 return;
5293         }
5294
5295         begin_reversible_command (command);
5296
5297         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5298         gdk_flush ();
5299
5300         int n = 0;
5301         int const N = rs.size ();
5302
5303         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5304                 RegionSelection::iterator tmp = r;
5305                 ++tmp;
5306
5307                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5308                 if (arv) {
5309                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5310
5311                         if (progress) {
5312                                 progress->descend (1.0 / N);
5313                         }
5314
5315                         if (arv->audio_region()->apply (filter, progress) == 0) {
5316
5317                                 playlist->clear_changes ();
5318                                 playlist->clear_owned_changes ();
5319
5320                                 if (filter.results.empty ()) {
5321
5322                                         /* no regions returned; remove the old one */
5323                                         playlist->remove_region (arv->region ());
5324
5325                                 } else {
5326
5327                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5328
5329                                         /* first region replaces the old one */
5330                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5331                                         ++res;
5332
5333                                         /* add the rest */
5334                                         while (res != filter.results.end()) {
5335                                                 playlist->add_region (*res, (*res)->position());
5336                                                 ++res;
5337                                         }
5338
5339                                 }
5340
5341                                 /* We might have removed regions, which alters other regions' layering_index,
5342                                    so we need to do a recursive diff here.
5343                                 */
5344                                 vector<Command*> cmds;
5345                                 playlist->rdiff (cmds);
5346                                 _session->add_commands (cmds);
5347                                 
5348                                 _session->add_command(new StatefulDiffCommand (playlist));
5349                         } else {
5350                                 return;
5351                         }
5352
5353                         if (progress) {
5354                                 progress->ascend ();
5355                         }
5356                 }
5357
5358                 r = tmp;
5359                 ++n;
5360         }
5361
5362         commit_reversible_command ();
5363 }
5364
5365 void
5366 Editor::external_edit_region ()
5367 {
5368         /* more to come */
5369 }
5370
5371 void
5372 Editor::reset_region_gain_envelopes ()
5373 {
5374         RegionSelection rs = get_regions_from_selection_and_entered ();
5375
5376         if (!_session || rs.empty()) {
5377                 return;
5378         }
5379
5380         begin_reversible_command (_("reset region gain"));
5381         
5382         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5383                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5384                 if (arv) {
5385                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5386                         XMLNode& before (alist->get_state());
5387
5388                         arv->audio_region()->set_default_envelope ();
5389                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5390                 }
5391         }
5392         
5393         commit_reversible_command ();
5394 }
5395
5396 void
5397 Editor::set_region_gain_visibility (RegionView* rv)
5398 {
5399         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5400         if (arv) {
5401                 arv->update_envelope_visibility();
5402         }
5403 }
5404
5405 void
5406 Editor::set_gain_envelope_visibility ()
5407 {
5408         if (!_session) {
5409                 return;
5410         }
5411
5412         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5413                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5414                 if (v) {
5415                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5416                 }
5417         }
5418 }
5419
5420 void
5421 Editor::toggle_gain_envelope_active ()
5422 {
5423         if (_ignore_region_action) {
5424                 return;
5425         }
5426
5427         RegionSelection rs = get_regions_from_selection_and_entered ();
5428
5429         if (!_session || rs.empty()) {
5430                 return;
5431         }
5432
5433         begin_reversible_command (_("region gain envelope active"));
5434         
5435         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5436                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5437                 if (arv) {
5438                         arv->region()->clear_changes ();
5439                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5440                         _session->add_command (new StatefulDiffCommand (arv->region()));
5441                 }
5442         }
5443         
5444         commit_reversible_command ();
5445 }
5446
5447 void
5448 Editor::toggle_region_lock ()
5449 {
5450         if (_ignore_region_action) {
5451                 return;
5452         }
5453
5454         RegionSelection rs = get_regions_from_selection_and_entered ();
5455
5456         if (!_session || rs.empty()) {
5457                 return;
5458         }
5459
5460         begin_reversible_command (_("toggle region lock"));
5461         
5462         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5463                 (*i)->region()->clear_changes ();
5464                 (*i)->region()->set_locked (!(*i)->region()->locked());
5465                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5466         }
5467         
5468         commit_reversible_command ();
5469 }
5470
5471 void
5472 Editor::toggle_region_video_lock ()
5473 {
5474         if (_ignore_region_action) {
5475                 return;
5476         }
5477
5478         RegionSelection rs = get_regions_from_selection_and_entered ();
5479
5480         if (!_session || rs.empty()) {
5481                 return;
5482         }
5483
5484         begin_reversible_command (_("Toggle Video Lock"));
5485         
5486         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5487                 (*i)->region()->clear_changes ();
5488                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5489                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5490         }
5491         
5492         commit_reversible_command ();
5493 }
5494
5495 void
5496 Editor::toggle_region_lock_style ()
5497 {
5498         if (_ignore_region_action) {
5499                 return;
5500         }
5501
5502         RegionSelection rs = get_regions_from_selection_and_entered ();
5503
5504         if (!_session || rs.empty()) {
5505                 return;
5506         }
5507
5508         begin_reversible_command (_("region lock style"));
5509         
5510         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5511                 (*i)->region()->clear_changes ();
5512                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5513                 (*i)->region()->set_position_lock_style (ns);
5514                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5515         }
5516         
5517         commit_reversible_command ();
5518 }
5519
5520 void
5521 Editor::toggle_opaque_region ()
5522 {
5523         if (_ignore_region_action) {
5524                 return;
5525         }
5526
5527         RegionSelection rs = get_regions_from_selection_and_entered ();
5528
5529         if (!_session || rs.empty()) {
5530                 return;
5531         }
5532
5533         begin_reversible_command (_("change region opacity"));
5534         
5535         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5536                 (*i)->region()->clear_changes ();
5537                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5538                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5539         }
5540         
5541         commit_reversible_command ();
5542 }
5543
5544 void
5545 Editor::toggle_record_enable ()
5546 {
5547         bool new_state = false;
5548         bool first = true;
5549         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5550                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5551                 if (!rtav)
5552                         continue;
5553                 if (!rtav->is_track())
5554                         continue;
5555
5556                 if (first) {
5557                         new_state = !rtav->track()->record_enabled();
5558                         first = false;
5559                 }
5560
5561                 rtav->track()->set_record_enabled (new_state, this);
5562         }
5563 }
5564
5565 void
5566 Editor::toggle_solo ()
5567 {
5568         bool new_state = false;
5569         bool first = true;
5570         boost::shared_ptr<RouteList> rl (new RouteList);
5571
5572         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5573                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5574
5575                 if (!rtav) {
5576                         continue;
5577                 }
5578
5579                 if (first) {
5580                         new_state = !rtav->route()->soloed ();
5581                         first = false;
5582                 }
5583
5584                 rl->push_back (rtav->route());
5585         }
5586
5587         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5588 }
5589
5590 void
5591 Editor::toggle_mute ()
5592 {
5593         bool new_state = false;
5594         bool first = true;
5595         boost::shared_ptr<RouteList> rl (new RouteList);
5596
5597         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5598                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5599
5600                 if (!rtav) {
5601                         continue;
5602                 }
5603
5604                 if (first) {
5605                         new_state = !rtav->route()->muted();
5606                         first = false;
5607                 }
5608
5609                 rl->push_back (rtav->route());
5610         }
5611
5612         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5613 }
5614
5615 void
5616 Editor::toggle_solo_isolate ()
5617 {
5618 }
5619
5620
5621 void
5622 Editor::fade_range ()
5623 {
5624         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5625
5626         begin_reversible_command (_("fade range"));
5627
5628         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5629                 (*i)->fade_range (selection->time);
5630         }
5631
5632         commit_reversible_command ();
5633 }
5634
5635
5636 void
5637 Editor::set_fade_length (bool in)
5638 {
5639         RegionSelection rs = get_regions_from_selection_and_entered ();
5640
5641         if (rs.empty()) {
5642                 return;
5643         }
5644
5645         /* we need a region to measure the offset from the start */
5646
5647         RegionView* rv = rs.front ();
5648
5649         framepos_t pos = get_preferred_edit_position();
5650         framepos_t len;
5651         char const * cmd;
5652
5653         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5654                 /* edit point is outside the relevant region */
5655                 return;
5656         }
5657
5658         if (in) {
5659                 if (pos <= rv->region()->position()) {
5660                         /* can't do it */
5661                         return;
5662                 }
5663                 len = pos - rv->region()->position();
5664                 cmd = _("set fade in length");
5665         } else {
5666                 if (pos >= rv->region()->last_frame()) {
5667                         /* can't do it */
5668                         return;
5669                 }
5670                 len = rv->region()->last_frame() - pos;
5671                 cmd = _("set fade out length");
5672         }
5673
5674         begin_reversible_command (cmd);
5675
5676         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5677                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5678
5679                 if (!tmp) {
5680                         return;
5681                 }
5682
5683                 boost::shared_ptr<AutomationList> alist;
5684                 if (in) {
5685                         alist = tmp->audio_region()->fade_in();
5686                 } else {
5687                         alist = tmp->audio_region()->fade_out();
5688                 }
5689
5690                 XMLNode &before = alist->get_state();
5691
5692                 if (in) {
5693                         tmp->audio_region()->set_fade_in_length (len);
5694                         tmp->audio_region()->set_fade_in_active (true);
5695                 } else {
5696                         tmp->audio_region()->set_fade_out_length (len);
5697                         tmp->audio_region()->set_fade_out_active (true);
5698                 }
5699
5700                 XMLNode &after = alist->get_state();
5701                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5702         }
5703
5704         commit_reversible_command ();
5705 }
5706
5707 void
5708 Editor::set_fade_in_shape (FadeShape shape)
5709 {
5710         RegionSelection rs = get_regions_from_selection_and_entered ();
5711
5712         if (rs.empty()) {
5713                 return;
5714         }
5715
5716         begin_reversible_command (_("set fade in shape"));
5717
5718         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5719                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5720
5721                 if (!tmp) {
5722                         return;
5723                 }
5724
5725                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5726                 XMLNode &before = alist->get_state();
5727
5728                 tmp->audio_region()->set_fade_in_shape (shape);
5729
5730                 XMLNode &after = alist->get_state();
5731                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5732         }
5733
5734         commit_reversible_command ();
5735
5736 }
5737
5738 void
5739 Editor::set_fade_out_shape (FadeShape shape)
5740 {
5741         RegionSelection rs = get_regions_from_selection_and_entered ();
5742
5743         if (rs.empty()) {
5744                 return;
5745         }
5746
5747         begin_reversible_command (_("set fade out shape"));
5748
5749         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5750                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5751
5752                 if (!tmp) {
5753                         return;
5754                 }
5755
5756                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5757                 XMLNode &before = alist->get_state();
5758
5759                 tmp->audio_region()->set_fade_out_shape (shape);
5760
5761                 XMLNode &after = alist->get_state();
5762                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5763         }
5764
5765         commit_reversible_command ();
5766 }
5767
5768 void
5769 Editor::set_fade_in_active (bool yn)
5770 {
5771         RegionSelection rs = get_regions_from_selection_and_entered ();
5772
5773         if (rs.empty()) {
5774                 return;
5775         }
5776
5777         begin_reversible_command (_("set fade in active"));
5778
5779         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5780                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5781
5782                 if (!tmp) {
5783                         return;
5784                 }
5785
5786
5787                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5788
5789                 ar->clear_changes ();
5790                 ar->set_fade_in_active (yn);
5791                 _session->add_command (new StatefulDiffCommand (ar));
5792         }
5793
5794         commit_reversible_command ();
5795 }
5796
5797 void
5798 Editor::set_fade_out_active (bool yn)
5799 {
5800         RegionSelection rs = get_regions_from_selection_and_entered ();
5801
5802         if (rs.empty()) {
5803                 return;
5804         }
5805
5806         begin_reversible_command (_("set fade out active"));
5807
5808         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5809                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5810
5811                 if (!tmp) {
5812                         return;
5813                 }
5814
5815                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5816
5817                 ar->clear_changes ();
5818                 ar->set_fade_out_active (yn);
5819                 _session->add_command(new StatefulDiffCommand (ar));
5820         }
5821
5822         commit_reversible_command ();
5823 }
5824
5825 void
5826 Editor::toggle_region_fades (int dir)
5827 {
5828         if (_ignore_region_action) {
5829                 return;
5830         }
5831         
5832         boost::shared_ptr<AudioRegion> ar;
5833         bool yn = false;
5834
5835         RegionSelection rs = get_regions_from_selection_and_entered ();
5836
5837         if (rs.empty()) {
5838                 return;
5839         }
5840
5841         RegionSelection::iterator i;
5842         for (i = rs.begin(); i != rs.end(); ++i) {
5843                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5844                         if (dir == -1) {
5845                                 yn = ar->fade_out_active ();
5846                         } else {
5847                                 yn = ar->fade_in_active ();
5848                         }
5849                         break;
5850                 }
5851         }
5852
5853         if (i == rs.end()) {
5854                 return;
5855         }
5856
5857         /* XXX should this undo-able? */
5858
5859         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5860                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5861                         continue;
5862                 }
5863                 if (dir == 1 || dir == 0) {
5864                         ar->set_fade_in_active (!yn);
5865                 }
5866
5867                 if (dir == -1 || dir == 0) {
5868                         ar->set_fade_out_active (!yn);
5869                 }
5870         }
5871 }
5872
5873
5874 /** Update region fade visibility after its configuration has been changed */
5875 void
5876 Editor::update_region_fade_visibility ()
5877 {
5878         bool _fade_visibility = _session->config.get_show_region_fades ();
5879
5880         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5881                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5882                 if (v) {
5883                         if (_fade_visibility) {
5884                                 v->audio_view()->show_all_fades ();
5885                         } else {
5886                                 v->audio_view()->hide_all_fades ();
5887                         }
5888                 }
5889         }
5890 }
5891
5892 void
5893 Editor::set_edit_point ()
5894 {
5895         framepos_t where;
5896         bool ignored;
5897
5898         if (!mouse_frame (where, ignored)) {
5899                 return;
5900         }
5901
5902         snap_to (where);
5903
5904         if (selection->markers.empty()) {
5905
5906                 mouse_add_new_marker (where);
5907
5908         } else {
5909                 bool ignored;
5910
5911                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5912
5913                 if (loc) {
5914                         loc->move_to (where);
5915                 }
5916         }
5917 }
5918
5919 void
5920 Editor::set_playhead_cursor ()
5921 {
5922         if (entered_marker) {
5923                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5924         } else {
5925                 framepos_t where;
5926                 bool ignored;
5927
5928                 if (!mouse_frame (where, ignored)) {
5929                         return;
5930                 }
5931
5932                 snap_to (where);
5933
5934                 if (_session) {
5935                         _session->request_locate (where, _session->transport_rolling());
5936                 }
5937         }
5938
5939         if (ARDOUR_UI::config()->get_follow_edits()) {
5940                 cancel_time_selection();
5941         }
5942 }
5943
5944 void
5945 Editor::split_region ()
5946 {
5947         //if a range is selected, separate it
5948         if ( !selection->time.empty()) {
5949                 separate_regions_between (selection->time);
5950                 return;
5951         }
5952
5953         //if no range was selected, try to find some regions to split
5954         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
5955         
5956                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5957
5958                 framepos_t where = get_preferred_edit_position ();
5959
5960                 if (rs.empty()) {
5961                         return;
5962                 }
5963
5964                 split_regions_at (where, rs);
5965         }
5966 }
5967
5968 struct EditorOrderRouteSorter {
5969     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5970             return a->order_key () < b->order_key ();
5971     }
5972 };
5973
5974 void
5975 Editor::select_next_route()
5976 {
5977         if (selection->tracks.empty()) {
5978                 selection->set (track_views.front());
5979                 return;
5980         }
5981
5982         TimeAxisView* current = selection->tracks.front();
5983
5984         RouteUI *rui;
5985         do {
5986                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5987                         if (*i == current) {
5988                                 ++i;
5989                                 if (i != track_views.end()) {
5990                                         current = (*i);
5991                                 } else {
5992                                         current = (*(track_views.begin()));
5993                                         //selection->set (*(track_views.begin()));
5994                                 }
5995                                 break;
5996                         }
5997                 }
5998                 rui = dynamic_cast<RouteUI *>(current);
5999         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6000
6001         selection->set(current);
6002
6003         ensure_time_axis_view_is_visible (*current, false);
6004 }
6005
6006 void
6007 Editor::select_prev_route()
6008 {
6009         if (selection->tracks.empty()) {
6010                 selection->set (track_views.front());
6011                 return;
6012         }
6013
6014         TimeAxisView* current = selection->tracks.front();
6015
6016         RouteUI *rui;
6017         do {
6018                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6019                         if (*i == current) {
6020                                 ++i;
6021                                 if (i != track_views.rend()) {
6022                                         current = (*i);
6023                                 } else {
6024                                         current = *(track_views.rbegin());
6025                                 }
6026                                 break;
6027                         }
6028                 }
6029                 rui = dynamic_cast<RouteUI *>(current);
6030         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6031
6032         selection->set (current);
6033
6034         ensure_time_axis_view_is_visible (*current, false);
6035 }
6036
6037 void
6038 Editor::set_loop_from_selection (bool play)
6039 {
6040         if (_session == 0) {
6041                 return;
6042         }
6043
6044         framepos_t start, end;
6045         if (!get_selection_extents ( start, end))
6046                 return;
6047
6048         set_loop_range (start, end,  _("set loop range from selection"));
6049
6050         if (play) {
6051                 _session->request_play_loop (true, true);
6052         }
6053 }
6054
6055 void
6056 Editor::set_loop_from_region (bool play)
6057 {
6058         framepos_t start, end;
6059         if (!get_selection_extents ( start, end))
6060                 return;
6061
6062         set_loop_range (start, end, _("set loop range from region"));
6063
6064         if (play) {
6065                 _session->request_locate (start, true);
6066                 _session->request_play_loop (true);
6067         }
6068 }
6069
6070 void
6071 Editor::set_punch_from_selection ()
6072 {
6073         if (_session == 0) {
6074                 return;
6075         }
6076
6077         framepos_t start, end;
6078         if (!get_selection_extents ( start, end))
6079                 return;
6080
6081         set_punch_range (start, end,  _("set punch range from selection"));
6082 }
6083
6084 void
6085 Editor::set_session_extents_from_selection ()
6086 {
6087         if (_session == 0) {
6088                 return;
6089         }
6090         
6091         framepos_t start, end;
6092         if (!get_selection_extents ( start, end))
6093                 return;
6094
6095         Location* loc;
6096         if ((loc = _session->locations()->session_range_location()) == 0) {
6097                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
6098         } else {
6099                 XMLNode &before = loc->get_state();
6100
6101                 _session->set_session_extents ( start, end );
6102
6103                 XMLNode &after = loc->get_state();
6104
6105                 begin_reversible_command (_("set session start/end from selection"));
6106
6107                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6108
6109                 commit_reversible_command ();
6110         }
6111 }
6112
6113 void
6114 Editor::set_punch_from_region ()
6115 {
6116         framepos_t start, end;
6117         if (!get_selection_extents ( start, end))
6118                 return;
6119
6120         set_punch_range (start, end, _("set punch range from region"));
6121 }
6122
6123 void
6124 Editor::pitch_shift_region ()
6125 {
6126         RegionSelection rs = get_regions_from_selection_and_entered ();
6127
6128         RegionSelection audio_rs;
6129         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6130                 if (dynamic_cast<AudioRegionView*> (*i)) {
6131                         audio_rs.push_back (*i);
6132                 }
6133         }
6134
6135         if (audio_rs.empty()) {
6136                 return;
6137         }
6138
6139         pitch_shift (audio_rs, 1.2);
6140 }
6141
6142 void
6143 Editor::transpose_region ()
6144 {
6145         RegionSelection rs = get_regions_from_selection_and_entered ();
6146
6147         list<MidiRegionView*> midi_region_views;
6148         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6149                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6150                 if (mrv) {
6151                         midi_region_views.push_back (mrv);
6152                 }
6153         }
6154
6155         TransposeDialog d;
6156         int const r = d.run ();
6157         if (r != RESPONSE_ACCEPT) {
6158                 return;
6159         }
6160
6161         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6162                 (*i)->midi_region()->transpose (d.semitones ());
6163         }
6164 }
6165
6166 void
6167 Editor::set_tempo_from_region ()
6168 {
6169         RegionSelection rs = get_regions_from_selection_and_entered ();
6170
6171         if (!_session || rs.empty()) {
6172                 return;
6173         }
6174
6175         RegionView* rv = rs.front();
6176
6177         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6178 }
6179
6180 void
6181 Editor::use_range_as_bar ()
6182 {
6183         framepos_t start, end;
6184         if (get_edit_op_range (start, end)) {
6185                 define_one_bar (start, end);
6186         }
6187 }
6188
6189 void
6190 Editor::define_one_bar (framepos_t start, framepos_t end)
6191 {
6192         framepos_t length = end - start;
6193
6194         const Meter& m (_session->tempo_map().meter_at (start));
6195
6196         /* length = 1 bar */
6197
6198         /* now we want frames per beat.
6199            we have frames per bar, and beats per bar, so ...
6200         */
6201
6202         /* XXXX METER MATH */
6203
6204         double frames_per_beat = length / m.divisions_per_bar();
6205
6206         /* beats per minute = */
6207
6208         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6209
6210         /* now decide whether to:
6211
6212             (a) set global tempo
6213             (b) add a new tempo marker
6214
6215         */
6216
6217         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6218
6219         bool do_global = false;
6220
6221         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6222
6223                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6224                    at the start, or create a new marker
6225                 */
6226
6227                 vector<string> options;
6228                 options.push_back (_("Cancel"));
6229                 options.push_back (_("Add new marker"));
6230                 options.push_back (_("Set global tempo"));
6231
6232                 Choice c (
6233                         _("Define one bar"),
6234                         _("Do you want to set the global tempo or add a new tempo marker?"),
6235                         options
6236                         );
6237
6238                 c.set_default_response (2);
6239
6240                 switch (c.run()) {
6241                 case 0:
6242                         return;
6243
6244                 case 2:
6245                         do_global = true;
6246                         break;
6247
6248                 default:
6249                         do_global = false;
6250                 }
6251
6252         } else {
6253
6254                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6255                    if the marker is at the region starter, change it, otherwise add
6256                    a new tempo marker
6257                 */
6258         }
6259
6260         begin_reversible_command (_("set tempo from region"));
6261         XMLNode& before (_session->tempo_map().get_state());
6262
6263         if (do_global) {
6264                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6265         } else if (t.frame() == start) {
6266                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6267         } else {
6268                 Timecode::BBT_Time bbt;
6269                 _session->tempo_map().bbt_time (start, bbt);
6270                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6271         }
6272
6273         XMLNode& after (_session->tempo_map().get_state());
6274
6275         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6276         commit_reversible_command ();
6277 }
6278
6279 void
6280 Editor::split_region_at_transients ()
6281 {
6282         AnalysisFeatureList positions;
6283
6284         RegionSelection rs = get_regions_from_selection_and_entered ();
6285
6286         if (!_session || rs.empty()) {
6287                 return;
6288         }
6289
6290         begin_reversible_command (_("split regions"));
6291         
6292         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6293
6294                 RegionSelection::iterator tmp;
6295
6296                 tmp = i;
6297                 ++tmp;
6298
6299                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6300
6301                 if (ar && (ar->get_transients (positions) == 0)) {
6302                         split_region_at_points ((*i)->region(), positions, true);
6303                         positions.clear ();
6304                 }
6305
6306                 i = tmp;
6307         }
6308         
6309         commit_reversible_command ();
6310
6311 }
6312
6313 void
6314 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6315 {
6316         bool use_rhythmic_rodent = false;
6317
6318         boost::shared_ptr<Playlist> pl = r->playlist();
6319
6320         list<boost::shared_ptr<Region> > new_regions;
6321
6322         if (!pl) {
6323                 return;
6324         }
6325
6326         if (positions.empty()) {
6327                 return;
6328         }
6329
6330
6331         if (positions.size() > 20 && can_ferret) {
6332                 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);
6333                 MessageDialog msg (msgstr,
6334                                    false,
6335                                    Gtk::MESSAGE_INFO,
6336                                    Gtk::BUTTONS_OK_CANCEL);
6337
6338                 if (can_ferret) {
6339                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6340                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6341                 } else {
6342                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6343                 }
6344
6345                 msg.set_title (_("Excessive split?"));
6346                 msg.present ();
6347
6348                 int response = msg.run();
6349                 msg.hide ();
6350
6351                 switch (response) {
6352                 case RESPONSE_OK:
6353                         break;
6354                 case RESPONSE_APPLY:
6355                         use_rhythmic_rodent = true;
6356                         break;
6357                 default:
6358                         return;
6359                 }
6360         }
6361
6362         if (use_rhythmic_rodent) {
6363                 show_rhythm_ferret ();
6364                 return;
6365         }
6366
6367         AnalysisFeatureList::const_iterator x;
6368
6369         pl->clear_changes ();
6370         pl->clear_owned_changes ();
6371
6372         x = positions.begin();
6373
6374         if (x == positions.end()) {
6375                 return;
6376         }
6377
6378         pl->freeze ();
6379         pl->remove_region (r);
6380
6381         framepos_t pos = 0;
6382
6383         while (x != positions.end()) {
6384
6385                 /* deal with positons that are out of scope of present region bounds */
6386                 if (*x <= 0 || *x > r->length()) {
6387                         ++x;
6388                         continue;
6389                 }
6390
6391                 /* file start = original start + how far we from the initial position ?
6392                  */
6393
6394                 framepos_t file_start = r->start() + pos;
6395
6396                 /* length = next position - current position
6397                  */
6398
6399                 framepos_t len = (*x) - pos;
6400
6401                 /* XXX we do we really want to allow even single-sample regions?
6402                    shouldn't we have some kind of lower limit on region size?
6403                 */
6404
6405                 if (len <= 0) {
6406                         break;
6407                 }
6408
6409                 string new_name;
6410
6411                 if (RegionFactory::region_name (new_name, r->name())) {
6412                         break;
6413                 }
6414
6415                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6416
6417                 PropertyList plist;
6418
6419                 plist.add (ARDOUR::Properties::start, file_start);
6420                 plist.add (ARDOUR::Properties::length, len);
6421                 plist.add (ARDOUR::Properties::name, new_name);
6422                 plist.add (ARDOUR::Properties::layer, 0);
6423
6424                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6425                 /* because we set annouce to false, manually add the new region to the
6426                    RegionFactory map
6427                 */
6428                 RegionFactory::map_add (nr);
6429
6430                 pl->add_region (nr, r->position() + pos);
6431
6432                 if (select_new) {
6433                         new_regions.push_front(nr);
6434                 }
6435
6436                 pos += len;
6437                 ++x;
6438         }
6439
6440         string new_name;
6441
6442         RegionFactory::region_name (new_name, r->name());
6443
6444         /* Add the final region */
6445         PropertyList plist;
6446
6447         plist.add (ARDOUR::Properties::start, r->start() + pos);
6448         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6449         plist.add (ARDOUR::Properties::name, new_name);
6450         plist.add (ARDOUR::Properties::layer, 0);
6451
6452         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6453         /* because we set annouce to false, manually add the new region to the
6454            RegionFactory map
6455         */
6456         RegionFactory::map_add (nr);
6457         pl->add_region (nr, r->position() + pos);
6458
6459         if (select_new) {
6460                 new_regions.push_front(nr);
6461         }
6462
6463         pl->thaw ();
6464
6465         /* We might have removed regions, which alters other regions' layering_index,
6466            so we need to do a recursive diff here.
6467         */
6468         vector<Command*> cmds;
6469         pl->rdiff (cmds);
6470         _session->add_commands (cmds);
6471         
6472         _session->add_command (new StatefulDiffCommand (pl));
6473
6474         if (select_new) {
6475
6476                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6477                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6478                 }
6479         }
6480 }
6481
6482 void
6483 Editor::place_transient()
6484 {
6485         if (!_session) {
6486                 return;
6487         }
6488
6489         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6490
6491         if (rs.empty()) {
6492                 return;
6493         }
6494
6495         framepos_t where = get_preferred_edit_position();
6496
6497         begin_reversible_command (_("place transient"));
6498         
6499         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6500                 framepos_t position = (*r)->region()->position();
6501                 (*r)->region()->add_transient(where - position);
6502         }
6503         
6504         commit_reversible_command ();
6505 }
6506
6507 void
6508 Editor::remove_transient(ArdourCanvas::Item* item)
6509 {
6510         if (!_session) {
6511                 return;
6512         }
6513
6514         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6515         assert (_line);
6516
6517         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6518         _arv->remove_transient (*(float*) _line->get_data ("position"));
6519 }
6520
6521 void
6522 Editor::snap_regions_to_grid ()
6523 {
6524         list <boost::shared_ptr<Playlist > > used_playlists;
6525
6526         RegionSelection rs = get_regions_from_selection_and_entered ();
6527
6528         if (!_session || rs.empty()) {
6529                 return;
6530         }
6531
6532         begin_reversible_command (_("snap regions to grid"));
6533         
6534         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6535
6536                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6537
6538                 if (!pl->frozen()) {
6539                         /* we haven't seen this playlist before */
6540
6541                         /* remember used playlists so we can thaw them later */
6542                         used_playlists.push_back(pl);
6543                         pl->freeze();
6544                 }
6545
6546                 framepos_t start_frame = (*r)->region()->first_frame ();
6547                 snap_to (start_frame);
6548                 (*r)->region()->set_position (start_frame);
6549         }
6550
6551         while (used_playlists.size() > 0) {
6552                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6553                 (*i)->thaw();
6554                 used_playlists.pop_front();
6555         }
6556         
6557         commit_reversible_command ();
6558 }
6559
6560 void
6561 Editor::close_region_gaps ()
6562 {
6563         list <boost::shared_ptr<Playlist > > used_playlists;
6564
6565         RegionSelection rs = get_regions_from_selection_and_entered ();
6566
6567         if (!_session || rs.empty()) {
6568                 return;
6569         }
6570
6571         Dialog dialog (_("Close Region Gaps"));
6572
6573         Table table (2, 3);
6574         table.set_spacings (12);
6575         table.set_border_width (12);
6576         Label* l = manage (left_aligned_label (_("Crossfade length")));
6577         table.attach (*l, 0, 1, 0, 1);
6578
6579         SpinButton spin_crossfade (1, 0);
6580         spin_crossfade.set_range (0, 15);
6581         spin_crossfade.set_increments (1, 1);
6582         spin_crossfade.set_value (5);
6583         table.attach (spin_crossfade, 1, 2, 0, 1);
6584
6585         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6586
6587         l = manage (left_aligned_label (_("Pull-back length")));
6588         table.attach (*l, 0, 1, 1, 2);
6589
6590         SpinButton spin_pullback (1, 0);
6591         spin_pullback.set_range (0, 100);
6592         spin_pullback.set_increments (1, 1);
6593         spin_pullback.set_value(30);
6594         table.attach (spin_pullback, 1, 2, 1, 2);
6595
6596         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6597
6598         dialog.get_vbox()->pack_start (table);
6599         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6600         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6601         dialog.show_all ();
6602
6603         if (dialog.run () == RESPONSE_CANCEL) {
6604                 return;
6605         }
6606
6607         framepos_t crossfade_len = spin_crossfade.get_value();
6608         framepos_t pull_back_frames = spin_pullback.get_value();
6609
6610         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6611         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6612
6613         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6614
6615         begin_reversible_command (_("close region gaps"));
6616         
6617         int idx = 0;
6618         boost::shared_ptr<Region> last_region;
6619
6620         rs.sort_by_position_and_track();
6621
6622         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6623
6624                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6625
6626                 if (!pl->frozen()) {
6627                         /* we haven't seen this playlist before */
6628
6629                         /* remember used playlists so we can thaw them later */
6630                         used_playlists.push_back(pl);
6631                         pl->freeze();
6632                 }
6633
6634                 framepos_t position = (*r)->region()->position();
6635
6636                 if (idx == 0 || position < last_region->position()){
6637                         last_region = (*r)->region();
6638                         idx++;
6639                         continue;
6640                 }
6641
6642                 (*r)->region()->trim_front( (position - pull_back_frames));
6643                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6644
6645                 last_region = (*r)->region();
6646
6647                 idx++;
6648         }
6649
6650         while (used_playlists.size() > 0) {
6651                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6652                 (*i)->thaw();
6653                 used_playlists.pop_front();
6654         }
6655         
6656         commit_reversible_command ();
6657 }
6658
6659 void
6660 Editor::tab_to_transient (bool forward)
6661 {
6662         AnalysisFeatureList positions;
6663
6664         RegionSelection rs = get_regions_from_selection_and_entered ();
6665
6666         if (!_session) {
6667                 return;
6668         }
6669
6670         framepos_t pos = _session->audible_frame ();
6671
6672         if (!selection->tracks.empty()) {
6673
6674                 /* don't waste time searching for transients in duplicate playlists.
6675                  */
6676
6677                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6678
6679                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6680
6681                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6682
6683                         if (rtv) {
6684                                 boost::shared_ptr<Track> tr = rtv->track();
6685                                 if (tr) {
6686                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6687                                         if (pl) {
6688                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6689
6690                                                 if (result >= 0) {
6691                                                         positions.push_back (result);
6692                                                 }
6693                                         }
6694                                 }
6695                         }
6696                 }
6697
6698         } else {
6699
6700                 if (rs.empty()) {
6701                         return;
6702                 }
6703
6704                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6705                         (*r)->region()->get_transients (positions);
6706                 }
6707         }
6708
6709         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6710
6711         if (forward) {
6712                 AnalysisFeatureList::iterator x;
6713
6714                 for (x = positions.begin(); x != positions.end(); ++x) {
6715                         if ((*x) > pos) {
6716                                 break;
6717                         }
6718                 }
6719
6720                 if (x != positions.end ()) {
6721                         _session->request_locate (*x);
6722                 }
6723
6724         } else {
6725                 AnalysisFeatureList::reverse_iterator x;
6726
6727                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6728                         if ((*x) < pos) {
6729                                 break;
6730                         }
6731                 }
6732
6733                 if (x != positions.rend ()) {
6734                         _session->request_locate (*x);
6735                 }
6736         }
6737 }
6738
6739 void
6740 Editor::playhead_forward_to_grid ()
6741 {
6742         if (!_session) {
6743                 return;
6744         }
6745         
6746         framepos_t pos = playhead_cursor->current_frame ();
6747         if (pos < max_framepos - 1) {
6748                 pos += 2;
6749                 snap_to_internal (pos, RoundUpAlways, false);
6750                 _session->request_locate (pos);
6751         }
6752 }
6753
6754
6755 void
6756 Editor::playhead_backward_to_grid ()
6757 {
6758         if (!_session) {
6759                 return;
6760         }
6761         
6762         framepos_t pos = playhead_cursor->current_frame ();
6763         if (pos > 2) {
6764                 pos -= 2;
6765                 snap_to_internal (pos, RoundDownAlways, false);
6766                 _session->request_locate (pos);
6767         }
6768 }
6769
6770 void
6771 Editor::set_track_height (Height h)
6772 {
6773         TrackSelection& ts (selection->tracks);
6774
6775         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6776                 (*x)->set_height_enum (h);
6777         }
6778 }
6779
6780 void
6781 Editor::toggle_tracks_active ()
6782 {
6783         TrackSelection& ts (selection->tracks);
6784         bool first = true;
6785         bool target = false;
6786
6787         if (ts.empty()) {
6788                 return;
6789         }
6790
6791         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6792                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6793
6794                 if (rtv) {
6795                         if (first) {
6796                                 target = !rtv->_route->active();
6797                                 first = false;
6798                         }
6799                         rtv->_route->set_active (target, this);
6800                 }
6801         }
6802 }
6803
6804 void
6805 Editor::remove_tracks ()
6806 {
6807         /* this will delete GUI objects that may be the subject of an event
6808            handler in which this method is called. Defer actual deletion to the
6809            next idle callback, when all event handling is finished.
6810         */
6811         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6812 }
6813
6814 bool
6815 Editor::idle_remove_tracks ()
6816 {
6817         _remove_tracks ();
6818         return false; /* do not call again */
6819 }
6820
6821 void
6822 Editor::_remove_tracks ()
6823 {
6824         TrackSelection& ts (selection->tracks);
6825
6826         if (ts.empty()) {
6827                 return;
6828         }
6829
6830         vector<string> choices;
6831         string prompt;
6832         int ntracks = 0;
6833         int nbusses = 0;
6834         const char* trackstr;
6835         const char* busstr;
6836         vector<boost::shared_ptr<Route> > routes;
6837         bool special_bus = false;
6838
6839         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6840                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6841                 if (!rtv) {
6842                         continue;
6843                 }
6844                 if (rtv->is_track()) {
6845                         ntracks++;
6846                 } else {
6847                         nbusses++;
6848                 }
6849                 routes.push_back (rtv->_route);
6850
6851                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6852                         special_bus = true;
6853                 }
6854         }
6855
6856         if (special_bus && !Config->get_allow_special_bus_removal()) {
6857                 MessageDialog msg (_("That would be bad news ...."),
6858                                    false,
6859                                    Gtk::MESSAGE_INFO,
6860                                    Gtk::BUTTONS_OK);
6861                 msg.set_secondary_text (string_compose (_(
6862                                                                 "Removing the master or monitor bus is such a bad idea\n\
6863 that %1 is not going to allow it.\n\
6864 \n\
6865 If you really want to do this sort of thing\n\
6866 edit your ardour.rc file to set the\n\
6867 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6868
6869                 msg.present ();
6870                 msg.run ();
6871                 return;
6872         }
6873
6874         if (ntracks + nbusses == 0) {
6875                 return;
6876         }
6877
6878         trackstr = P_("track", "tracks", ntracks);
6879         busstr = P_("bus", "busses", nbusses);
6880         
6881         if (ntracks) {
6882                 if (nbusses) {
6883                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6884                                                     "(You may also lose the playlists associated with the %2)\n\n"
6885                                                     "This action cannot be undone, and the session file will be overwritten!"),
6886                                                   ntracks, trackstr, nbusses, busstr);
6887                 } else {
6888                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6889                                                     "(You may also lose the playlists associated with the %2)\n\n"
6890                                                     "This action cannot be undone, and the session file will be overwritten!"),
6891                                                   ntracks, trackstr);
6892                 }
6893         } else if (nbusses) {
6894                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6895                                             "This action cannot be undone, and the session file will be overwritten"),
6896                                           nbusses, busstr);
6897         }
6898
6899         choices.push_back (_("No, do nothing."));
6900         if (ntracks + nbusses > 1) {
6901                 choices.push_back (_("Yes, remove them."));
6902         } else {
6903                 choices.push_back (_("Yes, remove it."));
6904         }
6905
6906         string title;
6907         if (ntracks) {
6908                 title = string_compose (_("Remove %1"), trackstr);
6909         } else {
6910                 title = string_compose (_("Remove %1"), busstr);
6911         }
6912
6913         Choice prompter (title, prompt, choices);
6914
6915         if (prompter.run () != 1) {
6916                 return;
6917         }
6918
6919         {
6920                 Session::StateProtector sp (_session);
6921                 DisplaySuspender ds;
6922                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6923                         _session->remove_route (*x);
6924                 }
6925         }
6926 }
6927
6928 void
6929 Editor::do_insert_time ()
6930 {
6931         if (selection->tracks.empty()) {
6932                 return;
6933         }
6934
6935         InsertRemoveTimeDialog d (*this);
6936         int response = d.run ();
6937
6938         if (response != RESPONSE_OK) {
6939                 return;
6940         }
6941
6942         if (d.distance() == 0) {
6943                 return;
6944         }
6945
6946         InsertTimeOption opt = d.intersected_region_action ();
6947
6948         insert_time (
6949                 get_preferred_edit_position(),
6950                 d.distance(),
6951                 opt,
6952                 d.all_playlists(),
6953                 d.move_glued(),
6954                 d.move_markers(),
6955                 d.move_glued_markers(),
6956                 d.move_locked_markers(),
6957                 d.move_tempos()
6958                 );
6959 }
6960
6961 void
6962 Editor::insert_time (
6963         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6964         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6965         )
6966 {
6967         bool commit = false;
6968
6969         if (Config->get_edit_mode() == Lock) {
6970                 return;
6971         }
6972
6973         begin_reversible_command (_("insert time"));
6974
6975         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6976
6977         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6978
6979                 /* regions */
6980
6981                 /* don't operate on any playlist more than once, which could
6982                  * happen if "all playlists" is enabled, but there is more
6983                  * than 1 track using playlists "from" a given track.
6984                  */
6985
6986                 set<boost::shared_ptr<Playlist> > pl;
6987
6988                 if (all_playlists) {
6989                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6990                         if (rtav) {
6991                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6992                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6993                                         pl.insert (*p);
6994                                 }
6995                         }
6996                 } else {
6997                         if ((*x)->playlist ()) {
6998                                 pl.insert ((*x)->playlist ());
6999                         }
7000                 }
7001                 
7002                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7003
7004                         (*i)->clear_changes ();
7005                         (*i)->clear_owned_changes ();
7006
7007                         if (opt == SplitIntersected) {
7008                                 (*i)->split (pos);
7009                         }
7010
7011                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7012
7013                         vector<Command*> cmds;
7014                         (*i)->rdiff (cmds);
7015                         _session->add_commands (cmds);
7016
7017                         _session->add_command (new StatefulDiffCommand (*i));
7018                         commit = true;
7019                 }
7020
7021                 /* automation */
7022                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7023                 if (rtav) {
7024                         rtav->route ()->shift (pos, frames);
7025                         commit = true;
7026                 }
7027         }
7028
7029         /* markers */
7030         if (markers_too) {
7031                 bool moved = false;
7032                 XMLNode& before (_session->locations()->get_state());
7033                 Locations::LocationList copy (_session->locations()->list());
7034
7035                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7036
7037                         Locations::LocationList::const_iterator tmp;
7038
7039                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7040                                 bool const was_locked = (*i)->locked ();
7041                                 if (locked_markers_too) {
7042                                         (*i)->unlock ();
7043                                 }
7044
7045                                 if ((*i)->start() >= pos) {
7046                                         // move end first, in case we're moving by more than the length of the range
7047                                         if (!(*i)->is_mark()) {
7048                                                 (*i)->set_end ((*i)->end() + frames);
7049                                         }
7050                                         (*i)->set_start ((*i)->start() + frames);
7051                                         moved = true;
7052                                 }
7053
7054                                 if (was_locked) {
7055                                         (*i)->lock ();
7056                                 }
7057                         }
7058                 }
7059
7060                 if (moved) {
7061                         XMLNode& after (_session->locations()->get_state());
7062                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7063                 }
7064         }
7065
7066         if (tempo_too) {
7067                 _session->tempo_map().insert_time (pos, frames);
7068         }
7069
7070         if (commit) {
7071                 commit_reversible_command ();
7072         }
7073 }
7074
7075 void
7076 Editor::do_remove_time ()
7077 {
7078         if (selection->tracks.empty()) {
7079                 return;
7080         }
7081
7082         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7083         InsertRemoveTimeDialog d (*this, true);
7084
7085         int response = d.run ();
7086
7087         if (response != RESPONSE_OK) {
7088                 return;
7089         }
7090         
7091         framecnt_t distance = d.distance();
7092
7093         if (distance == 0) {
7094                 return;
7095         }
7096
7097         remove_time (
7098                 pos,
7099                 distance,
7100                 SplitIntersected,
7101                 d.move_glued(),
7102                 d.move_markers(),
7103                 d.move_glued_markers(),
7104                 d.move_locked_markers(),
7105                 d.move_tempos()
7106         );
7107 }
7108
7109 void
7110 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, 
7111                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7112 {
7113         bool commit = false;
7114         
7115         if (Config->get_edit_mode() == Lock) {
7116                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7117                 return;
7118         }
7119
7120         begin_reversible_command (_("cut time"));
7121
7122         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7123                 /* regions */
7124                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7125                 
7126                 if (pl) {
7127
7128                         XMLNode &before = pl->get_state();
7129                         
7130                         std::list<AudioRange> rl;
7131                         AudioRange ar(pos, pos+frames, 0);
7132                         rl.push_back(ar);
7133                         pl->cut (rl);
7134                         pl->shift (pos, -frames, true, ignore_music_glue);
7135                         
7136                         XMLNode &after = pl->get_state();
7137                         
7138                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7139                         commit = true;
7140                 }
7141                         
7142                 /* automation */
7143                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7144                 if (rtav) {
7145                         rtav->route ()->shift (pos, -frames);
7146                         commit = true;
7147                 }
7148         }
7149
7150         std::list<Location*> loc_kill_list;
7151         
7152         /* markers */
7153         if (markers_too) {
7154                 bool moved = false;
7155                 XMLNode& before (_session->locations()->get_state());
7156                 Locations::LocationList copy (_session->locations()->list());
7157
7158                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7159                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7160
7161                                 bool const was_locked = (*i)->locked ();
7162                                 if (locked_markers_too) {
7163                                         (*i)->unlock ();
7164                                 }
7165
7166                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7167                                         if ((*i)->end() >= pos
7168                                         && (*i)->end() < pos+frames
7169                                         && (*i)->start() >= pos
7170                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7171                                                 moved = true;
7172                                                 loc_kill_list.push_back(*i);
7173                                         } else {  // only start or end is included, try to do the right thing
7174                                                 // move start before moving end, to avoid trying to move the end to before the start
7175                                                 // if we're removing more time than the length of the range
7176                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7177                                                         // start is within cut
7178                                                         (*i)->set_start (pos);  // bring the start marker to the beginning of the cut
7179                                                         moved = true;
7180                                                 } else if ((*i)->start() >= pos+frames) {
7181                                                         // start (and thus entire range) lies beyond end of cut
7182                                                         (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7183                                                         moved = true;
7184                                                 }
7185                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7186                                                         // end is inside cut
7187                                                         (*i)->set_end (pos);  // bring the end to the cut
7188                                                         moved = true;
7189                                                 } else if ((*i)->end() >= pos+frames) {
7190                                                         // end is beyond end of cut
7191                                                         (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7192                                                         moved = true;
7193                                                 }
7194
7195                                         }
7196                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7197                                         loc_kill_list.push_back(*i);
7198                                         moved = true;
7199                                 } else if ((*i)->start() >= pos) {
7200                                         (*i)->set_start ((*i)->start() -frames);
7201                                         moved = true;
7202                                 }
7203
7204                                 if (was_locked) {
7205                                         (*i)->lock ();
7206                                 }
7207                         }
7208                 }
7209
7210                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7211                         _session->locations()->remove( *i );
7212                 }
7213         
7214                 if (moved) {
7215                         XMLNode& after (_session->locations()->get_state());
7216                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7217                         commit = true;
7218                 }
7219         }
7220         
7221         if (tempo_too) {
7222                 XMLNode& before (_session->tempo_map().get_state());
7223
7224                 if (_session->tempo_map().remove_time (pos, frames) ) {
7225                         XMLNode& after (_session->tempo_map().get_state());
7226                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7227                         commit = true;
7228                 }
7229         }
7230         
7231         if (commit) {
7232                 commit_reversible_command ();
7233         }
7234 }
7235
7236 void
7237 Editor::fit_selection ()
7238 {
7239         if (!selection->tracks.empty()) {
7240                 fit_tracks (selection->tracks);
7241         } else {
7242                 TrackViewList tvl;
7243
7244                 /* no selected tracks - use tracks with selected regions */
7245
7246                 if (!selection->regions.empty()) {
7247                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7248                                 tvl.push_back (&(*r)->get_time_axis_view ());
7249                         }
7250
7251                         if (!tvl.empty()) {
7252                                 fit_tracks (tvl);
7253                         }
7254                 } else if (internal_editing()) {
7255                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7256                            the entered track
7257                         */
7258                         if (entered_track) {
7259                                 tvl.push_back (entered_track);
7260                                 fit_tracks (tvl);
7261                         }
7262                 }
7263         }
7264
7265 }
7266
7267 void
7268 Editor::fit_tracks (TrackViewList & tracks)
7269 {
7270         if (tracks.empty()) {
7271                 return;
7272         }
7273
7274         uint32_t child_heights = 0;
7275         int visible_tracks = 0;
7276
7277         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7278
7279                 if (!(*t)->marked_for_display()) {
7280                         continue;
7281                 }
7282
7283                 child_heights += (*t)->effective_height() - (*t)->current_height();
7284                 ++visible_tracks;
7285         }
7286
7287         /* compute the per-track height from:
7288
7289            total canvas visible height - 
7290                  height that will be taken by visible children of selected
7291                  tracks - height of the ruler/hscroll area 
7292         */
7293         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7294         double first_y_pos = DBL_MAX;
7295
7296         if (h < TimeAxisView::preset_height (HeightSmall)) {
7297                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7298                 /* too small to be displayed */
7299                 return;
7300         }
7301
7302         undo_visual_stack.push_back (current_visual_state (true));
7303         PBD::Unwinder<bool> nsv (no_save_visual, true);
7304
7305         /* build a list of all tracks, including children */
7306
7307         TrackViewList all;
7308         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7309                 all.push_back (*i);
7310                 TimeAxisView::Children c = (*i)->get_child_list ();
7311                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7312                         all.push_back (j->get());
7313                 }
7314         }
7315
7316
7317         // find selection range.
7318         // if someone knows how to user TrackViewList::iterator for this
7319         // I'm all ears.
7320         int selected_top = -1;
7321         int selected_bottom = -1;
7322         int i = 0;
7323         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7324                 if ((*t)->marked_for_display ()) {
7325                         if (tracks.contains(*t)) {
7326                                 if (selected_top == -1) {
7327                                         selected_top = i;
7328                                 }
7329                                 selected_bottom = i;
7330                         }
7331                 }
7332         }
7333
7334         i = 0;
7335         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7336                 if ((*t)->marked_for_display ()) {
7337                         if (tracks.contains(*t)) {
7338                                 (*t)->set_height (h);
7339                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7340                         } else {
7341                                 if (i > selected_top && i < selected_bottom) {
7342                                         hide_track_in_display (*t);
7343                                 }
7344                         }
7345                 }
7346         }
7347
7348         /*
7349            set the controls_layout height now, because waiting for its size
7350            request signal handler will cause the vertical adjustment setting to fail
7351         */
7352
7353         controls_layout.property_height () = _full_canvas_height;
7354         vertical_adjustment.set_value (first_y_pos);
7355
7356         redo_visual_stack.push_back (current_visual_state (true));
7357
7358         visible_tracks_selector.set_text (_("Sel"));
7359 }
7360
7361 void
7362 Editor::save_visual_state (uint32_t n)
7363 {
7364         while (visual_states.size() <= n) {
7365                 visual_states.push_back (0);
7366         }
7367
7368         if (visual_states[n] != 0) {
7369                 delete visual_states[n];
7370         }
7371
7372         visual_states[n] = current_visual_state (true);
7373         gdk_beep ();
7374 }
7375
7376 void
7377 Editor::goto_visual_state (uint32_t n)
7378 {
7379         if (visual_states.size() <= n) {
7380                 return;
7381         }
7382
7383         if (visual_states[n] == 0) {
7384                 return;
7385         }
7386
7387         use_visual_state (*visual_states[n]);
7388 }
7389
7390 void
7391 Editor::start_visual_state_op (uint32_t n)
7392 {
7393         save_visual_state (n);
7394         
7395         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7396         char buf[32];
7397         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7398         pup->set_text (buf);
7399         pup->touch();
7400 }
7401
7402 void
7403 Editor::cancel_visual_state_op (uint32_t n)
7404 {
7405         goto_visual_state (n);
7406 }
7407
7408 void
7409 Editor::toggle_region_mute ()
7410 {
7411         if (_ignore_region_action) {
7412                 return;
7413         }
7414
7415         RegionSelection rs = get_regions_from_selection_and_entered ();
7416
7417         if (rs.empty ()) {
7418                 return;
7419         }
7420
7421         if (rs.size() > 1) {
7422                 begin_reversible_command (_("mute regions"));
7423         } else {
7424                 begin_reversible_command (_("mute region"));
7425         }
7426
7427         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7428
7429                 (*i)->region()->playlist()->clear_changes ();
7430                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7431                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7432
7433         }
7434
7435         commit_reversible_command ();
7436 }
7437
7438 void
7439 Editor::combine_regions ()
7440 {
7441         /* foreach track with selected regions, take all selected regions
7442            and join them into a new region containing the subregions (as a
7443            playlist)
7444         */
7445
7446         typedef set<RouteTimeAxisView*> RTVS;
7447         RTVS tracks;
7448
7449         if (selection->regions.empty()) {
7450                 return;
7451         }
7452
7453         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7454                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7455
7456                 if (rtv) {
7457                         tracks.insert (rtv);
7458                 }
7459         }
7460
7461         begin_reversible_command (_("combine regions"));
7462
7463         vector<RegionView*> new_selection;
7464
7465         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7466                 RegionView* rv;
7467
7468                 if ((rv = (*i)->combine_regions ()) != 0) {
7469                         new_selection.push_back (rv);
7470                 }
7471         }
7472
7473         selection->clear_regions ();
7474         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7475                 selection->add (*i);
7476         }
7477
7478         commit_reversible_command ();
7479 }
7480
7481 void
7482 Editor::uncombine_regions ()
7483 {
7484         typedef set<RouteTimeAxisView*> RTVS;
7485         RTVS tracks;
7486
7487         if (selection->regions.empty()) {
7488                 return;
7489         }
7490
7491         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7492                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7493
7494                 if (rtv) {
7495                         tracks.insert (rtv);
7496                 }
7497         }
7498
7499         begin_reversible_command (_("uncombine regions"));
7500
7501         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7502                 (*i)->uncombine_regions ();
7503         }
7504
7505         commit_reversible_command ();
7506 }
7507
7508 void
7509 Editor::toggle_midi_input_active (bool flip_others)
7510 {
7511         bool onoff = false;
7512         boost::shared_ptr<RouteList> rl (new RouteList);
7513
7514         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7515                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7516
7517                 if (!rtav) {
7518                         continue;
7519                 }
7520
7521                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7522
7523                 if (mt) {
7524                         rl->push_back (rtav->route());
7525                         onoff = !mt->input_active();
7526                 }
7527         }
7528         
7529         _session->set_exclusive_input_active (rl, onoff, flip_others);
7530 }
7531
7532 void
7533 Editor::lock ()
7534 {
7535         if (!lock_dialog) {
7536                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7537
7538                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7539                 lock_dialog->get_vbox()->pack_start (*padlock);
7540
7541                 ArdourButton* b = manage (new ArdourButton);
7542                 b->set_name ("lock button");
7543                 b->set_text (_("Click to unlock"));
7544                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7545                 lock_dialog->get_vbox()->pack_start (*b);
7546                 
7547                 lock_dialog->get_vbox()->show_all ();
7548                 lock_dialog->set_size_request (200, 200);
7549         }
7550
7551         delete _main_menu_disabler;
7552         _main_menu_disabler = new MainMenuDisabler;
7553         
7554         lock_dialog->present ();
7555 }
7556
7557 void
7558 Editor::unlock ()
7559 {
7560         lock_dialog->hide ();
7561         
7562         delete _main_menu_disabler;
7563
7564         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7565                 start_lock_event_timing ();
7566         }
7567 }
7568
7569 void
7570 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7571 {
7572         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7573 }
7574
7575 void
7576 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7577 {
7578         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7579         Gtkmm2ext::UI::instance()->flush_pending ();
7580 }
7581
7582 void
7583 Editor::bring_all_sources_into_session ()
7584 {
7585         if (!_session) {
7586                 return;
7587         }
7588
7589         Gtk::Label msg;
7590         ArdourDialog w (_("Moving embedded files into session folder"));
7591         w.get_vbox()->pack_start (msg);
7592         w.present ();
7593         
7594         /* flush all pending GUI events because we're about to start copying
7595          * files
7596          */
7597         
7598         Gtkmm2ext::UI::instance()->flush_pending ();
7599
7600         cerr << " Do it\n";
7601
7602         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7603 }