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