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