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