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