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