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