Add editor selection state to session history via a SelectionMemento, which
[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         if (internal_editing()) {
3857
3858                 switch (effective_mouse_mode()) {
3859                 case MouseObject:
3860                 case MouseRange:
3861                         begin_reversible_command (opname + ' ' + X_("MIDI"));
3862                         cut_copy_midi (op);
3863                         commit_reversible_command ();
3864                         break;
3865                 default:
3866                         break;
3867                 }
3868
3869                 return;
3870         }
3871
3872         bool did_edit = false;
3873
3874         if (!selection->regions.empty() || !selection->points.empty()) {
3875                 begin_reversible_command (opname + ' ' + _("objects"));
3876                 did_edit = true;
3877
3878                 if (!selection->regions.empty()) {
3879                         cut_copy_regions (op, selection->regions);
3880                         
3881                         if (op == Cut || op == Delete) {
3882                                 selection->clear_regions ();
3883                         }
3884                 }
3885                 
3886                 if (!selection->points.empty()) {
3887                         cut_copy_points (op);
3888                         
3889                         if (op == Cut || op == Delete) {
3890                                 selection->clear_points ();
3891                         }
3892                 }
3893         } else if (selection->time.empty()) {
3894                 framepos_t start, end;
3895                 /* no time selection, see if we can get an edit range
3896                    and use that.
3897                 */
3898                 if (get_edit_op_range (start, end)) {
3899                         selection->set (start, end);
3900                 }
3901         } else if (!selection->time.empty()) {
3902                 begin_reversible_command (opname + ' ' + _("range"));
3903
3904                 did_edit = true;
3905                 cut_copy_ranges (op);
3906                 
3907                 if (op == Cut || op == Delete) {
3908                         selection->clear_time ();
3909                 }
3910         }
3911         
3912         if (did_edit) {
3913                 /* reset repeated paste state */
3914                 paste_count    = 0;
3915                 last_paste_pos = 0;
3916                 commit_reversible_command ();   
3917         }
3918         
3919         if (op == Delete || op == Cut || op == Clear) {
3920                 _drags->abort ();
3921         }
3922 }
3923
3924 struct AutomationRecord {
3925         AutomationRecord () : state (0) , line(NULL) {}
3926         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3927         
3928         XMLNode* state; ///< state before any operation
3929         const AutomationLine* line; ///< line this came from
3930         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3931 };
3932
3933 /** Cut, copy or clear selected automation points.
3934  *  @param op Operation (Cut, Copy or Clear)
3935  */
3936 void
3937 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::MusicalTime earliest, bool midi)
3938 {
3939         if (selection->points.empty ()) {
3940                 return;
3941         }
3942
3943         /* XXX: not ideal, as there may be more than one track involved in the point selection */
3944         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3945
3946         /* Keep a record of the AutomationLists that we end up using in this operation */
3947         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3948         Lists lists;
3949
3950         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3951         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3952                 const AutomationLine&                   line = (*i)->line();
3953                 const boost::shared_ptr<AutomationList> al   = line.the_list();
3954                 if (lists.find (al) == lists.end ()) {
3955                         /* We haven't seen this list yet, so make a record for it.  This includes
3956                            taking a copy of its current state, in case this is needed for undo later.
3957                         */
3958                         lists[al] = AutomationRecord (&al->get_state (), &line);
3959                 }
3960         }
3961
3962         if (op == Cut || op == Copy) {
3963                 /* This operation will involve putting things in the cut buffer, so create an empty
3964                    ControlList for each of our source lists to put the cut buffer data in.
3965                 */
3966                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3967                         i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
3968                 }
3969
3970                 /* Add all selected points to the relevant copy ControlLists */
3971                 framepos_t start = std::numeric_limits<framepos_t>::max();
3972                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3973                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3974                         AutomationList::const_iterator    j  = (*i)->model();
3975
3976                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3977                         if (midi) {
3978                                 /* Update earliest MIDI start time in beats */
3979                                 earliest = std::min(earliest,  Evoral::MusicalTime((*j)->when));
3980                         } else {
3981                                 /* Update earliest session start time in frames */
3982                                 start = std::min(start, (*i)->line().session_position(j));
3983                         }
3984                 }
3985
3986                 /* Snap start time backwards, so copy/paste is snap aligned. */
3987                 if (midi) {
3988                         if (earliest == Evoral::MusicalTime::max()) {
3989                                 earliest = Evoral::MusicalTime();  // Weird... don't offset
3990                         }
3991                         earliest.round_down_to_beat();
3992                 } else {
3993                         if (start == std::numeric_limits<double>::max()) {
3994                                 start = 0;  // Weird... don't offset
3995                         }
3996                         snap_to(start, RoundDownMaybe);
3997                 }
3998
3999                 const double line_offset = midi ? earliest.to_double() : start;
4000                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4001                         /* Correct this copy list so that it is relative to the earliest
4002                            start time, so relative ordering between points is preserved
4003                            when copying from several lists and the paste starts at the
4004                            earliest copied piece of data. */
4005                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4006                                 (*j)->when -= line_offset;
4007                         }
4008
4009                         /* And add it to the cut buffer */
4010                         cut_buffer->add (i->second.copy);
4011                 }
4012         }
4013                 
4014         if (op == Delete || op == Cut) {
4015                 /* This operation needs to remove things from the main AutomationList, so do that now */
4016                 
4017                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4018                         i->first->freeze ();
4019                 }
4020
4021                 /* Remove each selected point from its AutomationList */
4022                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4023                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4024                         al->erase ((*i)->model ());
4025                 }
4026
4027                 /* Thaw the lists and add undo records for them */
4028                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4029                         boost::shared_ptr<AutomationList> al = i->first;
4030                         al->thaw ();
4031                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4032                 }
4033         }
4034 }
4035
4036 /** Cut, copy or clear selected automation points.
4037  * @param op Operation (Cut, Copy or Clear)
4038  */
4039 void
4040 Editor::cut_copy_midi (CutCopyOp op)
4041 {
4042         Evoral::MusicalTime earliest = Evoral::MusicalTime::max();
4043         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4044                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4045                 if (mrv) {
4046                         if (!mrv->selection().empty()) {
4047                                 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4048                         }
4049                         mrv->cut_copy_clear (op);
4050
4051                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4052                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4053                 }
4054         }
4055
4056         if (!selection->points.empty()) {
4057                 cut_copy_points (op, earliest, true);
4058                 if (op == Cut || op == Delete) {
4059                         selection->clear_points ();
4060                 }
4061         }
4062 }
4063
4064 struct lt_playlist {
4065     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4066             return a.playlist < b.playlist;
4067     }
4068 };
4069
4070 struct PlaylistMapping {
4071     TimeAxisView* tv;
4072     boost::shared_ptr<Playlist> pl;
4073
4074     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4075 };
4076
4077 /** Remove `clicked_regionview' */
4078 void
4079 Editor::remove_clicked_region ()
4080 {
4081         if (clicked_routeview == 0 || clicked_regionview == 0) {
4082                 return;
4083         }
4084
4085         begin_reversible_command (_("remove region"));
4086
4087         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4088
4089         playlist->clear_changes ();
4090         playlist->clear_owned_changes ();
4091         playlist->remove_region (clicked_regionview->region());
4092         if (Config->get_edit_mode() == Ripple)
4093                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4094
4095         /* We might have removed regions, which alters other regions' layering_index,
4096            so we need to do a recursive diff here.
4097         */
4098         vector<Command*> cmds;
4099         playlist->rdiff (cmds);
4100         _session->add_commands (cmds);
4101         
4102         _session->add_command(new StatefulDiffCommand (playlist));
4103         commit_reversible_command ();
4104 }
4105
4106
4107 /** Remove the selected regions */
4108 void
4109 Editor::remove_selected_regions ()
4110 {
4111         RegionSelection rs = get_regions_from_selection_and_entered ();
4112
4113         if (!_session || rs.empty()) {
4114                 return;
4115         }
4116
4117         begin_reversible_command (_("remove region"));
4118
4119         list<boost::shared_ptr<Region> > regions_to_remove;
4120
4121         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4122                 // we can't just remove the region(s) in this loop because
4123                 // this removes them from the RegionSelection, and they thus
4124                 // disappear from underneath the iterator, and the ++i above
4125                 // SEGVs in a puzzling fashion.
4126
4127                 // so, first iterate over the regions to be removed from rs and
4128                 // add them to the regions_to_remove list, and then
4129                 // iterate over the list to actually remove them.
4130
4131                 regions_to_remove.push_back ((*i)->region());
4132         }
4133
4134         vector<boost::shared_ptr<Playlist> > playlists;
4135
4136         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4137
4138                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4139
4140                 if (!playlist) {
4141                         // is this check necessary?
4142                         continue;
4143                 }
4144
4145                 /* get_regions_from_selection_and_entered() guarantees that
4146                    the playlists involved are unique, so there is no need
4147                    to check here.
4148                 */
4149
4150                 playlists.push_back (playlist);
4151
4152                 playlist->clear_changes ();
4153                 playlist->clear_owned_changes ();
4154                 playlist->freeze ();
4155                 playlist->remove_region (*rl);
4156                 if (Config->get_edit_mode() == Ripple)
4157                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4158
4159         }
4160
4161         vector<boost::shared_ptr<Playlist> >::iterator pl;
4162
4163         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4164                 (*pl)->thaw ();
4165
4166                 /* We might have removed regions, which alters other regions' layering_index,
4167                    so we need to do a recursive diff here.
4168                 */
4169                 vector<Command*> cmds;
4170                 (*pl)->rdiff (cmds);
4171                 _session->add_commands (cmds);
4172                 
4173                 _session->add_command(new StatefulDiffCommand (*pl));
4174         }
4175
4176         commit_reversible_command ();
4177 }
4178
4179 /** Cut, copy or clear selected regions.
4180  * @param op Operation (Cut, Copy or Clear)
4181  */
4182 void
4183 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4184 {
4185         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4186            a map when we want ordered access to both elements. i think.
4187         */
4188
4189         vector<PlaylistMapping> pmap;
4190
4191         framepos_t first_position = max_framepos;
4192
4193         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4194         FreezeList freezelist;
4195
4196         /* get ordering correct before we cut/copy */
4197
4198         rs.sort_by_position_and_track ();
4199
4200         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4201
4202                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4203
4204                 if (op == Cut || op == Clear || op == Delete) {
4205                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4206
4207                         if (pl) {
4208                                 FreezeList::iterator fl;
4209
4210                                 // only take state if this is a new playlist.
4211                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4212                                         if ((*fl) == pl) {
4213                                                 break;
4214                                         }
4215                                 }
4216
4217                                 if (fl == freezelist.end()) {
4218                                         pl->clear_changes();
4219                                         pl->clear_owned_changes ();
4220                                         pl->freeze ();
4221                                         freezelist.insert (pl);
4222                                 }
4223                         }
4224                 }
4225
4226                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4227                 vector<PlaylistMapping>::iterator z;
4228
4229                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4230                         if ((*z).tv == tv) {
4231                                 break;
4232                         }
4233                 }
4234
4235                 if (z == pmap.end()) {
4236                         pmap.push_back (PlaylistMapping (tv));
4237                 }
4238         }
4239
4240         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4241
4242                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4243
4244                 if (!pl) {
4245                         /* region not yet associated with a playlist (e.g. unfinished
4246                            capture pass.
4247                         */
4248                         ++x;
4249                         continue;
4250                 }
4251
4252                 TimeAxisView& tv = (*x)->get_time_axis_view();
4253                 boost::shared_ptr<Playlist> npl;
4254                 RegionSelection::iterator tmp;
4255
4256                 tmp = x;
4257                 ++tmp;
4258
4259                 if (op != Delete) {
4260
4261                         vector<PlaylistMapping>::iterator z;
4262                         
4263                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4264                                 if ((*z).tv == &tv) {
4265                                         break;
4266                                 }
4267                         }
4268                         
4269                         assert (z != pmap.end());
4270                         
4271                         if (!(*z).pl) {
4272                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4273                                 npl->freeze();
4274                                 (*z).pl = npl;
4275                         } else {
4276                                 npl = (*z).pl;
4277                         }
4278                 }
4279
4280                 boost::shared_ptr<Region> r = (*x)->region();
4281                 boost::shared_ptr<Region> _xx;
4282
4283                 assert (r != 0);
4284
4285                 switch (op) {
4286                 case Delete:
4287                         pl->remove_region (r);
4288                         if (Config->get_edit_mode() == Ripple)
4289                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4290                         break;
4291                         
4292                 case Cut:
4293                         _xx = RegionFactory::create (r);
4294                         npl->add_region (_xx, r->position() - first_position);
4295                         pl->remove_region (r);
4296                         if (Config->get_edit_mode() == Ripple)
4297                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4298                         break;
4299
4300                 case Copy:
4301                         /* copy region before adding, so we're not putting same object into two different playlists */
4302                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4303                         break;
4304
4305                 case Clear:
4306                         pl->remove_region (r);
4307                         if (Config->get_edit_mode() == Ripple)
4308                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4309                         break;
4310                 }
4311
4312                 x = tmp;
4313         }
4314
4315         if (op != Delete) {
4316
4317                 list<boost::shared_ptr<Playlist> > foo;
4318                 
4319                 /* the pmap is in the same order as the tracks in which selected regions occured */
4320                 
4321                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4322                         if ((*i).pl) {
4323                                 (*i).pl->thaw();
4324                                 foo.push_back ((*i).pl);
4325                         }
4326                 }
4327                 
4328                 if (!foo.empty()) {
4329                         cut_buffer->set (foo);
4330                 }
4331                 
4332                 if (pmap.empty()) {
4333                         _last_cut_copy_source_track = 0;
4334                 } else {
4335                         _last_cut_copy_source_track = pmap.front().tv;
4336                 }
4337         }
4338
4339         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4340                 (*pl)->thaw ();
4341
4342                 /* We might have removed regions, which alters other regions' layering_index,
4343                    so we need to do a recursive diff here.
4344                 */
4345                 vector<Command*> cmds;
4346                 (*pl)->rdiff (cmds);
4347                 _session->add_commands (cmds);
4348                 
4349                 _session->add_command (new StatefulDiffCommand (*pl));
4350         }
4351 }
4352
4353 void
4354 Editor::cut_copy_ranges (CutCopyOp op)
4355 {
4356         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4357
4358         /* Sort the track selection now, so that it if is used, the playlists
4359            selected by the calls below to cut_copy_clear are in the order that
4360            their tracks appear in the editor.  This makes things like paste
4361            of ranges work properly.
4362         */
4363
4364         sort_track_selection (ts);
4365
4366         if (ts.empty()) {
4367                 if (!entered_track) {
4368                         return;
4369                 }
4370                 ts.push_back (entered_track);
4371         } 
4372
4373         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4374                 (*i)->cut_copy_clear (*selection, op);
4375         }
4376 }
4377
4378 void
4379 Editor::paste (float times, bool from_context)
4380 {
4381         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4382
4383         paste_internal (get_preferred_edit_position (false, from_context), times);
4384 }
4385
4386 void
4387 Editor::mouse_paste ()
4388 {
4389         framepos_t where;
4390         bool ignored;
4391
4392         if (!mouse_frame (where, ignored)) {
4393                 return;
4394         }
4395
4396         snap_to (where);
4397         paste_internal (where, 1);
4398 }
4399
4400 void
4401 Editor::paste_internal (framepos_t position, float times)
4402 {
4403         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4404
4405         if (cut_buffer->empty(internal_editing())) {
4406                 return;
4407         }
4408
4409         if (position == max_framepos) {
4410                 position = get_preferred_edit_position();
4411                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4412         }
4413
4414         if (position == last_paste_pos) {
4415                 /* repeated paste in the same position */
4416                 ++paste_count;
4417         } else {
4418                 /* paste in new location, reset repeated paste state */
4419                 paste_count = 0;
4420                 last_paste_pos = position;
4421         }
4422
4423         /* get everything in the correct order */
4424
4425         TrackViewList ts;
4426         if (!selection->tracks.empty()) {
4427                 /* If there is a track selection, paste into exactly those tracks and
4428                    only those tracks.  This allows the user to be explicit and override
4429                    the below "do the reasonable thing" logic. */
4430                 ts = selection->tracks.filter_to_unique_playlists ();
4431                 sort_track_selection (ts);
4432         } else {
4433                 /* Figure out which track to base the paste at. */
4434                 TimeAxisView* base_track = NULL;
4435                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4436                         /* With the mouse edit point, paste onto the track under the mouse. */
4437                         base_track = entered_track;
4438                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4439                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4440                         base_track = &entered_regionview->get_time_axis_view();
4441                 } else if (_last_cut_copy_source_track) {
4442                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4443                         base_track = _last_cut_copy_source_track;
4444                 } else {
4445                         /* This is "impossible" since we've copied... well, do nothing. */
4446                         return;
4447                 }
4448
4449                 /* Walk up to parent if necessary, so base track is a route. */
4450                 while (base_track->get_parent()) {
4451                         base_track = base_track->get_parent();
4452                 }
4453
4454                 /* Add base track and all tracks below it.  The paste logic will select
4455                    the appropriate object types from the cut buffer in relative order. */
4456                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4457                         if ((*i)->order() >= base_track->order()) {
4458                                 ts.push_back(*i);
4459                         }
4460                 }
4461
4462                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4463                 sort_track_selection (ts);
4464
4465                 /* Add automation children of each track in order, for pasting several lines. */
4466                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4467                         /* Add any automation children for pasting several lines */
4468                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4469                         if (!rtv) {
4470                                 continue;
4471                         }
4472
4473                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4474                         const ATracks& atracks = rtv->automation_tracks();
4475                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4476                                 i = ts.insert(i, a->second.get());
4477                                 ++i;
4478                         }
4479                 }
4480
4481                 /* We now have a list of trackviews starting at base_track, including
4482                    automation children, in the order shown in the editor, e.g. R1,
4483                    R1.A1, R1.A2, R2, R2.A1, ... */
4484         }
4485
4486         if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4487             dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4488             /* Only one line copied, and one automation track selected.  Do a
4489                "greedy" paste from one automation type to another. */
4490
4491             begin_reversible_command (Operations::paste);
4492
4493             PasteContext ctx(paste_count, times, ItemCounts(), true);
4494             ts.front()->paste (position, *cut_buffer, ctx);
4495
4496             commit_reversible_command ();
4497
4498         } else if (internal_editing ()) {
4499
4500                 /* undo/redo is handled by individual tracks/regions */
4501
4502                 RegionSelection rs;
4503                 get_regions_at (rs, position, ts);
4504
4505                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4506                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4507                         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4508                         if (mrv) {
4509                                 mrv->paste (position, *cut_buffer, ctx);
4510                         }
4511                 }
4512
4513         } else {
4514
4515                 /* we do redo (do you do voodoo?) */
4516
4517                 begin_reversible_command (Operations::paste);
4518
4519                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4520                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4521                         (*i)->paste (position, *cut_buffer, ctx);
4522                 }
4523
4524                 commit_reversible_command ();
4525         }
4526 }
4527
4528 void
4529 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4530 {
4531         boost::shared_ptr<Playlist> playlist;
4532         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4533         RegionSelection foo;
4534
4535         framepos_t const start_frame = regions.start ();
4536         framepos_t const end_frame = regions.end_frame ();
4537
4538         begin_reversible_command (Operations::duplicate_region);
4539
4540         selection->clear_regions ();
4541
4542         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4543
4544                 boost::shared_ptr<Region> r ((*i)->region());
4545
4546                 TimeAxisView& tv = (*i)->get_time_axis_view();
4547                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4548                 latest_regionviews.clear ();
4549                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4550
4551                 playlist = (*i)->region()->playlist();
4552                 playlist->clear_changes ();
4553                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4554                 _session->add_command(new StatefulDiffCommand (playlist));
4555
4556                 c.disconnect ();
4557
4558                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4559         }
4560
4561         if (!foo.empty()) {
4562                 selection->set (foo);
4563         }
4564
4565         commit_reversible_command ();
4566 }
4567
4568 void
4569 Editor::duplicate_selection (float times)
4570 {
4571         if (selection->time.empty() || selection->tracks.empty()) {
4572                 return;
4573         }
4574
4575         boost::shared_ptr<Playlist> playlist;
4576         vector<boost::shared_ptr<Region> > new_regions;
4577         vector<boost::shared_ptr<Region> >::iterator ri;
4578
4579         create_region_from_selection (new_regions);
4580
4581         if (new_regions.empty()) {
4582                 return;
4583         }
4584
4585         begin_reversible_command (_("duplicate selection"));
4586
4587         ri = new_regions.begin();
4588
4589         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4590
4591         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4592                 if ((playlist = (*i)->playlist()) == 0) {
4593                         continue;
4594                 }
4595                 playlist->clear_changes ();
4596                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4597                 _session->add_command (new StatefulDiffCommand (playlist));
4598
4599                 ++ri;
4600                 if (ri == new_regions.end()) {
4601                         --ri;
4602                 }
4603         }
4604
4605         commit_reversible_command ();
4606 }
4607
4608 /** Reset all selected points to the relevant default value */
4609 void
4610 Editor::reset_point_selection ()
4611 {
4612         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4613                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4614                 (*j)->value = (*i)->line().the_list()->default_value ();
4615         }
4616 }
4617
4618 void
4619 Editor::center_playhead ()
4620 {
4621         float const page = _visible_canvas_width * samples_per_pixel;
4622         center_screen_internal (playhead_cursor->current_frame (), page);
4623 }
4624
4625 void
4626 Editor::center_edit_point ()
4627 {
4628         float const page = _visible_canvas_width * samples_per_pixel;
4629         center_screen_internal (get_preferred_edit_position(), page);
4630 }
4631
4632 /** Caller must begin and commit a reversible command */
4633 void
4634 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4635 {
4636         playlist->clear_changes ();
4637         playlist->clear ();
4638         _session->add_command (new StatefulDiffCommand (playlist));
4639 }
4640
4641 void
4642 Editor::nudge_track (bool use_edit, bool forwards)
4643 {
4644         boost::shared_ptr<Playlist> playlist;
4645         framepos_t distance;
4646         framepos_t next_distance;
4647         framepos_t start;
4648
4649         if (use_edit) {
4650                 start = get_preferred_edit_position();
4651         } else {
4652                 start = 0;
4653         }
4654
4655         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4656                 return;
4657         }
4658
4659         if (selection->tracks.empty()) {
4660                 return;
4661         }
4662
4663         begin_reversible_command (_("nudge track"));
4664
4665         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4666
4667         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4668
4669                 if ((playlist = (*i)->playlist()) == 0) {
4670                         continue;
4671                 }
4672
4673                 playlist->clear_changes ();
4674                 playlist->clear_owned_changes ();
4675
4676                 playlist->nudge_after (start, distance, forwards);
4677
4678                 vector<Command*> cmds;
4679
4680                 playlist->rdiff (cmds);
4681                 _session->add_commands (cmds);
4682
4683                 _session->add_command (new StatefulDiffCommand (playlist));
4684         }
4685
4686         commit_reversible_command ();
4687 }
4688
4689 void
4690 Editor::remove_last_capture ()
4691 {
4692         vector<string> choices;
4693         string prompt;
4694
4695         if (!_session) {
4696                 return;
4697         }
4698
4699         if (Config->get_verify_remove_last_capture()) {
4700                 prompt  = _("Do you really want to destroy the last capture?"
4701                             "\n(This is destructive and cannot be undone)");
4702
4703                 choices.push_back (_("No, do nothing."));
4704                 choices.push_back (_("Yes, destroy it."));
4705
4706                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4707
4708                 if (prompter.run () == 1) {
4709                         _session->remove_last_capture ();
4710                         _regions->redisplay ();
4711                 }
4712
4713         } else {
4714                 _session->remove_last_capture();
4715                 _regions->redisplay ();
4716         }
4717 }
4718
4719 void
4720 Editor::normalize_region ()
4721 {
4722         if (!_session) {
4723                 return;
4724         }
4725
4726         RegionSelection rs = get_regions_from_selection_and_entered ();
4727
4728         if (rs.empty()) {
4729                 return;
4730         }
4731
4732         NormalizeDialog dialog (rs.size() > 1);
4733
4734         if (dialog.run () == RESPONSE_CANCEL) {
4735                 return;
4736         }
4737
4738         set_canvas_cursor (_cursors->wait);
4739         gdk_flush ();
4740
4741         /* XXX: should really only count audio regions here */
4742         int const regions = rs.size ();
4743
4744         /* Make a list of the selected audio regions' maximum amplitudes, and also
4745            obtain the maximum amplitude of them all.
4746         */
4747         list<double> max_amps;
4748         double max_amp = 0;
4749         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4750                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4751                 if (arv) {
4752                         dialog.descend (1.0 / regions);
4753                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4754
4755                         if (a == -1) {
4756                                 /* the user cancelled the operation */
4757                                 set_canvas_cursor (current_canvas_cursor);
4758                                 return;
4759                         }
4760
4761                         max_amps.push_back (a);
4762                         max_amp = max (max_amp, a);
4763                         dialog.ascend ();
4764                 }
4765         }
4766
4767         begin_reversible_command (_("normalize"));
4768
4769         list<double>::const_iterator a = max_amps.begin ();
4770
4771         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4772                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4773                 if (!arv) {
4774                         continue;
4775                 }
4776
4777                 arv->region()->clear_changes ();
4778
4779                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4780
4781                 arv->audio_region()->normalize (amp, dialog.target ());
4782                 _session->add_command (new StatefulDiffCommand (arv->region()));
4783
4784                 ++a;
4785         }
4786
4787         commit_reversible_command ();
4788         set_canvas_cursor (current_canvas_cursor);
4789 }
4790
4791
4792 void
4793 Editor::reset_region_scale_amplitude ()
4794 {
4795         if (!_session) {
4796                 return;
4797         }
4798
4799         RegionSelection rs = get_regions_from_selection_and_entered ();
4800
4801         if (rs.empty()) {
4802                 return;
4803         }
4804
4805         begin_reversible_command ("reset gain");
4806
4807         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4808                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4809                 if (!arv)
4810                         continue;
4811                 arv->region()->clear_changes ();
4812                 arv->audio_region()->set_scale_amplitude (1.0f);
4813                 _session->add_command (new StatefulDiffCommand (arv->region()));
4814         }
4815
4816         commit_reversible_command ();
4817 }
4818
4819 void
4820 Editor::adjust_region_gain (bool up)
4821 {
4822         RegionSelection rs = get_regions_from_selection_and_entered ();
4823
4824         if (!_session || rs.empty()) {
4825                 return;
4826         }
4827
4828         begin_reversible_command ("adjust region gain");
4829
4830         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4831                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4832                 if (!arv) {
4833                         continue;
4834                 }
4835
4836                 arv->region()->clear_changes ();
4837
4838                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4839
4840                 if (up) {
4841                         dB += 1;
4842                 } else {
4843                         dB -= 1;
4844                 }
4845
4846                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4847                 _session->add_command (new StatefulDiffCommand (arv->region()));
4848         }
4849
4850         commit_reversible_command ();
4851 }
4852
4853
4854 void
4855 Editor::reverse_region ()
4856 {
4857         if (!_session) {
4858                 return;
4859         }
4860
4861         Reverse rev (*_session);
4862         apply_filter (rev, _("reverse regions"));
4863 }
4864
4865 void
4866 Editor::strip_region_silence ()
4867 {
4868         if (!_session) {
4869                 return;
4870         }
4871
4872         RegionSelection rs = get_regions_from_selection_and_entered ();
4873
4874         if (rs.empty()) {
4875                 return;
4876         }
4877
4878         std::list<RegionView*> audio_only;
4879
4880         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4881                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4882                 if (arv) {
4883                         audio_only.push_back (arv);
4884                 }
4885         }
4886
4887         StripSilenceDialog d (_session, audio_only);
4888         int const r = d.run ();
4889
4890         d.drop_rects ();
4891
4892         if (r == Gtk::RESPONSE_OK) {
4893                 ARDOUR::AudioIntervalMap silences;
4894                 d.silences (silences);
4895                 StripSilence s (*_session, silences, d.fade_length());
4896                 apply_filter (s, _("strip silence"), &d);
4897         }
4898 }
4899
4900 Command*
4901 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4902 {
4903         Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4904         mrv.selection_as_notelist (selected, true);
4905
4906         vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4907         v.push_back (selected);
4908
4909         framepos_t          pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4910         Evoral::MusicalTime pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4911
4912         return op (mrv.midi_region()->model(), pos_beats, v);
4913 }
4914
4915 void
4916 Editor::apply_midi_note_edit_op (MidiOperator& op)
4917 {
4918         Command* cmd;
4919
4920         RegionSelection rs = get_regions_from_selection_and_entered ();
4921
4922         if (rs.empty()) {
4923                 return;
4924         }
4925
4926         begin_reversible_command (op.name ());
4927
4928         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4929                 RegionSelection::iterator tmp = r;
4930                 ++tmp;
4931
4932                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4933
4934                 if (mrv) {
4935                         cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4936                         if (cmd) {
4937                                 (*cmd)();
4938                                 _session->add_command (cmd);
4939                         }
4940                 }
4941
4942                 r = tmp;
4943         }
4944
4945         commit_reversible_command ();
4946 }
4947
4948 void
4949 Editor::fork_region ()
4950 {
4951         RegionSelection rs = get_regions_from_selection_and_entered ();
4952
4953         if (rs.empty()) {
4954                 return;
4955         }
4956
4957         begin_reversible_command (_("Fork Region(s)"));
4958
4959         set_canvas_cursor (_cursors->wait);
4960         gdk_flush ();
4961
4962         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4963                 RegionSelection::iterator tmp = r;
4964                 ++tmp;
4965
4966                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4967
4968                 if (mrv) {
4969                         try {
4970                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4971                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4972                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4973                                 
4974                                 playlist->clear_changes ();
4975                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4976                                 _session->add_command(new StatefulDiffCommand (playlist));
4977                         } catch (...) {
4978                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4979                         }
4980                 }
4981
4982                 r = tmp;
4983         }
4984
4985         commit_reversible_command ();
4986
4987         set_canvas_cursor (current_canvas_cursor);
4988 }
4989
4990 void
4991 Editor::quantize_region ()
4992 {
4993         int selected_midi_region_cnt = 0;
4994
4995         if (!_session) {
4996                 return;
4997         }
4998
4999         RegionSelection rs = get_regions_from_selection_and_entered ();
5000
5001         if (rs.empty()) {
5002                 return;
5003         }
5004
5005         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5006                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5007                 if (mrv) {
5008                         selected_midi_region_cnt++;
5009                 }
5010         }
5011
5012         if (selected_midi_region_cnt == 0) {
5013                 return;
5014         }
5015
5016         QuantizeDialog* qd = new QuantizeDialog (*this);
5017
5018         qd->present ();
5019         const int r = qd->run ();
5020         qd->hide ();
5021
5022         if (r == Gtk::RESPONSE_OK) {
5023                 Quantize quant (qd->snap_start(), qd->snap_end(),
5024                                 qd->start_grid_size(), qd->end_grid_size(),
5025                                 qd->strength(), qd->swing(), qd->threshold());
5026
5027                 apply_midi_note_edit_op (quant);
5028         }
5029 }
5030
5031 void
5032 Editor::legatize_region (bool shrink_only)
5033 {
5034         int selected_midi_region_cnt = 0;
5035
5036         if (!_session) {
5037                 return;
5038         }
5039
5040         RegionSelection rs = get_regions_from_selection_and_entered ();
5041
5042         if (rs.empty()) {
5043                 return;
5044         }
5045
5046         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5047                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5048                 if (mrv) {
5049                         selected_midi_region_cnt++;
5050                 }
5051         }
5052
5053         if (selected_midi_region_cnt == 0) {
5054                 return;
5055         }
5056
5057         Legatize legatize(shrink_only);
5058         apply_midi_note_edit_op (legatize);
5059 }
5060
5061 void
5062 Editor::insert_patch_change (bool from_context)
5063 {
5064         RegionSelection rs = get_regions_from_selection_and_entered ();
5065
5066         if (rs.empty ()) {
5067                 return;
5068         }
5069
5070         const framepos_t p = get_preferred_edit_position (false, from_context);
5071
5072         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5073            there may be more than one, but the PatchChangeDialog can only offer
5074            one set of patch menus.
5075         */
5076         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5077
5078         Evoral::PatchChange<Evoral::MusicalTime> empty (Evoral::MusicalTime(), 0, 0, 0);
5079         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5080
5081         if (d.run() == RESPONSE_CANCEL) {
5082                 return;
5083         }
5084
5085         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5086                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5087                 if (mrv) {
5088                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5089                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5090                         }
5091                 }
5092         }
5093 }
5094
5095 void
5096 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5097 {
5098         RegionSelection rs = get_regions_from_selection_and_entered ();
5099
5100         if (rs.empty()) {
5101                 return;
5102         }
5103
5104         begin_reversible_command (command);
5105
5106         set_canvas_cursor (_cursors->wait);
5107         gdk_flush ();
5108
5109         int n = 0;
5110         int const N = rs.size ();
5111
5112         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5113                 RegionSelection::iterator tmp = r;
5114                 ++tmp;
5115
5116                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5117                 if (arv) {
5118                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5119
5120                         if (progress) {
5121                                 progress->descend (1.0 / N);
5122                         }
5123
5124                         if (arv->audio_region()->apply (filter, progress) == 0) {
5125
5126                                 playlist->clear_changes ();
5127                                 playlist->clear_owned_changes ();
5128
5129                                 if (filter.results.empty ()) {
5130
5131                                         /* no regions returned; remove the old one */
5132                                         playlist->remove_region (arv->region ());
5133
5134                                 } else {
5135
5136                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5137
5138                                         /* first region replaces the old one */
5139                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5140                                         ++res;
5141
5142                                         /* add the rest */
5143                                         while (res != filter.results.end()) {
5144                                                 playlist->add_region (*res, (*res)->position());
5145                                                 ++res;
5146                                         }
5147
5148                                 }
5149
5150                                 /* We might have removed regions, which alters other regions' layering_index,
5151                                    so we need to do a recursive diff here.
5152                                 */
5153                                 vector<Command*> cmds;
5154                                 playlist->rdiff (cmds);
5155                                 _session->add_commands (cmds);
5156                                 
5157                                 _session->add_command(new StatefulDiffCommand (playlist));
5158                         } else {
5159                                 goto out;
5160                         }
5161
5162                         if (progress) {
5163                                 progress->ascend ();
5164                         }
5165                 }
5166
5167                 r = tmp;
5168                 ++n;
5169         }
5170
5171         commit_reversible_command ();
5172
5173   out:
5174         set_canvas_cursor (current_canvas_cursor);
5175 }
5176
5177 void
5178 Editor::external_edit_region ()
5179 {
5180         /* more to come */
5181 }
5182
5183 void
5184 Editor::reset_region_gain_envelopes ()
5185 {
5186         RegionSelection rs = get_regions_from_selection_and_entered ();
5187
5188         if (!_session || rs.empty()) {
5189                 return;
5190         }
5191
5192         begin_reversible_command (_("reset region gain"));
5193         
5194         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5195                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5196                 if (arv) {
5197                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5198                         XMLNode& before (alist->get_state());
5199
5200                         arv->audio_region()->set_default_envelope ();
5201                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5202                 }
5203         }
5204         
5205         commit_reversible_command ();
5206 }
5207
5208 void
5209 Editor::set_region_gain_visibility (RegionView* rv)
5210 {
5211         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5212         if (arv) {
5213                 arv->update_envelope_visibility();
5214         }
5215 }
5216
5217 void
5218 Editor::set_gain_envelope_visibility ()
5219 {
5220         if (!_session) {
5221                 return;
5222         }
5223
5224         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5225                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5226                 if (v) {
5227                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5228                 }
5229         }
5230 }
5231
5232 void
5233 Editor::toggle_gain_envelope_active ()
5234 {
5235         if (_ignore_region_action) {
5236                 return;
5237         }
5238
5239         RegionSelection rs = get_regions_from_selection_and_entered ();
5240
5241         if (!_session || rs.empty()) {
5242                 return;
5243         }
5244
5245         begin_reversible_command (_("region gain envelope active"));
5246         
5247         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5248                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5249                 if (arv) {
5250                         arv->region()->clear_changes ();
5251                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5252                         _session->add_command (new StatefulDiffCommand (arv->region()));
5253                 }
5254         }
5255         
5256         commit_reversible_command ();
5257 }
5258
5259 void
5260 Editor::toggle_region_lock ()
5261 {
5262         if (_ignore_region_action) {
5263                 return;
5264         }
5265
5266         RegionSelection rs = get_regions_from_selection_and_entered ();
5267
5268         if (!_session || rs.empty()) {
5269                 return;
5270         }
5271
5272         begin_reversible_command (_("toggle region lock"));
5273         
5274         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5275                 (*i)->region()->clear_changes ();
5276                 (*i)->region()->set_locked (!(*i)->region()->locked());
5277                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5278         }
5279         
5280         commit_reversible_command ();
5281 }
5282
5283 void
5284 Editor::toggle_region_video_lock ()
5285 {
5286         if (_ignore_region_action) {
5287                 return;
5288         }
5289
5290         RegionSelection rs = get_regions_from_selection_and_entered ();
5291
5292         if (!_session || rs.empty()) {
5293                 return;
5294         }
5295
5296         begin_reversible_command (_("Toggle Video Lock"));
5297         
5298         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5299                 (*i)->region()->clear_changes ();
5300                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5301                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5302         }
5303         
5304         commit_reversible_command ();
5305 }
5306
5307 void
5308 Editor::toggle_region_lock_style ()
5309 {
5310         if (_ignore_region_action) {
5311                 return;
5312         }
5313
5314         RegionSelection rs = get_regions_from_selection_and_entered ();
5315
5316         if (!_session || rs.empty()) {
5317                 return;
5318         }
5319
5320         begin_reversible_command (_("region lock style"));
5321         
5322         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5323                 (*i)->region()->clear_changes ();
5324                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5325                 (*i)->region()->set_position_lock_style (ns);
5326                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5327         }
5328         
5329         commit_reversible_command ();
5330 }
5331
5332 void
5333 Editor::toggle_opaque_region ()
5334 {
5335         if (_ignore_region_action) {
5336                 return;
5337         }
5338
5339         RegionSelection rs = get_regions_from_selection_and_entered ();
5340
5341         if (!_session || rs.empty()) {
5342                 return;
5343         }
5344
5345         begin_reversible_command (_("change region opacity"));
5346         
5347         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5348                 (*i)->region()->clear_changes ();
5349                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5350                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5351         }
5352         
5353         commit_reversible_command ();
5354 }
5355
5356 void
5357 Editor::toggle_record_enable ()
5358 {
5359         bool new_state = false;
5360         bool first = true;
5361         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5362                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5363                 if (!rtav)
5364                         continue;
5365                 if (!rtav->is_track())
5366                         continue;
5367
5368                 if (first) {
5369                         new_state = !rtav->track()->record_enabled();
5370                         first = false;
5371                 }
5372
5373                 rtav->track()->set_record_enabled (new_state, this);
5374         }
5375 }
5376
5377 void
5378 Editor::toggle_solo ()
5379 {
5380         bool new_state = false;
5381         bool first = true;
5382         boost::shared_ptr<RouteList> rl (new RouteList);
5383
5384         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5385                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5386
5387                 if (!rtav) {
5388                         continue;
5389                 }
5390
5391                 if (first) {
5392                         new_state = !rtav->route()->soloed ();
5393                         first = false;
5394                 }
5395
5396                 rl->push_back (rtav->route());
5397         }
5398
5399         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5400 }
5401
5402 void
5403 Editor::toggle_mute ()
5404 {
5405         bool new_state = false;
5406         bool first = true;
5407         boost::shared_ptr<RouteList> rl (new RouteList);
5408
5409         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5410                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5411
5412                 if (!rtav) {
5413                         continue;
5414                 }
5415
5416                 if (first) {
5417                         new_state = !rtav->route()->muted();
5418                         first = false;
5419                 }
5420
5421                 rl->push_back (rtav->route());
5422         }
5423
5424         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5425 }
5426
5427 void
5428 Editor::toggle_solo_isolate ()
5429 {
5430 }
5431
5432
5433 void
5434 Editor::fade_range ()
5435 {
5436         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5437
5438         begin_reversible_command (_("fade range"));
5439
5440         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5441                 (*i)->fade_range (selection->time);
5442         }
5443
5444         commit_reversible_command ();
5445 }
5446
5447
5448 void
5449 Editor::set_fade_length (bool in)
5450 {
5451         RegionSelection rs = get_regions_from_selection_and_entered ();
5452
5453         if (rs.empty()) {
5454                 return;
5455         }
5456
5457         /* we need a region to measure the offset from the start */
5458
5459         RegionView* rv = rs.front ();
5460
5461         framepos_t pos = get_preferred_edit_position();
5462         framepos_t len;
5463         char const * cmd;
5464
5465         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5466                 /* edit point is outside the relevant region */
5467                 return;
5468         }
5469
5470         if (in) {
5471                 if (pos <= rv->region()->position()) {
5472                         /* can't do it */
5473                         return;
5474                 }
5475                 len = pos - rv->region()->position();
5476                 cmd = _("set fade in length");
5477         } else {
5478                 if (pos >= rv->region()->last_frame()) {
5479                         /* can't do it */
5480                         return;
5481                 }
5482                 len = rv->region()->last_frame() - pos;
5483                 cmd = _("set fade out length");
5484         }
5485
5486         begin_reversible_command (cmd);
5487
5488         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5489                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5490
5491                 if (!tmp) {
5492                         return;
5493                 }
5494
5495                 boost::shared_ptr<AutomationList> alist;
5496                 if (in) {
5497                         alist = tmp->audio_region()->fade_in();
5498                 } else {
5499                         alist = tmp->audio_region()->fade_out();
5500                 }
5501
5502                 XMLNode &before = alist->get_state();
5503
5504                 if (in) {
5505                         tmp->audio_region()->set_fade_in_length (len);
5506                         tmp->audio_region()->set_fade_in_active (true);
5507                 } else {
5508                         tmp->audio_region()->set_fade_out_length (len);
5509                         tmp->audio_region()->set_fade_out_active (true);
5510                 }
5511
5512                 XMLNode &after = alist->get_state();
5513                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5514         }
5515
5516         commit_reversible_command ();
5517 }
5518
5519 void
5520 Editor::set_fade_in_shape (FadeShape shape)
5521 {
5522         RegionSelection rs = get_regions_from_selection_and_entered ();
5523
5524         if (rs.empty()) {
5525                 return;
5526         }
5527
5528         begin_reversible_command (_("set fade in shape"));
5529
5530         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5531                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5532
5533                 if (!tmp) {
5534                         return;
5535                 }
5536
5537                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5538                 XMLNode &before = alist->get_state();
5539
5540                 tmp->audio_region()->set_fade_in_shape (shape);
5541
5542                 XMLNode &after = alist->get_state();
5543                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5544         }
5545
5546         commit_reversible_command ();
5547
5548 }
5549
5550 void
5551 Editor::set_fade_out_shape (FadeShape shape)
5552 {
5553         RegionSelection rs = get_regions_from_selection_and_entered ();
5554
5555         if (rs.empty()) {
5556                 return;
5557         }
5558
5559         begin_reversible_command (_("set fade out shape"));
5560
5561         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5562                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5563
5564                 if (!tmp) {
5565                         return;
5566                 }
5567
5568                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5569                 XMLNode &before = alist->get_state();
5570
5571                 tmp->audio_region()->set_fade_out_shape (shape);
5572
5573                 XMLNode &after = alist->get_state();
5574                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5575         }
5576
5577         commit_reversible_command ();
5578 }
5579
5580 void
5581 Editor::set_fade_in_active (bool yn)
5582 {
5583         RegionSelection rs = get_regions_from_selection_and_entered ();
5584
5585         if (rs.empty()) {
5586                 return;
5587         }
5588
5589         begin_reversible_command (_("set fade in active"));
5590
5591         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5592                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5593
5594                 if (!tmp) {
5595                         return;
5596                 }
5597
5598
5599                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5600
5601                 ar->clear_changes ();
5602                 ar->set_fade_in_active (yn);
5603                 _session->add_command (new StatefulDiffCommand (ar));
5604         }
5605
5606         commit_reversible_command ();
5607 }
5608
5609 void
5610 Editor::set_fade_out_active (bool yn)
5611 {
5612         RegionSelection rs = get_regions_from_selection_and_entered ();
5613
5614         if (rs.empty()) {
5615                 return;
5616         }
5617
5618         begin_reversible_command (_("set fade out active"));
5619
5620         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5621                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5622
5623                 if (!tmp) {
5624                         return;
5625                 }
5626
5627                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5628
5629                 ar->clear_changes ();
5630                 ar->set_fade_out_active (yn);
5631                 _session->add_command(new StatefulDiffCommand (ar));
5632         }
5633
5634         commit_reversible_command ();
5635 }
5636
5637 void
5638 Editor::toggle_region_fades (int dir)
5639 {
5640         if (_ignore_region_action) {
5641                 return;
5642         }
5643         
5644         boost::shared_ptr<AudioRegion> ar;
5645         bool yn = false;
5646
5647         RegionSelection rs = get_regions_from_selection_and_entered ();
5648
5649         if (rs.empty()) {
5650                 return;
5651         }
5652
5653         RegionSelection::iterator i;
5654         for (i = rs.begin(); i != rs.end(); ++i) {
5655                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5656                         if (dir == -1) {
5657                                 yn = ar->fade_out_active ();
5658                         } else {
5659                                 yn = ar->fade_in_active ();
5660                         }
5661                         break;
5662                 }
5663         }
5664
5665         if (i == rs.end()) {
5666                 return;
5667         }
5668
5669         /* XXX should this undo-able? */
5670
5671         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5672                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5673                         continue;
5674                 }
5675                 if (dir == 1 || dir == 0) {
5676                         ar->set_fade_in_active (!yn);
5677                 }
5678
5679                 if (dir == -1 || dir == 0) {
5680                         ar->set_fade_out_active (!yn);
5681                 }
5682         }
5683 }
5684
5685
5686 /** Update region fade visibility after its configuration has been changed */
5687 void
5688 Editor::update_region_fade_visibility ()
5689 {
5690         bool _fade_visibility = _session->config.get_show_region_fades ();
5691
5692         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5693                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5694                 if (v) {
5695                         if (_fade_visibility) {
5696                                 v->audio_view()->show_all_fades ();
5697                         } else {
5698                                 v->audio_view()->hide_all_fades ();
5699                         }
5700                 }
5701         }
5702 }
5703
5704 void
5705 Editor::set_edit_point ()
5706 {
5707         framepos_t where;
5708         bool ignored;
5709
5710         if (!mouse_frame (where, ignored)) {
5711                 return;
5712         }
5713
5714         snap_to (where);
5715
5716         if (selection->markers.empty()) {
5717
5718                 mouse_add_new_marker (where);
5719
5720         } else {
5721                 bool ignored;
5722
5723                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5724
5725                 if (loc) {
5726                         loc->move_to (where);
5727                 }
5728         }
5729 }
5730
5731 void
5732 Editor::set_playhead_cursor ()
5733 {
5734         if (entered_marker) {
5735                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5736         } else {
5737                 framepos_t where;
5738                 bool ignored;
5739
5740                 if (!mouse_frame (where, ignored)) {
5741                         return;
5742                 }
5743
5744                 snap_to (where);
5745
5746                 if (_session) {
5747                         _session->request_locate (where, _session->transport_rolling());
5748                 }
5749         }
5750
5751         if ( Config->get_follow_edits() )
5752                 cancel_time_selection();
5753 }
5754
5755 void
5756 Editor::split_region ()
5757 {
5758         if ( !selection->time.empty()) {
5759                 separate_regions_between (selection->time);
5760                 return;
5761         }
5762
5763         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5764
5765         framepos_t where = get_preferred_edit_position ();
5766
5767         if (rs.empty()) {
5768                 return;
5769         }
5770
5771         split_regions_at (where, rs);
5772 }
5773
5774 struct EditorOrderRouteSorter {
5775     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5776             return a->order_key () < b->order_key ();
5777     }
5778 };
5779
5780 void
5781 Editor::select_next_route()
5782 {
5783         if (selection->tracks.empty()) {
5784                 selection->set (track_views.front());
5785                 return;
5786         }
5787
5788         TimeAxisView* current = selection->tracks.front();
5789
5790         RouteUI *rui;
5791         do {
5792                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5793                         if (*i == current) {
5794                                 ++i;
5795                                 if (i != track_views.end()) {
5796                                         current = (*i);
5797                                 } else {
5798                                         current = (*(track_views.begin()));
5799                                         //selection->set (*(track_views.begin()));
5800                                 }
5801                                 break;
5802                         }
5803                 }
5804                 rui = dynamic_cast<RouteUI *>(current);
5805         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5806
5807         selection->set(current);
5808
5809         ensure_time_axis_view_is_visible (*current, false);
5810 }
5811
5812 void
5813 Editor::select_prev_route()
5814 {
5815         if (selection->tracks.empty()) {
5816                 selection->set (track_views.front());
5817                 return;
5818         }
5819
5820         TimeAxisView* current = selection->tracks.front();
5821
5822         RouteUI *rui;
5823         do {
5824                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5825                         if (*i == current) {
5826                                 ++i;
5827                                 if (i != track_views.rend()) {
5828                                         current = (*i);
5829                                 } else {
5830                                         current = *(track_views.rbegin());
5831                                 }
5832                                 break;
5833                         }
5834                 }
5835                 rui = dynamic_cast<RouteUI *>(current);
5836         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5837
5838         selection->set (current);
5839
5840         ensure_time_axis_view_is_visible (*current, false);
5841 }
5842
5843 void
5844 Editor::set_loop_from_selection (bool play)
5845 {
5846         if (_session == 0 || selection->time.empty()) {
5847                 return;
5848         }
5849
5850         framepos_t start = selection->time[clicked_selection].start;
5851         framepos_t end = selection->time[clicked_selection].end;
5852
5853         set_loop_range (start, end,  _("set loop range from selection"));
5854
5855         if (play) {
5856                 _session->request_locate (start, true);
5857                 _session->request_play_loop (true);
5858         }
5859 }
5860
5861 void
5862 Editor::set_loop_from_edit_range (bool play)
5863 {
5864         if (_session == 0) {
5865                 return;
5866         }
5867
5868         framepos_t start;
5869         framepos_t end;
5870
5871         if (!get_edit_op_range (start, end)) {
5872                 return;
5873         }
5874
5875         set_loop_range (start, end,  _("set loop range from edit range"));
5876
5877         if (play) {
5878                 _session->request_locate (start, true);
5879                 _session->request_play_loop (true);
5880         }
5881 }
5882
5883 void
5884 Editor::set_loop_from_region (bool play)
5885 {
5886         framepos_t start = max_framepos;
5887         framepos_t end = 0;
5888
5889         RegionSelection rs = get_regions_from_selection_and_entered ();
5890
5891         if (rs.empty()) {
5892                 return;
5893         }
5894
5895         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5896                 if ((*i)->region()->position() < start) {
5897                         start = (*i)->region()->position();
5898                 }
5899                 if ((*i)->region()->last_frame() + 1 > end) {
5900                         end = (*i)->region()->last_frame() + 1;
5901                 }
5902         }
5903
5904         set_loop_range (start, end, _("set loop range from region"));
5905
5906         if (play) {
5907                 _session->request_locate (start, true);
5908                 _session->request_play_loop (true);
5909         }
5910 }
5911
5912 void
5913 Editor::set_punch_from_selection ()
5914 {
5915         if (_session == 0 || selection->time.empty()) {
5916                 return;
5917         }
5918
5919         framepos_t start = selection->time[clicked_selection].start;
5920         framepos_t end = selection->time[clicked_selection].end;
5921
5922         set_punch_range (start, end,  _("set punch range from selection"));
5923 }
5924
5925 void
5926 Editor::set_session_extents_from_selection ()
5927 {
5928         if (_session == 0 || selection->time.empty()) {
5929                 return;
5930         }
5931
5932         begin_reversible_command (_("set session start/stop from selection"));
5933
5934         framepos_t start = selection->time[clicked_selection].start;
5935         framepos_t end = selection->time[clicked_selection].end;
5936
5937         Location* loc;
5938         if ((loc = _session->locations()->session_range_location()) == 0) {
5939                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
5940         } else {
5941                 XMLNode &before = loc->get_state();
5942
5943                 _session->set_session_extents ( start, end );
5944
5945                 XMLNode &after = loc->get_state();
5946
5947                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
5948
5949                 commit_reversible_command ();
5950         }
5951 }
5952
5953 void
5954 Editor::set_punch_from_edit_range ()
5955 {
5956         if (_session == 0) {
5957                 return;
5958         }
5959
5960         framepos_t start;
5961         framepos_t end;
5962
5963         if (!get_edit_op_range (start, end)) {
5964                 return;
5965         }
5966
5967         set_punch_range (start, end,  _("set punch range from edit range"));
5968 }
5969
5970 void
5971 Editor::set_punch_from_region ()
5972 {
5973         framepos_t start = max_framepos;
5974         framepos_t end = 0;
5975
5976         RegionSelection rs = get_regions_from_selection_and_entered ();
5977
5978         if (rs.empty()) {
5979                 return;
5980         }
5981
5982         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5983                 if ((*i)->region()->position() < start) {
5984                         start = (*i)->region()->position();
5985                 }
5986                 if ((*i)->region()->last_frame() + 1 > end) {
5987                         end = (*i)->region()->last_frame() + 1;
5988                 }
5989         }
5990
5991         set_punch_range (start, end, _("set punch range from region"));
5992 }
5993
5994 void
5995 Editor::pitch_shift_region ()
5996 {
5997         RegionSelection rs = get_regions_from_selection_and_entered ();
5998
5999         RegionSelection audio_rs;
6000         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6001                 if (dynamic_cast<AudioRegionView*> (*i)) {
6002                         audio_rs.push_back (*i);
6003                 }
6004         }
6005
6006         if (audio_rs.empty()) {
6007                 return;
6008         }
6009
6010         pitch_shift (audio_rs, 1.2);
6011 }
6012
6013 void
6014 Editor::transpose_region ()
6015 {
6016         RegionSelection rs = get_regions_from_selection_and_entered ();
6017
6018         list<MidiRegionView*> midi_region_views;
6019         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6020                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6021                 if (mrv) {
6022                         midi_region_views.push_back (mrv);
6023                 }
6024         }
6025
6026         TransposeDialog d;
6027         int const r = d.run ();
6028         if (r != RESPONSE_ACCEPT) {
6029                 return;
6030         }
6031
6032         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6033                 (*i)->midi_region()->transpose (d.semitones ());
6034         }
6035 }
6036
6037 void
6038 Editor::set_tempo_from_region ()
6039 {
6040         RegionSelection rs = get_regions_from_selection_and_entered ();
6041
6042         if (!_session || rs.empty()) {
6043                 return;
6044         }
6045
6046         RegionView* rv = rs.front();
6047
6048         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6049 }
6050
6051 void
6052 Editor::use_range_as_bar ()
6053 {
6054         framepos_t start, end;
6055         if (get_edit_op_range (start, end)) {
6056                 define_one_bar (start, end);
6057         }
6058 }
6059
6060 void
6061 Editor::define_one_bar (framepos_t start, framepos_t end)
6062 {
6063         framepos_t length = end - start;
6064
6065         const Meter& m (_session->tempo_map().meter_at (start));
6066
6067         /* length = 1 bar */
6068
6069         /* now we want frames per beat.
6070            we have frames per bar, and beats per bar, so ...
6071         */
6072
6073         /* XXXX METER MATH */
6074
6075         double frames_per_beat = length / m.divisions_per_bar();
6076
6077         /* beats per minute = */
6078
6079         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6080
6081         /* now decide whether to:
6082
6083             (a) set global tempo
6084             (b) add a new tempo marker
6085
6086         */
6087
6088         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6089
6090         bool do_global = false;
6091
6092         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6093
6094                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6095                    at the start, or create a new marker
6096                 */
6097
6098                 vector<string> options;
6099                 options.push_back (_("Cancel"));
6100                 options.push_back (_("Add new marker"));
6101                 options.push_back (_("Set global tempo"));
6102
6103                 Choice c (
6104                         _("Define one bar"),
6105                         _("Do you want to set the global tempo or add a new tempo marker?"),
6106                         options
6107                         );
6108
6109                 c.set_default_response (2);
6110
6111                 switch (c.run()) {
6112                 case 0:
6113                         return;
6114
6115                 case 2:
6116                         do_global = true;
6117                         break;
6118
6119                 default:
6120                         do_global = false;
6121                 }
6122
6123         } else {
6124
6125                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6126                    if the marker is at the region starter, change it, otherwise add
6127                    a new tempo marker
6128                 */
6129         }
6130
6131         begin_reversible_command (_("set tempo from region"));
6132         XMLNode& before (_session->tempo_map().get_state());
6133
6134         if (do_global) {
6135                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6136         } else if (t.frame() == start) {
6137                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6138         } else {
6139                 Timecode::BBT_Time bbt;
6140                 _session->tempo_map().bbt_time (start, bbt);
6141                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6142         }
6143
6144         XMLNode& after (_session->tempo_map().get_state());
6145
6146         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6147         commit_reversible_command ();
6148 }
6149
6150 void
6151 Editor::split_region_at_transients ()
6152 {
6153         AnalysisFeatureList positions;
6154
6155         RegionSelection rs = get_regions_from_selection_and_entered ();
6156
6157         if (!_session || rs.empty()) {
6158                 return;
6159         }
6160
6161         begin_reversible_command (_("split regions"));
6162         
6163         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6164
6165                 RegionSelection::iterator tmp;
6166
6167                 tmp = i;
6168                 ++tmp;
6169
6170                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6171
6172                 if (ar && (ar->get_transients (positions) == 0)) {
6173                         split_region_at_points ((*i)->region(), positions, true);
6174                         positions.clear ();
6175                 }
6176
6177                 i = tmp;
6178         }
6179         
6180         commit_reversible_command ();
6181
6182 }
6183
6184 void
6185 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6186 {
6187         bool use_rhythmic_rodent = false;
6188
6189         boost::shared_ptr<Playlist> pl = r->playlist();
6190
6191         list<boost::shared_ptr<Region> > new_regions;
6192
6193         if (!pl) {
6194                 return;
6195         }
6196
6197         if (positions.empty()) {
6198                 return;
6199         }
6200
6201
6202         if (positions.size() > 20 && can_ferret) {
6203                 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);
6204                 MessageDialog msg (msgstr,
6205                                    false,
6206                                    Gtk::MESSAGE_INFO,
6207                                    Gtk::BUTTONS_OK_CANCEL);
6208
6209                 if (can_ferret) {
6210                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6211                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6212                 } else {
6213                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6214                 }
6215
6216                 msg.set_title (_("Excessive split?"));
6217                 msg.present ();
6218
6219                 int response = msg.run();
6220                 msg.hide ();
6221
6222                 switch (response) {
6223                 case RESPONSE_OK:
6224                         break;
6225                 case RESPONSE_APPLY:
6226                         use_rhythmic_rodent = true;
6227                         break;
6228                 default:
6229                         return;
6230                 }
6231         }
6232
6233         if (use_rhythmic_rodent) {
6234                 show_rhythm_ferret ();
6235                 return;
6236         }
6237
6238         AnalysisFeatureList::const_iterator x;
6239
6240         pl->clear_changes ();
6241         pl->clear_owned_changes ();
6242
6243         x = positions.begin();
6244
6245         if (x == positions.end()) {
6246                 return;
6247         }
6248
6249         pl->freeze ();
6250         pl->remove_region (r);
6251
6252         framepos_t pos = 0;
6253
6254         while (x != positions.end()) {
6255
6256                 /* deal with positons that are out of scope of present region bounds */
6257                 if (*x <= 0 || *x > r->length()) {
6258                         ++x;
6259                         continue;
6260                 }
6261
6262                 /* file start = original start + how far we from the initial position ?
6263                  */
6264
6265                 framepos_t file_start = r->start() + pos;
6266
6267                 /* length = next position - current position
6268                  */
6269
6270                 framepos_t len = (*x) - pos;
6271
6272                 /* XXX we do we really want to allow even single-sample regions?
6273                    shouldn't we have some kind of lower limit on region size?
6274                 */
6275
6276                 if (len <= 0) {
6277                         break;
6278                 }
6279
6280                 string new_name;
6281
6282                 if (RegionFactory::region_name (new_name, r->name())) {
6283                         break;
6284                 }
6285
6286                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6287
6288                 PropertyList plist;
6289
6290                 plist.add (ARDOUR::Properties::start, file_start);
6291                 plist.add (ARDOUR::Properties::length, len);
6292                 plist.add (ARDOUR::Properties::name, new_name);
6293                 plist.add (ARDOUR::Properties::layer, 0);
6294
6295                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6296                 /* because we set annouce to false, manually add the new region to the
6297                    RegionFactory map
6298                 */
6299                 RegionFactory::map_add (nr);
6300
6301                 pl->add_region (nr, r->position() + pos);
6302
6303                 if (select_new) {
6304                         new_regions.push_front(nr);
6305                 }
6306
6307                 pos += len;
6308                 ++x;
6309         }
6310
6311         string new_name;
6312
6313         RegionFactory::region_name (new_name, r->name());
6314
6315         /* Add the final region */
6316         PropertyList plist;
6317
6318         plist.add (ARDOUR::Properties::start, r->start() + pos);
6319         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6320         plist.add (ARDOUR::Properties::name, new_name);
6321         plist.add (ARDOUR::Properties::layer, 0);
6322
6323         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6324         /* because we set annouce to false, manually add the new region to the
6325            RegionFactory map
6326         */
6327         RegionFactory::map_add (nr);
6328         pl->add_region (nr, r->position() + pos);
6329
6330         if (select_new) {
6331                 new_regions.push_front(nr);
6332         }
6333
6334         pl->thaw ();
6335
6336         /* We might have removed regions, which alters other regions' layering_index,
6337            so we need to do a recursive diff here.
6338         */
6339         vector<Command*> cmds;
6340         pl->rdiff (cmds);
6341         _session->add_commands (cmds);
6342         
6343         _session->add_command (new StatefulDiffCommand (pl));
6344
6345         if (select_new) {
6346
6347                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6348                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6349                 }
6350         }
6351 }
6352
6353 void
6354 Editor::place_transient()
6355 {
6356         if (!_session) {
6357                 return;
6358         }
6359
6360         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6361
6362         if (rs.empty()) {
6363                 return;
6364         }
6365
6366         framepos_t where = get_preferred_edit_position();
6367
6368         begin_reversible_command (_("place transient"));
6369         
6370         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6371                 framepos_t position = (*r)->region()->position();
6372                 (*r)->region()->add_transient(where - position);
6373         }
6374         
6375         commit_reversible_command ();
6376 }
6377
6378 void
6379 Editor::remove_transient(ArdourCanvas::Item* item)
6380 {
6381         if (!_session) {
6382                 return;
6383         }
6384
6385         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6386         assert (_line);
6387
6388         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6389         _arv->remove_transient (*(float*) _line->get_data ("position"));
6390 }
6391
6392 void
6393 Editor::snap_regions_to_grid ()
6394 {
6395         list <boost::shared_ptr<Playlist > > used_playlists;
6396
6397         RegionSelection rs = get_regions_from_selection_and_entered ();
6398
6399         if (!_session || rs.empty()) {
6400                 return;
6401         }
6402
6403         begin_reversible_command (_("snap regions to grid"));
6404         
6405         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6406
6407                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6408
6409                 if (!pl->frozen()) {
6410                         /* we haven't seen this playlist before */
6411
6412                         /* remember used playlists so we can thaw them later */
6413                         used_playlists.push_back(pl);
6414                         pl->freeze();
6415                 }
6416
6417                 framepos_t start_frame = (*r)->region()->first_frame ();
6418                 snap_to (start_frame);
6419                 (*r)->region()->set_position (start_frame);
6420         }
6421
6422         while (used_playlists.size() > 0) {
6423                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6424                 (*i)->thaw();
6425                 used_playlists.pop_front();
6426         }
6427         
6428         commit_reversible_command ();
6429 }
6430
6431 void
6432 Editor::close_region_gaps ()
6433 {
6434         list <boost::shared_ptr<Playlist > > used_playlists;
6435
6436         RegionSelection rs = get_regions_from_selection_and_entered ();
6437
6438         if (!_session || rs.empty()) {
6439                 return;
6440         }
6441
6442         Dialog dialog (_("Close Region Gaps"));
6443
6444         Table table (2, 3);
6445         table.set_spacings (12);
6446         table.set_border_width (12);
6447         Label* l = manage (left_aligned_label (_("Crossfade length")));
6448         table.attach (*l, 0, 1, 0, 1);
6449
6450         SpinButton spin_crossfade (1, 0);
6451         spin_crossfade.set_range (0, 15);
6452         spin_crossfade.set_increments (1, 1);
6453         spin_crossfade.set_value (5);
6454         table.attach (spin_crossfade, 1, 2, 0, 1);
6455
6456         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6457
6458         l = manage (left_aligned_label (_("Pull-back length")));
6459         table.attach (*l, 0, 1, 1, 2);
6460
6461         SpinButton spin_pullback (1, 0);
6462         spin_pullback.set_range (0, 100);
6463         spin_pullback.set_increments (1, 1);
6464         spin_pullback.set_value(30);
6465         table.attach (spin_pullback, 1, 2, 1, 2);
6466
6467         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6468
6469         dialog.get_vbox()->pack_start (table);
6470         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6471         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6472         dialog.show_all ();
6473
6474         if (dialog.run () == RESPONSE_CANCEL) {
6475                 return;
6476         }
6477
6478         framepos_t crossfade_len = spin_crossfade.get_value();
6479         framepos_t pull_back_frames = spin_pullback.get_value();
6480
6481         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6482         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6483
6484         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6485
6486         begin_reversible_command (_("close region gaps"));
6487         
6488         int idx = 0;
6489         boost::shared_ptr<Region> last_region;
6490
6491         rs.sort_by_position_and_track();
6492
6493         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6494
6495                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6496
6497                 if (!pl->frozen()) {
6498                         /* we haven't seen this playlist before */
6499
6500                         /* remember used playlists so we can thaw them later */
6501                         used_playlists.push_back(pl);
6502                         pl->freeze();
6503                 }
6504
6505                 framepos_t position = (*r)->region()->position();
6506
6507                 if (idx == 0 || position < last_region->position()){
6508                         last_region = (*r)->region();
6509                         idx++;
6510                         continue;
6511                 }
6512
6513                 (*r)->region()->trim_front( (position - pull_back_frames));
6514                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6515
6516                 last_region = (*r)->region();
6517
6518                 idx++;
6519         }
6520
6521         while (used_playlists.size() > 0) {
6522                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6523                 (*i)->thaw();
6524                 used_playlists.pop_front();
6525         }
6526         
6527         commit_reversible_command ();
6528 }
6529
6530 void
6531 Editor::tab_to_transient (bool forward)
6532 {
6533         AnalysisFeatureList positions;
6534
6535         RegionSelection rs = get_regions_from_selection_and_entered ();
6536
6537         if (!_session) {
6538                 return;
6539         }
6540
6541         framepos_t pos = _session->audible_frame ();
6542
6543         if (!selection->tracks.empty()) {
6544
6545                 /* don't waste time searching for transients in duplicate playlists.
6546                  */
6547
6548                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6549
6550                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6551
6552                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6553
6554                         if (rtv) {
6555                                 boost::shared_ptr<Track> tr = rtv->track();
6556                                 if (tr) {
6557                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6558                                         if (pl) {
6559                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6560
6561                                                 if (result >= 0) {
6562                                                         positions.push_back (result);
6563                                                 }
6564                                         }
6565                                 }
6566                         }
6567                 }
6568
6569         } else {
6570
6571                 if (rs.empty()) {
6572                         return;
6573                 }
6574
6575                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6576                         (*r)->region()->get_transients (positions);
6577                 }
6578         }
6579
6580         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6581
6582         if (forward) {
6583                 AnalysisFeatureList::iterator x;
6584
6585                 for (x = positions.begin(); x != positions.end(); ++x) {
6586                         if ((*x) > pos) {
6587                                 break;
6588                         }
6589                 }
6590
6591                 if (x != positions.end ()) {
6592                         _session->request_locate (*x);
6593                 }
6594
6595         } else {
6596                 AnalysisFeatureList::reverse_iterator x;
6597
6598                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6599                         if ((*x) < pos) {
6600                                 break;
6601                         }
6602                 }
6603
6604                 if (x != positions.rend ()) {
6605                         _session->request_locate (*x);
6606                 }
6607         }
6608 }
6609
6610 void
6611 Editor::playhead_forward_to_grid ()
6612 {
6613         if (!_session) {
6614                 return;
6615         }
6616         
6617         framepos_t pos = playhead_cursor->current_frame ();
6618         if (pos < max_framepos - 1) {
6619                 pos += 2;
6620                 snap_to_internal (pos, RoundUpAlways, false);
6621                 _session->request_locate (pos);
6622         }
6623 }
6624
6625
6626 void
6627 Editor::playhead_backward_to_grid ()
6628 {
6629         if (!_session) {
6630                 return;
6631         }
6632         
6633         framepos_t pos = playhead_cursor->current_frame ();
6634         if (pos > 2) {
6635                 pos -= 2;
6636                 snap_to_internal (pos, RoundDownAlways, false);
6637                 _session->request_locate (pos);
6638         }
6639 }
6640
6641 void
6642 Editor::set_track_height (Height h)
6643 {
6644         TrackSelection& ts (selection->tracks);
6645
6646         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6647                 (*x)->set_height_enum (h);
6648         }
6649 }
6650
6651 void
6652 Editor::toggle_tracks_active ()
6653 {
6654         TrackSelection& ts (selection->tracks);
6655         bool first = true;
6656         bool target = false;
6657
6658         if (ts.empty()) {
6659                 return;
6660         }
6661
6662         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6663                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6664
6665                 if (rtv) {
6666                         if (first) {
6667                                 target = !rtv->_route->active();
6668                                 first = false;
6669                         }
6670                         rtv->_route->set_active (target, this);
6671                 }
6672         }
6673 }
6674
6675 void
6676 Editor::remove_tracks ()
6677 {
6678         TrackSelection& ts (selection->tracks);
6679
6680         if (ts.empty()) {
6681                 return;
6682         }
6683
6684         vector<string> choices;
6685         string prompt;
6686         int ntracks = 0;
6687         int nbusses = 0;
6688         const char* trackstr;
6689         const char* busstr;
6690         vector<boost::shared_ptr<Route> > routes;
6691         bool special_bus = false;
6692
6693         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6694                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6695                 if (!rtv) {
6696                         continue;
6697                 }
6698                 if (rtv->is_track()) {
6699                         ntracks++;
6700                 } else {
6701                         nbusses++;
6702                 }
6703                 routes.push_back (rtv->_route);
6704
6705                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6706                         special_bus = true;
6707                 }
6708         }
6709
6710         if (special_bus && !Config->get_allow_special_bus_removal()) {
6711                 MessageDialog msg (_("That would be bad news ...."),
6712                                    false,
6713                                    Gtk::MESSAGE_INFO,
6714                                    Gtk::BUTTONS_OK);
6715                 msg.set_secondary_text (string_compose (_(
6716                                                                 "Removing the master or monitor bus is such a bad idea\n\
6717 that %1 is not going to allow it.\n\
6718 \n\
6719 If you really want to do this sort of thing\n\
6720 edit your ardour.rc file to set the\n\
6721 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6722
6723                 msg.present ();
6724                 msg.run ();
6725                 return;
6726         }
6727
6728         if (ntracks + nbusses == 0) {
6729                 return;
6730         }
6731
6732         // XXX should be using gettext plural forms, maybe?
6733         if (ntracks > 1) {
6734                 trackstr = _("tracks");
6735         } else {
6736                 trackstr = _("track");
6737         }
6738
6739         if (nbusses > 1) {
6740                 busstr = _("busses");
6741         } else {
6742                 busstr = _("bus");
6743         }
6744
6745         if (ntracks) {
6746                 if (nbusses) {
6747                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\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, nbusses, busstr);
6751                 } else {
6752                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6753                                                     "(You may also lose the playlists associated with the %2)\n\n"
6754                                                     "This action cannot be undone, and the session file will be overwritten!"),
6755                                                   ntracks, trackstr);
6756                 }
6757         } else if (nbusses) {
6758                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6759                                             "This action cannot be undone, and the session file will be overwritten"),
6760                                           nbusses, busstr);
6761         }
6762
6763         choices.push_back (_("No, do nothing."));
6764         if (ntracks + nbusses > 1) {
6765                 choices.push_back (_("Yes, remove them."));
6766         } else {
6767                 choices.push_back (_("Yes, remove it."));
6768         }
6769
6770         string title;
6771         if (ntracks) {
6772                 title = string_compose (_("Remove %1"), trackstr);
6773         } else {
6774                 title = string_compose (_("Remove %1"), busstr);
6775         }
6776
6777         Choice prompter (title, prompt, choices);
6778
6779         if (prompter.run () != 1) {
6780                 return;
6781         }
6782
6783         {
6784                 Session::StateProtector sp (_session);
6785                 DisplaySuspender ds;
6786                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6787                         _session->remove_route (*x);
6788                 }
6789         }
6790 }
6791
6792 void
6793 Editor::do_insert_time ()
6794 {
6795         if (selection->tracks.empty()) {
6796                 return;
6797         }
6798
6799         InsertTimeDialog d (*this);
6800         int response = d.run ();
6801
6802         if (response != RESPONSE_OK) {
6803                 return;
6804         }
6805
6806         if (d.distance() == 0) {
6807                 return;
6808         }
6809
6810         InsertTimeOption opt = d.intersected_region_action ();
6811
6812         insert_time (
6813                 get_preferred_edit_position(),
6814                 d.distance(),
6815                 opt,
6816                 d.all_playlists(),
6817                 d.move_glued(),
6818                 d.move_markers(),
6819                 d.move_glued_markers(),
6820                 d.move_locked_markers(),
6821                 d.move_tempos()
6822                 );
6823 }
6824
6825 void
6826 Editor::insert_time (
6827         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6828         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6829         )
6830 {
6831         bool commit = false;
6832
6833         if (Config->get_edit_mode() == Lock) {
6834                 return;
6835         }
6836
6837         begin_reversible_command (_("insert time"));
6838
6839         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6840
6841         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6842
6843                 /* regions */
6844
6845                 /* don't operate on any playlist more than once, which could
6846                  * happen if "all playlists" is enabled, but there is more
6847                  * than 1 track using playlists "from" a given track.
6848                  */
6849
6850                 set<boost::shared_ptr<Playlist> > pl;
6851
6852                 if (all_playlists) {
6853                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6854                         if (rtav) {
6855                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6856                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6857                                         pl.insert (*p);
6858                                 }
6859                         }
6860                 } else {
6861                         if ((*x)->playlist ()) {
6862                                 pl.insert ((*x)->playlist ());
6863                         }
6864                 }
6865                 
6866                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6867
6868                         (*i)->clear_changes ();
6869                         (*i)->clear_owned_changes ();
6870
6871                         if (opt == SplitIntersected) {
6872                                 (*i)->split (pos);
6873                         }
6874
6875                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6876
6877                         vector<Command*> cmds;
6878                         (*i)->rdiff (cmds);
6879                         _session->add_commands (cmds);
6880
6881                         _session->add_command (new StatefulDiffCommand (*i));
6882                         commit = true;
6883                 }
6884
6885                 /* automation */
6886                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6887                 if (rtav) {
6888                         rtav->route ()->shift (pos, frames);
6889                         commit = true;
6890                 }
6891         }
6892
6893         /* markers */
6894         if (markers_too) {
6895                 bool moved = false;
6896                 XMLNode& before (_session->locations()->get_state());
6897                 Locations::LocationList copy (_session->locations()->list());
6898
6899                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6900
6901                         Locations::LocationList::const_iterator tmp;
6902
6903                         bool const was_locked = (*i)->locked ();
6904                         if (locked_markers_too) {
6905                                 (*i)->unlock ();
6906                         }
6907
6908                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6909
6910                                 if ((*i)->start() >= pos) {
6911                                         (*i)->set_start ((*i)->start() + frames);
6912                                         if (!(*i)->is_mark()) {
6913                                                 (*i)->set_end ((*i)->end() + frames);
6914                                         }
6915                                         moved = true;
6916                                 }
6917
6918                         }
6919
6920                         if (was_locked) {
6921                                 (*i)->lock ();
6922                         }
6923                 }
6924
6925                 if (moved) {
6926                         XMLNode& after (_session->locations()->get_state());
6927                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6928                 }
6929         }
6930
6931         if (tempo_too) {
6932                 _session->tempo_map().insert_time (pos, frames);
6933         }
6934
6935         if (commit) {
6936                 commit_reversible_command ();
6937         }
6938 }
6939
6940 void
6941 Editor::fit_selected_tracks ()
6942 {
6943         if (!selection->tracks.empty()) {
6944                 fit_tracks (selection->tracks);
6945         } else {
6946                 TrackViewList tvl;
6947
6948                 /* no selected tracks - use tracks with selected regions */
6949
6950                 if (!selection->regions.empty()) {
6951                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6952                                 tvl.push_back (&(*r)->get_time_axis_view ());
6953                         }
6954
6955                         if (!tvl.empty()) {
6956                                 fit_tracks (tvl);
6957                         }
6958                 } else if (internal_editing()) {
6959                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6960                            the entered track
6961                         */
6962                         if (entered_track) {
6963                                 tvl.push_back (entered_track);
6964                                 fit_tracks (tvl);
6965                         }
6966                 }
6967         }
6968
6969 }
6970
6971 void
6972 Editor::fit_tracks (TrackViewList & tracks)
6973 {
6974         if (tracks.empty()) {
6975                 return;
6976         }
6977
6978         uint32_t child_heights = 0;
6979         int visible_tracks = 0;
6980
6981         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6982
6983                 if (!(*t)->marked_for_display()) {
6984                         continue;
6985                 }
6986
6987                 child_heights += (*t)->effective_height() - (*t)->current_height();
6988                 ++visible_tracks;
6989         }
6990
6991         /* compute the per-track height from:
6992
6993            total canvas visible height - 
6994                  height that will be taken by visible children of selected
6995                  tracks - height of the ruler/hscroll area 
6996         */
6997         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6998         double first_y_pos = DBL_MAX;
6999
7000         if (h < TimeAxisView::preset_height (HeightSmall)) {
7001                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7002                 /* too small to be displayed */
7003                 return;
7004         }
7005
7006         undo_visual_stack.push_back (current_visual_state (true));
7007         no_save_visual = true;
7008
7009         /* build a list of all tracks, including children */
7010
7011         TrackViewList all;
7012         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7013                 all.push_back (*i);
7014                 TimeAxisView::Children c = (*i)->get_child_list ();
7015                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7016                         all.push_back (j->get());
7017                 }
7018         }
7019
7020         bool prev_was_selected = false;
7021         bool is_selected = tracks.contains (all.front());
7022         bool next_is_selected;
7023
7024         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
7025
7026                 TrackViewList::iterator next;
7027
7028                 next = t;
7029                 ++next;
7030
7031                 if (next != all.end()) {
7032                         next_is_selected = tracks.contains (*next);
7033                 } else {
7034                         next_is_selected = false;
7035                 }
7036
7037                 if ((*t)->marked_for_display ()) {
7038                         if (is_selected) {
7039                                 (*t)->set_height (h);
7040                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7041                         } else {
7042                                 if (prev_was_selected && next_is_selected) {
7043                                         hide_track_in_display (*t);
7044                                 }
7045                         }
7046                 }
7047
7048                 prev_was_selected = is_selected;
7049                 is_selected = next_is_selected;
7050         }
7051
7052         /*
7053            set the controls_layout height now, because waiting for its size
7054            request signal handler will cause the vertical adjustment setting to fail
7055         */
7056
7057         controls_layout.property_height () = _full_canvas_height;
7058         vertical_adjustment.set_value (first_y_pos);
7059
7060         redo_visual_stack.push_back (current_visual_state (true));
7061
7062         visible_tracks_selector.set_text (_("Sel"));
7063 }
7064
7065 void
7066 Editor::save_visual_state (uint32_t n)
7067 {
7068         while (visual_states.size() <= n) {
7069                 visual_states.push_back (0);
7070         }
7071
7072         if (visual_states[n] != 0) {
7073                 delete visual_states[n];
7074         }
7075
7076         visual_states[n] = current_visual_state (true);
7077         gdk_beep ();
7078 }
7079
7080 void
7081 Editor::goto_visual_state (uint32_t n)
7082 {
7083         if (visual_states.size() <= n) {
7084                 return;
7085         }
7086
7087         if (visual_states[n] == 0) {
7088                 return;
7089         }
7090
7091         use_visual_state (*visual_states[n]);
7092 }
7093
7094 void
7095 Editor::start_visual_state_op (uint32_t n)
7096 {
7097         save_visual_state (n);
7098         
7099         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7100         char buf[32];
7101         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7102         pup->set_text (buf);
7103         pup->touch();
7104 }
7105
7106 void
7107 Editor::cancel_visual_state_op (uint32_t n)
7108 {
7109         goto_visual_state (n);
7110 }
7111
7112 void
7113 Editor::toggle_region_mute ()
7114 {
7115         if (_ignore_region_action) {
7116                 return;
7117         }
7118
7119         RegionSelection rs = get_regions_from_selection_and_entered ();
7120
7121         if (rs.empty ()) {
7122                 return;
7123         }
7124
7125         if (rs.size() > 1) {
7126                 begin_reversible_command (_("mute regions"));
7127         } else {
7128                 begin_reversible_command (_("mute region"));
7129         }
7130
7131         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7132
7133                 (*i)->region()->playlist()->clear_changes ();
7134                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7135                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7136
7137         }
7138
7139         commit_reversible_command ();
7140 }
7141
7142 void
7143 Editor::combine_regions ()
7144 {
7145         /* foreach track with selected regions, take all selected regions
7146            and join them into a new region containing the subregions (as a
7147            playlist)
7148         */
7149
7150         typedef set<RouteTimeAxisView*> RTVS;
7151         RTVS tracks;
7152
7153         if (selection->regions.empty()) {
7154                 return;
7155         }
7156
7157         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7158                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7159
7160                 if (rtv) {
7161                         tracks.insert (rtv);
7162                 }
7163         }
7164
7165         begin_reversible_command (_("combine regions"));
7166
7167         vector<RegionView*> new_selection;
7168
7169         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7170                 RegionView* rv;
7171
7172                 if ((rv = (*i)->combine_regions ()) != 0) {
7173                         new_selection.push_back (rv);
7174                 }
7175         }
7176
7177         selection->clear_regions ();
7178         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7179                 selection->add (*i);
7180         }
7181
7182         commit_reversible_command ();
7183 }
7184
7185 void
7186 Editor::uncombine_regions ()
7187 {
7188         typedef set<RouteTimeAxisView*> RTVS;
7189         RTVS tracks;
7190
7191         if (selection->regions.empty()) {
7192                 return;
7193         }
7194
7195         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7196                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7197
7198                 if (rtv) {
7199                         tracks.insert (rtv);
7200                 }
7201         }
7202
7203         begin_reversible_command (_("uncombine regions"));
7204
7205         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7206                 (*i)->uncombine_regions ();
7207         }
7208
7209         commit_reversible_command ();
7210 }
7211
7212 void
7213 Editor::toggle_midi_input_active (bool flip_others)
7214 {
7215         bool onoff = false;
7216         boost::shared_ptr<RouteList> rl (new RouteList);
7217
7218         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7219                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7220
7221                 if (!rtav) {
7222                         continue;
7223                 }
7224
7225                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7226
7227                 if (mt) {
7228                         rl->push_back (rtav->route());
7229                         onoff = !mt->input_active();
7230                 }
7231         }
7232         
7233         _session->set_exclusive_input_active (rl, onoff, flip_others);
7234 }
7235
7236 void
7237 Editor::lock ()
7238 {
7239         if (!lock_dialog) {
7240                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7241
7242                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7243                 lock_dialog->get_vbox()->pack_start (*padlock);
7244
7245                 ArdourButton* b = manage (new ArdourButton);
7246                 b->set_name ("lock button");
7247                 b->set_text (_("Click to unlock"));
7248                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7249                 lock_dialog->get_vbox()->pack_start (*b);
7250                 
7251                 lock_dialog->get_vbox()->show_all ();
7252                 lock_dialog->set_size_request (200, 200);
7253         }
7254         
7255 #ifdef __APPLE__
7256         /* The global menu bar continues to be accessible to applications
7257            with modal dialogs, which means that we need to desensitize
7258            all items in the menu bar. Since those items are really just
7259            proxies for actions, that means disabling all actions.
7260         */
7261         ActionManager::disable_all_actions ();
7262 #endif
7263         lock_dialog->present ();
7264 }
7265
7266 void
7267 Editor::unlock ()
7268 {
7269         lock_dialog->hide ();
7270         
7271 #ifdef __APPLE__
7272         ActionManager::pop_action_state ();
7273 #endif  
7274
7275         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7276                 start_lock_event_timing ();
7277         }
7278 }
7279
7280 void
7281 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7282 {
7283         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7284 }
7285
7286 void
7287 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7288 {
7289         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7290         Gtkmm2ext::UI::instance()->flush_pending ();
7291 }
7292
7293 void
7294 Editor::bring_all_sources_into_session ()
7295 {
7296         if (!_session) {
7297                 return;
7298         }
7299
7300         Gtk::Label msg;
7301         ArdourDialog w (_("Moving embedded files into session folder"));
7302         w.get_vbox()->pack_start (msg);
7303         w.present ();
7304         
7305         /* flush all pending GUI events because we're about to start copying
7306          * files
7307          */
7308         
7309         Gtkmm2ext::UI::instance()->flush_pending ();
7310
7311         cerr << " Do it\n";
7312
7313         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7314 }