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