Fix "Crop Region to Range" -- second attempt.
[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 pos;
3260         framepos_t new_start;
3261         framepos_t new_end;
3262         framecnt_t new_length;
3263         bool in_command = false;
3264
3265         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3266
3267                 /* Only the top regions at start and end have to be cropped */
3268                 boost::shared_ptr<Region> region_at_start = (*i)->top_region_at(start);
3269                 boost::shared_ptr<Region> region_at_end = (*i)->top_region_at(end);
3270
3271                 vector<boost::shared_ptr<Region> > regions;
3272
3273                 if (region_at_start != 0) {
3274                         regions.push_back (region_at_start);
3275                 }
3276                 if (region_at_end != 0) {
3277                         regions.push_back (region_at_end);
3278                 }
3279
3280                 /* now adjust lengths */
3281                 for (vector<boost::shared_ptr<Region> >::iterator i = regions.begin(); i != regions.end(); ++i) {
3282
3283                         pos = (*i)->position();
3284                         new_start = max (start, pos);
3285                         if (max_framepos - pos > (*i)->length()) {
3286                                 new_end = pos + (*i)->length() - 1;
3287                         } else {
3288                                 new_end = max_framepos;
3289                         }
3290                         new_end = min (end, new_end);
3291                         new_length = new_end - new_start + 1;
3292
3293                         if(!in_command) {
3294                                 begin_reversible_command (_("trim to selection"));
3295                                 in_command = true;
3296                         }
3297                         (*i)->clear_changes ();
3298                         (*i)->trim_to (new_start, new_length);
3299                         _session->add_command (new StatefulDiffCommand (*i));
3300                 }
3301         }
3302
3303         if (in_command) {
3304                 commit_reversible_command ();
3305         }
3306 }
3307
3308 void
3309 Editor::region_fill_track ()
3310 {
3311         boost::shared_ptr<Playlist> playlist;
3312         RegionSelection regions = get_regions_from_selection_and_entered ();
3313         RegionSelection foo;
3314
3315         framepos_t const end = _session->current_end_frame ();
3316
3317         if (regions.empty () || regions.end_frame () + 1 >= end) {
3318                 return;
3319         }
3320
3321         framepos_t const start_frame = regions.start ();
3322         framepos_t const end_frame = regions.end_frame ();
3323         framecnt_t const gap = end_frame - start_frame + 1;
3324
3325         begin_reversible_command (Operations::region_fill);
3326
3327         selection->clear_regions ();
3328
3329         for (RegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3330
3331                 boost::shared_ptr<Region> r ((*i)->region());
3332
3333                 TimeAxisView& tv = (*i)->get_time_axis_view();
3334                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3335                 latest_regionviews.clear ();
3336                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3337
3338                 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
3339                 playlist = (*i)->region()->playlist();
3340                 playlist->clear_changes ();
3341                 playlist->duplicate_until (r, position, gap, end);
3342                 _session->add_command(new StatefulDiffCommand (playlist));
3343
3344                 c.disconnect ();
3345
3346                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3347         }
3348
3349         if (!foo.empty()) {
3350                 selection->set (foo);
3351         }
3352
3353         commit_reversible_command ();
3354 }
3355
3356 void
3357 Editor::region_fill_selection ()
3358 {
3359         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3360                 return;
3361         }
3362
3363         if (selection->time.empty()) {
3364                 return;
3365         }
3366
3367         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3368         if (region == 0) {
3369                 return;
3370         }
3371
3372         framepos_t start = selection->time[clicked_selection].start;
3373         framepos_t end = selection->time[clicked_selection].end;
3374
3375         boost::shared_ptr<Playlist> playlist;
3376
3377         if (selection->tracks.empty()) {
3378                 return;
3379         }
3380
3381         framepos_t selection_length = end - start;
3382         float times = (float)selection_length / region->length();
3383         bool in_command = false;
3384
3385         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3386         RegionSelection foo;
3387
3388         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3389
3390                 if ((playlist = (*i)->playlist()) == 0) {
3391                         continue;
3392                 }
3393
3394                 if (!in_command) {
3395                         begin_reversible_command (Operations::fill_selection);
3396                         in_command = true;
3397                 }
3398                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3399                 latest_regionviews.clear ();
3400                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3401
3402                 playlist->clear_changes ();
3403                 playlist->add_region (RegionFactory::create (region, true), start, times);
3404                 _session->add_command (new StatefulDiffCommand (playlist));
3405                 c.disconnect ();
3406                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3407         }
3408
3409         if (in_command) {
3410                 if (!foo.empty()) {
3411                         selection->set (foo);
3412                 }
3413                 commit_reversible_command ();
3414         }
3415 }
3416
3417 void
3418 Editor::set_region_sync_position ()
3419 {
3420         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3421 }
3422
3423 void
3424 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3425 {
3426         bool in_command = false;
3427
3428         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3429
3430                 if (!(*r)->region()->covers (where)) {
3431                         continue;
3432                 }
3433
3434                 boost::shared_ptr<Region> region ((*r)->region());
3435
3436                 if (!in_command) {
3437                         begin_reversible_command (_("set sync point"));
3438                         in_command = true;
3439                 }
3440
3441                 region->clear_changes ();
3442                 region->set_sync_position (where);
3443                 _session->add_command(new StatefulDiffCommand (region));
3444         }
3445
3446         if (in_command) {
3447                 commit_reversible_command ();
3448         }
3449 }
3450
3451 /** Remove the sync positions of the selection */
3452 void
3453 Editor::remove_region_sync ()
3454 {
3455         RegionSelection rs = get_regions_from_selection_and_entered ();
3456
3457         if (rs.empty()) {
3458                 return;
3459         }
3460
3461         begin_reversible_command (_("remove region sync"));
3462
3463         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3464
3465                 (*i)->region()->clear_changes ();
3466                 (*i)->region()->clear_sync_position ();
3467                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3468         }
3469
3470         commit_reversible_command ();
3471 }
3472
3473 void
3474 Editor::naturalize_region ()
3475 {
3476         RegionSelection rs = get_regions_from_selection_and_entered ();
3477
3478         if (rs.empty()) {
3479                 return;
3480         }
3481
3482         if (rs.size() > 1) {
3483                 begin_reversible_command (_("move regions to original position"));
3484         } else {
3485                 begin_reversible_command (_("move region to original position"));
3486         }
3487
3488         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3489                 (*i)->region()->clear_changes ();
3490                 (*i)->region()->move_to_natural_position ();
3491                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3492         }
3493
3494         commit_reversible_command ();
3495 }
3496
3497 void
3498 Editor::align_regions (RegionPoint what)
3499 {
3500         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3501
3502         if (rs.empty()) {
3503                 return;
3504         }
3505
3506         begin_reversible_command (_("align selection"));
3507
3508         framepos_t const position = get_preferred_edit_position ();
3509
3510         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3511                 align_region_internal ((*i)->region(), what, position);
3512         }
3513
3514         commit_reversible_command ();
3515 }
3516
3517 struct RegionSortByTime {
3518     bool operator() (const RegionView* a, const RegionView* b) {
3519             return a->region()->position() < b->region()->position();
3520     }
3521 };
3522
3523 void
3524 Editor::align_regions_relative (RegionPoint point)
3525 {
3526         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3527
3528         if (rs.empty()) {
3529                 return;
3530         }
3531
3532         framepos_t const position = get_preferred_edit_position ();
3533
3534         framepos_t distance = 0;
3535         framepos_t pos = 0;
3536         int dir = 1;
3537
3538         list<RegionView*> sorted;
3539         rs.by_position (sorted);
3540
3541         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3542
3543         switch (point) {
3544         case Start:
3545                 pos = position;
3546                 if (position > r->position()) {
3547                         distance = position - r->position();
3548                 } else {
3549                         distance = r->position() - position;
3550                         dir = -1;
3551                 }
3552                 break;
3553
3554         case End:
3555                 if (position > r->last_frame()) {
3556                         distance = position - r->last_frame();
3557                         pos = r->position() + distance;
3558                 } else {
3559                         distance = r->last_frame() - position;
3560                         pos = r->position() - distance;
3561                         dir = -1;
3562                 }
3563                 break;
3564
3565         case SyncPoint:
3566                 pos = r->adjust_to_sync (position);
3567                 if (pos > r->position()) {
3568                         distance = pos - r->position();
3569                 } else {
3570                         distance = r->position() - pos;
3571                         dir = -1;
3572                 }
3573                 break;
3574         }
3575
3576         if (pos == r->position()) {
3577                 return;
3578         }
3579
3580         begin_reversible_command (_("align selection (relative)"));
3581
3582         /* move first one specially */
3583
3584         r->clear_changes ();
3585         r->set_position (pos);
3586         _session->add_command(new StatefulDiffCommand (r));
3587
3588         /* move rest by the same amount */
3589
3590         sorted.pop_front();
3591
3592         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3593
3594                 boost::shared_ptr<Region> region ((*i)->region());
3595
3596                 region->clear_changes ();
3597
3598                 if (dir > 0) {
3599                         region->set_position (region->position() + distance);
3600                 } else {
3601                         region->set_position (region->position() - distance);
3602                 }
3603
3604                 _session->add_command(new StatefulDiffCommand (region));
3605
3606         }
3607
3608         commit_reversible_command ();
3609 }
3610
3611 void
3612 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3613 {
3614         begin_reversible_command (_("align region"));
3615         align_region_internal (region, point, position);
3616         commit_reversible_command ();
3617 }
3618
3619 void
3620 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3621 {
3622         region->clear_changes ();
3623
3624         switch (point) {
3625         case SyncPoint:
3626                 region->set_position (region->adjust_to_sync (position));
3627                 break;
3628
3629         case End:
3630                 if (position > region->length()) {
3631                         region->set_position (position - region->length());
3632                 }
3633                 break;
3634
3635         case Start:
3636                 region->set_position (position);
3637                 break;
3638         }
3639
3640         _session->add_command(new StatefulDiffCommand (region));
3641 }
3642
3643 void
3644 Editor::trim_region_front ()
3645 {
3646         trim_region (true);
3647 }
3648
3649 void
3650 Editor::trim_region_back ()
3651 {
3652         trim_region (false);
3653 }
3654
3655 void
3656 Editor::trim_region (bool front)
3657 {
3658         framepos_t where = get_preferred_edit_position();
3659         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3660
3661         if (rs.empty()) {
3662                 return;
3663         }
3664
3665         begin_reversible_command (front ? _("trim front") : _("trim back"));
3666
3667         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3668                 if (!(*i)->region()->locked()) {
3669
3670                         (*i)->region()->clear_changes ();
3671
3672                         if (front) {
3673                                 (*i)->region()->trim_front (where);
3674                                 maybe_locate_with_edit_preroll ( where );
3675                         } else {
3676                                 (*i)->region()->trim_end (where);
3677                                 maybe_locate_with_edit_preroll ( where );
3678                         }
3679
3680                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3681                 }
3682         }
3683
3684         commit_reversible_command ();
3685 }
3686
3687 /** Trim the end of the selected regions to the position of the edit cursor */
3688 void
3689 Editor::trim_region_to_loop ()
3690 {
3691         Location* loc = _session->locations()->auto_loop_location();
3692         if (!loc) {
3693                 return;
3694         }
3695         trim_region_to_location (*loc, _("trim to loop"));
3696 }
3697
3698 void
3699 Editor::trim_region_to_punch ()
3700 {
3701         Location* loc = _session->locations()->auto_punch_location();
3702         if (!loc) {
3703                 return;
3704         }
3705         trim_region_to_location (*loc, _("trim to punch"));
3706 }
3707
3708 void
3709 Editor::trim_region_to_location (const Location& loc, const char* str)
3710 {
3711         RegionSelection rs = get_regions_from_selection_and_entered ();
3712         bool in_command = false;
3713
3714         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3715                 RegionView* rv = (*x);
3716
3717                 /* require region to span proposed trim */
3718                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3719                 case Evoral::OverlapInternal:
3720                         break;
3721                 default:
3722                         continue;
3723                 }
3724
3725                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3726                 if (!tav) {
3727                         return;
3728                 }
3729
3730                 float speed = 1.0;
3731                 framepos_t start;
3732                 framepos_t end;
3733
3734                 if (tav->track() != 0) {
3735                         speed = tav->track()->speed();
3736                 }
3737
3738                 start = session_frame_to_track_frame (loc.start(), speed);
3739                 end = session_frame_to_track_frame (loc.end(), speed);
3740
3741                 rv->region()->clear_changes ();
3742                 rv->region()->trim_to (start, (end - start));
3743
3744                 if (!in_command) {
3745                         begin_reversible_command (str);
3746                         in_command = true;
3747                 }
3748                 _session->add_command(new StatefulDiffCommand (rv->region()));
3749         }
3750
3751         if (in_command) {
3752                 commit_reversible_command ();
3753         }
3754 }
3755
3756 void
3757 Editor::trim_region_to_previous_region_end ()
3758 {
3759         return trim_to_region(false);
3760 }
3761
3762 void
3763 Editor::trim_region_to_next_region_start ()
3764 {
3765         return trim_to_region(true);
3766 }
3767
3768 void
3769 Editor::trim_to_region(bool forward)
3770 {
3771         RegionSelection rs = get_regions_from_selection_and_entered ();
3772         bool in_command = false;
3773
3774         boost::shared_ptr<Region> next_region;
3775
3776         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3777
3778                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3779
3780                 if (!arv) {
3781                         continue;
3782                 }
3783
3784                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3785
3786                 if (!atav) {
3787                         continue;
3788                 }
3789
3790                 float speed = 1.0;
3791
3792                 if (atav->track() != 0) {
3793                         speed = atav->track()->speed();
3794                 }
3795
3796
3797                 boost::shared_ptr<Region> region = arv->region();
3798                 boost::shared_ptr<Playlist> playlist (region->playlist());
3799
3800                 region->clear_changes ();
3801
3802                 if (forward) {
3803
3804                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3805
3806                     if (!next_region) {
3807                         continue;
3808                     }
3809
3810                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3811                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3812                 }
3813                 else {
3814
3815                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3816
3817                     if(!next_region){
3818                         continue;
3819                     }
3820
3821                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3822
3823                     arv->region_changed (ARDOUR::bounds_change);
3824                 }
3825
3826                 if (!in_command) {
3827                         begin_reversible_command (_("trim to region"));
3828                         in_command = true;
3829                 }
3830                 _session->add_command(new StatefulDiffCommand (region));
3831         }
3832
3833         if (in_command) {
3834                 commit_reversible_command ();
3835         }
3836 }
3837
3838 void
3839 Editor::unfreeze_route ()
3840 {
3841         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3842                 return;
3843         }
3844
3845         clicked_routeview->track()->unfreeze ();
3846 }
3847
3848 void*
3849 Editor::_freeze_thread (void* arg)
3850 {
3851         return static_cast<Editor*>(arg)->freeze_thread ();
3852 }
3853
3854 void*
3855 Editor::freeze_thread ()
3856 {
3857         /* create event pool because we may need to talk to the session */
3858         SessionEvent::create_per_thread_pool ("freeze events", 64);
3859         /* create per-thread buffers for process() tree to use */
3860         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3861         current_interthread_info->done = true;
3862         return 0;
3863 }
3864
3865 void
3866 Editor::freeze_route ()
3867 {
3868         if (!_session) {
3869                 return;
3870         }
3871
3872         /* stop transport before we start. this is important */
3873
3874         _session->request_transport_speed (0.0);
3875
3876         /* wait for just a little while, because the above call is asynchronous */
3877
3878         Glib::usleep (250000);
3879
3880         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3881                 return;
3882         }
3883
3884         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3885                 MessageDialog d (
3886                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3887                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3888                         );
3889                 d.set_title (_("Cannot freeze"));
3890                 d.run ();
3891                 return;
3892         }
3893
3894         if (clicked_routeview->track()->has_external_redirects()) {
3895                 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"
3896                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3897                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3898
3899                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3900                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3901                 d.set_title (_("Freeze Limits"));
3902
3903                 int response = d.run ();
3904
3905                 switch (response) {
3906                 case Gtk::RESPONSE_CANCEL:
3907                         return;
3908                 default:
3909                         break;
3910                 }
3911         }
3912
3913         InterThreadInfo itt;
3914         current_interthread_info = &itt;
3915
3916         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3917
3918         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3919
3920         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3921
3922         while (!itt.done && !itt.cancel) {
3923                 gtk_main_iteration ();
3924         }
3925
3926         current_interthread_info = 0;
3927 }
3928
3929 void
3930 Editor::bounce_range_selection (bool replace, bool enable_processing)
3931 {
3932         if (selection->time.empty()) {
3933                 return;
3934         }
3935
3936         TrackSelection views = selection->tracks;
3937
3938         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3939
3940                 if (enable_processing) {
3941
3942                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3943
3944                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3945                                 MessageDialog d (
3946                                         _("You can't perform this operation because the processing of the signal "
3947                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3948                                           "You can do this without processing, which is a different operation.")
3949                                         );
3950                                 d.set_title (_("Cannot bounce"));
3951                                 d.run ();
3952                                 return;
3953                         }
3954                 }
3955         }
3956
3957         framepos_t start = selection->time[clicked_selection].start;
3958         framepos_t end = selection->time[clicked_selection].end;
3959         framepos_t cnt = end - start + 1;
3960         bool in_command = false;
3961
3962         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3963
3964                 RouteTimeAxisView* rtv;
3965
3966                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3967                         continue;
3968                 }
3969
3970                 boost::shared_ptr<Playlist> playlist;
3971
3972                 if ((playlist = rtv->playlist()) == 0) {
3973                         continue;
3974                 }
3975
3976                 InterThreadInfo itt;
3977
3978                 playlist->clear_changes ();
3979                 playlist->clear_owned_changes ();
3980
3981                 boost::shared_ptr<Region> r;
3982
3983                 if (enable_processing) {
3984                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3985                 } else {
3986                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3987                 }
3988
3989                 if (!r) {
3990                         continue;
3991                 }
3992
3993                 if (replace) {
3994                         list<AudioRange> ranges;
3995                         ranges.push_back (AudioRange (start, start+cnt, 0));
3996                         playlist->cut (ranges); // discard result
3997                         playlist->add_region (r, start);
3998                 }
3999
4000                 if (!in_command) {
4001                         begin_reversible_command (_("bounce range"));
4002                         in_command = true;
4003                 }
4004                 vector<Command*> cmds;
4005                 playlist->rdiff (cmds);
4006                 _session->add_commands (cmds);
4007
4008                 _session->add_command (new StatefulDiffCommand (playlist));
4009         }
4010
4011         if (in_command) {
4012                 commit_reversible_command ();
4013         }
4014 }
4015
4016 /** Delete selected regions, automation points or a time range */
4017 void
4018 Editor::delete_ ()
4019 {
4020         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4021         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4022         bool deleted = false;
4023         if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4024                 deleted = current_mixer_strip->delete_processors ();
4025
4026         if (!deleted)
4027                 cut_copy (Delete);
4028 }
4029
4030 /** Cut selected regions, automation points or a time range */
4031 void
4032 Editor::cut ()
4033 {
4034         cut_copy (Cut);
4035 }
4036
4037 /** Copy selected regions, automation points or a time range */
4038 void
4039 Editor::copy ()
4040 {
4041         cut_copy (Copy);
4042 }
4043
4044
4045 /** @return true if a Cut, Copy or Clear is possible */
4046 bool
4047 Editor::can_cut_copy () const
4048 {
4049         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4050                 return true;
4051
4052         return false;
4053 }
4054
4055
4056 /** Cut, copy or clear selected regions, automation points or a time range.
4057  * @param op Operation (Delete, Cut, Copy or Clear)
4058  */
4059 void
4060 Editor::cut_copy (CutCopyOp op)
4061 {
4062         /* only cancel selection if cut/copy is successful.*/
4063
4064         string opname;
4065
4066         switch (op) {
4067         case Delete:
4068                 opname = _("delete");
4069                 break;
4070         case Cut:
4071                 opname = _("cut");
4072                 break;
4073         case Copy:
4074                 opname = _("copy");
4075                 break;
4076         case Clear:
4077                 opname = _("clear");
4078                 break;
4079         }
4080
4081         /* if we're deleting something, and the mouse is still pressed,
4082            the thing we started a drag for will be gone when we release
4083            the mouse button(s). avoid this. see part 2 at the end of
4084            this function.
4085         */
4086
4087         if (op == Delete || op == Cut || op == Clear) {
4088                 if (_drags->active ()) {
4089                         _drags->abort ();
4090                 }
4091         }
4092
4093         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
4094                 cut_buffer->clear ();
4095
4096         if (entered_marker) {
4097
4098                 /* cut/delete op while pointing at a marker */
4099
4100                 bool ignored;
4101                 Location* loc = find_location_from_marker (entered_marker, ignored);
4102
4103                 if (_session && loc) {
4104                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4105                 }
4106
4107                 _drags->abort ();
4108                 return;
4109         }
4110
4111         switch (mouse_mode) {
4112         case MouseDraw:
4113         case MouseContent:
4114                 begin_reversible_command (opname + ' ' + X_("MIDI"));
4115                 cut_copy_midi (op);
4116                 commit_reversible_command ();
4117                 return;
4118         default:
4119                 break;
4120         }
4121
4122         bool did_edit = false;
4123
4124         if (!selection->regions.empty() || !selection->points.empty()) {
4125                 begin_reversible_command (opname + ' ' + _("objects"));
4126                 did_edit = true;
4127
4128                 if (!selection->regions.empty()) {
4129                         cut_copy_regions (op, selection->regions);
4130
4131                         if (op == Cut || op == Delete) {
4132                                 selection->clear_regions ();
4133                         }
4134                 }
4135
4136                 if (!selection->points.empty()) {
4137                         cut_copy_points (op);
4138
4139                         if (op == Cut || op == Delete) {
4140                                 selection->clear_points ();
4141                         }
4142                 }
4143         } else if (selection->time.empty()) {
4144                 framepos_t start, end;
4145                 /* no time selection, see if we can get an edit range
4146                    and use that.
4147                 */
4148                 if (get_edit_op_range (start, end)) {
4149                         selection->set (start, end);
4150                 }
4151         } else if (!selection->time.empty()) {
4152                 begin_reversible_command (opname + ' ' + _("range"));
4153
4154                 did_edit = true;
4155                 cut_copy_ranges (op);
4156
4157                 if (op == Cut || op == Delete) {
4158                         selection->clear_time ();
4159                 }
4160         }
4161
4162         if (did_edit) {
4163                 /* reset repeated paste state */
4164                 paste_count    = 0;
4165                 last_paste_pos = 0;
4166                 commit_reversible_command ();
4167         }
4168
4169         if (op == Delete || op == Cut || op == Clear) {
4170                 _drags->abort ();
4171         }
4172 }
4173
4174 struct AutomationRecord {
4175         AutomationRecord () : state (0) , line(NULL) {}
4176         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4177
4178         XMLNode* state; ///< state before any operation
4179         const AutomationLine* line; ///< line this came from
4180         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4181 };
4182
4183 /** Cut, copy or clear selected automation points.
4184  *  @param op Operation (Cut, Copy or Clear)
4185  */
4186 void
4187 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4188 {
4189         if (selection->points.empty ()) {
4190                 return;
4191         }
4192
4193         /* XXX: not ideal, as there may be more than one track involved in the point selection */
4194         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4195
4196         /* Keep a record of the AutomationLists that we end up using in this operation */
4197         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4198         Lists lists;
4199
4200         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4201         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4202                 const AutomationLine&                   line = (*i)->line();
4203                 const boost::shared_ptr<AutomationList> al   = line.the_list();
4204                 if (lists.find (al) == lists.end ()) {
4205                         /* We haven't seen this list yet, so make a record for it.  This includes
4206                            taking a copy of its current state, in case this is needed for undo later.
4207                         */
4208                         lists[al] = AutomationRecord (&al->get_state (), &line);
4209                 }
4210         }
4211
4212         if (op == Cut || op == Copy) {
4213                 /* This operation will involve putting things in the cut buffer, so create an empty
4214                    ControlList for each of our source lists to put the cut buffer data in.
4215                 */
4216                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4217                         i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4218                 }
4219
4220                 /* Add all selected points to the relevant copy ControlLists */
4221                 framepos_t start = std::numeric_limits<framepos_t>::max();
4222                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4223                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4224                         AutomationList::const_iterator    j  = (*i)->model();
4225
4226                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4227                         if (midi) {
4228                                 /* Update earliest MIDI start time in beats */
4229                                 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4230                         } else {
4231                                 /* Update earliest session start time in frames */
4232                                 start = std::min(start, (*i)->line().session_position(j));
4233                         }
4234                 }
4235
4236                 /* Snap start time backwards, so copy/paste is snap aligned. */
4237                 if (midi) {
4238                         if (earliest == Evoral::Beats::max()) {
4239                                 earliest = Evoral::Beats();  // Weird... don't offset
4240                         }
4241                         earliest.round_down_to_beat();
4242                 } else {
4243                         if (start == std::numeric_limits<double>::max()) {
4244                                 start = 0;  // Weird... don't offset
4245                         }
4246                         snap_to(start, RoundDownMaybe);
4247                 }
4248
4249                 const double line_offset = midi ? earliest.to_double() : start;
4250                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4251                         /* Correct this copy list so that it is relative to the earliest
4252                            start time, so relative ordering between points is preserved
4253                            when copying from several lists and the paste starts at the
4254                            earliest copied piece of data. */
4255                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4256                                 (*j)->when -= line_offset;
4257                         }
4258
4259                         /* And add it to the cut buffer */
4260                         cut_buffer->add (i->second.copy);
4261                 }
4262         }
4263
4264         if (op == Delete || op == Cut) {
4265                 /* This operation needs to remove things from the main AutomationList, so do that now */
4266
4267                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268                         i->first->freeze ();
4269                 }
4270
4271                 /* Remove each selected point from its AutomationList */
4272                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4273                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4274                         al->erase ((*i)->model ());
4275                 }
4276
4277                 /* Thaw the lists and add undo records for them */
4278                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4279                         boost::shared_ptr<AutomationList> al = i->first;
4280                         al->thaw ();
4281                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4282                 }
4283         }
4284 }
4285
4286 /** Cut, copy or clear selected automation points.
4287  * @param op Operation (Cut, Copy or Clear)
4288  */
4289 void
4290 Editor::cut_copy_midi (CutCopyOp op)
4291 {
4292         Evoral::Beats earliest = Evoral::Beats::max();
4293         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4294                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4295                 if (mrv) {
4296                         if (!mrv->selection().empty()) {
4297                                 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4298                         }
4299                         mrv->cut_copy_clear (op);
4300
4301                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4302                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4303                 }
4304         }
4305
4306         if (!selection->points.empty()) {
4307                 cut_copy_points (op, earliest, true);
4308                 if (op == Cut || op == Delete) {
4309                         selection->clear_points ();
4310                 }
4311         }
4312 }
4313
4314 struct lt_playlist {
4315     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4316             return a.playlist < b.playlist;
4317     }
4318 };
4319
4320 struct PlaylistMapping {
4321     TimeAxisView* tv;
4322     boost::shared_ptr<Playlist> pl;
4323
4324     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4325 };
4326
4327 /** Remove `clicked_regionview' */
4328 void
4329 Editor::remove_clicked_region ()
4330 {
4331         if (clicked_routeview == 0 || clicked_regionview == 0) {
4332                 return;
4333         }
4334
4335         begin_reversible_command (_("remove region"));
4336
4337         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4338
4339         playlist->clear_changes ();
4340         playlist->clear_owned_changes ();
4341         playlist->remove_region (clicked_regionview->region());
4342         if (Config->get_edit_mode() == Ripple)
4343                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4344
4345         /* We might have removed regions, which alters other regions' layering_index,
4346            so we need to do a recursive diff here.
4347         */
4348         vector<Command*> cmds;
4349         playlist->rdiff (cmds);
4350         _session->add_commands (cmds);
4351
4352         _session->add_command(new StatefulDiffCommand (playlist));
4353         commit_reversible_command ();
4354 }
4355
4356
4357 /** Remove the selected regions */
4358 void
4359 Editor::remove_selected_regions ()
4360 {
4361         RegionSelection rs = get_regions_from_selection_and_entered ();
4362
4363         if (!_session || rs.empty()) {
4364                 return;
4365         }
4366
4367         list<boost::shared_ptr<Region> > regions_to_remove;
4368
4369         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4370                 // we can't just remove the region(s) in this loop because
4371                 // this removes them from the RegionSelection, and they thus
4372                 // disappear from underneath the iterator, and the ++i above
4373                 // SEGVs in a puzzling fashion.
4374
4375                 // so, first iterate over the regions to be removed from rs and
4376                 // add them to the regions_to_remove list, and then
4377                 // iterate over the list to actually remove them.
4378
4379                 regions_to_remove.push_back ((*i)->region());
4380         }
4381
4382         vector<boost::shared_ptr<Playlist> > playlists;
4383
4384         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4385
4386                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4387
4388                 if (!playlist) {
4389                         // is this check necessary?
4390                         continue;
4391                 }
4392
4393                 /* get_regions_from_selection_and_entered() guarantees that
4394                    the playlists involved are unique, so there is no need
4395                    to check here.
4396                 */
4397
4398                 playlists.push_back (playlist);
4399
4400                 playlist->clear_changes ();
4401                 playlist->clear_owned_changes ();
4402                 playlist->freeze ();
4403                 playlist->remove_region (*rl);
4404                 if (Config->get_edit_mode() == Ripple)
4405                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4406
4407         }
4408
4409         vector<boost::shared_ptr<Playlist> >::iterator pl;
4410         bool in_command = false;
4411
4412         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4413                 (*pl)->thaw ();
4414
4415                 /* We might have removed regions, which alters other regions' layering_index,
4416                    so we need to do a recursive diff here.
4417                 */
4418
4419                 if (!in_command) {
4420                         begin_reversible_command (_("remove region"));
4421                         in_command = true;
4422                 }
4423                 vector<Command*> cmds;
4424                 (*pl)->rdiff (cmds);
4425                 _session->add_commands (cmds);
4426
4427                 _session->add_command(new StatefulDiffCommand (*pl));
4428         }
4429
4430         if (in_command) {
4431                 commit_reversible_command ();
4432         }
4433 }
4434
4435 /** Cut, copy or clear selected regions.
4436  * @param op Operation (Cut, Copy or Clear)
4437  */
4438 void
4439 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4440 {
4441         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4442            a map when we want ordered access to both elements. i think.
4443         */
4444
4445         vector<PlaylistMapping> pmap;
4446
4447         framepos_t first_position = max_framepos;
4448
4449         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4450         FreezeList freezelist;
4451
4452         /* get ordering correct before we cut/copy */
4453
4454         rs.sort_by_position_and_track ();
4455
4456         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4457
4458                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4459
4460                 if (op == Cut || op == Clear || op == Delete) {
4461                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4462
4463                         if (pl) {
4464                                 FreezeList::iterator fl;
4465
4466                                 // only take state if this is a new playlist.
4467                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4468                                         if ((*fl) == pl) {
4469                                                 break;
4470                                         }
4471                                 }
4472
4473                                 if (fl == freezelist.end()) {
4474                                         pl->clear_changes();
4475                                         pl->clear_owned_changes ();
4476                                         pl->freeze ();
4477                                         freezelist.insert (pl);
4478                                 }
4479                         }
4480                 }
4481
4482                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4483                 vector<PlaylistMapping>::iterator z;
4484
4485                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4486                         if ((*z).tv == tv) {
4487                                 break;
4488                         }
4489                 }
4490
4491                 if (z == pmap.end()) {
4492                         pmap.push_back (PlaylistMapping (tv));
4493                 }
4494         }
4495
4496         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4497
4498                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4499
4500                 if (!pl) {
4501                         /* region not yet associated with a playlist (e.g. unfinished
4502                            capture pass.
4503                         */
4504                         ++x;
4505                         continue;
4506                 }
4507
4508                 TimeAxisView& tv = (*x)->get_time_axis_view();
4509                 boost::shared_ptr<Playlist> npl;
4510                 RegionSelection::iterator tmp;
4511
4512                 tmp = x;
4513                 ++tmp;
4514
4515                 if (op != Delete) {
4516
4517                         vector<PlaylistMapping>::iterator z;
4518
4519                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4520                                 if ((*z).tv == &tv) {
4521                                         break;
4522                                 }
4523                         }
4524
4525                         assert (z != pmap.end());
4526
4527                         if (!(*z).pl) {
4528                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4529                                 npl->freeze();
4530                                 (*z).pl = npl;
4531                         } else {
4532                                 npl = (*z).pl;
4533                         }
4534                 }
4535
4536                 boost::shared_ptr<Region> r = (*x)->region();
4537                 boost::shared_ptr<Region> _xx;
4538
4539                 assert (r != 0);
4540
4541                 switch (op) {
4542                 case Delete:
4543                         pl->remove_region (r);
4544                         if (Config->get_edit_mode() == Ripple)
4545                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4546                         break;
4547
4548                 case Cut:
4549                         _xx = RegionFactory::create (r);
4550                         npl->add_region (_xx, r->position() - first_position);
4551                         pl->remove_region (r);
4552                         if (Config->get_edit_mode() == Ripple)
4553                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4554                         break;
4555
4556                 case Copy:
4557                         /* copy region before adding, so we're not putting same object into two different playlists */
4558                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4559                         break;
4560
4561                 case Clear:
4562                         pl->remove_region (r);
4563                         if (Config->get_edit_mode() == Ripple)
4564                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4565                         break;
4566                 }
4567
4568                 x = tmp;
4569         }
4570
4571         if (op != Delete) {
4572
4573                 list<boost::shared_ptr<Playlist> > foo;
4574
4575                 /* the pmap is in the same order as the tracks in which selected regions occured */
4576
4577                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4578                         if ((*i).pl) {
4579                                 (*i).pl->thaw();
4580                                 foo.push_back ((*i).pl);
4581                         }
4582                 }
4583
4584                 if (!foo.empty()) {
4585                         cut_buffer->set (foo);
4586                 }
4587
4588                 if (pmap.empty()) {
4589                         _last_cut_copy_source_track = 0;
4590                 } else {
4591                         _last_cut_copy_source_track = pmap.front().tv;
4592                 }
4593         }
4594
4595         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4596                 (*pl)->thaw ();
4597
4598                 /* We might have removed regions, which alters other regions' layering_index,
4599                    so we need to do a recursive diff here.
4600                 */
4601                 vector<Command*> cmds;
4602                 (*pl)->rdiff (cmds);
4603                 _session->add_commands (cmds);
4604
4605                 _session->add_command (new StatefulDiffCommand (*pl));
4606         }
4607 }
4608
4609 void
4610 Editor::cut_copy_ranges (CutCopyOp op)
4611 {
4612         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4613
4614         /* Sort the track selection now, so that it if is used, the playlists
4615            selected by the calls below to cut_copy_clear are in the order that
4616            their tracks appear in the editor.  This makes things like paste
4617            of ranges work properly.
4618         */
4619
4620         sort_track_selection (ts);
4621
4622         if (ts.empty()) {
4623                 if (!entered_track) {
4624                         return;
4625                 }
4626                 ts.push_back (entered_track);
4627         }
4628
4629         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4630                 (*i)->cut_copy_clear (*selection, op);
4631         }
4632 }
4633
4634 void
4635 Editor::paste (float times, bool from_context)
4636 {
4637         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4638
4639         paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4640 }
4641
4642 void
4643 Editor::mouse_paste ()
4644 {
4645         framepos_t where;
4646         bool ignored;
4647
4648         if (!mouse_frame (where, ignored)) {
4649                 return;
4650         }
4651
4652         snap_to (where);
4653         paste_internal (where, 1);
4654 }
4655
4656 void
4657 Editor::paste_internal (framepos_t position, float times)
4658 {
4659         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4660
4661         if (cut_buffer->empty(internal_editing())) {
4662                 return;
4663         }
4664
4665         if (position == max_framepos) {
4666                 position = get_preferred_edit_position();
4667                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4668         }
4669
4670         if (position == last_paste_pos) {
4671                 /* repeated paste in the same position */
4672                 ++paste_count;
4673         } else {
4674                 /* paste in new location, reset repeated paste state */
4675                 paste_count = 0;
4676                 last_paste_pos = position;
4677         }
4678
4679         /* get everything in the correct order */
4680
4681         TrackViewList ts;
4682         if (!selection->tracks.empty()) {
4683                 /* If there is a track selection, paste into exactly those tracks and
4684                    only those tracks.  This allows the user to be explicit and override
4685                    the below "do the reasonable thing" logic. */
4686                 ts = selection->tracks.filter_to_unique_playlists ();
4687                 sort_track_selection (ts);
4688         } else {
4689                 /* Figure out which track to base the paste at. */
4690                 TimeAxisView* base_track = NULL;
4691                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4692                         /* With the mouse edit point, paste onto the track under the mouse. */
4693                         base_track = entered_track;
4694                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4695                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4696                         base_track = &entered_regionview->get_time_axis_view();
4697                 } else if (_last_cut_copy_source_track) {
4698                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4699                         base_track = _last_cut_copy_source_track;
4700                 } else {
4701                         /* This is "impossible" since we've copied... well, do nothing. */
4702                         return;
4703                 }
4704
4705                 /* Walk up to parent if necessary, so base track is a route. */
4706                 while (base_track->get_parent()) {
4707                         base_track = base_track->get_parent();
4708                 }
4709
4710                 /* Add base track and all tracks below it.  The paste logic will select
4711                    the appropriate object types from the cut buffer in relative order. */
4712                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4713                         if ((*i)->order() >= base_track->order()) {
4714                                 ts.push_back(*i);
4715                         }
4716                 }
4717
4718                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4719                 sort_track_selection (ts);
4720
4721                 /* Add automation children of each track in order, for pasting several lines. */
4722                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4723                         /* Add any automation children for pasting several lines */
4724                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4725                         if (!rtv) {
4726                                 continue;
4727                         }
4728
4729                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4730                         const ATracks& atracks = rtv->automation_tracks();
4731                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4732                                 i = ts.insert(i, a->second.get());
4733                                 ++i;
4734                         }
4735                 }
4736
4737                 /* We now have a list of trackviews starting at base_track, including
4738                    automation children, in the order shown in the editor, e.g. R1,
4739                    R1.A1, R1.A2, R2, R2.A1, ... */
4740         }
4741
4742         begin_reversible_command (Operations::paste);
4743
4744         if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4745             dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4746             /* Only one line copied, and one automation track selected.  Do a
4747                "greedy" paste from one automation type to another. */
4748
4749             PasteContext ctx(paste_count, times, ItemCounts(), true);
4750             ts.front()->paste (position, *cut_buffer, ctx);
4751
4752         } else {
4753
4754                 /* Paste into tracks */
4755
4756                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4757                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4758                         (*i)->paste (position, *cut_buffer, ctx);
4759                 }
4760         }
4761
4762         commit_reversible_command ();
4763 }
4764
4765 void
4766 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4767 {
4768         if (regions.empty ()) {
4769                 return;
4770         }
4771
4772         boost::shared_ptr<Playlist> playlist;
4773         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4774         RegionSelection foo;
4775
4776         framepos_t const start_frame = regions.start ();
4777         framepos_t const end_frame = regions.end_frame ();
4778         framecnt_t const gap = end_frame - start_frame + 1;
4779
4780         begin_reversible_command (Operations::duplicate_region);
4781
4782         selection->clear_regions ();
4783
4784         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4785
4786                 boost::shared_ptr<Region> r ((*i)->region());
4787
4788                 TimeAxisView& tv = (*i)->get_time_axis_view();
4789                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4790                 latest_regionviews.clear ();
4791                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4792
4793                 framepos_t const position = end_frame + (r->first_frame() - start_frame + 1);
4794                 playlist = (*i)->region()->playlist();
4795                 playlist->clear_changes ();
4796                 playlist->duplicate (r, position, gap, times);
4797                 _session->add_command(new StatefulDiffCommand (playlist));
4798
4799                 c.disconnect ();
4800
4801                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4802         }
4803
4804         if (!foo.empty()) {
4805                 selection->set (foo);
4806         }
4807
4808         commit_reversible_command ();
4809 }
4810
4811 void
4812 Editor::duplicate_selection (float times)
4813 {
4814         if (selection->time.empty() || selection->tracks.empty()) {
4815                 return;
4816         }
4817
4818         boost::shared_ptr<Playlist> playlist;
4819         vector<boost::shared_ptr<Region> > new_regions;
4820         vector<boost::shared_ptr<Region> >::iterator ri;
4821
4822         create_region_from_selection (new_regions);
4823
4824         if (new_regions.empty()) {
4825                 return;
4826         }
4827
4828         ri = new_regions.begin();
4829
4830         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4831         bool in_command = false;
4832
4833         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4834                 if ((playlist = (*i)->playlist()) == 0) {
4835                         continue;
4836                 }
4837                 playlist->clear_changes ();
4838                 framepos_t end;
4839                 if (clicked_selection) {
4840                         end = selection->time[clicked_selection].end;
4841                 } else {
4842                         end = selection->time.end_frame();
4843                 }
4844                 playlist->duplicate (*ri, end + 1, times);
4845
4846                 if (!in_command) {
4847                         begin_reversible_command (_("duplicate selection"));
4848                         in_command = true;
4849                 }
4850                 _session->add_command (new StatefulDiffCommand (playlist));
4851
4852                 ++ri;
4853                 if (ri == new_regions.end()) {
4854                         --ri;
4855                 }
4856         }
4857
4858         if (in_command) {
4859                 commit_reversible_command ();
4860         }
4861 }
4862
4863 /** Reset all selected points to the relevant default value */
4864 void
4865 Editor::reset_point_selection ()
4866 {
4867         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4868                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4869                 (*j)->value = (*i)->line().the_list()->default_value ();
4870         }
4871 }
4872
4873 void
4874 Editor::center_playhead ()
4875 {
4876         float const page = _visible_canvas_width * samples_per_pixel;
4877         center_screen_internal (playhead_cursor->current_frame (), page);
4878 }
4879
4880 void
4881 Editor::center_edit_point ()
4882 {
4883         float const page = _visible_canvas_width * samples_per_pixel;
4884         center_screen_internal (get_preferred_edit_position(), page);
4885 }
4886
4887 /** Caller must begin and commit a reversible command */
4888 void
4889 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4890 {
4891         playlist->clear_changes ();
4892         playlist->clear ();
4893         _session->add_command (new StatefulDiffCommand (playlist));
4894 }
4895
4896 void
4897 Editor::nudge_track (bool use_edit, bool forwards)
4898 {
4899         boost::shared_ptr<Playlist> playlist;
4900         framepos_t distance;
4901         framepos_t next_distance;
4902         framepos_t start;
4903
4904         if (use_edit) {
4905                 start = get_preferred_edit_position();
4906         } else {
4907                 start = 0;
4908         }
4909
4910         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4911                 return;
4912         }
4913
4914         if (selection->tracks.empty()) {
4915                 return;
4916         }
4917
4918         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4919         bool in_command = false;
4920
4921         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4922
4923                 if ((playlist = (*i)->playlist()) == 0) {
4924                         continue;
4925                 }
4926
4927                 playlist->clear_changes ();
4928                 playlist->clear_owned_changes ();
4929
4930                 playlist->nudge_after (start, distance, forwards);
4931
4932                 if (!in_command) {
4933                         begin_reversible_command (_("nudge track"));
4934                         in_command = true;
4935                 }
4936                 vector<Command*> cmds;
4937
4938                 playlist->rdiff (cmds);
4939                 _session->add_commands (cmds);
4940
4941                 _session->add_command (new StatefulDiffCommand (playlist));
4942         }
4943
4944         if (in_command) {
4945                 commit_reversible_command ();
4946         }
4947 }
4948
4949 void
4950 Editor::remove_last_capture ()
4951 {
4952         vector<string> choices;
4953         string prompt;
4954
4955         if (!_session) {
4956                 return;
4957         }
4958
4959         if (Config->get_verify_remove_last_capture()) {
4960                 prompt  = _("Do you really want to destroy the last capture?"
4961                             "\n(This is destructive and cannot be undone)");
4962
4963                 choices.push_back (_("No, do nothing."));
4964                 choices.push_back (_("Yes, destroy it."));
4965
4966                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4967
4968                 if (prompter.run () == 1) {
4969                         _session->remove_last_capture ();
4970                         _regions->redisplay ();
4971                 }
4972
4973         } else {
4974                 _session->remove_last_capture();
4975                 _regions->redisplay ();
4976         }
4977 }
4978
4979 void
4980 Editor::normalize_region ()
4981 {
4982         if (!_session) {
4983                 return;
4984         }
4985
4986         RegionSelection rs = get_regions_from_selection_and_entered ();
4987
4988         if (rs.empty()) {
4989                 return;
4990         }
4991
4992         NormalizeDialog dialog (rs.size() > 1);
4993
4994         if (dialog.run () == RESPONSE_CANCEL) {
4995                 return;
4996         }
4997
4998         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
4999         gdk_flush ();
5000
5001         /* XXX: should really only count audio regions here */
5002         int const regions = rs.size ();
5003
5004         /* Make a list of the selected audio regions' maximum amplitudes, and also
5005            obtain the maximum amplitude of them all.
5006         */
5007         list<double> max_amps;
5008         double max_amp = 0;
5009         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5010                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5011                 if (arv) {
5012                         dialog.descend (1.0 / regions);
5013                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
5014
5015                         if (a == -1) {
5016                                 /* the user cancelled the operation */
5017                                 return;
5018                         }
5019
5020                         max_amps.push_back (a);
5021                         max_amp = max (max_amp, a);
5022                         dialog.ascend ();
5023                 }
5024         }
5025
5026         list<double>::const_iterator a = max_amps.begin ();
5027         bool in_command = false;
5028
5029         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5030                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5031                 if (!arv) {
5032                         continue;
5033                 }
5034
5035                 arv->region()->clear_changes ();
5036
5037                 double const amp = dialog.normalize_individually() ? *a : max_amp;
5038
5039                 arv->audio_region()->normalize (amp, dialog.target ());
5040
5041                 if (!in_command) {
5042                         begin_reversible_command (_("normalize"));
5043                         in_command = true;
5044                 }
5045                 _session->add_command (new StatefulDiffCommand (arv->region()));
5046
5047                 ++a;
5048         }
5049
5050         if (in_command) {
5051                 commit_reversible_command ();
5052         }
5053 }
5054
5055
5056 void
5057 Editor::reset_region_scale_amplitude ()
5058 {
5059         if (!_session) {
5060                 return;
5061         }
5062
5063         RegionSelection rs = get_regions_from_selection_and_entered ();
5064
5065         if (rs.empty()) {
5066                 return;
5067         }
5068
5069         bool in_command = false;
5070
5071         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5072                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5073                 if (!arv)
5074                         continue;
5075                 arv->region()->clear_changes ();
5076                 arv->audio_region()->set_scale_amplitude (1.0f);
5077
5078                 if(!in_command) {
5079                                 begin_reversible_command ("reset gain");
5080                                 in_command = true;
5081                 }
5082                 _session->add_command (new StatefulDiffCommand (arv->region()));
5083         }
5084
5085         if (in_command) {
5086                 commit_reversible_command ();
5087         }
5088 }
5089
5090 void
5091 Editor::adjust_region_gain (bool up)
5092 {
5093         RegionSelection rs = get_regions_from_selection_and_entered ();
5094
5095         if (!_session || rs.empty()) {
5096                 return;
5097         }
5098
5099         bool in_command = false;
5100
5101         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5102                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5103                 if (!arv) {
5104                         continue;
5105                 }
5106
5107                 arv->region()->clear_changes ();
5108
5109                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5110
5111                 if (up) {
5112                         dB += 1;
5113                 } else {
5114                         dB -= 1;
5115                 }
5116
5117                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5118
5119                 if (!in_command) {
5120                                 begin_reversible_command ("adjust region gain");
5121                                 in_command = true;
5122                 }
5123                 _session->add_command (new StatefulDiffCommand (arv->region()));
5124         }
5125
5126         if (in_command) {
5127                 commit_reversible_command ();
5128         }
5129 }
5130
5131
5132 void
5133 Editor::reverse_region ()
5134 {
5135         if (!_session) {
5136                 return;
5137         }
5138
5139         Reverse rev (*_session);
5140         apply_filter (rev, _("reverse regions"));
5141 }
5142
5143 void
5144 Editor::strip_region_silence ()
5145 {
5146         if (!_session) {
5147                 return;
5148         }
5149
5150         RegionSelection rs = get_regions_from_selection_and_entered ();
5151
5152         if (rs.empty()) {
5153                 return;
5154         }
5155
5156         std::list<RegionView*> audio_only;
5157
5158         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5159                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5160                 if (arv) {
5161                         audio_only.push_back (arv);
5162                 }
5163         }
5164
5165         assert (!audio_only.empty());
5166
5167         StripSilenceDialog d (_session, audio_only);
5168         int const r = d.run ();
5169
5170         d.drop_rects ();
5171
5172         if (r == Gtk::RESPONSE_OK) {
5173                 ARDOUR::AudioIntervalMap silences;
5174                 d.silences (silences);
5175                 StripSilence s (*_session, silences, d.fade_length());
5176                 apply_filter (s, _("strip silence"), &d);
5177         }
5178 }
5179
5180 Command*
5181 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5182 {
5183         Evoral::Sequence<Evoral::Beats>::Notes selected;
5184         mrv.selection_as_notelist (selected, true);
5185
5186         vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5187         v.push_back (selected);
5188
5189         framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5190         Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5191
5192         return op (mrv.midi_region()->model(), pos_beats, v);
5193 }
5194
5195 void
5196 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5197 {
5198         if (rs.empty()) {
5199                 return;
5200         }
5201
5202         bool in_command = false;
5203
5204         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5205                 RegionSelection::const_iterator tmp = r;
5206                 ++tmp;
5207
5208                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5209
5210                 if (mrv) {
5211                         Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5212                         if (cmd) {
5213                                 if (!in_command) {
5214                                         begin_reversible_command (op.name ());
5215                                         in_command = true;
5216                                 }
5217                                 (*cmd)();
5218                                 _session->add_command (cmd);
5219                         }
5220                 }
5221
5222                 r = tmp;
5223         }
5224
5225         if (in_command) {
5226                 commit_reversible_command ();
5227         }
5228 }
5229
5230 void
5231 Editor::fork_region ()
5232 {
5233         RegionSelection rs = get_regions_from_selection_and_entered ();
5234
5235         if (rs.empty()) {
5236                 return;
5237         }
5238
5239         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5240         bool in_command = false;
5241
5242         gdk_flush ();
5243
5244         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5245                 RegionSelection::iterator tmp = r;
5246                 ++tmp;
5247
5248                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5249
5250                 if (mrv) {
5251                         try {
5252                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5253                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5254                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5255
5256                                 if (!in_command) {
5257                                         begin_reversible_command (_("Fork Region(s)"));
5258                                         in_command = true;
5259                                 }
5260                                 playlist->clear_changes ();
5261                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5262                                 _session->add_command(new StatefulDiffCommand (playlist));
5263                         } catch (...) {
5264                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5265                         }
5266                 }
5267
5268                 r = tmp;
5269         }
5270
5271         if (in_command) {
5272                 commit_reversible_command ();
5273         }
5274 }
5275
5276 void
5277 Editor::quantize_region ()
5278 {
5279         if (_session) {
5280                 quantize_regions(get_regions_from_selection_and_entered ());
5281         }
5282 }
5283
5284 void
5285 Editor::quantize_regions (const RegionSelection& rs)
5286 {
5287         if (rs.n_midi_regions() == 0) {
5288                 return;
5289         }
5290
5291         if (!quantize_dialog) {
5292                 quantize_dialog = new QuantizeDialog (*this);
5293         }
5294
5295         quantize_dialog->present ();
5296         const int r = quantize_dialog->run ();
5297         quantize_dialog->hide ();
5298
5299         if (r == Gtk::RESPONSE_OK) {
5300                 Quantize quant (quantize_dialog->snap_start(),
5301                                 quantize_dialog->snap_end(),
5302                                 quantize_dialog->start_grid_size(),
5303                                 quantize_dialog->end_grid_size(),
5304                                 quantize_dialog->strength(),
5305                                 quantize_dialog->swing(),
5306                                 quantize_dialog->threshold());
5307
5308                 apply_midi_note_edit_op (quant, rs);
5309         }
5310 }
5311
5312 void
5313 Editor::legatize_region (bool shrink_only)
5314 {
5315         if (_session) {
5316                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5317         }
5318 }
5319
5320 void
5321 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5322 {
5323         if (rs.n_midi_regions() == 0) {
5324                 return;
5325         }
5326
5327         Legatize legatize(shrink_only);
5328         apply_midi_note_edit_op (legatize, rs);
5329 }
5330
5331 void
5332 Editor::transform_region ()
5333 {
5334         if (_session) {
5335                 transform_regions(get_regions_from_selection_and_entered ());
5336         }
5337 }
5338
5339 void
5340 Editor::transform_regions (const RegionSelection& rs)
5341 {
5342         if (rs.n_midi_regions() == 0) {
5343                 return;
5344         }
5345
5346         TransformDialog td;
5347
5348         td.present();
5349         const int r = td.run();
5350         td.hide();
5351
5352         if (r == Gtk::RESPONSE_OK) {
5353                 Transform transform(td.get());
5354                 apply_midi_note_edit_op(transform, rs);
5355         }
5356 }
5357
5358 void
5359 Editor::transpose_region ()
5360 {
5361         if (_session) {
5362                 transpose_regions(get_regions_from_selection_and_entered ());
5363         }
5364 }
5365
5366 void
5367 Editor::transpose_regions (const RegionSelection& rs)
5368 {
5369         if (rs.n_midi_regions() == 0) {
5370                 return;
5371         }
5372
5373         TransposeDialog d;
5374         int const r = d.run ();
5375
5376         if (r == RESPONSE_ACCEPT) {
5377                 Transpose transpose(d.semitones ());
5378                 apply_midi_note_edit_op (transpose, rs);
5379         }
5380 }
5381
5382 void
5383 Editor::insert_patch_change (bool from_context)
5384 {
5385         RegionSelection rs = get_regions_from_selection_and_entered ();
5386
5387         if (rs.empty ()) {
5388                 return;
5389         }
5390
5391         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5392
5393         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5394            there may be more than one, but the PatchChangeDialog can only offer
5395            one set of patch menus.
5396         */
5397         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5398
5399         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5400         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5401
5402         if (d.run() == RESPONSE_CANCEL) {
5403                 return;
5404         }
5405
5406         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5407                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5408                 if (mrv) {
5409                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5410                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5411                         }
5412                 }
5413         }
5414 }
5415
5416 void
5417 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5418 {
5419         RegionSelection rs = get_regions_from_selection_and_entered ();
5420
5421         if (rs.empty()) {
5422                 return;
5423         }
5424
5425         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5426         bool in_command = false;
5427
5428         gdk_flush ();
5429
5430         int n = 0;
5431         int const N = rs.size ();
5432
5433         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5434                 RegionSelection::iterator tmp = r;
5435                 ++tmp;
5436
5437                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5438                 if (arv) {
5439                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5440
5441                         if (progress) {
5442                                 progress->descend (1.0 / N);
5443                         }
5444
5445                         if (arv->audio_region()->apply (filter, progress) == 0) {
5446
5447                                 playlist->clear_changes ();
5448                                 playlist->clear_owned_changes ();
5449
5450                                 if (filter.results.empty ()) {
5451
5452                                         /* no regions returned; remove the old one */
5453                                         playlist->remove_region (arv->region ());
5454
5455                                 } else {
5456
5457                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5458
5459                                         /* first region replaces the old one */
5460                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5461                                         ++res;
5462
5463                                         /* add the rest */
5464                                         while (res != filter.results.end()) {
5465                                                 playlist->add_region (*res, (*res)->position());
5466                                                 ++res;
5467                                         }
5468
5469                                 }
5470                                 /* We might have removed regions, which alters other regions' layering_index,
5471                                    so we need to do a recursive diff here.
5472                                 */
5473
5474                                 if (!in_command) {
5475                                         begin_reversible_command (command);
5476                                         in_command = true;
5477                                 }
5478                                 vector<Command*> cmds;
5479                                 playlist->rdiff (cmds);
5480                                 _session->add_commands (cmds);
5481
5482                                 _session->add_command(new StatefulDiffCommand (playlist));
5483                         }
5484
5485                         if (progress) {
5486                                 progress->ascend ();
5487                         }
5488                 }
5489
5490                 r = tmp;
5491                 ++n;
5492         }
5493
5494         if (in_command) {
5495                 commit_reversible_command ();
5496         }
5497 }
5498
5499 void
5500 Editor::external_edit_region ()
5501 {
5502         /* more to come */
5503 }
5504
5505 void
5506 Editor::reset_region_gain_envelopes ()
5507 {
5508         RegionSelection rs = get_regions_from_selection_and_entered ();
5509
5510         if (!_session || rs.empty()) {
5511                 return;
5512         }
5513
5514         bool in_command = false;
5515
5516         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5517                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5518                 if (arv) {
5519                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5520                         XMLNode& before (alist->get_state());
5521
5522                         arv->audio_region()->set_default_envelope ();
5523
5524                         if (!in_command) {
5525                                 begin_reversible_command (_("reset region gain"));
5526                                 in_command = true;
5527                         }
5528                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5529                 }
5530         }
5531
5532         if (in_command) {
5533                 commit_reversible_command ();
5534         }
5535 }
5536
5537 void
5538 Editor::set_region_gain_visibility (RegionView* rv)
5539 {
5540         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5541         if (arv) {
5542                 arv->update_envelope_visibility();
5543         }
5544 }
5545
5546 void
5547 Editor::set_gain_envelope_visibility ()
5548 {
5549         if (!_session) {
5550                 return;
5551         }
5552
5553         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5554                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5555                 if (v) {
5556                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5557                 }
5558         }
5559 }
5560
5561 void
5562 Editor::toggle_gain_envelope_active ()
5563 {
5564         if (_ignore_region_action) {
5565                 return;
5566         }
5567
5568         RegionSelection rs = get_regions_from_selection_and_entered ();
5569
5570         if (!_session || rs.empty()) {
5571                 return;
5572         }
5573
5574         bool in_command = false;
5575
5576         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5577                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5578                 if (arv) {
5579                         arv->region()->clear_changes ();
5580                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5581
5582                         if (!in_command) {
5583                                 begin_reversible_command (_("region gain envelope active"));
5584                                 in_command = true;
5585                         }
5586                         _session->add_command (new StatefulDiffCommand (arv->region()));
5587                 }
5588         }
5589
5590         if (in_command) {
5591                 commit_reversible_command ();
5592         }
5593 }
5594
5595 void
5596 Editor::toggle_region_lock ()
5597 {
5598         if (_ignore_region_action) {
5599                 return;
5600         }
5601
5602         RegionSelection rs = get_regions_from_selection_and_entered ();
5603
5604         if (!_session || rs.empty()) {
5605                 return;
5606         }
5607
5608         begin_reversible_command (_("toggle region lock"));
5609
5610         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5611                 (*i)->region()->clear_changes ();
5612                 (*i)->region()->set_locked (!(*i)->region()->locked());
5613                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5614         }
5615
5616         commit_reversible_command ();
5617 }
5618
5619 void
5620 Editor::toggle_region_video_lock ()
5621 {
5622         if (_ignore_region_action) {
5623                 return;
5624         }
5625
5626         RegionSelection rs = get_regions_from_selection_and_entered ();
5627
5628         if (!_session || rs.empty()) {
5629                 return;
5630         }
5631
5632         begin_reversible_command (_("Toggle Video Lock"));
5633
5634         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5635                 (*i)->region()->clear_changes ();
5636                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5637                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5638         }
5639
5640         commit_reversible_command ();
5641 }
5642
5643 void
5644 Editor::toggle_region_lock_style ()
5645 {
5646         if (_ignore_region_action) {
5647                 return;
5648         }
5649
5650         RegionSelection rs = get_regions_from_selection_and_entered ();
5651
5652         if (!_session || rs.empty()) {
5653                 return;
5654         }
5655
5656         begin_reversible_command (_("region lock style"));
5657
5658         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5659                 (*i)->region()->clear_changes ();
5660                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5661                 (*i)->region()->set_position_lock_style (ns);
5662                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5663         }
5664
5665         commit_reversible_command ();
5666 }
5667
5668 void
5669 Editor::toggle_opaque_region ()
5670 {
5671         if (_ignore_region_action) {
5672                 return;
5673         }
5674
5675         RegionSelection rs = get_regions_from_selection_and_entered ();
5676
5677         if (!_session || rs.empty()) {
5678                 return;
5679         }
5680
5681         begin_reversible_command (_("change region opacity"));
5682
5683         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5684                 (*i)->region()->clear_changes ();
5685                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5686                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5687         }
5688
5689         commit_reversible_command ();
5690 }
5691
5692 void
5693 Editor::toggle_record_enable ()
5694 {
5695         bool new_state = false;
5696         bool first = true;
5697         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5698                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5699                 if (!rtav)
5700                         continue;
5701                 if (!rtav->is_track())
5702                         continue;
5703
5704                 if (first) {
5705                         new_state = !rtav->track()->record_enabled();
5706                         first = false;
5707                 }
5708
5709                 rtav->track()->set_record_enabled (new_state, this);
5710         }
5711 }
5712
5713 void
5714 Editor::toggle_solo ()
5715 {
5716         bool new_state = false;
5717         bool first = true;
5718         boost::shared_ptr<RouteList> rl (new RouteList);
5719
5720         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5721                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5722
5723                 if (!rtav) {
5724                         continue;
5725                 }
5726
5727                 if (first) {
5728                         new_state = !rtav->route()->soloed ();
5729                         first = false;
5730                 }
5731
5732                 rl->push_back (rtav->route());
5733         }
5734
5735         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5736 }
5737
5738 void
5739 Editor::toggle_mute ()
5740 {
5741         bool new_state = false;
5742         bool first = true;
5743         boost::shared_ptr<RouteList> rl (new RouteList);
5744
5745         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5746                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5747
5748                 if (!rtav) {
5749                         continue;
5750                 }
5751
5752                 if (first) {
5753                         new_state = !rtav->route()->muted();
5754                         first = false;
5755                 }
5756
5757                 rl->push_back (rtav->route());
5758         }
5759
5760         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5761 }
5762
5763 void
5764 Editor::toggle_solo_isolate ()
5765 {
5766 }
5767
5768
5769 void
5770 Editor::fade_range ()
5771 {
5772         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5773
5774         begin_reversible_command (_("fade range"));
5775
5776         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5777                 (*i)->fade_range (selection->time);
5778         }
5779
5780         commit_reversible_command ();
5781 }
5782
5783
5784 void
5785 Editor::set_fade_length (bool in)
5786 {
5787         RegionSelection rs = get_regions_from_selection_and_entered ();
5788
5789         if (rs.empty()) {
5790                 return;
5791         }
5792
5793         /* we need a region to measure the offset from the start */
5794
5795         RegionView* rv = rs.front ();
5796
5797         framepos_t pos = get_preferred_edit_position();
5798         framepos_t len;
5799         char const * cmd;
5800
5801         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5802                 /* edit point is outside the relevant region */
5803                 return;
5804         }
5805
5806         if (in) {
5807                 if (pos <= rv->region()->position()) {
5808                         /* can't do it */
5809                         return;
5810                 }
5811                 len = pos - rv->region()->position();
5812                 cmd = _("set fade in length");
5813         } else {
5814                 if (pos >= rv->region()->last_frame()) {
5815                         /* can't do it */
5816                         return;
5817                 }
5818                 len = rv->region()->last_frame() - pos;
5819                 cmd = _("set fade out length");
5820         }
5821
5822         bool in_command = false;
5823
5824         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5825                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5826
5827                 if (!tmp) {
5828                         continue;
5829                 }
5830
5831                 boost::shared_ptr<AutomationList> alist;
5832                 if (in) {
5833                         alist = tmp->audio_region()->fade_in();
5834                 } else {
5835                         alist = tmp->audio_region()->fade_out();
5836                 }
5837
5838                 XMLNode &before = alist->get_state();
5839
5840                 if (in) {
5841                         tmp->audio_region()->set_fade_in_length (len);
5842                         tmp->audio_region()->set_fade_in_active (true);
5843                 } else {
5844                         tmp->audio_region()->set_fade_out_length (len);
5845                         tmp->audio_region()->set_fade_out_active (true);
5846                 }
5847
5848                 if (!in_command) {
5849                         begin_reversible_command (cmd);
5850                         in_command = true;
5851                 }
5852                 XMLNode &after = alist->get_state();
5853                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5854         }
5855
5856         if (in_command) {
5857                 commit_reversible_command ();
5858         }
5859 }
5860
5861 void
5862 Editor::set_fade_in_shape (FadeShape shape)
5863 {
5864         RegionSelection rs = get_regions_from_selection_and_entered ();
5865
5866         if (rs.empty()) {
5867                 return;
5868         }
5869         bool in_command = false;
5870
5871         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5872                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5873
5874                 if (!tmp) {
5875                         continue;
5876                 }
5877
5878                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5879                 XMLNode &before = alist->get_state();
5880
5881                 tmp->audio_region()->set_fade_in_shape (shape);
5882
5883                 if (!in_command) {
5884                         begin_reversible_command (_("set fade in shape"));
5885                         in_command = true;
5886                 }
5887                 XMLNode &after = alist->get_state();
5888                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5889         }
5890
5891         if (in_command) {
5892                 commit_reversible_command ();
5893         }
5894 }
5895
5896 void
5897 Editor::set_fade_out_shape (FadeShape shape)
5898 {
5899         RegionSelection rs = get_regions_from_selection_and_entered ();
5900
5901         if (rs.empty()) {
5902                 return;
5903         }
5904         bool in_command = false;
5905
5906         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5907                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5908
5909                 if (!tmp) {
5910                         continue;
5911                 }
5912
5913                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5914                 XMLNode &before = alist->get_state();
5915
5916                 tmp->audio_region()->set_fade_out_shape (shape);
5917
5918                 if(!in_command) {
5919                         begin_reversible_command (_("set fade out shape"));
5920                         in_command = true;
5921                 }
5922                 XMLNode &after = alist->get_state();
5923                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5924         }
5925
5926         if (in_command) {
5927                 commit_reversible_command ();
5928         }
5929 }
5930
5931 void
5932 Editor::set_fade_in_active (bool yn)
5933 {
5934         RegionSelection rs = get_regions_from_selection_and_entered ();
5935
5936         if (rs.empty()) {
5937                 return;
5938         }
5939         bool in_command = false;
5940
5941         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5942                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5943
5944                 if (!tmp) {
5945                         continue;
5946                 }
5947
5948
5949                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5950
5951                 ar->clear_changes ();
5952                 ar->set_fade_in_active (yn);
5953
5954                 if (!in_command) {
5955                         begin_reversible_command (_("set fade in active"));
5956                         in_command = true;
5957                 }
5958                 _session->add_command (new StatefulDiffCommand (ar));
5959         }
5960
5961         if (in_command) {
5962                 commit_reversible_command ();
5963         }
5964 }
5965
5966 void
5967 Editor::set_fade_out_active (bool yn)
5968 {
5969         RegionSelection rs = get_regions_from_selection_and_entered ();
5970
5971         if (rs.empty()) {
5972                 return;
5973         }
5974         bool in_command = false;
5975
5976         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5977                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5978
5979                 if (!tmp) {
5980                         continue;
5981                 }
5982
5983                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5984
5985                 ar->clear_changes ();
5986                 ar->set_fade_out_active (yn);
5987
5988                 if (!in_command) {
5989                         begin_reversible_command (_("set fade out active"));
5990                         in_command = true;
5991                 }
5992                 _session->add_command(new StatefulDiffCommand (ar));
5993         }
5994
5995         if (in_command) {
5996                 commit_reversible_command ();
5997         }
5998 }
5999
6000 void
6001 Editor::toggle_region_fades (int dir)
6002 {
6003         if (_ignore_region_action) {
6004                 return;
6005         }
6006
6007         boost::shared_ptr<AudioRegion> ar;
6008         bool yn = false;
6009
6010         RegionSelection rs = get_regions_from_selection_and_entered ();
6011
6012         if (rs.empty()) {
6013                 return;
6014         }
6015
6016         RegionSelection::iterator i;
6017         for (i = rs.begin(); i != rs.end(); ++i) {
6018                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6019                         if (dir == -1) {
6020                                 yn = ar->fade_out_active ();
6021                         } else {
6022                                 yn = ar->fade_in_active ();
6023                         }
6024                         break;
6025                 }
6026         }
6027
6028         if (i == rs.end()) {
6029                 return;
6030         }
6031
6032         /* XXX should this undo-able? */
6033         bool in_command = false;
6034
6035         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6036                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6037                         continue;
6038                 }
6039                 ar->clear_changes ();
6040
6041                 if (dir == 1 || dir == 0) {
6042                         ar->set_fade_in_active (!yn);
6043                 }
6044
6045                 if (dir == -1 || dir == 0) {
6046                         ar->set_fade_out_active (!yn);
6047                 }
6048                 if (!in_command) {
6049                         begin_reversible_command (_("toggle fade active"));
6050                         in_command = true;
6051                 }
6052                 _session->add_command(new StatefulDiffCommand (ar));
6053         }
6054
6055         if (in_command) {
6056                 commit_reversible_command ();
6057         }
6058 }
6059
6060
6061 /** Update region fade visibility after its configuration has been changed */
6062 void
6063 Editor::update_region_fade_visibility ()
6064 {
6065         bool _fade_visibility = _session->config.get_show_region_fades ();
6066
6067         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6068                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6069                 if (v) {
6070                         if (_fade_visibility) {
6071                                 v->audio_view()->show_all_fades ();
6072                         } else {
6073                                 v->audio_view()->hide_all_fades ();
6074                         }
6075                 }
6076         }
6077 }
6078
6079 void
6080 Editor::set_edit_point ()
6081 {
6082         framepos_t where;
6083         bool ignored;
6084
6085         if (!mouse_frame (where, ignored)) {
6086                 return;
6087         }
6088
6089         snap_to (where);
6090
6091         if (selection->markers.empty()) {
6092
6093                 mouse_add_new_marker (where);
6094
6095         } else {
6096                 bool ignored;
6097
6098                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6099
6100                 if (loc) {
6101                         loc->move_to (where);
6102                 }
6103         }
6104 }
6105
6106 void
6107 Editor::set_playhead_cursor ()
6108 {
6109         if (entered_marker) {
6110                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6111         } else {
6112                 framepos_t where;
6113                 bool ignored;
6114
6115                 if (!mouse_frame (where, ignored)) {
6116                         return;
6117                 }
6118
6119                 snap_to (where);
6120
6121                 if (_session) {
6122                         _session->request_locate (where, _session->transport_rolling());
6123                 }
6124         }
6125
6126         if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6127                 cancel_time_selection();
6128         }
6129 }
6130
6131 void
6132 Editor::split_region ()
6133 {
6134         if (_drags->active ()) {
6135                 return;
6136         }
6137
6138         //if a range is selected, separate it
6139         if ( !selection->time.empty()) {
6140                 separate_regions_between (selection->time);
6141                 return;
6142         }
6143
6144         //if no range was selected, try to find some regions to split
6145         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
6146
6147                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6148
6149                 framepos_t where = get_preferred_edit_position ();
6150
6151                 if (rs.empty()) {
6152                         return;
6153                 }
6154
6155                 split_regions_at (where, rs);
6156         }
6157 }
6158
6159 struct EditorOrderRouteSorter {
6160     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6161             return a->order_key () < b->order_key ();
6162     }
6163 };
6164
6165 void
6166 Editor::select_next_route()
6167 {
6168         if (selection->tracks.empty()) {
6169                 selection->set (track_views.front());
6170                 return;
6171         }
6172
6173         TimeAxisView* current = selection->tracks.front();
6174
6175         RouteUI *rui;
6176         do {
6177                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6178                         if (*i == current) {
6179                                 ++i;
6180                                 if (i != track_views.end()) {
6181                                         current = (*i);
6182                                 } else {
6183                                         current = (*(track_views.begin()));
6184                                         //selection->set (*(track_views.begin()));
6185                                 }
6186                                 break;
6187                         }
6188                 }
6189                 rui = dynamic_cast<RouteUI *>(current);
6190         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6191
6192         selection->set(current);
6193
6194         ensure_time_axis_view_is_visible (*current, false);
6195 }
6196
6197 void
6198 Editor::select_prev_route()
6199 {
6200         if (selection->tracks.empty()) {
6201                 selection->set (track_views.front());
6202                 return;
6203         }
6204
6205         TimeAxisView* current = selection->tracks.front();
6206
6207         RouteUI *rui;
6208         do {
6209                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6210                         if (*i == current) {
6211                                 ++i;
6212                                 if (i != track_views.rend()) {
6213                                         current = (*i);
6214                                 } else {
6215                                         current = *(track_views.rbegin());
6216                                 }
6217                                 break;
6218                         }
6219                 }
6220                 rui = dynamic_cast<RouteUI *>(current);
6221         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6222
6223         selection->set (current);
6224
6225         ensure_time_axis_view_is_visible (*current, false);
6226 }
6227
6228 void
6229 Editor::set_loop_from_selection (bool play)
6230 {
6231         if (_session == 0) {
6232                 return;
6233         }
6234
6235         framepos_t start, end;
6236         if (!get_selection_extents ( start, end))
6237                 return;
6238
6239         set_loop_range (start, end,  _("set loop range from selection"));
6240
6241         if (play) {
6242                 _session->request_play_loop (true, true);
6243         }
6244 }
6245
6246 void
6247 Editor::set_loop_from_region (bool play)
6248 {
6249         framepos_t start, end;
6250         if (!get_selection_extents ( start, end))
6251                 return;
6252
6253         set_loop_range (start, end, _("set loop range from region"));
6254
6255         if (play) {
6256                 _session->request_locate (start, true);
6257                 _session->request_play_loop (true);
6258         }
6259 }
6260
6261 void
6262 Editor::set_punch_from_selection ()
6263 {
6264         if (_session == 0) {
6265                 return;
6266         }
6267
6268         framepos_t start, end;
6269         if (!get_selection_extents ( start, end))
6270                 return;
6271
6272         set_punch_range (start, end,  _("set punch range from selection"));
6273 }
6274
6275 void
6276 Editor::set_session_extents_from_selection ()
6277 {
6278         if (_session == 0) {
6279                 return;
6280         }
6281
6282         framepos_t start, end;
6283         if (!get_selection_extents ( start, end))
6284                 return;
6285
6286         Location* loc;
6287         if ((loc = _session->locations()->session_range_location()) == 0) {
6288                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
6289         } else {
6290                 XMLNode &before = loc->get_state();
6291
6292                 _session->set_session_extents ( start, end );
6293
6294                 XMLNode &after = loc->get_state();
6295
6296                 begin_reversible_command (_("set session start/end from selection"));
6297
6298                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6299
6300                 commit_reversible_command ();
6301         }
6302 }
6303
6304 void
6305 Editor::set_punch_start_from_edit_point ()
6306 {
6307         if (_session) {
6308
6309                 framepos_t start = 0;
6310                 framepos_t end = max_framepos;
6311
6312                 //use the existing punch end, if any
6313                 Location* tpl = transport_punch_location();
6314                 if (tpl) {
6315                         end = tpl->end();
6316                 }
6317
6318                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6319                         start = _session->audible_frame();
6320                 } else {
6321                         start = get_preferred_edit_position();
6322                 }
6323
6324                 //snap the selection start/end
6325                 snap_to(start);
6326
6327                 //if there's not already a sensible selection endpoint, go "forever"
6328                 if ( start > end ) {
6329                         end = max_framepos;
6330                 }
6331
6332                 set_punch_range (start, end, _("set punch start from EP"));
6333         }
6334
6335 }
6336
6337 void
6338 Editor::set_punch_end_from_edit_point ()
6339 {
6340         if (_session) {
6341
6342                 framepos_t start = 0;
6343                 framepos_t end = max_framepos;
6344
6345                 //use the existing punch start, if any
6346                 Location* tpl = transport_punch_location();
6347                 if (tpl) {
6348                         start = tpl->start();
6349                 }
6350
6351                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6352                         end = _session->audible_frame();
6353                 } else {
6354                         end = get_preferred_edit_position();
6355                 }
6356
6357                 //snap the selection start/end
6358                 snap_to(end);
6359
6360                 set_punch_range (start, end, _("set punch end from EP"));
6361
6362         }
6363 }
6364
6365 void
6366 Editor::set_loop_start_from_edit_point ()
6367 {
6368         if (_session) {
6369
6370                 framepos_t start = 0;
6371                 framepos_t end = max_framepos;
6372
6373                 //use the existing loop end, if any
6374                 Location* tpl = transport_loop_location();
6375                 if (tpl) {
6376                         end = tpl->end();
6377                 }
6378
6379                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6380                         start = _session->audible_frame();
6381                 } else {
6382                         start = get_preferred_edit_position();
6383                 }
6384
6385                 //snap the selection start/end
6386                 snap_to(start);
6387
6388                 //if there's not already a sensible selection endpoint, go "forever"
6389                 if ( start > end ) {
6390                         end = max_framepos;
6391                 }
6392
6393                 set_loop_range (start, end, _("set loop start from EP"));
6394         }
6395
6396 }
6397
6398 void
6399 Editor::set_loop_end_from_edit_point ()
6400 {
6401         if (_session) {
6402
6403                 framepos_t start = 0;
6404                 framepos_t end = max_framepos;
6405
6406                 //use the existing loop start, if any
6407                 Location* tpl = transport_loop_location();
6408                 if (tpl) {
6409                         start = tpl->start();
6410                 }
6411
6412                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6413                         end = _session->audible_frame();
6414                 } else {
6415                         end = get_preferred_edit_position();
6416                 }
6417
6418                 //snap the selection start/end
6419                 snap_to(end);
6420
6421                 set_loop_range (start, end, _("set loop end from EP"));
6422         }
6423 }
6424
6425 void
6426 Editor::set_punch_from_region ()
6427 {
6428         framepos_t start, end;
6429         if (!get_selection_extents ( start, end))
6430                 return;
6431
6432         set_punch_range (start, end, _("set punch range from region"));
6433 }
6434
6435 void
6436 Editor::pitch_shift_region ()
6437 {
6438         RegionSelection rs = get_regions_from_selection_and_entered ();
6439
6440         RegionSelection audio_rs;
6441         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6442                 if (dynamic_cast<AudioRegionView*> (*i)) {
6443                         audio_rs.push_back (*i);
6444                 }
6445         }
6446
6447         if (audio_rs.empty()) {
6448                 return;
6449         }
6450
6451         pitch_shift (audio_rs, 1.2);
6452 }
6453
6454 void
6455 Editor::set_tempo_from_region ()
6456 {
6457         RegionSelection rs = get_regions_from_selection_and_entered ();
6458
6459         if (!_session || rs.empty()) {
6460                 return;
6461         }
6462
6463         RegionView* rv = rs.front();
6464
6465         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6466 }
6467
6468 void
6469 Editor::use_range_as_bar ()
6470 {
6471         framepos_t start, end;
6472         if (get_edit_op_range (start, end)) {
6473                 define_one_bar (start, end);
6474         }
6475 }
6476
6477 void
6478 Editor::define_one_bar (framepos_t start, framepos_t end)
6479 {
6480         framepos_t length = end - start;
6481
6482         const Meter& m (_session->tempo_map().meter_at (start));
6483
6484         /* length = 1 bar */
6485
6486         /* now we want frames per beat.
6487            we have frames per bar, and beats per bar, so ...
6488         */
6489
6490         /* XXXX METER MATH */
6491
6492         double frames_per_beat = length / m.divisions_per_bar();
6493
6494         /* beats per minute = */
6495
6496         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6497
6498         /* now decide whether to:
6499
6500             (a) set global tempo
6501             (b) add a new tempo marker
6502
6503         */
6504
6505         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6506
6507         bool do_global = false;
6508
6509         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6510
6511                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6512                    at the start, or create a new marker
6513                 */
6514
6515                 vector<string> options;
6516                 options.push_back (_("Cancel"));
6517                 options.push_back (_("Add new marker"));
6518                 options.push_back (_("Set global tempo"));
6519
6520                 Choice c (
6521                         _("Define one bar"),
6522                         _("Do you want to set the global tempo or add a new tempo marker?"),
6523                         options
6524                         );
6525
6526                 c.set_default_response (2);
6527
6528                 switch (c.run()) {
6529                 case 0:
6530                         return;
6531
6532                 case 2:
6533                         do_global = true;
6534                         break;
6535
6536                 default:
6537                         do_global = false;
6538                 }
6539
6540         } else {
6541
6542                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6543                    if the marker is at the region starter, change it, otherwise add
6544                    a new tempo marker
6545                 */
6546         }
6547
6548         begin_reversible_command (_("set tempo from region"));
6549         XMLNode& before (_session->tempo_map().get_state());
6550
6551         if (do_global) {
6552                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6553         } else if (t.frame() == start) {
6554                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6555         } else {
6556                 Timecode::BBT_Time bbt;
6557                 _session->tempo_map().bbt_time (start, bbt);
6558                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6559         }
6560
6561         XMLNode& after (_session->tempo_map().get_state());
6562
6563         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6564         commit_reversible_command ();
6565 }
6566
6567 void
6568 Editor::split_region_at_transients ()
6569 {
6570         AnalysisFeatureList positions;
6571
6572         RegionSelection rs = get_regions_from_selection_and_entered ();
6573
6574         if (!_session || rs.empty()) {
6575                 return;
6576         }
6577
6578         begin_reversible_command (_("split regions"));
6579
6580         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6581
6582                 RegionSelection::iterator tmp;
6583
6584                 tmp = i;
6585                 ++tmp;
6586
6587                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6588
6589                 if (ar && (ar->get_transients (positions) == 0)) {
6590                         split_region_at_points ((*i)->region(), positions, true);
6591                         positions.clear ();
6592                 }
6593
6594                 i = tmp;
6595         }
6596
6597         commit_reversible_command ();
6598
6599 }
6600
6601 void
6602 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6603 {
6604         bool use_rhythmic_rodent = false;
6605
6606         boost::shared_ptr<Playlist> pl = r->playlist();
6607
6608         list<boost::shared_ptr<Region> > new_regions;
6609
6610         if (!pl) {
6611                 return;
6612         }
6613
6614         if (positions.empty()) {
6615                 return;
6616         }
6617
6618
6619         if (positions.size() > 20 && can_ferret) {
6620                 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);
6621                 MessageDialog msg (msgstr,
6622                                    false,
6623                                    Gtk::MESSAGE_INFO,
6624                                    Gtk::BUTTONS_OK_CANCEL);
6625
6626                 if (can_ferret) {
6627                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6628                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6629                 } else {
6630                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6631                 }
6632
6633                 msg.set_title (_("Excessive split?"));
6634                 msg.present ();
6635
6636                 int response = msg.run();
6637                 msg.hide ();
6638
6639                 switch (response) {
6640                 case RESPONSE_OK:
6641                         break;
6642                 case RESPONSE_APPLY:
6643                         use_rhythmic_rodent = true;
6644                         break;
6645                 default:
6646                         return;
6647                 }
6648         }
6649
6650         if (use_rhythmic_rodent) {
6651                 show_rhythm_ferret ();
6652                 return;
6653         }
6654
6655         AnalysisFeatureList::const_iterator x;
6656
6657         pl->clear_changes ();
6658         pl->clear_owned_changes ();
6659
6660         x = positions.begin();
6661
6662         if (x == positions.end()) {
6663                 return;
6664         }
6665
6666         pl->freeze ();
6667         pl->remove_region (r);
6668
6669         framepos_t pos = 0;
6670
6671         while (x != positions.end()) {
6672
6673                 /* deal with positons that are out of scope of present region bounds */
6674                 if (*x <= 0 || *x > r->length()) {
6675                         ++x;
6676                         continue;
6677                 }
6678
6679                 /* file start = original start + how far we from the initial position ?
6680                  */
6681
6682                 framepos_t file_start = r->start() + pos;
6683
6684                 /* length = next position - current position
6685                  */
6686
6687                 framepos_t len = (*x) - pos;
6688
6689                 /* XXX we do we really want to allow even single-sample regions?
6690                    shouldn't we have some kind of lower limit on region size?
6691                 */
6692
6693                 if (len <= 0) {
6694                         break;
6695                 }
6696
6697                 string new_name;
6698
6699                 if (RegionFactory::region_name (new_name, r->name())) {
6700                         break;
6701                 }
6702
6703                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6704
6705                 PropertyList plist;
6706
6707                 plist.add (ARDOUR::Properties::start, file_start);
6708                 plist.add (ARDOUR::Properties::length, len);
6709                 plist.add (ARDOUR::Properties::name, new_name);
6710                 plist.add (ARDOUR::Properties::layer, 0);
6711
6712                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6713                 /* because we set annouce to false, manually add the new region to the
6714                    RegionFactory map
6715                 */
6716                 RegionFactory::map_add (nr);
6717
6718                 pl->add_region (nr, r->position() + pos);
6719
6720                 if (select_new) {
6721                         new_regions.push_front(nr);
6722                 }
6723
6724                 pos += len;
6725                 ++x;
6726         }
6727
6728         string new_name;
6729
6730         RegionFactory::region_name (new_name, r->name());
6731
6732         /* Add the final region */
6733         PropertyList plist;
6734
6735         plist.add (ARDOUR::Properties::start, r->start() + pos);
6736         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6737         plist.add (ARDOUR::Properties::name, new_name);
6738         plist.add (ARDOUR::Properties::layer, 0);
6739
6740         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6741         /* because we set annouce to false, manually add the new region to the
6742            RegionFactory map
6743         */
6744         RegionFactory::map_add (nr);
6745         pl->add_region (nr, r->position() + pos);
6746
6747         if (select_new) {
6748                 new_regions.push_front(nr);
6749         }
6750
6751         pl->thaw ();
6752
6753         /* We might have removed regions, which alters other regions' layering_index,
6754            so we need to do a recursive diff here.
6755         */
6756         vector<Command*> cmds;
6757         pl->rdiff (cmds);
6758         _session->add_commands (cmds);
6759
6760         _session->add_command (new StatefulDiffCommand (pl));
6761
6762         if (select_new) {
6763
6764                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6765                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6766                 }
6767         }
6768 }
6769
6770 void
6771 Editor::place_transient()
6772 {
6773         if (!_session) {
6774                 return;
6775         }
6776
6777         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6778
6779         if (rs.empty()) {
6780                 return;
6781         }
6782
6783         framepos_t where = get_preferred_edit_position();
6784
6785         begin_reversible_command (_("place transient"));
6786
6787         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6788                 framepos_t position = (*r)->region()->position();
6789                 (*r)->region()->add_transient(where - position);
6790         }
6791
6792         commit_reversible_command ();
6793 }
6794
6795 void
6796 Editor::remove_transient(ArdourCanvas::Item* item)
6797 {
6798         if (!_session) {
6799                 return;
6800         }
6801
6802         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6803         assert (_line);
6804
6805         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6806         _arv->remove_transient (*(float*) _line->get_data ("position"));
6807 }
6808
6809 void
6810 Editor::snap_regions_to_grid ()
6811 {
6812         list <boost::shared_ptr<Playlist > > used_playlists;
6813
6814         RegionSelection rs = get_regions_from_selection_and_entered ();
6815
6816         if (!_session || rs.empty()) {
6817                 return;
6818         }
6819
6820         begin_reversible_command (_("snap regions to grid"));
6821
6822         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6823
6824                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6825
6826                 if (!pl->frozen()) {
6827                         /* we haven't seen this playlist before */
6828
6829                         /* remember used playlists so we can thaw them later */
6830                         used_playlists.push_back(pl);
6831                         pl->freeze();
6832                 }
6833
6834                 framepos_t start_frame = (*r)->region()->first_frame ();
6835                 snap_to (start_frame);
6836                 (*r)->region()->set_position (start_frame);
6837         }
6838
6839         while (used_playlists.size() > 0) {
6840                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6841                 (*i)->thaw();
6842                 used_playlists.pop_front();
6843         }
6844
6845         commit_reversible_command ();
6846 }
6847
6848 void
6849 Editor::close_region_gaps ()
6850 {
6851         list <boost::shared_ptr<Playlist > > used_playlists;
6852
6853         RegionSelection rs = get_regions_from_selection_and_entered ();
6854
6855         if (!_session || rs.empty()) {
6856                 return;
6857         }
6858
6859         Dialog dialog (_("Close Region Gaps"));
6860
6861         Table table (2, 3);
6862         table.set_spacings (12);
6863         table.set_border_width (12);
6864         Label* l = manage (left_aligned_label (_("Crossfade length")));
6865         table.attach (*l, 0, 1, 0, 1);
6866
6867         SpinButton spin_crossfade (1, 0);
6868         spin_crossfade.set_range (0, 15);
6869         spin_crossfade.set_increments (1, 1);
6870         spin_crossfade.set_value (5);
6871         table.attach (spin_crossfade, 1, 2, 0, 1);
6872
6873         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6874
6875         l = manage (left_aligned_label (_("Pull-back length")));
6876         table.attach (*l, 0, 1, 1, 2);
6877
6878         SpinButton spin_pullback (1, 0);
6879         spin_pullback.set_range (0, 100);
6880         spin_pullback.set_increments (1, 1);
6881         spin_pullback.set_value(30);
6882         table.attach (spin_pullback, 1, 2, 1, 2);
6883
6884         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6885
6886         dialog.get_vbox()->pack_start (table);
6887         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6888         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6889         dialog.show_all ();
6890
6891         if (dialog.run () == RESPONSE_CANCEL) {
6892                 return;
6893         }
6894
6895         framepos_t crossfade_len = spin_crossfade.get_value();
6896         framepos_t pull_back_frames = spin_pullback.get_value();
6897
6898         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6899         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6900
6901         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6902
6903         begin_reversible_command (_("close region gaps"));
6904
6905         int idx = 0;
6906         boost::shared_ptr<Region> last_region;
6907
6908         rs.sort_by_position_and_track();
6909
6910         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6911
6912                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6913
6914                 if (!pl->frozen()) {
6915                         /* we haven't seen this playlist before */
6916
6917                         /* remember used playlists so we can thaw them later */
6918                         used_playlists.push_back(pl);
6919                         pl->freeze();
6920                 }
6921
6922                 framepos_t position = (*r)->region()->position();
6923
6924                 if (idx == 0 || position < last_region->position()){
6925                         last_region = (*r)->region();
6926                         idx++;
6927                         continue;
6928                 }
6929
6930                 (*r)->region()->trim_front( (position - pull_back_frames));
6931                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6932
6933                 last_region = (*r)->region();
6934
6935                 idx++;
6936         }
6937
6938         while (used_playlists.size() > 0) {
6939                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6940                 (*i)->thaw();
6941                 used_playlists.pop_front();
6942         }
6943
6944         commit_reversible_command ();
6945 }
6946
6947 void
6948 Editor::tab_to_transient (bool forward)
6949 {
6950         AnalysisFeatureList positions;
6951
6952         RegionSelection rs = get_regions_from_selection_and_entered ();
6953
6954         if (!_session) {
6955                 return;
6956         }
6957
6958         framepos_t pos = _session->audible_frame ();
6959
6960         if (!selection->tracks.empty()) {
6961
6962                 /* don't waste time searching for transients in duplicate playlists.
6963                  */
6964
6965                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6966
6967                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6968
6969                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6970
6971                         if (rtv) {
6972                                 boost::shared_ptr<Track> tr = rtv->track();
6973                                 if (tr) {
6974                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6975                                         if (pl) {
6976                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6977
6978                                                 if (result >= 0) {
6979                                                         positions.push_back (result);
6980                                                 }
6981                                         }
6982                                 }
6983                         }
6984                 }
6985
6986         } else {
6987
6988                 if (rs.empty()) {
6989                         return;
6990                 }
6991
6992                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6993                         (*r)->region()->get_transients (positions);
6994                 }
6995         }
6996
6997         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6998
6999         if (forward) {
7000                 AnalysisFeatureList::iterator x;
7001
7002                 for (x = positions.begin(); x != positions.end(); ++x) {
7003                         if ((*x) > pos) {
7004                                 break;
7005                         }
7006                 }
7007
7008                 if (x != positions.end ()) {
7009                         _session->request_locate (*x);
7010                 }
7011
7012         } else {
7013                 AnalysisFeatureList::reverse_iterator x;
7014
7015                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7016                         if ((*x) < pos) {
7017                                 break;
7018                         }
7019                 }
7020
7021                 if (x != positions.rend ()) {
7022                         _session->request_locate (*x);
7023                 }
7024         }
7025 }
7026
7027 void
7028 Editor::playhead_forward_to_grid ()
7029 {
7030         if (!_session) {
7031                 return;
7032         }
7033
7034         framepos_t pos = playhead_cursor->current_frame ();
7035         if (pos < max_framepos - 1) {
7036                 pos += 2;
7037                 snap_to_internal (pos, RoundUpAlways, false);
7038                 _session->request_locate (pos);
7039         }
7040 }
7041
7042
7043 void
7044 Editor::playhead_backward_to_grid ()
7045 {
7046         if (!_session) {
7047                 return;
7048         }
7049
7050         framepos_t pos = playhead_cursor->current_frame ();
7051         if (pos > 2) {
7052                 pos -= 2;
7053                 snap_to_internal (pos, RoundDownAlways, false);
7054                 _session->request_locate (pos);
7055         }
7056 }
7057
7058 void
7059 Editor::set_track_height (Height h)
7060 {
7061         TrackSelection& ts (selection->tracks);
7062
7063         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7064                 (*x)->set_height_enum (h);
7065         }
7066 }
7067
7068 void
7069 Editor::toggle_tracks_active ()
7070 {
7071         TrackSelection& ts (selection->tracks);
7072         bool first = true;
7073         bool target = false;
7074
7075         if (ts.empty()) {
7076                 return;
7077         }
7078
7079         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7080                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7081
7082                 if (rtv) {
7083                         if (first) {
7084                                 target = !rtv->_route->active();
7085                                 first = false;
7086                         }
7087                         rtv->_route->set_active (target, this);
7088                 }
7089         }
7090 }
7091
7092 void
7093 Editor::remove_tracks ()
7094 {
7095         /* this will delete GUI objects that may be the subject of an event
7096            handler in which this method is called. Defer actual deletion to the
7097            next idle callback, when all event handling is finished.
7098         */
7099         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7100 }
7101
7102 bool
7103 Editor::idle_remove_tracks ()
7104 {
7105         _remove_tracks ();
7106         return false; /* do not call again */
7107 }
7108
7109 void
7110 Editor::_remove_tracks ()
7111 {
7112         TrackSelection& ts (selection->tracks);
7113
7114         if (ts.empty()) {
7115                 return;
7116         }
7117
7118         vector<string> choices;
7119         string prompt;
7120         int ntracks = 0;
7121         int nbusses = 0;
7122         const char* trackstr;
7123         const char* busstr;
7124         vector<boost::shared_ptr<Route> > routes;
7125         bool special_bus = false;
7126
7127         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7128                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7129                 if (!rtv) {
7130                         continue;
7131                 }
7132                 if (rtv->is_track()) {
7133                         ntracks++;
7134                 } else {
7135                         nbusses++;
7136                 }
7137                 routes.push_back (rtv->_route);
7138
7139                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7140                         special_bus = true;
7141                 }
7142         }
7143
7144         if (special_bus && !Config->get_allow_special_bus_removal()) {
7145                 MessageDialog msg (_("That would be bad news ...."),
7146                                    false,
7147                                    Gtk::MESSAGE_INFO,
7148                                    Gtk::BUTTONS_OK);
7149                 msg.set_secondary_text (string_compose (_(
7150                                                                 "Removing the master or monitor bus is such a bad idea\n\
7151 that %1 is not going to allow it.\n\
7152 \n\
7153 If you really want to do this sort of thing\n\
7154 edit your ardour.rc file to set the\n\
7155 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7156
7157                 msg.present ();
7158                 msg.run ();
7159                 return;
7160         }
7161
7162         if (ntracks + nbusses == 0) {
7163                 return;
7164         }
7165
7166         trackstr = P_("track", "tracks", ntracks);
7167         busstr = P_("bus", "busses", nbusses);
7168
7169         if (ntracks) {
7170                 if (nbusses) {
7171                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7172                                                     "(You may also lose the playlists associated with the %2)\n\n"
7173                                                     "This action cannot be undone, and the session file will be overwritten!"),
7174                                                   ntracks, trackstr, nbusses, busstr);
7175                 } else {
7176                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
7177                                                     "(You may also lose the playlists associated with the %2)\n\n"
7178                                                     "This action cannot be undone, and the session file will be overwritten!"),
7179                                                   ntracks, trackstr);
7180                 }
7181         } else if (nbusses) {
7182                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
7183                                             "This action cannot be undone, and the session file will be overwritten"),
7184                                           nbusses, busstr);
7185         }
7186
7187         choices.push_back (_("No, do nothing."));
7188         if (ntracks + nbusses > 1) {
7189                 choices.push_back (_("Yes, remove them."));
7190         } else {
7191                 choices.push_back (_("Yes, remove it."));
7192         }
7193
7194         string title;
7195         if (ntracks) {
7196                 title = string_compose (_("Remove %1"), trackstr);
7197         } else {
7198                 title = string_compose (_("Remove %1"), busstr);
7199         }
7200
7201         Choice prompter (title, prompt, choices);
7202
7203         if (prompter.run () != 1) {
7204                 return;
7205         }
7206
7207         {
7208                 Session::StateProtector sp (_session);
7209                 DisplaySuspender ds;
7210                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7211                         _session->remove_route (*x);
7212                 }
7213         }
7214 }
7215
7216 void
7217 Editor::do_insert_time ()
7218 {
7219         if (selection->tracks.empty()) {
7220                 return;
7221         }
7222
7223         InsertRemoveTimeDialog d (*this);
7224         int response = d.run ();
7225
7226         if (response != RESPONSE_OK) {
7227                 return;
7228         }
7229
7230         if (d.distance() == 0) {
7231                 return;
7232         }
7233
7234         InsertTimeOption opt = d.intersected_region_action ();
7235
7236         insert_time (
7237                 get_preferred_edit_position(),
7238                 d.distance(),
7239                 opt,
7240                 d.all_playlists(),
7241                 d.move_glued(),
7242                 d.move_markers(),
7243                 d.move_glued_markers(),
7244                 d.move_locked_markers(),
7245                 d.move_tempos()
7246                 );
7247 }
7248
7249 void
7250 Editor::insert_time (
7251         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7252         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7253         )
7254 {
7255
7256         if (Config->get_edit_mode() == Lock) {
7257                 return;
7258         }
7259         bool in_command = false;
7260
7261         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7262
7263         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7264
7265                 /* regions */
7266
7267                 /* don't operate on any playlist more than once, which could
7268                  * happen if "all playlists" is enabled, but there is more
7269                  * than 1 track using playlists "from" a given track.
7270                  */
7271
7272                 set<boost::shared_ptr<Playlist> > pl;
7273
7274                 if (all_playlists) {
7275                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7276                         if (rtav && rtav->track ()) {
7277                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7278                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7279                                         pl.insert (*p);
7280                                 }
7281                         }
7282                 } else {
7283                         if ((*x)->playlist ()) {
7284                                 pl.insert ((*x)->playlist ());
7285                         }
7286                 }
7287
7288                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7289
7290                         (*i)->clear_changes ();
7291                         (*i)->clear_owned_changes ();
7292
7293                         if (opt == SplitIntersected) {
7294                                 (*i)->split (pos);
7295                         }
7296
7297                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7298
7299                         if (!in_command) {
7300                                 begin_reversible_command (_("insert time"));
7301                                 in_command = true;
7302                         }
7303                         vector<Command*> cmds;
7304                         (*i)->rdiff (cmds);
7305                         _session->add_commands (cmds);
7306
7307                         _session->add_command (new StatefulDiffCommand (*i));
7308                 }
7309
7310                 /* automation */
7311                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7312                 if (rtav) {
7313                         if (!in_command) {
7314                                 begin_reversible_command (_("insert time"));
7315                                 in_command = true;
7316                         }
7317                         rtav->route ()->shift (pos, frames);
7318                 }
7319         }
7320
7321         /* markers */
7322         if (markers_too) {
7323                 bool moved = false;
7324                 XMLNode& before (_session->locations()->get_state());
7325                 Locations::LocationList copy (_session->locations()->list());
7326
7327                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7328
7329                         Locations::LocationList::const_iterator tmp;
7330
7331                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7332                                 bool const was_locked = (*i)->locked ();
7333                                 if (locked_markers_too) {
7334                                         (*i)->unlock ();
7335                                 }
7336
7337                                 if ((*i)->start() >= pos) {
7338                                         // move end first, in case we're moving by more than the length of the range
7339                                         if (!(*i)->is_mark()) {
7340                                                 (*i)->set_end ((*i)->end() + frames);
7341                                         }
7342                                         (*i)->set_start ((*i)->start() + frames);
7343                                         moved = true;
7344                                 }
7345
7346                                 if (was_locked) {
7347                                         (*i)->lock ();
7348                                 }
7349                         }
7350                 }
7351
7352                 if (moved) {
7353                         if (!in_command) {
7354                                 begin_reversible_command (_("insert time"));
7355                                 in_command = true;
7356                         }
7357                         XMLNode& after (_session->locations()->get_state());
7358                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7359                 }
7360         }
7361
7362         if (tempo_too) {
7363                 if (!in_command) {
7364                         begin_reversible_command (_("insert time"));
7365                         in_command = true;
7366                 }
7367                 XMLNode& before (_session->tempo_map().get_state());
7368                 _session->tempo_map().insert_time (pos, frames);
7369                 XMLNode& after (_session->tempo_map().get_state());
7370                 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7371         }
7372
7373         if (in_command) {
7374                 commit_reversible_command ();
7375         }
7376 }
7377
7378 void
7379 Editor::do_remove_time ()
7380 {
7381         if (selection->tracks.empty()) {
7382                 return;
7383         }
7384
7385         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7386         InsertRemoveTimeDialog d (*this, true);
7387
7388         int response = d.run ();
7389
7390         if (response != RESPONSE_OK) {
7391                 return;
7392         }
7393
7394         framecnt_t distance = d.distance();
7395
7396         if (distance == 0) {
7397                 return;
7398         }
7399
7400         remove_time (
7401                 pos,
7402                 distance,
7403                 SplitIntersected,
7404                 d.move_glued(),
7405                 d.move_markers(),
7406                 d.move_glued_markers(),
7407                 d.move_locked_markers(),
7408                 d.move_tempos()
7409         );
7410 }
7411
7412 void
7413 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7414                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7415 {
7416         if (Config->get_edit_mode() == Lock) {
7417                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7418                 return;
7419         }
7420         bool in_command = false;
7421
7422         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7423                 /* regions */
7424                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7425
7426                 if (pl) {
7427
7428                         XMLNode &before = pl->get_state();
7429
7430                         std::list<AudioRange> rl;
7431                         AudioRange ar(pos, pos+frames, 0);
7432                         rl.push_back(ar);
7433                         pl->cut (rl);
7434                         pl->shift (pos, -frames, true, ignore_music_glue);
7435
7436                         if (!in_command) {
7437                                 begin_reversible_command (_("cut time"));
7438                                 in_command = true;
7439                         }
7440                         XMLNode &after = pl->get_state();
7441
7442                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7443                 }
7444
7445                 /* automation */
7446                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7447                 if (rtav) {
7448                         if (!in_command) {
7449                                 begin_reversible_command (_("cut time"));
7450                                 in_command = true;
7451                         }
7452                         rtav->route ()->shift (pos, -frames);
7453                 }
7454         }
7455
7456         std::list<Location*> loc_kill_list;
7457
7458         /* markers */
7459         if (markers_too) {
7460                 bool moved = false;
7461                 XMLNode& before (_session->locations()->get_state());
7462                 Locations::LocationList copy (_session->locations()->list());
7463
7464                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7465                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7466
7467                                 bool const was_locked = (*i)->locked ();
7468                                 if (locked_markers_too) {
7469                                         (*i)->unlock ();
7470                                 }
7471
7472                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7473                                         if ((*i)->end() >= pos
7474                                         && (*i)->end() < pos+frames
7475                                         && (*i)->start() >= pos
7476                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7477                                                 moved = true;
7478                                                 loc_kill_list.push_back(*i);
7479                                         } else {  // only start or end is included, try to do the right thing
7480                                                 // move start before moving end, to avoid trying to move the end to before the start
7481                                                 // if we're removing more time than the length of the range
7482                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7483                                                         // start is within cut
7484                                                         (*i)->set_start (pos);  // bring the start marker to the beginning of the cut
7485                                                         moved = true;
7486                                                 } else if ((*i)->start() >= pos+frames) {
7487                                                         // start (and thus entire range) lies beyond end of cut
7488                                                         (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7489                                                         moved = true;
7490                                                 }
7491                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7492                                                         // end is inside cut
7493                                                         (*i)->set_end (pos);  // bring the end to the cut
7494                                                         moved = true;
7495                                                 } else if ((*i)->end() >= pos+frames) {
7496                                                         // end is beyond end of cut
7497                                                         (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7498                                                         moved = true;
7499                                                 }
7500
7501                                         }
7502                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7503                                         loc_kill_list.push_back(*i);
7504                                         moved = true;
7505                                 } else if ((*i)->start() >= pos) {
7506                                         (*i)->set_start ((*i)->start() -frames);
7507                                         moved = true;
7508                                 }
7509
7510                                 if (was_locked) {
7511                                         (*i)->lock ();
7512                                 }
7513                         }
7514                 }
7515
7516                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7517                         _session->locations()->remove( *i );
7518                 }
7519
7520                 if (moved) {
7521                         if (!in_command) {
7522                                 begin_reversible_command (_("cut time"));
7523                                 in_command = true;
7524                         }
7525                         XMLNode& after (_session->locations()->get_state());
7526                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7527                 }
7528         }
7529
7530         if (tempo_too) {
7531                 XMLNode& before (_session->tempo_map().get_state());
7532
7533                 if (_session->tempo_map().remove_time (pos, frames) ) {
7534                         if (!in_command) {
7535                                 begin_reversible_command (_("remove time"));
7536                                 in_command = true;
7537                         }
7538                         XMLNode& after (_session->tempo_map().get_state());
7539                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7540                 }
7541         }
7542
7543         if (in_command) {
7544                 commit_reversible_command ();
7545         }
7546 }
7547
7548 void
7549 Editor::fit_selection ()
7550 {
7551         if (!selection->tracks.empty()) {
7552                 fit_tracks (selection->tracks);
7553         } else {
7554                 TrackViewList tvl;
7555
7556                 /* no selected tracks - use tracks with selected regions */
7557
7558                 if (!selection->regions.empty()) {
7559                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7560                                 tvl.push_back (&(*r)->get_time_axis_view ());
7561                         }
7562
7563                         if (!tvl.empty()) {
7564                                 fit_tracks (tvl);
7565                         }
7566                 } else if (internal_editing()) {
7567                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7568                            the entered track
7569                         */
7570                         if (entered_track) {
7571                                 tvl.push_back (entered_track);
7572                                 fit_tracks (tvl);
7573                         }
7574                 }
7575         }
7576
7577 }
7578
7579 void
7580 Editor::fit_tracks (TrackViewList & tracks)
7581 {
7582         if (tracks.empty()) {
7583                 return;
7584         }
7585
7586         uint32_t child_heights = 0;
7587         int visible_tracks = 0;
7588
7589         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7590
7591                 if (!(*t)->marked_for_display()) {
7592                         continue;
7593                 }
7594
7595                 child_heights += (*t)->effective_height() - (*t)->current_height();
7596                 ++visible_tracks;
7597         }
7598
7599         /* compute the per-track height from:
7600
7601            total canvas visible height -
7602                  height that will be taken by visible children of selected
7603                  tracks - height of the ruler/hscroll area
7604         */
7605         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7606         double first_y_pos = DBL_MAX;
7607
7608         if (h < TimeAxisView::preset_height (HeightSmall)) {
7609                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7610                 /* too small to be displayed */
7611                 return;
7612         }
7613
7614         undo_visual_stack.push_back (current_visual_state (true));
7615         PBD::Unwinder<bool> nsv (no_save_visual, true);
7616
7617         /* build a list of all tracks, including children */
7618
7619         TrackViewList all;
7620         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7621                 all.push_back (*i);
7622                 TimeAxisView::Children c = (*i)->get_child_list ();
7623                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7624                         all.push_back (j->get());
7625                 }
7626         }
7627
7628
7629         // find selection range.
7630         // if someone knows how to user TrackViewList::iterator for this
7631         // I'm all ears.
7632         int selected_top = -1;
7633         int selected_bottom = -1;
7634         int i = 0;
7635         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7636                 if ((*t)->marked_for_display ()) {
7637                         if (tracks.contains(*t)) {
7638                                 if (selected_top == -1) {
7639                                         selected_top = i;
7640                                 }
7641                                 selected_bottom = i;
7642                         }
7643                 }
7644         }
7645
7646         i = 0;
7647         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7648                 if ((*t)->marked_for_display ()) {
7649                         if (tracks.contains(*t)) {
7650                                 (*t)->set_height (h);
7651                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7652                         } else {
7653                                 if (i > selected_top && i < selected_bottom) {
7654                                         hide_track_in_display (*t);
7655                                 }
7656                         }
7657                 }
7658         }
7659
7660         /*
7661            set the controls_layout height now, because waiting for its size
7662            request signal handler will cause the vertical adjustment setting to fail
7663         */
7664
7665         controls_layout.property_height () = _full_canvas_height;
7666         vertical_adjustment.set_value (first_y_pos);
7667
7668         redo_visual_stack.push_back (current_visual_state (true));
7669
7670         visible_tracks_selector.set_text (_("Sel"));
7671 }
7672
7673 void
7674 Editor::save_visual_state (uint32_t n)
7675 {
7676         while (visual_states.size() <= n) {
7677                 visual_states.push_back (0);
7678         }
7679
7680         if (visual_states[n] != 0) {
7681                 delete visual_states[n];
7682         }
7683
7684         visual_states[n] = current_visual_state (true);
7685         gdk_beep ();
7686 }
7687
7688 void
7689 Editor::goto_visual_state (uint32_t n)
7690 {
7691         if (visual_states.size() <= n) {
7692                 return;
7693         }
7694
7695         if (visual_states[n] == 0) {
7696                 return;
7697         }
7698
7699         use_visual_state (*visual_states[n]);
7700 }
7701
7702 void
7703 Editor::start_visual_state_op (uint32_t n)
7704 {
7705         save_visual_state (n);
7706
7707         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7708         char buf[32];
7709         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7710         pup->set_text (buf);
7711         pup->touch();
7712 }
7713
7714 void
7715 Editor::cancel_visual_state_op (uint32_t n)
7716 {
7717         goto_visual_state (n);
7718 }
7719
7720 void
7721 Editor::toggle_region_mute ()
7722 {
7723         if (_ignore_region_action) {
7724                 return;
7725         }
7726
7727         RegionSelection rs = get_regions_from_selection_and_entered ();
7728
7729         if (rs.empty ()) {
7730                 return;
7731         }
7732
7733         if (rs.size() > 1) {
7734                 begin_reversible_command (_("mute regions"));
7735         } else {
7736                 begin_reversible_command (_("mute region"));
7737         }
7738
7739         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7740
7741                 (*i)->region()->playlist()->clear_changes ();
7742                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7743                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7744
7745         }
7746
7747         commit_reversible_command ();
7748 }
7749
7750 void
7751 Editor::combine_regions ()
7752 {
7753         /* foreach track with selected regions, take all selected regions
7754            and join them into a new region containing the subregions (as a
7755            playlist)
7756         */
7757
7758         typedef set<RouteTimeAxisView*> RTVS;
7759         RTVS tracks;
7760
7761         if (selection->regions.empty()) {
7762                 return;
7763         }
7764
7765         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7766                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7767
7768                 if (rtv) {
7769                         tracks.insert (rtv);
7770                 }
7771         }
7772
7773         begin_reversible_command (_("combine regions"));
7774
7775         vector<RegionView*> new_selection;
7776
7777         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7778                 RegionView* rv;
7779
7780                 if ((rv = (*i)->combine_regions ()) != 0) {
7781                         new_selection.push_back (rv);
7782                 }
7783         }
7784
7785         selection->clear_regions ();
7786         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7787                 selection->add (*i);
7788         }
7789
7790         commit_reversible_command ();
7791 }
7792
7793 void
7794 Editor::uncombine_regions ()
7795 {
7796         typedef set<RouteTimeAxisView*> RTVS;
7797         RTVS tracks;
7798
7799         if (selection->regions.empty()) {
7800                 return;
7801         }
7802
7803         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7804                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7805
7806                 if (rtv) {
7807                         tracks.insert (rtv);
7808                 }
7809         }
7810
7811         begin_reversible_command (_("uncombine regions"));
7812
7813         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7814                 (*i)->uncombine_regions ();
7815         }
7816
7817         commit_reversible_command ();
7818 }
7819
7820 void
7821 Editor::toggle_midi_input_active (bool flip_others)
7822 {
7823         bool onoff = false;
7824         boost::shared_ptr<RouteList> rl (new RouteList);
7825
7826         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7827                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7828
7829                 if (!rtav) {
7830                         continue;
7831                 }
7832
7833                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7834
7835                 if (mt) {
7836                         rl->push_back (rtav->route());
7837                         onoff = !mt->input_active();
7838                 }
7839         }
7840
7841         _session->set_exclusive_input_active (rl, onoff, flip_others);
7842 }
7843
7844 void
7845 Editor::lock ()
7846 {
7847         if (!lock_dialog) {
7848                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7849
7850                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7851                 lock_dialog->get_vbox()->pack_start (*padlock);
7852
7853                 ArdourButton* b = manage (new ArdourButton);
7854                 b->set_name ("lock button");
7855                 b->set_text (_("Click to unlock"));
7856                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7857                 lock_dialog->get_vbox()->pack_start (*b);
7858
7859                 lock_dialog->get_vbox()->show_all ();
7860                 lock_dialog->set_size_request (200, 200);
7861         }
7862
7863         delete _main_menu_disabler;
7864         _main_menu_disabler = new MainMenuDisabler;
7865
7866         lock_dialog->present ();
7867 }
7868
7869 void
7870 Editor::unlock ()
7871 {
7872         lock_dialog->hide ();
7873
7874         delete _main_menu_disabler;
7875         _main_menu_disabler = 0;
7876
7877         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7878                 start_lock_event_timing ();
7879         }
7880 }
7881
7882 void
7883 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7884 {
7885         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7886 }
7887
7888 void
7889 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7890 {
7891         Timers::TimerSuspender t;
7892         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7893         Gtkmm2ext::UI::instance()->flush_pending ();
7894 }
7895
7896 void
7897 Editor::bring_all_sources_into_session ()
7898 {
7899         if (!_session) {
7900                 return;
7901         }
7902
7903         Gtk::Label msg;
7904         ArdourDialog w (_("Moving embedded files into session folder"));
7905         w.get_vbox()->pack_start (msg);
7906         w.present ();
7907
7908         /* flush all pending GUI events because we're about to start copying
7909          * files
7910          */
7911
7912         Timers::TimerSuspender t;
7913         Gtkmm2ext::UI::instance()->flush_pending ();
7914
7915         cerr << " Do it\n";
7916
7917         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7918 }