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