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