2741f66d4d2c2809fa298ef5271c0a5cd02f631f
[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         list<double> rms_vals;
5036         double max_amp = 0;
5037         double max_rms = 0;
5038         bool use_rms = dialog.constrain_rms ();
5039
5040         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5041                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5042                 if (!arv) {
5043                         continue;
5044                 }
5045                 dialog.descend (1.0 / regions);
5046                 double const a = arv->audio_region()->maximum_amplitude (&dialog);
5047                 if (use_rms) {
5048                         double r = arv->audio_region()->rms (&dialog);
5049                         max_rms = max (max_rms, r);
5050                         rms_vals.push_back (r);
5051                 }
5052
5053                 if (a == -1) {
5054                         /* the user cancelled the operation */
5055                         return;
5056                 }
5057
5058                 max_amps.push_back (a);
5059                 max_amp = max (max_amp, a);
5060                 dialog.ascend ();
5061         }
5062
5063         list<double>::const_iterator a = max_amps.begin ();
5064         list<double>::const_iterator l = rms_vals.begin ();
5065         bool in_command = false;
5066
5067         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5068                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5069                 if (!arv) {
5070                         continue;
5071                 }
5072
5073                 arv->region()->clear_changes ();
5074
5075                 double amp = dialog.normalize_individually() ? *a : max_amp;
5076                 double target = dialog.target_peak (); // dB
5077
5078                 if (use_rms) {
5079                         double const amp_rms = dialog.normalize_individually() ? *l : max_rms;
5080                         const double t_rms = dialog.target_rms ();
5081                         const gain_t c_peak = dB_to_coefficient (target);
5082                         const gain_t c_rms  = dB_to_coefficient (t_rms);
5083                         if ((amp_rms / c_rms) > (amp / c_peak)) {
5084                                 amp = amp_rms;
5085                                 target = t_rms;
5086                         }
5087                 }
5088
5089                 arv->audio_region()->normalize (amp, target);
5090
5091                 if (!in_command) {
5092                         begin_reversible_command (_("normalize"));
5093                         in_command = true;
5094                 }
5095                 _session->add_command (new StatefulDiffCommand (arv->region()));
5096
5097                 ++a;
5098                 ++l;
5099         }
5100
5101         if (in_command) {
5102                 commit_reversible_command ();
5103         }
5104 }
5105
5106
5107 void
5108 Editor::reset_region_scale_amplitude ()
5109 {
5110         if (!_session) {
5111                 return;
5112         }
5113
5114         RegionSelection rs = get_regions_from_selection_and_entered ();
5115
5116         if (rs.empty()) {
5117                 return;
5118         }
5119
5120         bool in_command = false;
5121
5122         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5123                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5124                 if (!arv)
5125                         continue;
5126                 arv->region()->clear_changes ();
5127                 arv->audio_region()->set_scale_amplitude (1.0f);
5128
5129                 if(!in_command) {
5130                                 begin_reversible_command ("reset gain");
5131                                 in_command = true;
5132                 }
5133                 _session->add_command (new StatefulDiffCommand (arv->region()));
5134         }
5135
5136         if (in_command) {
5137                 commit_reversible_command ();
5138         }
5139 }
5140
5141 void
5142 Editor::adjust_region_gain (bool up)
5143 {
5144         RegionSelection rs = get_regions_from_selection_and_entered ();
5145
5146         if (!_session || rs.empty()) {
5147                 return;
5148         }
5149
5150         bool in_command = false;
5151
5152         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5153                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5154                 if (!arv) {
5155                         continue;
5156                 }
5157
5158                 arv->region()->clear_changes ();
5159
5160                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5161
5162                 if (up) {
5163                         dB += 1;
5164                 } else {
5165                         dB -= 1;
5166                 }
5167
5168                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5169
5170                 if (!in_command) {
5171                                 begin_reversible_command ("adjust region gain");
5172                                 in_command = true;
5173                 }
5174                 _session->add_command (new StatefulDiffCommand (arv->region()));
5175         }
5176
5177         if (in_command) {
5178                 commit_reversible_command ();
5179         }
5180 }
5181
5182
5183 void
5184 Editor::reverse_region ()
5185 {
5186         if (!_session) {
5187                 return;
5188         }
5189
5190         Reverse rev (*_session);
5191         apply_filter (rev, _("reverse regions"));
5192 }
5193
5194 void
5195 Editor::strip_region_silence ()
5196 {
5197         if (!_session) {
5198                 return;
5199         }
5200
5201         RegionSelection rs = get_regions_from_selection_and_entered ();
5202
5203         if (rs.empty()) {
5204                 return;
5205         }
5206
5207         std::list<RegionView*> audio_only;
5208
5209         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5210                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5211                 if (arv) {
5212                         audio_only.push_back (arv);
5213                 }
5214         }
5215
5216         assert (!audio_only.empty());
5217
5218         StripSilenceDialog d (_session, audio_only);
5219         int const r = d.run ();
5220
5221         d.drop_rects ();
5222
5223         if (r == Gtk::RESPONSE_OK) {
5224                 ARDOUR::AudioIntervalMap silences;
5225                 d.silences (silences);
5226                 StripSilence s (*_session, silences, d.fade_length());
5227
5228                 apply_filter (s, _("strip silence"), &d);
5229         }
5230 }
5231
5232 Command*
5233 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5234 {
5235         Evoral::Sequence<Evoral::Beats>::Notes selected;
5236         mrv.selection_as_notelist (selected, true);
5237
5238         vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5239         v.push_back (selected);
5240
5241         framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5242         Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5243
5244         return op (mrv.midi_region()->model(), pos_beats, v);
5245 }
5246
5247 void
5248 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5249 {
5250         if (rs.empty()) {
5251                 return;
5252         }
5253
5254         bool in_command = false;
5255
5256         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5257                 RegionSelection::const_iterator tmp = r;
5258                 ++tmp;
5259
5260                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5261
5262                 if (mrv) {
5263                         Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5264                         if (cmd) {
5265                                 if (!in_command) {
5266                                         begin_reversible_command (op.name ());
5267                                         in_command = true;
5268                                 }
5269                                 (*cmd)();
5270                                 _session->add_command (cmd);
5271                         }
5272                 }
5273
5274                 r = tmp;
5275         }
5276
5277         if (in_command) {
5278                 commit_reversible_command ();
5279         }
5280 }
5281
5282 void
5283 Editor::fork_region ()
5284 {
5285         RegionSelection rs = get_regions_from_selection_and_entered ();
5286
5287         if (rs.empty()) {
5288                 return;
5289         }
5290
5291         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5292         bool in_command = false;
5293
5294         gdk_flush ();
5295
5296         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5297                 RegionSelection::iterator tmp = r;
5298                 ++tmp;
5299
5300                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5301
5302                 if (mrv) {
5303                         try {
5304                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5305                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5306                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5307
5308                                 if (!in_command) {
5309                                         begin_reversible_command (_("Fork Region(s)"));
5310                                         in_command = true;
5311                                 }
5312                                 playlist->clear_changes ();
5313                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5314                                 _session->add_command(new StatefulDiffCommand (playlist));
5315                         } catch (...) {
5316                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5317                         }
5318                 }
5319
5320                 r = tmp;
5321         }
5322
5323         if (in_command) {
5324                 commit_reversible_command ();
5325         }
5326 }
5327
5328 void
5329 Editor::quantize_region ()
5330 {
5331         if (_session) {
5332                 quantize_regions(get_regions_from_selection_and_entered ());
5333         }
5334 }
5335
5336 void
5337 Editor::quantize_regions (const RegionSelection& rs)
5338 {
5339         if (rs.n_midi_regions() == 0) {
5340                 return;
5341         }
5342
5343         if (!quantize_dialog) {
5344                 quantize_dialog = new QuantizeDialog (*this);
5345         }
5346
5347         quantize_dialog->present ();
5348         const int r = quantize_dialog->run ();
5349         quantize_dialog->hide ();
5350
5351         if (r == Gtk::RESPONSE_OK) {
5352                 Quantize quant (quantize_dialog->snap_start(),
5353                                 quantize_dialog->snap_end(),
5354                                 quantize_dialog->start_grid_size(),
5355                                 quantize_dialog->end_grid_size(),
5356                                 quantize_dialog->strength(),
5357                                 quantize_dialog->swing(),
5358                                 quantize_dialog->threshold());
5359
5360                 apply_midi_note_edit_op (quant, rs);
5361         }
5362 }
5363
5364 void
5365 Editor::legatize_region (bool shrink_only)
5366 {
5367         if (_session) {
5368                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5369         }
5370 }
5371
5372 void
5373 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5374 {
5375         if (rs.n_midi_regions() == 0) {
5376                 return;
5377         }
5378
5379         Legatize legatize(shrink_only);
5380         apply_midi_note_edit_op (legatize, rs);
5381 }
5382
5383 void
5384 Editor::transform_region ()
5385 {
5386         if (_session) {
5387                 transform_regions(get_regions_from_selection_and_entered ());
5388         }
5389 }
5390
5391 void
5392 Editor::transform_regions (const RegionSelection& rs)
5393 {
5394         if (rs.n_midi_regions() == 0) {
5395                 return;
5396         }
5397
5398         TransformDialog td;
5399
5400         td.present();
5401         const int r = td.run();
5402         td.hide();
5403
5404         if (r == Gtk::RESPONSE_OK) {
5405                 Transform transform(td.get());
5406                 apply_midi_note_edit_op(transform, rs);
5407         }
5408 }
5409
5410 void
5411 Editor::transpose_region ()
5412 {
5413         if (_session) {
5414                 transpose_regions(get_regions_from_selection_and_entered ());
5415         }
5416 }
5417
5418 void
5419 Editor::transpose_regions (const RegionSelection& rs)
5420 {
5421         if (rs.n_midi_regions() == 0) {
5422                 return;
5423         }
5424
5425         TransposeDialog d;
5426         int const r = d.run ();
5427
5428         if (r == RESPONSE_ACCEPT) {
5429                 Transpose transpose(d.semitones ());
5430                 apply_midi_note_edit_op (transpose, rs);
5431         }
5432 }
5433
5434 void
5435 Editor::insert_patch_change (bool from_context)
5436 {
5437         RegionSelection rs = get_regions_from_selection_and_entered ();
5438
5439         if (rs.empty ()) {
5440                 return;
5441         }
5442
5443         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5444
5445         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5446            there may be more than one, but the PatchChangeDialog can only offer
5447            one set of patch menus.
5448         */
5449         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5450
5451         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5452         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5453
5454         if (d.run() == RESPONSE_CANCEL) {
5455                 return;
5456         }
5457
5458         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5459                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5460                 if (mrv) {
5461                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5462                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5463                         }
5464                 }
5465         }
5466 }
5467
5468 void
5469 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5470 {
5471         RegionSelection rs = get_regions_from_selection_and_entered ();
5472
5473         if (rs.empty()) {
5474                 return;
5475         }
5476
5477         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5478         bool in_command = false;
5479
5480         gdk_flush ();
5481
5482         int n = 0;
5483         int const N = rs.size ();
5484
5485         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5486                 RegionSelection::iterator tmp = r;
5487                 ++tmp;
5488
5489                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5490                 if (arv) {
5491                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5492
5493                         if (progress) {
5494                                 progress->descend (1.0 / N);
5495                         }
5496
5497                         if (arv->audio_region()->apply (filter, progress) == 0) {
5498
5499                                 playlist->clear_changes ();
5500                                 playlist->clear_owned_changes ();
5501
5502                                 if (!in_command) {
5503                                         begin_reversible_command (command);
5504                                         in_command = true;
5505                                 }
5506
5507                                 if (filter.results.empty ()) {
5508
5509                                         /* no regions returned; remove the old one */
5510                                         playlist->remove_region (arv->region ());
5511
5512                                 } else {
5513
5514                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5515
5516                                         /* first region replaces the old one */
5517                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5518                                         ++res;
5519
5520                                         /* add the rest */
5521                                         while (res != filter.results.end()) {
5522                                                 playlist->add_region (*res, (*res)->position());
5523                                                 ++res;
5524                                         }
5525
5526                                 }
5527
5528                                 /* We might have removed regions, which alters other regions' layering_index,
5529                                    so we need to do a recursive diff here.
5530                                 */
5531                                 vector<Command*> cmds;
5532                                 playlist->rdiff (cmds);
5533                                 _session->add_commands (cmds);
5534
5535                                 _session->add_command(new StatefulDiffCommand (playlist));
5536                         }
5537
5538                         if (progress) {
5539                                 progress->ascend ();
5540                         }
5541                 }
5542
5543                 r = tmp;
5544                 ++n;
5545         }
5546
5547         if (in_command) {
5548                 commit_reversible_command ();
5549         }
5550 }
5551
5552 void
5553 Editor::external_edit_region ()
5554 {
5555         /* more to come */
5556 }
5557
5558 void
5559 Editor::reset_region_gain_envelopes ()
5560 {
5561         RegionSelection rs = get_regions_from_selection_and_entered ();
5562
5563         if (!_session || rs.empty()) {
5564                 return;
5565         }
5566
5567         bool in_command = false;
5568
5569         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5571                 if (arv) {
5572                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5573                         XMLNode& before (alist->get_state());
5574
5575                         arv->audio_region()->set_default_envelope ();
5576
5577                         if (!in_command) {
5578                                 begin_reversible_command (_("reset region gain"));
5579                                 in_command = true;
5580                         }
5581                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5582                 }
5583         }
5584
5585         if (in_command) {
5586                 commit_reversible_command ();
5587         }
5588 }
5589
5590 void
5591 Editor::set_region_gain_visibility (RegionView* rv)
5592 {
5593         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5594         if (arv) {
5595                 arv->update_envelope_visibility();
5596         }
5597 }
5598
5599 void
5600 Editor::set_gain_envelope_visibility ()
5601 {
5602         if (!_session) {
5603                 return;
5604         }
5605
5606         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5607                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5608                 if (v) {
5609                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5610                 }
5611         }
5612 }
5613
5614 void
5615 Editor::toggle_gain_envelope_active ()
5616 {
5617         if (_ignore_region_action) {
5618                 return;
5619         }
5620
5621         RegionSelection rs = get_regions_from_selection_and_entered ();
5622
5623         if (!_session || rs.empty()) {
5624                 return;
5625         }
5626
5627         bool in_command = false;
5628
5629         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5630                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5631                 if (arv) {
5632                         arv->region()->clear_changes ();
5633                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5634
5635                         if (!in_command) {
5636                                 begin_reversible_command (_("region gain envelope active"));
5637                                 in_command = true;
5638                         }
5639                         _session->add_command (new StatefulDiffCommand (arv->region()));
5640                 }
5641         }
5642
5643         if (in_command) {
5644                 commit_reversible_command ();
5645         }
5646 }
5647
5648 void
5649 Editor::toggle_region_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 region lock"));
5662
5663         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5664                 (*i)->region()->clear_changes ();
5665                 (*i)->region()->set_locked (!(*i)->region()->locked());
5666                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5667         }
5668
5669         commit_reversible_command ();
5670 }
5671
5672 void
5673 Editor::toggle_region_video_lock ()
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 (_("Toggle Video Lock"));
5686
5687         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5688                 (*i)->region()->clear_changes ();
5689                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5690                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5691         }
5692
5693         commit_reversible_command ();
5694 }
5695
5696 void
5697 Editor::toggle_region_lock_style ()
5698 {
5699         if (_ignore_region_action) {
5700                 return;
5701         }
5702
5703         RegionSelection rs = get_regions_from_selection_and_entered ();
5704
5705         if (!_session || rs.empty()) {
5706                 return;
5707         }
5708
5709         begin_reversible_command (_("region lock style"));
5710
5711         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5712                 (*i)->region()->clear_changes ();
5713                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5714                 (*i)->region()->set_position_lock_style (ns);
5715                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5716         }
5717
5718         commit_reversible_command ();
5719 }
5720
5721 void
5722 Editor::toggle_opaque_region ()
5723 {
5724         if (_ignore_region_action) {
5725                 return;
5726         }
5727
5728         RegionSelection rs = get_regions_from_selection_and_entered ();
5729
5730         if (!_session || rs.empty()) {
5731                 return;
5732         }
5733
5734         begin_reversible_command (_("change region opacity"));
5735
5736         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5737                 (*i)->region()->clear_changes ();
5738                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5739                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5740         }
5741
5742         commit_reversible_command ();
5743 }
5744
5745 void
5746 Editor::toggle_record_enable ()
5747 {
5748         bool new_state = false;
5749         bool first = true;
5750         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5751                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5752                 if (!rtav)
5753                         continue;
5754                 if (!rtav->is_track())
5755                         continue;
5756
5757                 if (first) {
5758                         new_state = !rtav->track()->rec_enable_control()->get_value();
5759                         first = false;
5760                 }
5761
5762                 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5763         }
5764 }
5765
5766 void
5767 Editor::toggle_solo ()
5768 {
5769         bool new_state = false;
5770         bool first = true;
5771         boost::shared_ptr<ControlList> cl (new ControlList);
5772
5773         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5774                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5775
5776                 if (!rtav) {
5777                         continue;
5778                 }
5779
5780                 if (first) {
5781                         new_state = !rtav->route()->soloed ();
5782                         first = false;
5783                 }
5784
5785                 cl->push_back (rtav->route()->solo_control());
5786         }
5787
5788         _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5789 }
5790
5791 void
5792 Editor::toggle_mute ()
5793 {
5794         bool new_state = false;
5795         bool first = true;
5796         boost::shared_ptr<RouteList> rl (new RouteList);
5797
5798         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5799                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5800
5801                 if (!rtav) {
5802                         continue;
5803                 }
5804
5805                 if (first) {
5806                         new_state = !rtav->route()->muted();
5807                         first = false;
5808                 }
5809
5810                 rl->push_back (rtav->route());
5811         }
5812
5813         _session->set_controls (route_list_to_control_list (rl, &Stripable::mute_control), new_state, Controllable::UseGroup);
5814 }
5815
5816 void
5817 Editor::toggle_solo_isolate ()
5818 {
5819 }
5820
5821
5822 void
5823 Editor::fade_range ()
5824 {
5825         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5826
5827         begin_reversible_command (_("fade range"));
5828
5829         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5830                 (*i)->fade_range (selection->time);
5831         }
5832
5833         commit_reversible_command ();
5834 }
5835
5836
5837 void
5838 Editor::set_fade_length (bool in)
5839 {
5840         RegionSelection rs = get_regions_from_selection_and_entered ();
5841
5842         if (rs.empty()) {
5843                 return;
5844         }
5845
5846         /* we need a region to measure the offset from the start */
5847
5848         RegionView* rv = rs.front ();
5849
5850         framepos_t pos = get_preferred_edit_position();
5851         framepos_t len;
5852         char const * cmd;
5853
5854         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5855                 /* edit point is outside the relevant region */
5856                 return;
5857         }
5858
5859         if (in) {
5860                 if (pos <= rv->region()->position()) {
5861                         /* can't do it */
5862                         return;
5863                 }
5864                 len = pos - rv->region()->position();
5865                 cmd = _("set fade in length");
5866         } else {
5867                 if (pos >= rv->region()->last_frame()) {
5868                         /* can't do it */
5869                         return;
5870                 }
5871                 len = rv->region()->last_frame() - pos;
5872                 cmd = _("set fade out length");
5873         }
5874
5875         bool in_command = false;
5876
5877         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5878                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5879
5880                 if (!tmp) {
5881                         continue;
5882                 }
5883
5884                 boost::shared_ptr<AutomationList> alist;
5885                 if (in) {
5886                         alist = tmp->audio_region()->fade_in();
5887                 } else {
5888                         alist = tmp->audio_region()->fade_out();
5889                 }
5890
5891                 XMLNode &before = alist->get_state();
5892
5893                 if (in) {
5894                         tmp->audio_region()->set_fade_in_length (len);
5895                         tmp->audio_region()->set_fade_in_active (true);
5896                 } else {
5897                         tmp->audio_region()->set_fade_out_length (len);
5898                         tmp->audio_region()->set_fade_out_active (true);
5899                 }
5900
5901                 if (!in_command) {
5902                         begin_reversible_command (cmd);
5903                         in_command = true;
5904                 }
5905                 XMLNode &after = alist->get_state();
5906                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5907         }
5908
5909         if (in_command) {
5910                 commit_reversible_command ();
5911         }
5912 }
5913
5914 void
5915 Editor::set_fade_in_shape (FadeShape shape)
5916 {
5917         RegionSelection rs = get_regions_from_selection_and_entered ();
5918
5919         if (rs.empty()) {
5920                 return;
5921         }
5922         bool in_command = false;
5923
5924         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5925                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5926
5927                 if (!tmp) {
5928                         continue;
5929                 }
5930
5931                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5932                 XMLNode &before = alist->get_state();
5933
5934                 tmp->audio_region()->set_fade_in_shape (shape);
5935
5936                 if (!in_command) {
5937                         begin_reversible_command (_("set fade in shape"));
5938                         in_command = true;
5939                 }
5940                 XMLNode &after = alist->get_state();
5941                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5942         }
5943
5944         if (in_command) {
5945                 commit_reversible_command ();
5946         }
5947 }
5948
5949 void
5950 Editor::set_fade_out_shape (FadeShape shape)
5951 {
5952         RegionSelection rs = get_regions_from_selection_and_entered ();
5953
5954         if (rs.empty()) {
5955                 return;
5956         }
5957         bool in_command = false;
5958
5959         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5960                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5961
5962                 if (!tmp) {
5963                         continue;
5964                 }
5965
5966                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5967                 XMLNode &before = alist->get_state();
5968
5969                 tmp->audio_region()->set_fade_out_shape (shape);
5970
5971                 if(!in_command) {
5972                         begin_reversible_command (_("set fade out shape"));
5973                         in_command = true;
5974                 }
5975                 XMLNode &after = alist->get_state();
5976                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5977         }
5978
5979         if (in_command) {
5980                 commit_reversible_command ();
5981         }
5982 }
5983
5984 void
5985 Editor::set_fade_in_active (bool yn)
5986 {
5987         RegionSelection rs = get_regions_from_selection_and_entered ();
5988
5989         if (rs.empty()) {
5990                 return;
5991         }
5992         bool in_command = false;
5993
5994         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5995                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5996
5997                 if (!tmp) {
5998                         continue;
5999                 }
6000
6001
6002                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6003
6004                 ar->clear_changes ();
6005                 ar->set_fade_in_active (yn);
6006
6007                 if (!in_command) {
6008                         begin_reversible_command (_("set fade in active"));
6009                         in_command = true;
6010                 }
6011                 _session->add_command (new StatefulDiffCommand (ar));
6012         }
6013
6014         if (in_command) {
6015                 commit_reversible_command ();
6016         }
6017 }
6018
6019 void
6020 Editor::set_fade_out_active (bool yn)
6021 {
6022         RegionSelection rs = get_regions_from_selection_and_entered ();
6023
6024         if (rs.empty()) {
6025                 return;
6026         }
6027         bool in_command = false;
6028
6029         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6030                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6031
6032                 if (!tmp) {
6033                         continue;
6034                 }
6035
6036                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6037
6038                 ar->clear_changes ();
6039                 ar->set_fade_out_active (yn);
6040
6041                 if (!in_command) {
6042                         begin_reversible_command (_("set fade out active"));
6043                         in_command = true;
6044                 }
6045                 _session->add_command(new StatefulDiffCommand (ar));
6046         }
6047
6048         if (in_command) {
6049                 commit_reversible_command ();
6050         }
6051 }
6052
6053 void
6054 Editor::toggle_region_fades (int dir)
6055 {
6056         if (_ignore_region_action) {
6057                 return;
6058         }
6059
6060         boost::shared_ptr<AudioRegion> ar;
6061         bool yn = false;
6062
6063         RegionSelection rs = get_regions_from_selection_and_entered ();
6064
6065         if (rs.empty()) {
6066                 return;
6067         }
6068
6069         RegionSelection::iterator i;
6070         for (i = rs.begin(); i != rs.end(); ++i) {
6071                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6072                         if (dir == -1) {
6073                                 yn = ar->fade_out_active ();
6074                         } else {
6075                                 yn = ar->fade_in_active ();
6076                         }
6077                         break;
6078                 }
6079         }
6080
6081         if (i == rs.end()) {
6082                 return;
6083         }
6084
6085         /* XXX should this undo-able? */
6086         bool in_command = false;
6087
6088         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6089                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6090                         continue;
6091                 }
6092                 ar->clear_changes ();
6093
6094                 if (dir == 1 || dir == 0) {
6095                         ar->set_fade_in_active (!yn);
6096                 }
6097
6098                 if (dir == -1 || dir == 0) {
6099                         ar->set_fade_out_active (!yn);
6100                 }
6101                 if (!in_command) {
6102                         begin_reversible_command (_("toggle fade active"));
6103                         in_command = true;
6104                 }
6105                 _session->add_command(new StatefulDiffCommand (ar));
6106         }
6107
6108         if (in_command) {
6109                 commit_reversible_command ();
6110         }
6111 }
6112
6113
6114 /** Update region fade visibility after its configuration has been changed */
6115 void
6116 Editor::update_region_fade_visibility ()
6117 {
6118         bool _fade_visibility = _session->config.get_show_region_fades ();
6119
6120         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6121                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6122                 if (v) {
6123                         if (_fade_visibility) {
6124                                 v->audio_view()->show_all_fades ();
6125                         } else {
6126                                 v->audio_view()->hide_all_fades ();
6127                         }
6128                 }
6129         }
6130 }
6131
6132 void
6133 Editor::set_edit_point ()
6134 {
6135         framepos_t where;
6136         bool ignored;
6137
6138         if (!mouse_frame (where, ignored)) {
6139                 return;
6140         }
6141
6142         snap_to (where);
6143
6144         if (selection->markers.empty()) {
6145
6146                 mouse_add_new_marker (where);
6147
6148         } else {
6149                 bool ignored;
6150
6151                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6152
6153                 if (loc) {
6154                         loc->move_to (where);
6155                 }
6156         }
6157 }
6158
6159 void
6160 Editor::set_playhead_cursor ()
6161 {
6162         if (entered_marker) {
6163                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6164         } else {
6165                 framepos_t where;
6166                 bool ignored;
6167
6168                 if (!mouse_frame (where, ignored)) {
6169                         return;
6170                 }
6171
6172                 snap_to (where);
6173
6174                 if (_session) {
6175                         _session->request_locate (where, _session->transport_rolling());
6176                 }
6177         }
6178
6179         if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6180                 cancel_time_selection();
6181         }
6182 }
6183
6184 void
6185 Editor::split_region ()
6186 {
6187         if (_drags->active ()) {
6188                 return;
6189         }
6190
6191         //if a range is selected, separate it
6192         if ( !selection->time.empty()) {
6193                 separate_regions_between (selection->time);
6194                 return;
6195         }
6196
6197         //if no range was selected, try to find some regions to split
6198         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
6199
6200                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6201
6202                 framepos_t where = get_preferred_edit_position ();
6203
6204                 if (rs.empty()) {
6205                         return;
6206                 }
6207
6208                 if (snap_musical()) {
6209                         split_regions_at (where, rs, get_grid_music_divisions (0));
6210                 } else {
6211                         split_regions_at (where, rs, 0);
6212                 }
6213         }
6214 }
6215
6216 void
6217 Editor::select_next_route()
6218 {
6219         if (selection->tracks.empty()) {
6220                 selection->set (track_views.front());
6221                 return;
6222         }
6223
6224         TimeAxisView* current = selection->tracks.front();
6225
6226         RouteUI *rui;
6227         do {
6228                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6229
6230                         if (*i == current) {
6231                                 ++i;
6232                                 if (i != track_views.end()) {
6233                                         current = (*i);
6234                                 } else {
6235                                         current = (*(track_views.begin()));
6236                                         //selection->set (*(track_views.begin()));
6237                                 }
6238                                 break;
6239                         }
6240                 }
6241
6242                 rui = dynamic_cast<RouteUI *>(current);
6243
6244         } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6245
6246         selection->set (current);
6247
6248         ensure_time_axis_view_is_visible (*current, false);
6249 }
6250
6251 void
6252 Editor::select_prev_route()
6253 {
6254         if (selection->tracks.empty()) {
6255                 selection->set (track_views.front());
6256                 return;
6257         }
6258
6259         TimeAxisView* current = selection->tracks.front();
6260
6261         RouteUI *rui;
6262         do {
6263                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6264
6265                         if (*i == current) {
6266                                 ++i;
6267                                 if (i != track_views.rend()) {
6268                                         current = (*i);
6269                                 } else {
6270                                         current = *(track_views.rbegin());
6271                                 }
6272                                 break;
6273                         }
6274                 }
6275                 rui = dynamic_cast<RouteUI *>(current);
6276
6277         } while (current->hidden() || (rui == NULL) || !rui->route()->active());
6278
6279         selection->set (current);
6280
6281         ensure_time_axis_view_is_visible (*current, false);
6282 }
6283
6284 void
6285 Editor::set_loop_from_selection (bool play)
6286 {
6287         if (_session == 0) {
6288                 return;
6289         }
6290
6291         framepos_t start, end;
6292         if (!get_selection_extents ( start, end))
6293                 return;
6294
6295         set_loop_range (start, end,  _("set loop range from selection"));
6296
6297         if (play) {
6298                 _session->request_play_loop (true, true);
6299         }
6300 }
6301
6302 void
6303 Editor::set_loop_from_region (bool play)
6304 {
6305         framepos_t start, end;
6306         if (!get_selection_extents ( start, end))
6307                 return;
6308
6309         set_loop_range (start, end, _("set loop range from region"));
6310
6311         if (play) {
6312                 _session->request_locate (start, true);
6313                 _session->request_play_loop (true);
6314         }
6315 }
6316
6317 void
6318 Editor::set_punch_from_selection ()
6319 {
6320         if (_session == 0) {
6321                 return;
6322         }
6323
6324         framepos_t start, end;
6325         if (!get_selection_extents ( start, end))
6326                 return;
6327
6328         set_punch_range (start, end,  _("set punch range from selection"));
6329 }
6330
6331 void
6332 Editor::set_session_extents_from_selection ()
6333 {
6334         if (_session == 0) {
6335                 return;
6336         }
6337
6338         framepos_t start, end;
6339         if (!get_selection_extents ( start, end))
6340                 return;
6341
6342         Location* loc;
6343         if ((loc = _session->locations()->session_range_location()) == 0) {
6344                 _session->set_session_extents (start, end);  // this will create a new session range;  no need for UNDO
6345         } else {
6346                 XMLNode &before = loc->get_state();
6347
6348                 _session->set_session_extents (start, end);
6349
6350                 XMLNode &after = loc->get_state();
6351
6352                 begin_reversible_command (_("set session start/end from selection"));
6353
6354                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6355
6356                 commit_reversible_command ();
6357         }
6358
6359         _session->set_end_is_free (false);
6360 }
6361
6362 void
6363 Editor::set_punch_start_from_edit_point ()
6364 {
6365         if (_session) {
6366
6367                 framepos_t start = 0;
6368                 framepos_t end = max_framepos;
6369
6370                 //use the existing punch end, if any
6371                 Location* tpl = transport_punch_location();
6372                 if (tpl) {
6373                         end = tpl->end();
6374                 }
6375
6376                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6377                         start = _session->audible_frame();
6378                 } else {
6379                         start = get_preferred_edit_position();
6380                 }
6381
6382                 //snap the selection start/end
6383                 snap_to(start);
6384
6385                 //if there's not already a sensible selection endpoint, go "forever"
6386                 if ( start > end ) {
6387                         end = max_framepos;
6388                 }
6389
6390                 set_punch_range (start, end, _("set punch start from EP"));
6391         }
6392
6393 }
6394
6395 void
6396 Editor::set_punch_end_from_edit_point ()
6397 {
6398         if (_session) {
6399
6400                 framepos_t start = 0;
6401                 framepos_t end = max_framepos;
6402
6403                 //use the existing punch start, if any
6404                 Location* tpl = transport_punch_location();
6405                 if (tpl) {
6406                         start = tpl->start();
6407                 }
6408
6409                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6410                         end = _session->audible_frame();
6411                 } else {
6412                         end = get_preferred_edit_position();
6413                 }
6414
6415                 //snap the selection start/end
6416                 snap_to(end);
6417
6418                 set_punch_range (start, end, _("set punch end from EP"));
6419
6420         }
6421 }
6422
6423 void
6424 Editor::set_loop_start_from_edit_point ()
6425 {
6426         if (_session) {
6427
6428                 framepos_t start = 0;
6429                 framepos_t end = max_framepos;
6430
6431                 //use the existing loop end, if any
6432                 Location* tpl = transport_loop_location();
6433                 if (tpl) {
6434                         end = tpl->end();
6435                 }
6436
6437                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6438                         start = _session->audible_frame();
6439                 } else {
6440                         start = get_preferred_edit_position();
6441                 }
6442
6443                 //snap the selection start/end
6444                 snap_to(start);
6445
6446                 //if there's not already a sensible selection endpoint, go "forever"
6447                 if ( start > end ) {
6448                         end = max_framepos;
6449                 }
6450
6451                 set_loop_range (start, end, _("set loop start from EP"));
6452         }
6453
6454 }
6455
6456 void
6457 Editor::set_loop_end_from_edit_point ()
6458 {
6459         if (_session) {
6460
6461                 framepos_t start = 0;
6462                 framepos_t end = max_framepos;
6463
6464                 //use the existing loop start, if any
6465                 Location* tpl = transport_loop_location();
6466                 if (tpl) {
6467                         start = tpl->start();
6468                 }
6469
6470                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6471                         end = _session->audible_frame();
6472                 } else {
6473                         end = get_preferred_edit_position();
6474                 }
6475
6476                 //snap the selection start/end
6477                 snap_to(end);
6478
6479                 set_loop_range (start, end, _("set loop end from EP"));
6480         }
6481 }
6482
6483 void
6484 Editor::set_punch_from_region ()
6485 {
6486         framepos_t start, end;
6487         if (!get_selection_extents ( start, end))
6488                 return;
6489
6490         set_punch_range (start, end, _("set punch range from region"));
6491 }
6492
6493 void
6494 Editor::pitch_shift_region ()
6495 {
6496         RegionSelection rs = get_regions_from_selection_and_entered ();
6497
6498         RegionSelection audio_rs;
6499         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6500                 if (dynamic_cast<AudioRegionView*> (*i)) {
6501                         audio_rs.push_back (*i);
6502                 }
6503         }
6504
6505         if (audio_rs.empty()) {
6506                 return;
6507         }
6508
6509         pitch_shift (audio_rs, 1.2);
6510 }
6511
6512 void
6513 Editor::set_tempo_from_region ()
6514 {
6515         RegionSelection rs = get_regions_from_selection_and_entered ();
6516
6517         if (!_session || rs.empty()) {
6518                 return;
6519         }
6520
6521         RegionView* rv = rs.front();
6522
6523         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6524 }
6525
6526 void
6527 Editor::use_range_as_bar ()
6528 {
6529         framepos_t start, end;
6530         if (get_edit_op_range (start, end)) {
6531                 define_one_bar (start, end);
6532         }
6533 }
6534
6535 void
6536 Editor::define_one_bar (framepos_t start, framepos_t end)
6537 {
6538         framepos_t length = end - start;
6539
6540         const Meter& m (_session->tempo_map().meter_at_frame (start));
6541
6542         /* length = 1 bar */
6543
6544         /* We're going to deliver a constant tempo here,
6545            so we can use frames per beat to determine length.
6546            now we want frames per beat.
6547            we have frames per bar, and beats per bar, so ...
6548         */
6549
6550         /* XXXX METER MATH */
6551
6552         double frames_per_beat = length / m.divisions_per_bar();
6553
6554         /* beats per minute = */
6555
6556         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6557
6558         /* now decide whether to:
6559
6560             (a) set global tempo
6561             (b) add a new tempo marker
6562
6563         */
6564
6565         const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6566
6567         bool do_global = false;
6568
6569         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6570
6571                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6572                    at the start, or create a new marker
6573                 */
6574
6575                 vector<string> options;
6576                 options.push_back (_("Cancel"));
6577                 options.push_back (_("Add new marker"));
6578                 options.push_back (_("Set global tempo"));
6579
6580                 Choice c (
6581                         _("Define one bar"),
6582                         _("Do you want to set the global tempo or add a new tempo marker?"),
6583                         options
6584                         );
6585
6586                 c.set_default_response (2);
6587
6588                 switch (c.run()) {
6589                 case 0:
6590                         return;
6591
6592                 case 2:
6593                         do_global = true;
6594                         break;
6595
6596                 default:
6597                         do_global = false;
6598                 }
6599
6600         } else {
6601
6602                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6603                    if the marker is at the region starter, change it, otherwise add
6604                    a new tempo marker
6605                 */
6606         }
6607
6608         begin_reversible_command (_("set tempo from region"));
6609         XMLNode& before (_session->tempo_map().get_state());
6610
6611         if (do_global) {
6612                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6613         } else if (t.frame() == start) {
6614                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6615         } else {
6616                 const Tempo tempo (beats_per_minute, t.note_type());
6617                 _session->tempo_map().add_tempo (tempo, 0.0, start, TempoSection::Constant, AudioTime);
6618         }
6619
6620         XMLNode& after (_session->tempo_map().get_state());
6621
6622         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6623         commit_reversible_command ();
6624 }
6625
6626 void
6627 Editor::split_region_at_transients ()
6628 {
6629         AnalysisFeatureList positions;
6630
6631         RegionSelection rs = get_regions_from_selection_and_entered ();
6632
6633         if (!_session || rs.empty()) {
6634                 return;
6635         }
6636
6637         begin_reversible_command (_("split regions"));
6638
6639         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6640
6641                 RegionSelection::iterator tmp;
6642
6643                 tmp = i;
6644                 ++tmp;
6645
6646                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6647
6648                 if (ar) {
6649                         ar->transients (positions);
6650                         split_region_at_points ((*i)->region(), positions, true);
6651                         positions.clear ();
6652                 }
6653
6654                 i = tmp;
6655         }
6656
6657         commit_reversible_command ();
6658
6659 }
6660
6661 void
6662 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6663 {
6664         bool use_rhythmic_rodent = false;
6665
6666         boost::shared_ptr<Playlist> pl = r->playlist();
6667
6668         list<boost::shared_ptr<Region> > new_regions;
6669
6670         if (!pl) {
6671                 return;
6672         }
6673
6674         if (positions.empty()) {
6675                 return;
6676         }
6677
6678         if (positions.size() > 20 && can_ferret) {
6679                 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);
6680                 MessageDialog msg (msgstr,
6681                                    false,
6682                                    Gtk::MESSAGE_INFO,
6683                                    Gtk::BUTTONS_OK_CANCEL);
6684
6685                 if (can_ferret) {
6686                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6687                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6688                 } else {
6689                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6690                 }
6691
6692                 msg.set_title (_("Excessive split?"));
6693                 msg.present ();
6694
6695                 int response = msg.run();
6696                 msg.hide ();
6697
6698                 switch (response) {
6699                 case RESPONSE_OK:
6700                         break;
6701                 case RESPONSE_APPLY:
6702                         use_rhythmic_rodent = true;
6703                         break;
6704                 default:
6705                         return;
6706                 }
6707         }
6708
6709         if (use_rhythmic_rodent) {
6710                 show_rhythm_ferret ();
6711                 return;
6712         }
6713
6714         AnalysisFeatureList::const_iterator x;
6715
6716         pl->clear_changes ();
6717         pl->clear_owned_changes ();
6718
6719         x = positions.begin();
6720
6721         if (x == positions.end()) {
6722                 return;
6723         }
6724
6725         pl->freeze ();
6726         pl->remove_region (r);
6727
6728         framepos_t pos = 0;
6729
6730         framepos_t rstart = r->first_frame ();
6731         framepos_t rend = r->last_frame ();
6732
6733         while (x != positions.end()) {
6734
6735                 /* deal with positons that are out of scope of present region bounds */
6736                 if (*x <= rstart || *x > rend) {
6737                         ++x;
6738                         continue;
6739                 }
6740
6741                 /* file start = original start + how far we from the initial position ?  */
6742
6743                 framepos_t file_start = r->start() + pos;
6744
6745                 /* length = next position - current position */
6746
6747                 framepos_t len = (*x) - pos - rstart;
6748
6749                 /* XXX we do we really want to allow even single-sample regions?
6750                  * shouldn't we have some kind of lower limit on region size?
6751                  */
6752
6753                 if (len <= 0) {
6754                         break;
6755                 }
6756
6757                 string new_name;
6758
6759                 if (RegionFactory::region_name (new_name, r->name())) {
6760                         break;
6761                 }
6762
6763                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6764
6765                 PropertyList plist;
6766
6767                 plist.add (ARDOUR::Properties::start, file_start);
6768                 plist.add (ARDOUR::Properties::length, len);
6769                 plist.add (ARDOUR::Properties::name, new_name);
6770                 plist.add (ARDOUR::Properties::layer, 0);
6771                 // TODO set transients_offset
6772
6773                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6774                 /* because we set annouce to false, manually add the new region to the
6775                  * RegionFactory map
6776                  */
6777                 RegionFactory::map_add (nr);
6778
6779                 pl->add_region (nr, rstart + pos);
6780
6781                 if (select_new) {
6782                         new_regions.push_front(nr);
6783                 }
6784
6785                 pos += len;
6786                 ++x;
6787         }
6788
6789         string new_name;
6790
6791         RegionFactory::region_name (new_name, r->name());
6792
6793         /* Add the final region */
6794         PropertyList plist;
6795
6796         plist.add (ARDOUR::Properties::start, r->start() + pos);
6797         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6798         plist.add (ARDOUR::Properties::name, new_name);
6799         plist.add (ARDOUR::Properties::layer, 0);
6800
6801         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6802         /* because we set annouce to false, manually add the new region to the
6803            RegionFactory map
6804         */
6805         RegionFactory::map_add (nr);
6806         pl->add_region (nr, r->position() + pos);
6807
6808         if (select_new) {
6809                 new_regions.push_front(nr);
6810         }
6811
6812         pl->thaw ();
6813
6814         /* We might have removed regions, which alters other regions' layering_index,
6815            so we need to do a recursive diff here.
6816         */
6817         vector<Command*> cmds;
6818         pl->rdiff (cmds);
6819         _session->add_commands (cmds);
6820
6821         _session->add_command (new StatefulDiffCommand (pl));
6822
6823         if (select_new) {
6824
6825                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6826                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6827                 }
6828         }
6829 }
6830
6831 void
6832 Editor::place_transient()
6833 {
6834         if (!_session) {
6835                 return;
6836         }
6837
6838         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6839
6840         if (rs.empty()) {
6841                 return;
6842         }
6843
6844         framepos_t where = get_preferred_edit_position();
6845
6846         begin_reversible_command (_("place transient"));
6847
6848         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6849                 (*r)->region()->add_transient(where);
6850         }
6851
6852         commit_reversible_command ();
6853 }
6854
6855 void
6856 Editor::remove_transient(ArdourCanvas::Item* item)
6857 {
6858         if (!_session) {
6859                 return;
6860         }
6861
6862         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6863         assert (_line);
6864
6865         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6866         _arv->remove_transient (*(float*) _line->get_data ("position"));
6867 }
6868
6869 void
6870 Editor::snap_regions_to_grid ()
6871 {
6872         list <boost::shared_ptr<Playlist > > used_playlists;
6873
6874         RegionSelection rs = get_regions_from_selection_and_entered ();
6875
6876         if (!_session || rs.empty()) {
6877                 return;
6878         }
6879
6880         begin_reversible_command (_("snap regions to grid"));
6881
6882         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6883
6884                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6885
6886                 if (!pl->frozen()) {
6887                         /* we haven't seen this playlist before */
6888
6889                         /* remember used playlists so we can thaw them later */
6890                         used_playlists.push_back(pl);
6891                         pl->freeze();
6892                 }
6893
6894                 framepos_t start_frame = (*r)->region()->first_frame ();
6895                 snap_to (start_frame);
6896                 (*r)->region()->set_position (start_frame);
6897         }
6898
6899         while (used_playlists.size() > 0) {
6900                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6901                 (*i)->thaw();
6902                 used_playlists.pop_front();
6903         }
6904
6905         commit_reversible_command ();
6906 }
6907
6908 void
6909 Editor::close_region_gaps ()
6910 {
6911         list <boost::shared_ptr<Playlist > > used_playlists;
6912
6913         RegionSelection rs = get_regions_from_selection_and_entered ();
6914
6915         if (!_session || rs.empty()) {
6916                 return;
6917         }
6918
6919         Dialog dialog (_("Close Region Gaps"));
6920
6921         Table table (2, 3);
6922         table.set_spacings (12);
6923         table.set_border_width (12);
6924         Label* l = manage (left_aligned_label (_("Crossfade length")));
6925         table.attach (*l, 0, 1, 0, 1);
6926
6927         SpinButton spin_crossfade (1, 0);
6928         spin_crossfade.set_range (0, 15);
6929         spin_crossfade.set_increments (1, 1);
6930         spin_crossfade.set_value (5);
6931         table.attach (spin_crossfade, 1, 2, 0, 1);
6932
6933         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6934
6935         l = manage (left_aligned_label (_("Pull-back length")));
6936         table.attach (*l, 0, 1, 1, 2);
6937
6938         SpinButton spin_pullback (1, 0);
6939         spin_pullback.set_range (0, 100);
6940         spin_pullback.set_increments (1, 1);
6941         spin_pullback.set_value(30);
6942         table.attach (spin_pullback, 1, 2, 1, 2);
6943
6944         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6945
6946         dialog.get_vbox()->pack_start (table);
6947         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6948         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6949         dialog.show_all ();
6950
6951         if (dialog.run () == RESPONSE_CANCEL) {
6952                 return;
6953         }
6954
6955         framepos_t crossfade_len = spin_crossfade.get_value();
6956         framepos_t pull_back_frames = spin_pullback.get_value();
6957
6958         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6959         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6960
6961         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6962
6963         begin_reversible_command (_("close region gaps"));
6964
6965         int idx = 0;
6966         boost::shared_ptr<Region> last_region;
6967
6968         rs.sort_by_position_and_track();
6969
6970         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6971
6972                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6973
6974                 if (!pl->frozen()) {
6975                         /* we haven't seen this playlist before */
6976
6977                         /* remember used playlists so we can thaw them later */
6978                         used_playlists.push_back(pl);
6979                         pl->freeze();
6980                 }
6981
6982                 framepos_t position = (*r)->region()->position();
6983
6984                 if (idx == 0 || position < last_region->position()){
6985                         last_region = (*r)->region();
6986                         idx++;
6987                         continue;
6988                 }
6989
6990                 (*r)->region()->trim_front( (position - pull_back_frames));
6991                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6992
6993                 last_region = (*r)->region();
6994
6995                 idx++;
6996         }
6997
6998         while (used_playlists.size() > 0) {
6999                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7000                 (*i)->thaw();
7001                 used_playlists.pop_front();
7002         }
7003
7004         commit_reversible_command ();
7005 }
7006
7007 void
7008 Editor::tab_to_transient (bool forward)
7009 {
7010         AnalysisFeatureList positions;
7011
7012         RegionSelection rs = get_regions_from_selection_and_entered ();
7013
7014         if (!_session) {
7015                 return;
7016         }
7017
7018         framepos_t pos = _session->audible_frame ();
7019
7020         if (!selection->tracks.empty()) {
7021
7022                 /* don't waste time searching for transients in duplicate playlists.
7023                  */
7024
7025                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7026
7027                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7028
7029                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7030
7031                         if (rtv) {
7032                                 boost::shared_ptr<Track> tr = rtv->track();
7033                                 if (tr) {
7034                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
7035                                         if (pl) {
7036                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7037
7038                                                 if (result >= 0) {
7039                                                         positions.push_back (result);
7040                                                 }
7041                                         }
7042                                 }
7043                         }
7044                 }
7045
7046         } else {
7047
7048                 if (rs.empty()) {
7049                         return;
7050                 }
7051
7052                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7053                         (*r)->region()->get_transients (positions);
7054                 }
7055         }
7056
7057         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7058
7059         if (forward) {
7060                 AnalysisFeatureList::iterator x;
7061
7062                 for (x = positions.begin(); x != positions.end(); ++x) {
7063                         if ((*x) > pos) {
7064                                 break;
7065                         }
7066                 }
7067
7068                 if (x != positions.end ()) {
7069                         _session->request_locate (*x);
7070                 }
7071
7072         } else {
7073                 AnalysisFeatureList::reverse_iterator x;
7074
7075                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7076                         if ((*x) < pos) {
7077                                 break;
7078                         }
7079                 }
7080
7081                 if (x != positions.rend ()) {
7082                         _session->request_locate (*x);
7083                 }
7084         }
7085 }
7086
7087 void
7088 Editor::playhead_forward_to_grid ()
7089 {
7090         if (!_session) {
7091                 return;
7092         }
7093
7094         framepos_t pos = playhead_cursor->current_frame ();
7095         if (pos < max_framepos - 1) {
7096                 pos += 2;
7097                 snap_to_internal (pos, RoundUpAlways, false);
7098                 _session->request_locate (pos);
7099         }
7100 }
7101
7102
7103 void
7104 Editor::playhead_backward_to_grid ()
7105 {
7106         if (!_session) {
7107                 return;
7108         }
7109
7110         framepos_t pos = playhead_cursor->current_frame ();
7111         if (pos > 2) {
7112                 pos -= 2;
7113                 snap_to_internal (pos, RoundDownAlways, false);
7114                 _session->request_locate (pos);
7115         }
7116 }
7117
7118 void
7119 Editor::set_track_height (Height h)
7120 {
7121         TrackSelection& ts (selection->tracks);
7122
7123         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7124                 (*x)->set_height_enum (h);
7125         }
7126 }
7127
7128 void
7129 Editor::toggle_tracks_active ()
7130 {
7131         TrackSelection& ts (selection->tracks);
7132         bool first = true;
7133         bool target = false;
7134
7135         if (ts.empty()) {
7136                 return;
7137         }
7138
7139         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7140                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7141
7142                 if (rtv) {
7143                         if (first) {
7144                                 target = !rtv->_route->active();
7145                                 first = false;
7146                         }
7147                         rtv->_route->set_active (target, this);
7148                 }
7149         }
7150 }
7151
7152 void
7153 Editor::remove_tracks ()
7154 {
7155         /* this will delete GUI objects that may be the subject of an event
7156            handler in which this method is called. Defer actual deletion to the
7157            next idle callback, when all event handling is finished.
7158         */
7159         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7160 }
7161
7162 bool
7163 Editor::idle_remove_tracks ()
7164 {
7165         Session::StateProtector sp (_session);
7166         _remove_tracks ();
7167         return false; /* do not call again */
7168 }
7169
7170 void
7171 Editor::_remove_tracks ()
7172 {
7173         TrackSelection& ts (selection->tracks);
7174
7175         if (ts.empty()) {
7176                 return;
7177         }
7178
7179         vector<string> choices;
7180         string prompt;
7181         int ntracks = 0;
7182         int nbusses = 0;
7183         const char* trackstr;
7184         const char* busstr;
7185         vector<boost::shared_ptr<Route> > routes;
7186         bool special_bus = false;
7187
7188         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7189                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7190                 if (!rtv) {
7191                         continue;
7192                 }
7193                 if (rtv->is_track()) {
7194                         ntracks++;
7195                 } else {
7196                         nbusses++;
7197                 }
7198                 routes.push_back (rtv->_route);
7199
7200                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7201                         special_bus = true;
7202                 }
7203         }
7204
7205         if (special_bus && !Config->get_allow_special_bus_removal()) {
7206                 MessageDialog msg (_("That would be bad news ...."),
7207                                    false,
7208                                    Gtk::MESSAGE_INFO,
7209                                    Gtk::BUTTONS_OK);
7210                 msg.set_secondary_text (string_compose (_(
7211                                                                 "Removing the master or monitor bus is such a bad idea\n\
7212 that %1 is not going to allow it.\n\
7213 \n\
7214 If you really want to do this sort of thing\n\
7215 edit your ardour.rc file to set the\n\
7216 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7217
7218                 msg.present ();
7219                 msg.run ();
7220                 return;
7221         }
7222
7223         if (ntracks + nbusses == 0) {
7224                 return;
7225         }
7226
7227         trackstr = P_("track", "tracks", ntracks);
7228         busstr = P_("bus", "busses", nbusses);
7229
7230         if (ntracks) {
7231                 if (nbusses) {
7232                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7233                                                     "(You may also lose the playlists associated with the %2)\n\n"
7234                                                     "This action cannot be undone, and the session file will be overwritten!"),
7235                                                   ntracks, trackstr, nbusses, busstr);
7236                 } else {
7237                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
7238                                                     "(You may also lose the playlists associated with the %2)\n\n"
7239                                                     "This action cannot be undone, and the session file will be overwritten!"),
7240                                                   ntracks, trackstr);
7241                 }
7242         } else if (nbusses) {
7243                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
7244                                             "This action cannot be undone, and the session file will be overwritten"),
7245                                           nbusses, busstr);
7246         }
7247
7248         choices.push_back (_("No, do nothing."));
7249         if (ntracks + nbusses > 1) {
7250                 choices.push_back (_("Yes, remove them."));
7251         } else {
7252                 choices.push_back (_("Yes, remove it."));
7253         }
7254
7255         string title;
7256         if (ntracks) {
7257                 title = string_compose (_("Remove %1"), trackstr);
7258         } else {
7259                 title = string_compose (_("Remove %1"), busstr);
7260         }
7261
7262         Choice prompter (title, prompt, choices);
7263
7264         if (prompter.run () != 1) {
7265                 return;
7266         }
7267
7268         {
7269                 DisplaySuspender ds;
7270                 boost::shared_ptr<RouteList> rl (new RouteList);
7271                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7272                         rl->push_back (*x);
7273                 }
7274                 _session->remove_routes (rl);
7275         }
7276         /* TrackSelection and RouteList leave scope,
7277          * destructors are called,
7278          * diskstream drops references, save_state is called (again for every track)
7279          */
7280 }
7281
7282 void
7283 Editor::do_insert_time ()
7284 {
7285         if (selection->tracks.empty()) {
7286                 return;
7287         }
7288
7289         InsertRemoveTimeDialog d (*this);
7290         int response = d.run ();
7291
7292         if (response != RESPONSE_OK) {
7293                 return;
7294         }
7295
7296         if (d.distance() == 0) {
7297                 return;
7298         }
7299
7300         insert_time (
7301                 get_preferred_edit_position (EDIT_IGNORE_MOUSE),
7302                 d.distance(),
7303                 d.intersected_region_action (),
7304                 d.all_playlists(),
7305                 d.move_glued(),
7306                 d.move_markers(),
7307                 d.move_glued_markers(),
7308                 d.move_locked_markers(),
7309                 d.move_tempos()
7310                 );
7311 }
7312
7313 void
7314 Editor::insert_time (
7315         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7316         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7317         )
7318 {
7319
7320         if (Config->get_edit_mode() == Lock) {
7321                 return;
7322         }
7323         bool in_command = false;
7324
7325         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7326
7327         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7328
7329                 /* regions */
7330
7331                 /* don't operate on any playlist more than once, which could
7332                  * happen if "all playlists" is enabled, but there is more
7333                  * than 1 track using playlists "from" a given track.
7334                  */
7335
7336                 set<boost::shared_ptr<Playlist> > pl;
7337
7338                 if (all_playlists) {
7339                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7340                         if (rtav && rtav->track ()) {
7341                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7342                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7343                                         pl.insert (*p);
7344                                 }
7345                         }
7346                 } else {
7347                         if ((*x)->playlist ()) {
7348                                 pl.insert ((*x)->playlist ());
7349                         }
7350                 }
7351
7352                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7353
7354                         (*i)->clear_changes ();
7355                         (*i)->clear_owned_changes ();
7356
7357                         if (opt == SplitIntersected) {
7358                                 /* non musical split */
7359                                 (*i)->split (pos, 0);
7360                         }
7361
7362                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7363
7364                         if (!in_command) {
7365                                 begin_reversible_command (_("insert time"));
7366                                 in_command = true;
7367                         }
7368                         vector<Command*> cmds;
7369                         (*i)->rdiff (cmds);
7370                         _session->add_commands (cmds);
7371
7372                         _session->add_command (new StatefulDiffCommand (*i));
7373                 }
7374
7375                 /* automation */
7376                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7377                 if (rtav) {
7378                         if (!in_command) {
7379                                 begin_reversible_command (_("insert time"));
7380                                 in_command = true;
7381                         }
7382                         rtav->route ()->shift (pos, frames);
7383                 }
7384         }
7385
7386         /* markers */
7387         if (markers_too) {
7388                 bool moved = false;
7389                 XMLNode& before (_session->locations()->get_state());
7390                 Locations::LocationList copy (_session->locations()->list());
7391
7392                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7393
7394                         Locations::LocationList::const_iterator tmp;
7395
7396                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7397                                 bool const was_locked = (*i)->locked ();
7398                                 if (locked_markers_too) {
7399                                         (*i)->unlock ();
7400                                 }
7401
7402                                 if ((*i)->start() >= pos) {
7403                                         // move end first, in case we're moving by more than the length of the range
7404                                         if (!(*i)->is_mark()) {
7405                                                 (*i)->set_end ((*i)->end() + frames);
7406                                         }
7407                                         (*i)->set_start ((*i)->start() + frames);
7408                                         moved = true;
7409                                 }
7410
7411                                 if (was_locked) {
7412                                         (*i)->lock ();
7413                                 }
7414                         }
7415                 }
7416
7417                 if (moved) {
7418                         if (!in_command) {
7419                                 begin_reversible_command (_("insert time"));
7420                                 in_command = true;
7421                         }
7422                         XMLNode& after (_session->locations()->get_state());
7423                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7424                 }
7425         }
7426
7427         if (tempo_too) {
7428                 if (!in_command) {
7429                         begin_reversible_command (_("insert time"));
7430                         in_command = true;
7431                 }
7432                 XMLNode& before (_session->tempo_map().get_state());
7433                 _session->tempo_map().insert_time (pos, frames);
7434                 XMLNode& after (_session->tempo_map().get_state());
7435                 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7436         }
7437
7438         if (in_command) {
7439                 commit_reversible_command ();
7440         }
7441 }
7442
7443 void
7444 Editor::do_remove_time ()
7445 {
7446         if (selection->tracks.empty()) {
7447                 return;
7448         }
7449
7450         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7451         InsertRemoveTimeDialog d (*this, true);
7452
7453         int response = d.run ();
7454
7455         if (response != RESPONSE_OK) {
7456                 return;
7457         }
7458
7459         framecnt_t distance = d.distance();
7460
7461         if (distance == 0) {
7462                 return;
7463         }
7464
7465         remove_time (
7466                 pos,
7467                 distance,
7468                 SplitIntersected,
7469                 d.move_glued(),
7470                 d.move_markers(),
7471                 d.move_glued_markers(),
7472                 d.move_locked_markers(),
7473                 d.move_tempos()
7474         );
7475 }
7476
7477 void
7478 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7479                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7480 {
7481         if (Config->get_edit_mode() == Lock) {
7482                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7483                 return;
7484         }
7485         bool in_command = false;
7486
7487         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7488                 /* regions */
7489                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7490
7491                 if (pl) {
7492
7493                         XMLNode &before = pl->get_state();
7494
7495                         std::list<AudioRange> rl;
7496                         AudioRange ar(pos, pos+frames, 0);
7497                         rl.push_back(ar);
7498                         pl->cut (rl);
7499                         pl->shift (pos, -frames, true, ignore_music_glue);
7500
7501                         if (!in_command) {
7502                                 begin_reversible_command (_("remove time"));
7503                                 in_command = true;
7504                         }
7505                         XMLNode &after = pl->get_state();
7506
7507                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7508                 }
7509
7510                 /* automation */
7511                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7512                 if (rtav) {
7513                         if (!in_command) {
7514                                 begin_reversible_command (_("remove time"));
7515                                 in_command = true;
7516                         }
7517                         rtav->route ()->shift (pos, -frames);
7518                 }
7519         }
7520
7521         std::list<Location*> loc_kill_list;
7522
7523         /* markers */
7524         if (markers_too) {
7525                 bool moved = false;
7526                 XMLNode& before (_session->locations()->get_state());
7527                 Locations::LocationList copy (_session->locations()->list());
7528
7529                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7530                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7531
7532                                 bool const was_locked = (*i)->locked ();
7533                                 if (locked_markers_too) {
7534                                         (*i)->unlock ();
7535                                 }
7536
7537                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7538                                         if ((*i)->end() >= pos
7539                                         && (*i)->end() < pos+frames
7540                                         && (*i)->start() >= pos
7541                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7542                                                 moved = true;
7543                                                 loc_kill_list.push_back(*i);
7544                                         } else {  // only start or end is included, try to do the right thing
7545                                                 // move start before moving end, to avoid trying to move the end to before the start
7546                                                 // if we're removing more time than the length of the range
7547                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7548                                                         // start is within cut
7549                                                         (*i)->set_start (pos);  // bring the start marker to the beginning of the cut
7550                                                         moved = true;
7551                                                 } else if ((*i)->start() >= pos+frames) {
7552                                                         // start (and thus entire range) lies beyond end of cut
7553                                                         (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7554                                                         moved = true;
7555                                                 }
7556                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7557                                                         // end is inside cut
7558                                                         (*i)->set_end (pos);  // bring the end to the cut
7559                                                         moved = true;
7560                                                 } else if ((*i)->end() >= pos+frames) {
7561                                                         // end is beyond end of cut
7562                                                         (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7563                                                         moved = true;
7564                                                 }
7565
7566                                         }
7567                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7568                                         loc_kill_list.push_back(*i);
7569                                         moved = true;
7570                                 } else if ((*i)->start() >= pos) {
7571                                         (*i)->set_start ((*i)->start() -frames);
7572                                         moved = true;
7573                                 }
7574
7575                                 if (was_locked) {
7576                                         (*i)->lock ();
7577                                 }
7578                         }
7579                 }
7580
7581                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7582                         _session->locations()->remove( *i );
7583                 }
7584
7585                 if (moved) {
7586                         if (!in_command) {
7587                                 begin_reversible_command (_("remove time"));
7588                                 in_command = true;
7589                         }
7590                         XMLNode& after (_session->locations()->get_state());
7591                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7592                 }
7593         }
7594
7595         if (tempo_too) {
7596                 XMLNode& before (_session->tempo_map().get_state());
7597
7598                 if (_session->tempo_map().remove_time (pos, frames) ) {
7599                         if (!in_command) {
7600                                 begin_reversible_command (_("remove time"));
7601                                 in_command = true;
7602                         }
7603                         XMLNode& after (_session->tempo_map().get_state());
7604                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7605                 }
7606         }
7607
7608         if (in_command) {
7609                 commit_reversible_command ();
7610         }
7611 }
7612
7613 void
7614 Editor::fit_selection ()
7615 {
7616         if (!selection->tracks.empty()) {
7617                 fit_tracks (selection->tracks);
7618         } else {
7619                 TrackViewList tvl;
7620
7621                 /* no selected tracks - use tracks with selected regions */
7622
7623                 if (!selection->regions.empty()) {
7624                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7625                                 tvl.push_back (&(*r)->get_time_axis_view ());
7626                         }
7627
7628                         if (!tvl.empty()) {
7629                                 fit_tracks (tvl);
7630                         }
7631                 } else if (internal_editing()) {
7632                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7633                            the entered track
7634                         */
7635                         if (entered_track) {
7636                                 tvl.push_back (entered_track);
7637                                 fit_tracks (tvl);
7638                         }
7639                 }
7640         }
7641
7642 }
7643
7644 void
7645 Editor::fit_tracks (TrackViewList & tracks)
7646 {
7647         if (tracks.empty()) {
7648                 return;
7649         }
7650
7651         uint32_t child_heights = 0;
7652         int visible_tracks = 0;
7653
7654         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7655
7656                 if (!(*t)->marked_for_display()) {
7657                         continue;
7658                 }
7659
7660                 child_heights += (*t)->effective_height() - (*t)->current_height();
7661                 ++visible_tracks;
7662         }
7663
7664         /* compute the per-track height from:
7665
7666            total canvas visible height -
7667                  height that will be taken by visible children of selected
7668                  tracks - height of the ruler/hscroll area
7669         */
7670         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7671         double first_y_pos = DBL_MAX;
7672
7673         if (h < TimeAxisView::preset_height (HeightSmall)) {
7674                 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7675                 /* too small to be displayed */
7676                 return;
7677         }
7678
7679         undo_visual_stack.push_back (current_visual_state (true));
7680         PBD::Unwinder<bool> nsv (no_save_visual, true);
7681
7682         /* build a list of all tracks, including children */
7683
7684         TrackViewList all;
7685         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7686                 all.push_back (*i);
7687                 TimeAxisView::Children c = (*i)->get_child_list ();
7688                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7689                         all.push_back (j->get());
7690                 }
7691         }
7692
7693
7694         // find selection range.
7695         // if someone knows how to user TrackViewList::iterator for this
7696         // I'm all ears.
7697         int selected_top = -1;
7698         int selected_bottom = -1;
7699         int i = 0;
7700         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7701                 if ((*t)->marked_for_display ()) {
7702                         if (tracks.contains(*t)) {
7703                                 if (selected_top == -1) {
7704                                         selected_top = i;
7705                                 }
7706                                 selected_bottom = i;
7707                         }
7708                 }
7709         }
7710
7711         i = 0;
7712         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7713                 if ((*t)->marked_for_display ()) {
7714                         if (tracks.contains(*t)) {
7715                                 (*t)->set_height (h);
7716                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7717                         } else {
7718                                 if (i > selected_top && i < selected_bottom) {
7719                                         hide_track_in_display (*t);
7720                                 }
7721                         }
7722                 }
7723         }
7724
7725         /*
7726            set the controls_layout height now, because waiting for its size
7727            request signal handler will cause the vertical adjustment setting to fail
7728         */
7729
7730         controls_layout.property_height () = _full_canvas_height;
7731         vertical_adjustment.set_value (first_y_pos);
7732
7733         redo_visual_stack.push_back (current_visual_state (true));
7734
7735         visible_tracks_selector.set_text (_("Sel"));
7736 }
7737
7738 void
7739 Editor::save_visual_state (uint32_t n)
7740 {
7741         while (visual_states.size() <= n) {
7742                 visual_states.push_back (0);
7743         }
7744
7745         if (visual_states[n] != 0) {
7746                 delete visual_states[n];
7747         }
7748
7749         visual_states[n] = current_visual_state (true);
7750         gdk_beep ();
7751 }
7752
7753 void
7754 Editor::goto_visual_state (uint32_t n)
7755 {
7756         if (visual_states.size() <= n) {
7757                 return;
7758         }
7759
7760         if (visual_states[n] == 0) {
7761                 return;
7762         }
7763
7764         use_visual_state (*visual_states[n]);
7765 }
7766
7767 void
7768 Editor::start_visual_state_op (uint32_t n)
7769 {
7770         save_visual_state (n);
7771
7772         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7773         char buf[32];
7774         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7775         pup->set_text (buf);
7776         pup->touch();
7777 }
7778
7779 void
7780 Editor::cancel_visual_state_op (uint32_t n)
7781 {
7782         goto_visual_state (n);
7783 }
7784
7785 void
7786 Editor::toggle_region_mute ()
7787 {
7788         if (_ignore_region_action) {
7789                 return;
7790         }
7791
7792         RegionSelection rs = get_regions_from_selection_and_entered ();
7793
7794         if (rs.empty ()) {
7795                 return;
7796         }
7797
7798         if (rs.size() > 1) {
7799                 begin_reversible_command (_("mute regions"));
7800         } else {
7801                 begin_reversible_command (_("mute region"));
7802         }
7803
7804         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7805
7806                 (*i)->region()->playlist()->clear_changes ();
7807                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7808                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7809
7810         }
7811
7812         commit_reversible_command ();
7813 }
7814
7815 void
7816 Editor::combine_regions ()
7817 {
7818         /* foreach track with selected regions, take all selected regions
7819            and join them into a new region containing the subregions (as a
7820            playlist)
7821         */
7822
7823         typedef set<RouteTimeAxisView*> RTVS;
7824         RTVS tracks;
7825
7826         if (selection->regions.empty()) {
7827                 return;
7828         }
7829
7830         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7831                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7832
7833                 if (rtv) {
7834                         tracks.insert (rtv);
7835                 }
7836         }
7837
7838         begin_reversible_command (_("combine regions"));
7839
7840         vector<RegionView*> new_selection;
7841
7842         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7843                 RegionView* rv;
7844
7845                 if ((rv = (*i)->combine_regions ()) != 0) {
7846                         new_selection.push_back (rv);
7847                 }
7848         }
7849
7850         selection->clear_regions ();
7851         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7852                 selection->add (*i);
7853         }
7854
7855         commit_reversible_command ();
7856 }
7857
7858 void
7859 Editor::uncombine_regions ()
7860 {
7861         typedef set<RouteTimeAxisView*> RTVS;
7862         RTVS tracks;
7863
7864         if (selection->regions.empty()) {
7865                 return;
7866         }
7867
7868         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7869                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7870
7871                 if (rtv) {
7872                         tracks.insert (rtv);
7873                 }
7874         }
7875
7876         begin_reversible_command (_("uncombine regions"));
7877
7878         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7879                 (*i)->uncombine_regions ();
7880         }
7881
7882         commit_reversible_command ();
7883 }
7884
7885 void
7886 Editor::toggle_midi_input_active (bool flip_others)
7887 {
7888         bool onoff = false;
7889         boost::shared_ptr<RouteList> rl (new RouteList);
7890
7891         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7892                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7893
7894                 if (!rtav) {
7895                         continue;
7896                 }
7897
7898                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7899
7900                 if (mt) {
7901                         rl->push_back (rtav->route());
7902                         onoff = !mt->input_active();
7903                 }
7904         }
7905
7906         _session->set_exclusive_input_active (rl, onoff, flip_others);
7907 }
7908
7909 void
7910 Editor::lock ()
7911 {
7912         if (!lock_dialog) {
7913                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7914
7915                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7916                 lock_dialog->get_vbox()->pack_start (*padlock);
7917
7918                 ArdourButton* b = manage (new ArdourButton);
7919                 b->set_name ("lock button");
7920                 b->set_text (_("Click to unlock"));
7921                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7922                 lock_dialog->get_vbox()->pack_start (*b);
7923
7924                 lock_dialog->get_vbox()->show_all ();
7925                 lock_dialog->set_size_request (200, 200);
7926         }
7927
7928         delete _main_menu_disabler;
7929         _main_menu_disabler = new MainMenuDisabler;
7930
7931         lock_dialog->present ();
7932 }
7933
7934 void
7935 Editor::unlock ()
7936 {
7937         lock_dialog->hide ();
7938
7939         delete _main_menu_disabler;
7940         _main_menu_disabler = 0;
7941
7942         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7943                 start_lock_event_timing ();
7944         }
7945 }
7946
7947 void
7948 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7949 {
7950         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7951 }
7952
7953 void
7954 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7955 {
7956         Timers::TimerSuspender t;
7957         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7958         Gtkmm2ext::UI::instance()->flush_pending (1);
7959 }
7960
7961 void
7962 Editor::bring_all_sources_into_session ()
7963 {
7964         if (!_session) {
7965                 return;
7966         }
7967
7968         Gtk::Label msg;
7969         ArdourDialog w (_("Moving embedded files into session folder"));
7970         w.get_vbox()->pack_start (msg);
7971         w.present ();
7972
7973         /* flush all pending GUI events because we're about to start copying
7974          * files
7975          */
7976
7977         Timers::TimerSuspender t;
7978         Gtkmm2ext::UI::instance()->flush_pending (3);
7979
7980         cerr << " Do it\n";
7981
7982         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7983 }