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