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