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