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