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