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