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