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