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