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