resolve merge with master (?)
[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 Engine:
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
2387         entry.set_text (rs.front()->region()->name());
2388         entry.select_region (0, -1);
2389
2390         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2391
2392         d.show_all ();
2393
2394         entry.grab_focus();
2395
2396         int const ret = d.run();
2397
2398         d.hide ();
2399
2400         if (ret != RESPONSE_OK) {
2401                 return;
2402         }
2403
2404         std::string str = entry.get_text();
2405         strip_whitespace_edges (str);
2406         if (!str.empty()) {
2407                 rs.front()->region()->set_name (str);
2408                 _regions->redisplay ();
2409         }
2410 }
2411
2412 void
2413 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2414 {
2415         if (_session->is_auditioning()) {
2416                 _session->cancel_audition ();
2417         }
2418
2419         // note: some potential for creativity here, because region doesn't
2420         // have to belong to the playlist that Route is handling
2421
2422         // bool was_soloed = route.soloed();
2423
2424         route.set_solo (true, this);
2425
2426         _session->request_bounded_roll (region->position(), region->position() + region->length());
2427
2428         /* XXX how to unset the solo state ? */
2429 }
2430
2431 /** Start an audition of the first selected region */
2432 void
2433 Editor::play_edit_range ()
2434 {
2435         framepos_t start, end;
2436
2437         if (get_edit_op_range (start, end)) {
2438                 _session->request_bounded_roll (start, end);
2439         }
2440 }
2441
2442 void
2443 Editor::play_selected_region ()
2444 {
2445         framepos_t start = max_framepos;
2446         framepos_t end = 0;
2447
2448         RegionSelection rs = get_regions_from_selection_and_entered ();
2449
2450         if (rs.empty()) {
2451                 return;
2452         }
2453
2454         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2455                 if ((*i)->region()->position() < start) {
2456                         start = (*i)->region()->position();
2457                 }
2458                 if ((*i)->region()->last_frame() + 1 > end) {
2459                         end = (*i)->region()->last_frame() + 1;
2460                 }
2461         }
2462
2463         _session->request_bounded_roll (start, end);
2464 }
2465
2466 void
2467 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2468 {
2469         _session->audition_region (region);
2470 }
2471
2472 void
2473 Editor::region_from_selection ()
2474 {
2475         if (clicked_axisview == 0) {
2476                 return;
2477         }
2478
2479         if (selection->time.empty()) {
2480                 return;
2481         }
2482
2483         framepos_t start = selection->time[clicked_selection].start;
2484         framepos_t end = selection->time[clicked_selection].end;
2485
2486         TrackViewList tracks = get_tracks_for_range_action ();
2487
2488         framepos_t selection_cnt = end - start + 1;
2489
2490         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2491                 boost::shared_ptr<Region> current;
2492                 boost::shared_ptr<Playlist> pl;
2493                 framepos_t internal_start;
2494                 string new_name;
2495
2496                 if ((pl = (*i)->playlist()) == 0) {
2497                         continue;
2498                 }
2499
2500                 if ((current = pl->top_region_at (start)) == 0) {
2501                         continue;
2502                 }
2503
2504                 internal_start = start - current->position();
2505                 RegionFactory::region_name (new_name, current->name(), true);
2506
2507                 PropertyList plist;
2508
2509                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2510                 plist.add (ARDOUR::Properties::length, selection_cnt);
2511                 plist.add (ARDOUR::Properties::name, new_name);
2512                 plist.add (ARDOUR::Properties::layer, 0);
2513
2514                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2515         }
2516 }
2517
2518 void
2519 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2520 {
2521         if (selection->time.empty() || selection->tracks.empty()) {
2522                 return;
2523         }
2524
2525         framepos_t start = selection->time[clicked_selection].start;
2526         framepos_t end = selection->time[clicked_selection].end;
2527
2528         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2529         sort_track_selection (ts);
2530
2531         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2532                 boost::shared_ptr<Region> current;
2533                 boost::shared_ptr<Playlist> playlist;
2534                 framepos_t internal_start;
2535                 string new_name;
2536
2537                 if ((playlist = (*i)->playlist()) == 0) {
2538                         continue;
2539                 }
2540
2541                 if ((current = playlist->top_region_at(start)) == 0) {
2542                         continue;
2543                 }
2544
2545                 internal_start = start - current->position();
2546                 RegionFactory::region_name (new_name, current->name(), true);
2547
2548                 PropertyList plist;
2549
2550                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2551                 plist.add (ARDOUR::Properties::length, end - start + 1);
2552                 plist.add (ARDOUR::Properties::name, new_name);
2553
2554                 new_regions.push_back (RegionFactory::create (current, plist));
2555         }
2556 }
2557
2558 void
2559 Editor::split_multichannel_region ()
2560 {
2561         RegionSelection rs = get_regions_from_selection_and_entered ();
2562
2563         if (rs.empty()) {
2564                 return;
2565         }
2566
2567         vector< boost::shared_ptr<Region> > v;
2568
2569         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2570                 (*x)->region()->separate_by_channel (*_session, v);
2571         }
2572 }
2573
2574 void
2575 Editor::new_region_from_selection ()
2576 {
2577         region_from_selection ();
2578         cancel_selection ();
2579 }
2580
2581 static void
2582 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2583 {
2584         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2585         case Evoral::OverlapNone:
2586                 break;
2587         default:
2588                 rs->push_back (rv);
2589         }
2590 }
2591
2592 /** Return either:
2593  *    - selected tracks, or if there are none...
2594  *    - tracks containing selected regions, or if there are none...
2595  *    - all tracks
2596  * @return tracks.
2597  */
2598 TrackViewList
2599 Editor::get_tracks_for_range_action () const
2600 {
2601         TrackViewList t;
2602
2603         if (selection->tracks.empty()) {
2604
2605                 /* use tracks with selected regions */
2606
2607                 RegionSelection rs = selection->regions;
2608
2609                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2610                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2611
2612                         if (!t.contains (tv)) {
2613                                 t.push_back (tv);
2614                         }
2615                 }
2616
2617                 if (t.empty()) {
2618                         /* no regions and no tracks: use all tracks */
2619                         t = track_views;
2620                 }
2621
2622         } else {
2623
2624                 t = selection->tracks;
2625         }
2626
2627         return t.filter_to_unique_playlists();
2628 }
2629
2630 void
2631 Editor::separate_regions_between (const TimeSelection& ts)
2632 {
2633         bool in_command = false;
2634         boost::shared_ptr<Playlist> playlist;
2635         RegionSelection new_selection;
2636
2637         TrackViewList tmptracks = get_tracks_for_range_action ();
2638         sort_track_selection (tmptracks);
2639
2640         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2641
2642                 RouteTimeAxisView* rtv;
2643
2644                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2645
2646                         if (rtv->is_track()) {
2647
2648                                 /* no edits to destructive tracks */
2649
2650                                 if (rtv->track()->destructive()) {
2651                                         continue;
2652                                 }
2653
2654                                 if ((playlist = rtv->playlist()) != 0) {
2655
2656                                         playlist->clear_changes ();
2657
2658                                         /* XXX need to consider musical time selections here at some point */
2659
2660                                         double speed = rtv->track()->speed();
2661
2662
2663                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2664
2665                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2666                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2667
2668                                                 latest_regionviews.clear ();
2669
2670                                                 playlist->partition ((framepos_t)((*t).start * speed),
2671                                                                 (framepos_t)((*t).end * speed), false);
2672
2673                                                 c.disconnect ();
2674
2675                                                 if (!latest_regionviews.empty()) {
2676
2677                                                         rtv->view()->foreach_regionview (sigc::bind (
2678                                                                                 sigc::ptr_fun (add_if_covered),
2679                                                                                 &(*t), &new_selection));
2680
2681                                                         if (!in_command) {
2682                                                                 begin_reversible_command (_("separate"));
2683                                                                 in_command = true;
2684                                                         }
2685
2686                                                         /* pick up changes to existing regions */
2687
2688                                                         vector<Command*> cmds;
2689                                                         playlist->rdiff (cmds);
2690                                                         _session->add_commands (cmds);
2691
2692                                                         /* pick up changes to the playlist itself (adds/removes)
2693                                                          */
2694
2695                                                         _session->add_command(new StatefulDiffCommand (playlist));
2696                                                 }
2697                                         }
2698                                 }
2699                         }
2700                 }
2701         }
2702
2703         if (in_command) {
2704                 selection->set (new_selection);
2705                 set_mouse_mode (MouseObject);
2706
2707                 commit_reversible_command ();
2708         }
2709 }
2710
2711 struct PlaylistState {
2712     boost::shared_ptr<Playlist> playlist;
2713     XMLNode*  before;
2714 };
2715
2716 /** Take tracks from get_tracks_for_range_action and cut any regions
2717  *  on those tracks so that the tracks are empty over the time
2718  *  selection.
2719  */
2720 void
2721 Editor::separate_region_from_selection ()
2722 {
2723         /* preferentially use *all* ranges in the time selection if we're in range mode
2724            to allow discontiguous operation, since get_edit_op_range() currently
2725            returns a single range.
2726         */
2727
2728         if (!selection->time.empty()) {
2729
2730                 separate_regions_between (selection->time);
2731
2732         } else {
2733
2734                 framepos_t start;
2735                 framepos_t end;
2736
2737                 if (get_edit_op_range (start, end)) {
2738
2739                         AudioRange ar (start, end, 1);
2740                         TimeSelection ts;
2741                         ts.push_back (ar);
2742
2743                         separate_regions_between (ts);
2744                 }
2745         }
2746 }
2747
2748 void
2749 Editor::separate_region_from_punch ()
2750 {
2751         Location* loc  = _session->locations()->auto_punch_location();
2752         if (loc) {
2753                 separate_regions_using_location (*loc);
2754         }
2755 }
2756
2757 void
2758 Editor::separate_region_from_loop ()
2759 {
2760         Location* loc  = _session->locations()->auto_loop_location();
2761         if (loc) {
2762                 separate_regions_using_location (*loc);
2763         }
2764 }
2765
2766 void
2767 Editor::separate_regions_using_location (Location& loc)
2768 {
2769         if (loc.is_mark()) {
2770                 return;
2771         }
2772
2773         AudioRange ar (loc.start(), loc.end(), 1);
2774         TimeSelection ts;
2775
2776         ts.push_back (ar);
2777
2778         separate_regions_between (ts);
2779 }
2780
2781 /** Separate regions under the selected region */
2782 void
2783 Editor::separate_under_selected_regions ()
2784 {
2785         vector<PlaylistState> playlists;
2786
2787         RegionSelection rs;
2788
2789         rs = get_regions_from_selection_and_entered();
2790
2791         if (!_session || rs.empty()) {
2792                 return;
2793         }
2794
2795         begin_reversible_command (_("separate region under"));
2796
2797         list<boost::shared_ptr<Region> > regions_to_remove;
2798
2799         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2800                 // we can't just remove the region(s) in this loop because
2801                 // this removes them from the RegionSelection, and they thus
2802                 // disappear from underneath the iterator, and the ++i above
2803                 // SEGVs in a puzzling fashion.
2804
2805                 // so, first iterate over the regions to be removed from rs and
2806                 // add them to the regions_to_remove list, and then
2807                 // iterate over the list to actually remove them.
2808
2809                 regions_to_remove.push_back ((*i)->region());
2810         }
2811
2812         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2813
2814                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2815
2816                 if (!playlist) {
2817                         // is this check necessary?
2818                         continue;
2819                 }
2820
2821                 vector<PlaylistState>::iterator i;
2822
2823                 //only take state if this is a new playlist.
2824                 for (i = playlists.begin(); i != playlists.end(); ++i) {
2825                         if ((*i).playlist == playlist) {
2826                                 break;
2827                         }
2828                 }
2829
2830                 if (i == playlists.end()) {
2831
2832                         PlaylistState before;
2833                         before.playlist = playlist;
2834                         before.before = &playlist->get_state();
2835
2836                         playlist->freeze ();
2837                         playlists.push_back(before);
2838                 }
2839
2840                 //Partition on the region bounds
2841                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2842
2843                 //Re-add region that was just removed due to the partition operation
2844                 playlist->add_region( (*rl), (*rl)->first_frame() );
2845         }
2846
2847         vector<PlaylistState>::iterator pl;
2848
2849         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2850                 (*pl).playlist->thaw ();
2851                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2852         }
2853
2854         commit_reversible_command ();
2855 }
2856
2857 void
2858 Editor::crop_region_to_selection ()
2859 {
2860         if (!selection->time.empty()) {
2861
2862                 crop_region_to (selection->time.start(), selection->time.end_frame());
2863
2864         } else {
2865
2866                 framepos_t start;
2867                 framepos_t end;
2868
2869                 if (get_edit_op_range (start, end)) {
2870                         crop_region_to (start, end);
2871                 }
2872         }
2873
2874 }
2875
2876 void
2877 Editor::crop_region_to (framepos_t start, framepos_t end)
2878 {
2879         vector<boost::shared_ptr<Playlist> > playlists;
2880         boost::shared_ptr<Playlist> playlist;
2881         TrackViewList ts;
2882
2883         if (selection->tracks.empty()) {
2884                 ts = track_views.filter_to_unique_playlists();
2885         } else {
2886                 ts = selection->tracks.filter_to_unique_playlists ();
2887         }
2888
2889         sort_track_selection (ts);
2890
2891         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2892
2893                 RouteTimeAxisView* rtv;
2894
2895                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2896
2897                         boost::shared_ptr<Track> t = rtv->track();
2898
2899                         if (t != 0 && ! t->destructive()) {
2900
2901                                 if ((playlist = rtv->playlist()) != 0) {
2902                                         playlists.push_back (playlist);
2903                                 }
2904                         }
2905                 }
2906         }
2907
2908         if (playlists.empty()) {
2909                 return;
2910         }
2911
2912         framepos_t the_start;
2913         framepos_t the_end;
2914         framepos_t cnt;
2915
2916         begin_reversible_command (_("trim to selection"));
2917
2918         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2919
2920                 boost::shared_ptr<Region> region;
2921
2922                 the_start = start;
2923
2924                 if ((region = (*i)->top_region_at(the_start)) == 0) {
2925                         continue;
2926                 }
2927
2928                 /* now adjust lengths to that we do the right thing
2929                    if the selection extends beyond the region
2930                 */
2931
2932                 the_start = max (the_start, (framepos_t) region->position());
2933                 if (max_framepos - the_start < region->length()) {
2934                         the_end = the_start + region->length() - 1;
2935                 } else {
2936                         the_end = max_framepos;
2937                 }
2938                 the_end = min (end, the_end);
2939                 cnt = the_end - the_start + 1;
2940
2941                 region->clear_changes ();
2942                 region->trim_to (the_start, cnt);
2943                 _session->add_command (new StatefulDiffCommand (region));
2944         }
2945
2946         commit_reversible_command ();
2947 }
2948
2949 void
2950 Editor::region_fill_track ()
2951 {
2952         RegionSelection rs = get_regions_from_selection_and_entered ();
2953
2954         if (!_session || rs.empty()) {
2955                 return;
2956         }
2957
2958         framepos_t const end = _session->current_end_frame ();
2959
2960         begin_reversible_command (Operations::region_fill);
2961
2962         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2963
2964                 boost::shared_ptr<Region> region ((*i)->region());
2965
2966                 boost::shared_ptr<Playlist> pl = region->playlist();
2967
2968                 if (end <= region->last_frame()) {
2969                         return;
2970                 }
2971
2972                 double times = (double) (end - region->last_frame()) / (double) region->length();
2973
2974                 if (times == 0) {
2975                         return;
2976                 }
2977
2978                 pl->clear_changes ();
2979                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
2980                 _session->add_command (new StatefulDiffCommand (pl));
2981         }
2982
2983         commit_reversible_command ();
2984 }
2985
2986 void
2987 Editor::region_fill_selection ()
2988 {
2989         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2990                 return;
2991         }
2992
2993         if (selection->time.empty()) {
2994                 return;
2995         }
2996
2997         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2998         if (region == 0) {
2999                 return;
3000         }
3001
3002         framepos_t start = selection->time[clicked_selection].start;
3003         framepos_t end = selection->time[clicked_selection].end;
3004
3005         boost::shared_ptr<Playlist> playlist;
3006
3007         if (selection->tracks.empty()) {
3008                 return;
3009         }
3010
3011         framepos_t selection_length = end - start;
3012         float times = (float)selection_length / region->length();
3013
3014         begin_reversible_command (Operations::fill_selection);
3015
3016         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3017
3018         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3019
3020                 if ((playlist = (*i)->playlist()) == 0) {
3021                         continue;
3022                 }
3023
3024                 playlist->clear_changes ();
3025                 playlist->add_region (RegionFactory::create (region, true), start, times);
3026                 _session->add_command (new StatefulDiffCommand (playlist));
3027         }
3028
3029         commit_reversible_command ();
3030 }
3031
3032 void
3033 Editor::set_region_sync_position ()
3034 {
3035         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3036 }
3037
3038 void
3039 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3040 {
3041         bool in_command = false;
3042
3043         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3044
3045                 if (!(*r)->region()->covers (where)) {
3046                         continue;
3047                 }
3048
3049                 boost::shared_ptr<Region> region ((*r)->region());
3050
3051                 if (!in_command) {
3052                         begin_reversible_command (_("set sync point"));
3053                         in_command = true;
3054                 }
3055
3056                 region->clear_changes ();
3057                 region->set_sync_position (where);
3058                 _session->add_command(new StatefulDiffCommand (region));
3059         }
3060
3061         if (in_command) {
3062                 commit_reversible_command ();
3063         }
3064 }
3065
3066 /** Remove the sync positions of the selection */
3067 void
3068 Editor::remove_region_sync ()
3069 {
3070         RegionSelection rs = get_regions_from_selection_and_entered ();
3071
3072         if (rs.empty()) {
3073                 return;
3074         }
3075
3076         begin_reversible_command (_("remove region sync"));
3077
3078         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3079
3080                 (*i)->region()->clear_changes ();
3081                 (*i)->region()->clear_sync_position ();
3082                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3083         }
3084
3085         commit_reversible_command ();
3086 }
3087
3088 void
3089 Editor::naturalize_region ()
3090 {
3091         RegionSelection rs = get_regions_from_selection_and_entered ();
3092
3093         if (rs.empty()) {
3094                 return;
3095         }
3096
3097         if (rs.size() > 1) {
3098                 begin_reversible_command (_("move regions to original position"));
3099         } else {
3100                 begin_reversible_command (_("move region to original position"));
3101         }
3102
3103         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3104                 (*i)->region()->clear_changes ();
3105                 (*i)->region()->move_to_natural_position ();
3106                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3107         }
3108
3109         commit_reversible_command ();
3110 }
3111
3112 void
3113 Editor::align_regions (RegionPoint what)
3114 {
3115         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3116
3117         if (rs.empty()) {
3118                 return;
3119         }
3120
3121         begin_reversible_command (_("align selection"));
3122
3123         framepos_t const position = get_preferred_edit_position ();
3124
3125         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3126                 align_region_internal ((*i)->region(), what, position);
3127         }
3128
3129         commit_reversible_command ();
3130 }
3131
3132 struct RegionSortByTime {
3133     bool operator() (const RegionView* a, const RegionView* b) {
3134             return a->region()->position() < b->region()->position();
3135     }
3136 };
3137
3138 void
3139 Editor::align_regions_relative (RegionPoint point)
3140 {
3141         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3142
3143         if (rs.empty()) {
3144                 return;
3145         }
3146
3147         framepos_t const position = get_preferred_edit_position ();
3148
3149         framepos_t distance = 0;
3150         framepos_t pos = 0;
3151         int dir = 1;
3152
3153         list<RegionView*> sorted;
3154         rs.by_position (sorted);
3155
3156         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3157
3158         switch (point) {
3159         case Start:
3160                 pos = position;
3161                 if (position > r->position()) {
3162                         distance = position - r->position();
3163                 } else {
3164                         distance = r->position() - position;
3165                         dir = -1;
3166                 }
3167                 break;
3168
3169         case End:
3170                 if (position > r->last_frame()) {
3171                         distance = position - r->last_frame();
3172                         pos = r->position() + distance;
3173                 } else {
3174                         distance = r->last_frame() - position;
3175                         pos = r->position() - distance;
3176                         dir = -1;
3177                 }
3178                 break;
3179
3180         case SyncPoint:
3181                 pos = r->adjust_to_sync (position);
3182                 if (pos > r->position()) {
3183                         distance = pos - r->position();
3184                 } else {
3185                         distance = r->position() - pos;
3186                         dir = -1;
3187                 }
3188                 break;
3189         }
3190
3191         if (pos == r->position()) {
3192                 return;
3193         }
3194
3195         begin_reversible_command (_("align selection (relative)"));
3196
3197         /* move first one specially */
3198
3199         r->clear_changes ();
3200         r->set_position (pos);
3201         _session->add_command(new StatefulDiffCommand (r));
3202
3203         /* move rest by the same amount */
3204
3205         sorted.pop_front();
3206
3207         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3208
3209                 boost::shared_ptr<Region> region ((*i)->region());
3210
3211                 region->clear_changes ();
3212
3213                 if (dir > 0) {
3214                         region->set_position (region->position() + distance);
3215                 } else {
3216                         region->set_position (region->position() - distance);
3217                 }
3218
3219                 _session->add_command(new StatefulDiffCommand (region));
3220
3221         }
3222
3223         commit_reversible_command ();
3224 }
3225
3226 void
3227 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3228 {
3229         begin_reversible_command (_("align region"));
3230         align_region_internal (region, point, position);
3231         commit_reversible_command ();
3232 }
3233
3234 void
3235 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3236 {
3237         region->clear_changes ();
3238
3239         switch (point) {
3240         case SyncPoint:
3241                 region->set_position (region->adjust_to_sync (position));
3242                 break;
3243
3244         case End:
3245                 if (position > region->length()) {
3246                         region->set_position (position - region->length());
3247                 }
3248                 break;
3249
3250         case Start:
3251                 region->set_position (position);
3252                 break;
3253         }
3254
3255         _session->add_command(new StatefulDiffCommand (region));
3256 }
3257
3258 void
3259 Editor::trim_region_front ()
3260 {
3261         trim_region (true);
3262 }
3263
3264 void
3265 Editor::trim_region_back ()
3266 {
3267         trim_region (false);
3268 }
3269
3270 void
3271 Editor::trim_region (bool front)
3272 {
3273         framepos_t where = get_preferred_edit_position();
3274         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3275
3276         if (rs.empty()) {
3277                 return;
3278         }
3279
3280         begin_reversible_command (front ? _("trim front") : _("trim back"));
3281
3282         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3283                 if (!(*i)->region()->locked()) {
3284
3285                         (*i)->region()->clear_changes ();
3286
3287                         if (front) {
3288                                 (*i)->region()->trim_front (where);
3289                                 maybe_locate_with_edit_preroll ( where );
3290                         } else {
3291                                 (*i)->region()->trim_end (where);
3292                                 maybe_locate_with_edit_preroll ( where );
3293                         }
3294
3295                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3296                 }
3297         }
3298
3299         commit_reversible_command ();
3300 }
3301
3302 /** Trim the end of the selected regions to the position of the edit cursor */
3303 void
3304 Editor::trim_region_to_loop ()
3305 {
3306         Location* loc = _session->locations()->auto_loop_location();
3307         if (!loc) {
3308                 return;
3309         }
3310         trim_region_to_location (*loc, _("trim to loop"));
3311 }
3312
3313 void
3314 Editor::trim_region_to_punch ()
3315 {
3316         Location* loc = _session->locations()->auto_punch_location();
3317         if (!loc) {
3318                 return;
3319         }
3320         trim_region_to_location (*loc, _("trim to punch"));
3321 }
3322
3323 void
3324 Editor::trim_region_to_location (const Location& loc, const char* str)
3325 {
3326         RegionSelection rs = get_regions_from_selection_and_entered ();
3327
3328         begin_reversible_command (str);
3329
3330         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3331                 RegionView* rv = (*x);
3332
3333                 /* require region to span proposed trim */
3334                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3335                 case Evoral::OverlapInternal:
3336                         break;
3337                 default:
3338                         continue;
3339                 }
3340
3341                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3342                 if (!tav) {
3343                         return;
3344                 }
3345
3346                 float speed = 1.0;
3347                 framepos_t start;
3348                 framepos_t end;
3349
3350                 if (tav->track() != 0) {
3351                         speed = tav->track()->speed();
3352                 }
3353
3354                 start = session_frame_to_track_frame (loc.start(), speed);
3355                 end = session_frame_to_track_frame (loc.end(), speed);
3356
3357                 rv->region()->clear_changes ();
3358                 rv->region()->trim_to (start, (end - start));
3359                 _session->add_command(new StatefulDiffCommand (rv->region()));
3360         }
3361
3362         commit_reversible_command ();
3363 }
3364
3365 void
3366 Editor::trim_region_to_previous_region_end ()
3367 {
3368         return trim_to_region(false);
3369 }
3370
3371 void
3372 Editor::trim_region_to_next_region_start ()
3373 {
3374         return trim_to_region(true);
3375 }
3376
3377 void
3378 Editor::trim_to_region(bool forward)
3379 {
3380         RegionSelection rs = get_regions_from_selection_and_entered ();
3381
3382         begin_reversible_command (_("trim to region"));
3383
3384         boost::shared_ptr<Region> next_region;
3385
3386         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3387
3388                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3389
3390                 if (!arv) {
3391                         continue;
3392                 }
3393
3394                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3395
3396                 if (!atav) {
3397                         return;
3398                 }
3399
3400                 float speed = 1.0;
3401
3402                 if (atav->track() != 0) {
3403                         speed = atav->track()->speed();
3404                 }
3405
3406
3407                 boost::shared_ptr<Region> region = arv->region();
3408                 boost::shared_ptr<Playlist> playlist (region->playlist());
3409
3410                 region->clear_changes ();
3411
3412                 if (forward) {
3413
3414                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3415
3416                     if (!next_region) {
3417                         continue;
3418                     }
3419
3420                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3421                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3422                 }
3423                 else {
3424
3425                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3426
3427                     if(!next_region){
3428                         continue;
3429                     }
3430
3431                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3432
3433                     arv->region_changed (ARDOUR::bounds_change);
3434                 }
3435
3436                 _session->add_command(new StatefulDiffCommand (region));
3437         }
3438
3439         commit_reversible_command ();
3440 }
3441
3442 void
3443 Editor::unfreeze_route ()
3444 {
3445         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3446                 return;
3447         }
3448
3449         clicked_routeview->track()->unfreeze ();
3450 }
3451
3452 void*
3453 Editor::_freeze_thread (void* arg)
3454 {
3455         return static_cast<Editor*>(arg)->freeze_thread ();
3456 }
3457
3458 void*
3459 Editor::freeze_thread ()
3460 {
3461         /* create event pool because we may need to talk to the session */
3462         SessionEvent::create_per_thread_pool ("freeze events", 64);
3463         /* create per-thread buffers for process() tree to use */
3464         current_interthread_info->process_thread.get_buffers ();
3465         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3466         current_interthread_info->done = true;
3467         current_interthread_info->process_thread.drop_buffers();
3468         return 0;
3469 }
3470
3471 void
3472 Editor::freeze_route ()
3473 {
3474         if (!_session) {
3475                 return;
3476         }
3477
3478         /* stop transport before we start. this is important */
3479
3480         _session->request_transport_speed (0.0);
3481         
3482         /* wait for just a little while, because the above call is asynchronous */
3483
3484         ::usleep (250000);
3485
3486         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3487                 return;
3488         }
3489
3490         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3491                 MessageDialog d (
3492                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3493                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3494                         );
3495                 d.set_title (_("Cannot freeze"));
3496                 d.run ();
3497                 return;
3498         }
3499
3500         if (clicked_routeview->track()->has_external_redirects()) {
3501                 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"
3502                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3503                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3504
3505                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3506                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3507                 d.set_title (_("Freeze Limits"));
3508
3509                 int response = d.run ();
3510
3511                 switch (response) {
3512                 case Gtk::RESPONSE_CANCEL:
3513                         return;
3514                 default:
3515                         break;
3516                 }
3517         }
3518
3519         InterThreadInfo itt;
3520         current_interthread_info = &itt;
3521
3522         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3523
3524         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3525
3526         set_canvas_cursor (_cursors->wait);
3527
3528         while (!itt.done && !itt.cancel) {
3529                 gtk_main_iteration ();
3530         }
3531
3532         current_interthread_info = 0;
3533         set_canvas_cursor (current_canvas_cursor);
3534 }
3535
3536 void
3537 Editor::bounce_range_selection (bool replace, bool enable_processing)
3538 {
3539         if (selection->time.empty()) {
3540                 return;
3541         }
3542
3543         TrackSelection views = selection->tracks;
3544
3545         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3546
3547                 if (enable_processing) {
3548
3549                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3550
3551                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3552                                 MessageDialog d (
3553                                         _("You can't perform this operation because the processing of the signal "
3554                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3555                                           "You can do this without processing, which is a different operation.")
3556                                         );
3557                                 d.set_title (_("Cannot bounce"));
3558                                 d.run ();
3559                                 return;
3560                         }
3561                 }
3562         }
3563
3564         framepos_t start = selection->time[clicked_selection].start;
3565         framepos_t end = selection->time[clicked_selection].end;
3566         framepos_t cnt = end - start + 1;
3567
3568         begin_reversible_command (_("bounce range"));
3569
3570         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3571
3572                 RouteTimeAxisView* rtv;
3573
3574                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3575                         continue;
3576                 }
3577
3578                 boost::shared_ptr<Playlist> playlist;
3579
3580                 if ((playlist = rtv->playlist()) == 0) {
3581                         return;
3582                 }
3583
3584                 InterThreadInfo itt;
3585
3586                 playlist->clear_changes ();
3587                 playlist->clear_owned_changes ();
3588
3589                 boost::shared_ptr<Region> r;
3590
3591                 if (enable_processing) {
3592                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3593                 } else {
3594                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3595                 }
3596
3597                 if (!r) {
3598                         continue;
3599                 }
3600
3601                 if (replace) {
3602                         list<AudioRange> ranges;
3603                         ranges.push_back (AudioRange (start, start+cnt, 0));
3604                         playlist->cut (ranges); // discard result
3605                         playlist->add_region (r, start);
3606                 }
3607
3608                 vector<Command*> cmds;
3609                 playlist->rdiff (cmds);
3610                 _session->add_commands (cmds);
3611
3612                 _session->add_command (new StatefulDiffCommand (playlist));
3613         }
3614
3615         commit_reversible_command ();
3616 }
3617
3618 /** Delete selected regions, automation points or a time range */
3619 void
3620 Editor::delete_ ()
3621 {
3622         cut_copy (Delete);
3623 }
3624
3625 /** Cut selected regions, automation points or a time range */
3626 void
3627 Editor::cut ()
3628 {
3629         cut_copy (Cut);
3630 }
3631
3632 /** Copy selected regions, automation points or a time range */
3633 void
3634 Editor::copy ()
3635 {
3636         cut_copy (Copy);
3637 }
3638
3639
3640 /** @return true if a Cut, Copy or Clear is possible */
3641 bool
3642 Editor::can_cut_copy () const
3643 {
3644         switch (effective_mouse_mode()) {
3645
3646         case MouseObject:
3647                 if (!selection->regions.empty() || !selection->points.empty()) {
3648                         return true;
3649                 }
3650                 break;
3651
3652         case MouseRange:
3653                 if (!selection->time.empty()) {
3654                         return true;
3655                 }
3656                 break;
3657
3658         default:
3659                 break;
3660         }
3661
3662         return false;
3663 }
3664
3665
3666 /** Cut, copy or clear selected regions, automation points or a time range.
3667  * @param op Operation (Cut, Copy or Clear)
3668  */
3669 void
3670 Editor::cut_copy (CutCopyOp op)
3671 {
3672         /* only cancel selection if cut/copy is successful.*/
3673
3674         string opname;
3675
3676         switch (op) {
3677         case Delete:
3678                 opname = _("delete");
3679                 break;
3680         case Cut:
3681                 opname = _("cut");
3682                 break;
3683         case Copy:
3684                 opname = _("copy");
3685                 break;
3686         case Clear:
3687                 opname = _("clear");
3688                 break;
3689         }
3690
3691         /* if we're deleting something, and the mouse is still pressed,
3692            the thing we started a drag for will be gone when we release
3693            the mouse button(s). avoid this. see part 2 at the end of
3694            this function.
3695         */
3696
3697         if (op == Delete || op == Cut || op == Clear) {
3698                 if (_drags->active ()) {
3699                         _drags->abort ();
3700                 }
3701         }
3702
3703         if ( op != Clear )  //"Delete" doesn't change copy/paste buf
3704                 cut_buffer->clear ();
3705
3706         if (entered_marker) {
3707
3708                 /* cut/delete op while pointing at a marker */
3709
3710                 bool ignored;
3711                 Location* loc = find_location_from_marker (entered_marker, ignored);
3712
3713                 if (_session && loc) {
3714                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3715                 }
3716
3717                 _drags->abort ();
3718                 return;
3719         }
3720
3721         if (internal_editing()) {
3722
3723                 switch (effective_mouse_mode()) {
3724                 case MouseObject:
3725                 case MouseRange:
3726                         cut_copy_midi (op);
3727                         break;
3728                 default:
3729                         break;
3730                 }
3731
3732         } else {
3733
3734         RegionSelection rs; 
3735
3736         /* we only want to cut regions if some are selected */
3737
3738         if (!selection->regions.empty()) {
3739                 rs = selection->regions;
3740         }
3741
3742         switch (effective_mouse_mode()) {
3743 /*
3744  *              case MouseGain: {
3745                         //find regions's gain line
3746                         AudioRegionView *rview = dynamic_cast<AudioRegionView*>(clicked_regionview);
3747                                 AutomationTimeAxisView *tview = dynamic_cast<AutomationTimeAxisView*>(clicked_trackview);
3748                         if (rview) {
3749                                 AudioRegionGainLine *line = rview->get_gain_line();
3750                                 if (!line) break;
3751                                 
3752                                 //cut region gain points in the selection
3753                                 AutomationList& alist (line->the_list());
3754                                 XMLNode &before = alist.get_state();
3755                                 AutomationList* what_we_got = 0;
3756                                 if ((what_we_got = alist.cut (selection->time.front().start - rview->audio_region()->position(), selection->time.front().end - rview->audio_region()->position())) != 0) {
3757                                         session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3758                                         delete what_we_got;
3759                                         what_we_got = 0;
3760                                 }
3761                                 
3762                                 rview->set_envelope_visible(true);
3763                                 rview->audio_region()->set_envelope_active(true);
3764                                 
3765                         } else if (tview) {
3766                                 AutomationLine *line = *(tview->lines.begin());
3767                                 if (!line) break;
3768                                 
3769                                 //cut auto points in the selection
3770                                 AutomationList& alist (line->the_list());
3771                                 XMLNode &before = alist.get_state();
3772                                 AutomationList* what_we_got = 0;
3773                                 if ((what_we_got = alist.cut (selection->time.front().start, selection->time.front().end)) != 0) {
3774                                         session->add_command(new MementoCommand<AutomationList>(alist, &before, &alist.get_state()));
3775                                         delete what_we_got;
3776                                         what_we_got = 0;
3777                                 }               
3778                         } else
3779                                 break;
3780                 } break;
3781 */                      
3782                 case MouseObject: 
3783                 case MouseRange:
3784                         if (!rs.empty() || !selection->points.empty()) {
3785                                 begin_reversible_command (opname + _(" objects"));
3786
3787                                 if (!rs.empty()) {
3788                                         cut_copy_regions (op, rs);
3789                                         
3790                                         if (op == Cut || op == Delete) {
3791                                                 selection->clear_regions ();
3792                                         }
3793                                 }
3794
3795                                 if (!selection->points.empty()) {
3796                                         cut_copy_points (op);
3797
3798                                         if (op == Cut || op == Delete) {
3799                                                 selection->clear_points ();
3800                                         }
3801                                 }
3802
3803                                 commit_reversible_command ();   
3804                                 break;
3805                         } 
3806                         
3807                         if (selection->time.empty()) {
3808                                 framepos_t start, end;
3809                                 if (!get_edit_op_range (start, end)) {
3810                                         return;
3811                                 }
3812                                 selection->set (start, end);
3813                         }
3814                                 
3815                         begin_reversible_command (opname + _(" range"));
3816                         cut_copy_ranges (op);
3817                         commit_reversible_command ();
3818                         
3819                         if (op == Cut || op == Delete) {
3820                                 selection->clear_time ();
3821                         }
3822
3823                         break;
3824                         
3825                 default:
3826                         break;
3827                 }
3828         }
3829
3830         if (op == Delete || op == Cut || op == Clear) {
3831                 _drags->abort ();
3832         }
3833 }
3834
3835 struct AutomationRecord {
3836         AutomationRecord () : state (0) {}
3837         AutomationRecord (XMLNode* s) : state (s) {}
3838         
3839         XMLNode* state; ///< state before any operation
3840         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3841 };
3842
3843 /** Cut, copy or clear selected automation points.
3844  *  @param op Operation (Cut, Copy or Clear)
3845  */
3846 void
3847 Editor::cut_copy_points (CutCopyOp op)
3848 {
3849         if (selection->points.empty ()) {
3850                 return;
3851         }
3852
3853         /* XXX: not ideal, as there may be more than one track involved in the point selection */
3854         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3855
3856         /* Keep a record of the AutomationLists that we end up using in this operation */
3857         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3858         Lists lists;
3859
3860         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3861         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3862                 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3863                 if (lists.find (al) == lists.end ()) {
3864                         /* We haven't seen this list yet, so make a record for it.  This includes
3865                            taking a copy of its current state, in case this is needed for undo later.
3866                         */
3867                         lists[al] = AutomationRecord (&al->get_state ());
3868                 }
3869         }
3870
3871         if (op == Cut || op == Copy) {
3872                 /* This operation will involve putting things in the cut buffer, so create an empty
3873                    ControlList for each of our source lists to put the cut buffer data in.
3874                 */
3875                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3876                         i->second.copy = i->first->create (i->first->parameter ());
3877                 }
3878
3879                 /* Add all selected points to the relevant copy ControlLists */
3880                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3881                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3882                         AutomationList::const_iterator j = (*i)->model ();
3883                         lists[al].copy->add ((*j)->when, (*j)->value);
3884                 }
3885
3886                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3887                         /* Correct this copy list so that it starts at time 0 */
3888                         double const start = i->second.copy->front()->when;
3889                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3890                                 (*j)->when -= start;
3891                         }
3892
3893                         /* And add it to the cut buffer */
3894                         cut_buffer->add (i->second.copy);
3895                 }
3896         }
3897                 
3898         if (op == Delete || op == Cut) {
3899                 /* This operation needs to remove things from the main AutomationList, so do that now */
3900                 
3901                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3902                         i->first->freeze ();
3903                 }
3904
3905                 /* Remove each selected point from its AutomationList */
3906                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3907                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3908                         al->erase ((*i)->model ());
3909                 }
3910
3911                 /* Thaw the lists and add undo records for them */
3912                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3913                         boost::shared_ptr<AutomationList> al = i->first;
3914                         al->thaw ();
3915                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3916                 }
3917         }
3918 }
3919
3920 /** Cut, copy or clear selected automation points.
3921  * @param op Operation (Cut, Copy or Clear)
3922  */
3923 void
3924 Editor::cut_copy_midi (CutCopyOp op)
3925 {
3926         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
3927                 MidiRegionView* mrv = *i;
3928                 mrv->cut_copy_clear (op);
3929         }
3930 }
3931
3932
3933
3934 struct lt_playlist {
3935     bool operator () (const PlaylistState& a, const PlaylistState& b) {
3936             return a.playlist < b.playlist;
3937     }
3938 };
3939
3940 struct PlaylistMapping {
3941     TimeAxisView* tv;
3942     boost::shared_ptr<Playlist> pl;
3943
3944     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3945 };
3946
3947 /** Remove `clicked_regionview' */
3948 void
3949 Editor::remove_clicked_region ()
3950 {
3951         if (clicked_routeview == 0 || clicked_regionview == 0) {
3952                 return;
3953         }
3954
3955         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
3956
3957         begin_reversible_command (_("remove region"));
3958         playlist->clear_changes ();
3959         playlist->clear_owned_changes ();
3960         playlist->remove_region (clicked_regionview->region());
3961
3962         /* We might have removed regions, which alters other regions' layering_index,
3963            so we need to do a recursive diff here.
3964         */
3965         vector<Command*> cmds;
3966         playlist->rdiff (cmds);
3967         _session->add_commands (cmds);
3968         
3969         _session->add_command(new StatefulDiffCommand (playlist));
3970         commit_reversible_command ();
3971 }
3972
3973
3974 /** Remove the selected regions */
3975 void
3976 Editor::remove_selected_regions ()
3977 {
3978         RegionSelection rs = get_regions_from_selection_and_entered ();
3979
3980         if (!_session || rs.empty()) {
3981                 return;
3982         }
3983
3984         begin_reversible_command (_("remove region"));
3985
3986         list<boost::shared_ptr<Region> > regions_to_remove;
3987
3988         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3989                 // we can't just remove the region(s) in this loop because
3990                 // this removes them from the RegionSelection, and they thus
3991                 // disappear from underneath the iterator, and the ++i above
3992                 // SEGVs in a puzzling fashion.
3993
3994                 // so, first iterate over the regions to be removed from rs and
3995                 // add them to the regions_to_remove list, and then
3996                 // iterate over the list to actually remove them.
3997
3998                 regions_to_remove.push_back ((*i)->region());
3999         }
4000
4001         vector<boost::shared_ptr<Playlist> > playlists;
4002
4003         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4004
4005                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4006
4007                 if (!playlist) {
4008                         // is this check necessary?
4009                         continue;
4010                 }
4011
4012                 /* get_regions_from_selection_and_entered() guarantees that
4013                    the playlists involved are unique, so there is no need
4014                    to check here.
4015                 */
4016
4017                 playlists.push_back (playlist);
4018
4019                 playlist->clear_changes ();
4020                 playlist->clear_owned_changes ();
4021                 playlist->freeze ();
4022                 playlist->remove_region (*rl);
4023         }
4024
4025         vector<boost::shared_ptr<Playlist> >::iterator pl;
4026
4027         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4028                 (*pl)->thaw ();
4029
4030                 /* We might have removed regions, which alters other regions' layering_index,
4031                    so we need to do a recursive diff here.
4032                 */
4033                 vector<Command*> cmds;
4034                 (*pl)->rdiff (cmds);
4035                 _session->add_commands (cmds);
4036                 
4037                 _session->add_command(new StatefulDiffCommand (*pl));
4038         }
4039
4040         commit_reversible_command ();
4041 }
4042
4043 /** Cut, copy or clear selected regions.
4044  * @param op Operation (Cut, Copy or Clear)
4045  */
4046 void
4047 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4048 {
4049         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4050            a map when we want ordered access to both elements. i think.
4051         */
4052
4053         vector<PlaylistMapping> pmap;
4054
4055         framepos_t first_position = max_framepos;
4056
4057         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4058         FreezeList freezelist;
4059
4060         /* get ordering correct before we cut/copy */
4061
4062         rs.sort_by_position_and_track ();
4063
4064         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4065
4066                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4067
4068                 if (op == Cut || op == Clear || op == Delete) {
4069                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4070
4071                         if (pl) {
4072                                 FreezeList::iterator fl;
4073
4074                                 // only take state if this is a new playlist.
4075                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4076                                         if ((*fl) == pl) {
4077                                                 break;
4078                                         }
4079                                 }
4080
4081                                 if (fl == freezelist.end()) {
4082                                         pl->clear_changes();
4083                                         pl->clear_owned_changes ();
4084                                         pl->freeze ();
4085                                         freezelist.insert (pl);
4086                                 }
4087                         }
4088                 }
4089
4090                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4091                 vector<PlaylistMapping>::iterator z;
4092
4093                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4094                         if ((*z).tv == tv) {
4095                                 break;
4096                         }
4097                 }
4098
4099                 if (z == pmap.end()) {
4100                         pmap.push_back (PlaylistMapping (tv));
4101                 }
4102         }
4103
4104         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4105
4106                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4107
4108                 if (!pl) {
4109                         /* region not yet associated with a playlist (e.g. unfinished
4110                            capture pass.
4111                         */
4112                         ++x;
4113                         continue;
4114                 }
4115
4116                 TimeAxisView& tv = (*x)->get_time_axis_view();
4117                 boost::shared_ptr<Playlist> npl;
4118                 RegionSelection::iterator tmp;
4119
4120                 tmp = x;
4121                 ++tmp;
4122
4123                 if (op != Delete) {
4124
4125                         vector<PlaylistMapping>::iterator z;
4126                         
4127                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4128                                 if ((*z).tv == &tv) {
4129                                         break;
4130                                 }
4131                         }
4132                         
4133                         assert (z != pmap.end());
4134                         
4135                         if (!(*z).pl) {
4136                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4137                                 npl->freeze();
4138                                 (*z).pl = npl;
4139                         } else {
4140                                 npl = (*z).pl;
4141                         }
4142                 }
4143
4144                 boost::shared_ptr<Region> r = (*x)->region();
4145                 boost::shared_ptr<Region> _xx;
4146
4147                 assert (r != 0);
4148
4149                 switch (op) {
4150                 case Delete:
4151                         pl->remove_region (r);
4152                         break;
4153                         
4154                 case Cut:
4155                         _xx = RegionFactory::create (r);
4156                         npl->add_region (_xx, r->position() - first_position);
4157                         pl->remove_region (r);
4158                         break;
4159
4160                 case Copy:
4161                         /* copy region before adding, so we're not putting same object into two different playlists */
4162                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4163                         break;
4164
4165                 case Clear:
4166                         pl->remove_region (r);  
4167                         break;
4168                 }
4169
4170                 x = tmp;
4171         }
4172
4173         if (op != Delete) {
4174
4175                 list<boost::shared_ptr<Playlist> > foo;
4176                 
4177                 /* the pmap is in the same order as the tracks in which selected regions occured */
4178                 
4179                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4180                         if ((*i).pl) {
4181                                 (*i).pl->thaw();
4182                                 foo.push_back ((*i).pl);
4183                         }
4184                 }
4185                 
4186                 if (!foo.empty()) {
4187                         cut_buffer->set (foo);
4188                 }
4189                 
4190                 if (pmap.empty()) {
4191                         _last_cut_copy_source_track = 0;
4192                 } else {
4193                         _last_cut_copy_source_track = pmap.front().tv;
4194                 }
4195         }
4196
4197         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4198                 (*pl)->thaw ();
4199
4200                 /* We might have removed regions, which alters other regions' layering_index,
4201                    so we need to do a recursive diff here.
4202                 */
4203                 vector<Command*> cmds;
4204                 (*pl)->rdiff (cmds);
4205                 _session->add_commands (cmds);
4206                 
4207                 _session->add_command (new StatefulDiffCommand (*pl));
4208         }
4209 }
4210
4211 void
4212 Editor::cut_copy_ranges (CutCopyOp op)
4213 {
4214         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4215
4216         /* Sort the track selection now, so that it if is used, the playlists
4217            selected by the calls below to cut_copy_clear are in the order that
4218            their tracks appear in the editor.  This makes things like paste
4219            of ranges work properly.
4220         */
4221
4222         sort_track_selection (ts);
4223
4224         if (ts.empty()) {
4225                 if (!entered_track) {
4226                         return;
4227                 }
4228                 ts.push_back (entered_track);
4229         } 
4230
4231         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4232                 (*i)->cut_copy_clear (*selection, op);
4233         }
4234 }
4235
4236 void
4237 Editor::paste (float times, bool from_context)
4238 {
4239         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4240
4241         paste_internal (get_preferred_edit_position (false, from_context), times);
4242 }
4243
4244 void
4245 Editor::mouse_paste ()
4246 {
4247         framepos_t where;
4248         bool ignored;
4249
4250         if (!mouse_frame (where, ignored)) {
4251                 return;
4252         }
4253
4254         snap_to (where);
4255         paste_internal (where, 1);
4256 }
4257
4258 void
4259 Editor::paste_internal (framepos_t position, float times)
4260 {
4261         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4262
4263         if (internal_editing()) {
4264                 if (cut_buffer->midi_notes.empty()) {
4265                         return;
4266                 }
4267         } else {
4268                 if (cut_buffer->empty()) {
4269                         return;
4270                 }
4271         }
4272
4273         if (position == max_framepos) {
4274                 position = get_preferred_edit_position();
4275                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4276         }
4277
4278         TrackViewList ts;
4279         TrackViewList::iterator i;
4280         size_t nth;
4281
4282         /* get everything in the correct order */
4283
4284         if (_edit_point == Editing::EditAtMouse && entered_track) {
4285                 /* With the mouse edit point, paste onto the track under the mouse */
4286                 ts.push_back (entered_track);
4287         } else if (!selection->tracks.empty()) {
4288                 /* Otherwise, if there are some selected tracks, paste to them */
4289                 ts = selection->tracks.filter_to_unique_playlists ();
4290                 sort_track_selection (ts);
4291         } else if (_last_cut_copy_source_track) {
4292                 /* Otherwise paste to the track that the cut/copy came from;
4293                    see discussion in mantis #3333.
4294                 */
4295                 ts.push_back (_last_cut_copy_source_track);
4296         }
4297
4298         if (internal_editing ()) {
4299
4300                 /* undo/redo is handled by individual tracks/regions */
4301
4302                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4303
4304                         RegionSelection rs;
4305                         RegionSelection::iterator r;
4306                         MidiNoteSelection::iterator cb;
4307
4308                         get_regions_at (rs, position, ts);
4309
4310                         for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4311                              cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4312                                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4313                                 if (mrv) {
4314                                         mrv->paste (position, times, **cb);
4315                                         ++cb;
4316                                 }
4317                         }
4318                 }
4319
4320         } else {
4321
4322                 /* we do redo (do you do voodoo?) */
4323
4324                 begin_reversible_command (Operations::paste);
4325
4326                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4327                         (*i)->paste (position, times, *cut_buffer, nth);
4328                 }
4329
4330                 commit_reversible_command ();
4331         }
4332 }
4333
4334 void
4335 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4336 {
4337         boost::shared_ptr<Playlist> playlist;
4338         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4339         RegionSelection foo;
4340
4341         framepos_t const start_frame = regions.start ();
4342         framepos_t const end_frame = regions.end_frame ();
4343
4344         begin_reversible_command (Operations::duplicate_region);
4345
4346         selection->clear_regions ();
4347
4348         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4349
4350                 boost::shared_ptr<Region> r ((*i)->region());
4351
4352                 TimeAxisView& tv = (*i)->get_time_axis_view();
4353                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4354                 latest_regionviews.clear ();
4355                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4356
4357                 playlist = (*i)->region()->playlist();
4358                 playlist->clear_changes ();
4359                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4360                 _session->add_command(new StatefulDiffCommand (playlist));
4361
4362                 c.disconnect ();
4363
4364                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4365         }
4366
4367         commit_reversible_command ();
4368
4369         if (!foo.empty()) {
4370                 selection->set (foo);
4371         }
4372 }
4373
4374 void
4375 Editor::duplicate_selection (float times)
4376 {
4377         if (selection->time.empty() || selection->tracks.empty()) {
4378                 return;
4379         }
4380
4381         boost::shared_ptr<Playlist> playlist;
4382         vector<boost::shared_ptr<Region> > new_regions;
4383         vector<boost::shared_ptr<Region> >::iterator ri;
4384
4385         create_region_from_selection (new_regions);
4386
4387         if (new_regions.empty()) {
4388                 return;
4389         }
4390
4391         begin_reversible_command (_("duplicate selection"));
4392
4393         ri = new_regions.begin();
4394
4395         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4396
4397         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4398                 if ((playlist = (*i)->playlist()) == 0) {
4399                         continue;
4400                 }
4401                 playlist->clear_changes ();
4402                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4403                 _session->add_command (new StatefulDiffCommand (playlist));
4404
4405                 ++ri;
4406                 if (ri == new_regions.end()) {
4407                         --ri;
4408                 }
4409         }
4410
4411         commit_reversible_command ();
4412 }
4413
4414 /** Reset all selected points to the relevant default value */
4415 void
4416 Editor::reset_point_selection ()
4417 {
4418         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4419                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4420                 (*j)->value = (*i)->line().the_list()->default_value ();
4421         }
4422 }
4423
4424 void
4425 Editor::center_playhead ()
4426 {
4427         float page = _canvas_width * frames_per_unit;
4428         center_screen_internal (playhead_cursor->current_frame, page);
4429 }
4430
4431 void
4432 Editor::center_edit_point ()
4433 {
4434         float page = _canvas_width * frames_per_unit;
4435         center_screen_internal (get_preferred_edit_position(), page);
4436 }
4437
4438 /** Caller must begin and commit a reversible command */
4439 void
4440 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4441 {
4442         playlist->clear_changes ();
4443         playlist->clear ();
4444         _session->add_command (new StatefulDiffCommand (playlist));
4445 }
4446
4447 void
4448 Editor::nudge_track (bool use_edit, bool forwards)
4449 {
4450         boost::shared_ptr<Playlist> playlist;
4451         framepos_t distance;
4452         framepos_t next_distance;
4453         framepos_t start;
4454
4455         if (use_edit) {
4456                 start = get_preferred_edit_position();
4457         } else {
4458                 start = 0;
4459         }
4460
4461         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4462                 return;
4463         }
4464
4465         if (selection->tracks.empty()) {
4466                 return;
4467         }
4468
4469         begin_reversible_command (_("nudge track"));
4470
4471         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4472
4473         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4474
4475                 if ((playlist = (*i)->playlist()) == 0) {
4476                         continue;
4477                 }
4478
4479                 playlist->clear_changes ();
4480                 playlist->clear_owned_changes ();
4481
4482                 playlist->nudge_after (start, distance, forwards);
4483
4484                 vector<Command*> cmds;
4485
4486                 playlist->rdiff (cmds);
4487                 _session->add_commands (cmds);
4488
4489                 _session->add_command (new StatefulDiffCommand (playlist));
4490         }
4491
4492         commit_reversible_command ();
4493 }
4494
4495 void
4496 Editor::remove_last_capture ()
4497 {
4498         vector<string> choices;
4499         string prompt;
4500
4501         if (!_session) {
4502                 return;
4503         }
4504
4505         if (Config->get_verify_remove_last_capture()) {
4506                 prompt  = _("Do you really want to destroy the last capture?"
4507                             "\n(This is destructive and cannot be undone)");
4508
4509                 choices.push_back (_("No, do nothing."));
4510                 choices.push_back (_("Yes, destroy it."));
4511
4512                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4513
4514                 if (prompter.run () == 1) {
4515                         _session->remove_last_capture ();
4516                         _regions->redisplay ();
4517                 }
4518
4519         } else {
4520                 _session->remove_last_capture();
4521                 _regions->redisplay ();
4522         }
4523 }
4524
4525 void
4526 Editor::normalize_region ()
4527 {
4528         if (!_session) {
4529                 return;
4530         }
4531
4532         RegionSelection rs = get_regions_from_selection_and_entered ();
4533
4534         if (rs.empty()) {
4535                 return;
4536         }
4537
4538         NormalizeDialog dialog (rs.size() > 1);
4539
4540         if (dialog.run () == RESPONSE_CANCEL) {
4541                 return;
4542         }
4543
4544         set_canvas_cursor (_cursors->wait);
4545         gdk_flush ();
4546
4547         /* XXX: should really only count audio regions here */
4548         int const regions = rs.size ();
4549
4550         /* Make a list of the selected audio regions' maximum amplitudes, and also
4551            obtain the maximum amplitude of them all.
4552         */
4553         list<double> max_amps;
4554         double max_amp = 0;
4555         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4556                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4557                 if (arv) {
4558                         dialog.descend (1.0 / regions);
4559                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4560
4561                         if (a == -1) {
4562                                 /* the user cancelled the operation */
4563                                 set_canvas_cursor (current_canvas_cursor);
4564                                 return;
4565                         }
4566
4567                         max_amps.push_back (a);
4568                         max_amp = max (max_amp, a);
4569                         dialog.ascend ();
4570                 }
4571         }
4572
4573         begin_reversible_command (_("normalize"));
4574
4575         list<double>::const_iterator a = max_amps.begin ();
4576
4577         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4578                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4579                 if (!arv) {
4580                         continue;
4581                 }
4582
4583                 arv->region()->clear_changes ();
4584
4585                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4586
4587                 arv->audio_region()->normalize (amp, dialog.target ());
4588                 _session->add_command (new StatefulDiffCommand (arv->region()));
4589
4590                 ++a;
4591         }
4592
4593         commit_reversible_command ();
4594         set_canvas_cursor (current_canvas_cursor);
4595 }
4596
4597
4598 void
4599 Editor::reset_region_scale_amplitude ()
4600 {
4601         if (!_session) {
4602                 return;
4603         }
4604
4605         RegionSelection rs = get_regions_from_selection_and_entered ();
4606
4607         if (rs.empty()) {
4608                 return;
4609         }
4610
4611         begin_reversible_command ("reset gain");
4612
4613         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4614                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4615                 if (!arv)
4616                         continue;
4617                 arv->region()->clear_changes ();
4618                 arv->audio_region()->set_scale_amplitude (1.0f);
4619                 _session->add_command (new StatefulDiffCommand (arv->region()));
4620         }
4621
4622         commit_reversible_command ();
4623 }
4624
4625 void
4626 Editor::adjust_region_gain (bool up)
4627 {
4628         RegionSelection rs = get_regions_from_selection_and_entered ();
4629
4630         if (!_session || rs.empty()) {
4631                 return;
4632         }
4633
4634         begin_reversible_command ("adjust region gain");
4635
4636         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4637                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4638                 if (!arv) {
4639                         continue;
4640                 }
4641
4642                 arv->region()->clear_changes ();
4643
4644                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4645
4646                 if (up) {
4647                         dB += 1;
4648                 } else {
4649                         dB -= 1;
4650                 }
4651
4652                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4653                 _session->add_command (new StatefulDiffCommand (arv->region()));
4654         }
4655
4656         commit_reversible_command ();
4657 }
4658
4659
4660 void
4661 Editor::reverse_region ()
4662 {
4663         if (!_session) {
4664                 return;
4665         }
4666
4667         Reverse rev (*_session);
4668         apply_filter (rev, _("reverse regions"));
4669 }
4670
4671 void
4672 Editor::strip_region_silence ()
4673 {
4674         if (!_session) {
4675                 return;
4676         }
4677
4678         RegionSelection rs = get_regions_from_selection_and_entered ();
4679
4680         if (rs.empty()) {
4681                 return;
4682         }
4683
4684         std::list<RegionView*> audio_only;
4685
4686         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4687                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4688                 if (arv) {
4689                         audio_only.push_back (arv);
4690                 }
4691         }
4692
4693         StripSilenceDialog d (_session, audio_only);
4694         int const r = d.run ();
4695
4696         d.drop_rects ();
4697
4698         if (r == Gtk::RESPONSE_OK) {
4699                 ARDOUR::AudioIntervalMap silences;
4700                 d.silences (silences);
4701                 StripSilence s (*_session, silences, d.fade_length());
4702                 apply_filter (s, _("strip silence"), &d);
4703         }
4704 }
4705
4706 Command*
4707 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4708 {
4709         Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4710         mrv.selection_as_notelist (selected, true);
4711
4712         vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4713         v.push_back (selected);
4714
4715         framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4716         double     pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4717
4718         return op (mrv.midi_region()->model(), pos_beats, v);
4719 }
4720
4721 void
4722 Editor::apply_midi_note_edit_op (MidiOperator& op)
4723 {
4724         Command* cmd;
4725
4726         RegionSelection rs = get_regions_from_selection_and_entered ();
4727
4728         if (rs.empty()) {
4729                 return;
4730         }
4731
4732         begin_reversible_command (op.name ());
4733
4734         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4735                 RegionSelection::iterator tmp = r;
4736                 ++tmp;
4737
4738                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4739
4740                 if (mrv) {
4741                         cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4742                         if (cmd) {
4743                                 (*cmd)();
4744                                 _session->add_command (cmd);
4745                         }
4746                 }
4747
4748                 r = tmp;
4749         }
4750
4751         commit_reversible_command ();
4752 }
4753
4754 void
4755 Editor::fork_region ()
4756 {
4757         RegionSelection rs = get_regions_from_selection_and_entered ();
4758
4759         if (rs.empty()) {
4760                 return;
4761         }
4762
4763         begin_reversible_command (_("Fork Region(s)"));
4764
4765         set_canvas_cursor (_cursors->wait);
4766         gdk_flush ();
4767
4768         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4769                 RegionSelection::iterator tmp = r;
4770                 ++tmp;
4771
4772                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4773
4774                 if (mrv) {
4775                         boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4776                         boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone ();
4777
4778                         playlist->clear_changes ();
4779                         playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4780                         _session->add_command(new StatefulDiffCommand (playlist));
4781                 }
4782
4783                 r = tmp;
4784         }
4785
4786         commit_reversible_command ();
4787
4788         set_canvas_cursor (current_canvas_cursor);
4789 }
4790
4791 void
4792 Editor::quantize_region ()
4793 {
4794         int selected_midi_region_cnt = 0;
4795
4796         if (!_session) {
4797                 return;
4798         }
4799
4800         RegionSelection rs = get_regions_from_selection_and_entered ();
4801
4802         if (rs.empty()) {
4803                 return;
4804         }
4805
4806         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4807                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4808                 if (mrv) {
4809                         selected_midi_region_cnt++;
4810                 }
4811         }
4812
4813         if (selected_midi_region_cnt == 0) {
4814                 return;
4815         }
4816
4817         QuantizeDialog* qd = new QuantizeDialog (*this);
4818
4819         qd->present ();
4820         const int r = qd->run ();
4821         qd->hide ();
4822
4823         if (r == Gtk::RESPONSE_OK) {
4824                 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4825                                 qd->start_grid_size(), qd->end_grid_size(),
4826                                 qd->strength(), qd->swing(), qd->threshold());
4827
4828                 apply_midi_note_edit_op (quant);
4829         }
4830 }
4831
4832 void
4833 Editor::insert_patch_change (bool from_context)
4834 {
4835         RegionSelection rs = get_regions_from_selection_and_entered ();
4836
4837         if (rs.empty ()) {
4838                 return;
4839         }
4840
4841         const framepos_t p = get_preferred_edit_position (false, from_context);
4842
4843         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4844            there may be more than one, but the PatchChangeDialog can only offer
4845            one set of patch menus.
4846         */
4847         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4848
4849         Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4850         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4851
4852         if (d.run() == RESPONSE_CANCEL) {
4853                 return;
4854         }
4855
4856         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4857                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4858                 if (mrv) {
4859                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4860                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4861                         }
4862                 }
4863         }
4864 }
4865
4866 void
4867 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4868 {
4869         RegionSelection rs = get_regions_from_selection_and_entered ();
4870
4871         if (rs.empty()) {
4872                 return;
4873         }
4874
4875         begin_reversible_command (command);
4876
4877         set_canvas_cursor (_cursors->wait);
4878         gdk_flush ();
4879
4880         int n = 0;
4881         int const N = rs.size ();
4882
4883         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4884                 RegionSelection::iterator tmp = r;
4885                 ++tmp;
4886
4887                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4888                 if (arv) {
4889                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4890
4891                         if (progress) {
4892                                 progress->descend (1.0 / N);
4893                         }
4894
4895                         if (arv->audio_region()->apply (filter, progress) == 0) {
4896
4897                                 playlist->clear_changes ();
4898                                 playlist->clear_owned_changes ();
4899
4900                                 if (filter.results.empty ()) {
4901
4902                                         /* no regions returned; remove the old one */
4903                                         playlist->remove_region (arv->region ());
4904
4905                                 } else {
4906
4907                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4908
4909                                         /* first region replaces the old one */
4910                                         playlist->replace_region (arv->region(), *res, (*res)->position());
4911                                         ++res;
4912
4913                                         /* add the rest */
4914                                         while (res != filter.results.end()) {
4915                                                 playlist->add_region (*res, (*res)->position());
4916                                                 ++res;
4917                                         }
4918
4919                                 }
4920
4921                                 /* We might have removed regions, which alters other regions' layering_index,
4922                                    so we need to do a recursive diff here.
4923                                 */
4924                                 vector<Command*> cmds;
4925                                 playlist->rdiff (cmds);
4926                                 _session->add_commands (cmds);
4927                                 
4928                                 _session->add_command(new StatefulDiffCommand (playlist));
4929                         } else {
4930                                 goto out;
4931                         }
4932
4933                         if (progress) {
4934                                 progress->ascend ();
4935                         }
4936                 }
4937
4938                 r = tmp;
4939                 ++n;
4940         }
4941
4942         commit_reversible_command ();
4943
4944   out:
4945         set_canvas_cursor (current_canvas_cursor);
4946 }
4947
4948 void
4949 Editor::external_edit_region ()
4950 {
4951         /* more to come */
4952 }
4953
4954 void
4955 Editor::reset_region_gain_envelopes ()
4956 {
4957         RegionSelection rs = get_regions_from_selection_and_entered ();
4958
4959         if (!_session || rs.empty()) {
4960                 return;
4961         }
4962
4963         _session->begin_reversible_command (_("reset region gain"));
4964
4965         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4966                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4967                 if (arv) {
4968                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4969                         XMLNode& before (alist->get_state());
4970
4971                         arv->audio_region()->set_default_envelope ();
4972                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4973                 }
4974         }
4975
4976         _session->commit_reversible_command ();
4977 }
4978
4979 void
4980 Editor::set_region_gain_visibility (RegionView* rv)
4981 {
4982         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
4983         if (arv) {
4984                 arv->update_envelope_visibility();
4985         }
4986 }
4987
4988 void
4989 Editor::set_gain_envelope_visibility ()
4990 {
4991         if (!_session) {
4992                 return;
4993         }
4994
4995         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4996                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4997                 if (v) {
4998                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
4999                 }
5000         }
5001 }
5002
5003 void
5004 Editor::toggle_gain_envelope_active ()
5005 {
5006         if (_ignore_region_action) {
5007                 return;
5008         }
5009
5010         RegionSelection rs = get_regions_from_selection_and_entered ();
5011
5012         if (!_session || rs.empty()) {
5013                 return;
5014         }
5015
5016         _session->begin_reversible_command (_("region gain envelope active"));
5017
5018         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5019                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5020                 if (arv) {
5021                         arv->region()->clear_changes ();
5022                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5023                         _session->add_command (new StatefulDiffCommand (arv->region()));
5024                 }
5025         }
5026
5027         _session->commit_reversible_command ();
5028 }
5029
5030 void
5031 Editor::toggle_region_lock ()
5032 {
5033         if (_ignore_region_action) {
5034                 return;
5035         }
5036
5037         RegionSelection rs = get_regions_from_selection_and_entered ();
5038
5039         if (!_session || rs.empty()) {
5040                 return;
5041         }
5042
5043         _session->begin_reversible_command (_("toggle region lock"));
5044
5045         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5046                 (*i)->region()->clear_changes ();
5047                 (*i)->region()->set_locked (!(*i)->region()->locked());
5048                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5049         }
5050
5051         _session->commit_reversible_command ();
5052 }
5053
5054 void
5055 Editor::toggle_region_video_lock ()
5056 {
5057         if (_ignore_region_action) {
5058                 return;
5059         }
5060
5061         RegionSelection rs = get_regions_from_selection_and_entered ();
5062
5063         if (!_session || rs.empty()) {
5064                 return;
5065         }
5066
5067         _session->begin_reversible_command (_("Toggle Video Lock"));
5068
5069         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5070                 (*i)->region()->clear_changes ();
5071                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5072                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5073         }
5074
5075         _session->commit_reversible_command ();
5076 }
5077
5078 void
5079 Editor::toggle_region_lock_style ()
5080 {
5081         if (_ignore_region_action) {
5082                 return;
5083         }
5084
5085         RegionSelection rs = get_regions_from_selection_and_entered ();
5086
5087         if (!_session || rs.empty()) {
5088                 return;
5089         }
5090
5091         _session->begin_reversible_command (_("region lock style"));
5092
5093         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5094                 (*i)->region()->clear_changes ();
5095                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5096                 (*i)->region()->set_position_lock_style (ns);
5097                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5098         }
5099
5100         _session->commit_reversible_command ();
5101 }
5102
5103 void
5104 Editor::toggle_opaque_region ()
5105 {
5106         if (_ignore_region_action) {
5107                 return;
5108         }
5109
5110         RegionSelection rs = get_regions_from_selection_and_entered ();
5111
5112         if (!_session || rs.empty()) {
5113                 return;
5114         }
5115
5116         _session->begin_reversible_command (_("change region opacity"));
5117
5118         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5119                 (*i)->region()->clear_changes ();
5120                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5121                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5122         }
5123
5124         _session->commit_reversible_command ();
5125 }
5126
5127 void
5128 Editor::toggle_record_enable ()
5129 {
5130         bool new_state = false;
5131         bool first = true;
5132         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5133                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5134                 if (!rtav)
5135                         continue;
5136                 if (!rtav->is_track())
5137                         continue;
5138
5139                 if (first) {
5140                         new_state = !rtav->track()->record_enabled();
5141                         first = false;
5142                 }
5143
5144                 rtav->track()->set_record_enabled (new_state, this);
5145         }
5146 }
5147
5148 void
5149 Editor::toggle_solo ()
5150 {
5151         bool new_state = false;
5152         bool first = true;
5153         boost::shared_ptr<RouteList> rl (new RouteList);
5154
5155         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5156                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5157
5158                 if (!rtav) {
5159                         continue;
5160                 }
5161
5162                 if (first) {
5163                         new_state = !rtav->route()->soloed ();
5164                         first = false;
5165                 }
5166
5167                 rl->push_back (rtav->route());
5168         }
5169
5170         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5171 }
5172
5173 void
5174 Editor::toggle_mute ()
5175 {
5176         bool new_state = false;
5177         bool first = true;
5178         boost::shared_ptr<RouteList> rl (new RouteList);
5179
5180         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5181                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5182
5183                 if (!rtav) {
5184                         continue;
5185                 }
5186
5187                 if (first) {
5188                         new_state = !rtav->route()->muted();
5189                         first = false;
5190                 }
5191
5192                 rl->push_back (rtav->route());
5193         }
5194
5195         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5196 }
5197
5198 void
5199 Editor::toggle_solo_isolate ()
5200 {
5201 }
5202
5203 void
5204 Editor::set_fade_length (bool in)
5205 {
5206         RegionSelection rs = get_regions_from_selection_and_entered ();
5207
5208         if (rs.empty()) {
5209                 return;
5210         }
5211
5212         /* we need a region to measure the offset from the start */
5213
5214         RegionView* rv = rs.front ();
5215
5216         framepos_t pos = get_preferred_edit_position();
5217         framepos_t len;
5218         char const * cmd;
5219
5220         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5221                 /* edit point is outside the relevant region */
5222                 return;
5223         }
5224
5225         if (in) {
5226                 if (pos <= rv->region()->position()) {
5227                         /* can't do it */
5228                         return;
5229                 }
5230                 len = pos - rv->region()->position();
5231                 cmd = _("set fade in length");
5232         } else {
5233                 if (pos >= rv->region()->last_frame()) {
5234                         /* can't do it */
5235                         return;
5236                 }
5237                 len = rv->region()->last_frame() - pos;
5238                 cmd = _("set fade out length");
5239         }
5240
5241         begin_reversible_command (cmd);
5242
5243         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5244                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5245
5246                 if (!tmp) {
5247                         return;
5248                 }
5249
5250                 boost::shared_ptr<AutomationList> alist;
5251                 if (in) {
5252                         alist = tmp->audio_region()->fade_in();
5253                 } else {
5254                         alist = tmp->audio_region()->fade_out();
5255                 }
5256
5257                 XMLNode &before = alist->get_state();
5258
5259                 if (in) {
5260                         tmp->audio_region()->set_fade_in_length (len);
5261                         tmp->audio_region()->set_fade_in_active (true);
5262                 } else {
5263                         tmp->audio_region()->set_fade_out_length (len);
5264                         tmp->audio_region()->set_fade_out_active (true);
5265                 }
5266
5267                 XMLNode &after = alist->get_state();
5268                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5269         }
5270
5271         commit_reversible_command ();
5272 }
5273
5274 void
5275 Editor::set_fade_in_shape (FadeShape shape)
5276 {
5277         RegionSelection rs = get_regions_from_selection_and_entered ();
5278
5279         if (rs.empty()) {
5280                 return;
5281         }
5282
5283         begin_reversible_command (_("set fade in shape"));
5284
5285         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5286                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5287
5288                 if (!tmp) {
5289                         return;
5290                 }
5291
5292                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5293                 XMLNode &before = alist->get_state();
5294
5295                 tmp->audio_region()->set_fade_in_shape (shape);
5296
5297                 XMLNode &after = alist->get_state();
5298                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5299         }
5300
5301         commit_reversible_command ();
5302
5303 }
5304
5305 void
5306 Editor::set_fade_out_shape (FadeShape shape)
5307 {
5308         RegionSelection rs = get_regions_from_selection_and_entered ();
5309
5310         if (rs.empty()) {
5311                 return;
5312         }
5313
5314         begin_reversible_command (_("set fade out shape"));
5315
5316         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5317                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5318
5319                 if (!tmp) {
5320                         return;
5321                 }
5322
5323                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5324                 XMLNode &before = alist->get_state();
5325
5326                 tmp->audio_region()->set_fade_out_shape (shape);
5327
5328                 XMLNode &after = alist->get_state();
5329                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5330         }
5331
5332         commit_reversible_command ();
5333 }
5334
5335 void
5336 Editor::set_fade_in_active (bool yn)
5337 {
5338         RegionSelection rs = get_regions_from_selection_and_entered ();
5339
5340         if (rs.empty()) {
5341                 return;
5342         }
5343
5344         begin_reversible_command (_("set fade in active"));
5345
5346         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5347                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5348
5349                 if (!tmp) {
5350                         return;
5351                 }
5352
5353
5354                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5355
5356                 ar->clear_changes ();
5357                 ar->set_fade_in_active (yn);
5358                 _session->add_command (new StatefulDiffCommand (ar));
5359         }
5360
5361         commit_reversible_command ();
5362 }
5363
5364 void
5365 Editor::set_fade_out_active (bool yn)
5366 {
5367         RegionSelection rs = get_regions_from_selection_and_entered ();
5368
5369         if (rs.empty()) {
5370                 return;
5371         }
5372
5373         begin_reversible_command (_("set fade out active"));
5374
5375         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5376                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5377
5378                 if (!tmp) {
5379                         return;
5380                 }
5381
5382                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5383
5384                 ar->clear_changes ();
5385                 ar->set_fade_out_active (yn);
5386                 _session->add_command(new StatefulDiffCommand (ar));
5387         }
5388
5389         commit_reversible_command ();
5390 }
5391
5392 void
5393 Editor::toggle_region_fades (int dir)
5394 {
5395         if (_ignore_region_action) {
5396                 return;
5397         }
5398         
5399         boost::shared_ptr<AudioRegion> ar;
5400         bool yn = false;
5401
5402         RegionSelection rs = get_regions_from_selection_and_entered ();
5403
5404         if (rs.empty()) {
5405                 return;
5406         }
5407
5408         RegionSelection::iterator i;
5409         for (i = rs.begin(); i != rs.end(); ++i) {
5410                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5411                         if (dir == -1) {
5412                                 yn = ar->fade_out_active ();
5413                         } else {
5414                                 yn = ar->fade_in_active ();
5415                         }
5416                         break;
5417                 }
5418         }
5419
5420         if (i == rs.end()) {
5421                 return;
5422         }
5423
5424         /* XXX should this undo-able? */
5425
5426         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5427                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5428                         continue;
5429                 }
5430                 if (dir == 1 || dir == 0) {
5431                         ar->set_fade_in_active (!yn);
5432                 }
5433
5434                 if (dir == -1 || dir == 0) {
5435                         ar->set_fade_out_active (!yn);
5436                 }
5437         }
5438 }
5439
5440
5441 /** Update region fade visibility after its configuration has been changed */
5442 void
5443 Editor::update_region_fade_visibility ()
5444 {
5445         bool _fade_visibility = _session->config.get_show_region_fades ();
5446
5447         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5448                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5449                 if (v) {
5450                         if (_fade_visibility) {
5451                                 v->audio_view()->show_all_fades ();
5452                         } else {
5453                                 v->audio_view()->hide_all_fades ();
5454                         }
5455                 }
5456         }
5457 }
5458
5459 void
5460 Editor::set_edit_point ()
5461 {
5462         framepos_t where;
5463         bool ignored;
5464
5465         if (!mouse_frame (where, ignored)) {
5466                 return;
5467         }
5468
5469         snap_to (where);
5470
5471         if (selection->markers.empty()) {
5472
5473                 mouse_add_new_marker (where);
5474
5475         } else {
5476                 bool ignored;
5477
5478                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5479
5480                 if (loc) {
5481                         loc->move_to (where);
5482                 }
5483         }
5484 }
5485
5486 void
5487 Editor::set_playhead_cursor ()
5488 {
5489         if (entered_marker) {
5490                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5491         } else {
5492                 framepos_t where;
5493                 bool ignored;
5494
5495                 if (!mouse_frame (where, ignored)) {
5496                         return;
5497                 }
5498
5499                 snap_to (where);
5500
5501                 if (_session) {
5502                         _session->request_locate (where, _session->transport_rolling());
5503                 }
5504         }
5505
5506         if ( Config->get_always_play_range() )
5507                 cancel_time_selection();
5508 }
5509
5510 void
5511 Editor::split_region ()
5512 {
5513         if ( !selection->time.empty()) {
5514                 separate_regions_between (selection->time);
5515                 return;
5516         }
5517
5518         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5519
5520         framepos_t where = get_preferred_edit_position ();
5521
5522         if (rs.empty()) {
5523                 return;
5524         }
5525
5526         split_regions_at (where, rs);
5527 }
5528
5529 struct EditorOrderRouteSorter {
5530     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5531             return a->order_key () < b->order_key ();
5532     }
5533 };
5534
5535 void
5536 Editor::select_next_route()
5537 {
5538         if (selection->tracks.empty()) {
5539                 selection->set (track_views.front());
5540                 return;
5541         }
5542
5543         TimeAxisView* current = selection->tracks.front();
5544
5545         RouteUI *rui;
5546         do {
5547                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5548                         if (*i == current) {
5549                                 ++i;
5550                                 if (i != track_views.end()) {
5551                                         current = (*i);
5552                                 } else {
5553                                         current = (*(track_views.begin()));
5554                                         //selection->set (*(track_views.begin()));
5555                                 }
5556                                 break;
5557                         }
5558                 }
5559                 rui = dynamic_cast<RouteUI *>(current);
5560         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5561
5562         selection->set(current);
5563
5564         ensure_track_visible(current);
5565 }
5566
5567 void
5568 Editor::select_prev_route()
5569 {
5570         if (selection->tracks.empty()) {
5571                 selection->set (track_views.front());
5572                 return;
5573         }
5574
5575         TimeAxisView* current = selection->tracks.front();
5576
5577         RouteUI *rui;
5578         do {
5579                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5580                         if (*i == current) {
5581                                 ++i;
5582                                 if (i != track_views.rend()) {
5583                                         current = (*i);
5584                                 } else {
5585                                         current = *(track_views.rbegin());
5586                                 }
5587                                 break;
5588                         }
5589                 }
5590                 rui = dynamic_cast<RouteUI *>(current);
5591         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5592
5593         selection->set (current);
5594
5595         ensure_track_visible(current);
5596 }
5597
5598 void
5599 Editor::ensure_track_visible(TimeAxisView *track)
5600 {
5601         if (track->hidden())
5602                 return;
5603
5604         double const current_view_min_y = vertical_adjustment.get_value();
5605         double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5606
5607         double const track_min_y = track->y_position ();
5608         double const track_max_y = track->y_position () + track->effective_height ();
5609
5610         if (track_min_y >= current_view_min_y &&
5611             track_max_y <= current_view_max_y) {
5612                 return;
5613         }
5614
5615         double new_value;
5616
5617         if (track_min_y < current_view_min_y) {
5618                 // Track is above the current view
5619                 new_value = track_min_y;
5620         } else {
5621                 // Track is below the current view
5622                 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5623         }
5624
5625         vertical_adjustment.set_value(new_value);
5626 }
5627
5628 void
5629 Editor::set_loop_from_selection (bool play)
5630 {
5631         if (_session == 0 || selection->time.empty()) {
5632                 return;
5633         }
5634
5635         framepos_t start = selection->time[clicked_selection].start;
5636         framepos_t end = selection->time[clicked_selection].end;
5637
5638         set_loop_range (start, end,  _("set loop range from selection"));
5639
5640         if (play) {
5641                 _session->request_play_loop (true);
5642                 _session->request_locate (start, true);
5643         }
5644 }
5645
5646 void
5647 Editor::set_loop_from_edit_range (bool play)
5648 {
5649         if (_session == 0) {
5650                 return;
5651         }
5652
5653         framepos_t start;
5654         framepos_t end;
5655
5656         if (!get_edit_op_range (start, end)) {
5657                 return;
5658         }
5659
5660         set_loop_range (start, end,  _("set loop range from edit range"));
5661
5662         if (play) {
5663                 _session->request_play_loop (true);
5664                 _session->request_locate (start, true);
5665         }
5666 }
5667
5668 void
5669 Editor::set_loop_from_region (bool play)
5670 {
5671         framepos_t start = max_framepos;
5672         framepos_t end = 0;
5673
5674         RegionSelection rs = get_regions_from_selection_and_entered ();
5675
5676         if (rs.empty()) {
5677                 return;
5678         }
5679
5680         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5681                 if ((*i)->region()->position() < start) {
5682                         start = (*i)->region()->position();
5683                 }
5684                 if ((*i)->region()->last_frame() + 1 > end) {
5685                         end = (*i)->region()->last_frame() + 1;
5686                 }
5687         }
5688
5689         set_loop_range (start, end, _("set loop range from region"));
5690
5691         if (play) {
5692                 _session->request_play_loop (true);
5693                 _session->request_locate (start, true);
5694         }
5695 }
5696
5697 void
5698 Editor::set_punch_from_selection ()
5699 {
5700         if (_session == 0 || selection->time.empty()) {
5701                 return;
5702         }
5703
5704         framepos_t start = selection->time[clicked_selection].start;
5705         framepos_t end = selection->time[clicked_selection].end;
5706
5707         set_punch_range (start, end,  _("set punch range from selection"));
5708 }
5709
5710 void
5711 Editor::set_punch_from_edit_range ()
5712 {
5713         if (_session == 0) {
5714                 return;
5715         }
5716
5717         framepos_t start;
5718         framepos_t end;
5719
5720         if (!get_edit_op_range (start, end)) {
5721                 return;
5722         }
5723
5724         set_punch_range (start, end,  _("set punch range from edit range"));
5725 }
5726
5727 void
5728 Editor::set_punch_from_region ()
5729 {
5730         framepos_t start = max_framepos;
5731         framepos_t end = 0;
5732
5733         RegionSelection rs = get_regions_from_selection_and_entered ();
5734
5735         if (rs.empty()) {
5736                 return;
5737         }
5738
5739         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5740                 if ((*i)->region()->position() < start) {
5741                         start = (*i)->region()->position();
5742                 }
5743                 if ((*i)->region()->last_frame() + 1 > end) {
5744                         end = (*i)->region()->last_frame() + 1;
5745                 }
5746         }
5747
5748         set_punch_range (start, end, _("set punch range from region"));
5749 }
5750
5751 void
5752 Editor::pitch_shift_region ()
5753 {
5754         RegionSelection rs = get_regions_from_selection_and_entered ();
5755
5756         RegionSelection audio_rs;
5757         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5758                 if (dynamic_cast<AudioRegionView*> (*i)) {
5759                         audio_rs.push_back (*i);
5760                 }
5761         }
5762
5763         if (audio_rs.empty()) {
5764                 return;
5765         }
5766
5767         pitch_shift (audio_rs, 1.2);
5768 }
5769
5770 void
5771 Editor::transpose_region ()
5772 {
5773         RegionSelection rs = get_regions_from_selection_and_entered ();
5774
5775         list<MidiRegionView*> midi_region_views;
5776         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5777                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5778                 if (mrv) {
5779                         midi_region_views.push_back (mrv);
5780                 }
5781         }
5782
5783         TransposeDialog d;
5784         int const r = d.run ();
5785         if (r != RESPONSE_ACCEPT) {
5786                 return;
5787         }
5788
5789         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5790                 (*i)->midi_region()->transpose (d.semitones ());
5791         }
5792 }
5793
5794 void
5795 Editor::set_tempo_from_region ()
5796 {
5797         RegionSelection rs = get_regions_from_selection_and_entered ();
5798
5799         if (!_session || rs.empty()) {
5800                 return;
5801         }
5802
5803         RegionView* rv = rs.front();
5804
5805         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5806 }
5807
5808 void
5809 Editor::use_range_as_bar ()
5810 {
5811         framepos_t start, end;
5812         if (get_edit_op_range (start, end)) {
5813                 define_one_bar (start, end);
5814         }
5815 }
5816
5817 void
5818 Editor::define_one_bar (framepos_t start, framepos_t end)
5819 {
5820         framepos_t length = end - start;
5821
5822         const Meter& m (_session->tempo_map().meter_at (start));
5823
5824         /* length = 1 bar */
5825
5826         /* now we want frames per beat.
5827            we have frames per bar, and beats per bar, so ...
5828         */
5829
5830         /* XXXX METER MATH */
5831
5832         double frames_per_beat = length / m.divisions_per_bar();
5833
5834         /* beats per minute = */
5835
5836         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5837
5838         /* now decide whether to:
5839
5840             (a) set global tempo
5841             (b) add a new tempo marker
5842
5843         */
5844
5845         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5846
5847         bool do_global = false;
5848
5849         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5850
5851                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5852                    at the start, or create a new marker
5853                 */
5854
5855                 vector<string> options;
5856                 options.push_back (_("Cancel"));
5857                 options.push_back (_("Add new marker"));
5858                 options.push_back (_("Set global tempo"));
5859
5860                 Choice c (
5861                         _("Define one bar"),
5862                         _("Do you want to set the global tempo or add a new tempo marker?"),
5863                         options
5864                         );
5865
5866                 c.set_default_response (2);
5867
5868                 switch (c.run()) {
5869                 case 0:
5870                         return;
5871
5872                 case 2:
5873                         do_global = true;
5874                         break;
5875
5876                 default:
5877                         do_global = false;
5878                 }
5879
5880         } else {
5881
5882                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5883                    if the marker is at the region starter, change it, otherwise add
5884                    a new tempo marker
5885                 */
5886         }
5887
5888         begin_reversible_command (_("set tempo from region"));
5889         XMLNode& before (_session->tempo_map().get_state());
5890
5891         if (do_global) {
5892                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5893         } else if (t.frame() == start) {
5894                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5895         } else {
5896                 Timecode::BBT_Time bbt;
5897                 _session->tempo_map().bbt_time (start, bbt);
5898                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5899         }
5900
5901         XMLNode& after (_session->tempo_map().get_state());
5902
5903         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5904         commit_reversible_command ();
5905 }
5906
5907 void
5908 Editor::split_region_at_transients ()
5909 {
5910         AnalysisFeatureList positions;
5911
5912         RegionSelection rs = get_regions_from_selection_and_entered ();
5913
5914         if (!_session || rs.empty()) {
5915                 return;
5916         }
5917
5918         _session->begin_reversible_command (_("split regions"));
5919
5920         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5921
5922                 RegionSelection::iterator tmp;
5923
5924                 tmp = i;
5925                 ++tmp;
5926
5927                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5928
5929                 if (ar && (ar->get_transients (positions) == 0)) {
5930                         split_region_at_points ((*i)->region(), positions, true);
5931                         positions.clear ();
5932                 }
5933
5934                 i = tmp;
5935         }
5936
5937         _session->commit_reversible_command ();
5938
5939 }
5940
5941 void
5942 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
5943 {
5944         bool use_rhythmic_rodent = false;
5945
5946         boost::shared_ptr<Playlist> pl = r->playlist();
5947
5948         list<boost::shared_ptr<Region> > new_regions;
5949
5950         if (!pl) {
5951                 return;
5952         }
5953
5954         if (positions.empty()) {
5955                 return;
5956         }
5957
5958
5959         if (positions.size() > 20 && can_ferret) {
5960                 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);
5961                 MessageDialog msg (msgstr,
5962                                    false,
5963                                    Gtk::MESSAGE_INFO,
5964                                    Gtk::BUTTONS_OK_CANCEL);
5965
5966                 if (can_ferret) {
5967                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5968                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5969                 } else {
5970                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
5971                 }
5972
5973                 msg.set_title (_("Excessive split?"));
5974                 msg.present ();
5975
5976                 int response = msg.run();
5977                 msg.hide ();
5978
5979                 switch (response) {
5980                 case RESPONSE_OK:
5981                         break;
5982                 case RESPONSE_APPLY:
5983                         use_rhythmic_rodent = true;
5984                         break;
5985                 default:
5986                         return;
5987                 }
5988         }
5989
5990         if (use_rhythmic_rodent) {
5991                 show_rhythm_ferret ();
5992                 return;
5993         }
5994
5995         AnalysisFeatureList::const_iterator x;
5996
5997         pl->clear_changes ();
5998         pl->clear_owned_changes ();
5999
6000         x = positions.begin();
6001
6002         if (x == positions.end()) {
6003                 return;
6004         }
6005
6006         pl->freeze ();
6007         pl->remove_region (r);
6008
6009         framepos_t pos = 0;
6010
6011         while (x != positions.end()) {
6012
6013                 /* deal with positons that are out of scope of present region bounds */
6014                 if (*x <= 0 || *x > r->length()) {
6015                         ++x;
6016                         continue;
6017                 }
6018
6019                 /* file start = original start + how far we from the initial position ?
6020                  */
6021
6022                 framepos_t file_start = r->start() + pos;
6023
6024                 /* length = next position - current position
6025                  */
6026
6027                 framepos_t len = (*x) - pos;
6028
6029                 /* XXX we do we really want to allow even single-sample regions?
6030                    shouldn't we have some kind of lower limit on region size?
6031                 */
6032
6033                 if (len <= 0) {
6034                         break;
6035                 }
6036
6037                 string new_name;
6038
6039                 if (RegionFactory::region_name (new_name, r->name())) {
6040                         break;
6041                 }
6042
6043                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6044
6045                 PropertyList plist;
6046
6047                 plist.add (ARDOUR::Properties::start, file_start);
6048                 plist.add (ARDOUR::Properties::length, len);
6049                 plist.add (ARDOUR::Properties::name, new_name);
6050                 plist.add (ARDOUR::Properties::layer, 0);
6051
6052                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6053                 /* because we set annouce to false, manually add the new region to the
6054                    RegionFactory map
6055                 */
6056                 RegionFactory::map_add (nr);
6057
6058                 pl->add_region (nr, r->position() + pos);
6059
6060                 if (select_new) {
6061                         new_regions.push_front(nr);
6062                 }
6063
6064                 pos += len;
6065                 ++x;
6066         }
6067
6068         string new_name;
6069
6070         RegionFactory::region_name (new_name, r->name());
6071
6072         /* Add the final region */
6073         PropertyList plist;
6074
6075         plist.add (ARDOUR::Properties::start, r->start() + pos);
6076         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6077         plist.add (ARDOUR::Properties::name, new_name);
6078         plist.add (ARDOUR::Properties::layer, 0);
6079
6080         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6081         /* because we set annouce to false, manually add the new region to the
6082            RegionFactory map
6083         */
6084         RegionFactory::map_add (nr);
6085         pl->add_region (nr, r->position() + pos);
6086
6087         if (select_new) {
6088                 new_regions.push_front(nr);
6089         }
6090
6091         pl->thaw ();
6092
6093         /* We might have removed regions, which alters other regions' layering_index,
6094            so we need to do a recursive diff here.
6095         */
6096         vector<Command*> cmds;
6097         pl->rdiff (cmds);
6098         _session->add_commands (cmds);
6099         
6100         _session->add_command (new StatefulDiffCommand (pl));
6101
6102         if (select_new) {
6103
6104                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6105                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6106                 }
6107         }
6108 }
6109
6110 void
6111 Editor::place_transient()
6112 {
6113         if (!_session) {
6114                 return;
6115         }
6116
6117         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6118
6119         if (rs.empty()) {
6120                 return;
6121         }
6122
6123         framepos_t where = get_preferred_edit_position();
6124
6125         _session->begin_reversible_command (_("place transient"));
6126
6127         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6128                 framepos_t position = (*r)->region()->position();
6129                 (*r)->region()->add_transient(where - position);
6130         }
6131
6132         _session->commit_reversible_command ();
6133 }
6134
6135 void
6136 Editor::remove_transient(ArdourCanvas::Item* item)
6137 {
6138         if (!_session) {
6139                 return;
6140         }
6141
6142         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6143         assert (_line);
6144
6145         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6146         _arv->remove_transient (*(float*) _line->get_data ("position"));
6147 }
6148
6149 void
6150 Editor::snap_regions_to_grid ()
6151 {
6152         list <boost::shared_ptr<Playlist > > used_playlists;
6153
6154         RegionSelection rs = get_regions_from_selection_and_entered ();
6155
6156         if (!_session || rs.empty()) {
6157                 return;
6158         }
6159
6160         _session->begin_reversible_command (_("snap regions to grid"));
6161
6162         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6163
6164                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6165
6166                 if (!pl->frozen()) {
6167                         /* we haven't seen this playlist before */
6168
6169                         /* remember used playlists so we can thaw them later */
6170                         used_playlists.push_back(pl);
6171                         pl->freeze();
6172                 }
6173
6174                 framepos_t start_frame = (*r)->region()->first_frame ();
6175                 snap_to (start_frame);
6176                 (*r)->region()->set_position (start_frame);
6177         }
6178
6179         while (used_playlists.size() > 0) {
6180                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6181                 (*i)->thaw();
6182                 used_playlists.pop_front();
6183         }
6184
6185         _session->commit_reversible_command ();
6186 }
6187
6188 void
6189 Editor::close_region_gaps ()
6190 {
6191         list <boost::shared_ptr<Playlist > > used_playlists;
6192
6193         RegionSelection rs = get_regions_from_selection_and_entered ();
6194
6195         if (!_session || rs.empty()) {
6196                 return;
6197         }
6198
6199         Dialog dialog (_("Close Region Gaps"));
6200
6201         Table table (2, 3);
6202         table.set_spacings (12);
6203         table.set_border_width (12);
6204         Label* l = manage (left_aligned_label (_("Crossfade length")));
6205         table.attach (*l, 0, 1, 0, 1);
6206
6207         SpinButton spin_crossfade (1, 0);
6208         spin_crossfade.set_range (0, 15);
6209         spin_crossfade.set_increments (1, 1);
6210         spin_crossfade.set_value (5);
6211         table.attach (spin_crossfade, 1, 2, 0, 1);
6212
6213         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6214
6215         l = manage (left_aligned_label (_("Pull-back length")));
6216         table.attach (*l, 0, 1, 1, 2);
6217
6218         SpinButton spin_pullback (1, 0);
6219         spin_pullback.set_range (0, 100);
6220         spin_pullback.set_increments (1, 1);
6221         spin_pullback.set_value(30);
6222         table.attach (spin_pullback, 1, 2, 1, 2);
6223
6224         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6225
6226         dialog.get_vbox()->pack_start (table);
6227         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6228         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6229         dialog.show_all ();
6230
6231         if (dialog.run () == RESPONSE_CANCEL) {
6232                 return;
6233         }
6234
6235         framepos_t crossfade_len = spin_crossfade.get_value();
6236         framepos_t pull_back_frames = spin_pullback.get_value();
6237
6238         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6239         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6240
6241         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6242
6243         _session->begin_reversible_command (_("close region gaps"));
6244
6245         int idx = 0;
6246         boost::shared_ptr<Region> last_region;
6247
6248         rs.sort_by_position_and_track();
6249
6250         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6251
6252                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6253
6254                 if (!pl->frozen()) {
6255                         /* we haven't seen this playlist before */
6256
6257                         /* remember used playlists so we can thaw them later */
6258                         used_playlists.push_back(pl);
6259                         pl->freeze();
6260                 }
6261
6262                 framepos_t position = (*r)->region()->position();
6263
6264                 if (idx == 0 || position < last_region->position()){
6265                         last_region = (*r)->region();
6266                         idx++;
6267                         continue;
6268                 }
6269
6270                 (*r)->region()->trim_front( (position - pull_back_frames));
6271                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6272
6273                 last_region = (*r)->region();
6274
6275                 idx++;
6276         }
6277
6278         while (used_playlists.size() > 0) {
6279                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6280                 (*i)->thaw();
6281                 used_playlists.pop_front();
6282         }
6283
6284         _session->commit_reversible_command ();
6285 }
6286
6287 void
6288 Editor::tab_to_transient (bool forward)
6289 {
6290         AnalysisFeatureList positions;
6291
6292         RegionSelection rs = get_regions_from_selection_and_entered ();
6293
6294         if (!_session) {
6295                 return;
6296         }
6297
6298         framepos_t pos = _session->audible_frame ();
6299
6300         if (!selection->tracks.empty()) {
6301
6302                 /* don't waste time searching for transients in duplicate playlists.
6303                  */
6304
6305                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6306
6307                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6308
6309                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6310
6311                         if (rtv) {
6312                                 boost::shared_ptr<Track> tr = rtv->track();
6313                                 if (tr) {
6314                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6315                                         if (pl) {
6316                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6317
6318                                                 if (result >= 0) {
6319                                                         positions.push_back (result);
6320                                                 }
6321                                         }
6322                                 }
6323                         }
6324                 }
6325
6326         } else {
6327
6328                 if (rs.empty()) {
6329                         return;
6330                 }
6331
6332                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6333                         (*r)->region()->get_transients (positions);
6334                 }
6335         }
6336
6337         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6338
6339         if (forward) {
6340                 AnalysisFeatureList::iterator x;
6341
6342                 for (x = positions.begin(); x != positions.end(); ++x) {
6343                         if ((*x) > pos) {
6344                                 break;
6345                         }
6346                 }
6347
6348                 if (x != positions.end ()) {
6349                         _session->request_locate (*x);
6350                 }
6351
6352         } else {
6353                 AnalysisFeatureList::reverse_iterator x;
6354
6355                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6356                         if ((*x) < pos) {
6357                                 break;
6358                         }
6359                 }
6360
6361                 if (x != positions.rend ()) {
6362                         _session->request_locate (*x);
6363                 }
6364         }
6365 }
6366
6367 void
6368 Editor::playhead_forward_to_grid ()
6369 {
6370         if (!_session) return;
6371         framepos_t pos = playhead_cursor->current_frame;
6372         if (pos < max_framepos - 1) {
6373                 pos += 2;
6374                 snap_to_internal (pos, 1, false);
6375                 _session->request_locate (pos);
6376         }
6377 }
6378
6379
6380 void
6381 Editor::playhead_backward_to_grid ()
6382 {
6383         if (!_session) return;
6384         framepos_t pos = playhead_cursor->current_frame;
6385         if (pos > 2) {
6386                 pos -= 2;
6387                 snap_to_internal (pos, -1, false);
6388                 _session->request_locate (pos);
6389         }
6390 }
6391
6392 void
6393 Editor::set_track_height (Height h)
6394 {
6395         TrackSelection& ts (selection->tracks);
6396
6397         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6398                 (*x)->set_height_enum (h);
6399         }
6400 }
6401
6402 void
6403 Editor::toggle_tracks_active ()
6404 {
6405         TrackSelection& ts (selection->tracks);
6406         bool first = true;
6407         bool target = false;
6408
6409         if (ts.empty()) {
6410                 return;
6411         }
6412
6413         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6414                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6415
6416                 if (rtv) {
6417                         if (first) {
6418                                 target = !rtv->_route->active();
6419                                 first = false;
6420                         }
6421                         rtv->_route->set_active (target, this);
6422                 }
6423         }
6424 }
6425
6426 void
6427 Editor::remove_tracks ()
6428 {
6429         TrackSelection& ts (selection->tracks);
6430
6431         if (ts.empty()) {
6432                 return;
6433         }
6434
6435         vector<string> choices;
6436         string prompt;
6437         int ntracks = 0;
6438         int nbusses = 0;
6439         const char* trackstr;
6440         const char* busstr;
6441         vector<boost::shared_ptr<Route> > routes;
6442         bool special_bus = false;
6443
6444         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6445                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6446                 if (rtv) {
6447                         if (rtv->is_track()) {
6448                                 ntracks++;
6449                         } else {
6450                                 nbusses++;
6451                         }
6452                 }
6453                 routes.push_back (rtv->_route);
6454
6455                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6456                         special_bus = true;
6457                 }
6458         }
6459
6460         if (special_bus && !Config->get_allow_special_bus_removal()) {
6461                 MessageDialog msg (_("That would be bad news ...."),
6462                                    false,
6463                                    Gtk::MESSAGE_INFO,
6464                                    Gtk::BUTTONS_OK);
6465                 msg.set_secondary_text (string_compose (_(
6466                                                                 "Removing the master or monitor bus is such a bad idea\n\
6467 that %1 is not going to allow it.\n\
6468 \n\
6469 If you really want to do this sort of thing\n\
6470 edit your ardour.rc file to set the\n\
6471 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6472
6473                 msg.present ();
6474                 msg.run ();
6475                 return;
6476         }
6477
6478         if (ntracks + nbusses == 0) {
6479                 return;
6480         }
6481
6482         if (ntracks > 1) {
6483                 trackstr = _("tracks");
6484         } else {
6485                 trackstr = _("track");
6486         }
6487
6488         if (nbusses > 1) {
6489                 busstr = _("busses");
6490         } else {
6491                 busstr = _("bus");
6492         }
6493
6494         if (ntracks) {
6495                 if (nbusses) {
6496                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6497                                                     "(You may also lose the playlists associated with the %2)\n\n"
6498                                                     "This action cannot be undone, and the session file will be overwritten!"),
6499                                                   ntracks, trackstr, nbusses, busstr);
6500                 } else {
6501                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6502                                                     "(You may also lose the playlists associated with the %2)\n\n"
6503                                                     "This action cannot be undone, and the session file will be overwritten!"),
6504                                                   ntracks, trackstr);
6505                 }
6506         } else if (nbusses) {
6507                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6508                                             "This action cannot be undon, and the session file will be overwritten"),
6509                                           nbusses, busstr);
6510         }
6511
6512         choices.push_back (_("No, do nothing."));
6513         if (ntracks + nbusses > 1) {
6514                 choices.push_back (_("Yes, remove them."));
6515         } else {
6516                 choices.push_back (_("Yes, remove it."));
6517         }
6518
6519         string title;
6520         if (ntracks) {
6521                 title = string_compose (_("Remove %1"), trackstr);
6522         } else {
6523                 title = string_compose (_("Remove %1"), busstr);
6524         }
6525
6526         Choice prompter (title, prompt, choices);
6527
6528         if (prompter.run () != 1) {
6529                 return;
6530         }
6531
6532         for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6533                 _session->remove_route (*x);
6534         }
6535 }
6536
6537 void
6538 Editor::do_insert_time ()
6539 {
6540         if (selection->tracks.empty()) {
6541                 return;
6542         }
6543
6544         InsertTimeDialog d (*this);
6545         int response = d.run ();
6546
6547         if (response != RESPONSE_OK) {
6548                 return;
6549         }
6550
6551         if (d.distance() == 0) {
6552                 return;
6553         }
6554
6555         InsertTimeOption opt = d.intersected_region_action ();
6556
6557         insert_time (
6558                 get_preferred_edit_position(),
6559                 d.distance(),
6560                 opt,
6561                 d.all_playlists(),
6562                 d.move_glued(),
6563                 d.move_markers(),
6564                 d.move_glued_markers(),
6565                 d.move_locked_markers(),
6566                 d.move_tempos()
6567                 );
6568 }
6569
6570 void
6571 Editor::insert_time (
6572         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6573         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6574         )
6575 {
6576         bool commit = false;
6577
6578         if (Config->get_edit_mode() == Lock) {
6579                 return;
6580         }
6581
6582         begin_reversible_command (_("insert time"));
6583
6584         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6585
6586         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6587
6588                 /* regions */
6589
6590                 /* don't operate on any playlist more than once, which could
6591                  * happen if "all playlists" is enabled, but there is more
6592                  * than 1 track using playlists "from" a given track.
6593                  */
6594
6595                 set<boost::shared_ptr<Playlist> > pl;
6596
6597                 if (all_playlists) {
6598                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6599                         if (rtav) {
6600                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6601                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6602                                         pl.insert (*p);
6603                                 }
6604                         }
6605                 } else {
6606                         if ((*x)->playlist ()) {
6607                                 pl.insert ((*x)->playlist ());
6608                         }
6609                 }
6610                 
6611                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6612
6613                         (*i)->clear_changes ();
6614                         (*i)->clear_owned_changes ();
6615
6616                         if (opt == SplitIntersected) {
6617                                 (*i)->split (pos);
6618                         }
6619
6620                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6621
6622                         vector<Command*> cmds;
6623                         (*i)->rdiff (cmds);
6624                         _session->add_commands (cmds);
6625
6626                         _session->add_command (new StatefulDiffCommand (*i));
6627                         commit = true;
6628                 }
6629
6630                 /* automation */
6631                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6632                 if (rtav) {
6633                         rtav->route ()->shift (pos, frames);
6634                         commit = true;
6635                 }
6636         }
6637
6638         /* markers */
6639         if (markers_too) {
6640                 bool moved = false;
6641                 XMLNode& before (_session->locations()->get_state());
6642                 Locations::LocationList copy (_session->locations()->list());
6643
6644                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6645
6646                         Locations::LocationList::const_iterator tmp;
6647
6648                         bool const was_locked = (*i)->locked ();
6649                         if (locked_markers_too) {
6650                                 (*i)->unlock ();
6651                         }
6652
6653                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6654
6655                                 if ((*i)->start() >= pos) {
6656                                         (*i)->set_start ((*i)->start() + frames);
6657                                         if (!(*i)->is_mark()) {
6658                                                 (*i)->set_end ((*i)->end() + frames);
6659                                         }
6660                                         moved = true;
6661                                 }
6662
6663                         }
6664
6665                         if (was_locked) {
6666                                 (*i)->lock ();
6667                         }
6668                 }
6669
6670                 if (moved) {
6671                         XMLNode& after (_session->locations()->get_state());
6672                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6673                 }
6674         }
6675
6676         if (tempo_too) {
6677                 _session->tempo_map().insert_time (pos, frames);
6678         }
6679
6680         if (commit) {
6681                 commit_reversible_command ();
6682         }
6683 }
6684
6685 void
6686 Editor::fit_selected_tracks ()
6687 {
6688         if (!selection->tracks.empty()) {
6689                 fit_tracks (selection->tracks);
6690         } else {
6691                 TrackViewList tvl;
6692
6693                 /* no selected tracks - use tracks with selected regions */
6694
6695                 if (!selection->regions.empty()) {
6696                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6697                                 tvl.push_back (&(*r)->get_time_axis_view ());
6698                         }
6699
6700                         if (!tvl.empty()) {
6701                                 fit_tracks (tvl);
6702                         }
6703                 } else if (internal_editing()) {
6704                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6705                            the entered track
6706                         */
6707                         if (entered_track) {
6708                                 tvl.push_back (entered_track);
6709                                 fit_tracks (tvl);
6710                         }
6711                 }
6712         }
6713 }
6714
6715 void
6716 Editor::fit_tracks (TrackViewList & tracks)
6717 {
6718         if (tracks.empty()) {
6719                 return;
6720         }
6721
6722         uint32_t child_heights = 0;
6723         int visible_tracks = 0;
6724
6725         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6726
6727                 if (!(*t)->marked_for_display()) {
6728                         continue;
6729                 }
6730
6731                 child_heights += (*t)->effective_height() - (*t)->current_height();
6732                 ++visible_tracks;
6733         }
6734
6735         uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / visible_tracks);
6736         double first_y_pos = DBL_MAX;
6737
6738         if (h < TimeAxisView::preset_height (HeightSmall)) {
6739                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6740                 /* too small to be displayed */
6741                 return;
6742         }
6743
6744         undo_visual_stack.push_back (current_visual_state (true));
6745         no_save_visual = true;
6746
6747         /* build a list of all tracks, including children */
6748
6749         TrackViewList all;
6750         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6751                 all.push_back (*i);
6752                 TimeAxisView::Children c = (*i)->get_child_list ();
6753                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6754                         all.push_back (j->get());
6755                 }
6756         }
6757
6758         /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6759
6760         bool prev_was_selected = false;
6761         bool is_selected = tracks.contains (all.front());
6762         bool next_is_selected;
6763
6764         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6765
6766                 TrackViewList::iterator next;
6767
6768                 next = t;
6769                 ++next;
6770
6771                 if (next != all.end()) {
6772                         next_is_selected = tracks.contains (*next);
6773                 } else {
6774                         next_is_selected = false;
6775                 }
6776
6777                 if ((*t)->marked_for_display ()) {
6778                         if (is_selected) {
6779                                 (*t)->set_height (h);
6780                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6781                         } else {
6782                                 if (prev_was_selected && next_is_selected) {
6783                                         hide_track_in_display (*t);
6784                                 }
6785                         }
6786                 }
6787
6788                 prev_was_selected = is_selected;
6789                 is_selected = next_is_selected;
6790         }
6791
6792         /*
6793            set the controls_layout height now, because waiting for its size
6794            request signal handler will cause the vertical adjustment setting to fail
6795         */
6796
6797         controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6798         vertical_adjustment.set_value (first_y_pos);
6799
6800         redo_visual_stack.push_back (current_visual_state (true));
6801 }
6802
6803 void
6804 Editor::save_visual_state (uint32_t n)
6805 {
6806         while (visual_states.size() <= n) {
6807                 visual_states.push_back (0);
6808         }
6809
6810         if (visual_states[n] != 0) {
6811                 delete visual_states[n];
6812         }
6813
6814         visual_states[n] = current_visual_state (true);
6815         gdk_beep ();
6816 }
6817
6818 void
6819 Editor::goto_visual_state (uint32_t n)
6820 {
6821         if (visual_states.size() <= n) {
6822                 return;
6823         }
6824
6825         if (visual_states[n] == 0) {
6826                 return;
6827         }
6828
6829         use_visual_state (*visual_states[n]);
6830 }
6831
6832 void
6833 Editor::start_visual_state_op (uint32_t n)
6834 {
6835         save_visual_state (n);
6836         
6837         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6838         char buf[32];
6839         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6840         pup->set_text (buf);
6841         pup->touch();
6842 }
6843
6844 void
6845 Editor::cancel_visual_state_op (uint32_t n)
6846 {
6847         goto_visual_state (n);
6848 }
6849
6850 void
6851 Editor::toggle_region_mute ()
6852 {
6853         if (_ignore_region_action) {
6854                 return;
6855         }
6856
6857         RegionSelection rs = get_regions_from_selection_and_entered ();
6858
6859         if (rs.empty ()) {
6860                 return;
6861         }
6862
6863         if (rs.size() > 1) {
6864                 begin_reversible_command (_("mute regions"));
6865         } else {
6866                 begin_reversible_command (_("mute region"));
6867         }
6868
6869         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6870
6871                 (*i)->region()->playlist()->clear_changes ();
6872                 (*i)->region()->set_muted (!(*i)->region()->muted ());
6873                 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6874
6875         }
6876
6877         commit_reversible_command ();
6878 }
6879
6880 void
6881 Editor::combine_regions ()
6882 {
6883         /* foreach track with selected regions, take all selected regions
6884            and join them into a new region containing the subregions (as a
6885            playlist)
6886         */
6887
6888         typedef set<RouteTimeAxisView*> RTVS;
6889         RTVS tracks;
6890
6891         if (selection->regions.empty()) {
6892                 return;
6893         }
6894
6895         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6896                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6897
6898                 if (rtv) {
6899                         tracks.insert (rtv);
6900                 }
6901         }
6902
6903         begin_reversible_command (_("combine regions"));
6904
6905         vector<RegionView*> new_selection;
6906
6907         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6908                 RegionView* rv;
6909
6910                 if ((rv = (*i)->combine_regions ()) != 0) {
6911                         new_selection.push_back (rv);
6912                 }
6913         }
6914
6915         selection->clear_regions ();
6916         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
6917                 selection->add (*i);
6918         }
6919
6920         commit_reversible_command ();
6921 }
6922
6923 void
6924 Editor::uncombine_regions ()
6925 {
6926         typedef set<RouteTimeAxisView*> RTVS;
6927         RTVS tracks;
6928
6929         if (selection->regions.empty()) {
6930                 return;
6931         }
6932
6933         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6934                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6935
6936                 if (rtv) {
6937                         tracks.insert (rtv);
6938                 }
6939         }
6940
6941         begin_reversible_command (_("uncombine regions"));
6942
6943         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6944                 (*i)->uncombine_regions ();
6945         }
6946
6947         commit_reversible_command ();
6948 }
6949
6950 void
6951 Editor::toggle_midi_input_active (bool flip_others)
6952 {
6953         bool onoff = false;
6954         boost::shared_ptr<RouteList> rl (new RouteList);
6955
6956         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
6957                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
6958
6959                 if (!rtav) {
6960                         continue;
6961                 }
6962
6963                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
6964
6965                 if (mt) {
6966                         rl->push_back (rtav->route());
6967                         onoff = !mt->input_active();
6968                 }
6969         }
6970         
6971         _session->set_exclusive_input_active (rl, onoff, flip_others);
6972 }