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