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