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