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