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