c7a46d0ad3d9493d207822fea8f31af80501719f
[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 void
2771 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2772 {
2773         if (_session->is_auditioning()) {
2774                 _session->cancel_audition ();
2775         }
2776
2777         // note: some potential for creativity here, because region doesn't
2778         // have to belong to the playlist that Route is handling
2779
2780         // bool was_soloed = route.soloed();
2781
2782         route.set_solo (true, this);
2783
2784         _session->request_bounded_roll (region->position(), region->position() + region->length());
2785
2786         /* XXX how to unset the solo state ? */
2787 }
2788
2789 /** Start an audition of the first selected region */
2790 void
2791 Editor::play_edit_range ()
2792 {
2793         framepos_t start, end;
2794
2795         if (get_edit_op_range (start, end)) {
2796                 _session->request_bounded_roll (start, end);
2797         }
2798 }
2799
2800 void
2801 Editor::play_selected_region ()
2802 {
2803         framepos_t start = max_framepos;
2804         framepos_t end = 0;
2805
2806         RegionSelection rs = get_regions_from_selection_and_entered ();
2807
2808         if (rs.empty()) {
2809                 return;
2810         }
2811
2812         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2813                 if ((*i)->region()->position() < start) {
2814                         start = (*i)->region()->position();
2815                 }
2816                 if ((*i)->region()->last_frame() + 1 > end) {
2817                         end = (*i)->region()->last_frame() + 1;
2818                 }
2819         }
2820
2821         _session->request_bounded_roll (start, end);
2822 }
2823
2824 void
2825 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2826 {
2827         _session->audition_region (region);
2828 }
2829
2830 void
2831 Editor::region_from_selection ()
2832 {
2833         if (clicked_axisview == 0) {
2834                 return;
2835         }
2836
2837         if (selection->time.empty()) {
2838                 return;
2839         }
2840
2841         framepos_t start = selection->time[clicked_selection].start;
2842         framepos_t end = selection->time[clicked_selection].end;
2843
2844         TrackViewList tracks = get_tracks_for_range_action ();
2845
2846         framepos_t selection_cnt = end - start + 1;
2847
2848         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2849                 boost::shared_ptr<Region> current;
2850                 boost::shared_ptr<Playlist> pl;
2851                 framepos_t internal_start;
2852                 string new_name;
2853
2854                 if ((pl = (*i)->playlist()) == 0) {
2855                         continue;
2856                 }
2857
2858                 if ((current = pl->top_region_at (start)) == 0) {
2859                         continue;
2860                 }
2861
2862                 internal_start = start - current->position();
2863                 RegionFactory::region_name (new_name, current->name(), true);
2864
2865                 PropertyList plist;
2866
2867                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2868                 plist.add (ARDOUR::Properties::length, selection_cnt);
2869                 plist.add (ARDOUR::Properties::name, new_name);
2870                 plist.add (ARDOUR::Properties::layer, 0);
2871
2872                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2873         }
2874 }
2875
2876 void
2877 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2878 {
2879         if (selection->time.empty() || selection->tracks.empty()) {
2880                 return;
2881         }
2882
2883         framepos_t start, end;
2884         if (clicked_selection) {
2885                 start = selection->time[clicked_selection].start;
2886                 end = selection->time[clicked_selection].end;
2887         } else {
2888                 start = selection->time.start();
2889                 end = selection->time.end_frame();
2890         }
2891
2892         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2893         sort_track_selection (ts);
2894
2895         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2896                 boost::shared_ptr<Region> current;
2897                 boost::shared_ptr<Playlist> playlist;
2898                 framepos_t internal_start;
2899                 string new_name;
2900
2901                 if ((playlist = (*i)->playlist()) == 0) {
2902                         continue;
2903                 }
2904
2905                 if ((current = playlist->top_region_at(start)) == 0) {
2906                         continue;
2907                 }
2908
2909                 internal_start = start - current->position();
2910                 RegionFactory::region_name (new_name, current->name(), true);
2911
2912                 PropertyList plist;
2913
2914                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2915                 plist.add (ARDOUR::Properties::length, end - start + 1);
2916                 plist.add (ARDOUR::Properties::name, new_name);
2917
2918                 new_regions.push_back (RegionFactory::create (current, plist));
2919         }
2920 }
2921
2922 void
2923 Editor::split_multichannel_region ()
2924 {
2925         RegionSelection rs = get_regions_from_selection_and_entered ();
2926
2927         if (rs.empty()) {
2928                 return;
2929         }
2930
2931         vector< boost::shared_ptr<Region> > v;
2932
2933         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2934                 (*x)->region()->separate_by_channel (*_session, v);
2935         }
2936 }
2937
2938 void
2939 Editor::new_region_from_selection ()
2940 {
2941         region_from_selection ();
2942         cancel_selection ();
2943 }
2944
2945 static void
2946 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2947 {
2948         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2949         // n.b. -1 because AudioRange::end is one past the end, but coverage expects inclusive ranges
2950         case Evoral::OverlapNone:
2951                 break;
2952         default:
2953                 rs->push_back (rv);
2954         }
2955 }
2956
2957 /** Return either:
2958  *    - selected tracks, or if there are none...
2959  *    - tracks containing selected regions, or if there are none...
2960  *    - all tracks
2961  * @return tracks.
2962  */
2963 TrackViewList
2964 Editor::get_tracks_for_range_action () const
2965 {
2966         TrackViewList t;
2967
2968         if (selection->tracks.empty()) {
2969
2970                 /* use tracks with selected regions */
2971
2972                 RegionSelection rs = selection->regions;
2973
2974                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2975                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2976
2977                         if (!t.contains (tv)) {
2978                                 t.push_back (tv);
2979                         }
2980                 }
2981
2982                 if (t.empty()) {
2983                         /* no regions and no tracks: use all tracks */
2984                         t = track_views;
2985                 }
2986
2987         } else {
2988
2989                 t = selection->tracks;
2990         }
2991
2992         return t.filter_to_unique_playlists();
2993 }
2994
2995 void
2996 Editor::separate_regions_between (const TimeSelection& ts)
2997 {
2998         bool in_command = false;
2999         boost::shared_ptr<Playlist> playlist;
3000         RegionSelection new_selection;
3001
3002         TrackViewList tmptracks = get_tracks_for_range_action ();
3003         sort_track_selection (tmptracks);
3004
3005         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
3006
3007                 RouteTimeAxisView* rtv;
3008
3009                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3010
3011                         if (rtv->is_track()) {
3012
3013                                 /* no edits to destructive tracks */
3014
3015                                 if (rtv->track()->destructive()) {
3016                                         continue;
3017                                 }
3018
3019                                 if ((playlist = rtv->playlist()) != 0) {
3020
3021                                         playlist->clear_changes ();
3022
3023                                         /* XXX need to consider musical time selections here at some point */
3024
3025                                         double speed = rtv->track()->speed();
3026
3027
3028                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
3029
3030                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
3031                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
3032
3033                                                 latest_regionviews.clear ();
3034
3035                                                 playlist->partition ((framepos_t)((*t).start * speed),
3036                                                                 (framepos_t)((*t).end * speed), false);
3037
3038                                                 c.disconnect ();
3039
3040                                                 if (!latest_regionviews.empty()) {
3041
3042                                                         rtv->view()->foreach_regionview (sigc::bind (
3043                                                                                 sigc::ptr_fun (add_if_covered),
3044                                                                                 &(*t), &new_selection));
3045
3046                                                         if (!in_command) {
3047                                                                 begin_reversible_command (_("separate"));
3048                                                                 in_command = true;
3049                                                         }
3050
3051                                                         /* pick up changes to existing regions */
3052
3053                                                         vector<Command*> cmds;
3054                                                         playlist->rdiff (cmds);
3055                                                         _session->add_commands (cmds);
3056
3057                                                         /* pick up changes to the playlist itself (adds/removes)
3058                                                          */
3059
3060                                                         _session->add_command(new StatefulDiffCommand (playlist));
3061                                                 }
3062                                         }
3063                                 }
3064                         }
3065                 }
3066         }
3067
3068         if (in_command) {
3069 //              selection->set (new_selection);
3070
3071                 commit_reversible_command ();
3072         }
3073 }
3074
3075 struct PlaylistState {
3076     boost::shared_ptr<Playlist> playlist;
3077     XMLNode*  before;
3078 };
3079
3080 /** Take tracks from get_tracks_for_range_action and cut any regions
3081  *  on those tracks so that the tracks are empty over the time
3082  *  selection.
3083  */
3084 void
3085 Editor::separate_region_from_selection ()
3086 {
3087         /* preferentially use *all* ranges in the time selection if we're in range mode
3088            to allow discontiguous operation, since get_edit_op_range() currently
3089            returns a single range.
3090         */
3091
3092         if (!selection->time.empty()) {
3093
3094                 separate_regions_between (selection->time);
3095
3096         } else {
3097
3098                 framepos_t start;
3099                 framepos_t end;
3100
3101                 if (get_edit_op_range (start, end)) {
3102
3103                         AudioRange ar (start, end, 1);
3104                         TimeSelection ts;
3105                         ts.push_back (ar);
3106
3107                         separate_regions_between (ts);
3108                 }
3109         }
3110 }
3111
3112 void
3113 Editor::separate_region_from_punch ()
3114 {
3115         Location* loc  = _session->locations()->auto_punch_location();
3116         if (loc) {
3117                 separate_regions_using_location (*loc);
3118         }
3119 }
3120
3121 void
3122 Editor::separate_region_from_loop ()
3123 {
3124         Location* loc  = _session->locations()->auto_loop_location();
3125         if (loc) {
3126                 separate_regions_using_location (*loc);
3127         }
3128 }
3129
3130 void
3131 Editor::separate_regions_using_location (Location& loc)
3132 {
3133         if (loc.is_mark()) {
3134                 return;
3135         }
3136
3137         AudioRange ar (loc.start(), loc.end(), 1);
3138         TimeSelection ts;
3139
3140         ts.push_back (ar);
3141
3142         separate_regions_between (ts);
3143 }
3144
3145 /** Separate regions under the selected region */
3146 void
3147 Editor::separate_under_selected_regions ()
3148 {
3149         vector<PlaylistState> playlists;
3150
3151         RegionSelection rs;
3152
3153         rs = get_regions_from_selection_and_entered();
3154
3155         if (!_session || rs.empty()) {
3156                 return;
3157         }
3158
3159         begin_reversible_command (_("separate region under"));
3160
3161         list<boost::shared_ptr<Region> > regions_to_remove;
3162
3163         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3164                 // we can't just remove the region(s) in this loop because
3165                 // this removes them from the RegionSelection, and they thus
3166                 // disappear from underneath the iterator, and the ++i above
3167                 // SEGVs in a puzzling fashion.
3168
3169                 // so, first iterate over the regions to be removed from rs and
3170                 // add them to the regions_to_remove list, and then
3171                 // iterate over the list to actually remove them.
3172
3173                 regions_to_remove.push_back ((*i)->region());
3174         }
3175
3176         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
3177
3178                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
3179
3180                 if (!playlist) {
3181                         // is this check necessary?
3182                         continue;
3183                 }
3184
3185                 vector<PlaylistState>::iterator i;
3186
3187                 //only take state if this is a new playlist.
3188                 for (i = playlists.begin(); i != playlists.end(); ++i) {
3189                         if ((*i).playlist == playlist) {
3190                                 break;
3191                         }
3192                 }
3193
3194                 if (i == playlists.end()) {
3195
3196                         PlaylistState before;
3197                         before.playlist = playlist;
3198                         before.before = &playlist->get_state();
3199
3200                         playlist->freeze ();
3201                         playlists.push_back(before);
3202                 }
3203
3204                 //Partition on the region bounds
3205                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
3206
3207                 //Re-add region that was just removed due to the partition operation
3208                 playlist->add_region( (*rl), (*rl)->first_frame() );
3209         }
3210
3211         vector<PlaylistState>::iterator pl;
3212
3213         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
3214                 (*pl).playlist->thaw ();
3215                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3216         }
3217
3218         commit_reversible_command ();
3219 }
3220
3221 void
3222 Editor::crop_region_to_selection ()
3223 {
3224         if (!selection->time.empty()) {
3225
3226                 crop_region_to (selection->time.start(), selection->time.end_frame());
3227
3228         } else {
3229
3230                 framepos_t start;
3231                 framepos_t end;
3232
3233                 if (get_edit_op_range (start, end)) {
3234                         crop_region_to (start, end);
3235                 }
3236         }
3237
3238 }
3239
3240 void
3241 Editor::crop_region_to (framepos_t start, framepos_t end)
3242 {
3243         vector<boost::shared_ptr<Playlist> > playlists;
3244         boost::shared_ptr<Playlist> playlist;
3245         TrackViewList ts;
3246
3247         if (selection->tracks.empty()) {
3248                 ts = track_views.filter_to_unique_playlists();
3249         } else {
3250                 ts = selection->tracks.filter_to_unique_playlists ();
3251         }
3252
3253         sort_track_selection (ts);
3254
3255         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3256
3257                 RouteTimeAxisView* rtv;
3258
3259                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3260
3261                         boost::shared_ptr<Track> t = rtv->track();
3262
3263                         if (t != 0 && ! t->destructive()) {
3264
3265                                 if ((playlist = rtv->playlist()) != 0) {
3266                                         playlists.push_back (playlist);
3267                                 }
3268                         }
3269                 }
3270         }
3271
3272         if (playlists.empty()) {
3273                 return;
3274         }
3275
3276         framepos_t the_start;
3277         framepos_t the_end;
3278         framepos_t cnt;
3279         bool in_command = false;
3280
3281         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3282
3283                 boost::shared_ptr<Region> region;
3284
3285                 the_start = start;
3286
3287                 if ((region = (*i)->top_region_at(the_start)) == 0) {
3288                         continue;
3289                 }
3290
3291                 /* now adjust lengths to that we do the right thing
3292                    if the selection extends beyond the region
3293                 */
3294
3295                 the_start = max (the_start, (framepos_t) region->position());
3296                 if (max_framepos - the_start < region->length()) {
3297                         the_end = the_start + region->length() - 1;
3298                 } else {
3299                         the_end = max_framepos;
3300                 }
3301                 the_end = min (end, the_end);
3302                 cnt = the_end - the_start + 1;
3303
3304                 if(!in_command) {
3305                         begin_reversible_command (_("trim to selection"));
3306                         in_command = true;
3307                 }
3308                 region->clear_changes ();
3309                 region->trim_to (the_start, cnt);
3310                 _session->add_command (new StatefulDiffCommand (region));
3311         }
3312
3313         if (in_command) {
3314                 commit_reversible_command ();
3315         }
3316 }
3317
3318 void
3319 Editor::region_fill_track ()
3320 {
3321         RegionSelection rs = get_regions_from_selection_and_entered ();
3322
3323         if (!_session || rs.empty()) {
3324                 return;
3325         }
3326
3327         framepos_t const end = _session->current_end_frame ();
3328         RegionSelection foo;
3329         bool in_command = false;
3330
3331         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3332
3333                 boost::shared_ptr<Region> region ((*i)->region());
3334
3335                 boost::shared_ptr<Playlist> pl = region->playlist();
3336
3337                 if (end <= region->last_frame()) {
3338                         continue;
3339                 }
3340
3341                 double times = (double) (end - region->last_frame()) / (double) region->length();
3342
3343                 if (times == 0) {
3344                         continue;
3345                 }
3346
3347                 if (!in_command) {
3348                         begin_reversible_command (Operations::region_fill);
3349                         in_command = true;
3350                 }
3351                 TimeAxisView& tv = (*i)->get_time_axis_view();
3352                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
3353                 latest_regionviews.clear ();
3354                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3355
3356                 pl->clear_changes ();
3357                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3358                 _session->add_command (new StatefulDiffCommand (pl));
3359
3360                 c.disconnect ();
3361
3362                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3363         }
3364
3365         if (in_command) {
3366                 if (!foo.empty()) {
3367                         selection->set (foo);
3368                 }
3369                 commit_reversible_command ();
3370         }
3371 }
3372
3373 void
3374 Editor::region_fill_selection ()
3375 {
3376         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3377                 return;
3378         }
3379
3380         if (selection->time.empty()) {
3381                 return;
3382         }
3383
3384         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3385         if (region == 0) {
3386                 return;
3387         }
3388
3389         framepos_t start = selection->time[clicked_selection].start;
3390         framepos_t end = selection->time[clicked_selection].end;
3391
3392         boost::shared_ptr<Playlist> playlist;
3393
3394         if (selection->tracks.empty()) {
3395                 return;
3396         }
3397
3398         framepos_t selection_length = end - start;
3399         float times = (float)selection_length / region->length();
3400         bool in_command = false;
3401
3402         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3403         RegionSelection foo;
3404
3405         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3406
3407                 if ((playlist = (*i)->playlist()) == 0) {
3408                         continue;
3409                 }
3410
3411                 if (!in_command) {
3412                         begin_reversible_command (Operations::fill_selection);
3413                         in_command = true;
3414                 }
3415                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3416                 latest_regionviews.clear ();
3417                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
3418
3419                 playlist->clear_changes ();
3420                 playlist->add_region (RegionFactory::create (region, true), start, times);
3421                 _session->add_command (new StatefulDiffCommand (playlist));
3422                 c.disconnect ();
3423                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3424         }
3425
3426         if (in_command) {
3427                 if (!foo.empty()) {
3428                         selection->set (foo);
3429                 }
3430                 commit_reversible_command ();
3431         }
3432 }
3433
3434 void
3435 Editor::set_region_sync_position ()
3436 {
3437         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3438 }
3439
3440 void
3441 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3442 {
3443         bool in_command = false;
3444
3445         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3446
3447                 if (!(*r)->region()->covers (where)) {
3448                         continue;
3449                 }
3450
3451                 boost::shared_ptr<Region> region ((*r)->region());
3452
3453                 if (!in_command) {
3454                         begin_reversible_command (_("set sync point"));
3455                         in_command = true;
3456                 }
3457
3458                 region->clear_changes ();
3459                 region->set_sync_position (where);
3460                 _session->add_command(new StatefulDiffCommand (region));
3461         }
3462
3463         if (in_command) {
3464                 commit_reversible_command ();
3465         }
3466 }
3467
3468 /** Remove the sync positions of the selection */
3469 void
3470 Editor::remove_region_sync ()
3471 {
3472         RegionSelection rs = get_regions_from_selection_and_entered ();
3473
3474         if (rs.empty()) {
3475                 return;
3476         }
3477
3478         begin_reversible_command (_("remove region sync"));
3479
3480         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3481
3482                 (*i)->region()->clear_changes ();
3483                 (*i)->region()->clear_sync_position ();
3484                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3485         }
3486
3487         commit_reversible_command ();
3488 }
3489
3490 void
3491 Editor::naturalize_region ()
3492 {
3493         RegionSelection rs = get_regions_from_selection_and_entered ();
3494
3495         if (rs.empty()) {
3496                 return;
3497         }
3498
3499         if (rs.size() > 1) {
3500                 begin_reversible_command (_("move regions to original position"));
3501         } else {
3502                 begin_reversible_command (_("move region to original position"));
3503         }
3504
3505         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3506                 (*i)->region()->clear_changes ();
3507                 (*i)->region()->move_to_natural_position ();
3508                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3509         }
3510
3511         commit_reversible_command ();
3512 }
3513
3514 void
3515 Editor::align_regions (RegionPoint what)
3516 {
3517         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3518
3519         if (rs.empty()) {
3520                 return;
3521         }
3522
3523         begin_reversible_command (_("align selection"));
3524
3525         framepos_t const position = get_preferred_edit_position ();
3526
3527         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3528                 align_region_internal ((*i)->region(), what, position);
3529         }
3530
3531         commit_reversible_command ();
3532 }
3533
3534 struct RegionSortByTime {
3535     bool operator() (const RegionView* a, const RegionView* b) {
3536             return a->region()->position() < b->region()->position();
3537     }
3538 };
3539
3540 void
3541 Editor::align_regions_relative (RegionPoint point)
3542 {
3543         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3544
3545         if (rs.empty()) {
3546                 return;
3547         }
3548
3549         framepos_t const position = get_preferred_edit_position ();
3550
3551         framepos_t distance = 0;
3552         framepos_t pos = 0;
3553         int dir = 1;
3554
3555         list<RegionView*> sorted;
3556         rs.by_position (sorted);
3557
3558         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3559
3560         switch (point) {
3561         case Start:
3562                 pos = position;
3563                 if (position > r->position()) {
3564                         distance = position - r->position();
3565                 } else {
3566                         distance = r->position() - position;
3567                         dir = -1;
3568                 }
3569                 break;
3570
3571         case End:
3572                 if (position > r->last_frame()) {
3573                         distance = position - r->last_frame();
3574                         pos = r->position() + distance;
3575                 } else {
3576                         distance = r->last_frame() - position;
3577                         pos = r->position() - distance;
3578                         dir = -1;
3579                 }
3580                 break;
3581
3582         case SyncPoint:
3583                 pos = r->adjust_to_sync (position);
3584                 if (pos > r->position()) {
3585                         distance = pos - r->position();
3586                 } else {
3587                         distance = r->position() - pos;
3588                         dir = -1;
3589                 }
3590                 break;
3591         }
3592
3593         if (pos == r->position()) {
3594                 return;
3595         }
3596
3597         begin_reversible_command (_("align selection (relative)"));
3598
3599         /* move first one specially */
3600
3601         r->clear_changes ();
3602         r->set_position (pos);
3603         _session->add_command(new StatefulDiffCommand (r));
3604
3605         /* move rest by the same amount */
3606
3607         sorted.pop_front();
3608
3609         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3610
3611                 boost::shared_ptr<Region> region ((*i)->region());
3612
3613                 region->clear_changes ();
3614
3615                 if (dir > 0) {
3616                         region->set_position (region->position() + distance);
3617                 } else {
3618                         region->set_position (region->position() - distance);
3619                 }
3620
3621                 _session->add_command(new StatefulDiffCommand (region));
3622
3623         }
3624
3625         commit_reversible_command ();
3626 }
3627
3628 void
3629 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3630 {
3631         begin_reversible_command (_("align region"));
3632         align_region_internal (region, point, position);
3633         commit_reversible_command ();
3634 }
3635
3636 void
3637 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3638 {
3639         region->clear_changes ();
3640
3641         switch (point) {
3642         case SyncPoint:
3643                 region->set_position (region->adjust_to_sync (position));
3644                 break;
3645
3646         case End:
3647                 if (position > region->length()) {
3648                         region->set_position (position - region->length());
3649                 }
3650                 break;
3651
3652         case Start:
3653                 region->set_position (position);
3654                 break;
3655         }
3656
3657         _session->add_command(new StatefulDiffCommand (region));
3658 }
3659
3660 void
3661 Editor::trim_region_front ()
3662 {
3663         trim_region (true);
3664 }
3665
3666 void
3667 Editor::trim_region_back ()
3668 {
3669         trim_region (false);
3670 }
3671
3672 void
3673 Editor::trim_region (bool front)
3674 {
3675         framepos_t where = get_preferred_edit_position();
3676         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3677
3678         if (rs.empty()) {
3679                 return;
3680         }
3681
3682         begin_reversible_command (front ? _("trim front") : _("trim back"));
3683
3684         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3685                 if (!(*i)->region()->locked()) {
3686
3687                         (*i)->region()->clear_changes ();
3688
3689                         if (front) {
3690                                 (*i)->region()->trim_front (where);
3691                                 maybe_locate_with_edit_preroll ( where );
3692                         } else {
3693                                 (*i)->region()->trim_end (where);
3694                                 maybe_locate_with_edit_preroll ( where );
3695                         }
3696
3697                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3698                 }
3699         }
3700
3701         commit_reversible_command ();
3702 }
3703
3704 /** Trim the end of the selected regions to the position of the edit cursor */
3705 void
3706 Editor::trim_region_to_loop ()
3707 {
3708         Location* loc = _session->locations()->auto_loop_location();
3709         if (!loc) {
3710                 return;
3711         }
3712         trim_region_to_location (*loc, _("trim to loop"));
3713 }
3714
3715 void
3716 Editor::trim_region_to_punch ()
3717 {
3718         Location* loc = _session->locations()->auto_punch_location();
3719         if (!loc) {
3720                 return;
3721         }
3722         trim_region_to_location (*loc, _("trim to punch"));
3723 }
3724
3725 void
3726 Editor::trim_region_to_location (const Location& loc, const char* str)
3727 {
3728         RegionSelection rs = get_regions_from_selection_and_entered ();
3729         bool in_command = false;
3730
3731         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3732                 RegionView* rv = (*x);
3733
3734                 /* require region to span proposed trim */
3735                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3736                 case Evoral::OverlapInternal:
3737                         break;
3738                 default:
3739                         continue;
3740                 }
3741
3742                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3743                 if (!tav) {
3744                         return;
3745                 }
3746
3747                 float speed = 1.0;
3748                 framepos_t start;
3749                 framepos_t end;
3750
3751                 if (tav->track() != 0) {
3752                         speed = tav->track()->speed();
3753                 }
3754
3755                 start = session_frame_to_track_frame (loc.start(), speed);
3756                 end = session_frame_to_track_frame (loc.end(), speed);
3757
3758                 rv->region()->clear_changes ();
3759                 rv->region()->trim_to (start, (end - start));
3760
3761                 if (!in_command) {
3762                         begin_reversible_command (str);
3763                         in_command = true;
3764                 }
3765                 _session->add_command(new StatefulDiffCommand (rv->region()));
3766         }
3767
3768         if (in_command) {
3769                 commit_reversible_command ();
3770         }
3771 }
3772
3773 void
3774 Editor::trim_region_to_previous_region_end ()
3775 {
3776         return trim_to_region(false);
3777 }
3778
3779 void
3780 Editor::trim_region_to_next_region_start ()
3781 {
3782         return trim_to_region(true);
3783 }
3784
3785 void
3786 Editor::trim_to_region(bool forward)
3787 {
3788         RegionSelection rs = get_regions_from_selection_and_entered ();
3789         bool in_command = false;
3790
3791         boost::shared_ptr<Region> next_region;
3792
3793         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3794
3795                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3796
3797                 if (!arv) {
3798                         continue;
3799                 }
3800
3801                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3802
3803                 if (!atav) {
3804                         continue;
3805                 }
3806
3807                 float speed = 1.0;
3808
3809                 if (atav->track() != 0) {
3810                         speed = atav->track()->speed();
3811                 }
3812
3813
3814                 boost::shared_ptr<Region> region = arv->region();
3815                 boost::shared_ptr<Playlist> playlist (region->playlist());
3816
3817                 region->clear_changes ();
3818
3819                 if (forward) {
3820
3821                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3822
3823                     if (!next_region) {
3824                         continue;
3825                     }
3826
3827                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3828                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3829                 }
3830                 else {
3831
3832                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3833
3834                     if(!next_region){
3835                         continue;
3836                     }
3837
3838                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3839
3840                     arv->region_changed (ARDOUR::bounds_change);
3841                 }
3842
3843                 if (!in_command) {
3844                         begin_reversible_command (_("trim to region"));
3845                         in_command = true;
3846                 }
3847                 _session->add_command(new StatefulDiffCommand (region));
3848         }
3849
3850         if (in_command) {
3851                 commit_reversible_command ();
3852         }
3853 }
3854
3855 void
3856 Editor::unfreeze_route ()
3857 {
3858         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3859                 return;
3860         }
3861
3862         clicked_routeview->track()->unfreeze ();
3863 }
3864
3865 void*
3866 Editor::_freeze_thread (void* arg)
3867 {
3868         return static_cast<Editor*>(arg)->freeze_thread ();
3869 }
3870
3871 void*
3872 Editor::freeze_thread ()
3873 {
3874         /* create event pool because we may need to talk to the session */
3875         SessionEvent::create_per_thread_pool ("freeze events", 64);
3876         /* create per-thread buffers for process() tree to use */
3877         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3878         current_interthread_info->done = true;
3879         return 0;
3880 }
3881
3882 void
3883 Editor::freeze_route ()
3884 {
3885         if (!_session) {
3886                 return;
3887         }
3888
3889         /* stop transport before we start. this is important */
3890
3891         _session->request_transport_speed (0.0);
3892         
3893         /* wait for just a little while, because the above call is asynchronous */
3894
3895         Glib::usleep (250000);
3896
3897         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3898                 return;
3899         }
3900
3901         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3902                 MessageDialog d (
3903                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3904                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3905                         );
3906                 d.set_title (_("Cannot freeze"));
3907                 d.run ();
3908                 return;
3909         }
3910
3911         if (clicked_routeview->track()->has_external_redirects()) {
3912                 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"
3913                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3914                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3915
3916                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3917                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3918                 d.set_title (_("Freeze Limits"));
3919
3920                 int response = d.run ();
3921
3922                 switch (response) {
3923                 case Gtk::RESPONSE_CANCEL:
3924                         return;
3925                 default:
3926                         break;
3927                 }
3928         }
3929
3930         InterThreadInfo itt;
3931         current_interthread_info = &itt;
3932
3933         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3934
3935         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3936
3937         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
3938
3939         while (!itt.done && !itt.cancel) {
3940                 gtk_main_iteration ();
3941         }
3942
3943         current_interthread_info = 0;
3944 }
3945
3946 void
3947 Editor::bounce_range_selection (bool replace, bool enable_processing)
3948 {
3949         if (selection->time.empty()) {
3950                 return;
3951         }
3952
3953         TrackSelection views = selection->tracks;
3954
3955         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3956
3957                 if (enable_processing) {
3958
3959                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3960
3961                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3962                                 MessageDialog d (
3963                                         _("You can't perform this operation because the processing of the signal "
3964                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3965                                           "You can do this without processing, which is a different operation.")
3966                                         );
3967                                 d.set_title (_("Cannot bounce"));
3968                                 d.run ();
3969                                 return;
3970                         }
3971                 }
3972         }
3973
3974         framepos_t start = selection->time[clicked_selection].start;
3975         framepos_t end = selection->time[clicked_selection].end;
3976         framepos_t cnt = end - start + 1;
3977         bool in_command = false;
3978
3979         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3980
3981                 RouteTimeAxisView* rtv;
3982
3983                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3984                         continue;
3985                 }
3986
3987                 boost::shared_ptr<Playlist> playlist;
3988
3989                 if ((playlist = rtv->playlist()) == 0) {
3990                         continue;
3991                 }
3992
3993                 InterThreadInfo itt;
3994
3995                 playlist->clear_changes ();
3996                 playlist->clear_owned_changes ();
3997
3998                 boost::shared_ptr<Region> r;
3999
4000                 if (enable_processing) {
4001                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
4002                 } else {
4003                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
4004                 }
4005
4006                 if (!r) {
4007                         continue;
4008                 }
4009
4010                 if (replace) {
4011                         list<AudioRange> ranges;
4012                         ranges.push_back (AudioRange (start, start+cnt, 0));
4013                         playlist->cut (ranges); // discard result
4014                         playlist->add_region (r, start);
4015                 }
4016
4017                 if (!in_command) {
4018                         begin_reversible_command (_("bounce range"));
4019                         in_command = true;
4020                 }
4021                 vector<Command*> cmds;
4022                 playlist->rdiff (cmds);
4023                 _session->add_commands (cmds);
4024
4025                 _session->add_command (new StatefulDiffCommand (playlist));
4026         }
4027
4028         if (in_command) {
4029                 commit_reversible_command ();
4030         }
4031 }
4032
4033 /** Delete selected regions, automation points or a time range */
4034 void
4035 Editor::delete_ ()
4036 {
4037         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
4038         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
4039         bool deleted = false;
4040         if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
4041                 deleted = current_mixer_strip->delete_processors ();
4042
4043         if (!deleted)
4044                 cut_copy (Delete);
4045 }
4046
4047 /** Cut selected regions, automation points or a time range */
4048 void
4049 Editor::cut ()
4050 {
4051         cut_copy (Cut);
4052 }
4053
4054 /** Copy selected regions, automation points or a time range */
4055 void
4056 Editor::copy ()
4057 {
4058         cut_copy (Copy);
4059 }
4060
4061
4062 /** @return true if a Cut, Copy or Clear is possible */
4063 bool
4064 Editor::can_cut_copy () const
4065 {
4066         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
4067                 return true;
4068
4069         return false;
4070 }
4071
4072
4073 /** Cut, copy or clear selected regions, automation points or a time range.
4074  * @param op Operation (Delete, Cut, Copy or Clear)
4075  */
4076 void
4077 Editor::cut_copy (CutCopyOp op)
4078 {
4079         /* only cancel selection if cut/copy is successful.*/
4080
4081         string opname;
4082
4083         switch (op) {
4084         case Delete:
4085                 opname = _("delete");
4086                 break;
4087         case Cut:
4088                 opname = _("cut");
4089                 break;
4090         case Copy:
4091                 opname = _("copy");
4092                 break;
4093         case Clear:
4094                 opname = _("clear");
4095                 break;
4096         }
4097
4098         /* if we're deleting something, and the mouse is still pressed,
4099            the thing we started a drag for will be gone when we release
4100            the mouse button(s). avoid this. see part 2 at the end of
4101            this function.
4102         */
4103
4104         if (op == Delete || op == Cut || op == Clear) {
4105                 if (_drags->active ()) {
4106                         _drags->abort ();
4107                 }
4108         }
4109
4110         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
4111                 cut_buffer->clear ();
4112
4113         if (entered_marker) {
4114
4115                 /* cut/delete op while pointing at a marker */
4116
4117                 bool ignored;
4118                 Location* loc = find_location_from_marker (entered_marker, ignored);
4119
4120                 if (_session && loc) {
4121                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
4122                 }
4123
4124                 _drags->abort ();
4125                 return;
4126         }
4127
4128         switch (mouse_mode) {
4129         case MouseDraw:
4130         case MouseContent:
4131                 begin_reversible_command (opname + ' ' + X_("MIDI"));
4132                 cut_copy_midi (op);
4133                 commit_reversible_command ();
4134                 return;
4135         default:
4136                 break;
4137         }
4138
4139         bool did_edit = false;
4140
4141         if (!selection->regions.empty() || !selection->points.empty()) {
4142                 begin_reversible_command (opname + ' ' + _("objects"));
4143                 did_edit = true;
4144
4145                 if (!selection->regions.empty()) {
4146                         cut_copy_regions (op, selection->regions);
4147                         
4148                         if (op == Cut || op == Delete) {
4149                                 selection->clear_regions ();
4150                         }
4151                 }
4152                 
4153                 if (!selection->points.empty()) {
4154                         cut_copy_points (op);
4155                         
4156                         if (op == Cut || op == Delete) {
4157                                 selection->clear_points ();
4158                         }
4159                 }
4160         } else if (selection->time.empty()) {
4161                 framepos_t start, end;
4162                 /* no time selection, see if we can get an edit range
4163                    and use that.
4164                 */
4165                 if (get_edit_op_range (start, end)) {
4166                         selection->set (start, end);
4167                 }
4168         } else if (!selection->time.empty()) {
4169                 begin_reversible_command (opname + ' ' + _("range"));
4170
4171                 did_edit = true;
4172                 cut_copy_ranges (op);
4173                 
4174                 if (op == Cut || op == Delete) {
4175                         selection->clear_time ();
4176                 }
4177         }
4178         
4179         if (did_edit) {
4180                 /* reset repeated paste state */
4181                 paste_count    = 0;
4182                 last_paste_pos = 0;
4183                 commit_reversible_command ();   
4184         }
4185         
4186         if (op == Delete || op == Cut || op == Clear) {
4187                 _drags->abort ();
4188         }
4189 }
4190
4191 struct AutomationRecord {
4192         AutomationRecord () : state (0) , line(NULL) {}
4193         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
4194         
4195         XMLNode* state; ///< state before any operation
4196         const AutomationLine* line; ///< line this came from
4197         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
4198 };
4199
4200 /** Cut, copy or clear selected automation points.
4201  *  @param op Operation (Cut, Copy or Clear)
4202  */
4203 void
4204 Editor::cut_copy_points (Editing::CutCopyOp op, Evoral::Beats earliest, bool midi)
4205 {
4206         if (selection->points.empty ()) {
4207                 return;
4208         }
4209
4210         /* XXX: not ideal, as there may be more than one track involved in the point selection */
4211         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
4212
4213         /* Keep a record of the AutomationLists that we end up using in this operation */
4214         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
4215         Lists lists;
4216
4217         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
4218         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4219                 const AutomationLine&                   line = (*i)->line();
4220                 const boost::shared_ptr<AutomationList> al   = line.the_list();
4221                 if (lists.find (al) == lists.end ()) {
4222                         /* We haven't seen this list yet, so make a record for it.  This includes
4223                            taking a copy of its current state, in case this is needed for undo later.
4224                         */
4225                         lists[al] = AutomationRecord (&al->get_state (), &line);
4226                 }
4227         }
4228
4229         if (op == Cut || op == Copy) {
4230                 /* This operation will involve putting things in the cut buffer, so create an empty
4231                    ControlList for each of our source lists to put the cut buffer data in.
4232                 */
4233                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4234                         i->second.copy = i->first->create (i->first->parameter (), i->first->descriptor());
4235                 }
4236
4237                 /* Add all selected points to the relevant copy ControlLists */
4238                 framepos_t start = std::numeric_limits<framepos_t>::max();
4239                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4240                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4241                         AutomationList::const_iterator    j  = (*i)->model();
4242
4243                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
4244                         if (midi) {
4245                                 /* Update earliest MIDI start time in beats */
4246                                 earliest = std::min(earliest, Evoral::Beats((*j)->when));
4247                         } else {
4248                                 /* Update earliest session start time in frames */
4249                                 start = std::min(start, (*i)->line().session_position(j));
4250                         }
4251                 }
4252
4253                 /* Snap start time backwards, so copy/paste is snap aligned. */
4254                 if (midi) {
4255                         if (earliest == Evoral::Beats::max()) {
4256                                 earliest = Evoral::Beats();  // Weird... don't offset
4257                         }
4258                         earliest.round_down_to_beat();
4259                 } else {
4260                         if (start == std::numeric_limits<double>::max()) {
4261                                 start = 0;  // Weird... don't offset
4262                         }
4263                         snap_to(start, RoundDownMaybe);
4264                 }
4265
4266                 const double line_offset = midi ? earliest.to_double() : start;
4267                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4268                         /* Correct this copy list so that it is relative to the earliest
4269                            start time, so relative ordering between points is preserved
4270                            when copying from several lists and the paste starts at the
4271                            earliest copied piece of data. */
4272                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
4273                                 (*j)->when -= line_offset;
4274                         }
4275
4276                         /* And add it to the cut buffer */
4277                         cut_buffer->add (i->second.copy);
4278                 }
4279         }
4280                 
4281         if (op == Delete || op == Cut) {
4282                 /* This operation needs to remove things from the main AutomationList, so do that now */
4283                 
4284                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4285                         i->first->freeze ();
4286                 }
4287
4288                 /* Remove each selected point from its AutomationList */
4289                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4290                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
4291                         al->erase ((*i)->model ());
4292                 }
4293
4294                 /* Thaw the lists and add undo records for them */
4295                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
4296                         boost::shared_ptr<AutomationList> al = i->first;
4297                         al->thaw ();
4298                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
4299                 }
4300         }
4301 }
4302
4303 /** Cut, copy or clear selected automation points.
4304  * @param op Operation (Cut, Copy or Clear)
4305  */
4306 void
4307 Editor::cut_copy_midi (CutCopyOp op)
4308 {
4309         Evoral::Beats earliest = Evoral::Beats::max();
4310         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4311                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4312                 if (mrv) {
4313                         if (!mrv->selection().empty()) {
4314                                 earliest = std::min(earliest, (*mrv->selection().begin())->note()->time());
4315                         }
4316                         mrv->cut_copy_clear (op);
4317
4318                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4319                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4320                 }
4321         }
4322
4323         if (!selection->points.empty()) {
4324                 cut_copy_points (op, earliest, true);
4325                 if (op == Cut || op == Delete) {
4326                         selection->clear_points ();
4327                 }
4328         }
4329 }
4330
4331 struct lt_playlist {
4332     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4333             return a.playlist < b.playlist;
4334     }
4335 };
4336
4337 struct PlaylistMapping {
4338     TimeAxisView* tv;
4339     boost::shared_ptr<Playlist> pl;
4340
4341     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4342 };
4343
4344 /** Remove `clicked_regionview' */
4345 void
4346 Editor::remove_clicked_region ()
4347 {
4348         if (clicked_routeview == 0 || clicked_regionview == 0) {
4349                 return;
4350         }
4351
4352         begin_reversible_command (_("remove region"));
4353
4354         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4355
4356         playlist->clear_changes ();
4357         playlist->clear_owned_changes ();
4358         playlist->remove_region (clicked_regionview->region());
4359         if (Config->get_edit_mode() == Ripple)
4360                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4361
4362         /* We might have removed regions, which alters other regions' layering_index,
4363            so we need to do a recursive diff here.
4364         */
4365         vector<Command*> cmds;
4366         playlist->rdiff (cmds);
4367         _session->add_commands (cmds);
4368         
4369         _session->add_command(new StatefulDiffCommand (playlist));
4370         commit_reversible_command ();
4371 }
4372
4373
4374 /** Remove the selected regions */
4375 void
4376 Editor::remove_selected_regions ()
4377 {
4378         RegionSelection rs = get_regions_from_selection_and_entered ();
4379
4380         if (!_session || rs.empty()) {
4381                 return;
4382         }
4383
4384         list<boost::shared_ptr<Region> > regions_to_remove;
4385
4386         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4387                 // we can't just remove the region(s) in this loop because
4388                 // this removes them from the RegionSelection, and they thus
4389                 // disappear from underneath the iterator, and the ++i above
4390                 // SEGVs in a puzzling fashion.
4391
4392                 // so, first iterate over the regions to be removed from rs and
4393                 // add them to the regions_to_remove list, and then
4394                 // iterate over the list to actually remove them.
4395
4396                 regions_to_remove.push_back ((*i)->region());
4397         }
4398
4399         vector<boost::shared_ptr<Playlist> > playlists;
4400
4401         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4402
4403                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4404
4405                 if (!playlist) {
4406                         // is this check necessary?
4407                         continue;
4408                 }
4409
4410                 /* get_regions_from_selection_and_entered() guarantees that
4411                    the playlists involved are unique, so there is no need
4412                    to check here.
4413                 */
4414
4415                 playlists.push_back (playlist);
4416
4417                 playlist->clear_changes ();
4418                 playlist->clear_owned_changes ();
4419                 playlist->freeze ();
4420                 playlist->remove_region (*rl);
4421                 if (Config->get_edit_mode() == Ripple)
4422                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4423
4424         }
4425
4426         vector<boost::shared_ptr<Playlist> >::iterator pl;
4427         bool in_command = false;
4428
4429         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4430                 (*pl)->thaw ();
4431
4432                 /* We might have removed regions, which alters other regions' layering_index,
4433                    so we need to do a recursive diff here.
4434                 */
4435
4436                 if (!in_command) {
4437                         begin_reversible_command (_("remove region"));
4438                         in_command = true;
4439                 }
4440                 vector<Command*> cmds;
4441                 (*pl)->rdiff (cmds);
4442                 _session->add_commands (cmds);
4443                 
4444                 _session->add_command(new StatefulDiffCommand (*pl));
4445         }
4446
4447         if (in_command) {
4448                 commit_reversible_command ();
4449         }
4450 }
4451
4452 /** Cut, copy or clear selected regions.
4453  * @param op Operation (Cut, Copy or Clear)
4454  */
4455 void
4456 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4457 {
4458         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4459            a map when we want ordered access to both elements. i think.
4460         */
4461
4462         vector<PlaylistMapping> pmap;
4463
4464         framepos_t first_position = max_framepos;
4465
4466         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4467         FreezeList freezelist;
4468
4469         /* get ordering correct before we cut/copy */
4470
4471         rs.sort_by_position_and_track ();
4472
4473         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4474
4475                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4476
4477                 if (op == Cut || op == Clear || op == Delete) {
4478                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4479
4480                         if (pl) {
4481                                 FreezeList::iterator fl;
4482
4483                                 // only take state if this is a new playlist.
4484                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4485                                         if ((*fl) == pl) {
4486                                                 break;
4487                                         }
4488                                 }
4489
4490                                 if (fl == freezelist.end()) {
4491                                         pl->clear_changes();
4492                                         pl->clear_owned_changes ();
4493                                         pl->freeze ();
4494                                         freezelist.insert (pl);
4495                                 }
4496                         }
4497                 }
4498
4499                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4500                 vector<PlaylistMapping>::iterator z;
4501
4502                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4503                         if ((*z).tv == tv) {
4504                                 break;
4505                         }
4506                 }
4507
4508                 if (z == pmap.end()) {
4509                         pmap.push_back (PlaylistMapping (tv));
4510                 }
4511         }
4512
4513         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4514
4515                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4516
4517                 if (!pl) {
4518                         /* region not yet associated with a playlist (e.g. unfinished
4519                            capture pass.
4520                         */
4521                         ++x;
4522                         continue;
4523                 }
4524
4525                 TimeAxisView& tv = (*x)->get_time_axis_view();
4526                 boost::shared_ptr<Playlist> npl;
4527                 RegionSelection::iterator tmp;
4528
4529                 tmp = x;
4530                 ++tmp;
4531
4532                 if (op != Delete) {
4533
4534                         vector<PlaylistMapping>::iterator z;
4535                         
4536                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4537                                 if ((*z).tv == &tv) {
4538                                         break;
4539                                 }
4540                         }
4541                         
4542                         assert (z != pmap.end());
4543                         
4544                         if (!(*z).pl) {
4545                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4546                                 npl->freeze();
4547                                 (*z).pl = npl;
4548                         } else {
4549                                 npl = (*z).pl;
4550                         }
4551                 }
4552
4553                 boost::shared_ptr<Region> r = (*x)->region();
4554                 boost::shared_ptr<Region> _xx;
4555
4556                 assert (r != 0);
4557
4558                 switch (op) {
4559                 case Delete:
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                 case Cut:
4566                         _xx = RegionFactory::create (r);
4567                         npl->add_region (_xx, r->position() - first_position);
4568                         pl->remove_region (r);
4569                         if (Config->get_edit_mode() == Ripple)
4570                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4571                         break;
4572
4573                 case Copy:
4574                         /* copy region before adding, so we're not putting same object into two different playlists */
4575                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4576                         break;
4577
4578                 case Clear:
4579                         pl->remove_region (r);
4580                         if (Config->get_edit_mode() == Ripple)
4581                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4582                         break;
4583                 }
4584
4585                 x = tmp;
4586         }
4587
4588         if (op != Delete) {
4589
4590                 list<boost::shared_ptr<Playlist> > foo;
4591                 
4592                 /* the pmap is in the same order as the tracks in which selected regions occured */
4593                 
4594                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4595                         if ((*i).pl) {
4596                                 (*i).pl->thaw();
4597                                 foo.push_back ((*i).pl);
4598                         }
4599                 }
4600                 
4601                 if (!foo.empty()) {
4602                         cut_buffer->set (foo);
4603                 }
4604                 
4605                 if (pmap.empty()) {
4606                         _last_cut_copy_source_track = 0;
4607                 } else {
4608                         _last_cut_copy_source_track = pmap.front().tv;
4609                 }
4610         }
4611
4612         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4613                 (*pl)->thaw ();
4614
4615                 /* We might have removed regions, which alters other regions' layering_index,
4616                    so we need to do a recursive diff here.
4617                 */
4618                 vector<Command*> cmds;
4619                 (*pl)->rdiff (cmds);
4620                 _session->add_commands (cmds);
4621                 
4622                 _session->add_command (new StatefulDiffCommand (*pl));
4623         }
4624 }
4625
4626 void
4627 Editor::cut_copy_ranges (CutCopyOp op)
4628 {
4629         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4630
4631         /* Sort the track selection now, so that it if is used, the playlists
4632            selected by the calls below to cut_copy_clear are in the order that
4633            their tracks appear in the editor.  This makes things like paste
4634            of ranges work properly.
4635         */
4636
4637         sort_track_selection (ts);
4638
4639         if (ts.empty()) {
4640                 if (!entered_track) {
4641                         return;
4642                 }
4643                 ts.push_back (entered_track);
4644         } 
4645
4646         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4647                 (*i)->cut_copy_clear (*selection, op);
4648         }
4649 }
4650
4651 void
4652 Editor::paste (float times, bool from_context)
4653 {
4654         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4655
4656         paste_internal (get_preferred_edit_position (EDIT_IGNORE_NONE, from_context), times);
4657 }
4658
4659 void
4660 Editor::mouse_paste ()
4661 {
4662         framepos_t where;
4663         bool ignored;
4664
4665         if (!mouse_frame (where, ignored)) {
4666                 return;
4667         }
4668
4669         snap_to (where);
4670         paste_internal (where, 1);
4671 }
4672
4673 void
4674 Editor::paste_internal (framepos_t position, float times)
4675 {
4676         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4677
4678         if (cut_buffer->empty(internal_editing())) {
4679                 return;
4680         }
4681
4682         if (position == max_framepos) {
4683                 position = get_preferred_edit_position();
4684                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4685         }
4686
4687         if (position == last_paste_pos) {
4688                 /* repeated paste in the same position */
4689                 ++paste_count;
4690         } else {
4691                 /* paste in new location, reset repeated paste state */
4692                 paste_count = 0;
4693                 last_paste_pos = position;
4694         }
4695
4696         /* get everything in the correct order */
4697
4698         TrackViewList ts;
4699         if (!selection->tracks.empty()) {
4700                 /* If there is a track selection, paste into exactly those tracks and
4701                    only those tracks.  This allows the user to be explicit and override
4702                    the below "do the reasonable thing" logic. */
4703                 ts = selection->tracks.filter_to_unique_playlists ();
4704                 sort_track_selection (ts);
4705         } else {
4706                 /* Figure out which track to base the paste at. */
4707                 TimeAxisView* base_track = NULL;
4708                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4709                         /* With the mouse edit point, paste onto the track under the mouse. */
4710                         base_track = entered_track;
4711                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4712                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4713                         base_track = &entered_regionview->get_time_axis_view();
4714                 } else if (_last_cut_copy_source_track) {
4715                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4716                         base_track = _last_cut_copy_source_track;
4717                 } else {
4718                         /* This is "impossible" since we've copied... well, do nothing. */
4719                         return;
4720                 }
4721
4722                 /* Walk up to parent if necessary, so base track is a route. */
4723                 while (base_track->get_parent()) {
4724                         base_track = base_track->get_parent();
4725                 }
4726
4727                 /* Add base track and all tracks below it.  The paste logic will select
4728                    the appropriate object types from the cut buffer in relative order. */
4729                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4730                         if ((*i)->order() >= base_track->order()) {
4731                                 ts.push_back(*i);
4732                         }
4733                 }
4734
4735                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4736                 sort_track_selection (ts);
4737
4738                 /* Add automation children of each track in order, for pasting several lines. */
4739                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4740                         /* Add any automation children for pasting several lines */
4741                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4742                         if (!rtv) {
4743                                 continue;
4744                         }
4745
4746                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4747                         const ATracks& atracks = rtv->automation_tracks();
4748                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4749                                 i = ts.insert(i, a->second.get());
4750                                 ++i;
4751                         }
4752                 }
4753
4754                 /* We now have a list of trackviews starting at base_track, including
4755                    automation children, in the order shown in the editor, e.g. R1,
4756                    R1.A1, R1.A2, R2, R2.A1, ... */
4757         }
4758
4759         begin_reversible_command (Operations::paste);
4760
4761         if (ts.size() == 1 && cut_buffer->lines.size() == 1 &&
4762             dynamic_cast<AutomationTimeAxisView*>(ts.front())) {
4763             /* Only one line copied, and one automation track selected.  Do a
4764                "greedy" paste from one automation type to another. */
4765
4766             PasteContext ctx(paste_count, times, ItemCounts(), true);
4767             ts.front()->paste (position, *cut_buffer, ctx);
4768
4769         } else {
4770
4771                 /* Paste into tracks */
4772
4773                 PasteContext ctx(paste_count, times, ItemCounts(), false);
4774                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4775                         (*i)->paste (position, *cut_buffer, ctx);
4776                 }
4777         }
4778
4779         commit_reversible_command ();
4780 }
4781
4782 void
4783 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4784 {
4785         if (regions.empty ()) {
4786                 return;
4787         }
4788
4789         boost::shared_ptr<Playlist> playlist;
4790         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4791         RegionSelection foo;
4792
4793         framepos_t const start_frame = regions.start ();
4794         framepos_t const end_frame = regions.end_frame ();
4795         framecnt_t const gap = end_frame - start_frame;
4796
4797         begin_reversible_command (Operations::duplicate_region);
4798
4799         selection->clear_regions ();
4800
4801         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4802
4803                 boost::shared_ptr<Region> r ((*i)->region());
4804
4805                 TimeAxisView& tv = (*i)->get_time_axis_view();
4806                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4807                 latest_regionviews.clear ();
4808                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4809
4810                 framepos_t const position = end_frame + (r->first_frame() - start_frame);
4811                 playlist = (*i)->region()->playlist();
4812                 playlist->clear_changes ();
4813                 playlist->duplicate (r, position, gap, times);
4814                 _session->add_command(new StatefulDiffCommand (playlist));
4815
4816                 c.disconnect ();
4817
4818                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4819         }
4820
4821         if (!foo.empty()) {
4822                 selection->set (foo);
4823         }
4824
4825         commit_reversible_command ();
4826 }
4827
4828 void
4829 Editor::duplicate_selection (float times)
4830 {
4831         if (selection->time.empty() || selection->tracks.empty()) {
4832                 return;
4833         }
4834
4835         boost::shared_ptr<Playlist> playlist;
4836         vector<boost::shared_ptr<Region> > new_regions;
4837         vector<boost::shared_ptr<Region> >::iterator ri;
4838
4839         create_region_from_selection (new_regions);
4840
4841         if (new_regions.empty()) {
4842                 return;
4843         }
4844
4845         ri = new_regions.begin();
4846
4847         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4848         bool in_command = false;
4849
4850         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4851                 if ((playlist = (*i)->playlist()) == 0) {
4852                         continue;
4853                 }
4854                 playlist->clear_changes ();
4855                 framepos_t end;
4856                 if (clicked_selection) {
4857                         end = selection->time[clicked_selection].end;
4858                 } else {
4859                         end = selection->time.end_frame();
4860                 }
4861                 playlist->duplicate (*ri, end, times);
4862
4863                 if (!in_command) {
4864                         begin_reversible_command (_("duplicate selection"));
4865                         in_command = true;
4866                 }
4867                 _session->add_command (new StatefulDiffCommand (playlist));
4868
4869                 ++ri;
4870                 if (ri == new_regions.end()) {
4871                         --ri;
4872                 }
4873         }
4874
4875         if (in_command) {
4876                 commit_reversible_command ();
4877         }
4878 }
4879
4880 /** Reset all selected points to the relevant default value */
4881 void
4882 Editor::reset_point_selection ()
4883 {
4884         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4885                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4886                 (*j)->value = (*i)->line().the_list()->default_value ();
4887         }
4888 }
4889
4890 void
4891 Editor::center_playhead ()
4892 {
4893         float const page = _visible_canvas_width * samples_per_pixel;
4894         center_screen_internal (playhead_cursor->current_frame (), page);
4895 }
4896
4897 void
4898 Editor::center_edit_point ()
4899 {
4900         float const page = _visible_canvas_width * samples_per_pixel;
4901         center_screen_internal (get_preferred_edit_position(), page);
4902 }
4903
4904 /** Caller must begin and commit a reversible command */
4905 void
4906 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4907 {
4908         playlist->clear_changes ();
4909         playlist->clear ();
4910         _session->add_command (new StatefulDiffCommand (playlist));
4911 }
4912
4913 void
4914 Editor::nudge_track (bool use_edit, bool forwards)
4915 {
4916         boost::shared_ptr<Playlist> playlist;
4917         framepos_t distance;
4918         framepos_t next_distance;
4919         framepos_t start;
4920
4921         if (use_edit) {
4922                 start = get_preferred_edit_position();
4923         } else {
4924                 start = 0;
4925         }
4926
4927         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4928                 return;
4929         }
4930
4931         if (selection->tracks.empty()) {
4932                 return;
4933         }
4934
4935         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4936         bool in_command = false;
4937
4938         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4939
4940                 if ((playlist = (*i)->playlist()) == 0) {
4941                         continue;
4942                 }
4943
4944                 playlist->clear_changes ();
4945                 playlist->clear_owned_changes ();
4946
4947                 playlist->nudge_after (start, distance, forwards);
4948
4949                 if (!in_command) {
4950                         begin_reversible_command (_("nudge track"));
4951                         in_command = true;
4952                 }
4953                 vector<Command*> cmds;
4954
4955                 playlist->rdiff (cmds);
4956                 _session->add_commands (cmds);
4957
4958                 _session->add_command (new StatefulDiffCommand (playlist));
4959         }
4960
4961         if (in_command) {
4962                 commit_reversible_command ();
4963         }
4964 }
4965
4966 void
4967 Editor::remove_last_capture ()
4968 {
4969         vector<string> choices;
4970         string prompt;
4971
4972         if (!_session) {
4973                 return;
4974         }
4975
4976         if (Config->get_verify_remove_last_capture()) {
4977                 prompt  = _("Do you really want to destroy the last capture?"
4978                             "\n(This is destructive and cannot be undone)");
4979
4980                 choices.push_back (_("No, do nothing."));
4981                 choices.push_back (_("Yes, destroy it."));
4982
4983                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4984
4985                 if (prompter.run () == 1) {
4986                         _session->remove_last_capture ();
4987                         _regions->redisplay ();
4988                 }
4989
4990         } else {
4991                 _session->remove_last_capture();
4992                 _regions->redisplay ();
4993         }
4994 }
4995
4996 void
4997 Editor::normalize_region ()
4998 {
4999         if (!_session) {
5000                 return;
5001         }
5002
5003         RegionSelection rs = get_regions_from_selection_and_entered ();
5004
5005         if (rs.empty()) {
5006                 return;
5007         }
5008
5009         NormalizeDialog dialog (rs.size() > 1);
5010
5011         if (dialog.run () == RESPONSE_CANCEL) {
5012                 return;
5013         }
5014
5015         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5016         gdk_flush ();
5017
5018         /* XXX: should really only count audio regions here */
5019         int const regions = rs.size ();
5020
5021         /* Make a list of the selected audio regions' maximum amplitudes, and also
5022            obtain the maximum amplitude of them all.
5023         */
5024         list<double> max_amps;
5025         double max_amp = 0;
5026         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
5027                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
5028                 if (arv) {
5029                         dialog.descend (1.0 / regions);
5030                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
5031
5032                         if (a == -1) {
5033                                 /* the user cancelled the operation */
5034                                 return;
5035                         }
5036
5037                         max_amps.push_back (a);
5038                         max_amp = max (max_amp, a);
5039                         dialog.ascend ();
5040                 }
5041         }
5042
5043         list<double>::const_iterator a = max_amps.begin ();
5044         bool in_command = false;
5045
5046         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5047                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
5048                 if (!arv) {
5049                         continue;
5050                 }
5051
5052                 arv->region()->clear_changes ();
5053
5054                 double const amp = dialog.normalize_individually() ? *a : max_amp;
5055
5056                 arv->audio_region()->normalize (amp, dialog.target ());
5057
5058                 if (!in_command) {
5059                         begin_reversible_command (_("normalize"));
5060                         in_command = true;
5061                 }
5062                 _session->add_command (new StatefulDiffCommand (arv->region()));
5063
5064                 ++a;
5065         }
5066
5067         if (in_command) {
5068                 commit_reversible_command ();
5069         }
5070 }
5071
5072
5073 void
5074 Editor::reset_region_scale_amplitude ()
5075 {
5076         if (!_session) {
5077                 return;
5078         }
5079
5080         RegionSelection rs = get_regions_from_selection_and_entered ();
5081
5082         if (rs.empty()) {
5083                 return;
5084         }
5085
5086         bool in_command = false;
5087
5088         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5089                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5090                 if (!arv)
5091                         continue;
5092                 arv->region()->clear_changes ();
5093                 arv->audio_region()->set_scale_amplitude (1.0f);
5094
5095                 if(!in_command) {
5096                                 begin_reversible_command ("reset gain");
5097                                 in_command = true;
5098                 }
5099                 _session->add_command (new StatefulDiffCommand (arv->region()));
5100         }
5101
5102         if (in_command) {
5103                 commit_reversible_command ();
5104         }
5105 }
5106
5107 void
5108 Editor::adjust_region_gain (bool up)
5109 {
5110         RegionSelection rs = get_regions_from_selection_and_entered ();
5111
5112         if (!_session || rs.empty()) {
5113                 return;
5114         }
5115
5116         bool in_command = false;
5117
5118         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5119                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5120                 if (!arv) {
5121                         continue;
5122                 }
5123
5124                 arv->region()->clear_changes ();
5125
5126                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
5127
5128                 if (up) {
5129                         dB += 1;
5130                 } else {
5131                         dB -= 1;
5132                 }
5133
5134                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
5135
5136                 if (!in_command) {
5137                                 begin_reversible_command ("adjust region gain");
5138                                 in_command = true;
5139                 }
5140                 _session->add_command (new StatefulDiffCommand (arv->region()));
5141         }
5142
5143         if (in_command) {
5144                 commit_reversible_command ();
5145         }
5146 }
5147
5148
5149 void
5150 Editor::reverse_region ()
5151 {
5152         if (!_session) {
5153                 return;
5154         }
5155
5156         Reverse rev (*_session);
5157         apply_filter (rev, _("reverse regions"));
5158 }
5159
5160 void
5161 Editor::strip_region_silence ()
5162 {
5163         if (!_session) {
5164                 return;
5165         }
5166
5167         RegionSelection rs = get_regions_from_selection_and_entered ();
5168
5169         if (rs.empty()) {
5170                 return;
5171         }
5172
5173         std::list<RegionView*> audio_only;
5174
5175         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5176                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
5177                 if (arv) {
5178                         audio_only.push_back (arv);
5179                 }
5180         }
5181
5182         assert (!audio_only.empty());
5183
5184         StripSilenceDialog d (_session, audio_only);
5185         int const r = d.run ();
5186
5187         d.drop_rects ();
5188
5189         if (r == Gtk::RESPONSE_OK) {
5190                 ARDOUR::AudioIntervalMap silences;
5191                 d.silences (silences);
5192                 StripSilence s (*_session, silences, d.fade_length());
5193                 apply_filter (s, _("strip silence"), &d);
5194         }
5195 }
5196
5197 Command*
5198 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
5199 {
5200         Evoral::Sequence<Evoral::Beats>::Notes selected;
5201         mrv.selection_as_notelist (selected, true);
5202
5203         vector<Evoral::Sequence<Evoral::Beats>::Notes> v;
5204         v.push_back (selected);
5205
5206         framepos_t    pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
5207         Evoral::Beats pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
5208
5209         return op (mrv.midi_region()->model(), pos_beats, v);
5210 }
5211
5212 void
5213 Editor::apply_midi_note_edit_op (MidiOperator& op, const RegionSelection& rs)
5214 {
5215         if (rs.empty()) {
5216                 return;
5217         }
5218
5219         bool in_command = false;
5220
5221         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ) {
5222                 RegionSelection::const_iterator tmp = r;
5223                 ++tmp;
5224
5225                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
5226
5227                 if (mrv) {
5228                         Command* cmd = apply_midi_note_edit_op_to_region (op, *mrv);
5229                         if (cmd) {
5230                                 if (!in_command) {
5231                                         begin_reversible_command (op.name ());
5232                                         in_command = true;
5233                                 }
5234                                 (*cmd)();
5235                                 _session->add_command (cmd);
5236                         }
5237                 }
5238
5239                 r = tmp;
5240         }
5241
5242         if (in_command) {
5243                 commit_reversible_command ();
5244         }
5245 }
5246
5247 void
5248 Editor::fork_region ()
5249 {
5250         RegionSelection rs = get_regions_from_selection_and_entered ();
5251
5252         if (rs.empty()) {
5253                 return;
5254         }
5255
5256         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5257         bool in_command = false;
5258
5259         gdk_flush ();
5260
5261         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5262                 RegionSelection::iterator tmp = r;
5263                 ++tmp;
5264
5265                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
5266
5267                 if (mrv) {
5268                         try {
5269                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
5270                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
5271                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
5272
5273                                 if (!in_command) {
5274                                         begin_reversible_command (_("Fork Region(s)"));
5275                                         in_command = true;
5276                                 }
5277                                 playlist->clear_changes ();
5278                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
5279                                 _session->add_command(new StatefulDiffCommand (playlist));
5280                         } catch (...) {
5281                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
5282                         }
5283                 }
5284
5285                 r = tmp;
5286         }
5287
5288         if (in_command) {
5289                 commit_reversible_command ();
5290         }
5291 }
5292
5293 void
5294 Editor::quantize_region ()
5295 {
5296         if (_session) {
5297                 quantize_regions(get_regions_from_selection_and_entered ());
5298         }
5299 }
5300
5301 void
5302 Editor::quantize_regions (const RegionSelection& rs)
5303 {
5304         if (rs.n_midi_regions() == 0) {
5305                 return;
5306         }
5307
5308         if (!quantize_dialog) {
5309                 quantize_dialog = new QuantizeDialog (*this);
5310         }
5311
5312         quantize_dialog->present ();
5313         const int r = quantize_dialog->run ();
5314         quantize_dialog->hide ();
5315
5316         if (r == Gtk::RESPONSE_OK) {
5317                 Quantize quant (quantize_dialog->snap_start(),
5318                                 quantize_dialog->snap_end(),
5319                                 quantize_dialog->start_grid_size(),
5320                                 quantize_dialog->end_grid_size(),
5321                                 quantize_dialog->strength(),
5322                                 quantize_dialog->swing(),
5323                                 quantize_dialog->threshold());
5324
5325                 apply_midi_note_edit_op (quant, rs);
5326         }
5327 }
5328
5329 void
5330 Editor::legatize_region (bool shrink_only)
5331 {
5332         if (_session) {
5333                 legatize_regions(get_regions_from_selection_and_entered (), shrink_only);
5334         }
5335 }
5336
5337 void
5338 Editor::legatize_regions (const RegionSelection& rs, bool shrink_only)
5339 {
5340         if (rs.n_midi_regions() == 0) {
5341                 return;
5342         }
5343
5344         Legatize legatize(shrink_only);
5345         apply_midi_note_edit_op (legatize, rs);
5346 }
5347
5348 void
5349 Editor::transform_region ()
5350 {
5351         if (_session) {
5352                 transform_regions(get_regions_from_selection_and_entered ());
5353         }
5354 }
5355
5356 void
5357 Editor::transform_regions (const RegionSelection& rs)
5358 {
5359         if (rs.n_midi_regions() == 0) {
5360                 return;
5361         }
5362
5363         TransformDialog* td = new TransformDialog();
5364
5365         td->present();
5366         const int r = td->run();
5367         td->hide();
5368
5369         if (r == Gtk::RESPONSE_OK) {
5370                 Transform transform(td->get());
5371                 apply_midi_note_edit_op(transform, rs);
5372         }
5373 }
5374
5375 void
5376 Editor::insert_patch_change (bool from_context)
5377 {
5378         RegionSelection rs = get_regions_from_selection_and_entered ();
5379
5380         if (rs.empty ()) {
5381                 return;
5382         }
5383
5384         const framepos_t p = get_preferred_edit_position (EDIT_IGNORE_NONE, from_context);
5385
5386         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
5387            there may be more than one, but the PatchChangeDialog can only offer
5388            one set of patch menus.
5389         */
5390         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
5391
5392         Evoral::PatchChange<Evoral::Beats> empty (Evoral::Beats(), 0, 0, 0);
5393         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
5394
5395         if (d.run() == RESPONSE_CANCEL) {
5396                 return;
5397         }
5398
5399         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
5400                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5401                 if (mrv) {
5402                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5403                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5404                         }
5405                 }
5406         }
5407 }
5408
5409 void
5410 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5411 {
5412         RegionSelection rs = get_regions_from_selection_and_entered ();
5413
5414         if (rs.empty()) {
5415                 return;
5416         }
5417
5418         CursorContext::Handle cursor_ctx = CursorContext::create(*this, _cursors->wait);
5419         bool in_command = false;
5420
5421         gdk_flush ();
5422
5423         int n = 0;
5424         int const N = rs.size ();
5425
5426         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5427                 RegionSelection::iterator tmp = r;
5428                 ++tmp;
5429
5430                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5431                 if (arv) {
5432                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5433
5434                         if (progress) {
5435                                 progress->descend (1.0 / N);
5436                         }
5437
5438                         if (arv->audio_region()->apply (filter, progress) == 0) {
5439
5440                                 playlist->clear_changes ();
5441                                 playlist->clear_owned_changes ();
5442
5443                                 if (filter.results.empty ()) {
5444
5445                                         /* no regions returned; remove the old one */
5446                                         playlist->remove_region (arv->region ());
5447
5448                                 } else {
5449
5450                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5451
5452                                         /* first region replaces the old one */
5453                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5454                                         ++res;
5455
5456                                         /* add the rest */
5457                                         while (res != filter.results.end()) {
5458                                                 playlist->add_region (*res, (*res)->position());
5459                                                 ++res;
5460                                         }
5461
5462                                 }
5463                                 /* We might have removed regions, which alters other regions' layering_index,
5464                                    so we need to do a recursive diff here.
5465                                 */
5466
5467                                 if (!in_command) {
5468                                         begin_reversible_command (command);
5469                                         in_command = true;
5470                                 }
5471                                 vector<Command*> cmds;
5472                                 playlist->rdiff (cmds);
5473                                 _session->add_commands (cmds);
5474                                 
5475                                 _session->add_command(new StatefulDiffCommand (playlist));
5476                         }
5477
5478                         if (progress) {
5479                                 progress->ascend ();
5480                         }
5481                 }
5482
5483                 r = tmp;
5484                 ++n;
5485         }
5486
5487         if (in_command) {
5488                 commit_reversible_command ();
5489         }
5490 }
5491
5492 void
5493 Editor::external_edit_region ()
5494 {
5495         /* more to come */
5496 }
5497
5498 void
5499 Editor::reset_region_gain_envelopes ()
5500 {
5501         RegionSelection rs = get_regions_from_selection_and_entered ();
5502
5503         if (!_session || rs.empty()) {
5504                 return;
5505         }
5506
5507         bool in_command = false;
5508         
5509         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5510                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5511                 if (arv) {
5512                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5513                         XMLNode& before (alist->get_state());
5514
5515                         arv->audio_region()->set_default_envelope ();
5516
5517                         if (!in_command) {
5518                                 begin_reversible_command (_("reset region gain"));
5519                                 in_command = true;
5520                         }
5521                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5522                 }
5523         }
5524
5525         if (in_command) {
5526                 commit_reversible_command ();
5527         }
5528 }
5529
5530 void
5531 Editor::set_region_gain_visibility (RegionView* rv)
5532 {
5533         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5534         if (arv) {
5535                 arv->update_envelope_visibility();
5536         }
5537 }
5538
5539 void
5540 Editor::set_gain_envelope_visibility ()
5541 {
5542         if (!_session) {
5543                 return;
5544         }
5545
5546         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5547                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5548                 if (v) {
5549                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5550                 }
5551         }
5552 }
5553
5554 void
5555 Editor::toggle_gain_envelope_active ()
5556 {
5557         if (_ignore_region_action) {
5558                 return;
5559         }
5560
5561         RegionSelection rs = get_regions_from_selection_and_entered ();
5562
5563         if (!_session || rs.empty()) {
5564                 return;
5565         }
5566
5567         bool in_command = false;
5568
5569         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5570                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5571                 if (arv) {
5572                         arv->region()->clear_changes ();
5573                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5574
5575                         if (!in_command) {
5576                                 begin_reversible_command (_("region gain envelope active"));
5577                                 in_command = true;
5578                         }
5579                         _session->add_command (new StatefulDiffCommand (arv->region()));
5580                 }
5581         }
5582
5583         if (in_command) {
5584                 commit_reversible_command ();
5585         }
5586 }
5587
5588 void
5589 Editor::toggle_region_lock ()
5590 {
5591         if (_ignore_region_action) {
5592                 return;
5593         }
5594
5595         RegionSelection rs = get_regions_from_selection_and_entered ();
5596
5597         if (!_session || rs.empty()) {
5598                 return;
5599         }
5600
5601         begin_reversible_command (_("toggle region lock"));
5602         
5603         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5604                 (*i)->region()->clear_changes ();
5605                 (*i)->region()->set_locked (!(*i)->region()->locked());
5606                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5607         }
5608         
5609         commit_reversible_command ();
5610 }
5611
5612 void
5613 Editor::toggle_region_video_lock ()
5614 {
5615         if (_ignore_region_action) {
5616                 return;
5617         }
5618
5619         RegionSelection rs = get_regions_from_selection_and_entered ();
5620
5621         if (!_session || rs.empty()) {
5622                 return;
5623         }
5624
5625         begin_reversible_command (_("Toggle Video Lock"));
5626         
5627         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5628                 (*i)->region()->clear_changes ();
5629                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5630                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5631         }
5632         
5633         commit_reversible_command ();
5634 }
5635
5636 void
5637 Editor::toggle_region_lock_style ()
5638 {
5639         if (_ignore_region_action) {
5640                 return;
5641         }
5642
5643         RegionSelection rs = get_regions_from_selection_and_entered ();
5644
5645         if (!_session || rs.empty()) {
5646                 return;
5647         }
5648
5649         begin_reversible_command (_("region lock style"));
5650         
5651         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5652                 (*i)->region()->clear_changes ();
5653                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5654                 (*i)->region()->set_position_lock_style (ns);
5655                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5656         }
5657         
5658         commit_reversible_command ();
5659 }
5660
5661 void
5662 Editor::toggle_opaque_region ()
5663 {
5664         if (_ignore_region_action) {
5665                 return;
5666         }
5667
5668         RegionSelection rs = get_regions_from_selection_and_entered ();
5669
5670         if (!_session || rs.empty()) {
5671                 return;
5672         }
5673
5674         begin_reversible_command (_("change region opacity"));
5675         
5676         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5677                 (*i)->region()->clear_changes ();
5678                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5679                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5680         }
5681         
5682         commit_reversible_command ();
5683 }
5684
5685 void
5686 Editor::toggle_record_enable ()
5687 {
5688         bool new_state = false;
5689         bool first = true;
5690         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5691                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5692                 if (!rtav)
5693                         continue;
5694                 if (!rtav->is_track())
5695                         continue;
5696
5697                 if (first) {
5698                         new_state = !rtav->track()->record_enabled();
5699                         first = false;
5700                 }
5701
5702                 rtav->track()->set_record_enabled (new_state, this);
5703         }
5704 }
5705
5706 void
5707 Editor::toggle_solo ()
5708 {
5709         bool new_state = false;
5710         bool first = true;
5711         boost::shared_ptr<RouteList> rl (new RouteList);
5712
5713         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5714                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5715
5716                 if (!rtav) {
5717                         continue;
5718                 }
5719
5720                 if (first) {
5721                         new_state = !rtav->route()->soloed ();
5722                         first = false;
5723                 }
5724
5725                 rl->push_back (rtav->route());
5726         }
5727
5728         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5729 }
5730
5731 void
5732 Editor::toggle_mute ()
5733 {
5734         bool new_state = false;
5735         bool first = true;
5736         boost::shared_ptr<RouteList> rl (new RouteList);
5737
5738         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5739                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5740
5741                 if (!rtav) {
5742                         continue;
5743                 }
5744
5745                 if (first) {
5746                         new_state = !rtav->route()->muted();
5747                         first = false;
5748                 }
5749
5750                 rl->push_back (rtav->route());
5751         }
5752
5753         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5754 }
5755
5756 void
5757 Editor::toggle_solo_isolate ()
5758 {
5759 }
5760
5761
5762 void
5763 Editor::fade_range ()
5764 {
5765         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5766
5767         begin_reversible_command (_("fade range"));
5768
5769         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5770                 (*i)->fade_range (selection->time);
5771         }
5772
5773         commit_reversible_command ();
5774 }
5775
5776
5777 void
5778 Editor::set_fade_length (bool in)
5779 {
5780         RegionSelection rs = get_regions_from_selection_and_entered ();
5781
5782         if (rs.empty()) {
5783                 return;
5784         }
5785
5786         /* we need a region to measure the offset from the start */
5787
5788         RegionView* rv = rs.front ();
5789
5790         framepos_t pos = get_preferred_edit_position();
5791         framepos_t len;
5792         char const * cmd;
5793
5794         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5795                 /* edit point is outside the relevant region */
5796                 return;
5797         }
5798
5799         if (in) {
5800                 if (pos <= rv->region()->position()) {
5801                         /* can't do it */
5802                         return;
5803                 }
5804                 len = pos - rv->region()->position();
5805                 cmd = _("set fade in length");
5806         } else {
5807                 if (pos >= rv->region()->last_frame()) {
5808                         /* can't do it */
5809                         return;
5810                 }
5811                 len = rv->region()->last_frame() - pos;
5812                 cmd = _("set fade out length");
5813         }
5814
5815         bool in_command = false;
5816
5817         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5818                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5819
5820                 if (!tmp) {
5821                         continue;
5822                 }
5823
5824                 boost::shared_ptr<AutomationList> alist;
5825                 if (in) {
5826                         alist = tmp->audio_region()->fade_in();
5827                 } else {
5828                         alist = tmp->audio_region()->fade_out();
5829                 }
5830
5831                 XMLNode &before = alist->get_state();
5832
5833                 if (in) {
5834                         tmp->audio_region()->set_fade_in_length (len);
5835                         tmp->audio_region()->set_fade_in_active (true);
5836                 } else {
5837                         tmp->audio_region()->set_fade_out_length (len);
5838                         tmp->audio_region()->set_fade_out_active (true);
5839                 }
5840
5841                 if (!in_command) {
5842                         begin_reversible_command (cmd);
5843                         in_command = true;
5844                 }
5845                 XMLNode &after = alist->get_state();
5846                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5847         }
5848
5849         if (in_command) {
5850                 commit_reversible_command ();
5851         }
5852 }
5853
5854 void
5855 Editor::set_fade_in_shape (FadeShape shape)
5856 {
5857         RegionSelection rs = get_regions_from_selection_and_entered ();
5858
5859         if (rs.empty()) {
5860                 return;
5861         }
5862         bool in_command = false;
5863
5864         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5865                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5866
5867                 if (!tmp) {
5868                         continue;
5869                 }
5870
5871                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5872                 XMLNode &before = alist->get_state();
5873
5874                 tmp->audio_region()->set_fade_in_shape (shape);
5875
5876                 if (!in_command) {
5877                         begin_reversible_command (_("set fade in shape"));
5878                         in_command = true;
5879                 }
5880                 XMLNode &after = alist->get_state();
5881                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5882         }
5883
5884         if (in_command) {
5885                 commit_reversible_command ();
5886         }
5887 }
5888
5889 void
5890 Editor::set_fade_out_shape (FadeShape shape)
5891 {
5892         RegionSelection rs = get_regions_from_selection_and_entered ();
5893
5894         if (rs.empty()) {
5895                 return;
5896         }
5897         bool in_command = false;
5898
5899         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5900                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5901
5902                 if (!tmp) {
5903                         continue;
5904                 }
5905
5906                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5907                 XMLNode &before = alist->get_state();
5908
5909                 tmp->audio_region()->set_fade_out_shape (shape);
5910
5911                 if(!in_command) {
5912                         begin_reversible_command (_("set fade out shape"));
5913                         in_command = true;
5914                 }
5915                 XMLNode &after = alist->get_state();
5916                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5917         }
5918
5919         if (in_command) {
5920                 commit_reversible_command ();
5921         }
5922 }
5923
5924 void
5925 Editor::set_fade_in_active (bool yn)
5926 {
5927         RegionSelection rs = get_regions_from_selection_and_entered ();
5928
5929         if (rs.empty()) {
5930                 return;
5931         }
5932         bool in_command = false;
5933
5934         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5935                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5936
5937                 if (!tmp) {
5938                         continue;
5939                 }
5940
5941
5942                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5943
5944                 ar->clear_changes ();
5945                 ar->set_fade_in_active (yn);
5946
5947                 if (!in_command) {
5948                         begin_reversible_command (_("set fade in active"));
5949                         in_command = true;
5950                 }
5951                 _session->add_command (new StatefulDiffCommand (ar));
5952         }
5953
5954         if (in_command) {
5955                 commit_reversible_command ();
5956         }
5957 }
5958
5959 void
5960 Editor::set_fade_out_active (bool yn)
5961 {
5962         RegionSelection rs = get_regions_from_selection_and_entered ();
5963
5964         if (rs.empty()) {
5965                 return;
5966         }
5967         bool in_command = false;
5968
5969         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5970                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5971
5972                 if (!tmp) {
5973                         continue;
5974                 }
5975
5976                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5977
5978                 ar->clear_changes ();
5979                 ar->set_fade_out_active (yn);
5980
5981                 if (!in_command) {
5982                         begin_reversible_command (_("set fade out active"));
5983                         in_command = true;
5984                 }
5985                 _session->add_command(new StatefulDiffCommand (ar));
5986         }
5987
5988         if (in_command) {
5989                 commit_reversible_command ();
5990         }
5991 }
5992
5993 void
5994 Editor::toggle_region_fades (int dir)
5995 {
5996         if (_ignore_region_action) {
5997                 return;
5998         }
5999         
6000         boost::shared_ptr<AudioRegion> ar;
6001         bool yn = false;
6002
6003         RegionSelection rs = get_regions_from_selection_and_entered ();
6004
6005         if (rs.empty()) {
6006                 return;
6007         }
6008
6009         RegionSelection::iterator i;
6010         for (i = rs.begin(); i != rs.end(); ++i) {
6011                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
6012                         if (dir == -1) {
6013                                 yn = ar->fade_out_active ();
6014                         } else {
6015                                 yn = ar->fade_in_active ();
6016                         }
6017                         break;
6018                 }
6019         }
6020
6021         if (i == rs.end()) {
6022                 return;
6023         }
6024
6025         /* XXX should this undo-able? */
6026         bool in_command = false;
6027
6028         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6029                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
6030                         continue;
6031                 }
6032                 ar->clear_changes ();
6033
6034                 if (dir == 1 || dir == 0) {
6035                         ar->set_fade_in_active (!yn);
6036                 }
6037
6038                 if (dir == -1 || dir == 0) {
6039                         ar->set_fade_out_active (!yn);
6040                 }
6041                 if (!in_command) {
6042                         begin_reversible_command (_("toggle fade active"));
6043                         in_command = true;
6044                 }
6045                 _session->add_command(new StatefulDiffCommand (ar));
6046         }
6047
6048         if (in_command) {
6049                 commit_reversible_command ();
6050         }
6051 }
6052
6053
6054 /** Update region fade visibility after its configuration has been changed */
6055 void
6056 Editor::update_region_fade_visibility ()
6057 {
6058         bool _fade_visibility = _session->config.get_show_region_fades ();
6059
6060         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6061                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
6062                 if (v) {
6063                         if (_fade_visibility) {
6064                                 v->audio_view()->show_all_fades ();
6065                         } else {
6066                                 v->audio_view()->hide_all_fades ();
6067                         }
6068                 }
6069         }
6070 }
6071
6072 void
6073 Editor::set_edit_point ()
6074 {
6075         framepos_t where;
6076         bool ignored;
6077
6078         if (!mouse_frame (where, ignored)) {
6079                 return;
6080         }
6081
6082         snap_to (where);
6083
6084         if (selection->markers.empty()) {
6085
6086                 mouse_add_new_marker (where);
6087
6088         } else {
6089                 bool ignored;
6090
6091                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
6092
6093                 if (loc) {
6094                         loc->move_to (where);
6095                 }
6096         }
6097 }
6098
6099 void
6100 Editor::set_playhead_cursor ()
6101 {
6102         if (entered_marker) {
6103                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
6104         } else {
6105                 framepos_t where;
6106                 bool ignored;
6107
6108                 if (!mouse_frame (where, ignored)) {
6109                         return;
6110                 }
6111
6112                 snap_to (where);
6113
6114                 if (_session) {
6115                         _session->request_locate (where, _session->transport_rolling());
6116                 }
6117         }
6118
6119         if (UIConfiguration::instance().get_follow_edits()) {
6120                 cancel_time_selection();
6121         }
6122 }
6123
6124 void
6125 Editor::split_region ()
6126 {
6127         if (_drags->active ()) {
6128                 return;
6129         }
6130
6131         //if a range is selected, separate it
6132         if ( !selection->time.empty()) {
6133                 separate_regions_between (selection->time);
6134                 return;
6135         }
6136
6137         //if no range was selected, try to find some regions to split
6138         if (current_mouse_mode() == MouseObject) {  //don't try this for Internal Edit, Stretch, Draw, etc.
6139         
6140                 RegionSelection rs = get_regions_from_selection_and_edit_point ();
6141
6142                 framepos_t where = get_preferred_edit_position ();
6143
6144                 if (rs.empty()) {
6145                         return;
6146                 }
6147
6148                 split_regions_at (where, rs);
6149         }
6150 }
6151
6152 struct EditorOrderRouteSorter {
6153     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
6154             return a->order_key () < b->order_key ();
6155     }
6156 };
6157
6158 void
6159 Editor::select_next_route()
6160 {
6161         if (selection->tracks.empty()) {
6162                 selection->set (track_views.front());
6163                 return;
6164         }
6165
6166         TimeAxisView* current = selection->tracks.front();
6167
6168         RouteUI *rui;
6169         do {
6170                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6171                         if (*i == current) {
6172                                 ++i;
6173                                 if (i != track_views.end()) {
6174                                         current = (*i);
6175                                 } else {
6176                                         current = (*(track_views.begin()));
6177                                         //selection->set (*(track_views.begin()));
6178                                 }
6179                                 break;
6180                         }
6181                 }
6182                 rui = dynamic_cast<RouteUI *>(current);
6183         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6184
6185         selection->set(current);
6186
6187         ensure_time_axis_view_is_visible (*current, false);
6188 }
6189
6190 void
6191 Editor::select_prev_route()
6192 {
6193         if (selection->tracks.empty()) {
6194                 selection->set (track_views.front());
6195                 return;
6196         }
6197
6198         TimeAxisView* current = selection->tracks.front();
6199
6200         RouteUI *rui;
6201         do {
6202                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
6203                         if (*i == current) {
6204                                 ++i;
6205                                 if (i != track_views.rend()) {
6206                                         current = (*i);
6207                                 } else {
6208                                         current = *(track_views.rbegin());
6209                                 }
6210                                 break;
6211                         }
6212                 }
6213                 rui = dynamic_cast<RouteUI *>(current);
6214         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
6215
6216         selection->set (current);
6217
6218         ensure_time_axis_view_is_visible (*current, false);
6219 }
6220
6221 void
6222 Editor::set_loop_from_selection (bool play)
6223 {
6224         if (_session == 0) {
6225                 return;
6226         }
6227
6228         framepos_t start, end;
6229         if (!get_selection_extents ( start, end))
6230                 return;
6231
6232         set_loop_range (start, end,  _("set loop range from selection"));
6233
6234         if (play) {
6235                 _session->request_play_loop (true, true);
6236         }
6237 }
6238
6239 void
6240 Editor::set_loop_from_region (bool play)
6241 {
6242         framepos_t start, end;
6243         if (!get_selection_extents ( start, end))
6244                 return;
6245
6246         set_loop_range (start, end, _("set loop range from region"));
6247
6248         if (play) {
6249                 _session->request_locate (start, true);
6250                 _session->request_play_loop (true);
6251         }
6252 }
6253
6254 void
6255 Editor::set_punch_from_selection ()
6256 {
6257         if (_session == 0) {
6258                 return;
6259         }
6260
6261         framepos_t start, end;
6262         if (!get_selection_extents ( start, end))
6263                 return;
6264
6265         set_punch_range (start, end,  _("set punch range from selection"));
6266 }
6267
6268 void
6269 Editor::set_punch_from_loop ()
6270 {
6271         if (_session == 0) {
6272                 return;
6273         }
6274
6275         Location* tll;
6276
6277         if ((tll = transport_loop_location()) == 0) {
6278                 return;
6279         }
6280
6281         set_punch_range (tll->start(), tll->end(),  _("set punch range from loop"));
6282 }
6283
6284 void
6285 Editor::setup_loop_record ()
6286 {
6287         if (_session == 0) {
6288                 return;
6289         }
6290
6291         Location * looploc = _session->locations()->auto_loop_location();
6292
6293         if (!looploc) {
6294                 return;
6295         }
6296
6297         set_punch_range (looploc->start(), looploc->end(), _("setup loop recording"));
6298
6299         Glib::RefPtr<Action> action = ActionManager::get_action ("Transport", "TogglePunch");
6300
6301         if (action) {
6302
6303                 Glib::RefPtr<ToggleAction> tact = Glib::RefPtr<ToggleAction>::cast_dynamic(action);
6304
6305                 if (!tact) {
6306                         return;
6307                 }
6308
6309                 /* drive the other two actions from this one */
6310
6311                 Glib::RefPtr<Action> in_action = ActionManager::get_action ("Transport", "TogglePunchIn");
6312                 Glib::RefPtr<Action> out_action = ActionManager::get_action ("Transport", "TogglePunchOut");
6313
6314                 if (in_action && out_action) {
6315                         Glib::RefPtr<ToggleAction> tiact = Glib::RefPtr<ToggleAction>::cast_dynamic(in_action);
6316                         Glib::RefPtr<ToggleAction> toact = Glib::RefPtr<ToggleAction>::cast_dynamic(out_action);
6317                         tiact->set_active (true);
6318                         toact->set_active (true);
6319                 }
6320         }
6321 }
6322 void
6323 Editor::set_session_extents_from_selection ()
6324 {
6325         if (_session == 0) {
6326                 return;
6327         }
6328         
6329         framepos_t start, end;
6330         if (!get_selection_extents ( start, end))
6331                 return;
6332
6333         Location* loc;
6334         if ((loc = _session->locations()->session_range_location()) == 0) {
6335                 _session->set_session_extents ( start, end );  // this will create a new session range;  no need for UNDO
6336         } else {
6337                 XMLNode &before = loc->get_state();
6338
6339                 _session->set_session_extents ( start, end );
6340
6341                 XMLNode &after = loc->get_state();
6342
6343                 begin_reversible_command (_("set session start/end from selection"));
6344
6345                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
6346
6347                 commit_reversible_command ();
6348         }
6349 }
6350
6351 void
6352 Editor::set_punch_start_from_edit_point ()
6353 {
6354         if (_session) {
6355
6356                 framepos_t start = 0;
6357                 framepos_t end = max_framepos;
6358                 
6359                 //use the existing punch end, if any
6360                 Location* tpl = transport_punch_location();
6361                 if (tpl) {
6362                         end = tpl->end();
6363                 }
6364                 
6365                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6366                         start = _session->audible_frame();
6367                 } else {
6368                         start = get_preferred_edit_position();
6369                 }
6370                 
6371                 //snap the selection start/end
6372                 snap_to(start);
6373                 
6374                 //if there's not already a sensible selection endpoint, go "forever"
6375                 if ( start > end ) {
6376                         end = max_framepos;
6377                 }
6378                                 
6379                 set_punch_range (start, end, _("set punch start from EP"));
6380         }
6381
6382 }
6383
6384 void
6385 Editor::set_punch_end_from_edit_point ()
6386 {
6387         if (_session) {
6388
6389                 framepos_t start = 0;
6390                 framepos_t end = max_framepos;
6391                 
6392                 //use the existing punch start, if any
6393                 Location* tpl = transport_punch_location();
6394                 if (tpl) {
6395                         start = tpl->start();
6396                 }
6397                 
6398                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6399                         end = _session->audible_frame();
6400                 } else {
6401                         end = get_preferred_edit_position();
6402                 }
6403
6404                 //snap the selection start/end
6405                 snap_to(end);
6406                 
6407                 set_punch_range (start, end, _("set punch end from EP"));
6408
6409         }
6410 }
6411
6412 void
6413 Editor::set_loop_start_from_edit_point ()
6414 {
6415         if (_session) {
6416
6417                 framepos_t start = 0;
6418                 framepos_t end = max_framepos;
6419                 
6420                 //use the existing loop end, if any
6421                 Location* tpl = transport_loop_location();
6422                 if (tpl) {
6423                         end = tpl->end();
6424                 }
6425                 
6426                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6427                         start = _session->audible_frame();
6428                 } else {
6429                         start = get_preferred_edit_position();
6430                 }
6431                 
6432                 //snap the selection start/end
6433                 snap_to(start);
6434                 
6435                 //if there's not already a sensible selection endpoint, go "forever"
6436                 if ( start > end ) {
6437                         end = max_framepos;
6438                 }
6439
6440                 set_loop_range (start, end, _("set loop start from EP"));
6441         }
6442
6443 }
6444
6445 void
6446 Editor::set_loop_end_from_edit_point ()
6447 {
6448         if (_session) {
6449
6450                 framepos_t start = 0;
6451                 framepos_t end = max_framepos;
6452                 
6453                 //use the existing loop start, if any
6454                 Location* tpl = transport_loop_location();
6455                 if (tpl) {
6456                         start = tpl->start();
6457                 }
6458                 
6459                 if ((_edit_point == EditAtPlayhead) && _session->transport_rolling()) {
6460                         end = _session->audible_frame();
6461                 } else {
6462                         end = get_preferred_edit_position();
6463                 }
6464
6465                 //snap the selection start/end
6466                 snap_to(end);
6467                 
6468                 set_loop_range (start, end, _("set loop end from EP"));
6469         }
6470 }
6471
6472 void
6473 Editor::set_punch_from_region ()
6474 {
6475         framepos_t start, end;
6476         if (!get_selection_extents ( start, end))
6477                 return;
6478
6479         set_punch_range (start, end, _("set punch range from region"));
6480 }
6481
6482 void
6483 Editor::pitch_shift_region ()
6484 {
6485         RegionSelection rs = get_regions_from_selection_and_entered ();
6486
6487         RegionSelection audio_rs;
6488         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6489                 if (dynamic_cast<AudioRegionView*> (*i)) {
6490                         audio_rs.push_back (*i);
6491                 }
6492         }
6493
6494         if (audio_rs.empty()) {
6495                 return;
6496         }
6497
6498         pitch_shift (audio_rs, 1.2);
6499 }
6500
6501 void
6502 Editor::transpose_region ()
6503 {
6504         RegionSelection rs = get_regions_from_selection_and_entered ();
6505
6506         list<MidiRegionView*> midi_region_views;
6507         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6508                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
6509                 if (mrv) {
6510                         midi_region_views.push_back (mrv);
6511                 }
6512         }
6513
6514         TransposeDialog d;
6515         int const r = d.run ();
6516         if (r != RESPONSE_ACCEPT) {
6517                 return;
6518         }
6519
6520         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
6521                 (*i)->midi_region()->transpose (d.semitones ());
6522         }
6523 }
6524
6525 void
6526 Editor::set_tempo_from_region ()
6527 {
6528         RegionSelection rs = get_regions_from_selection_and_entered ();
6529
6530         if (!_session || rs.empty()) {
6531                 return;
6532         }
6533
6534         RegionView* rv = rs.front();
6535
6536         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
6537 }
6538
6539 void
6540 Editor::use_range_as_bar ()
6541 {
6542         framepos_t start, end;
6543         if (get_edit_op_range (start, end)) {
6544                 define_one_bar (start, end);
6545         }
6546 }
6547
6548 void
6549 Editor::define_one_bar (framepos_t start, framepos_t end)
6550 {
6551         framepos_t length = end - start;
6552
6553         const Meter& m (_session->tempo_map().meter_at (start));
6554
6555         /* length = 1 bar */
6556
6557         /* now we want frames per beat.
6558            we have frames per bar, and beats per bar, so ...
6559         */
6560
6561         /* XXXX METER MATH */
6562
6563         double frames_per_beat = length / m.divisions_per_bar();
6564
6565         /* beats per minute = */
6566
6567         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
6568
6569         /* now decide whether to:
6570
6571             (a) set global tempo
6572             (b) add a new tempo marker
6573
6574         */
6575
6576         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
6577
6578         bool do_global = false;
6579
6580         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
6581
6582                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
6583                    at the start, or create a new marker
6584                 */
6585
6586                 vector<string> options;
6587                 options.push_back (_("Cancel"));
6588                 options.push_back (_("Add new marker"));
6589                 options.push_back (_("Set global tempo"));
6590
6591                 Choice c (
6592                         _("Define one bar"),
6593                         _("Do you want to set the global tempo or add a new tempo marker?"),
6594                         options
6595                         );
6596
6597                 c.set_default_response (2);
6598
6599                 switch (c.run()) {
6600                 case 0:
6601                         return;
6602
6603                 case 2:
6604                         do_global = true;
6605                         break;
6606
6607                 default:
6608                         do_global = false;
6609                 }
6610
6611         } else {
6612
6613                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6614                    if the marker is at the region starter, change it, otherwise add
6615                    a new tempo marker
6616                 */
6617         }
6618
6619         begin_reversible_command (_("set tempo from region"));
6620         XMLNode& before (_session->tempo_map().get_state());
6621
6622         if (do_global) {
6623                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6624         } else if (t.frame() == start) {
6625                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6626         } else {
6627                 Timecode::BBT_Time bbt;
6628                 _session->tempo_map().bbt_time (start, bbt);
6629                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6630         }
6631
6632         XMLNode& after (_session->tempo_map().get_state());
6633
6634         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6635         commit_reversible_command ();
6636 }
6637
6638 void
6639 Editor::split_region_at_transients ()
6640 {
6641         AnalysisFeatureList positions;
6642
6643         RegionSelection rs = get_regions_from_selection_and_entered ();
6644
6645         if (!_session || rs.empty()) {
6646                 return;
6647         }
6648
6649         begin_reversible_command (_("split regions"));
6650         
6651         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6652
6653                 RegionSelection::iterator tmp;
6654
6655                 tmp = i;
6656                 ++tmp;
6657
6658                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6659
6660                 if (ar && (ar->get_transients (positions) == 0)) {
6661                         split_region_at_points ((*i)->region(), positions, true);
6662                         positions.clear ();
6663                 }
6664
6665                 i = tmp;
6666         }
6667         
6668         commit_reversible_command ();
6669
6670 }
6671
6672 void
6673 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6674 {
6675         bool use_rhythmic_rodent = false;
6676
6677         boost::shared_ptr<Playlist> pl = r->playlist();
6678
6679         list<boost::shared_ptr<Region> > new_regions;
6680
6681         if (!pl) {
6682                 return;
6683         }
6684
6685         if (positions.empty()) {
6686                 return;
6687         }
6688
6689
6690         if (positions.size() > 20 && can_ferret) {
6691                 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);
6692                 MessageDialog msg (msgstr,
6693                                    false,
6694                                    Gtk::MESSAGE_INFO,
6695                                    Gtk::BUTTONS_OK_CANCEL);
6696
6697                 if (can_ferret) {
6698                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6699                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6700                 } else {
6701                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6702                 }
6703
6704                 msg.set_title (_("Excessive split?"));
6705                 msg.present ();
6706
6707                 int response = msg.run();
6708                 msg.hide ();
6709
6710                 switch (response) {
6711                 case RESPONSE_OK:
6712                         break;
6713                 case RESPONSE_APPLY:
6714                         use_rhythmic_rodent = true;
6715                         break;
6716                 default:
6717                         return;
6718                 }
6719         }
6720
6721         if (use_rhythmic_rodent) {
6722                 show_rhythm_ferret ();
6723                 return;
6724         }
6725
6726         AnalysisFeatureList::const_iterator x;
6727
6728         pl->clear_changes ();
6729         pl->clear_owned_changes ();
6730
6731         x = positions.begin();
6732
6733         if (x == positions.end()) {
6734                 return;
6735         }
6736
6737         pl->freeze ();
6738         pl->remove_region (r);
6739
6740         framepos_t pos = 0;
6741
6742         while (x != positions.end()) {
6743
6744                 /* deal with positons that are out of scope of present region bounds */
6745                 if (*x <= 0 || *x > r->length()) {
6746                         ++x;
6747                         continue;
6748                 }
6749
6750                 /* file start = original start + how far we from the initial position ?
6751                  */
6752
6753                 framepos_t file_start = r->start() + pos;
6754
6755                 /* length = next position - current position
6756                  */
6757
6758                 framepos_t len = (*x) - pos;
6759
6760                 /* XXX we do we really want to allow even single-sample regions?
6761                    shouldn't we have some kind of lower limit on region size?
6762                 */
6763
6764                 if (len <= 0) {
6765                         break;
6766                 }
6767
6768                 string new_name;
6769
6770                 if (RegionFactory::region_name (new_name, r->name())) {
6771                         break;
6772                 }
6773
6774                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6775
6776                 PropertyList plist;
6777
6778                 plist.add (ARDOUR::Properties::start, file_start);
6779                 plist.add (ARDOUR::Properties::length, len);
6780                 plist.add (ARDOUR::Properties::name, new_name);
6781                 plist.add (ARDOUR::Properties::layer, 0);
6782
6783                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6784                 /* because we set annouce to false, manually add the new region to the
6785                    RegionFactory map
6786                 */
6787                 RegionFactory::map_add (nr);
6788
6789                 pl->add_region (nr, r->position() + pos);
6790
6791                 if (select_new) {
6792                         new_regions.push_front(nr);
6793                 }
6794
6795                 pos += len;
6796                 ++x;
6797         }
6798
6799         string new_name;
6800
6801         RegionFactory::region_name (new_name, r->name());
6802
6803         /* Add the final region */
6804         PropertyList plist;
6805
6806         plist.add (ARDOUR::Properties::start, r->start() + pos);
6807         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6808         plist.add (ARDOUR::Properties::name, new_name);
6809         plist.add (ARDOUR::Properties::layer, 0);
6810
6811         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6812         /* because we set annouce to false, manually add the new region to the
6813            RegionFactory map
6814         */
6815         RegionFactory::map_add (nr);
6816         pl->add_region (nr, r->position() + pos);
6817
6818         if (select_new) {
6819                 new_regions.push_front(nr);
6820         }
6821
6822         pl->thaw ();
6823
6824         /* We might have removed regions, which alters other regions' layering_index,
6825            so we need to do a recursive diff here.
6826         */
6827         vector<Command*> cmds;
6828         pl->rdiff (cmds);
6829         _session->add_commands (cmds);
6830         
6831         _session->add_command (new StatefulDiffCommand (pl));
6832
6833         if (select_new) {
6834
6835                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6836                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6837                 }
6838         }
6839 }
6840
6841 void
6842 Editor::place_transient()
6843 {
6844         if (!_session) {
6845                 return;
6846         }
6847
6848         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6849
6850         if (rs.empty()) {
6851                 return;
6852         }
6853
6854         framepos_t where = get_preferred_edit_position();
6855
6856         begin_reversible_command (_("place transient"));
6857         
6858         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6859                 framepos_t position = (*r)->region()->position();
6860                 (*r)->region()->add_transient(where - position);
6861         }
6862         
6863         commit_reversible_command ();
6864 }
6865
6866 void
6867 Editor::remove_transient(ArdourCanvas::Item* item)
6868 {
6869         if (!_session) {
6870                 return;
6871         }
6872
6873         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6874         assert (_line);
6875
6876         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6877         _arv->remove_transient (*(float*) _line->get_data ("position"));
6878 }
6879
6880 void
6881 Editor::snap_regions_to_grid ()
6882 {
6883         list <boost::shared_ptr<Playlist > > used_playlists;
6884
6885         RegionSelection rs = get_regions_from_selection_and_entered ();
6886
6887         if (!_session || rs.empty()) {
6888                 return;
6889         }
6890
6891         begin_reversible_command (_("snap regions to grid"));
6892         
6893         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6894
6895                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6896
6897                 if (!pl->frozen()) {
6898                         /* we haven't seen this playlist before */
6899
6900                         /* remember used playlists so we can thaw them later */
6901                         used_playlists.push_back(pl);
6902                         pl->freeze();
6903                 }
6904
6905                 framepos_t start_frame = (*r)->region()->first_frame ();
6906                 snap_to (start_frame);
6907                 (*r)->region()->set_position (start_frame);
6908         }
6909
6910         while (used_playlists.size() > 0) {
6911                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6912                 (*i)->thaw();
6913                 used_playlists.pop_front();
6914         }
6915         
6916         commit_reversible_command ();
6917 }
6918
6919 void
6920 Editor::close_region_gaps ()
6921 {
6922         list <boost::shared_ptr<Playlist > > used_playlists;
6923
6924         RegionSelection rs = get_regions_from_selection_and_entered ();
6925
6926         if (!_session || rs.empty()) {
6927                 return;
6928         }
6929
6930         Dialog dialog (_("Close Region Gaps"));
6931
6932         Table table (2, 3);
6933         table.set_spacings (12);
6934         table.set_border_width (12);
6935         Label* l = manage (left_aligned_label (_("Crossfade length")));
6936         table.attach (*l, 0, 1, 0, 1);
6937
6938         SpinButton spin_crossfade (1, 0);
6939         spin_crossfade.set_range (0, 15);
6940         spin_crossfade.set_increments (1, 1);
6941         spin_crossfade.set_value (5);
6942         table.attach (spin_crossfade, 1, 2, 0, 1);
6943
6944         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6945
6946         l = manage (left_aligned_label (_("Pull-back length")));
6947         table.attach (*l, 0, 1, 1, 2);
6948
6949         SpinButton spin_pullback (1, 0);
6950         spin_pullback.set_range (0, 100);
6951         spin_pullback.set_increments (1, 1);
6952         spin_pullback.set_value(30);
6953         table.attach (spin_pullback, 1, 2, 1, 2);
6954
6955         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6956
6957         dialog.get_vbox()->pack_start (table);
6958         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6959         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6960         dialog.show_all ();
6961
6962         if (dialog.run () == RESPONSE_CANCEL) {
6963                 return;
6964         }
6965
6966         framepos_t crossfade_len = spin_crossfade.get_value();
6967         framepos_t pull_back_frames = spin_pullback.get_value();
6968
6969         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6970         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6971
6972         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6973
6974         begin_reversible_command (_("close region gaps"));
6975         
6976         int idx = 0;
6977         boost::shared_ptr<Region> last_region;
6978
6979         rs.sort_by_position_and_track();
6980
6981         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6982
6983                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6984
6985                 if (!pl->frozen()) {
6986                         /* we haven't seen this playlist before */
6987
6988                         /* remember used playlists so we can thaw them later */
6989                         used_playlists.push_back(pl);
6990                         pl->freeze();
6991                 }
6992
6993                 framepos_t position = (*r)->region()->position();
6994
6995                 if (idx == 0 || position < last_region->position()){
6996                         last_region = (*r)->region();
6997                         idx++;
6998                         continue;
6999                 }
7000
7001                 (*r)->region()->trim_front( (position - pull_back_frames));
7002                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
7003
7004                 last_region = (*r)->region();
7005
7006                 idx++;
7007         }
7008
7009         while (used_playlists.size() > 0) {
7010                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
7011                 (*i)->thaw();
7012                 used_playlists.pop_front();
7013         }
7014         
7015         commit_reversible_command ();
7016 }
7017
7018 void
7019 Editor::tab_to_transient (bool forward)
7020 {
7021         AnalysisFeatureList positions;
7022
7023         RegionSelection rs = get_regions_from_selection_and_entered ();
7024
7025         if (!_session) {
7026                 return;
7027         }
7028
7029         framepos_t pos = _session->audible_frame ();
7030
7031         if (!selection->tracks.empty()) {
7032
7033                 /* don't waste time searching for transients in duplicate playlists.
7034                  */
7035
7036                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7037
7038                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
7039
7040                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
7041
7042                         if (rtv) {
7043                                 boost::shared_ptr<Track> tr = rtv->track();
7044                                 if (tr) {
7045                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
7046                                         if (pl) {
7047                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
7048
7049                                                 if (result >= 0) {
7050                                                         positions.push_back (result);
7051                                                 }
7052                                         }
7053                                 }
7054                         }
7055                 }
7056
7057         } else {
7058
7059                 if (rs.empty()) {
7060                         return;
7061                 }
7062
7063                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
7064                         (*r)->region()->get_transients (positions);
7065                 }
7066         }
7067
7068         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
7069
7070         if (forward) {
7071                 AnalysisFeatureList::iterator x;
7072
7073                 for (x = positions.begin(); x != positions.end(); ++x) {
7074                         if ((*x) > pos) {
7075                                 break;
7076                         }
7077                 }
7078
7079                 if (x != positions.end ()) {
7080                         _session->request_locate (*x);
7081                 }
7082
7083         } else {
7084                 AnalysisFeatureList::reverse_iterator x;
7085
7086                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
7087                         if ((*x) < pos) {
7088                                 break;
7089                         }
7090                 }
7091
7092                 if (x != positions.rend ()) {
7093                         _session->request_locate (*x);
7094                 }
7095         }
7096 }
7097
7098 void
7099 Editor::playhead_forward_to_grid ()
7100 {
7101         if (!_session) {
7102                 return;
7103         }
7104         
7105         framepos_t pos = playhead_cursor->current_frame ();
7106         if (pos < max_framepos - 1) {
7107                 pos += 2;
7108                 snap_to_internal (pos, RoundUpAlways, false);
7109                 _session->request_locate (pos);
7110         }
7111 }
7112
7113
7114 void
7115 Editor::playhead_backward_to_grid ()
7116 {
7117         if (!_session) {
7118                 return;
7119         }
7120         
7121         framepos_t pos = playhead_cursor->current_frame ();
7122         if (pos > 2) {
7123                 pos -= 2;
7124                 snap_to_internal (pos, RoundDownAlways, false);
7125                 _session->request_locate (pos);
7126         }
7127 }
7128
7129 void
7130 Editor::set_track_height (Height h)
7131 {
7132         TrackSelection& ts (selection->tracks);
7133
7134         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7135                 (*x)->set_height_enum (h);
7136         }
7137 }
7138
7139 void
7140 Editor::toggle_tracks_active ()
7141 {
7142         TrackSelection& ts (selection->tracks);
7143         bool first = true;
7144         bool target = false;
7145
7146         if (ts.empty()) {
7147                 return;
7148         }
7149
7150         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7151                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
7152
7153                 if (rtv) {
7154                         if (first) {
7155                                 target = !rtv->_route->active();
7156                                 first = false;
7157                         }
7158                         rtv->_route->set_active (target, this);
7159                 }
7160         }
7161 }
7162
7163 void
7164 Editor::remove_tracks ()
7165 {
7166         /* this will delete GUI objects that may be the subject of an event
7167            handler in which this method is called. Defer actual deletion to the
7168            next idle callback, when all event handling is finished.
7169         */
7170         Glib::signal_idle().connect (sigc::mem_fun (*this, &Editor::idle_remove_tracks));
7171 }
7172
7173 bool
7174 Editor::idle_remove_tracks ()
7175 {
7176         _remove_tracks ();
7177         return false; /* do not call again */
7178 }
7179
7180 void
7181 Editor::_remove_tracks ()
7182 {
7183         TrackSelection& ts (selection->tracks);
7184
7185         if (ts.empty()) {
7186                 return;
7187         }
7188
7189         vector<string> choices;
7190         string prompt;
7191         int ntracks = 0;
7192         int nbusses = 0;
7193         const char* trackstr;
7194         const char* busstr;
7195         vector<boost::shared_ptr<Route> > routes;
7196         bool special_bus = false;
7197
7198         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
7199                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
7200                 if (!rtv) {
7201                         continue;
7202                 }
7203                 if (rtv->is_track()) {
7204                         ntracks++;
7205                 } else {
7206                         nbusses++;
7207                 }
7208                 routes.push_back (rtv->_route);
7209
7210                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
7211                         special_bus = true;
7212                 }
7213         }
7214
7215         if (special_bus && !Config->get_allow_special_bus_removal()) {
7216                 MessageDialog msg (_("That would be bad news ...."),
7217                                    false,
7218                                    Gtk::MESSAGE_INFO,
7219                                    Gtk::BUTTONS_OK);
7220                 msg.set_secondary_text (string_compose (_(
7221                                                                 "Removing the master or monitor bus is such a bad idea\n\
7222 that %1 is not going to allow it.\n\
7223 \n\
7224 If you really want to do this sort of thing\n\
7225 edit your ardour.rc file to set the\n\
7226 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
7227
7228                 msg.present ();
7229                 msg.run ();
7230                 return;
7231         }
7232
7233         if (ntracks + nbusses == 0) {
7234                 return;
7235         }
7236
7237         trackstr = P_("track", "tracks", ntracks);
7238         busstr = P_("bus", "busses", nbusses);
7239         
7240         if (ntracks) {
7241                 if (nbusses) {
7242                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
7243                                                     "(You may also lose the playlists associated with the %2)\n\n"
7244                                                     "This action cannot be undone, and the session file will be overwritten!"),
7245                                                   ntracks, trackstr, nbusses, busstr);
7246                 } else {
7247                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
7248                                                     "(You may also lose the playlists associated with the %2)\n\n"
7249                                                     "This action cannot be undone, and the session file will be overwritten!"),
7250                                                   ntracks, trackstr);
7251                 }
7252         } else if (nbusses) {
7253                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
7254                                             "This action cannot be undone, and the session file will be overwritten"),
7255                                           nbusses, busstr);
7256         }
7257
7258         choices.push_back (_("No, do nothing."));
7259         if (ntracks + nbusses > 1) {
7260                 choices.push_back (_("Yes, remove them."));
7261         } else {
7262                 choices.push_back (_("Yes, remove it."));
7263         }
7264
7265         string title;
7266         if (ntracks) {
7267                 title = string_compose (_("Remove %1"), trackstr);
7268         } else {
7269                 title = string_compose (_("Remove %1"), busstr);
7270         }
7271
7272         Choice prompter (title, prompt, choices);
7273
7274         if (prompter.run () != 1) {
7275                 return;
7276         }
7277
7278         {
7279                 Session::StateProtector sp (_session);
7280                 DisplaySuspender ds;
7281                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
7282                         _session->remove_route (*x);
7283                 }
7284         }
7285 }
7286
7287 void
7288 Editor::do_insert_time ()
7289 {
7290         if (selection->tracks.empty()) {
7291                 return;
7292         }
7293
7294         InsertRemoveTimeDialog d (*this);
7295         int response = d.run ();
7296
7297         if (response != RESPONSE_OK) {
7298                 return;
7299         }
7300
7301         if (d.distance() == 0) {
7302                 return;
7303         }
7304
7305         InsertTimeOption opt = d.intersected_region_action ();
7306
7307         insert_time (
7308                 get_preferred_edit_position(),
7309                 d.distance(),
7310                 opt,
7311                 d.all_playlists(),
7312                 d.move_glued(),
7313                 d.move_markers(),
7314                 d.move_glued_markers(),
7315                 d.move_locked_markers(),
7316                 d.move_tempos()
7317                 );
7318 }
7319
7320 void
7321 Editor::insert_time (
7322         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
7323         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
7324         )
7325 {
7326
7327         if (Config->get_edit_mode() == Lock) {
7328                 return;
7329         }
7330         bool in_command = false;
7331
7332         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
7333
7334         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
7335
7336                 /* regions */
7337
7338                 /* don't operate on any playlist more than once, which could
7339                  * happen if "all playlists" is enabled, but there is more
7340                  * than 1 track using playlists "from" a given track.
7341                  */
7342
7343                 set<boost::shared_ptr<Playlist> > pl;
7344
7345                 if (all_playlists) {
7346                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7347                         if (rtav && rtav->track ()) {
7348                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
7349                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
7350                                         pl.insert (*p);
7351                                 }
7352                         }
7353                 } else {
7354                         if ((*x)->playlist ()) {
7355                                 pl.insert ((*x)->playlist ());
7356                         }
7357                 }
7358                 
7359                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
7360
7361                         (*i)->clear_changes ();
7362                         (*i)->clear_owned_changes ();
7363
7364                         if (opt == SplitIntersected) {
7365                                 (*i)->split (pos);
7366                         }
7367
7368                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
7369
7370                         if (!in_command) {
7371                                 begin_reversible_command (_("insert time"));
7372                                 in_command = true;
7373                         }
7374                         vector<Command*> cmds;
7375                         (*i)->rdiff (cmds);
7376                         _session->add_commands (cmds);
7377
7378                         _session->add_command (new StatefulDiffCommand (*i));
7379                 }
7380
7381                 /* automation */
7382                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7383                 if (rtav) {
7384                         if (!in_command) {
7385                                 begin_reversible_command (_("insert time"));
7386                                 in_command = true;
7387                         }
7388                         rtav->route ()->shift (pos, frames);
7389                 }
7390         }
7391
7392         /* markers */
7393         if (markers_too) {
7394                 bool moved = false;
7395                 XMLNode& before (_session->locations()->get_state());
7396                 Locations::LocationList copy (_session->locations()->list());
7397
7398                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7399
7400                         Locations::LocationList::const_iterator tmp;
7401
7402                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7403                                 bool const was_locked = (*i)->locked ();
7404                                 if (locked_markers_too) {
7405                                         (*i)->unlock ();
7406                                 }
7407
7408                                 if ((*i)->start() >= pos) {
7409                                         // move end first, in case we're moving by more than the length of the range
7410                                         if (!(*i)->is_mark()) {
7411                                                 (*i)->set_end ((*i)->end() + frames);
7412                                         }
7413                                         (*i)->set_start ((*i)->start() + frames);
7414                                         moved = true;
7415                                 }
7416
7417                                 if (was_locked) {
7418                                         (*i)->lock ();
7419                                 }
7420                         }
7421                 }
7422
7423                 if (moved) {
7424                         if (!in_command) {
7425                                 begin_reversible_command (_("insert time"));
7426                                 in_command = true;
7427                         }
7428                         XMLNode& after (_session->locations()->get_state());
7429                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7430                 }
7431         }
7432
7433         if (tempo_too) {
7434                 if (!in_command) {
7435                         begin_reversible_command (_("insert time"));
7436                         in_command = true;
7437                 }
7438                 XMLNode& before (_session->tempo_map().get_state());
7439                 _session->tempo_map().insert_time (pos, frames);
7440                 XMLNode& after (_session->tempo_map().get_state());
7441                 _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7442         }
7443
7444         if (in_command) {
7445                 commit_reversible_command ();
7446         }
7447 }
7448
7449 void
7450 Editor::do_remove_time ()
7451 {
7452         if (selection->tracks.empty()) {
7453                 return;
7454         }
7455
7456         framepos_t pos = get_preferred_edit_position (EDIT_IGNORE_MOUSE);
7457         InsertRemoveTimeDialog d (*this, true);
7458
7459         int response = d.run ();
7460
7461         if (response != RESPONSE_OK) {
7462                 return;
7463         }
7464         
7465         framecnt_t distance = d.distance();
7466
7467         if (distance == 0) {
7468                 return;
7469         }
7470
7471         remove_time (
7472                 pos,
7473                 distance,
7474                 SplitIntersected,
7475                 d.move_glued(),
7476                 d.move_markers(),
7477                 d.move_glued_markers(),
7478                 d.move_locked_markers(),
7479                 d.move_tempos()
7480         );
7481 }
7482
7483 void
7484 Editor::remove_time (framepos_t pos, framecnt_t frames, InsertTimeOption opt, 
7485                      bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too)
7486 {
7487         if (Config->get_edit_mode() == Lock) {
7488                 error << (_("Cannot insert or delete time when in Lock edit.")) << endmsg;
7489                 return;
7490         }
7491         bool in_command = false;
7492
7493         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
7494                 /* regions */
7495                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
7496                 
7497                 if (pl) {
7498
7499                         XMLNode &before = pl->get_state();
7500                         
7501                         std::list<AudioRange> rl;
7502                         AudioRange ar(pos, pos+frames, 0);
7503                         rl.push_back(ar);
7504                         pl->cut (rl);
7505                         pl->shift (pos, -frames, true, ignore_music_glue);
7506                         
7507                         if (!in_command) {
7508                                 begin_reversible_command (_("cut time"));
7509                                 in_command = true;
7510                         }
7511                         XMLNode &after = pl->get_state();
7512                         
7513                         _session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
7514                 }
7515                         
7516                 /* automation */
7517                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
7518                 if (rtav) {
7519                         if (!in_command) {
7520                                 begin_reversible_command (_("cut time"));
7521                                 in_command = true;
7522                         }
7523                         rtav->route ()->shift (pos, -frames);
7524                 }
7525         }
7526
7527         std::list<Location*> loc_kill_list;
7528         
7529         /* markers */
7530         if (markers_too) {
7531                 bool moved = false;
7532                 XMLNode& before (_session->locations()->get_state());
7533                 Locations::LocationList copy (_session->locations()->list());
7534
7535                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
7536                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
7537
7538                                 bool const was_locked = (*i)->locked ();
7539                                 if (locked_markers_too) {
7540                                         (*i)->unlock ();
7541                                 }
7542
7543                                 if (!(*i)->is_mark()) {  // it's a range;  have to handle both start and end
7544                                         if ((*i)->end() >= pos
7545                                         && (*i)->end() < pos+frames
7546                                         && (*i)->start() >= pos
7547                                         && (*i)->end() < pos+frames) {  // range is completely enclosed;  kill it
7548                                                 moved = true;
7549                                                 loc_kill_list.push_back(*i);
7550                                         } else {  // only start or end is included, try to do the right thing
7551                                                 // move start before moving end, to avoid trying to move the end to before the start
7552                                                 // if we're removing more time than the length of the range
7553                                                 if ((*i)->start() >= pos && (*i)->start() < pos+frames) {
7554                                                         // start is within cut
7555                                                         (*i)->set_start (pos);  // bring the start marker to the beginning of the cut
7556                                                         moved = true;
7557                                                 } else if ((*i)->start() >= pos+frames) {
7558                                                         // start (and thus entire range) lies beyond end of cut
7559                                                         (*i)->set_start ((*i)->start() - frames); // slip the start marker back
7560                                                         moved = true;
7561                                                 }
7562                                                 if ((*i)->end() >= pos && (*i)->end() < pos+frames) {
7563                                                         // end is inside cut
7564                                                         (*i)->set_end (pos);  // bring the end to the cut
7565                                                         moved = true;
7566                                                 } else if ((*i)->end() >= pos+frames) {
7567                                                         // end is beyond end of cut
7568                                                         (*i)->set_end ((*i)->end() - frames); // slip the end marker back
7569                                                         moved = true;
7570                                                 }
7571
7572                                         }
7573                                 } else if ((*i)->start() >= pos && (*i)->start() < pos+frames ) {
7574                                         loc_kill_list.push_back(*i);
7575                                         moved = true;
7576                                 } else if ((*i)->start() >= pos) {
7577                                         (*i)->set_start ((*i)->start() -frames);
7578                                         moved = true;
7579                                 }
7580
7581                                 if (was_locked) {
7582                                         (*i)->lock ();
7583                                 }
7584                         }
7585                 }
7586
7587                 for (list<Location*>::iterator i = loc_kill_list.begin(); i != loc_kill_list.end(); ++i) {
7588                         _session->locations()->remove( *i );
7589                 }
7590         
7591                 if (moved) {
7592                         if (!in_command) {
7593                                 begin_reversible_command (_("cut time"));
7594                                 in_command = true;
7595                         }
7596                         XMLNode& after (_session->locations()->get_state());
7597                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
7598                 }
7599         }
7600         
7601         if (tempo_too) {
7602                 XMLNode& before (_session->tempo_map().get_state());
7603
7604                 if (_session->tempo_map().remove_time (pos, frames) ) {
7605                         if (!in_command) {
7606                                 begin_reversible_command (_("remove time"));
7607                                 in_command = true;
7608                         }
7609                         XMLNode& after (_session->tempo_map().get_state());
7610                         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
7611                 }
7612         }
7613         
7614         if (in_command) {
7615                 commit_reversible_command ();
7616         }
7617 }
7618
7619 void
7620 Editor::fit_selection ()
7621 {
7622         if (!selection->tracks.empty()) {
7623                 fit_tracks (selection->tracks);
7624         } else {
7625                 TrackViewList tvl;
7626
7627                 /* no selected tracks - use tracks with selected regions */
7628
7629                 if (!selection->regions.empty()) {
7630                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
7631                                 tvl.push_back (&(*r)->get_time_axis_view ());
7632                         }
7633
7634                         if (!tvl.empty()) {
7635                                 fit_tracks (tvl);
7636                         }
7637                 } else if (internal_editing()) {
7638                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
7639                            the entered track
7640                         */
7641                         if (entered_track) {
7642                                 tvl.push_back (entered_track);
7643                                 fit_tracks (tvl);
7644                         }
7645                 }
7646         }
7647
7648 }
7649
7650 void
7651 Editor::fit_tracks (TrackViewList & tracks)
7652 {
7653         if (tracks.empty()) {
7654                 return;
7655         }
7656
7657         uint32_t child_heights = 0;
7658         int visible_tracks = 0;
7659
7660         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
7661
7662                 if (!(*t)->marked_for_display()) {
7663                         continue;
7664                 }
7665
7666                 child_heights += (*t)->effective_height() - (*t)->current_height();
7667                 ++visible_tracks;
7668         }
7669
7670         /* compute the per-track height from:
7671
7672            total canvas visible height - 
7673                  height that will be taken by visible children of selected
7674                  tracks - height of the ruler/hscroll area 
7675         */
7676         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
7677         double first_y_pos = DBL_MAX;
7678
7679         if (h < TimeAxisView::preset_height (HeightSmall)) {
7680                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
7681                 /* too small to be displayed */
7682                 return;
7683         }
7684
7685         undo_visual_stack.push_back (current_visual_state (true));
7686         PBD::Unwinder<bool> nsv (no_save_visual, true);
7687
7688         /* build a list of all tracks, including children */
7689
7690         TrackViewList all;
7691         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
7692                 all.push_back (*i);
7693                 TimeAxisView::Children c = (*i)->get_child_list ();
7694                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
7695                         all.push_back (j->get());
7696                 }
7697         }
7698
7699
7700         // find selection range.
7701         // if someone knows how to user TrackViewList::iterator for this
7702         // I'm all ears.
7703         int selected_top = -1;
7704         int selected_bottom = -1;
7705         int i = 0;
7706         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7707                 if ((*t)->marked_for_display ()) {
7708                         if (tracks.contains(*t)) {
7709                                 if (selected_top == -1) {
7710                                         selected_top = i;
7711                                 }
7712                                 selected_bottom = i;
7713                         }
7714                 }
7715         }
7716
7717         i = 0;
7718         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t, ++i) {
7719                 if ((*t)->marked_for_display ()) {
7720                         if (tracks.contains(*t)) {
7721                                 (*t)->set_height (h);
7722                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
7723                         } else {
7724                                 if (i > selected_top && i < selected_bottom) {
7725                                         hide_track_in_display (*t);
7726                                 }
7727                         }
7728                 }
7729         }
7730
7731         /*
7732            set the controls_layout height now, because waiting for its size
7733            request signal handler will cause the vertical adjustment setting to fail
7734         */
7735
7736         controls_layout.property_height () = _full_canvas_height;
7737         vertical_adjustment.set_value (first_y_pos);
7738
7739         redo_visual_stack.push_back (current_visual_state (true));
7740
7741         visible_tracks_selector.set_text (_("Sel"));
7742 }
7743
7744 void
7745 Editor::save_visual_state (uint32_t n)
7746 {
7747         while (visual_states.size() <= n) {
7748                 visual_states.push_back (0);
7749         }
7750
7751         if (visual_states[n] != 0) {
7752                 delete visual_states[n];
7753         }
7754
7755         visual_states[n] = current_visual_state (true);
7756         gdk_beep ();
7757 }
7758
7759 void
7760 Editor::goto_visual_state (uint32_t n)
7761 {
7762         if (visual_states.size() <= n) {
7763                 return;
7764         }
7765
7766         if (visual_states[n] == 0) {
7767                 return;
7768         }
7769
7770         use_visual_state (*visual_states[n]);
7771 }
7772
7773 void
7774 Editor::start_visual_state_op (uint32_t n)
7775 {
7776         save_visual_state (n);
7777         
7778         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
7779         char buf[32];
7780         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
7781         pup->set_text (buf);
7782         pup->touch();
7783 }
7784
7785 void
7786 Editor::cancel_visual_state_op (uint32_t n)
7787 {
7788         goto_visual_state (n);
7789 }
7790
7791 void
7792 Editor::toggle_region_mute ()
7793 {
7794         if (_ignore_region_action) {
7795                 return;
7796         }
7797
7798         RegionSelection rs = get_regions_from_selection_and_entered ();
7799
7800         if (rs.empty ()) {
7801                 return;
7802         }
7803
7804         if (rs.size() > 1) {
7805                 begin_reversible_command (_("mute regions"));
7806         } else {
7807                 begin_reversible_command (_("mute region"));
7808         }
7809
7810         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7811
7812                 (*i)->region()->playlist()->clear_changes ();
7813                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7814                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
7815
7816         }
7817
7818         commit_reversible_command ();
7819 }
7820
7821 void
7822 Editor::combine_regions ()
7823 {
7824         /* foreach track with selected regions, take all selected regions
7825            and join them into a new region containing the subregions (as a
7826            playlist)
7827         */
7828
7829         typedef set<RouteTimeAxisView*> RTVS;
7830         RTVS tracks;
7831
7832         if (selection->regions.empty()) {
7833                 return;
7834         }
7835
7836         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7837                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7838
7839                 if (rtv) {
7840                         tracks.insert (rtv);
7841                 }
7842         }
7843
7844         begin_reversible_command (_("combine regions"));
7845
7846         vector<RegionView*> new_selection;
7847
7848         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7849                 RegionView* rv;
7850
7851                 if ((rv = (*i)->combine_regions ()) != 0) {
7852                         new_selection.push_back (rv);
7853                 }
7854         }
7855
7856         selection->clear_regions ();
7857         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7858                 selection->add (*i);
7859         }
7860
7861         commit_reversible_command ();
7862 }
7863
7864 void
7865 Editor::uncombine_regions ()
7866 {
7867         typedef set<RouteTimeAxisView*> RTVS;
7868         RTVS tracks;
7869
7870         if (selection->regions.empty()) {
7871                 return;
7872         }
7873
7874         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7875                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7876
7877                 if (rtv) {
7878                         tracks.insert (rtv);
7879                 }
7880         }
7881
7882         begin_reversible_command (_("uncombine regions"));
7883
7884         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7885                 (*i)->uncombine_regions ();
7886         }
7887
7888         commit_reversible_command ();
7889 }
7890
7891 void
7892 Editor::toggle_midi_input_active (bool flip_others)
7893 {
7894         bool onoff = false;
7895         boost::shared_ptr<RouteList> rl (new RouteList);
7896
7897         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7898                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7899
7900                 if (!rtav) {
7901                         continue;
7902                 }
7903
7904                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7905
7906                 if (mt) {
7907                         rl->push_back (rtav->route());
7908                         onoff = !mt->input_active();
7909                 }
7910         }
7911         
7912         _session->set_exclusive_input_active (rl, onoff, flip_others);
7913 }
7914
7915 void
7916 Editor::lock ()
7917 {
7918         if (!lock_dialog) {
7919                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7920
7921                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7922                 lock_dialog->get_vbox()->pack_start (*padlock);
7923
7924                 ArdourButton* b = manage (new ArdourButton);
7925                 b->set_name ("lock button");
7926                 b->set_text (_("Click to unlock"));
7927                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7928                 lock_dialog->get_vbox()->pack_start (*b);
7929                 
7930                 lock_dialog->get_vbox()->show_all ();
7931                 lock_dialog->set_size_request (200, 200);
7932         }
7933
7934         delete _main_menu_disabler;
7935         _main_menu_disabler = new MainMenuDisabler;
7936         
7937         lock_dialog->present ();
7938 }
7939
7940 void
7941 Editor::unlock ()
7942 {
7943         lock_dialog->hide ();
7944         
7945         delete _main_menu_disabler;
7946
7947         if (UIConfiguration::instance().get_lock_gui_after_seconds()) {
7948                 start_lock_event_timing ();
7949         }
7950 }
7951
7952 void
7953 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7954 {
7955         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7956 }
7957
7958 void
7959 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7960 {
7961         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7962         Gtkmm2ext::UI::instance()->flush_pending ();
7963 }
7964
7965 void
7966 Editor::bring_all_sources_into_session ()
7967 {
7968         if (!_session) {
7969                 return;
7970         }
7971
7972         Gtk::Label msg;
7973         ArdourDialog w (_("Moving embedded files into session folder"));
7974         w.get_vbox()->pack_start (msg);
7975         w.present ();
7976         
7977         /* flush all pending GUI events because we're about to start copying
7978          * files
7979          */
7980         
7981         Gtkmm2ext::UI::instance()->flush_pending ();
7982
7983         cerr << " Do it\n";
7984
7985         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7986 }