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