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