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