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