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