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