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