Insert time: don't unlock markers we're not going to move anyway
[ardour.git] / gtk2_ardour / editor_ops.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <limits>
28 #include <map>
29 #include <set>
30
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
38
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
42
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/legatize.h"
54 #include "ardour/region_factory.h"
55 #include "ardour/reverse.h"
56 #include "ardour/session.h"
57 #include "ardour/session_playlists.h"
58 #include "ardour/strip_silence.h"
59 #include "ardour/transient_detector.h"
60
61 #include "canvas/canvas.h"
62
63 #include "actions.h"
64 #include "ardour_ui.h"
65 #include "audio_region_view.h"
66 #include "audio_streamview.h"
67 #include "audio_time_axis.h"
68 #include "automation_region_view.h"
69 #include "automation_time_axis.h"
70 #include "control_point.h"
71 #include "debug.h"
72 #include "editing.h"
73 #include "editor.h"
74 #include "editor_cursors.h"
75 #include "editor_drag.h"
76 #include "editor_regions.h"
77 #include "editor_routes.h"
78 #include "gui_thread.h"
79 #include "insert_time_dialog.h"
80 #include "interthread_progress_window.h"
81 #include "item_counts.h"
82 #include "keyboard.h"
83 #include "midi_region_view.h"
84 #include "mixer_strip.h"
85 #include "mouse_cursors.h"
86 #include "normalize_dialog.h"
87 #include "note.h"
88 #include "paste_context.h"
89 #include "patch_change_dialog.h"
90 #include "quantize_dialog.h"
91 #include "region_gain_line.h"
92 #include "rgb_macros.h"
93 #include "route_time_axis.h"
94 #include "selection.h"
95 #include "selection_templates.h"
96 #include "streamview.h"
97 #include "strip_silence_dialog.h"
98 #include "time_axis_view.h"
99 #include "transpose_dialog.h"
100 #include "transform_dialog.h"
101
102 #include "i18n.h"
103
104 using namespace std;
105 using namespace ARDOUR;
106 using namespace PBD;
107 using namespace Gtk;
108 using namespace Gtkmm2ext;
109 using namespace Editing;
110 using Gtkmm2ext::Keyboard;
111
112 /***********************************************************************
113   Editor operations
114  ***********************************************************************/
115
116 void
117 Editor::undo (uint32_t n)
118 {
119         if (_drags->active ()) {
120                 _drags->abort ();
121         }
122         
123         if (_session) {
124                 _session->undo (n);
125                 if (_session->undo_depth() == 0) {
126                         undo_action->set_sensitive(false);
127                 }
128                 redo_action->set_sensitive(true);
129                 begin_selection_op_history ();
130         }
131 }
132
133 void
134 Editor::redo (uint32_t n)
135 {
136         if (_drags->active ()) {
137                 _drags->abort ();
138         }
139         
140         if (_session) {
141                 _session->redo (n);
142                 if (_session->redo_depth() == 0) {
143                         redo_action->set_sensitive(false);
144                 }
145                 undo_action->set_sensitive(true);
146                 begin_selection_op_history ();
147         }
148 }
149
150 void
151 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
152 {
153         bool frozen = false;
154
155         RegionSelection pre_selected_regions = selection->regions;
156         bool working_on_selection = !pre_selected_regions.empty();
157
158         list<boost::shared_ptr<Playlist> > used_playlists;
159         list<RouteTimeAxisView*> used_trackviews;
160
161         if (regions.empty()) {
162                 return;
163         }
164
165         begin_reversible_command (_("split"));
166
167         // if splitting a single region, and snap-to is using
168         // region boundaries, don't pay attention to them
169
170         if (regions.size() == 1) {
171                 switch (_snap_type) {
172                 case SnapToRegionStart:
173                 case SnapToRegionSync:
174                 case SnapToRegionEnd:
175                         break;
176                 default:
177                         snap_to (where);
178                 }
179         } else {
180                 snap_to (where);
181
182                 frozen = true;
183                 EditorFreeze(); /* Emit Signal */
184         }
185
186         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
187
188                 RegionSelection::iterator tmp;
189
190                 /* XXX this test needs to be more complicated, to make sure we really
191                    have something to split.
192                 */
193
194                 if (!(*a)->region()->covers (where)) {
195                         ++a;
196                         continue;
197                 }
198
199                 tmp = a;
200                 ++tmp;
201
202                 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
203
204                 if (!pl) {
205                         a = tmp;
206                         continue;
207                 }
208
209                 if (!pl->frozen()) {
210                         /* we haven't seen this playlist before */
211
212                         /* remember used playlists so we can thaw them later */
213                         used_playlists.push_back(pl);
214
215                         TimeAxisView& tv = (*a)->get_time_axis_view();
216                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
217                         if (rtv) {
218                                 used_trackviews.push_back (rtv);
219                         }
220                         pl->freeze();
221                 }
222
223
224                 if (pl) {
225                         pl->clear_changes ();
226                         pl->split_region ((*a)->region(), where);
227                         _session->add_command (new StatefulDiffCommand (pl));
228                 }
229
230                 a = tmp;
231         }
232
233         latest_regionviews.clear ();
234
235         vector<sigc::connection> region_added_connections;
236
237         for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
238                 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
239         }
240         
241         while (used_playlists.size() > 0) {
242                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
243                 (*i)->thaw();
244                 used_playlists.pop_front();
245         }
246
247         for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
248                 (*c).disconnect ();
249         }
250
251         if (frozen){
252                 EditorThaw(); /* Emit Signal */
253         }
254
255         if (working_on_selection) {
256                 // IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
257
258                 _ignore_follow_edits = true;  // a split will change the region selection in mysterious ways;  it's not practical or wanted to follow this edit
259                 RegionSelectionAfterSplit rsas = Config->get_region_selection_after_split();
260                 /* There are three classes of regions that we might want selected after
261                    splitting selected regions:
262                     - regions selected before the split operation, and unaffected by it
263                     - newly-created regions before the split
264                     - newly-created regions after the split
265                  */
266
267                 if (rsas & Existing) {
268                         // region selections that existed before the split.
269                         selection->add ( pre_selected_regions );
270                 }
271
272                 for (RegionSelection::iterator ri = latest_regionviews.begin(); ri != latest_regionviews.end(); ri++) {
273                         if ((*ri)->region()->position() < where) {
274                                 // new regions created before the split
275                                 if (rsas & NewlyCreatedLeft) {
276                                         selection->add (*ri);
277                                 }
278                         } else {
279                                 // new regions created after the split
280                                 if (rsas & NewlyCreatedRight) {
281                                         selection->add (*ri);
282                                 }
283                         }
284                 }
285                 _ignore_follow_edits = false;
286         } else {
287                 _ignore_follow_edits = true;
288                 if( working_on_selection ) {
289                         selection->add (latest_regionviews);  //these are the new regions created after the split
290                 }
291                 _ignore_follow_edits = false;
292         }
293
294         commit_reversible_command ();
295 }
296
297 /** Move one extreme of the current range selection.  If more than one range is selected,
298  *  the start of the earliest range or the end of the latest range is moved.
299  *
300  *  @param move_end true to move the end of the current range selection, false to move
301  *  the start.
302  *  @param next true to move the extreme to the next region boundary, false to move to
303  *  the previous.
304  */
305 void
306 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
307 {
308         if (selection->time.start() == selection->time.end_frame()) {
309                 return;
310         }
311
312         framepos_t start = selection->time.start ();
313         framepos_t end = selection->time.end_frame ();
314
315         /* the position of the thing we may move */
316         framepos_t pos = move_end ? end : start;
317         int dir = next ? 1 : -1;
318
319         /* so we don't find the current region again */
320         if (dir > 0 || pos > 0) {
321                 pos += dir;
322         }
323
324         framepos_t const target = get_region_boundary (pos, dir, true, false);
325         if (target < 0) {
326                 return;
327         }
328
329         if (move_end) {
330                 end = target;
331         } else {
332                 start = target;
333         }
334
335         if (end < start) {
336                 return;
337         }
338
339         begin_reversible_command (_("alter selection"));
340         selection->set_preserving_all_ranges (start, end);
341         commit_reversible_command ();
342 }
343
344 bool
345 Editor::nudge_forward_release (GdkEventButton* ev)
346 {
347         if (ev->state & Keyboard::PrimaryModifier) {
348                 nudge_forward (false, true);
349         } else {
350                 nudge_forward (false, false);
351         }
352         return false;
353 }
354
355 bool
356 Editor::nudge_backward_release (GdkEventButton* ev)
357 {
358         if (ev->state & Keyboard::PrimaryModifier) {
359                 nudge_backward (false, true);
360         } else {
361                 nudge_backward (false, false);
362         }
363         return false;
364 }
365
366
367 void
368 Editor::nudge_forward (bool next, bool force_playhead)
369 {
370         framepos_t distance;
371         framepos_t next_distance;
372
373         if (!_session) {
374                 return;
375         }
376
377         RegionSelection rs = get_regions_from_selection_and_entered ();
378
379         if (!force_playhead && !rs.empty()) {
380
381                 begin_reversible_command (_("nudge regions forward"));
382
383                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
384                         boost::shared_ptr<Region> r ((*i)->region());
385
386                         distance = get_nudge_distance (r->position(), next_distance);
387
388                         if (next) {
389                                 distance = next_distance;
390                         }
391
392                         r->clear_changes ();
393                         r->set_position (r->position() + distance);
394                         _session->add_command (new StatefulDiffCommand (r));
395                 }
396
397                 commit_reversible_command ();
398
399
400         } else if (!force_playhead && !selection->markers.empty()) {
401
402                 bool is_start;
403
404                 begin_reversible_command (_("nudge location forward"));
405
406                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
407
408                         Location* loc = find_location_from_marker ((*i), is_start);
409
410                         if (loc) {
411
412                                 XMLNode& before (loc->get_state());
413
414                                 if (is_start) {
415                                         distance = get_nudge_distance (loc->start(), next_distance);
416                                         if (next) {
417                                                 distance = next_distance;
418                                         }
419                                         if (max_framepos - distance > loc->start() + loc->length()) {
420                                                 loc->set_start (loc->start() + distance);
421                                         } else {
422                                                 loc->set_start (max_framepos - loc->length());
423                                         }
424                                 } else {
425                                         distance = get_nudge_distance (loc->end(), next_distance);
426                                         if (next) {
427                                                 distance = next_distance;
428                                         }
429                                         if (max_framepos - distance > loc->end()) {
430                                                 loc->set_end (loc->end() + distance);
431                                         } else {
432                                                 loc->set_end (max_framepos);
433                                         }
434                                 }
435                                 XMLNode& after (loc->get_state());
436                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
437                         }
438                 }
439
440                 commit_reversible_command ();
441
442         } else {
443                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
444                 _session->request_locate (playhead_cursor->current_frame () + distance);
445         }
446 }
447
448 void
449 Editor::nudge_backward (bool next, bool force_playhead)
450 {
451         framepos_t distance;
452         framepos_t next_distance;
453
454         if (!_session) {
455                 return;
456         }
457
458         RegionSelection rs = get_regions_from_selection_and_entered ();
459
460         if (!force_playhead && !rs.empty()) {
461
462                 begin_reversible_command (_("nudge regions backward"));
463
464                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
465                         boost::shared_ptr<Region> r ((*i)->region());
466
467                         distance = get_nudge_distance (r->position(), next_distance);
468
469                         if (next) {
470                                 distance = next_distance;
471                         }
472
473                         r->clear_changes ();
474
475                         if (r->position() > distance) {
476                                 r->set_position (r->position() - distance);
477                         } else {
478                                 r->set_position (0);
479                         }
480                         _session->add_command (new StatefulDiffCommand (r));
481                 }
482
483                 commit_reversible_command ();
484
485         } else if (!force_playhead && !selection->markers.empty()) {
486
487                 bool is_start;
488
489                 begin_reversible_command (_("nudge location forward"));
490
491                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
492
493                         Location* loc = find_location_from_marker ((*i), is_start);
494
495                         if (loc) {
496
497                                 XMLNode& before (loc->get_state());
498
499                                 if (is_start) {
500                                         distance = get_nudge_distance (loc->start(), next_distance);
501                                         if (next) {
502                                                 distance = next_distance;
503                                         }
504                                         if (distance < loc->start()) {
505                                                 loc->set_start (loc->start() - distance);
506                                         } else {
507                                                 loc->set_start (0);
508                                         }
509                                 } else {
510                                         distance = get_nudge_distance (loc->end(), next_distance);
511
512                                         if (next) {
513                                                 distance = next_distance;
514                                         }
515
516                                         if (distance < loc->end() - loc->length()) {
517                                                 loc->set_end (loc->end() - distance);
518                                         } else {
519                                                 loc->set_end (loc->length());
520                                         }
521                                 }
522
523                                 XMLNode& after (loc->get_state());
524                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
525                         }
526                 }
527
528                 commit_reversible_command ();
529
530         } else {
531
532                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
533
534                 if (playhead_cursor->current_frame () > distance) {
535                         _session->request_locate (playhead_cursor->current_frame () - distance);
536                 } else {
537                         _session->goto_start();
538                 }
539         }
540 }
541
542 void
543 Editor::nudge_forward_capture_offset ()
544 {
545         RegionSelection rs = get_regions_from_selection_and_entered ();
546
547         if (!_session || rs.empty()) {
548                 return;
549         }
550
551         begin_reversible_command (_("nudge forward"));
552
553         framepos_t const distance = _session->worst_output_latency();
554
555         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
556                 boost::shared_ptr<Region> r ((*i)->region());
557
558                 r->clear_changes ();
559                 r->set_position (r->position() + distance);
560                 _session->add_command(new StatefulDiffCommand (r));
561         }
562
563         commit_reversible_command ();
564 }
565
566 void
567 Editor::nudge_backward_capture_offset ()
568 {
569         RegionSelection rs = get_regions_from_selection_and_entered ();
570
571         if (!_session || rs.empty()) {
572                 return;
573         }
574
575         begin_reversible_command (_("nudge backward"));
576
577         framepos_t const distance = _session->worst_output_latency();
578
579         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
580                 boost::shared_ptr<Region> r ((*i)->region());
581
582                 r->clear_changes ();
583
584                 if (r->position() > distance) {
585                         r->set_position (r->position() - distance);
586                 } else {
587                         r->set_position (0);
588                 }
589                 _session->add_command(new StatefulDiffCommand (r));
590         }
591
592         commit_reversible_command ();
593 }
594
595 struct RegionSelectionPositionSorter {
596         bool operator() (RegionView* a, RegionView* b) {
597                 return a->region()->position() < b->region()->position();
598         }
599 };
600
601 void
602 Editor::sequence_regions ()
603 {
604         framepos_t r_end;
605         framepos_t r_end_prev;
606
607         int iCount=0;
608
609         if (!_session) {
610                 return;
611         }
612
613         RegionSelection rs = get_regions_from_selection_and_entered ();
614         rs.sort(RegionSelectionPositionSorter());
615
616         if (!rs.empty()) {
617
618                 begin_reversible_command (_("sequence regions"));
619                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
620                         boost::shared_ptr<Region> r ((*i)->region());
621
622                         r->clear_changes();
623
624                         if(r->locked())
625                         {
626                                 continue;
627                         }
628                         if(r->position_locked())
629                         {
630                                 continue;
631                         }
632                         if(iCount>0)
633                         {
634                                 r_end_prev=r_end;
635                                 r->set_position(r_end_prev);
636                         }
637
638                         _session->add_command (new StatefulDiffCommand (r));
639
640                         r_end=r->position() + r->length();
641
642                         iCount++;
643                 }
644                 commit_reversible_command ();
645         } 
646
647
648
649 /* DISPLAY MOTION */
650
651 void
652 Editor::move_to_start ()
653 {
654         _session->goto_start ();
655 }
656
657 void
658 Editor::move_to_end ()
659 {
660
661         _session->request_locate (_session->current_end_frame());
662 }
663
664 void
665 Editor::build_region_boundary_cache ()
666 {
667         framepos_t pos = 0;
668         vector<RegionPoint> interesting_points;
669         boost::shared_ptr<Region> r;
670         TrackViewList tracks;
671         bool at_end = false;
672
673         region_boundary_cache.clear ();
674
675         if (_session == 0) {
676                 return;
677         }
678
679         switch (_snap_type) {
680         case SnapToRegionStart:
681                 interesting_points.push_back (Start);
682                 break;
683         case SnapToRegionEnd:
684                 interesting_points.push_back (End);
685                 break;
686         case SnapToRegionSync:
687                 interesting_points.push_back (SyncPoint);
688                 break;
689         case SnapToRegionBoundary:
690                 interesting_points.push_back (Start);
691                 interesting_points.push_back (End);
692                 break;
693         default:
694                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
695                 abort(); /*NOTREACHED*/
696                 return;
697         }
698
699         TimeAxisView *ontrack = 0;
700         TrackViewList tlist;
701         
702         if (!selection->tracks.empty()) {
703                 tlist = selection->tracks.filter_to_unique_playlists ();
704         } else {
705                 tlist = track_views.filter_to_unique_playlists ();
706         }
707
708         while (pos < _session->current_end_frame() && !at_end) {
709
710                 framepos_t rpos;
711                 framepos_t lpos = max_framepos;
712
713                 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
714
715                         if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
716                                 if (*p == interesting_points.back()) {
717                                         at_end = true;
718                                 }
719                                 /* move to next point type */
720                                 continue;
721                         }
722
723                         switch (*p) {
724                         case Start:
725                                 rpos = r->first_frame();
726                                 break;
727
728                         case End:
729                                 rpos = r->last_frame();
730                                 break;
731
732                         case SyncPoint:
733                                 rpos = r->sync_position ();
734                                 break;
735
736                         default:
737                                 break;
738                         }
739
740                         float speed = 1.0f;
741                         RouteTimeAxisView *rtav;
742
743                         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
744                                 if (rtav->track() != 0) {
745                                         speed = rtav->track()->speed();
746                                 }
747                         }
748
749                         rpos = track_frame_to_session_frame (rpos, speed);
750
751                         if (rpos < lpos) {
752                                 lpos = rpos;
753                         }
754
755                         /* prevent duplicates, but we don't use set<> because we want to be able
756                            to sort later.
757                         */
758
759                         vector<framepos_t>::iterator ri;
760
761                         for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
762                                 if (*ri == rpos) {
763                                         break;
764                                 }
765                         }
766
767                         if (ri == region_boundary_cache.end()) {
768                                 region_boundary_cache.push_back (rpos);
769                         }
770                 }
771
772                 pos = lpos + 1;
773         }
774
775         /* finally sort to be sure that the order is correct */
776
777         sort (region_boundary_cache.begin(), region_boundary_cache.end());
778 }
779
780 boost::shared_ptr<Region>
781 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
782 {
783         TrackViewList::iterator i;
784         framepos_t closest = max_framepos;
785         boost::shared_ptr<Region> ret;
786         framepos_t rpos = 0;
787
788         float track_speed;
789         framepos_t track_frame;
790         RouteTimeAxisView *rtav;
791
792         for (i = tracks.begin(); i != tracks.end(); ++i) {
793
794                 framecnt_t distance;
795                 boost::shared_ptr<Region> r;
796
797                 track_speed = 1.0f;
798                 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
799                         if (rtav->track()!=0)
800                                 track_speed = rtav->track()->speed();
801                 }
802
803                 track_frame = session_frame_to_track_frame(frame, track_speed);
804
805                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
806                         continue;
807                 }
808
809                 switch (point) {
810                 case Start:
811                         rpos = r->first_frame ();
812                         break;
813
814                 case End:
815                         rpos = r->last_frame ();
816                         break;
817
818                 case SyncPoint:
819                         rpos = r->sync_position ();
820                         break;
821                 }
822
823                 // rpos is a "track frame", converting it to "_session frame"
824                 rpos = track_frame_to_session_frame(rpos, track_speed);
825
826                 if (rpos > frame) {
827                         distance = rpos - frame;
828                 } else {
829                         distance = frame - rpos;
830                 }
831
832                 if (distance < closest) {
833                         closest = distance;
834                         if (ontrack != 0)
835                                 *ontrack = (*i);
836                         ret = r;
837                 }
838         }
839
840         return ret;
841 }
842
843 framepos_t
844 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
845 {
846         framecnt_t distance = max_framepos;
847         framepos_t current_nearest = -1;
848
849         for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
850                 framepos_t contender;
851                 framecnt_t d;
852
853                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
854
855                 if (!rtv) {
856                         continue;
857                 }
858
859                 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
860                         continue;
861                 }
862
863                 d = ::llabs (pos - contender);
864
865                 if (d < distance) {
866                         current_nearest = contender;
867                         distance = d;
868                 }
869         }
870
871         return current_nearest;
872 }
873
874 framepos_t
875 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
876 {
877         framepos_t target;
878         TrackViewList tvl;
879
880         if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
881
882                 if (!selection->tracks.empty()) {
883
884                         target = find_next_region_boundary (pos, dir, selection->tracks);
885
886                 } else {
887
888                         if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
889                                 get_onscreen_tracks (tvl);
890                                 target = find_next_region_boundary (pos, dir, tvl);
891                         } else {
892                                 target = find_next_region_boundary (pos, dir, track_views);
893                         }
894                 }
895
896         } else {
897
898                 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
899                         get_onscreen_tracks (tvl);
900                         target = find_next_region_boundary (pos, dir, tvl);
901                 } else {
902                         target = find_next_region_boundary (pos, dir, track_views);
903                 }
904         }
905
906         return target;
907 }
908
909 void
910 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
911 {
912         framepos_t pos = playhead_cursor->current_frame ();
913         framepos_t target;
914
915         if (!_session) {
916                 return;
917         }
918
919         // so we don't find the current region again..
920         if (dir > 0 || pos > 0) {
921                 pos += dir;
922         }
923
924         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
925                 return;
926         }
927
928         _session->request_locate (target);
929 }
930
931 void
932 Editor::cursor_to_next_region_boundary (bool with_selection)
933 {
934         cursor_to_region_boundary (with_selection, 1);
935 }
936
937 void
938 Editor::cursor_to_previous_region_boundary (bool with_selection)
939 {
940         cursor_to_region_boundary (with_selection, -1);
941 }
942
943 void
944 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
945 {
946         boost::shared_ptr<Region> r;
947         framepos_t pos = cursor->current_frame ();
948
949         if (!_session) {
950                 return;
951         }
952
953         TimeAxisView *ontrack = 0;
954
955         // so we don't find the current region again..
956         if (dir>0 || pos>0)
957                 pos+=dir;
958
959         if (!selection->tracks.empty()) {
960
961                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
962
963         } else if (clicked_axisview) {
964
965                 TrackViewList t;
966                 t.push_back (clicked_axisview);
967
968                 r = find_next_region (pos, point, dir, t, &ontrack);
969
970         } else {
971
972                 r = find_next_region (pos, point, dir, track_views, &ontrack);
973         }
974
975         if (r == 0) {
976                 return;
977         }
978
979         switch (point) {
980         case Start:
981                 pos = r->first_frame ();
982                 break;
983
984         case End:
985                 pos = r->last_frame ();
986                 break;
987
988         case SyncPoint:
989                 pos = r->sync_position ();
990                 break;
991         }
992
993         float speed = 1.0f;
994         RouteTimeAxisView *rtav;
995
996         if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
997                 if (rtav->track() != 0) {
998                         speed = rtav->track()->speed();
999                 }
1000         }
1001
1002         pos = track_frame_to_session_frame(pos, speed);
1003
1004         if (cursor == playhead_cursor) {
1005                 _session->request_locate (pos);
1006         } else {
1007                 cursor->set_position (pos);
1008         }
1009 }
1010
1011 void
1012 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
1013 {
1014         cursor_to_region_point (cursor, point, 1);
1015 }
1016
1017 void
1018 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
1019 {
1020         cursor_to_region_point (cursor, point, -1);
1021 }
1022
1023 void
1024 Editor::cursor_to_selection_start (EditorCursor *cursor)
1025 {
1026         framepos_t pos = 0;
1027
1028         switch (mouse_mode) {
1029         case MouseObject:
1030                 if (!selection->regions.empty()) {
1031                         pos = selection->regions.start();
1032                 }
1033                 break;
1034
1035         case MouseRange:
1036                 if (!selection->time.empty()) {
1037                         pos = selection->time.start ();
1038                 }
1039                 break;
1040
1041         default:
1042                 return;
1043         }
1044
1045         if (cursor == playhead_cursor) {
1046                 _session->request_locate (pos);
1047         } else {
1048                 cursor->set_position (pos);
1049         }
1050 }
1051
1052 void
1053 Editor::cursor_to_selection_end (EditorCursor *cursor)
1054 {
1055         framepos_t pos = 0;
1056
1057         switch (mouse_mode) {
1058         case MouseObject:
1059                 if (!selection->regions.empty()) {
1060                         pos = selection->regions.end_frame();
1061                 }
1062                 break;
1063
1064         case MouseRange:
1065                 if (!selection->time.empty()) {
1066                         pos = selection->time.end_frame ();
1067                 }
1068                 break;
1069
1070         default:
1071                 return;
1072         }
1073
1074         if (cursor == playhead_cursor) {
1075                 _session->request_locate (pos);
1076         } else {
1077                 cursor->set_position (pos);
1078         }
1079 }
1080
1081 void
1082 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1083 {
1084         framepos_t target;
1085         Location* loc;
1086         bool ignored;
1087
1088         if (!_session) {
1089                 return;
1090         }
1091
1092         if (selection->markers.empty()) {
1093                 framepos_t mouse;
1094                 bool ignored;
1095
1096                 if (!mouse_frame (mouse, ignored)) {
1097                         return;
1098                 }
1099
1100                 add_location_mark (mouse);
1101         }
1102
1103         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1104                 return;
1105         }
1106
1107         framepos_t pos = loc->start();
1108
1109         // so we don't find the current region again..
1110         if (dir > 0 || pos > 0) {
1111                 pos += dir;
1112         }
1113
1114         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1115                 return;
1116         }
1117
1118         loc->move_to (target);
1119 }
1120
1121 void
1122 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1123 {
1124         selected_marker_to_region_boundary (with_selection, 1);
1125 }
1126
1127 void
1128 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1129 {
1130         selected_marker_to_region_boundary (with_selection, -1);
1131 }
1132
1133 void
1134 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1135 {
1136         boost::shared_ptr<Region> r;
1137         framepos_t pos;
1138         Location* loc;
1139         bool ignored;
1140
1141         if (!_session || selection->markers.empty()) {
1142                 return;
1143         }
1144
1145         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1146                 return;
1147         }
1148
1149         TimeAxisView *ontrack = 0;
1150
1151         pos = loc->start();
1152
1153         // so we don't find the current region again..
1154         if (dir>0 || pos>0)
1155                 pos+=dir;
1156
1157         if (!selection->tracks.empty()) {
1158
1159                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1160
1161         } else {
1162
1163                 r = find_next_region (pos, point, dir, track_views, &ontrack);
1164         }
1165
1166         if (r == 0) {
1167                 return;
1168         }
1169
1170         switch (point) {
1171         case Start:
1172                 pos = r->first_frame ();
1173                 break;
1174
1175         case End:
1176                 pos = r->last_frame ();
1177                 break;
1178
1179         case SyncPoint:
1180                 pos = r->adjust_to_sync (r->first_frame());
1181                 break;
1182         }
1183
1184         float speed = 1.0f;
1185         RouteTimeAxisView *rtav;
1186
1187         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1188                 if (rtav->track() != 0) {
1189                         speed = rtav->track()->speed();
1190                 }
1191         }
1192
1193         pos = track_frame_to_session_frame(pos, speed);
1194
1195         loc->move_to (pos);
1196 }
1197
1198 void
1199 Editor::selected_marker_to_next_region_point (RegionPoint point)
1200 {
1201         selected_marker_to_region_point (point, 1);
1202 }
1203
1204 void
1205 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1206 {
1207         selected_marker_to_region_point (point, -1);
1208 }
1209
1210 void
1211 Editor::selected_marker_to_selection_start ()
1212 {
1213         framepos_t pos = 0;
1214         Location* loc;
1215         bool ignored;
1216
1217         if (!_session || selection->markers.empty()) {
1218                 return;
1219         }
1220
1221         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1222                 return;
1223         }
1224
1225         switch (mouse_mode) {
1226         case MouseObject:
1227                 if (!selection->regions.empty()) {
1228                         pos = selection->regions.start();
1229                 }
1230                 break;
1231
1232         case MouseRange:
1233                 if (!selection->time.empty()) {
1234                         pos = selection->time.start ();
1235                 }
1236                 break;
1237
1238         default:
1239                 return;
1240         }
1241
1242         loc->move_to (pos);
1243 }
1244
1245 void
1246 Editor::selected_marker_to_selection_end ()
1247 {
1248         framepos_t pos = 0;
1249         Location* loc;
1250         bool ignored;
1251
1252         if (!_session || selection->markers.empty()) {
1253                 return;
1254         }
1255
1256         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1257                 return;
1258         }
1259
1260         switch (mouse_mode) {
1261         case MouseObject:
1262                 if (!selection->regions.empty()) {
1263                         pos = selection->regions.end_frame();
1264                 }
1265                 break;
1266
1267         case MouseRange:
1268                 if (!selection->time.empty()) {
1269                         pos = selection->time.end_frame ();
1270                 }
1271                 break;
1272
1273         default:
1274                 return;
1275         }
1276
1277         loc->move_to (pos);
1278 }
1279
1280 void
1281 Editor::scroll_playhead (bool forward)
1282 {
1283         framepos_t pos = playhead_cursor->current_frame ();
1284         framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1285
1286         if (forward) {
1287                 if (pos == max_framepos) {
1288                         return;
1289                 }
1290
1291                 if (pos < max_framepos - delta) {
1292                         pos += delta ;
1293                 } else {
1294                         pos = max_framepos;
1295                 }
1296
1297         } else {
1298
1299                 if (pos == 0) {
1300                         return;
1301                 }
1302
1303                 if (pos > delta) {
1304                         pos -= delta;
1305                 } else {
1306                         pos = 0;
1307                 }
1308         }
1309
1310         _session->request_locate (pos);
1311 }
1312
1313 void
1314 Editor::cursor_align (bool playhead_to_edit)
1315 {
1316         if (!_session) {
1317                 return;
1318         }
1319
1320         if (playhead_to_edit) {
1321
1322                 if (selection->markers.empty()) {
1323                         return;
1324                 }
1325
1326                 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1327
1328         } else {
1329                 /* move selected markers to playhead */
1330
1331                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1332                         bool ignored;
1333
1334                         Location* loc = find_location_from_marker (*i, ignored);
1335
1336                         if (loc->is_mark()) {
1337                                 loc->set_start (playhead_cursor->current_frame ());
1338                         } else {
1339                                 loc->set (playhead_cursor->current_frame (),
1340                                           playhead_cursor->current_frame () + loc->length());
1341                         }
1342                 }
1343         }
1344 }
1345
1346 void
1347 Editor::scroll_backward (float pages)
1348 {
1349         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1350         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1351
1352         framepos_t frame;
1353         if (leftmost_frame < cnt) {
1354                 frame = 0;
1355         } else {
1356                 frame = leftmost_frame - cnt;
1357         }
1358
1359         reset_x_origin (frame);
1360 }
1361
1362 void
1363 Editor::scroll_forward (float pages)
1364 {
1365         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1366         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1367
1368         framepos_t frame;
1369         if (max_framepos - cnt < leftmost_frame) {
1370                 frame = max_framepos - cnt;
1371         } else {
1372                 frame = leftmost_frame + cnt;
1373         }
1374
1375         reset_x_origin (frame);
1376 }
1377
1378 void
1379 Editor::scroll_tracks_down ()
1380 {
1381         double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1382         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1383                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1384         }
1385
1386         vertical_adjustment.set_value (vert_value);
1387 }
1388
1389 void
1390 Editor::scroll_tracks_up ()
1391 {
1392         vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1393 }
1394
1395 void
1396 Editor::scroll_tracks_down_line ()
1397 {
1398         double vert_value = vertical_adjustment.get_value() + 60;
1399
1400         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1401                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1402         }
1403
1404         vertical_adjustment.set_value (vert_value);
1405 }
1406
1407 void
1408 Editor::scroll_tracks_up_line ()
1409 {
1410         reset_y_origin (vertical_adjustment.get_value() - 60);
1411 }
1412
1413 bool
1414 Editor::scroll_down_one_track (bool skip_child_views)
1415 {
1416         TrackViewList::reverse_iterator next = track_views.rend();
1417         const double top_of_trackviews = vertical_adjustment.get_value();
1418
1419         for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1420                 if ((*t)->hidden()) {
1421                         continue;
1422                 }
1423
1424                 /* If this is the upper-most visible trackview, we want to display
1425                  * the one above it (next)
1426                  *
1427                  * Note that covers_y_position() is recursive and includes child views
1428                  */
1429                 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1430
1431                 if (res.first) {
1432                         if (skip_child_views) {
1433                                 break;
1434                         }
1435                         /* automation lane (one level, non-recursive)
1436                          *
1437                          * - if no automation lane exists -> move to next tack
1438                          * - if the first (here: bottom-most) matches -> move to next tack
1439                          * - if no y-axis match is found -> the current track is at the top
1440                          *     -> move to last (here: top-most) automation lane
1441                          */
1442                         TimeAxisView::Children kids = (*t)->get_child_list();
1443                         TimeAxisView::Children::reverse_iterator nkid = kids.rend();
1444
1445                         for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1446                                 if ((*ci)->hidden()) {
1447                                         continue;
1448                                 }
1449
1450                                 std::pair<TimeAxisView*,double> dev;
1451                                 dev = (*ci)->covers_y_position (top_of_trackviews);
1452                                 if (dev.first) {
1453                                         /* some automation lane is currently at the top */
1454                                         if (ci == kids.rbegin()) {
1455                                                 /* first (bottom-most) autmation lane is at the top.
1456                                                  * -> move to next track
1457                                                  */
1458                                                 nkid = kids.rend();
1459                                         }
1460                                         break;
1461                                 }
1462                                 nkid = ci;
1463                         }
1464
1465                         if (nkid != kids.rend()) {
1466                                 ensure_time_axis_view_is_visible (**nkid, true);
1467                                 return true;
1468                         }
1469                         break;
1470                 }
1471                 next = t;
1472         }
1473
1474         /* move to the track below the first one that covers the */
1475         
1476         if (next != track_views.rend()) {
1477                 ensure_time_axis_view_is_visible (**next, true);
1478                 return true;
1479         }
1480
1481         return false;
1482 }       
1483
1484 bool
1485 Editor::scroll_up_one_track (bool skip_child_views)
1486 {
1487         TrackViewList::iterator prev = track_views.end();
1488         double top_of_trackviews = vertical_adjustment.get_value ();
1489         
1490         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1491
1492                 if ((*t)->hidden()) {
1493                         continue;
1494                 }
1495
1496                 /* find the trackview at the top of the trackview group 
1497                  *
1498                  * Note that covers_y_position() is recursive and includes child views
1499                  */
1500                 std::pair<TimeAxisView*,double> res = (*t)->covers_y_position (top_of_trackviews);
1501                 
1502                 if (res.first) {
1503                         if (skip_child_views) {
1504                                 break;
1505                         }
1506                         /* automation lane (one level, non-recursive)
1507                          *
1508                          * - if no automation lane exists -> move to prev tack
1509                          * - if no y-axis match is found -> the current track is at the top -> move to prev track 
1510                          *     (actually last automation lane of previous track, see below)
1511                          * - if first (top-most) lane is at the top -> move to this track
1512                          * - else move up one lane
1513                          */
1514                         TimeAxisView::Children kids = (*t)->get_child_list();
1515                         TimeAxisView::Children::iterator pkid = kids.end();
1516
1517                         for (TimeAxisView::Children::iterator ci = kids.begin(); ci != kids.end(); ++ci) {
1518                                 if ((*ci)->hidden()) {
1519                                         continue;
1520                                 }
1521
1522                                 std::pair<TimeAxisView*,double> dev;
1523                                 dev = (*ci)->covers_y_position (top_of_trackviews);
1524                                 if (dev.first) {
1525                                         /* some automation lane is currently at the top */
1526                                         if (ci == kids.begin()) {
1527                                                 /* first (top-most) autmation lane is at the top.
1528                                                  * jump directly to this track's top
1529                                                  */
1530                                                 ensure_time_axis_view_is_visible (**t, true);
1531                                                 return true;
1532                                         }
1533                                         else if (pkid != kids.end()) {
1534                                                 /* some other automation lane is at the top.
1535                                                  * move up to prev automation lane.
1536                                                  */
1537                                                 ensure_time_axis_view_is_visible (**pkid, true);
1538                                                 return true;
1539                                         }
1540                                         assert(0); // not reached
1541                                         break;
1542                                 }
1543                                 pkid = ci;
1544                         }
1545                         break;
1546                 }
1547
1548                 prev = t;
1549         }
1550         
1551         if (prev != track_views.end()) {
1552                 // move to bottom-most automation-lane of the previous track
1553                 TimeAxisView::Children kids = (*prev)->get_child_list();
1554                 TimeAxisView::Children::reverse_iterator pkid = kids.rend();
1555                 if (!skip_child_views) {
1556                         // find the last visible lane
1557                         for (TimeAxisView::Children::reverse_iterator ci = kids.rbegin(); ci != kids.rend(); ++ci) {
1558                                 if (!(*ci)->hidden()) {
1559                                         pkid = ci;
1560                                         break;
1561                                 }
1562                         }
1563                 }
1564                 if (pkid != kids.rend()) {
1565                         ensure_time_axis_view_is_visible (**pkid, true);
1566                 } else  {
1567                         ensure_time_axis_view_is_visible (**prev, true);
1568                 }
1569                 return true;
1570         }
1571
1572         return false;
1573 }
1574
1575 /* ZOOM */
1576
1577 void
1578 Editor::tav_zoom_step (bool coarser)
1579 {
1580         DisplaySuspender ds;
1581
1582         TrackViewList* ts;
1583
1584         if (selection->tracks.empty()) {
1585                 ts = &track_views;
1586         } else {
1587                 ts = &selection->tracks;
1588         }
1589         
1590         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1591                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1592                         tv->step_height (coarser);
1593         }
1594 }
1595
1596 void
1597 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1598 {
1599         DisplaySuspender ds;
1600
1601         TrackViewList* ts;
1602
1603         if (selection->tracks.empty() || force_all) {
1604                 ts = &track_views;
1605         } else {
1606                 ts = &selection->tracks;
1607         }
1608         
1609         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1610                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1611                 uint32_t h = tv->current_height ();
1612
1613                 if (coarser) {
1614                         if (h > 5) {
1615                                 h -= 5; // pixels
1616                                 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1617                                         tv->set_height (h);
1618                                 }
1619                         }
1620                 } else {
1621                         tv->set_height (h + 5);
1622                 }
1623         }
1624 }
1625
1626
1627 void
1628 Editor::temporal_zoom_step (bool coarser)
1629 {
1630         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1631
1632         framecnt_t nspp = samples_per_pixel;
1633
1634         if (coarser) {
1635                 nspp *= 2;
1636         } else {
1637                 nspp /= 2;
1638         }
1639
1640         temporal_zoom (nspp);
1641 }
1642
1643 void
1644 Editor::temporal_zoom (framecnt_t fpp)
1645 {
1646         if (!_session) {
1647                 return;
1648         }
1649
1650         framepos_t current_page = current_page_samples();
1651         framepos_t current_leftmost = leftmost_frame;
1652         framepos_t current_rightmost;
1653         framepos_t current_center;
1654         framepos_t new_page_size;
1655         framepos_t half_page_size;
1656         framepos_t leftmost_after_zoom = 0;
1657         framepos_t where;
1658         bool in_track_canvas;
1659         framecnt_t nfpp;
1660         double l;
1661
1662         if (fpp == samples_per_pixel) {
1663                 return;
1664         }
1665
1666         // Imposing an arbitrary limit to zoom out as too much zoom out produces 
1667         // segfaults for lack of memory. If somebody decides this is not high enough I
1668         // believe it can be raisen to higher values but some limit must be in place.
1669         //
1670         // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1671         // all of which is used for the editor track displays. The whole day
1672         // would be 4147200000 samples, so 2592000 samples per pixel.
1673
1674         nfpp = min (fpp, (framecnt_t) 2592000);
1675         nfpp = max ((framecnt_t) 1, nfpp);
1676
1677         new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1678         half_page_size = new_page_size / 2;
1679
1680         switch (zoom_focus) {
1681         case ZoomFocusLeft:
1682                 leftmost_after_zoom = current_leftmost;
1683                 break;
1684
1685         case ZoomFocusRight:
1686                 current_rightmost = leftmost_frame + current_page;
1687                 if (current_rightmost < new_page_size) {
1688                         leftmost_after_zoom = 0;
1689                 } else {
1690                         leftmost_after_zoom = current_rightmost - new_page_size;
1691                 }
1692                 break;
1693
1694         case ZoomFocusCenter:
1695                 current_center = current_leftmost + (current_page/2);
1696                 if (current_center < half_page_size) {
1697                         leftmost_after_zoom = 0;
1698                 } else {
1699                         leftmost_after_zoom = current_center - half_page_size;
1700                 }
1701                 break;
1702
1703         case ZoomFocusPlayhead:
1704                 /* centre playhead */
1705                 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1706
1707                 if (l < 0) {
1708                         leftmost_after_zoom = 0;
1709                 } else if (l > max_framepos) {
1710                         leftmost_after_zoom = max_framepos - new_page_size;
1711                 } else {
1712                         leftmost_after_zoom = (framepos_t) l;
1713                 }
1714                 break;
1715
1716         case ZoomFocusMouse:
1717                 /* try to keep the mouse over the same point in the display */
1718
1719                 if (!mouse_frame (where, in_track_canvas)) {
1720                         /* use playhead instead */
1721                         where = playhead_cursor->current_frame ();
1722
1723                         if (where < half_page_size) {
1724                                 leftmost_after_zoom = 0;
1725                         } else {
1726                                 leftmost_after_zoom = where - half_page_size;
1727                         }
1728
1729                 } else {
1730
1731                         l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1732
1733                         if (l < 0) {
1734                                 leftmost_after_zoom = 0;
1735                         } else if (l > max_framepos) {
1736                                 leftmost_after_zoom = max_framepos - new_page_size;
1737                         } else {
1738                                 leftmost_after_zoom = (framepos_t) l;
1739                         }
1740                 }
1741
1742                 break;
1743
1744         case ZoomFocusEdit:
1745                 /* try to keep the edit point in the same place */
1746                 where = get_preferred_edit_position ();
1747
1748                 if (where > 0) {
1749
1750                         double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1751
1752                         if (l < 0) {
1753                                 leftmost_after_zoom = 0;
1754                         } else if (l > max_framepos) {
1755                                 leftmost_after_zoom = max_framepos - new_page_size;
1756                         } else {
1757                                 leftmost_after_zoom = (framepos_t) l;
1758                         }
1759
1760                 } else {
1761                         /* edit point not defined */
1762                         return;
1763                 }
1764                 break;
1765
1766         }
1767
1768         // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1769
1770         reposition_and_zoom (leftmost_after_zoom, nfpp);
1771 }
1772
1773 void
1774 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1775 {
1776         /* this func helps make sure we leave a little space
1777            at each end of the editor so that the zoom doesn't fit the region
1778            precisely to the screen.
1779         */
1780
1781         GdkScreen* screen = gdk_screen_get_default ();
1782         const gint pixwidth = gdk_screen_get_width (screen);
1783         const gint mmwidth = gdk_screen_get_width_mm (screen);
1784         const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1785         const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1786
1787         const framepos_t range = end - start;
1788         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1789         const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1790
1791         if (start > extra_samples) {
1792                 start -= extra_samples;
1793         } else {
1794                 start = 0;
1795         }
1796
1797         if (max_framepos - extra_samples > end) {
1798                 end += extra_samples;
1799         } else {
1800                 end = max_framepos;
1801         }
1802 }
1803
1804 void
1805 Editor::temporal_zoom_region (bool both_axes)
1806 {
1807         framepos_t start = max_framepos;
1808         framepos_t end = 0;
1809         set<TimeAxisView*> tracks;
1810
1811         if ( !get_selection_extents(start, end) )
1812                 return;
1813         
1814         calc_extra_zoom_edges (start, end);
1815
1816         /* if we're zooming on both axes we need to save track heights etc.
1817          */
1818
1819         undo_visual_stack.push_back (current_visual_state (both_axes));
1820
1821         PBD::Unwinder<bool> nsv (no_save_visual, true);
1822
1823         temporal_zoom_by_frame (start, end);
1824         
1825         if (both_axes) {
1826                 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1827
1828                 /* set visible track heights appropriately */
1829
1830                 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1831                         (*t)->set_height (per_track_height);
1832                 }
1833
1834                 /* hide irrelevant tracks */
1835
1836                 DisplaySuspender ds;
1837
1838                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1839                         if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1840                                 hide_track_in_display (*i);
1841                         }
1842                 }
1843
1844                 vertical_adjustment.set_value (0.0);
1845         }
1846
1847         redo_visual_stack.push_back (current_visual_state (both_axes));
1848 }
1849
1850
1851 bool
1852 Editor::get_selection_extents ( framepos_t &start, framepos_t &end )
1853 {
1854         start = max_framepos;
1855         end = 0;
1856         bool ret = true;
1857         
1858         //ToDo:  if notes are selected, set extents to that selection
1859
1860         //ToDo:  if control points are selected, set extents to that selection
1861
1862         if ( !selection->regions.empty() ) {
1863                 RegionSelection rs = get_regions_from_selection_and_entered ();
1864
1865                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1866
1867                         if ((*i)->region()->position() < start) {
1868                                 start = (*i)->region()->position();
1869                         }
1870
1871                         if ((*i)->region()->last_frame() + 1 > end) {
1872                                 end = (*i)->region()->last_frame() + 1;
1873                         }
1874                 }
1875
1876         } else if (!selection->time.empty()) {
1877                 start = selection->time.start();
1878                 end = selection->time.end_frame();
1879         } else 
1880                 ret = false;  //no selection found
1881
1882         //range check
1883         if ((start == 0 && end == 0) || end < start) {
1884                 ret = false;
1885         }
1886         
1887         return ret;     
1888 }
1889
1890
1891 void
1892 Editor::temporal_zoom_selection (bool both_axes)
1893 {
1894         if (!selection) return;
1895
1896         //ToDo:  if notes are selected, zoom to that
1897
1898         //ToDo:  if control points are selected, zoom to that
1899
1900         //if region(s) are selected, zoom to that
1901         if ( !selection->regions.empty() )
1902                 temporal_zoom_region (both_axes);
1903
1904         //if a range is selected, zoom to that
1905         if (!selection->time.empty()) {
1906
1907                 framepos_t start,  end;
1908                 if (get_selection_extents (start, end)) {
1909                         calc_extra_zoom_edges(start, end);
1910                         temporal_zoom_by_frame (start, end);
1911                 }
1912                 
1913                 if (both_axes)
1914                         fit_selection();
1915         }
1916
1917 }
1918
1919 void
1920 Editor::temporal_zoom_session ()
1921 {
1922         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1923
1924         if (_session) {
1925                 framecnt_t start = _session->current_start_frame();
1926                 framecnt_t end = _session->current_end_frame();
1927
1928                 if (_session->actively_recording () ) {
1929                         framepos_t cur = playhead_cursor->current_frame ();
1930                         if (cur > end) {
1931                                 /* recording beyond the end marker; zoom out
1932                                  * by 5 seconds more so that if 'follow
1933                                  * playhead' is active we don't immediately
1934                                  * scroll.
1935                                  */
1936                                 end = cur + _session->frame_rate() * 5;
1937                         }
1938                 }
1939
1940                 if ((start == 0 && end == 0) || end < start) {
1941                         return;
1942                 }
1943
1944                 calc_extra_zoom_edges(start, end);
1945
1946                 temporal_zoom_by_frame (start, end);
1947         }
1948 }
1949
1950 void
1951 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1952 {
1953         if (!_session) return;
1954
1955         if ((start == 0 && end == 0) || end < start) {
1956                 return;
1957         }
1958
1959         framepos_t range = end - start;
1960
1961         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1962         
1963         framepos_t new_page = range;
1964         framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1965         framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1966
1967         if (new_leftmost > middle) {
1968                 new_leftmost = 0;
1969         }
1970
1971         if (new_leftmost < 0) {
1972                 new_leftmost = 0;
1973         }
1974
1975         reposition_and_zoom (new_leftmost, new_fpp);
1976 }
1977
1978 void
1979 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1980 {
1981         if (!_session) {
1982                 return;
1983         }
1984
1985         framecnt_t range_before = frame - leftmost_frame;
1986         framecnt_t new_spp;
1987
1988         if (coarser) {
1989                 if (samples_per_pixel <= 1) {
1990                         new_spp = 2;
1991                 } else {
1992                         new_spp = samples_per_pixel + (samples_per_pixel/2);
1993                 }
1994                 range_before += range_before/2;
1995         } else {
1996                 if (samples_per_pixel >= 1) {
1997                         new_spp = samples_per_pixel - (samples_per_pixel/2);
1998                 } else {
1999                         /* could bail out here since we cannot zoom any finer,
2000                            but leave that to the equality test below
2001                         */
2002                         new_spp = samples_per_pixel;
2003                 }
2004
2005                 range_before -= range_before/2;
2006         }
2007
2008         if (new_spp == samples_per_pixel)  {
2009                 return;
2010         }
2011
2012         /* zoom focus is automatically taken as @param frame when this
2013            method is used.
2014         */
2015         
2016         framepos_t new_leftmost = frame - (framepos_t)range_before;
2017
2018         if (new_leftmost > frame) {
2019                 new_leftmost = 0;
2020         }
2021
2022         if (new_leftmost < 0) {
2023                 new_leftmost = 0;
2024         }
2025
2026         reposition_and_zoom (new_leftmost, new_spp);
2027 }
2028
2029
2030 bool
2031 Editor::choose_new_marker_name(string &name) {
2032
2033         if (!ARDOUR_UI::config()->get_name_new_markers()) {
2034                 /* don't prompt user for a new name */
2035                 return true;
2036         }
2037
2038         ArdourPrompter dialog (true);
2039
2040         dialog.set_prompt (_("New Name:"));
2041
2042         dialog.set_title (_("New Location Marker"));
2043
2044         dialog.set_name ("MarkNameWindow");
2045         dialog.set_size_request (250, -1);
2046         dialog.set_position (Gtk::WIN_POS_MOUSE);
2047
2048         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
2049         dialog.set_initial_text (name);
2050
2051         dialog.show ();
2052
2053         switch (dialog.run ()) {
2054         case RESPONSE_ACCEPT:
2055                 break;
2056         default:
2057                 return false;
2058         }
2059
2060         dialog.get_result(name);
2061         return true;
2062
2063 }
2064
2065
2066 void
2067 Editor::add_location_from_selection ()
2068 {
2069         string rangename;
2070
2071         if (selection->time.empty()) {
2072                 return;
2073         }
2074
2075         if (_session == 0 || clicked_axisview == 0) {
2076                 return;
2077         }
2078
2079         framepos_t start = selection->time[clicked_selection].start;
2080         framepos_t end = selection->time[clicked_selection].end;
2081
2082         _session->locations()->next_available_name(rangename,"selection");
2083         Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
2084
2085         begin_reversible_command (_("add marker"));
2086         
2087         XMLNode &before = _session->locations()->get_state();
2088         _session->locations()->add (location, true);
2089         XMLNode &after = _session->locations()->get_state();
2090         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2091         
2092         commit_reversible_command ();
2093 }
2094
2095 void
2096 Editor::add_location_mark (framepos_t where)
2097 {
2098         string markername;
2099
2100         select_new_marker = true;
2101
2102         _session->locations()->next_available_name(markername,"mark");
2103         if (!choose_new_marker_name(markername)) {
2104                 return;
2105         }
2106         Location *location = new Location (*_session, where, where, markername, Location::IsMark);
2107         begin_reversible_command (_("add marker"));
2108         
2109         XMLNode &before = _session->locations()->get_state();
2110         _session->locations()->add (location, true);
2111         XMLNode &after = _session->locations()->get_state();
2112         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2113         
2114         commit_reversible_command ();
2115 }
2116
2117 void
2118 Editor::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         QuantizeDialog* qd = new QuantizeDialog (*this);
5186
5187         qd->present ();
5188         const int r = qd->run ();
5189         qd->hide ();
5190
5191         if (r == Gtk::RESPONSE_OK) {
5192                 Quantize quant (qd->snap_start(), qd->snap_end(),
5193                                 qd->start_grid_size(), qd->end_grid_size(),
5194                                 qd->strength(), qd->swing(), qd->threshold());
5195
5196                 apply_midi_note_edit_op (quant, rs);
5197         }
5198 }
5199
5200 void
5201 Editor::legatize_region (bool shrink_only)
5202 {
5203         if (_session) {
5204                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5205         }
5206 }
5207
5208 void
5209 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5210 {
5211         if (rs.n_midi_regions() == 0) {
5212                 return;
5213         }
5214
5215         Legatize legatize(shrink_only);
5216         apply_midi_note_edit_op (legatize, rs);
5217 }
5218
5219 void
5220 Editor::transform_region ()
5221 {
5222         if (_session) {
5223                 transform_regions(get_regions_from_selection_and_entered ());
5224         }
5225 }
5226
5227 void
5228 Editor::transform_regions (const RegionSelection& rs)
5229 {
5230         if (rs.n_midi_regions() == 0) {
5231                 return;
5232         }
5233
5234         TransformDialog* td = new TransformDialog();
5235
5236         td->present();
5237         const int r = td->run();
5238         td->hide();
5239
5240         if (r == Gtk::RESPONSE_OK) {
5241                 Transform transform(td->get());
5242                 apply_midi_note_edit_op(transform, rs);
5243         }
5244 }
5245
5246 void
5247 Editor::insert_patch_change (bool from_context)
5248 {
5249         RegionSelection rs = get_regions_from_selection_and_entered ();
5250
5251         if (rs.empty ()) {
5252                 return;
5253         }
5254
5255         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5256
5257         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5258            there may be more than one, but the PatchChangeDialog can only offer
5259            one set of patch menus.
5260         */
5261         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5262
5263         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5264         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5265
5266         if (d.run() == RESPONSE_CANCEL) {
5267                 return;
5268         }
5269
5270         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5271                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5272                 if (mrv) {
5273                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5274                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5275                         }
5276                 }
5277         }
5278 }
5279
5280 void
5281 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5282 {
5283         RegionSelection rs = get_regions_from_selection_and_entered ();
5284
5285         if (rs.empty()) {
5286                 return;
5287         }
5288
5289         begin_reversible_command (command);
5290
5291         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5292         gdk_flush ();
5293
5294         int n = 0;
5295         int const N = rs.size ();
5296
5297         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5298                 RegionSelection::iterator tmp = r;
5299                 ++tmp;
5300
5301                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5302                 if (arv) {
5303                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5304
5305                         if (progress) {
5306                                 progress->descend (1.0 / N);
5307                         }
5308
5309                         if (arv->audio_region()->apply (filter, progress) == 0) {
5310
5311                                 playlist->clear_changes ();
5312                                 playlist->clear_owned_changes ();
5313
5314                                 if (filter.results.empty ()) {
5315
5316                                         /* no regions returned; remove the old one */
5317                                         playlist->remove_region (arv->region ());
5318
5319                                 } else {
5320
5321                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5322
5323                                         /* first region replaces the old one */
5324                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5325                                         ++res;
5326
5327                                         /* add the rest */
5328                                         while (res != filter.results.end()) {
5329                                                 playlist->add_region (*res, (*res)->position());
5330                                                 ++res;
5331                                         }
5332
5333                                 }
5334
5335                                 /* We might have removed regions, which alters other regions' layering_index,
5336                                    so we need to do a recursive diff here.
5337                                 */
5338                                 vector<Command*> cmds;
5339                                 playlist->rdiff (cmds);
5340                                 _session->add_commands (cmds);
5341                                 
5342                                 _session->add_command(new StatefulDiffCommand (playlist));
5343                         } else {
5344                                 return;
5345                         }
5346
5347                         if (progress) {
5348                                 progress->ascend ();
5349                         }
5350                 }
5351
5352                 r = tmp;
5353                 ++n;
5354         }
5355
5356         commit_reversible_command ();
5357 }
5358
5359 void
5360 Editor::external_edit_region ()
5361 {
5362         /* more to come */
5363 }
5364
5365 void
5366 Editor::reset_region_gain_envelopes ()
5367 {
5368         RegionSelection rs = get_regions_from_selection_and_entered ();
5369
5370         if (!_session || rs.empty()) {
5371                 return;
5372         }
5373
5374         begin_reversible_command (_("reset region gain"));
5375         
5376         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5377                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5378                 if (arv) {
5379                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5380                         XMLNode& before (alist->get_state());
5381
5382                         arv->audio_region()->set_default_envelope ();
5383                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5384                 }
5385         }
5386         
5387         commit_reversible_command ();
5388 }
5389
5390 void
5391 Editor::set_region_gain_visibility (RegionView* rv)
5392 {
5393         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5394         if (arv) {
5395                 arv->update_envelope_visibility();
5396         }
5397 }
5398
5399 void
5400 Editor::set_gain_envelope_visibility ()
5401 {
5402         if (!_session) {
5403                 return;
5404         }
5405
5406         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5407                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5408                 if (v) {
5409                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5410                 }
5411         }
5412 }
5413
5414 void
5415 Editor::toggle_gain_envelope_active ()
5416 {
5417         if (_ignore_region_action) {
5418                 return;
5419         }
5420
5421         RegionSelection rs = get_regions_from_selection_and_entered ();
5422
5423         if (!_session || rs.empty()) {
5424                 return;
5425         }
5426
5427         begin_reversible_command (_("region gain envelope active"));
5428         
5429         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5430                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5431                 if (arv) {
5432                         arv->region()->clear_changes ();
5433                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5434                         _session->add_command (new StatefulDiffCommand (arv->region()));
5435                 }
5436         }
5437         
5438         commit_reversible_command ();
5439 }
5440
5441 void
5442 Editor::toggle_region_lock ()
5443 {
5444         if (_ignore_region_action) {
5445                 return;
5446         }
5447
5448         RegionSelection rs = get_regions_from_selection_and_entered ();
5449
5450         if (!_session || rs.empty()) {
5451                 return;
5452         }
5453
5454         begin_reversible_command (_("toggle region lock"));
5455         
5456         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5457                 (*i)->region()->clear_changes ();
5458                 (*i)->region()->set_locked (!(*i)->region()->locked());
5459                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5460         }
5461         
5462         commit_reversible_command ();
5463 }
5464
5465 void
5466 Editor::toggle_region_video_lock ()
5467 {
5468         if (_ignore_region_action) {
5469                 return;
5470         }
5471
5472         RegionSelection rs = get_regions_from_selection_and_entered ();
5473
5474         if (!_session || rs.empty()) {
5475                 return;
5476         }
5477
5478         begin_reversible_command (_("Toggle Video Lock"));
5479         
5480         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5481                 (*i)->region()->clear_changes ();
5482                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5483                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5484         }
5485         
5486         commit_reversible_command ();
5487 }
5488
5489 void
5490 Editor::toggle_region_lock_style ()
5491 {
5492         if (_ignore_region_action) {
5493                 return;
5494         }
5495
5496         RegionSelection rs = get_regions_from_selection_and_entered ();
5497
5498         if (!_session || rs.empty()) {
5499                 return;
5500         }
5501
5502         begin_reversible_command (_("region lock style"));
5503         
5504         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5505                 (*i)->region()->clear_changes ();
5506                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5507                 (*i)->region()->set_position_lock_style (ns);
5508                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5509         }
5510         
5511         commit_reversible_command ();
5512 }
5513
5514 void
5515 Editor::toggle_opaque_region ()
5516 {
5517         if (_ignore_region_action) {
5518                 return;
5519         }
5520
5521         RegionSelection rs = get_regions_from_selection_and_entered ();
5522
5523         if (!_session || rs.empty()) {
5524                 return;
5525         }
5526
5527         begin_reversible_command (_("change region opacity"));
5528         
5529         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5530                 (*i)->region()->clear_changes ();
5531                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5532                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5533         }
5534         
5535         commit_reversible_command ();
5536 }
5537
5538 void
5539 Editor::toggle_record_enable ()
5540 {
5541         bool new_state = false;
5542         bool first = true;
5543         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5544                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5545                 if (!rtav)
5546                         continue;
5547                 if (!rtav->is_track())
5548                         continue;
5549
5550                 if (first) {
5551                         new_state = !rtav->track()->record_enabled();
5552                         first = false;
5553                 }
5554
5555                 rtav->track()->set_record_enabled (new_state, this);
5556         }
5557 }
5558
5559 void
5560 Editor::toggle_solo ()
5561 {
5562         bool new_state = false;
5563         bool first = true;
5564         boost::shared_ptr<RouteList> rl (new RouteList);
5565
5566         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5567                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5568
5569                 if (!rtav) {
5570                         continue;
5571                 }
5572
5573                 if (first) {
5574                         new_state = !rtav->route()->soloed ();
5575                         first = false;
5576                 }
5577
5578                 rl->push_back (rtav->route());
5579         }
5580
5581         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5582 }
5583
5584 void
5585 Editor::toggle_mute ()
5586 {
5587         bool new_state = false;
5588         bool first = true;
5589         boost::shared_ptr<RouteList> rl (new RouteList);
5590
5591         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5592                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5593
5594                 if (!rtav) {
5595                         continue;
5596                 }
5597
5598                 if (first) {
5599                         new_state = !rtav->route()->muted();
5600                         first = false;
5601                 }
5602
5603                 rl->push_back (rtav->route());
5604         }
5605
5606         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5607 }
5608
5609 void
5610 Editor::toggle_solo_isolate ()
5611 {
5612 }
5613
5614
5615 void
5616 Editor::fade_range ()
5617 {
5618         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5619
5620         begin_reversible_command (_("fade range"));
5621
5622         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5623                 (*i)->fade_range (selection->time);
5624         }
5625
5626         commit_reversible_command ();
5627 }
5628
5629
5630 void
5631 Editor::set_fade_length (bool in)
5632 {
5633         RegionSelection rs = get_regions_from_selection_and_entered ();
5634
5635         if (rs.empty()) {
5636                 return;
5637         }
5638
5639         /* we need a region to measure the offset from the start */
5640
5641         RegionView* rv = rs.front ();
5642
5643         framepos_t pos = get_preferred_edit_position();
5644         framepos_t len;
5645         char const * cmd;
5646
5647         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5648                 /* edit point is outside the relevant region */
5649                 return;
5650         }
5651
5652         if (in) {
5653                 if (pos <= rv->region()->position()) {
5654                         /* can't do it */
5655                         return;
5656                 }
5657                 len = pos - rv->region()->position();
5658                 cmd = _("set fade in length");
5659         } else {
5660                 if (pos >= rv->region()->last_frame()) {
5661                         /* can't do it */
5662                         return;
5663                 }
5664                 len = rv->region()->last_frame() - pos;
5665                 cmd = _("set fade out length");
5666         }
5667
5668         begin_reversible_command (cmd);
5669
5670         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5671                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5672
5673                 if (!tmp) {
5674                         return;
5675                 }
5676
5677                 boost::shared_ptr<AutomationList> alist;
5678                 if (in) {
5679                         alist = tmp->audio_region()->fade_in();
5680                 } else {
5681                         alist = tmp->audio_region()->fade_out();
5682                 }
5683
5684                 XMLNode &before = alist->get_state();
5685
5686                 if (in) {
5687                         tmp->audio_region()->set_fade_in_length (len);
5688                         tmp->audio_region()->set_fade_in_active (true);
5689                 } else {
5690                         tmp->audio_region()->set_fade_out_length (len);
5691                         tmp->audio_region()->set_fade_out_active (true);
5692                 }
5693
5694                 XMLNode &after = alist->get_state();
5695                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5696         }
5697
5698         commit_reversible_command ();
5699 }
5700
5701 void
5702 Editor::set_fade_in_shape (FadeShape shape)
5703 {
5704         RegionSelection rs = get_regions_from_selection_and_entered ();
5705
5706         if (rs.empty()) {
5707                 return;
5708         }
5709
5710         begin_reversible_command (_("set fade in shape"));
5711
5712         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5713                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5714
5715                 if (!tmp) {
5716                         return;
5717                 }
5718
5719                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5720                 XMLNode &before = alist->get_state();
5721
5722                 tmp->audio_region()->set_fade_in_shape (shape);
5723
5724                 XMLNode &after = alist->get_state();
5725                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5726         }
5727
5728         commit_reversible_command ();
5729
5730 }
5731
5732 void
5733 Editor::set_fade_out_shape (FadeShape shape)
5734 {
5735         RegionSelection rs = get_regions_from_selection_and_entered ();
5736
5737         if (rs.empty()) {
5738                 return;
5739         }
5740
5741         begin_reversible_command (_("set fade out shape"));
5742
5743         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5744                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5745
5746                 if (!tmp) {
5747                         return;
5748                 }
5749
5750                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5751                 XMLNode &before = alist->get_state();
5752
5753                 tmp->audio_region()->set_fade_out_shape (shape);
5754
5755                 XMLNode &after = alist->get_state();
5756                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5757         }
5758
5759         commit_reversible_command ();
5760 }
5761
5762 void
5763 Editor::set_fade_in_active (bool yn)
5764 {
5765         RegionSelection rs = get_regions_from_selection_and_entered ();
5766
5767         if (rs.empty()) {
5768                 return;
5769         }
5770
5771         begin_reversible_command (_("set fade in active"));
5772
5773         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5774                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5775
5776                 if (!tmp) {
5777                         return;
5778                 }
5779
5780
5781                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5782
5783                 ar->clear_changes ();
5784                 ar->set_fade_in_active (yn);
5785                 _session->add_command (new StatefulDiffCommand (ar));
5786         }
5787
5788         commit_reversible_command ();
5789 }
5790
5791 void
5792 Editor::set_fade_out_active (bool yn)
5793 {
5794         RegionSelection rs = get_regions_from_selection_and_entered ();
5795
5796         if (rs.empty()) {
5797                 return;
5798         }
5799
5800         begin_reversible_command (_("set fade out active"));
5801
5802         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5803                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5804
5805                 if (!tmp) {
5806                         return;
5807                 }
5808
5809                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5810
5811                 ar->clear_changes ();
5812                 ar->set_fade_out_active (yn);
5813                 _session->add_command(new StatefulDiffCommand (ar));
5814         }
5815
5816         commit_reversible_command ();
5817 }
5818
5819 void
5820 Editor::toggle_region_fades (int dir)
5821 {
5822         if (_ignore_region_action) {
5823                 return;
5824         }
5825         
5826         boost::shared_ptr<AudioRegion> ar;
5827         bool yn = false;
5828
5829         RegionSelection rs = get_regions_from_selection_and_entered ();
5830
5831         if (rs.empty()) {
5832                 return;
5833         }
5834
5835         RegionSelection::iterator i;
5836         for (i = rs.begin(); i != rs.end(); ++i) {
5837                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5838                         if (dir == -1) {
5839                                 yn = ar->fade_out_active ();
5840                         } else {
5841                                 yn = ar->fade_in_active ();
5842                         }
5843                         break;
5844                 }
5845         }
5846
5847         if (i == rs.end()) {
5848                 return;
5849         }
5850
5851         /* XXX should this undo-able? */
5852
5853         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5854                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5855                         continue;
5856                 }
5857                 if (dir == 1 || dir == 0) {
5858                         ar->set_fade_in_active (!yn);
5859                 }
5860
5861                 if (dir == -1 || dir == 0) {
5862                         ar->set_fade_out_active (!yn);
5863                 }
5864         }
5865 }
5866
5867
5868 /** Update region fade visibility after its configuration has been changed */
5869 void
5870 Editor::update_region_fade_visibility ()
5871 {
5872         bool _fade_visibility = _session->config.get_show_region_fades ();
5873
5874         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5875                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5876                 if (v) {
5877                         if (_fade_visibility) {
5878                                 v->audio_view()->show_all_fades ();
5879                         } else {
5880                                 v->audio_view()->hide_all_fades ();
5881                         }
5882                 }
5883         }
5884 }
5885
5886 void
5887 Editor::set_edit_point ()
5888 {
5889         framepos_t where;
5890         bool ignored;
5891
5892         if (!mouse_frame (where, ignored)) {
5893                 return;
5894         }
5895
5896         snap_to (where);
5897
5898         if (selection->markers.empty()) {
5899
5900                 mouse_add_new_marker (where);
5901
5902         } else {
5903                 bool ignored;
5904
5905                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5906
5907                 if (loc) {
5908                         loc->move_to (where);
5909                 }
5910         }
5911 }
5912
5913 void
5914 Editor::set_playhead_cursor ()
5915 {
5916         if (entered_marker) {
5917                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5918         } else {
5919                 framepos_t where;
5920                 bool ignored;
5921
5922                 if (!mouse_frame (where, ignored)) {
5923                         return;
5924                 }
5925
5926                 snap_to (where);
5927
5928                 if (_session) {
5929                         _session->request_locate (where, _session->transport_rolling());
5930                 }
5931         }
5932
5933         if (ARDOUR_UI::config()->get_follow_edits()) {
5934                 cancel_time_selection();
5935         }
5936 }
5937
5938 void
5939 Editor::split_region ()
5940 {
5941         //if a range is selected, separate it
5942         if ( !selection->time.empty()) {
5943                 separate_regions_between (selection->time);
5944                 return;
5945         }
5946
5947         //if no range was selected, try to find some regions to split
5948         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
5949         
5950                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
5951
5952                 framepos_t where = get_preferred_edit_position ();
5953
5954                 if (rs.empty()) {
5955                         return;
5956                 }
5957
5958                 split_regions_at (where, rs);
5959         }
5960 }
5961
5962 struct EditorOrderRouteSorter {
5963     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5964             return a->order_key () < b->order_key ();
5965     }
5966 };
5967
5968 void
5969 Editor::select_next_route()
5970 {
5971         if (selection->tracks.empty()) {
5972                 selection->set (track_views.front());
5973                 return;
5974         }
5975
5976         TimeAxisView* current = selection->tracks.front();
5977
5978         RouteUI *rui;
5979         do {
5980                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5981                         if (*i == current) {
5982                                 ++i;
5983                                 if (i != track_views.end()) {
5984                                         current = (*i);
5985                                 } else {
5986                                         current = (*(track_views.begin()));
5987                                         //selection->set (*(track_views.begin()));
5988                                 }
5989                                 break;
5990                         }
5991                 }
5992                 rui = dynamic_cast<RouteUI *>(current);
5993         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5994
5995         selection->set(current);
5996
5997         ensure_time_axis_view_is_visible (*current, false);
5998 }
5999
6000 void
6001 Editor::select_prev_route()
6002 {
6003         if (selection->tracks.empty()) {
6004                 selection->set (track_views.front());
6005                 return;
6006         }
6007
6008         TimeAxisView* current = selection->tracks.front();
6009
6010         RouteUI *rui;
6011         do {
6012                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6013                         if (*i == current) {
6014                                 ++i;
6015                                 if (i != track_views.rend()) {
6016                                         current = (*i);
6017                                 } else {
6018                                         current = *(track_views.rbegin());
6019                                 }
6020                                 break;
6021                         }
6022                 }
6023                 rui = dynamic_cast<RouteUI *>(current);
6024         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6025
6026         selection->set (current);
6027
6028         ensure_time_axis_view_is_visible (*current, false);
6029 }
6030
6031 void
6032 Editor::set_loop_from_selection (bool play)
6033 {
6034         if (_session == 0) {
6035                 return;
6036         }
6037
6038         framepos_t start, end;
6039         if (!get_selection_extents ( start, end))
6040                 return;
6041
6042         set_loop_range (start, end,  _("set loop range from selection"));
6043
6044         if (play) {
6045                 _session->request_play_loop (true, true);
6046         }
6047 }
6048
6049 void
6050 Editor::set_loop_from_region (bool play)
6051 {
6052         framepos_t start, end;
6053         if (!get_selection_extents ( start, end))
6054                 return;
6055
6056         set_loop_range (start, end, _("set loop range from region"));
6057
6058         if (play) {
6059                 _session->request_locate (start, true);
6060                 _session->request_play_loop (true);
6061         }
6062 }
6063
6064 void
6065 Editor::set_punch_from_selection ()
6066 {
6067         if (_session == 0) {
6068                 return;
6069         }
6070
6071         framepos_t start, end;
6072         if (!get_selection_extents ( start, end))
6073                 return;
6074
6075         set_punch_range (start, end,  _("set punch range from selection"));
6076 }
6077
6078 void
6079 Editor::set_session_extents_from_selection ()
6080 {
6081         if (_session == 0) {
6082                 return;
6083         }
6084         
6085         framepos_t start, end;
6086         if (!get_selection_extents ( start, end))
6087                 return;
6088
6089         Location* loc;
6090         if ((loc = _session->locations()->session_range_location()) == 0) {
6091                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
6092         } else {
6093                 XMLNode &before = loc->get_state();
6094
6095                 _session->set_session_extents ( start, end );
6096
6097                 XMLNode &after = loc->get_state();
6098
6099                 begin_reversible_command (_("set session start/end from selection"));
6100
6101                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6102
6103                 commit_reversible_command ();
6104         }
6105 }
6106
6107 void
6108 Editor::set_punch_from_region ()
6109 {
6110         framepos_t start, end;
6111         if (!get_selection_extents ( start, end))
6112                 return;
6113
6114         set_punch_range (start, end, _("set punch range from region"));
6115 }
6116
6117 void
6118 Editor::pitch_shift_region ()
6119 {
6120         RegionSelection rs = get_regions_from_selection_and_entered ();
6121
6122         RegionSelection audio_rs;
6123         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6124                 if (dynamic_cast<AudioRegionView*> (*i)) {
6125                         audio_rs.push_back (*i);
6126                 }
6127         }
6128
6129         if (audio_rs.empty()) {
6130                 return;
6131         }
6132
6133         pitch_shift (audio_rs, 1.2);
6134 }
6135
6136 void
6137 Editor::transpose_region ()
6138 {
6139         RegionSelection rs = get_regions_from_selection_and_entered ();
6140
6141         list<MidiRegionView*> midi_region_views;
6142         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6143                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6144                 if (mrv) {
6145                         midi_region_views.push_back (mrv);
6146                 }
6147         }
6148
6149         TransposeDialog d;
6150         int const r = d.run ();
6151         if (r != RESPONSE_ACCEPT) {
6152                 return;
6153         }
6154
6155         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6156                 (*i)->midi_region()->transpose (d.semitones ());
6157         }
6158 }
6159
6160 void
6161 Editor::set_tempo_from_region ()
6162 {
6163         RegionSelection rs = get_regions_from_selection_and_entered ();
6164
6165         if (!_session || rs.empty()) {
6166                 return;
6167         }
6168
6169         RegionView* rv = rs.front();
6170
6171         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6172 }
6173
6174 void
6175 Editor::use_range_as_bar ()
6176 {
6177         framepos_t start, end;
6178         if (get_edit_op_range (start, end)) {
6179                 define_one_bar (start, end);
6180         }
6181 }
6182
6183 void
6184 Editor::define_one_bar (framepos_t start, framepos_t end)
6185 {
6186         framepos_t length = end - start;
6187
6188         const Meter& m (_session->tempo_map().meter_at (start));
6189
6190         /* length = 1 bar */
6191
6192         /* now we want frames per beat.
6193            we have frames per bar, and beats per bar, so ...
6194         */
6195
6196         /* XXXX METER MATH */
6197
6198         double frames_per_beat = length / m.divisions_per_bar();
6199
6200         /* beats per minute = */
6201
6202         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6203
6204         /* now decide whether to:
6205
6206             (a) set global tempo
6207             (b) add a new tempo marker
6208
6209         */
6210
6211         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6212
6213         bool do_global = false;
6214
6215         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6216
6217                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6218                    at the start, or create a new marker
6219                 */
6220
6221                 vector<string> options;
6222                 options.push_back (_("Cancel"));
6223                 options.push_back (_("Add new marker"));
6224                 options.push_back (_("Set global tempo"));
6225
6226                 Choice c (
6227                         _("Define one bar"),
6228                         _("Do you want to set the global tempo or add a new tempo marker?"),
6229                         options
6230                         );
6231
6232                 c.set_default_response (2);
6233
6234                 switch (c.run()) {
6235                 case 0:
6236                         return;
6237
6238                 case 2:
6239                         do_global = true;
6240                         break;
6241
6242                 default:
6243                         do_global = false;
6244                 }
6245
6246         } else {
6247
6248                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6249                    if the marker is at the region starter, change it, otherwise add
6250                    a new tempo marker
6251                 */
6252         }
6253
6254         begin_reversible_command (_("set tempo from region"));
6255         XMLNode& before (_session->tempo_map().get_state());
6256
6257         if (do_global) {
6258                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6259         } else if (t.frame() == start) {
6260                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6261         } else {
6262                 Timecode::BBT_Time bbt;
6263                 _session->tempo_map().bbt_time (start, bbt);
6264                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6265         }
6266
6267         XMLNode& after (_session->tempo_map().get_state());
6268
6269         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6270         commit_reversible_command ();
6271 }
6272
6273 void
6274 Editor::split_region_at_transients ()
6275 {
6276         AnalysisFeatureList positions;
6277
6278         RegionSelection rs = get_regions_from_selection_and_entered ();
6279
6280         if (!_session || rs.empty()) {
6281                 return;
6282         }
6283
6284         begin_reversible_command (_("split regions"));
6285         
6286         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6287
6288                 RegionSelection::iterator tmp;
6289
6290                 tmp = i;
6291                 ++tmp;
6292
6293                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6294
6295                 if (ar && (ar->get_transients (positions) == 0)) {
6296                         split_region_at_points ((*i)->region(), positions, true);
6297                         positions.clear ();
6298                 }
6299
6300                 i = tmp;
6301         }
6302         
6303         commit_reversible_command ();
6304
6305 }
6306
6307 void
6308 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6309 {
6310         bool use_rhythmic_rodent = false;
6311
6312         boost::shared_ptr<Playlist> pl = r->playlist();
6313
6314         list<boost::shared_ptr<Region> > new_regions;
6315
6316         if (!pl) {
6317                 return;
6318         }
6319
6320         if (positions.empty()) {
6321                 return;
6322         }
6323
6324
6325         if (positions.size() > 20 && can_ferret) {
6326                 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);
6327                 MessageDialog msg (msgstr,
6328                                    false,
6329                                    Gtk::MESSAGE_INFO,
6330                                    Gtk::BUTTONS_OK_CANCEL);
6331
6332                 if (can_ferret) {
6333                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6334                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6335                 } else {
6336                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6337                 }
6338
6339                 msg.set_title (_("Excessive split?"));
6340                 msg.present ();
6341
6342                 int response = msg.run();
6343                 msg.hide ();
6344
6345                 switch (response) {
6346                 case RESPONSE_OK:
6347                         break;
6348                 case RESPONSE_APPLY:
6349                         use_rhythmic_rodent = true;
6350                         break;
6351                 default:
6352                         return;
6353                 }
6354         }
6355
6356         if (use_rhythmic_rodent) {
6357                 show_rhythm_ferret ();
6358                 return;
6359         }
6360
6361         AnalysisFeatureList::const_iterator x;
6362
6363         pl->clear_changes ();
6364         pl->clear_owned_changes ();
6365
6366         x = positions.begin();
6367
6368         if (x == positions.end()) {
6369                 return;
6370         }
6371
6372         pl->freeze ();
6373         pl->remove_region (r);
6374
6375         framepos_t pos = 0;
6376
6377         while (x != positions.end()) {
6378
6379                 /* deal with positons that are out of scope of present region bounds */
6380                 if (*x <= 0 || *x > r->length()) {
6381                         ++x;
6382                         continue;
6383                 }
6384
6385                 /* file start = original start + how far we from the initial position ?
6386                  */
6387
6388                 framepos_t file_start = r->start() + pos;
6389
6390                 /* length = next position - current position
6391                  */
6392
6393                 framepos_t len = (*x) - pos;
6394
6395                 /* XXX we do we really want to allow even single-sample regions?
6396                    shouldn't we have some kind of lower limit on region size?
6397                 */
6398
6399                 if (len <= 0) {
6400                         break;
6401                 }
6402
6403                 string new_name;
6404
6405                 if (RegionFactory::region_name (new_name, r->name())) {
6406                         break;
6407                 }
6408
6409                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6410
6411                 PropertyList plist;
6412
6413                 plist.add (ARDOUR::Properties::start, file_start);
6414                 plist.add (ARDOUR::Properties::length, len);
6415                 plist.add (ARDOUR::Properties::name, new_name);
6416                 plist.add (ARDOUR::Properties::layer, 0);
6417
6418                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6419                 /* because we set annouce to false, manually add the new region to the
6420                    RegionFactory map
6421                 */
6422                 RegionFactory::map_add (nr);
6423
6424                 pl->add_region (nr, r->position() + pos);
6425
6426                 if (select_new) {
6427                         new_regions.push_front(nr);
6428                 }
6429
6430                 pos += len;
6431                 ++x;
6432         }
6433
6434         string new_name;
6435
6436         RegionFactory::region_name (new_name, r->name());
6437
6438         /* Add the final region */
6439         PropertyList plist;
6440
6441         plist.add (ARDOUR::Properties::start, r->start() + pos);
6442         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6443         plist.add (ARDOUR::Properties::name, new_name);
6444         plist.add (ARDOUR::Properties::layer, 0);
6445
6446         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6447         /* because we set annouce to false, manually add the new region to the
6448            RegionFactory map
6449         */
6450         RegionFactory::map_add (nr);
6451         pl->add_region (nr, r->position() + pos);
6452
6453         if (select_new) {
6454                 new_regions.push_front(nr);
6455         }
6456
6457         pl->thaw ();
6458
6459         /* We might have removed regions, which alters other regions' layering_index,
6460            so we need to do a recursive diff here.
6461         */
6462         vector<Command*> cmds;
6463         pl->rdiff (cmds);
6464         _session->add_commands (cmds);
6465         
6466         _session->add_command (new StatefulDiffCommand (pl));
6467
6468         if (select_new) {
6469
6470                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6471                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6472                 }
6473         }
6474 }
6475
6476 void
6477 Editor::place_transient()
6478 {
6479         if (!_session) {
6480                 return;
6481         }
6482
6483         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6484
6485         if (rs.empty()) {
6486                 return;
6487         }
6488
6489         framepos_t where = get_preferred_edit_position();
6490
6491         begin_reversible_command (_("place transient"));
6492         
6493         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6494                 framepos_t position = (*r)->region()->position();
6495                 (*r)->region()->add_transient(where - position);
6496         }
6497         
6498         commit_reversible_command ();
6499 }
6500
6501 void
6502 Editor::remove_transient(ArdourCanvas::Item* item)
6503 {
6504         if (!_session) {
6505                 return;
6506         }
6507
6508         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6509         assert (_line);
6510
6511         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6512         _arv->remove_transient (*(float*) _line->get_data ("position"));
6513 }
6514
6515 void
6516 Editor::snap_regions_to_grid ()
6517 {
6518         list <boost::shared_ptr<Playlist > > used_playlists;
6519
6520         RegionSelection rs = get_regions_from_selection_and_entered ();
6521
6522         if (!_session || rs.empty()) {
6523                 return;
6524         }
6525
6526         begin_reversible_command (_("snap regions to grid"));
6527         
6528         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6529
6530                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6531
6532                 if (!pl->frozen()) {
6533                         /* we haven't seen this playlist before */
6534
6535                         /* remember used playlists so we can thaw them later */
6536                         used_playlists.push_back(pl);
6537                         pl->freeze();
6538                 }
6539
6540                 framepos_t start_frame = (*r)->region()->first_frame ();
6541                 snap_to (start_frame);
6542                 (*r)->region()->set_position (start_frame);
6543         }
6544
6545         while (used_playlists.size() > 0) {
6546                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6547                 (*i)->thaw();
6548                 used_playlists.pop_front();
6549         }
6550         
6551         commit_reversible_command ();
6552 }
6553
6554 void
6555 Editor::close_region_gaps ()
6556 {
6557         list <boost::shared_ptr<Playlist > > used_playlists;
6558
6559         RegionSelection rs = get_regions_from_selection_and_entered ();
6560
6561         if (!_session || rs.empty()) {
6562                 return;
6563         }
6564
6565         Dialog dialog (_("Close Region Gaps"));
6566
6567         Table table (2, 3);
6568         table.set_spacings (12);
6569         table.set_border_width (12);
6570         Label* l = manage (left_aligned_label (_("Crossfade length")));
6571         table.attach (*l, 0, 1, 0, 1);
6572
6573         SpinButton spin_crossfade (1, 0);
6574         spin_crossfade.set_range (0, 15);
6575         spin_crossfade.set_increments (1, 1);
6576         spin_crossfade.set_value (5);
6577         table.attach (spin_crossfade, 1, 2, 0, 1);
6578
6579         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6580
6581         l = manage (left_aligned_label (_("Pull-back length")));
6582         table.attach (*l, 0, 1, 1, 2);
6583
6584         SpinButton spin_pullback (1, 0);
6585         spin_pullback.set_range (0, 100);
6586         spin_pullback.set_increments (1, 1);
6587         spin_pullback.set_value(30);
6588         table.attach (spin_pullback, 1, 2, 1, 2);
6589
6590         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6591
6592         dialog.get_vbox()->pack_start (table);
6593         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6594         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6595         dialog.show_all ();
6596
6597         if (dialog.run () == RESPONSE_CANCEL) {
6598                 return;
6599         }
6600
6601         framepos_t crossfade_len = spin_crossfade.get_value();
6602         framepos_t pull_back_frames = spin_pullback.get_value();
6603
6604         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6605         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6606
6607         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6608
6609         begin_reversible_command (_("close region gaps"));
6610         
6611         int idx = 0;
6612         boost::shared_ptr<Region> last_region;
6613
6614         rs.sort_by_position_and_track();
6615
6616         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6617
6618                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6619
6620                 if (!pl->frozen()) {
6621                         /* we haven't seen this playlist before */
6622
6623                         /* remember used playlists so we can thaw them later */
6624                         used_playlists.push_back(pl);
6625                         pl->freeze();
6626                 }
6627
6628                 framepos_t position = (*r)->region()->position();
6629
6630                 if (idx == 0 || position < last_region->position()){
6631                         last_region = (*r)->region();
6632                         idx++;
6633                         continue;
6634                 }
6635
6636                 (*r)->region()->trim_front( (position - pull_back_frames));
6637                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6638
6639                 last_region = (*r)->region();
6640
6641                 idx++;
6642         }
6643
6644         while (used_playlists.size() > 0) {
6645                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6646                 (*i)->thaw();
6647                 used_playlists.pop_front();
6648         }
6649         
6650         commit_reversible_command ();
6651 }
6652
6653 void
6654 Editor::tab_to_transient (bool forward)
6655 {
6656         AnalysisFeatureList positions;
6657
6658         RegionSelection rs = get_regions_from_selection_and_entered ();
6659
6660         if (!_session) {
6661                 return;
6662         }
6663
6664         framepos_t pos = _session->audible_frame ();
6665
6666         if (!selection->tracks.empty()) {
6667
6668                 /* don't waste time searching for transients in duplicate playlists.
6669                  */
6670
6671                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6672
6673                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6674
6675                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6676
6677                         if (rtv) {
6678                                 boost::shared_ptr<Track> tr = rtv->track();
6679                                 if (tr) {
6680                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6681                                         if (pl) {
6682                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6683
6684                                                 if (result >= 0) {
6685                                                         positions.push_back (result);
6686                                                 }
6687                                         }
6688                                 }
6689                         }
6690                 }
6691
6692         } else {
6693
6694                 if (rs.empty()) {
6695                         return;
6696                 }
6697
6698                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6699                         (*r)->region()->get_transients (positions);
6700                 }
6701         }
6702
6703         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6704
6705         if (forward) {
6706                 AnalysisFeatureList::iterator x;
6707
6708                 for (x = positions.begin(); x != positions.end(); ++x) {
6709                         if ((*x) > pos) {
6710                                 break;
6711                         }
6712                 }
6713
6714                 if (x != positions.end ()) {
6715                         _session->request_locate (*x);
6716                 }
6717
6718         } else {
6719                 AnalysisFeatureList::reverse_iterator x;
6720
6721                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6722                         if ((*x) < pos) {
6723                                 break;
6724                         }
6725                 }
6726
6727                 if (x != positions.rend ()) {
6728                         _session->request_locate (*x);
6729                 }
6730         }
6731 }
6732
6733 void
6734 Editor::playhead_forward_to_grid ()
6735 {
6736         if (!_session) {
6737                 return;
6738         }
6739         
6740         framepos_t pos = playhead_cursor->current_frame ();
6741         if (pos < max_framepos - 1) {
6742                 pos += 2;
6743                 snap_to_internal (pos, RoundUpAlways, false);
6744                 _session->request_locate (pos);
6745         }
6746 }
6747
6748
6749 void
6750 Editor::playhead_backward_to_grid ()
6751 {
6752         if (!_session) {
6753                 return;
6754         }
6755         
6756         framepos_t pos = playhead_cursor->current_frame ();
6757         if (pos > 2) {
6758                 pos -= 2;
6759                 snap_to_internal (pos, RoundDownAlways, false);
6760                 _session->request_locate (pos);
6761         }
6762 }
6763
6764 void
6765 Editor::set_track_height (Height h)
6766 {
6767         TrackSelection& ts (selection->tracks);
6768
6769         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6770                 (*x)->set_height_enum (h);
6771         }
6772 }
6773
6774 void
6775 Editor::toggle_tracks_active ()
6776 {
6777         TrackSelection& ts (selection->tracks);
6778         bool first = true;
6779         bool target = false;
6780
6781         if (ts.empty()) {
6782                 return;
6783         }
6784
6785         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6786                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6787
6788                 if (rtv) {
6789                         if (first) {
6790                                 target = !rtv->_route->active();
6791                                 first = false;
6792                         }
6793                         rtv->_route->set_active (target, this);
6794                 }
6795         }
6796 }
6797
6798 void
6799 Editor::remove_tracks ()
6800 {
6801         /* this will delete GUI objects that may be the subject of an event
6802            handler in which this method is called. Defer actual deletion to the
6803            next idle callback, when all event handling is finished.
6804         */
6805         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
6806 }
6807
6808 bool
6809 Editor::idle_remove_tracks ()
6810 {
6811         _remove_tracks ();
6812         return false; /* do not call again */
6813 }
6814
6815 void
6816 Editor::_remove_tracks ()
6817 {
6818         TrackSelection& ts (selection->tracks);
6819
6820         if (ts.empty()) {
6821                 return;
6822         }
6823
6824         vector<string> choices;
6825         string prompt;
6826         int ntracks = 0;
6827         int nbusses = 0;
6828         const char* trackstr;
6829         const char* busstr;
6830         vector<boost::shared_ptr<Route> > routes;
6831         bool special_bus = false;
6832
6833         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6834                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6835                 if (!rtv) {
6836                         continue;
6837                 }
6838                 if (rtv->is_track()) {
6839                         ntracks++;
6840                 } else {
6841                         nbusses++;
6842                 }
6843                 routes.push_back (rtv->_route);
6844
6845                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6846                         special_bus = true;
6847                 }
6848         }
6849
6850         if (special_bus && !Config->get_allow_special_bus_removal()) {
6851                 MessageDialog msg (_("That would be bad news ...."),
6852                                    false,
6853                                    Gtk::MESSAGE_INFO,
6854                                    Gtk::BUTTONS_OK);
6855                 msg.set_secondary_text (string_compose (_(
6856                                                                 "Removing the master or monitor bus is such a bad idea\n\
6857 that %1 is not going to allow it.\n\
6858 \n\
6859 If you really want to do this sort of thing\n\
6860 edit your ardour.rc file to set the\n\
6861 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6862
6863                 msg.present ();
6864                 msg.run ();
6865                 return;
6866         }
6867
6868         if (ntracks + nbusses == 0) {
6869                 return;
6870         }
6871
6872         trackstr = P_("track", "tracks", ntracks);
6873         busstr = P_("bus", "busses", nbusses);
6874         
6875         if (ntracks) {
6876                 if (nbusses) {
6877                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6878                                                     "(You may also lose the playlists associated with the %2)\n\n"
6879                                                     "This action cannot be undone, and the session file will be overwritten!"),
6880                                                   ntracks, trackstr, nbusses, busstr);
6881                 } else {
6882                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6883                                                     "(You may also lose the playlists associated with the %2)\n\n"
6884                                                     "This action cannot be undone, and the session file will be overwritten!"),
6885                                                   ntracks, trackstr);
6886                 }
6887         } else if (nbusses) {
6888                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6889                                             "This action cannot be undone, and the session file will be overwritten"),
6890                                           nbusses, busstr);
6891         }
6892
6893         choices.push_back (_("No, do nothing."));
6894         if (ntracks + nbusses > 1) {
6895                 choices.push_back (_("Yes, remove them."));
6896         } else {
6897                 choices.push_back (_("Yes, remove it."));
6898         }
6899
6900         string title;
6901         if (ntracks) {
6902                 title = string_compose (_("Remove %1"), trackstr);
6903         } else {
6904                 title = string_compose (_("Remove %1"), busstr);
6905         }
6906
6907         Choice prompter (title, prompt, choices);
6908
6909         if (prompter.run () != 1) {
6910                 return;
6911         }
6912
6913         {
6914                 Session::StateProtector sp (_session);
6915                 DisplaySuspender ds;
6916                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6917                         _session->remove_route (*x);
6918                 }
6919         }
6920 }
6921
6922 void
6923 Editor::do_insert_time ()
6924 {
6925         if (selection->tracks.empty()) {
6926                 return;
6927         }
6928
6929         InsertTimeDialog d (*this);
6930         int response = d.run ();
6931
6932         if (response != RESPONSE_OK) {
6933                 return;
6934         }
6935
6936         if (d.distance() == 0) {
6937                 return;
6938         }
6939
6940         InsertTimeOption opt = d.intersected_region_action ();
6941
6942         insert_time (
6943                 get_preferred_edit_position(),
6944                 d.distance(),
6945                 opt,
6946                 d.all_playlists(),
6947                 d.move_glued(),
6948                 d.move_markers(),
6949                 d.move_glued_markers(),
6950                 d.move_locked_markers(),
6951                 d.move_tempos()
6952                 );
6953 }
6954
6955 void
6956 Editor::insert_time (
6957         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6958         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6959         )
6960 {
6961         bool commit = false;
6962
6963         if (Config->get_edit_mode() == Lock) {
6964                 return;
6965         }
6966
6967         begin_reversible_command (_("insert time"));
6968
6969         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6970
6971         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6972
6973                 /* regions */
6974
6975                 /* don't operate on any playlist more than once, which could
6976                  * happen if "all playlists" is enabled, but there is more
6977                  * than 1 track using playlists "from" a given track.
6978                  */
6979
6980                 set<boost::shared_ptr<Playlist> > pl;
6981
6982                 if (all_playlists) {
6983                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6984                         if (rtav) {
6985                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6986                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6987                                         pl.insert (*p);
6988                                 }
6989                         }
6990                 } else {
6991                         if ((*x)->playlist ()) {
6992                                 pl.insert ((*x)->playlist ());
6993                         }
6994                 }
6995                 
6996                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6997
6998                         (*i)->clear_changes ();
6999                         (*i)->clear_owned_changes ();
7000
7001                         if (opt == SplitIntersected) {
7002                                 (*i)->split (pos);
7003                         }
7004
7005                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7006
7007                         vector<Command*> cmds;
7008                         (*i)->rdiff (cmds);
7009                         _session->add_commands (cmds);
7010
7011                         _session->add_command (new StatefulDiffCommand (*i));
7012                         commit = true;
7013                 }
7014
7015                 /* automation */
7016                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7017                 if (rtav) {
7018                         rtav->route ()->shift (pos, frames);
7019                         commit = true;
7020                 }
7021         }
7022
7023         /* markers */
7024         if (markers_too) {
7025                 bool moved = false;
7026                 XMLNode& before (_session->locations()->get_state());
7027                 Locations::LocationList copy (_session->locations()->list());
7028
7029                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7030
7031                         Locations::LocationList::const_iterator tmp;
7032
7033                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7034                                 bool const was_locked = (*i)->locked ();
7035                                 if (locked_markers_too) {
7036                                         (*i)->unlock ();
7037                                 }
7038
7039                                 if ((*i)->start() >= pos) {
7040                                         // move end first, in case we're moving by more than the length of the range
7041                                         if (!(*i)->is_mark()) {
7042                                                 (*i)->set_end ((*i)->end() + frames);
7043                                         }
7044                                         (*i)->set_start ((*i)->start() + frames);
7045                                         moved = true;
7046                                 }
7047
7048                                 if (was_locked) {
7049                                         (*i)->lock ();
7050                                 }
7051                         }
7052                 }
7053
7054                 if (moved) {
7055                         XMLNode& after (_session->locations()->get_state());
7056                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7057                 }
7058         }
7059
7060         if (tempo_too) {
7061                 _session->tempo_map().insert_time (pos, frames);
7062         }
7063
7064         if (commit) {
7065                 commit_reversible_command ();
7066         }
7067 }
7068 void
7069 Editor::do_cut_time ()
7070 {
7071         if (selection->tracks.empty()) {
7072                 return;
7073         }
7074
7075         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7076         ArdourDialog d (*this, _("Cut Time"));
7077         VButtonBox button_box;
7078         VBox option_box;
7079
7080         CheckButton glue_button (_("Move Glued Regions"));  glue_button.set_active();
7081         CheckButton marker_button (_("Move Markers"));  marker_button.set_active();
7082         CheckButton tempo_button (_("Move Tempo & Meters"));  tempo_button.set_active();
7083         AudioClock clock ("cutTimeClock", true, "", true, false, true, false);
7084         HBox clock_box;
7085
7086         clock.set (0);
7087         clock.set_session (_session);
7088         clock.set_bbt_reference (pos);
7089
7090         clock_box.pack_start (clock, false, true);
7091
7092         option_box.set_spacing (6);
7093         option_box.pack_start (button_box, false, false);
7094         option_box.pack_start (glue_button, false, false);
7095         option_box.pack_start (marker_button, false, false);
7096         option_box.pack_start (tempo_button, false, false);
7097
7098         d.get_vbox()->set_border_width (12);
7099         d.get_vbox()->pack_start (clock_box, false, false);
7100         d.get_vbox()->pack_start (option_box, false, false);
7101         
7102         option_box.show ();
7103         button_box.show ();
7104         glue_button.show ();
7105         clock.show_all();
7106         clock_box.show ();
7107         marker_button.show ();
7108         tempo_button.show ();
7109
7110         d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
7111         d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
7112         d.show ();
7113
7114         int response = d.run ();
7115
7116         if (response != RESPONSE_OK) {
7117                 return;
7118         }
7119         
7120         framecnt_t distance = clock.current_duration (pos);
7121
7122         if (distance == 0) {
7123                 return;
7124         }
7125
7126         cut_time (pos, distance, SplitIntersected, glue_button.get_active(), marker_button.get_active(), tempo_button.get_active());
7127 }
7128
7129 void
7130 Editor::cut_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, 
7131                      bool ignore_music_glue, bool markers_too, bool tempo_too)
7132 {
7133         bool commit = false;
7134         
7135         if (Config->get_edit_mode() == Lock) {
7136                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7137                 return;
7138         }
7139
7140         begin_reversible_command (_("cut time"));
7141
7142         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7143                 /* regions */
7144                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7145                 
7146                 if (pl) {
7147
7148                         XMLNode &before = pl->get_state();
7149                         
7150                         std::list<AudioRange> rl;
7151                         AudioRange ar(pos, pos+frames, 0);
7152                         rl.push_back(ar);
7153                         pl->cut (rl);
7154                         pl->shift (pos, -frames, true, ignore_music_glue);
7155                         
7156                         XMLNode &after = pl->get_state();
7157                         
7158                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7159                         commit = true;
7160                 }
7161                         
7162                 /* automation */
7163                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7164                 if (rtav) {
7165                         rtav->route ()->shift (pos, -frames);
7166                         commit = true;
7167                 }
7168         }
7169
7170         std::list<Location*> loc_kill_list;
7171         
7172         /* markers */
7173         if (markers_too) {
7174                 bool moved = false;
7175                 XMLNode& before (_session->locations()->get_state());
7176                 Locations::LocationList copy (_session->locations()->list());
7177
7178                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7179                         
7180                         if (!(*i)->is_mark()) {  //range;  have to handle both start and end
7181                                         if ((*i)->end() >= pos
7182                                         && (*i)->end() < pos+frames
7183                                         && (*i)->start() >= pos
7184                                         && (*i)->end() < pos+frames) {  //range is completely enclosed;  kill it
7185                                                 moved = true;
7186                                                 loc_kill_list.push_back(*i);
7187                                         } else {  //ony start or end is included, try to do the right thing
7188                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7189                                                         (*i)->set_end (pos);  //bring the end to the cut
7190                                                         moved = true;
7191                                                 } else if ((*i)->end() >= pos) {
7192                                                         (*i)->set_end ((*i)->end()-frames); //slip the end marker back
7193                                                         moved = true;
7194                                                 }
7195                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7196                                                         (*i)->set_start (pos);  //bring the start marker to the beginning of the cut
7197                                                         moved = true;
7198                                                 } else if ((*i)->start() >= pos) {
7199                                                         (*i)->set_start ((*i)->start() -frames); //slip the end marker back
7200                                                         moved = true;
7201                                                 }
7202                                         }
7203                         } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7204                                 loc_kill_list.push_back(*i);
7205                                 moved = true;
7206                         } else if ((*i)->start() >= pos) {
7207                                 (*i)->set_start ((*i)->start() -frames);
7208                                 moved = true;
7209                         }
7210                 }
7211
7212                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7213                         _session->locations()->remove( *i );
7214                 }
7215         
7216                 if (moved) {
7217                         XMLNode& after (_session->locations()->get_state());
7218                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7219                         commit = true;
7220                 }
7221         }
7222         
7223         if (tempo_too) {
7224                 XMLNode& before (_session->tempo_map().get_state());
7225
7226                 if (_session->tempo_map().cut_time (pos, frames) ) {
7227                         XMLNode& after (_session->tempo_map().get_state());
7228                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7229                         commit = true;
7230                 }
7231         }
7232         
7233         if (commit) {
7234                 commit_reversible_command ();
7235         }
7236 }
7237
7238 void
7239 Editor::fit_selection ()
7240 {
7241         if (!selection->tracks.empty()) {
7242                 fit_tracks (selection->tracks);
7243         } else {
7244                 TrackViewList tvl;
7245
7246                 /* no selected tracks - use tracks with selected regions */
7247
7248                 if (!selection->regions.empty()) {
7249                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7250                                 tvl.push_back (&(*r)->get_time_axis_view ());
7251                         }
7252
7253                         if (!tvl.empty()) {
7254                                 fit_tracks (tvl);
7255                         }
7256                 } else if (internal_editing()) {
7257                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7258                            the entered track
7259                         */
7260                         if (entered_track) {
7261                                 tvl.push_back (entered_track);
7262                                 fit_tracks (tvl);
7263                         }
7264                 }
7265         }
7266
7267 }
7268
7269 void
7270 Editor::fit_tracks (TrackViewList & tracks)
7271 {
7272         if (tracks.empty()) {
7273                 return;
7274         }
7275
7276         uint32_t child_heights = 0;
7277         int visible_tracks = 0;
7278
7279         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7280
7281                 if (!(*t)->marked_for_display()) {
7282                         continue;
7283                 }
7284
7285                 child_heights += (*t)->effective_height() - (*t)->current_height();
7286                 ++visible_tracks;
7287         }
7288
7289         /* compute the per-track height from:
7290
7291            total canvas visible height - 
7292                  height that will be taken by visible children of selected
7293                  tracks - height of the ruler/hscroll area 
7294         */
7295         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7296         double first_y_pos = DBL_MAX;
7297
7298         if (h < TimeAxisView::preset_height (HeightSmall)) {
7299                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7300                 /* too small to be displayed */
7301                 return;
7302         }
7303
7304         undo_visual_stack.push_back (current_visual_state (true));
7305         PBD::Unwinder<bool> nsv (no_save_visual, true);
7306
7307         /* build a list of all tracks, including children */
7308
7309         TrackViewList all;
7310         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7311                 all.push_back (*i);
7312                 TimeAxisView::Children c = (*i)->get_child_list ();
7313                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7314                         all.push_back (j->get());
7315                 }
7316         }
7317
7318
7319         // find selection range.
7320         // if someone knows how to user TrackViewList::iterator for this
7321         // I'm all ears.
7322         int selected_top = -1;
7323         int selected_bottom = -1;
7324         int i = 0;
7325         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7326                 if ((*t)->marked_for_display ()) {
7327                         if (tracks.contains(*t)) {
7328                                 if (selected_top == -1) {
7329                                         selected_top = i;
7330                                 }
7331                                 selected_bottom = i;
7332                         }
7333                 }
7334         }
7335
7336         i = 0;
7337         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7338                 if ((*t)->marked_for_display ()) {
7339                         if (tracks.contains(*t)) {
7340                                 (*t)->set_height (h);
7341                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7342                         } else {
7343                                 if (i > selected_top && i < selected_bottom) {
7344                                         hide_track_in_display (*t);
7345                                 }
7346                         }
7347                 }
7348         }
7349
7350         /*
7351            set the controls_layout height now, because waiting for its size
7352            request signal handler will cause the vertical adjustment setting to fail
7353         */
7354
7355         controls_layout.property_height () = _full_canvas_height;
7356         vertical_adjustment.set_value (first_y_pos);
7357
7358         redo_visual_stack.push_back (current_visual_state (true));
7359
7360         visible_tracks_selector.set_text (_("Sel"));
7361 }
7362
7363 void
7364 Editor::save_visual_state (uint32_t n)
7365 {
7366         while (visual_states.size() <= n) {
7367                 visual_states.push_back (0);
7368         }
7369
7370         if (visual_states[n] != 0) {
7371                 delete visual_states[n];
7372         }
7373
7374         visual_states[n] = current_visual_state (true);
7375         gdk_beep ();
7376 }
7377
7378 void
7379 Editor::goto_visual_state (uint32_t n)
7380 {
7381         if (visual_states.size() <= n) {
7382                 return;
7383         }
7384
7385         if (visual_states[n] == 0) {
7386                 return;
7387         }
7388
7389         use_visual_state (*visual_states[n]);
7390 }
7391
7392 void
7393 Editor::start_visual_state_op (uint32_t n)
7394 {
7395         save_visual_state (n);
7396         
7397         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7398         char buf[32];
7399         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7400         pup->set_text (buf);
7401         pup->touch();
7402 }
7403
7404 void
7405 Editor::cancel_visual_state_op (uint32_t n)
7406 {
7407         goto_visual_state (n);
7408 }
7409
7410 void
7411 Editor::toggle_region_mute ()
7412 {
7413         if (_ignore_region_action) {
7414                 return;
7415         }
7416
7417         RegionSelection rs = get_regions_from_selection_and_entered ();
7418
7419         if (rs.empty ()) {
7420                 return;
7421         }
7422
7423         if (rs.size() > 1) {
7424                 begin_reversible_command (_("mute regions"));
7425         } else {
7426                 begin_reversible_command (_("mute region"));
7427         }
7428
7429         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7430
7431                 (*i)->region()->playlist()->clear_changes ();
7432                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7433                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7434
7435         }
7436
7437         commit_reversible_command ();
7438 }
7439
7440 void
7441 Editor::combine_regions ()
7442 {
7443         /* foreach track with selected regions, take all selected regions
7444            and join them into a new region containing the subregions (as a
7445            playlist)
7446         */
7447
7448         typedef set<RouteTimeAxisView*> RTVS;
7449         RTVS tracks;
7450
7451         if (selection->regions.empty()) {
7452                 return;
7453         }
7454
7455         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7456                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7457
7458                 if (rtv) {
7459                         tracks.insert (rtv);
7460                 }
7461         }
7462
7463         begin_reversible_command (_("combine regions"));
7464
7465         vector<RegionView*> new_selection;
7466
7467         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7468                 RegionView* rv;
7469
7470                 if ((rv = (*i)->combine_regions ()) != 0) {
7471                         new_selection.push_back (rv);
7472                 }
7473         }
7474
7475         selection->clear_regions ();
7476         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7477                 selection->add (*i);
7478         }
7479
7480         commit_reversible_command ();
7481 }
7482
7483 void
7484 Editor::uncombine_regions ()
7485 {
7486         typedef set<RouteTimeAxisView*> RTVS;
7487         RTVS tracks;
7488
7489         if (selection->regions.empty()) {
7490                 return;
7491         }
7492
7493         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7494                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7495
7496                 if (rtv) {
7497                         tracks.insert (rtv);
7498                 }
7499         }
7500
7501         begin_reversible_command (_("uncombine regions"));
7502
7503         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7504                 (*i)->uncombine_regions ();
7505         }
7506
7507         commit_reversible_command ();
7508 }
7509
7510 void
7511 Editor::toggle_midi_input_active (bool flip_others)
7512 {
7513         bool onoff = false;
7514         boost::shared_ptr<RouteList> rl (new RouteList);
7515
7516         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7517                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7518
7519                 if (!rtav) {
7520                         continue;
7521                 }
7522
7523                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7524
7525                 if (mt) {
7526                         rl->push_back (rtav->route());
7527                         onoff = !mt->input_active();
7528                 }
7529         }
7530         
7531         _session->set_exclusive_input_active (rl, onoff, flip_others);
7532 }
7533
7534 void
7535 Editor::lock ()
7536 {
7537         if (!lock_dialog) {
7538                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7539
7540                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7541                 lock_dialog->get_vbox()->pack_start (*padlock);
7542
7543                 ArdourButton* b = manage (new ArdourButton);
7544                 b->set_name ("lock button");
7545                 b->set_text (_("Click to unlock"));
7546                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7547                 lock_dialog->get_vbox()->pack_start (*b);
7548                 
7549                 lock_dialog->get_vbox()->show_all ();
7550                 lock_dialog->set_size_request (200, 200);
7551         }
7552         
7553 #ifdef __APPLE__
7554         /* The global menu bar continues to be accessible to applications
7555            with modal dialogs, which means that we need to desensitize
7556            all items in the menu bar. Since those items are really just
7557            proxies for actions, that means disabling all actions.
7558         */
7559         ActionManager::disable_all_actions ();
7560 #endif
7561         lock_dialog->present ();
7562 }
7563
7564 void
7565 Editor::unlock ()
7566 {
7567         lock_dialog->hide ();
7568         
7569 #ifdef __APPLE__
7570         ActionManager::pop_action_state ();
7571 #endif  
7572
7573         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7574                 start_lock_event_timing ();
7575         }
7576 }
7577
7578 void
7579 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7580 {
7581         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7582 }
7583
7584 void
7585 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7586 {
7587         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7588         Gtkmm2ext::UI::instance()->flush_pending ();
7589 }
7590
7591 void
7592 Editor::bring_all_sources_into_session ()
7593 {
7594         if (!_session) {
7595                 return;
7596         }
7597
7598         Gtk::Label msg;
7599         ArdourDialog w (_("Moving embedded files into session folder"));
7600         w.get_vbox()->pack_start (msg);
7601         w.present ();
7602         
7603         /* flush all pending GUI events because we're about to start copying
7604          * files
7605          */
7606         
7607         Gtkmm2ext::UI::instance()->flush_pending ();
7608
7609         cerr << " Do it\n";
7610
7611         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7612 }