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