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