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