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