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