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