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