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