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