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