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