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