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