Use new separate_by_channel API
[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 (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                 _session->set_dirty ();
5432         }
5433 }
5434
5435 void
5436 Editor::fork_region ()
5437 {
5438         RegionSelection rs = get_regions_from_selection_and_entered ();
5439
5440         if (rs.empty()) {
5441                 return;
5442         }
5443
5444         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5445         bool in_command = false;
5446
5447         gdk_flush ();
5448
5449         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5450                 RegionSelection::iterator tmp = r;
5451                 ++tmp;
5452
5453                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5454
5455                 if (mrv) {
5456                         try {
5457                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5458                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5459                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5460
5461                                 if (!in_command) {
5462                                         begin_reversible_command (_("Fork Region(s)"));
5463                                         in_command = true;
5464                                 }
5465                                 playlist->clear_changes ();
5466                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5467                                 _session->add_command(new StatefulDiffCommand (playlist));
5468                         } catch (...) {
5469                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5470                         }
5471                 }
5472
5473                 r = tmp;
5474         }
5475
5476         if (in_command) {
5477                 commit_reversible_command ();
5478         }
5479 }
5480
5481 void
5482 Editor::quantize_region ()
5483 {
5484         if (_session) {
5485                 quantize_regions(get_regions_from_selection_and_entered ());
5486         }
5487 }
5488
5489 void
5490 Editor::quantize_regions (const RegionSelection& rs)
5491 {
5492         if (rs.n_midi_regions() == 0) {
5493                 return;
5494         }
5495
5496         if (!quantize_dialog) {
5497                 quantize_dialog = new QuantizeDialog (*this);
5498         }
5499
5500         if (quantize_dialog->is_mapped()) {
5501                 /* in progress already */
5502                 return;
5503         }
5504
5505         quantize_dialog->present ();
5506         const int r = quantize_dialog->run ();
5507         quantize_dialog->hide ();
5508
5509         if (r == Gtk::RESPONSE_OK) {
5510                 Quantize quant (quantize_dialog->snap_start(),
5511                                 quantize_dialog->snap_end(),
5512                                 quantize_dialog->start_grid_size(),
5513                                 quantize_dialog->end_grid_size(),
5514                                 quantize_dialog->strength(),
5515                                 quantize_dialog->swing(),
5516                                 quantize_dialog->threshold());
5517
5518                 apply_midi_note_edit_op (quant, rs);
5519         }
5520 }
5521
5522 void
5523 Editor::legatize_region (bool shrink_only)
5524 {
5525         if (_session) {
5526                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5527         }
5528 }
5529
5530 void
5531 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5532 {
5533         if (rs.n_midi_regions() == 0) {
5534                 return;
5535         }
5536
5537         Legatize legatize(shrink_only);
5538         apply_midi_note_edit_op (legatize, rs);
5539 }
5540
5541 void
5542 Editor::transform_region ()
5543 {
5544         if (_session) {
5545                 transform_regions(get_regions_from_selection_and_entered ());
5546         }
5547 }
5548
5549 void
5550 Editor::transform_regions (const RegionSelection& rs)
5551 {
5552         if (rs.n_midi_regions() == 0) {
5553                 return;
5554         }
5555
5556         TransformDialog td;
5557
5558         td.present();
5559         const int r = td.run();
5560         td.hide();
5561
5562         if (r == Gtk::RESPONSE_OK) {
5563                 Transform transform(td.get());
5564                 apply_midi_note_edit_op(transform, rs);
5565         }
5566 }
5567
5568 void
5569 Editor::transpose_region ()
5570 {
5571         if (_session) {
5572                 transpose_regions(get_regions_from_selection_and_entered ());
5573         }
5574 }
5575
5576 void
5577 Editor::transpose_regions (const RegionSelection& rs)
5578 {
5579         if (rs.n_midi_regions() == 0) {
5580                 return;
5581         }
5582
5583         TransposeDialog d;
5584         int const r = d.run ();
5585
5586         if (r == RESPONSE_ACCEPT) {
5587                 Transpose transpose(d.semitones ());
5588                 apply_midi_note_edit_op (transpose, rs);
5589         }
5590 }
5591
5592 void
5593 Editor::insert_patch_change (bool from_context)
5594 {
5595         RegionSelection rs = get_regions_from_selection_and_entered ();
5596
5597         if (rs.empty ()) {
5598                 return;
5599         }
5600
5601         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5602
5603         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5604            there may be more than one, but the PatchChangeDialog can only offer
5605            one set of patch menus.
5606         */
5607         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5608
5609         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5610         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5611
5612         if (d.run() == RESPONSE_CANCEL) {
5613                 return;
5614         }
5615
5616         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5617                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5618                 if (mrv) {
5619                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5620                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5621                         }
5622                 }
5623         }
5624 }
5625
5626 void
5627 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5628 {
5629         RegionSelection rs = get_regions_from_selection_and_entered ();
5630
5631         if (rs.empty()) {
5632                 return;
5633         }
5634
5635         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5636         bool in_command = false;
5637
5638         gdk_flush ();
5639
5640         int n = 0;
5641         int const N = rs.size ();
5642
5643         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5644                 RegionSelection::iterator tmp = r;
5645                 ++tmp;
5646
5647                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5648                 if (arv) {
5649                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5650
5651                         if (progress) {
5652                                 progress->descend (1.0 / N);
5653                         }
5654
5655                         if (arv->audio_region()->apply (filter, progress) == 0) {
5656
5657                                 playlist->clear_changes ();
5658                                 playlist->clear_owned_changes ();
5659
5660                                 if (!in_command) {
5661                                         begin_reversible_command (command);
5662                                         in_command = true;
5663                                 }
5664
5665                                 if (filter.results.empty ()) {
5666
5667                                         /* no regions returned; remove the old one */
5668                                         playlist->remove_region (arv->region ());
5669
5670                                 } else {
5671
5672                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5673
5674                                         /* first region replaces the old one */
5675                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5676                                         ++res;
5677
5678                                         /* add the rest */
5679                                         while (res != filter.results.end()) {
5680                                                 playlist->add_region (*res, (*res)->position());
5681                                                 ++res;
5682                                         }
5683
5684                                 }
5685
5686                                 /* We might have removed regions, which alters other regions' layering_index,
5687                                    so we need to do a recursive diff here.
5688                                 */
5689                                 vector<Command*> cmds;
5690                                 playlist->rdiff (cmds);
5691                                 _session->add_commands (cmds);
5692
5693                                 _session->add_command(new StatefulDiffCommand (playlist));
5694                         }
5695
5696                         if (progress) {
5697                                 progress->ascend ();
5698                         }
5699                 }
5700
5701                 r = tmp;
5702                 ++n;
5703         }
5704
5705         if (in_command) {
5706                 commit_reversible_command ();
5707         }
5708 }
5709
5710 void
5711 Editor::external_edit_region ()
5712 {
5713         /* more to come */
5714 }
5715
5716 void
5717 Editor::reset_region_gain_envelopes ()
5718 {
5719         RegionSelection rs = get_regions_from_selection_and_entered ();
5720
5721         if (!_session || rs.empty()) {
5722                 return;
5723         }
5724
5725         bool in_command = false;
5726
5727         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5728                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5729                 if (arv) {
5730                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5731                         XMLNode& before (alist->get_state());
5732
5733                         arv->audio_region()->set_default_envelope ();
5734
5735                         if (!in_command) {
5736                                 begin_reversible_command (_("reset region gain"));
5737                                 in_command = true;
5738                         }
5739                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5740                 }
5741         }
5742
5743         if (in_command) {
5744                 commit_reversible_command ();
5745         }
5746 }
5747
5748 void
5749 Editor::set_region_gain_visibility (RegionView* rv)
5750 {
5751         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5752         if (arv) {
5753                 arv->update_envelope_visibility();
5754         }
5755 }
5756
5757 void
5758 Editor::set_gain_envelope_visibility ()
5759 {
5760         if (!_session) {
5761                 return;
5762         }
5763
5764         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5765                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5766                 if (v) {
5767                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5768                 }
5769         }
5770 }
5771
5772 void
5773 Editor::toggle_gain_envelope_active ()
5774 {
5775         if (_ignore_region_action) {
5776                 return;
5777         }
5778
5779         RegionSelection rs = get_regions_from_selection_and_entered ();
5780
5781         if (!_session || rs.empty()) {
5782                 return;
5783         }
5784
5785         bool in_command = false;
5786
5787         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5788                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5789                 if (arv) {
5790                         arv->region()->clear_changes ();
5791                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5792
5793                         if (!in_command) {
5794                                 begin_reversible_command (_("region gain envelope active"));
5795                                 in_command = true;
5796                         }
5797                         _session->add_command (new StatefulDiffCommand (arv->region()));
5798                 }
5799         }
5800
5801         if (in_command) {
5802                 commit_reversible_command ();
5803         }
5804 }
5805
5806 void
5807 Editor::toggle_region_lock ()
5808 {
5809         if (_ignore_region_action) {
5810                 return;
5811         }
5812
5813         RegionSelection rs = get_regions_from_selection_and_entered ();
5814
5815         if (!_session || rs.empty()) {
5816                 return;
5817         }
5818
5819         begin_reversible_command (_("toggle region lock"));
5820
5821         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5822                 (*i)->region()->clear_changes ();
5823                 (*i)->region()->set_locked (!(*i)->region()->locked());
5824                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5825         }
5826
5827         commit_reversible_command ();
5828 }
5829
5830 void
5831 Editor::toggle_region_video_lock ()
5832 {
5833         if (_ignore_region_action) {
5834                 return;
5835         }
5836
5837         RegionSelection rs = get_regions_from_selection_and_entered ();
5838
5839         if (!_session || rs.empty()) {
5840                 return;
5841         }
5842
5843         begin_reversible_command (_("Toggle Video Lock"));
5844
5845         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5846                 (*i)->region()->clear_changes ();
5847                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5848                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5849         }
5850
5851         commit_reversible_command ();
5852 }
5853
5854 void
5855 Editor::toggle_region_lock_style ()
5856 {
5857         if (_ignore_region_action) {
5858                 return;
5859         }
5860
5861         RegionSelection rs = get_regions_from_selection_and_entered ();
5862
5863         if (!_session || rs.empty()) {
5864                 return;
5865         }
5866
5867         Glib::RefPtr<ToggleAction> a = Glib::RefPtr<ToggleAction>::cast_dynamic (_region_actions->get_action("toggle-region-lock-style"));
5868         vector<Widget*> proxies = a->get_proxies();
5869         Gtk::CheckMenuItem* cmi = dynamic_cast<Gtk::CheckMenuItem*> (proxies.front());
5870
5871         assert (cmi);
5872
5873         begin_reversible_command (_("toggle region lock style"));
5874
5875         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5876                 (*i)->region()->clear_changes ();
5877                 PositionLockStyle const ns = ((*i)->region()->position_lock_style() == AudioTime && !cmi->get_inconsistent()) ? MusicTime : AudioTime;
5878                 (*i)->region()->set_position_lock_style (ns);
5879                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5880         }
5881
5882         commit_reversible_command ();
5883 }
5884
5885 void
5886 Editor::toggle_opaque_region ()
5887 {
5888         if (_ignore_region_action) {
5889                 return;
5890         }
5891
5892         RegionSelection rs = get_regions_from_selection_and_entered ();
5893
5894         if (!_session || rs.empty()) {
5895                 return;
5896         }
5897
5898         begin_reversible_command (_("change region opacity"));
5899
5900         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5901                 (*i)->region()->clear_changes ();
5902                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5903                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5904         }
5905
5906         commit_reversible_command ();
5907 }
5908
5909 void
5910 Editor::toggle_record_enable ()
5911 {
5912         bool new_state = false;
5913         bool first = true;
5914         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5915                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5916                 if (!rtav)
5917                         continue;
5918                 if (!rtav->is_track())
5919                         continue;
5920
5921                 if (first) {
5922                         new_state = !rtav->track()->rec_enable_control()->get_value();
5923                         first = false;
5924                 }
5925
5926                 rtav->track()->rec_enable_control()->set_value (new_state, Controllable::UseGroup);
5927         }
5928 }
5929
5930 void
5931 Editor::toggle_solo ()
5932 {
5933         bool new_state = false;
5934         bool first = true;
5935         boost::shared_ptr<ControlList> cl (new ControlList);
5936
5937         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5938                 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5939
5940                 if (!stav || !stav->stripable()->solo_control()) {
5941                         continue;
5942                 }
5943
5944                 if (first) {
5945                         new_state = !stav->stripable()->solo_control()->soloed ();
5946                         first = false;
5947                 }
5948
5949                 cl->push_back (stav->stripable()->solo_control());
5950         }
5951
5952         _session->set_controls (cl, new_state ? 1.0 : 0.0, Controllable::UseGroup);
5953 }
5954
5955 void
5956 Editor::toggle_mute ()
5957 {
5958         bool new_state = false;
5959         bool first = true;
5960         boost::shared_ptr<ControlList> cl (new ControlList);
5961
5962         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5963                 StripableTimeAxisView *stav = dynamic_cast<StripableTimeAxisView *>(*i);
5964
5965                 if (!stav || !stav->stripable()->mute_control()) {
5966                         continue;
5967                 }
5968
5969                 if (first) {
5970                         new_state = !stav->stripable()->mute_control()->muted();
5971                         first = false;
5972                 }
5973
5974                 cl->push_back (stav->stripable()->mute_control());
5975         }
5976
5977         _session->set_controls (cl, new_state, Controllable::UseGroup);
5978 }
5979
5980 void
5981 Editor::toggle_solo_isolate ()
5982 {
5983 }
5984
5985
5986 void
5987 Editor::fade_range ()
5988 {
5989         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5990
5991         begin_reversible_command (_("fade range"));
5992
5993         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5994                 (*i)->fade_range (selection->time);
5995         }
5996
5997         commit_reversible_command ();
5998 }
5999
6000
6001 void
6002 Editor::set_fade_length (bool in)
6003 {
6004         RegionSelection rs = get_regions_from_selection_and_entered ();
6005
6006         if (rs.empty()) {
6007                 return;
6008         }
6009
6010         /* we need a region to measure the offset from the start */
6011
6012         RegionView* rv = rs.front ();
6013
6014         framepos_t pos = get_preferred_edit_position();
6015         framepos_t len;
6016         char const * cmd;
6017
6018         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
6019                 /* edit point is outside the relevant region */
6020                 return;
6021         }
6022
6023         if (in) {
6024                 if (pos <= rv->region()->position()) {
6025                         /* can't do it */
6026                         return;
6027                 }
6028                 len = pos - rv->region()->position();
6029                 cmd = _("set fade in length");
6030         } else {
6031                 if (pos >= rv->region()->last_frame()) {
6032                         /* can't do it */
6033                         return;
6034                 }
6035                 len = rv->region()->last_frame() - pos;
6036                 cmd = _("set fade out length");
6037         }
6038
6039         bool in_command = false;
6040
6041         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6042                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6043
6044                 if (!tmp) {
6045                         continue;
6046                 }
6047
6048                 boost::shared_ptr<AutomationList> alist;
6049                 if (in) {
6050                         alist = tmp->audio_region()->fade_in();
6051                 } else {
6052                         alist = tmp->audio_region()->fade_out();
6053                 }
6054
6055                 XMLNode &before = alist->get_state();
6056
6057                 if (in) {
6058                         tmp->audio_region()->set_fade_in_length (len);
6059                         tmp->audio_region()->set_fade_in_active (true);
6060                 } else {
6061                         tmp->audio_region()->set_fade_out_length (len);
6062                         tmp->audio_region()->set_fade_out_active (true);
6063                 }
6064
6065                 if (!in_command) {
6066                         begin_reversible_command (cmd);
6067                         in_command = true;
6068                 }
6069                 XMLNode &after = alist->get_state();
6070                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
6071         }
6072
6073         if (in_command) {
6074                 commit_reversible_command ();
6075         }
6076 }
6077
6078 void
6079 Editor::set_fade_in_shape (FadeShape shape)
6080 {
6081         RegionSelection rs = get_regions_from_selection_and_entered ();
6082
6083         if (rs.empty()) {
6084                 return;
6085         }
6086         bool in_command = false;
6087
6088         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6089                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6090
6091                 if (!tmp) {
6092                         continue;
6093                 }
6094
6095                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
6096                 XMLNode &before = alist->get_state();
6097
6098                 tmp->audio_region()->set_fade_in_shape (shape);
6099
6100                 if (!in_command) {
6101                         begin_reversible_command (_("set fade in shape"));
6102                         in_command = true;
6103                 }
6104                 XMLNode &after = alist->get_state();
6105                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6106         }
6107
6108         if (in_command) {
6109                 commit_reversible_command ();
6110         }
6111 }
6112
6113 void
6114 Editor::set_fade_out_shape (FadeShape shape)
6115 {
6116         RegionSelection rs = get_regions_from_selection_and_entered ();
6117
6118         if (rs.empty()) {
6119                 return;
6120         }
6121         bool in_command = false;
6122
6123         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6124                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6125
6126                 if (!tmp) {
6127                         continue;
6128                 }
6129
6130                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
6131                 XMLNode &before = alist->get_state();
6132
6133                 tmp->audio_region()->set_fade_out_shape (shape);
6134
6135                 if(!in_command) {
6136                         begin_reversible_command (_("set fade out shape"));
6137                         in_command = true;
6138                 }
6139                 XMLNode &after = alist->get_state();
6140                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
6141         }
6142
6143         if (in_command) {
6144                 commit_reversible_command ();
6145         }
6146 }
6147
6148 void
6149 Editor::set_fade_in_active (bool yn)
6150 {
6151         RegionSelection rs = get_regions_from_selection_and_entered ();
6152
6153         if (rs.empty()) {
6154                 return;
6155         }
6156         bool in_command = false;
6157
6158         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6159                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6160
6161                 if (!tmp) {
6162                         continue;
6163                 }
6164
6165
6166                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6167
6168                 ar->clear_changes ();
6169                 ar->set_fade_in_active (yn);
6170
6171                 if (!in_command) {
6172                         begin_reversible_command (_("set fade in active"));
6173                         in_command = true;
6174                 }
6175                 _session->add_command (new StatefulDiffCommand (ar));
6176         }
6177
6178         if (in_command) {
6179                 commit_reversible_command ();
6180         }
6181 }
6182
6183 void
6184 Editor::set_fade_out_active (bool yn)
6185 {
6186         RegionSelection rs = get_regions_from_selection_and_entered ();
6187
6188         if (rs.empty()) {
6189                 return;
6190         }
6191         bool in_command = false;
6192
6193         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
6194                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
6195
6196                 if (!tmp) {
6197                         continue;
6198                 }
6199
6200                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
6201
6202                 ar->clear_changes ();
6203                 ar->set_fade_out_active (yn);
6204
6205                 if (!in_command) {
6206                         begin_reversible_command (_("set fade out active"));
6207                         in_command = true;
6208                 }
6209                 _session->add_command(new StatefulDiffCommand (ar));
6210         }
6211
6212         if (in_command) {
6213                 commit_reversible_command ();
6214         }
6215 }
6216
6217 void
6218 Editor::toggle_region_fades (int dir)
6219 {
6220         if (_ignore_region_action) {
6221                 return;
6222         }
6223
6224         boost::shared_ptr<AudioRegion> ar;
6225         bool yn = false;
6226
6227         RegionSelection rs = get_regions_from_selection_and_entered ();
6228
6229         if (rs.empty()) {
6230                 return;
6231         }
6232
6233         RegionSelection::iterator i;
6234         for (i = rs.begin(); i != rs.end(); ++i) {
6235                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6236                         if (dir == -1) {
6237                                 yn = ar->fade_out_active ();
6238                         } else {
6239                                 yn = ar->fade_in_active ();
6240                         }
6241                         break;
6242                 }
6243         }
6244
6245         if (i == rs.end()) {
6246                 return;
6247         }
6248
6249         /* XXX should this undo-able? */
6250         bool in_command = false;
6251
6252         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6253                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6254                         continue;
6255                 }
6256                 ar->clear_changes ();
6257
6258                 if (dir == 1 || dir == 0) {
6259                         ar->set_fade_in_active (!yn);
6260                 }
6261
6262                 if (dir == -1 || dir == 0) {
6263                         ar->set_fade_out_active (!yn);
6264                 }
6265                 if (!in_command) {
6266                         begin_reversible_command (_("toggle fade active"));
6267                         in_command = true;
6268                 }
6269                 _session->add_command(new StatefulDiffCommand (ar));
6270         }
6271
6272         if (in_command) {
6273                 commit_reversible_command ();
6274         }
6275 }
6276
6277
6278 /** Update region fade visibility after its configuration has been changed */
6279 void
6280 Editor::update_region_fade_visibility ()
6281 {
6282         bool _fade_visibility = _session->config.get_show_region_fades ();
6283
6284         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6285                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6286                 if (v) {
6287                         if (_fade_visibility) {
6288                                 v->audio_view()->show_all_fades ();
6289                         } else {
6290                                 v->audio_view()->hide_all_fades ();
6291                         }
6292                 }
6293         }
6294 }
6295
6296 void
6297 Editor::set_edit_point ()
6298 {
6299         bool ignored;
6300         MusicFrame where (0, 0);
6301
6302         if (!mouse_frame (where.frame, ignored)) {
6303                 return;
6304         }
6305
6306         snap_to (where);
6307
6308         if (selection->markers.empty()) {
6309
6310                 mouse_add_new_marker (where.frame);
6311
6312         } else {
6313                 bool ignored;
6314
6315                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6316
6317                 if (loc) {
6318                         loc->move_to (where.frame, where.division);
6319                 }
6320         }
6321 }
6322
6323 void
6324 Editor::set_playhead_cursor ()
6325 {
6326         if (entered_marker) {
6327                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6328         } else {
6329                 MusicFrame where (0, 0);
6330                 bool ignored;
6331
6332                 if (!mouse_frame (where.frame, ignored)) {
6333                         return;
6334                 }
6335
6336                 snap_to (where);
6337
6338                 if (_session) {
6339                         _session->request_locate (where.frame, _session->transport_rolling());
6340                 }
6341         }
6342
6343 //not sure what this was for;  remove it for now.
6344 //      if (UIConfiguration::instance().get_follow_edits() && (!_session || !_session->config.get_external_sync())) {
6345 //              cancel_time_selection();
6346 //      }
6347
6348 }
6349
6350 void
6351 Editor::split_region ()
6352 {
6353         if (_drags->active ()) {
6354                 return;
6355         }
6356
6357         //if a range is selected, separate it
6358         if ( !selection->time.empty()) {
6359                 separate_regions_between (selection->time);
6360                 return;
6361         }
6362
6363         //if no range was selected, try to find some regions to split
6364         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
6365
6366                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6367                 const framepos_t pos = get_preferred_edit_position();
6368                 const int32_t division = get_grid_music_divisions (0);
6369                 MusicFrame where (pos, division);
6370
6371                 if (rs.empty()) {
6372                         return;
6373                 }
6374
6375                 split_regions_at (where, rs);
6376
6377         }
6378 }
6379
6380 void
6381 Editor::select_next_stripable (bool routes_only)
6382 {
6383         if (selection->tracks.empty()) {
6384                 selection->set (track_views.front());
6385                 return;
6386         }
6387
6388         TimeAxisView* current = selection->tracks.front();
6389
6390         bool valid;
6391         do {
6392                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6393
6394                         if (*i == current) {
6395                                 ++i;
6396                                 if (i != track_views.end()) {
6397                                         current = (*i);
6398                                 } else {
6399                                         current = (*(track_views.begin()));
6400                                         //selection->set (*(track_views.begin()));
6401                                 }
6402                                 break;
6403                         }
6404                 }
6405
6406                 if (routes_only) {
6407                         RouteUI* rui = dynamic_cast<RouteUI *>(current);
6408                         valid = rui && rui->route()->active();
6409                 } else {
6410                         valid = 0 != current->stripable ().get();
6411                 }
6412
6413         } while (current->hidden() || !valid);
6414
6415         selection->set (current);
6416
6417         ensure_time_axis_view_is_visible (*current, false);
6418 }
6419
6420 void
6421 Editor::select_prev_stripable (bool routes_only)
6422 {
6423         if (selection->tracks.empty()) {
6424                 selection->set (track_views.front());
6425                 return;
6426         }
6427
6428         TimeAxisView* current = selection->tracks.front();
6429
6430         bool valid;
6431         do {
6432                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6433
6434                         if (*i == current) {
6435                                 ++i;
6436                                 if (i != track_views.rend()) {
6437                                         current = (*i);
6438                                 } else {
6439                                         current = *(track_views.rbegin());
6440                                 }
6441                                 break;
6442                         }
6443                 }
6444                 if (routes_only) {
6445                         RouteUI* rui = dynamic_cast<RouteUI *>(current);
6446                         valid = rui && rui->route()->active();
6447                 } else {
6448                         valid = 0 != current->stripable ().get();
6449                 }
6450
6451         } while (current->hidden() || !valid);
6452
6453         selection->set (current);
6454
6455         ensure_time_axis_view_is_visible (*current, false);
6456 }
6457
6458 void
6459 Editor::set_loop_from_selection (bool play)
6460 {
6461         if (_session == 0) {
6462                 return;
6463         }
6464
6465         framepos_t start, end;
6466         if (!get_selection_extents ( start, end))
6467                 return;
6468
6469         set_loop_range (start, end,  _("set loop range from selection"));
6470
6471         if (play) {
6472                 _session->request_play_loop (true, true);
6473         }
6474 }
6475
6476 void
6477 Editor::set_loop_from_region (bool play)
6478 {
6479         framepos_t start, end;
6480         if (!get_selection_extents ( start, end))
6481                 return;
6482
6483         set_loop_range (start, end, _("set loop range from region"));
6484
6485         if (play) {
6486                 _session->request_locate (start, true);
6487                 _session->request_play_loop (true);
6488         }
6489 }
6490
6491 void
6492 Editor::set_punch_from_selection ()
6493 {
6494         if (_session == 0) {
6495                 return;
6496         }
6497
6498         framepos_t start, end;
6499         if (!get_selection_extents ( start, end))
6500                 return;
6501
6502         set_punch_range (start, end,  _("set punch range from selection"));
6503 }
6504
6505 void
6506 Editor::set_auto_punch_range ()
6507 {
6508         // auto punch in/out button from a single button
6509         // If Punch In is unset, set punch range from playhead to end, enable punch in
6510         // If Punch In is set, the next punch sets Punch Out, unless the playhead has been
6511         //   rewound beyond the Punch In marker, in which case that marker will be moved back
6512         //   to the current playhead position.
6513         // If punch out is set, it clears the punch range and Punch In/Out buttons
6514
6515         if (_session == 0) {
6516                 return;
6517         }
6518
6519         Location* tpl = transport_punch_location();
6520         framepos_t now = playhead_cursor->current_frame();
6521         framepos_t begin = now;
6522         framepos_t end = _session->current_end_frame();
6523
6524         if (!_session->config.get_punch_in()) {
6525                 // First Press - set punch in and create range from here to eternity
6526                 set_punch_range (begin, end, _("Auto Punch In"));
6527                 _session->config.set_punch_in(true);
6528         } else if (tpl && !_session->config.get_punch_out()) {
6529                 // Second press - update end range marker and set punch_out
6530                 if (now < tpl->start()) {
6531                         // playhead has been rewound - move start back  and pretend nothing happened
6532                         begin = now;
6533                         set_punch_range (begin, end, _("Auto Punch In/Out"));
6534                 } else {
6535                         // normal case for 2nd press - set the punch out
6536                         end = playhead_cursor->current_frame ();
6537                         set_punch_range (tpl->start(), now, _("Auto Punch In/Out"));
6538                         _session->config.set_punch_out(true);
6539                 }
6540         } else  {
6541                 if (_session->config.get_punch_out()) {
6542                         _session->config.set_punch_out(false);
6543                 }
6544
6545                 if (_session->config.get_punch_in()) {
6546                         _session->config.set_punch_in(false);
6547                 }
6548
6549                 if (tpl)
6550                 {
6551                         // third press - unset punch in/out and remove range
6552                         _session->locations()->remove(tpl);
6553                 }
6554         }
6555
6556 }
6557
6558 void
6559 Editor::set_session_extents_from_selection ()
6560 {
6561         if (_session == 0) {
6562                 return;
6563         }
6564
6565         framepos_t start, end;
6566         if (!get_selection_extents ( start, end))
6567                 return;
6568
6569         Location* loc;
6570         if ((loc = _session->locations()->session_range_location()) == 0) {
6571                 _session->set_session_extents (start, end);  // this will create a new session range;  no need for UNDO
6572         } else {
6573                 XMLNode &before = loc->get_state();
6574
6575                 _session->set_session_extents (start, end);
6576
6577                 XMLNode &after = loc->get_state();
6578
6579                 begin_reversible_command (_("set session start/end from selection"));
6580
6581                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6582
6583                 commit_reversible_command ();
6584         }
6585
6586         _session->set_end_is_free (false);
6587 }
6588
6589 void
6590 Editor::set_punch_start_from_edit_point ()
6591 {
6592         if (_session) {
6593
6594                 MusicFrame start (0, 0);
6595                 framepos_t end = max_framepos;
6596
6597                 //use the existing punch end, if any
6598                 Location* tpl = transport_punch_location();
6599                 if (tpl) {
6600                         end = tpl->end();
6601                 }
6602
6603                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6604                         start.frame = _session->audible_frame();
6605                 } else {
6606                         start.frame = get_preferred_edit_position();
6607                 }
6608
6609                 //snap the selection start/end
6610                 snap_to(start);
6611
6612                 //if there's not already a sensible selection endpoint, go "forever"
6613                 if (start.frame > end ) {
6614                         end = max_framepos;
6615                 }
6616
6617                 set_punch_range (start.frame, end, _("set punch start from EP"));
6618         }
6619
6620 }
6621
6622 void
6623 Editor::set_punch_end_from_edit_point ()
6624 {
6625         if (_session) {
6626
6627                 framepos_t start = 0;
6628                 MusicFrame end (max_framepos, 0);
6629
6630                 //use the existing punch start, if any
6631                 Location* tpl = transport_punch_location();
6632                 if (tpl) {
6633                         start = tpl->start();
6634                 }
6635
6636                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6637                         end.frame = _session->audible_frame();
6638                 } else {
6639                         end.frame = get_preferred_edit_position();
6640                 }
6641
6642                 //snap the selection start/end
6643                 snap_to (end);
6644
6645                 set_punch_range (start, end.frame, _("set punch end from EP"));
6646
6647         }
6648 }
6649
6650 void
6651 Editor::set_loop_start_from_edit_point ()
6652 {
6653         if (_session) {
6654
6655                 MusicFrame start (0, 0);
6656                 framepos_t end = max_framepos;
6657
6658                 //use the existing loop end, if any
6659                 Location* tpl = transport_loop_location();
6660                 if (tpl) {
6661                         end = tpl->end();
6662                 }
6663
6664                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6665                         start.frame = _session->audible_frame();
6666                 } else {
6667                         start.frame = get_preferred_edit_position();
6668                 }
6669
6670                 //snap the selection start/end
6671                 snap_to (start);
6672
6673                 //if there's not already a sensible selection endpoint, go "forever"
6674                 if (start.frame > end ) {
6675                         end = max_framepos;
6676                 }
6677
6678                 set_loop_range (start.frame, end, _("set loop start from EP"));
6679         }
6680
6681 }
6682
6683 void
6684 Editor::set_loop_end_from_edit_point ()
6685 {
6686         if (_session) {
6687
6688                 framepos_t start = 0;
6689                 MusicFrame end (max_framepos, 0);
6690
6691                 //use the existing loop start, if any
6692                 Location* tpl = transport_loop_location();
6693                 if (tpl) {
6694                         start = tpl->start();
6695                 }
6696
6697                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6698                         end.frame = _session->audible_frame();
6699                 } else {
6700                         end.frame = get_preferred_edit_position();
6701                 }
6702
6703                 //snap the selection start/end
6704                 snap_to(end);
6705
6706                 set_loop_range (start, end.frame, _("set loop end from EP"));
6707         }
6708 }
6709
6710 void
6711 Editor::set_punch_from_region ()
6712 {
6713         framepos_t start, end;
6714         if (!get_selection_extents ( start, end))
6715                 return;
6716
6717         set_punch_range (start, end, _("set punch range from region"));
6718 }
6719
6720 void
6721 Editor::pitch_shift_region ()
6722 {
6723         RegionSelection rs = get_regions_from_selection_and_entered ();
6724
6725         RegionSelection audio_rs;
6726         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6727                 if (dynamic_cast<AudioRegionView*> (*i)) {
6728                         audio_rs.push_back (*i);
6729                 }
6730         }
6731
6732         if (audio_rs.empty()) {
6733                 return;
6734         }
6735
6736         pitch_shift (audio_rs, 1.2);
6737 }
6738
6739 void
6740 Editor::set_tempo_from_region ()
6741 {
6742         RegionSelection rs = get_regions_from_selection_and_entered ();
6743
6744         if (!_session || rs.empty()) {
6745                 return;
6746         }
6747
6748         RegionView* rv = rs.front();
6749
6750         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6751 }
6752
6753 void
6754 Editor::use_range_as_bar ()
6755 {
6756         framepos_t start, end;
6757         if (get_edit_op_range (start, end)) {
6758                 define_one_bar (start, end);
6759         }
6760 }
6761
6762 void
6763 Editor::define_one_bar (framepos_t start, framepos_t end)
6764 {
6765         framepos_t length = end - start;
6766
6767         const Meter& m (_session->tempo_map().meter_at_frame (start));
6768
6769         /* length = 1 bar */
6770
6771         /* We're going to deliver a constant tempo here,
6772            so we can use frames per beat to determine length.
6773            now we want frames per beat.
6774            we have frames per bar, and beats per bar, so ...
6775         */
6776
6777         /* XXXX METER MATH */
6778
6779         double frames_per_beat = length / m.divisions_per_bar();
6780
6781         /* beats per minute = */
6782
6783         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6784
6785         /* now decide whether to:
6786
6787             (a) set global tempo
6788             (b) add a new tempo marker
6789
6790         */
6791
6792         const TempoSection& t (_session->tempo_map().tempo_section_at_frame (start));
6793
6794         bool do_global = false;
6795
6796         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6797
6798                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6799                    at the start, or create a new marker
6800                 */
6801
6802                 vector<string> options;
6803                 options.push_back (_("Cancel"));
6804                 options.push_back (_("Add new marker"));
6805                 options.push_back (_("Set global tempo"));
6806
6807                 Choice c (
6808                         _("Define one bar"),
6809                         _("Do you want to set the global tempo or add a new tempo marker?"),
6810                         options
6811                         );
6812
6813                 c.set_default_response (2);
6814
6815                 switch (c.run()) {
6816                 case 0:
6817                         return;
6818
6819                 case 2:
6820                         do_global = true;
6821                         break;
6822
6823                 default:
6824                         do_global = false;
6825                 }
6826
6827         } else {
6828
6829                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6830                    if the marker is at the region starter, change it, otherwise add
6831                    a new tempo marker
6832                 */
6833         }
6834
6835         begin_reversible_command (_("set tempo from region"));
6836         XMLNode& before (_session->tempo_map().get_state());
6837
6838         if (do_global) {
6839                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6840         } else if (t.frame() == start) {
6841                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type(), t.end_note_types_per_minute());
6842         } else {
6843                 /* constant tempo */
6844                 const Tempo tempo (beats_per_minute, t.note_type());
6845                 _session->tempo_map().add_tempo (tempo, 0.0, start, AudioTime);
6846         }
6847
6848         XMLNode& after (_session->tempo_map().get_state());
6849
6850         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6851         commit_reversible_command ();
6852 }
6853
6854 void
6855 Editor::split_region_at_transients ()
6856 {
6857         AnalysisFeatureList positions;
6858
6859         RegionSelection rs = get_regions_from_selection_and_entered ();
6860
6861         if (!_session || rs.empty()) {
6862                 return;
6863         }
6864
6865         begin_reversible_command (_("split regions"));
6866
6867         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6868
6869                 RegionSelection::iterator tmp;
6870
6871                 tmp = i;
6872                 ++tmp;
6873
6874                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6875
6876                 if (ar) {
6877                         ar->transients (positions);
6878                         split_region_at_points ((*i)->region(), positions, true);
6879                         positions.clear ();
6880                 }
6881
6882                 i = tmp;
6883         }
6884
6885         commit_reversible_command ();
6886
6887 }
6888
6889 void
6890 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6891 {
6892         bool use_rhythmic_rodent = false;
6893
6894         boost::shared_ptr<Playlist> pl = r->playlist();
6895
6896         list<boost::shared_ptr<Region> > new_regions;
6897
6898         if (!pl) {
6899                 return;
6900         }
6901
6902         if (positions.empty()) {
6903                 return;
6904         }
6905
6906         if (positions.size() > 20 && can_ferret) {
6907                 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);
6908                 MessageDialog msg (msgstr,
6909                                    false,
6910                                    Gtk::MESSAGE_INFO,
6911                                    Gtk::BUTTONS_OK_CANCEL);
6912
6913                 if (can_ferret) {
6914                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6915                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6916                 } else {
6917                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6918                 }
6919
6920                 msg.set_title (_("Excessive split?"));
6921                 msg.present ();
6922
6923                 int response = msg.run();
6924                 msg.hide ();
6925
6926                 switch (response) {
6927                 case RESPONSE_OK:
6928                         break;
6929                 case RESPONSE_APPLY:
6930                         use_rhythmic_rodent = true;
6931                         break;
6932                 default:
6933                         return;
6934                 }
6935         }
6936
6937         if (use_rhythmic_rodent) {
6938                 show_rhythm_ferret ();
6939                 return;
6940         }
6941
6942         AnalysisFeatureList::const_iterator x;
6943
6944         pl->clear_changes ();
6945         pl->clear_owned_changes ();
6946
6947         x = positions.begin();
6948
6949         if (x == positions.end()) {
6950                 return;
6951         }
6952
6953         pl->freeze ();
6954         pl->remove_region (r);
6955
6956         framepos_t pos = 0;
6957
6958         framepos_t rstart = r->first_frame ();
6959         framepos_t rend = r->last_frame ();
6960
6961         while (x != positions.end()) {
6962
6963                 /* deal with positons that are out of scope of present region bounds */
6964                 if (*x <= rstart || *x > rend) {
6965                         ++x;
6966                         continue;
6967                 }
6968
6969                 /* file start = original start + how far we from the initial position ?  */
6970
6971                 framepos_t file_start = r->start() + pos;
6972
6973                 /* length = next position - current position */
6974
6975                 framepos_t len = (*x) - pos - rstart;
6976
6977                 /* XXX we do we really want to allow even single-sample regions?
6978                  * shouldn't we have some kind of lower limit on region size?
6979                  */
6980
6981                 if (len <= 0) {
6982                         break;
6983                 }
6984
6985                 string new_name;
6986
6987                 if (RegionFactory::region_name (new_name, r->name())) {
6988                         break;
6989                 }
6990
6991                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6992
6993                 PropertyList plist;
6994
6995                 plist.add (ARDOUR::Properties::start, file_start);
6996                 plist.add (ARDOUR::Properties::length, len);
6997                 plist.add (ARDOUR::Properties::name, new_name);
6998                 plist.add (ARDOUR::Properties::layer, 0);
6999                 // TODO set transients_offset
7000
7001                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7002                 /* because we set annouce to false, manually add the new region to the
7003                  * RegionFactory map
7004                  */
7005                 RegionFactory::map_add (nr);
7006
7007                 pl->add_region (nr, rstart + pos);
7008
7009                 if (select_new) {
7010                         new_regions.push_front(nr);
7011                 }
7012
7013                 pos += len;
7014                 ++x;
7015         }
7016
7017         string new_name;
7018
7019         RegionFactory::region_name (new_name, r->name());
7020
7021         /* Add the final region */
7022         PropertyList plist;
7023
7024         plist.add (ARDOUR::Properties::start, r->start() + pos);
7025         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
7026         plist.add (ARDOUR::Properties::name, new_name);
7027         plist.add (ARDOUR::Properties::layer, 0);
7028
7029         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
7030         /* because we set annouce to false, manually add the new region to the
7031            RegionFactory map
7032         */
7033         RegionFactory::map_add (nr);
7034         pl->add_region (nr, r->position() + pos);
7035
7036         if (select_new) {
7037                 new_regions.push_front(nr);
7038         }
7039
7040         pl->thaw ();
7041
7042         /* We might have removed regions, which alters other regions' layering_index,
7043            so we need to do a recursive diff here.
7044         */
7045         vector<Command*> cmds;
7046         pl->rdiff (cmds);
7047         _session->add_commands (cmds);
7048
7049         _session->add_command (new StatefulDiffCommand (pl));
7050
7051         if (select_new) {
7052
7053                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
7054                         set_selected_regionview_from_region_list ((*i), Selection::Add);
7055                 }
7056         }
7057 }
7058
7059 void
7060 Editor::place_transient()
7061 {
7062         if (!_session) {
7063                 return;
7064         }
7065
7066         RegionSelection rs = get_regions_from_selection_and_edit_point ();
7067
7068         if (rs.empty()) {
7069                 return;
7070         }
7071
7072         framepos_t where = get_preferred_edit_position();
7073
7074         begin_reversible_command (_("place transient"));
7075
7076         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7077                 (*r)->region()->add_transient(where);
7078         }
7079
7080         commit_reversible_command ();
7081 }
7082
7083 void
7084 Editor::remove_transient(ArdourCanvas::Item* item)
7085 {
7086         if (!_session) {
7087                 return;
7088         }
7089
7090         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
7091         assert (_line);
7092
7093         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
7094         _arv->remove_transient (*(float*) _line->get_data ("position"));
7095 }
7096
7097 void
7098 Editor::snap_regions_to_grid ()
7099 {
7100         list <boost::shared_ptr<Playlist > > used_playlists;
7101
7102         RegionSelection rs = get_regions_from_selection_and_entered ();
7103
7104         if (!_session || rs.empty()) {
7105                 return;
7106         }
7107
7108         begin_reversible_command (_("snap regions to grid"));
7109
7110         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7111
7112                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7113
7114                 if (!pl->frozen()) {
7115                         /* we haven't seen this playlist before */
7116
7117                         /* remember used playlists so we can thaw them later */
7118                         used_playlists.push_back(pl);
7119                         pl->freeze();
7120                 }
7121                 (*r)->region()->clear_changes ();
7122
7123                 MusicFrame start ((*r)->region()->first_frame (), 0);
7124                 snap_to (start);
7125                 (*r)->region()->set_position (start.frame, start.division);
7126                 _session->add_command(new StatefulDiffCommand ((*r)->region()));
7127         }
7128
7129         while (used_playlists.size() > 0) {
7130                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7131                 (*i)->thaw();
7132                 used_playlists.pop_front();
7133         }
7134
7135         commit_reversible_command ();
7136 }
7137
7138 void
7139 Editor::close_region_gaps ()
7140 {
7141         list <boost::shared_ptr<Playlist > > used_playlists;
7142
7143         RegionSelection rs = get_regions_from_selection_and_entered ();
7144
7145         if (!_session || rs.empty()) {
7146                 return;
7147         }
7148
7149         Dialog dialog (_("Close Region Gaps"));
7150
7151         Table table (2, 3);
7152         table.set_spacings (12);
7153         table.set_border_width (12);
7154         Label* l = manage (left_aligned_label (_("Crossfade length")));
7155         table.attach (*l, 0, 1, 0, 1);
7156
7157         SpinButton spin_crossfade (1, 0);
7158         spin_crossfade.set_range (0, 15);
7159         spin_crossfade.set_increments (1, 1);
7160         spin_crossfade.set_value (5);
7161         table.attach (spin_crossfade, 1, 2, 0, 1);
7162
7163         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
7164
7165         l = manage (left_aligned_label (_("Pull-back length")));
7166         table.attach (*l, 0, 1, 1, 2);
7167
7168         SpinButton spin_pullback (1, 0);
7169         spin_pullback.set_range (0, 100);
7170         spin_pullback.set_increments (1, 1);
7171         spin_pullback.set_value(30);
7172         table.attach (spin_pullback, 1, 2, 1, 2);
7173
7174         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
7175
7176         dialog.get_vbox()->pack_start (table);
7177         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
7178         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
7179         dialog.show_all ();
7180
7181         if (dialog.run () == RESPONSE_CANCEL) {
7182                 return;
7183         }
7184
7185         framepos_t crossfade_len = spin_crossfade.get_value();
7186         framepos_t pull_back_frames = spin_pullback.get_value();
7187
7188         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
7189         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
7190
7191         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
7192
7193         begin_reversible_command (_("close region gaps"));
7194
7195         int idx = 0;
7196         boost::shared_ptr<Region> last_region;
7197
7198         rs.sort_by_position_and_track();
7199
7200         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7201
7202                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
7203
7204                 if (!pl->frozen()) {
7205                         /* we haven't seen this playlist before */
7206
7207                         /* remember used playlists so we can thaw them later */
7208                         used_playlists.push_back(pl);
7209                         pl->freeze();
7210                 }
7211
7212                 framepos_t position = (*r)->region()->position();
7213
7214                 if (idx == 0 || position < last_region->position()){
7215                         last_region = (*r)->region();
7216                         idx++;
7217                         continue;
7218                 }
7219
7220                 (*r)->region()->clear_changes ();
7221                 (*r)->region()->trim_front( (position - pull_back_frames));
7222
7223                 last_region->clear_changes ();
7224                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7225
7226                 _session->add_command (new StatefulDiffCommand ((*r)->region()));
7227                 _session->add_command (new StatefulDiffCommand (last_region));
7228
7229                 last_region = (*r)->region();
7230                 idx++;
7231         }
7232
7233         while (used_playlists.size() > 0) {
7234                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7235                 (*i)->thaw();
7236                 used_playlists.pop_front();
7237         }
7238
7239         commit_reversible_command ();
7240 }
7241
7242 void
7243 Editor::tab_to_transient (bool forward)
7244 {
7245         AnalysisFeatureList positions;
7246
7247         RegionSelection rs = get_regions_from_selection_and_entered ();
7248
7249         if (!_session) {
7250                 return;
7251         }
7252
7253         framepos_t pos = _session->audible_frame ();
7254
7255         if (!selection->tracks.empty()) {
7256
7257                 /* don't waste time searching for transients in duplicate playlists.
7258                  */
7259
7260                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7261
7262                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7263
7264                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7265
7266                         if (rtv) {
7267                                 boost::shared_ptr<Track> tr = rtv->track();
7268                                 if (tr) {
7269                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
7270                                         if (pl) {
7271                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7272
7273                                                 if (result >= 0) {
7274                                                         positions.push_back (result);
7275                                                 }
7276                                         }
7277                                 }
7278                         }
7279                 }
7280
7281         } else {
7282
7283                 if (rs.empty()) {
7284                         return;
7285                 }
7286
7287                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7288                         (*r)->region()->get_transients (positions);
7289                 }
7290         }
7291
7292         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7293
7294         if (forward) {
7295                 AnalysisFeatureList::iterator x;
7296
7297                 for (x = positions.begin(); x != positions.end(); ++x) {
7298                         if ((*x) > pos) {
7299                                 break;
7300                         }
7301                 }
7302
7303                 if (x != positions.end ()) {
7304                         _session->request_locate (*x);
7305                 }
7306
7307         } else {
7308                 AnalysisFeatureList::reverse_iterator x;
7309
7310                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7311                         if ((*x) < pos) {
7312                                 break;
7313                         }
7314                 }
7315
7316                 if (x != positions.rend ()) {
7317                         _session->request_locate (*x);
7318                 }
7319         }
7320 }
7321
7322 void
7323 Editor::playhead_forward_to_grid ()
7324 {
7325         if (!_session) {
7326                 return;
7327         }
7328
7329         MusicFrame pos (playhead_cursor->current_frame (), 0);
7330
7331         if (pos.frame < max_framepos - 1) {
7332                 pos.frame += 2;
7333                 snap_to_internal (pos, RoundUpAlways, false, true);
7334                 _session->request_locate (pos.frame);
7335         }
7336 }
7337
7338
7339 void
7340 Editor::playhead_backward_to_grid ()
7341 {
7342         if (!_session) {
7343                 return;
7344         }
7345
7346         MusicFrame pos  (playhead_cursor->current_frame (), 0);
7347
7348         if (pos.frame > 2) {
7349                 pos.frame -= 2;
7350                 snap_to_internal (pos, RoundDownAlways, false, true);
7351                 _session->request_locate (pos.frame);
7352         }
7353 }
7354
7355 void
7356 Editor::set_track_height (Height h)
7357 {
7358         TrackSelection& ts (selection->tracks);
7359
7360         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7361                 (*x)->set_height_enum (h);
7362         }
7363 }
7364
7365 void
7366 Editor::toggle_tracks_active ()
7367 {
7368         TrackSelection& ts (selection->tracks);
7369         bool first = true;
7370         bool target = false;
7371
7372         if (ts.empty()) {
7373                 return;
7374         }
7375
7376         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7377                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7378
7379                 if (rtv) {
7380                         if (first) {
7381                                 target = !rtv->_route->active();
7382                                 first = false;
7383                         }
7384                         rtv->_route->set_active (target, this);
7385                 }
7386         }
7387 }
7388
7389 void
7390 Editor::remove_tracks ()
7391 {
7392         /* this will delete GUI objects that may be the subject of an event
7393            handler in which this method is called. Defer actual deletion to the
7394            next idle callback, when all event handling is finished.
7395         */
7396         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7397 }
7398
7399 bool
7400 Editor::idle_remove_tracks ()
7401 {
7402         Session::StateProtector sp (_session);
7403         _remove_tracks ();
7404         return false; /* do not call again */
7405 }
7406
7407 void
7408 Editor::_remove_tracks ()
7409 {
7410         TrackSelection& ts (selection->tracks);
7411
7412         if (ts.empty()) {
7413                 return;
7414         }
7415
7416         vector<string> choices;
7417         string prompt;
7418         int ntracks = 0;
7419         int nbusses = 0;
7420         int nvcas = 0;
7421         const char* trackstr;
7422         const char* busstr;
7423         const char* vcastr;
7424         vector<boost::shared_ptr<Route> > routes;
7425         vector<boost::shared_ptr<VCA> > vcas;
7426         bool special_bus = false;
7427
7428         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7429                 VCATimeAxisView* vtv = dynamic_cast<VCATimeAxisView*> (*x);
7430                 if (vtv) {
7431                         vcas.push_back (vtv->vca());
7432                         ++nvcas;
7433                         continue;
7434                 }
7435                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7436                 if (!rtv) {
7437                         continue;
7438                 }
7439                 if (rtv->is_track()) {
7440                         ++ntracks;
7441                 } else {
7442                         ++nbusses;
7443                 }
7444                 routes.push_back (rtv->_route);
7445
7446                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7447                         special_bus = true;
7448                 }
7449         }
7450
7451         if (special_bus && !Config->get_allow_special_bus_removal()) {
7452                 MessageDialog msg (_("That would be bad news ...."),
7453                                    false,
7454                                    Gtk::MESSAGE_INFO,
7455                                    Gtk::BUTTONS_OK);
7456                 msg.set_secondary_text (string_compose (_(
7457                                                                 "Removing the master or monitor bus is such a bad idea\n\
7458 that %1 is not going to allow it.\n\
7459 \n\
7460 If you really want to do this sort of thing\n\
7461 edit your ardour.rc file to set the\n\
7462 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7463
7464                 msg.present ();
7465                 msg.run ();
7466                 return;
7467         }
7468
7469         if (ntracks + nbusses + nvcas == 0) {
7470                 return;
7471         }
7472
7473         string title;
7474
7475         trackstr = P_("track", "tracks", ntracks);
7476         busstr = P_("bus", "busses", nbusses);
7477         vcastr = P_("VCA", "VCAs", nvcas);
7478
7479         if (ntracks > 0 && nbusses > 0 && nvcas > 0) {
7480                 title = _("Remove various strips");
7481                 prompt = string_compose (_("Do you really want to remove %1 %2, %3 %4 and %5 %6?"),
7482                                                   ntracks, trackstr, nbusses, busstr, nvcas, vcastr);
7483         }
7484         else if (ntracks > 0 && nbusses > 0) {
7485                 title = string_compose (_("Remove %1 and %2"), trackstr, busstr);
7486                 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7487                                 ntracks, trackstr, nbusses, busstr);
7488         }
7489         else if (ntracks > 0 && nvcas > 0) {
7490                 title = string_compose (_("Remove %1 and %2"), trackstr, vcastr);
7491                 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7492                                 ntracks, trackstr, nvcas, vcastr);
7493         }
7494         else if (nbusses > 0 && nvcas > 0) {
7495                 title = string_compose (_("Remove %1 and %2"), busstr, vcastr);
7496                 prompt = string_compose (_("Do you really want to remove %1 %2 and %3 %4?"),
7497                                 nbusses, busstr, nvcas, vcastr);
7498         }
7499         else if (ntracks > 0) {
7500                 title = string_compose (_("Remove %1"), trackstr);
7501                 prompt  = string_compose (_("Do you really want to remove %1 %2?"),
7502                                 ntracks, trackstr);
7503         }
7504         else if (nbusses > 0) {
7505                 title = string_compose (_("Remove %1"), busstr);
7506                 prompt  = string_compose (_("Do you really want to remove %1 %2?"),
7507                                 nbusses, busstr);
7508         }
7509         else if (nvcas > 0) {
7510                 title = string_compose (_("Remove %1"), vcastr);
7511                 prompt  = string_compose (_("Do you really want to remove %1 %2?"),
7512                                 nvcas, vcastr);
7513         }
7514         else {
7515                 assert (0);
7516         }
7517
7518         if (ntracks > 0) {
7519                         prompt += "\n" + string_compose ("(You may also lose the playlists associated with the %1)", trackstr) + "\n";
7520         }
7521
7522         prompt += "\n" + string(_("This action cannot be undone, and the session file will be overwritten!"));
7523
7524         choices.push_back (_("No, do nothing."));
7525         if (ntracks + nbusses + nvcas > 1) {
7526                 choices.push_back (_("Yes, remove them."));
7527         } else {
7528                 choices.push_back (_("Yes, remove it."));
7529         }
7530
7531         Choice prompter (title, prompt, choices);
7532
7533         if (prompter.run () != 1) {
7534                 return;
7535         }
7536
7537         if (current_mixer_strip && routes.size () > 1 && std::find (routes.begin(), routes.end(), current_mixer_strip->route()) != routes.end ()) {
7538                 /* Route deletion calls Editor::timeaxisview_deleted() iteratively (for each deleted
7539                  * route). If the deleted route is currently displayed in the Editor-Mixer (highly
7540                  * likely because deletion requires selection) this will call
7541                  * Editor::set_selected_mixer_strip () which is expensive ( MixerStrip::set_route() ).
7542                  * It's likewise likely that the route that has just been displayed in the
7543                  * Editor-Mixer will be next in line for deletion.
7544                  *
7545                  * So simply switch to the master-bus (if present)
7546                  */
7547                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7548                         if ((*i)->stripable ()->is_master ()) {
7549                                 set_selected_mixer_strip (*(*i));
7550                                 break;
7551                         }
7552                 }
7553         }
7554
7555         {
7556                 PresentationInfo::ChangeSuspender cs;
7557                 DisplaySuspender ds;
7558
7559                 boost::shared_ptr<RouteList> rl (new RouteList);
7560                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7561                         rl->push_back (*x);
7562                 }
7563                 _session->remove_routes (rl);
7564
7565                 for (vector<boost::shared_ptr<VCA> >::iterator x = vcas.begin(); x != vcas.end(); ++x) {
7566                         _session->vca_manager().remove_vca (*x);
7567                 }
7568
7569         }
7570         /* TrackSelection and RouteList leave scope,
7571          * destructors are called,
7572          * diskstream drops references, save_state is called (again for every track)
7573          */
7574 }
7575
7576 void
7577 Editor::do_insert_time ()
7578 {
7579         if (selection->tracks.empty()) {
7580                 return;
7581         }
7582
7583         InsertRemoveTimeDialog d (*this);
7584         int response = d.run ();
7585
7586         if (response != RESPONSE_OK) {
7587                 return;
7588         }
7589
7590         if (d.distance() == 0) {
7591                 return;
7592         }
7593
7594         insert_time (
7595                 d.position(),
7596                 d.distance(),
7597                 d.intersected_region_action (),
7598                 d.all_playlists(),
7599                 d.move_glued(),
7600                 d.move_markers(),
7601                 d.move_glued_markers(),
7602                 d.move_locked_markers(),
7603                 d.move_tempos()
7604                 );
7605 }
7606
7607 void
7608 Editor::insert_time (
7609         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7610         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7611         )
7612 {
7613
7614         if (Config->get_edit_mode() == Lock) {
7615                 return;
7616         }
7617         bool in_command = false;
7618
7619         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7620
7621         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7622
7623                 /* regions */
7624
7625                 /* don't operate on any playlist more than once, which could
7626                  * happen if "all playlists" is enabled, but there is more
7627                  * than 1 track using playlists "from" a given track.
7628                  */
7629
7630                 set<boost::shared_ptr<Playlist> > pl;
7631
7632                 if (all_playlists) {
7633                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7634                         if (rtav && rtav->track ()) {
7635                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7636                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7637                                         pl.insert (*p);
7638                                 }
7639                         }
7640                 } else {
7641                         if ((*x)->playlist ()) {
7642                                 pl.insert ((*x)->playlist ());
7643                         }
7644                 }
7645
7646                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7647
7648                         (*i)->clear_changes ();
7649                         (*i)->clear_owned_changes ();
7650
7651                         if (!in_command) {
7652                                 begin_reversible_command (_("insert time"));
7653                                 in_command = true;
7654                         }
7655
7656                         if (opt == SplitIntersected) {
7657                                 /* non musical split */
7658                                 (*i)->split (MusicFrame (pos, 0));
7659                         }
7660
7661                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7662
7663                         vector<Command*> cmds;
7664                         (*i)->rdiff (cmds);
7665                         _session->add_commands (cmds);
7666
7667                         _session->add_command (new StatefulDiffCommand (*i));
7668                 }
7669
7670                 /* automation */
7671                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7672                 if (rtav) {
7673                         if (!in_command) {
7674                                 begin_reversible_command (_("insert time"));
7675                                 in_command = true;
7676                         }
7677                         rtav->route ()->shift (pos, frames);
7678                 }
7679         }
7680
7681         /* markers */
7682         if (markers_too) {
7683                 bool moved = false;
7684                 const int32_t divisions = get_grid_music_divisions (0);
7685                 XMLNode& before (_session->locations()->get_state());
7686                 Locations::LocationList copy (_session->locations()->list());
7687
7688                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7689
7690                         Locations::LocationList::const_iterator tmp;
7691
7692                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7693                                 bool const was_locked = (*i)->locked ();
7694                                 if (locked_markers_too) {
7695                                         (*i)->unlock ();
7696                                 }
7697
7698                                 if ((*i)->start() >= pos) {
7699                                         // move end first, in case we're moving by more than the length of the range
7700                                         if (!(*i)->is_mark()) {
7701                                                 (*i)->set_end ((*i)->end() + frames, false, true, divisions);
7702                                         }
7703                                         (*i)->set_start ((*i)->start() + frames, false, true, divisions);
7704                                         moved = true;
7705                                 }
7706
7707                                 if (was_locked) {
7708                                         (*i)->lock ();
7709                                 }
7710                         }
7711                 }
7712
7713                 if (moved) {
7714                         if (!in_command) {
7715                                 begin_reversible_command (_("insert time"));
7716                                 in_command = true;
7717                         }
7718                         XMLNode& after (_session->locations()->get_state());
7719                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7720                 }
7721         }
7722
7723         if (tempo_too) {
7724                 if (!in_command) {
7725                         begin_reversible_command (_("insert time"));
7726                         in_command = true;
7727                 }
7728                 XMLNode& before (_session->tempo_map().get_state());
7729                 _session->tempo_map().insert_time (pos, frames);
7730                 XMLNode& after (_session->tempo_map().get_state());
7731                 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7732         }
7733
7734         if (in_command) {
7735                 commit_reversible_command ();
7736         }
7737 }
7738
7739 void
7740 Editor::do_remove_time ()
7741 {
7742         if (selection->tracks.empty()) {
7743                 return;
7744         }
7745
7746         InsertRemoveTimeDialog d (*this, true);
7747
7748         int response = d.run ();
7749
7750         if (response != RESPONSE_OK) {
7751                 return;
7752         }
7753
7754         framecnt_t distance = d.distance();
7755
7756         if (distance == 0) {
7757                 return;
7758         }
7759
7760         remove_time (
7761                 d.position(),
7762                 distance,
7763                 SplitIntersected,
7764                 d.move_glued(),
7765                 d.move_markers(),
7766                 d.move_glued_markers(),
7767                 d.move_locked_markers(),
7768                 d.move_tempos()
7769         );
7770 }
7771
7772 void
7773 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7774                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7775 {
7776         if (Config->get_edit_mode() == Lock) {
7777                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7778                 return;
7779         }
7780         bool in_command = false;
7781
7782         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7783                 /* regions */
7784                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7785
7786                 if (pl) {
7787
7788                         XMLNode &before = pl->get_state();
7789
7790                         if (!in_command) {
7791                                 begin_reversible_command (_("remove time"));
7792                                 in_command = true;
7793                         }
7794
7795                         std::list<AudioRange> rl;
7796                         AudioRange ar(pos, pos+frames, 0);
7797                         rl.push_back(ar);
7798                         pl->cut (rl);
7799                         pl->shift (pos, -frames, true, ignore_music_glue);
7800
7801                         XMLNode &after = pl->get_state();
7802
7803                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7804                 }
7805
7806                 /* automation */
7807                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7808                 if (rtav) {
7809                         if (!in_command) {
7810                                 begin_reversible_command (_("remove time"));
7811                                 in_command = true;
7812                         }
7813                         rtav->route ()->shift (pos, -frames);
7814                 }
7815         }
7816
7817         const int32_t divisions = get_grid_music_divisions (0);
7818         std::list<Location*> loc_kill_list;
7819
7820         /* markers */
7821         if (markers_too) {
7822                 bool moved = false;
7823                 XMLNode& before (_session->locations()->get_state());
7824                 Locations::LocationList copy (_session->locations()->list());
7825
7826                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7827                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7828
7829                                 bool const was_locked = (*i)->locked ();
7830                                 if (locked_markers_too) {
7831                                         (*i)->unlock ();
7832                                 }
7833
7834                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7835                                         if ((*i)->end() >= pos
7836                                         && (*i)->end() < pos+frames
7837                                         && (*i)->start() >= pos
7838                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7839                                                 moved = true;
7840                                                 loc_kill_list.push_back(*i);
7841                                         } else {  // only start or end is included, try to do the right thing
7842                                                 // move start before moving end, to avoid trying to move the end to before the start
7843                                                 // if we're removing more time than the length of the range
7844                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7845                                                         // start is within cut
7846                                                         (*i)->set_start (pos, false, true,divisions);  // bring the start marker to the beginning of the cut
7847                                                         moved = true;
7848                                                 } else if ((*i)->start() >= pos+frames) {
7849                                                         // start (and thus entire range) lies beyond end of cut
7850                                                         (*i)->set_start ((*i)->start() - frames, false, true, divisions); // slip the start marker back
7851                                                         moved = true;
7852                                                 }
7853                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7854                                                         // end is inside cut
7855                                                         (*i)->set_end (pos, false, true, divisions);  // bring the end to the cut
7856                                                         moved = true;
7857                                                 } else if ((*i)->end() >= pos+frames) {
7858                                                         // end is beyond end of cut
7859                                                         (*i)->set_end ((*i)->end() - frames, false, true, divisions); // slip the end marker back
7860                                                         moved = true;
7861                                                 }
7862
7863                                         }
7864                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7865                                         loc_kill_list.push_back(*i);
7866                                         moved = true;
7867                                 } else if ((*i)->start() >= pos) {
7868                                         (*i)->set_start ((*i)->start() -frames, false, true, divisions);
7869                                         moved = true;
7870                                 }
7871
7872                                 if (was_locked) {
7873                                         (*i)->lock ();
7874                                 }
7875                         }
7876                 }
7877
7878                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7879                         _session->locations()->remove( *i );
7880                 }
7881
7882                 if (moved) {
7883                         if (!in_command) {
7884                                 begin_reversible_command (_("remove time"));
7885                                 in_command = true;
7886                         }
7887                         XMLNode& after (_session->locations()->get_state());
7888                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7889                 }
7890         }
7891
7892         if (tempo_too) {
7893                 XMLNode& before (_session->tempo_map().get_state());
7894
7895                 if (_session->tempo_map().remove_time (pos, frames) ) {
7896                         if (!in_command) {
7897                                 begin_reversible_command (_("remove time"));
7898                                 in_command = true;
7899                         }
7900                         XMLNode& after (_session->tempo_map().get_state());
7901                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7902                 }
7903         }
7904
7905         if (in_command) {
7906                 commit_reversible_command ();
7907         }
7908 }
7909
7910 void
7911 Editor::fit_selection ()
7912 {
7913         if (!selection->tracks.empty()) {
7914                 fit_tracks (selection->tracks);
7915         } else {
7916                 TrackViewList tvl;
7917
7918                 /* no selected tracks - use tracks with selected regions */
7919
7920                 if (!selection->regions.empty()) {
7921                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7922                                 tvl.push_back (&(*r)->get_time_axis_view ());
7923                         }
7924
7925                         if (!tvl.empty()) {
7926                                 fit_tracks (tvl);
7927                         }
7928                 } else if (internal_editing()) {
7929                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7930                          * the entered track
7931                          */
7932                         if (entered_track) {
7933                                 tvl.push_back (entered_track);
7934                                 fit_tracks (tvl);
7935                         }
7936                 }
7937         }
7938 }
7939
7940 void
7941 Editor::fit_tracks (TrackViewList & tracks)
7942 {
7943         if (tracks.empty()) {
7944                 return;
7945         }
7946
7947         uint32_t child_heights = 0;
7948         int visible_tracks = 0;
7949
7950         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7951
7952                 if (!(*t)->marked_for_display()) {
7953                         continue;
7954                 }
7955
7956                 child_heights += (*t)->effective_height() - (*t)->current_height();
7957                 ++visible_tracks;
7958         }
7959
7960         /* compute the per-track height from:
7961          *
7962          * total canvas visible height
7963          *  - height that will be taken by visible children of selected tracks
7964          *  - height of the ruler/hscroll area
7965          */
7966         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7967         double first_y_pos = DBL_MAX;
7968
7969         if (h < TimeAxisView::preset_height (HeightSmall)) {
7970                 MessageDialog msg (_("There are too many tracks to fit in the current window"));
7971                 /* too small to be displayed */
7972                 return;
7973         }
7974
7975         undo_visual_stack.push_back (current_visual_state (true));
7976         PBD::Unwinder<bool> nsv (no_save_visual, true);
7977
7978         /* build a list of all tracks, including children */
7979
7980         TrackViewList all;
7981         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7982                 all.push_back (*i);
7983                 TimeAxisView::Children c = (*i)->get_child_list ();
7984                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7985                         all.push_back (j->get());
7986                 }
7987         }
7988
7989
7990         // find selection range.
7991         // if someone knows how to user TrackViewList::iterator for this
7992         // I'm all ears.
7993         int selected_top = -1;
7994         int selected_bottom = -1;
7995         int i = 0;
7996         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7997                 if ((*t)->marked_for_display ()) {
7998                         if (tracks.contains(*t)) {
7999                                 if (selected_top == -1) {
8000                                         selected_top = i;
8001                                 }
8002                                 selected_bottom = i;
8003                         }
8004                 }
8005         }
8006
8007         i = 0;
8008         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
8009                 if ((*t)->marked_for_display ()) {
8010                         if (tracks.contains(*t)) {
8011                                 (*t)->set_height (h);
8012                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
8013                         } else {
8014                                 if (i > selected_top && i < selected_bottom) {
8015                                         hide_track_in_display (*t);
8016                                 }
8017                         }
8018                 }
8019         }
8020
8021         /*
8022            set the controls_layout height now, because waiting for its size
8023            request signal handler will cause the vertical adjustment setting to fail
8024         */
8025
8026         controls_layout.property_height () = _full_canvas_height;
8027         vertical_adjustment.set_value (first_y_pos);
8028
8029         redo_visual_stack.push_back (current_visual_state (true));
8030
8031         visible_tracks_selector.set_text (_("Sel"));
8032 }
8033
8034 void
8035 Editor::save_visual_state (uint32_t n)
8036 {
8037         while (visual_states.size() <= n) {
8038                 visual_states.push_back (0);
8039         }
8040
8041         if (visual_states[n] != 0) {
8042                 delete visual_states[n];
8043         }
8044
8045         visual_states[n] = current_visual_state (true);
8046         gdk_beep ();
8047 }
8048
8049 void
8050 Editor::goto_visual_state (uint32_t n)
8051 {
8052         if (visual_states.size() <= n) {
8053                 return;
8054         }
8055
8056         if (visual_states[n] == 0) {
8057                 return;
8058         }
8059
8060         use_visual_state (*visual_states[n]);
8061 }
8062
8063 void
8064 Editor::start_visual_state_op (uint32_t n)
8065 {
8066         save_visual_state (n);
8067
8068         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
8069         char buf[32];
8070         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
8071         pup->set_text (buf);
8072         pup->touch();
8073 }
8074
8075 void
8076 Editor::cancel_visual_state_op (uint32_t n)
8077 {
8078         goto_visual_state (n);
8079 }
8080
8081 void
8082 Editor::toggle_region_mute ()
8083 {
8084         if (_ignore_region_action) {
8085                 return;
8086         }
8087
8088         RegionSelection rs = get_regions_from_selection_and_entered ();
8089
8090         if (rs.empty ()) {
8091                 return;
8092         }
8093
8094         if (rs.size() > 1) {
8095                 begin_reversible_command (_("mute regions"));
8096         } else {
8097                 begin_reversible_command (_("mute region"));
8098         }
8099
8100         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
8101
8102                 (*i)->region()->playlist()->clear_changes ();
8103                 (*i)->region()->set_muted (!(*i)->region()->muted ());
8104                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
8105
8106         }
8107
8108         commit_reversible_command ();
8109 }
8110
8111 void
8112 Editor::combine_regions ()
8113 {
8114         /* foreach track with selected regions, take all selected regions
8115            and join them into a new region containing the subregions (as a
8116            playlist)
8117         */
8118
8119         typedef set<RouteTimeAxisView*> RTVS;
8120         RTVS tracks;
8121
8122         if (selection->regions.empty()) {
8123                 return;
8124         }
8125
8126         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8127                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8128
8129                 if (rtv) {
8130                         tracks.insert (rtv);
8131                 }
8132         }
8133
8134         begin_reversible_command (_("combine regions"));
8135
8136         vector<RegionView*> new_selection;
8137
8138         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8139                 RegionView* rv;
8140
8141                 if ((rv = (*i)->combine_regions ()) != 0) {
8142                         new_selection.push_back (rv);
8143                 }
8144         }
8145
8146         selection->clear_regions ();
8147         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
8148                 selection->add (*i);
8149         }
8150
8151         commit_reversible_command ();
8152 }
8153
8154 void
8155 Editor::uncombine_regions ()
8156 {
8157         typedef set<RouteTimeAxisView*> RTVS;
8158         RTVS tracks;
8159
8160         if (selection->regions.empty()) {
8161                 return;
8162         }
8163
8164         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
8165                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
8166
8167                 if (rtv) {
8168                         tracks.insert (rtv);
8169                 }
8170         }
8171
8172         begin_reversible_command (_("uncombine regions"));
8173
8174         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
8175                 (*i)->uncombine_regions ();
8176         }
8177
8178         commit_reversible_command ();
8179 }
8180
8181 void
8182 Editor::toggle_midi_input_active (bool flip_others)
8183 {
8184         bool onoff = false;
8185         boost::shared_ptr<RouteList> rl (new RouteList);
8186
8187         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
8188                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
8189
8190                 if (!rtav) {
8191                         continue;
8192                 }
8193
8194                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
8195
8196                 if (mt) {
8197                         rl->push_back (rtav->route());
8198                         onoff = !mt->input_active();
8199                 }
8200         }
8201
8202         _session->set_exclusive_input_active (rl, onoff, flip_others);
8203 }
8204
8205 static bool ok_fine (GdkEventAny*) { return true; }
8206
8207 void
8208 Editor::lock ()
8209 {
8210         if (!lock_dialog) {
8211                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
8212
8213                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
8214                 lock_dialog->get_vbox()->pack_start (*padlock);
8215                 lock_dialog->signal_delete_event ().connect (sigc::ptr_fun (ok_fine));
8216
8217                 ArdourButton* b = manage (new ArdourButton);
8218                 b->set_name ("lock button");
8219                 b->set_text (_("Click to unlock"));
8220                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
8221                 lock_dialog->get_vbox()->pack_start (*b);
8222
8223                 lock_dialog->get_vbox()->show_all ();
8224                 lock_dialog->set_size_request (200, 200);
8225         }
8226
8227         delete _main_menu_disabler;
8228         _main_menu_disabler = new MainMenuDisabler;
8229
8230         lock_dialog->present ();
8231
8232         lock_dialog->get_window()->set_decorations (Gdk::WMDecoration (0));
8233 }
8234
8235 void
8236 Editor::unlock ()
8237 {
8238         lock_dialog->hide ();
8239
8240         delete _main_menu_disabler;
8241         _main_menu_disabler = 0;
8242
8243         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
8244                 start_lock_event_timing ();
8245         }
8246 }
8247
8248 void
8249 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8250 {
8251         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
8252 }
8253
8254 void
8255 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
8256 {
8257         Timers::TimerSuspender t;
8258         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
8259         Gtkmm2ext::UI::instance()->flush_pending (1);
8260 }
8261
8262 void
8263 Editor::bring_all_sources_into_session ()
8264 {
8265         if (!_session) {
8266                 return;
8267         }
8268
8269         Gtk::Label msg;
8270         ArdourDialog w (_("Moving embedded files into session folder"));
8271         w.get_vbox()->pack_start (msg);
8272         w.present ();
8273
8274         /* flush all pending GUI events because we're about to start copying
8275          * files
8276          */
8277
8278         Timers::TimerSuspender t;
8279         Gtkmm2ext::UI::instance()->flush_pending (3);
8280
8281         cerr << " Do it\n";
8282
8283         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
8284 }