Allow deletion of processors in editor_mixer_strip by pointing and pressing Delete
[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 ((start == 0 && end == 0) || end < start) {
1771                         return;
1772                 }
1773
1774                 calc_extra_zoom_edges(start, end);
1775
1776                 temporal_zoom_by_frame (start, end);
1777         }
1778 }
1779
1780 void
1781 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1782 {
1783         if (!_session) return;
1784
1785         if ((start == 0 && end == 0) || end < start) {
1786                 return;
1787         }
1788
1789         framepos_t range = end - start;
1790
1791         double const new_fpp = (double) range / (double) _visible_canvas_width;
1792
1793         framepos_t new_page = (framepos_t) floor (_visible_canvas_width * new_fpp);
1794         framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1795         framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1796
1797         if (new_leftmost > middle) {
1798                 new_leftmost = 0;
1799         }
1800
1801         if (new_leftmost < 0) {
1802                 new_leftmost = 0;
1803         }
1804
1805         reposition_and_zoom (new_leftmost, new_fpp);
1806 }
1807
1808 void
1809 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1810 {
1811         if (!_session) {
1812                 return;
1813         }
1814
1815         framecnt_t range_before = frame - leftmost_frame;
1816         framecnt_t new_spp;
1817
1818         if (coarser) {
1819                 if (samples_per_pixel <= 1) {
1820                         new_spp = 2;
1821                 } else {
1822                         new_spp = samples_per_pixel + (samples_per_pixel/2);
1823                 }
1824                 range_before += range_before/2;
1825         } else {
1826                 if (samples_per_pixel >= 1) {
1827                         new_spp = samples_per_pixel - (samples_per_pixel/2);
1828                 } else {
1829                         /* could bail out here since we cannot zoom any finer,
1830                            but leave that to the equality test below
1831                         */
1832                         new_spp = samples_per_pixel;
1833                 }
1834
1835                 range_before -= range_before/2;
1836         }
1837
1838         if (new_spp == samples_per_pixel)  {
1839                 return;
1840         }
1841
1842         /* zoom focus is automatically taken as @param frame when this
1843            method is used.
1844         */
1845         
1846         framepos_t new_leftmost = frame - (framepos_t)range_before;
1847
1848         if (new_leftmost > frame) {
1849                 new_leftmost = 0;
1850         }
1851
1852         if (new_leftmost < 0) {
1853                 new_leftmost = 0;
1854         }
1855
1856         reposition_and_zoom (new_leftmost, new_spp);
1857 }
1858
1859
1860 bool
1861 Editor::choose_new_marker_name(string &name) {
1862
1863         if (!Config->get_name_new_markers()) {
1864                 /* don't prompt user for a new name */
1865                 return true;
1866         }
1867
1868         ArdourPrompter dialog (true);
1869
1870         dialog.set_prompt (_("New Name:"));
1871
1872         dialog.set_title (_("New Location Marker"));
1873
1874         dialog.set_name ("MarkNameWindow");
1875         dialog.set_size_request (250, -1);
1876         dialog.set_position (Gtk::WIN_POS_MOUSE);
1877
1878         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1879         dialog.set_initial_text (name);
1880
1881         dialog.show ();
1882
1883         switch (dialog.run ()) {
1884         case RESPONSE_ACCEPT:
1885                 break;
1886         default:
1887                 return false;
1888         }
1889
1890         dialog.get_result(name);
1891         return true;
1892
1893 }
1894
1895
1896 void
1897 Editor::add_location_from_selection ()
1898 {
1899         string rangename;
1900
1901         if (selection->time.empty()) {
1902                 return;
1903         }
1904
1905         if (_session == 0 || clicked_axisview == 0) {
1906                 return;
1907         }
1908
1909         framepos_t start = selection->time[clicked_selection].start;
1910         framepos_t end = selection->time[clicked_selection].end;
1911
1912         _session->locations()->next_available_name(rangename,"selection");
1913         Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1914
1915         _session->begin_reversible_command (_("add marker"));
1916         XMLNode &before = _session->locations()->get_state();
1917         _session->locations()->add (location, true);
1918         XMLNode &after = _session->locations()->get_state();
1919         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1920         _session->commit_reversible_command ();
1921 }
1922
1923 void
1924 Editor::add_location_mark (framepos_t where)
1925 {
1926         string markername;
1927
1928         select_new_marker = true;
1929
1930         _session->locations()->next_available_name(markername,"mark");
1931         if (!choose_new_marker_name(markername)) {
1932                 return;
1933         }
1934         Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1935         _session->begin_reversible_command (_("add marker"));
1936         XMLNode &before = _session->locations()->get_state();
1937         _session->locations()->add (location, true);
1938         XMLNode &after = _session->locations()->get_state();
1939         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1940         _session->commit_reversible_command ();
1941 }
1942
1943 void
1944 Editor::add_location_from_playhead_cursor ()
1945 {
1946         add_location_mark (_session->audible_frame());
1947 }
1948
1949 void
1950 Editor::remove_location_at_playhead_cursor ()
1951 {
1952         if (_session) {
1953
1954                 //set up for undo
1955                 _session->begin_reversible_command (_("remove marker"));
1956                 XMLNode &before = _session->locations()->get_state();
1957                 bool removed = false;
1958
1959                 //find location(s) at this time
1960                 Locations::LocationList locs;
1961                 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1962                 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1963                         if ((*i)->is_mark()) {
1964                                 _session->locations()->remove (*i);
1965                                 removed = true;
1966                         }
1967                 }
1968                 
1969                 //store undo
1970                 if (removed) {
1971                         XMLNode &after = _session->locations()->get_state();
1972                         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1973                         _session->commit_reversible_command ();
1974                 }
1975         }
1976 }
1977
1978 /** Add a range marker around each selected region */
1979 void
1980 Editor::add_locations_from_region ()
1981 {
1982         RegionSelection rs = get_regions_from_selection_and_entered ();
1983
1984         if (rs.empty()) {
1985                 return;
1986         }
1987
1988         _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
1989         XMLNode &before = _session->locations()->get_state();
1990
1991         for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
1992
1993                 boost::shared_ptr<Region> region = (*i)->region ();
1994
1995                 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1996
1997                 _session->locations()->add (location, true);
1998         }
1999
2000         XMLNode &after = _session->locations()->get_state();
2001         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2002         _session->commit_reversible_command ();
2003 }
2004
2005 /** Add a single range marker around all selected regions */
2006 void
2007 Editor::add_location_from_region ()
2008 {
2009         RegionSelection rs = get_regions_from_selection_and_entered ();
2010
2011         if (rs.empty()) {
2012                 return;
2013         }
2014
2015         _session->begin_reversible_command (_("add marker"));
2016         XMLNode &before = _session->locations()->get_state();
2017
2018         string markername;
2019
2020         if (rs.size() > 1) {
2021                 _session->locations()->next_available_name(markername, "regions");
2022         } else {
2023                 RegionView* rv = *(rs.begin());
2024                 boost::shared_ptr<Region> region = rv->region();
2025                 markername = region->name();
2026         }
2027
2028         if (!choose_new_marker_name(markername)) {
2029                 return;
2030         }
2031
2032         // single range spanning all selected
2033         Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2034         _session->locations()->add (location, true);
2035
2036         XMLNode &after = _session->locations()->get_state();
2037         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2038         _session->commit_reversible_command ();
2039 }
2040
2041 /* MARKS */
2042
2043 void
2044 Editor::jump_forward_to_mark ()
2045 {
2046         if (!_session) {
2047                 return;
2048         }
2049
2050         framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2051
2052         if (pos < 0) {
2053                 return;
2054         }
2055         
2056         _session->request_locate (pos, _session->transport_rolling());
2057 }
2058
2059 void
2060 Editor::jump_backward_to_mark ()
2061 {
2062         if (!_session) {
2063                 return;
2064         }
2065
2066         framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2067
2068         if (pos < 0) {
2069                 return;
2070         }
2071
2072         _session->request_locate (pos, _session->transport_rolling());
2073 }
2074
2075 void
2076 Editor::set_mark ()
2077 {
2078         framepos_t const pos = _session->audible_frame ();
2079
2080         string markername;
2081         _session->locations()->next_available_name (markername, "mark");
2082
2083         if (!choose_new_marker_name (markername)) {
2084                 return;
2085         }
2086
2087         _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2088 }
2089
2090 void
2091 Editor::clear_markers ()
2092 {
2093         if (_session) {
2094                 _session->begin_reversible_command (_("clear markers"));
2095                 XMLNode &before = _session->locations()->get_state();
2096                 _session->locations()->clear_markers ();
2097                 XMLNode &after = _session->locations()->get_state();
2098                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2099                 _session->commit_reversible_command ();
2100         }
2101 }
2102
2103 void
2104 Editor::clear_ranges ()
2105 {
2106         if (_session) {
2107                 _session->begin_reversible_command (_("clear ranges"));
2108                 XMLNode &before = _session->locations()->get_state();
2109
2110                 Location * looploc = _session->locations()->auto_loop_location();
2111                 Location * punchloc = _session->locations()->auto_punch_location();
2112                 Location * sessionloc = _session->locations()->session_range_location();
2113
2114                 _session->locations()->clear_ranges ();
2115                 // re-add these
2116                 if (looploc) _session->locations()->add (looploc);
2117                 if (punchloc) _session->locations()->add (punchloc);
2118                 if (sessionloc) _session->locations()->add (sessionloc);
2119
2120                 XMLNode &after = _session->locations()->get_state();
2121                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2122                 _session->commit_reversible_command ();
2123         }
2124 }
2125
2126 void
2127 Editor::clear_locations ()
2128 {
2129         _session->begin_reversible_command (_("clear locations"));
2130         XMLNode &before = _session->locations()->get_state();
2131         _session->locations()->clear ();
2132         XMLNode &after = _session->locations()->get_state();
2133         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2134         _session->commit_reversible_command ();
2135         _session->locations()->clear ();
2136 }
2137
2138 void
2139 Editor::unhide_markers ()
2140 {
2141         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2142                 Location *l = (*i).first;
2143                 if (l->is_hidden() && l->is_mark()) {
2144                         l->set_hidden(false, this);
2145                 }
2146         }
2147 }
2148
2149 void
2150 Editor::unhide_ranges ()
2151 {
2152         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2153                 Location *l = (*i).first;
2154                 if (l->is_hidden() && l->is_range_marker()) {
2155                         l->set_hidden(false, this);
2156                 }
2157         }
2158 }
2159
2160 /* INSERT/REPLACE */
2161
2162 void
2163 Editor::insert_region_list_selection (float times)
2164 {
2165         RouteTimeAxisView *tv = 0;
2166         boost::shared_ptr<Playlist> playlist;
2167
2168         if (clicked_routeview != 0) {
2169                 tv = clicked_routeview;
2170         } else if (!selection->tracks.empty()) {
2171                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2172                         return;
2173                 }
2174         } else if (entered_track != 0) {
2175                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2176                         return;
2177                 }
2178         } else {
2179                 return;
2180         }
2181
2182         if ((playlist = tv->playlist()) == 0) {
2183                 return;
2184         }
2185
2186         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2187         if (region == 0) {
2188                 return;
2189         }
2190
2191         begin_reversible_command (_("insert region"));
2192         playlist->clear_changes ();
2193         playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2194         if (Config->get_edit_mode() == Ripple)
2195                 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2196
2197         _session->add_command(new StatefulDiffCommand (playlist));
2198         commit_reversible_command ();
2199 }
2200
2201 /* BUILT-IN EFFECTS */
2202
2203 void
2204 Editor::reverse_selection ()
2205 {
2206
2207 }
2208
2209 /* GAIN ENVELOPE EDITING */
2210
2211 void
2212 Editor::edit_envelope ()
2213 {
2214 }
2215
2216 /* PLAYBACK */
2217
2218 void
2219 Editor::transition_to_rolling (bool fwd)
2220 {
2221         if (!_session) {
2222                 return;
2223         }
2224
2225         if (_session->config.get_external_sync()) {
2226                 switch (Config->get_sync_source()) {
2227                 case Engine:
2228                         break;
2229                 default:
2230                         /* transport controlled by the master */
2231                         return;
2232                 }
2233         }
2234
2235         if (_session->is_auditioning()) {
2236                 _session->cancel_audition ();
2237                 return;
2238         }
2239
2240         _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2241 }
2242
2243 void
2244 Editor::play_from_start ()
2245 {
2246         _session->request_locate (_session->current_start_frame(), true);
2247 }
2248
2249 void
2250 Editor::play_from_edit_point ()
2251 {
2252         _session->request_locate (get_preferred_edit_position(), true);
2253 }
2254
2255 void
2256 Editor::play_from_edit_point_and_return ()
2257 {
2258         framepos_t start_frame;
2259         framepos_t return_frame;
2260
2261         start_frame = get_preferred_edit_position (true);
2262
2263         if (_session->transport_rolling()) {
2264                 _session->request_locate (start_frame, false);
2265                 return;
2266         }
2267
2268         /* don't reset the return frame if its already set */
2269
2270         if ((return_frame = _session->requested_return_frame()) < 0) {
2271                 return_frame = _session->audible_frame();
2272         }
2273
2274         if (start_frame >= 0) {
2275                 _session->request_roll_at_and_return (start_frame, return_frame);
2276         }
2277 }
2278
2279 void
2280 Editor::play_selection ()
2281 {
2282         if (selection->time.empty()) {
2283                 return;
2284         }
2285
2286         _session->request_play_range (&selection->time, true);
2287 }
2288
2289 framepos_t
2290 Editor::get_preroll ()
2291 {
2292         return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2293 }
2294
2295
2296 void
2297 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2298 {
2299         if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2300                 return;
2301
2302         location -= get_preroll();
2303         
2304         //don't try to locate before the beginning of time
2305         if ( location < 0 ) 
2306                 location = 0;
2307                 
2308         //if follow_playhead is on, keep the playhead on the screen
2309         if ( _follow_playhead )
2310                 if ( location < leftmost_frame ) 
2311                         location = leftmost_frame;
2312
2313         _session->request_locate( location );
2314 }
2315
2316 void
2317 Editor::play_with_preroll ()
2318 {
2319         if (selection->time.empty()) {
2320                 return;
2321         } else {
2322                 framepos_t preroll = get_preroll();
2323                 
2324                 framepos_t start = 0;
2325                 if (selection->time[clicked_selection].start > preroll)
2326                         start = selection->time[clicked_selection].start - preroll;
2327                 
2328                 framepos_t end = selection->time[clicked_selection].end + preroll;
2329                 
2330                 AudioRange ar (start, end, 0);
2331                 list<AudioRange> lar;
2332                 lar.push_back (ar);
2333
2334                 _session->request_play_range (&lar, true);
2335         }
2336 }
2337
2338 void
2339 Editor::play_location (Location& location)
2340 {
2341         if (location.start() <= location.end()) {
2342                 return;
2343         }
2344
2345         _session->request_bounded_roll (location.start(), location.end());
2346 }
2347
2348 void
2349 Editor::loop_location (Location& location)
2350 {
2351         if (location.start() <= location.end()) {
2352                 return;
2353         }
2354
2355         Location* tll;
2356
2357         if ((tll = transport_loop_location()) != 0) {
2358                 tll->set (location.start(), location.end());
2359
2360                 // enable looping, reposition and start rolling
2361                 _session->request_play_loop (true);
2362                 _session->request_locate (tll->start(), true);
2363         }
2364 }
2365
2366 void
2367 Editor::do_layer_operation (LayerOperation op)
2368 {
2369         if (selection->regions.empty ()) {
2370                 return;
2371         }
2372
2373         bool const multiple = selection->regions.size() > 1;
2374         switch (op) {
2375         case Raise:
2376                 if (multiple) {
2377                         begin_reversible_command (_("raise regions"));
2378                 } else {
2379                         begin_reversible_command (_("raise region"));
2380                 }
2381                 break;
2382
2383         case RaiseToTop:
2384                 if (multiple) {
2385                         begin_reversible_command (_("raise regions to top"));
2386                 } else {
2387                         begin_reversible_command (_("raise region to top"));
2388                 }
2389                 break;
2390                 
2391         case Lower:
2392                 if (multiple) {
2393                         begin_reversible_command (_("lower regions"));
2394                 } else {
2395                         begin_reversible_command (_("lower region"));
2396                 }
2397                 break;
2398                 
2399         case LowerToBottom:
2400                 if (multiple) {
2401                         begin_reversible_command (_("lower regions to bottom"));
2402                 } else {
2403                         begin_reversible_command (_("lower region"));
2404                 }
2405                 break;
2406         }
2407
2408         set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2409         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2410                 (*i)->clear_owned_changes ();
2411         }
2412         
2413         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2414                 boost::shared_ptr<Region> r = (*i)->region ();
2415                 switch (op) {
2416                 case Raise:
2417                         r->raise ();
2418                         break;
2419                 case RaiseToTop:
2420                         r->raise_to_top ();
2421                         break;
2422                 case Lower:
2423                         r->lower ();
2424                         break;
2425                 case LowerToBottom:
2426                         r->lower_to_bottom ();
2427                 }
2428         }
2429
2430         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2431                 vector<Command*> cmds;
2432                 (*i)->rdiff (cmds);
2433                 _session->add_commands (cmds);
2434         }
2435         
2436         commit_reversible_command ();
2437 }
2438
2439 void
2440 Editor::raise_region ()
2441 {
2442         do_layer_operation (Raise);
2443 }
2444
2445 void
2446 Editor::raise_region_to_top ()
2447 {
2448         do_layer_operation (RaiseToTop);
2449 }
2450
2451 void
2452 Editor::lower_region ()
2453 {
2454         do_layer_operation (Lower);
2455 }
2456
2457 void
2458 Editor::lower_region_to_bottom ()
2459 {
2460         do_layer_operation (LowerToBottom);
2461 }
2462
2463 /** Show the region editor for the selected regions */
2464 void
2465 Editor::show_region_properties ()
2466 {
2467         selection->foreach_regionview (&RegionView::show_region_editor);
2468 }
2469
2470 /** Show the midi list editor for the selected MIDI regions */
2471 void
2472 Editor::show_midi_list_editor ()
2473 {
2474         selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2475 }
2476
2477 void
2478 Editor::rename_region ()
2479 {
2480         RegionSelection rs = get_regions_from_selection_and_entered ();
2481
2482         if (rs.empty()) {
2483                 return;
2484         }
2485
2486         ArdourDialog d (*this, _("Rename Region"), true, false);
2487         Entry entry;
2488         Label label (_("New name:"));
2489         HBox hbox;
2490
2491         hbox.set_spacing (6);
2492         hbox.pack_start (label, false, false);
2493         hbox.pack_start (entry, true, true);
2494
2495         d.get_vbox()->set_border_width (12);
2496         d.get_vbox()->pack_start (hbox, false, false);
2497
2498         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2499         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2500
2501         d.set_size_request (300, -1);
2502
2503         entry.set_text (rs.front()->region()->name());
2504         entry.select_region (0, -1);
2505
2506         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2507
2508         d.show_all ();
2509
2510         entry.grab_focus();
2511
2512         int const ret = d.run();
2513
2514         d.hide ();
2515
2516         if (ret != RESPONSE_OK) {
2517                 return;
2518         }
2519
2520         std::string str = entry.get_text();
2521         strip_whitespace_edges (str);
2522         if (!str.empty()) {
2523                 rs.front()->region()->set_name (str);
2524                 _regions->redisplay ();
2525         }
2526 }
2527
2528 void
2529 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2530 {
2531         if (_session->is_auditioning()) {
2532                 _session->cancel_audition ();
2533         }
2534
2535         // note: some potential for creativity here, because region doesn't
2536         // have to belong to the playlist that Route is handling
2537
2538         // bool was_soloed = route.soloed();
2539
2540         route.set_solo (true, this);
2541
2542         _session->request_bounded_roll (region->position(), region->position() + region->length());
2543
2544         /* XXX how to unset the solo state ? */
2545 }
2546
2547 /** Start an audition of the first selected region */
2548 void
2549 Editor::play_edit_range ()
2550 {
2551         framepos_t start, end;
2552
2553         if (get_edit_op_range (start, end)) {
2554                 _session->request_bounded_roll (start, end);
2555         }
2556 }
2557
2558 void
2559 Editor::play_selected_region ()
2560 {
2561         framepos_t start = max_framepos;
2562         framepos_t end = 0;
2563
2564         RegionSelection rs = get_regions_from_selection_and_entered ();
2565
2566         if (rs.empty()) {
2567                 return;
2568         }
2569
2570         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2571                 if ((*i)->region()->position() < start) {
2572                         start = (*i)->region()->position();
2573                 }
2574                 if ((*i)->region()->last_frame() + 1 > end) {
2575                         end = (*i)->region()->last_frame() + 1;
2576                 }
2577         }
2578
2579         _session->request_bounded_roll (start, end);
2580 }
2581
2582 void
2583 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2584 {
2585         _session->audition_region (region);
2586 }
2587
2588 void
2589 Editor::region_from_selection ()
2590 {
2591         if (clicked_axisview == 0) {
2592                 return;
2593         }
2594
2595         if (selection->time.empty()) {
2596                 return;
2597         }
2598
2599         framepos_t start = selection->time[clicked_selection].start;
2600         framepos_t end = selection->time[clicked_selection].end;
2601
2602         TrackViewList tracks = get_tracks_for_range_action ();
2603
2604         framepos_t selection_cnt = end - start + 1;
2605
2606         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2607                 boost::shared_ptr<Region> current;
2608                 boost::shared_ptr<Playlist> pl;
2609                 framepos_t internal_start;
2610                 string new_name;
2611
2612                 if ((pl = (*i)->playlist()) == 0) {
2613                         continue;
2614                 }
2615
2616                 if ((current = pl->top_region_at (start)) == 0) {
2617                         continue;
2618                 }
2619
2620                 internal_start = start - current->position();
2621                 RegionFactory::region_name (new_name, current->name(), true);
2622
2623                 PropertyList plist;
2624
2625                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2626                 plist.add (ARDOUR::Properties::length, selection_cnt);
2627                 plist.add (ARDOUR::Properties::name, new_name);
2628                 plist.add (ARDOUR::Properties::layer, 0);
2629
2630                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2631         }
2632 }
2633
2634 void
2635 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2636 {
2637         if (selection->time.empty() || selection->tracks.empty()) {
2638                 return;
2639         }
2640
2641         framepos_t start = selection->time[clicked_selection].start;
2642         framepos_t end = selection->time[clicked_selection].end;
2643
2644         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2645         sort_track_selection (ts);
2646
2647         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2648                 boost::shared_ptr<Region> current;
2649                 boost::shared_ptr<Playlist> playlist;
2650                 framepos_t internal_start;
2651                 string new_name;
2652
2653                 if ((playlist = (*i)->playlist()) == 0) {
2654                         continue;
2655                 }
2656
2657                 if ((current = playlist->top_region_at(start)) == 0) {
2658                         continue;
2659                 }
2660
2661                 internal_start = start - current->position();
2662                 RegionFactory::region_name (new_name, current->name(), true);
2663
2664                 PropertyList plist;
2665
2666                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2667                 plist.add (ARDOUR::Properties::length, end - start + 1);
2668                 plist.add (ARDOUR::Properties::name, new_name);
2669
2670                 new_regions.push_back (RegionFactory::create (current, plist));
2671         }
2672 }
2673
2674 void
2675 Editor::split_multichannel_region ()
2676 {
2677         RegionSelection rs = get_regions_from_selection_and_entered ();
2678
2679         if (rs.empty()) {
2680                 return;
2681         }
2682
2683         vector< boost::shared_ptr<Region> > v;
2684
2685         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2686                 (*x)->region()->separate_by_channel (*_session, v);
2687         }
2688 }
2689
2690 void
2691 Editor::new_region_from_selection ()
2692 {
2693         region_from_selection ();
2694         cancel_selection ();
2695 }
2696
2697 static void
2698 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2699 {
2700         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2701         case Evoral::OverlapNone:
2702                 break;
2703         default:
2704                 rs->push_back (rv);
2705         }
2706 }
2707
2708 /** Return either:
2709  *    - selected tracks, or if there are none...
2710  *    - tracks containing selected regions, or if there are none...
2711  *    - all tracks
2712  * @return tracks.
2713  */
2714 TrackViewList
2715 Editor::get_tracks_for_range_action () const
2716 {
2717         TrackViewList t;
2718
2719         if (selection->tracks.empty()) {
2720
2721                 /* use tracks with selected regions */
2722
2723                 RegionSelection rs = selection->regions;
2724
2725                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2726                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2727
2728                         if (!t.contains (tv)) {
2729                                 t.push_back (tv);
2730                         }
2731                 }
2732
2733                 if (t.empty()) {
2734                         /* no regions and no tracks: use all tracks */
2735                         t = track_views;
2736                 }
2737
2738         } else {
2739
2740                 t = selection->tracks;
2741         }
2742
2743         return t.filter_to_unique_playlists();
2744 }
2745
2746 void
2747 Editor::separate_regions_between (const TimeSelection& ts)
2748 {
2749         bool in_command = false;
2750         boost::shared_ptr<Playlist> playlist;
2751         RegionSelection new_selection;
2752
2753         TrackViewList tmptracks = get_tracks_for_range_action ();
2754         sort_track_selection (tmptracks);
2755
2756         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2757
2758                 RouteTimeAxisView* rtv;
2759
2760                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2761
2762                         if (rtv->is_track()) {
2763
2764                                 /* no edits to destructive tracks */
2765
2766                                 if (rtv->track()->destructive()) {
2767                                         continue;
2768                                 }
2769
2770                                 if ((playlist = rtv->playlist()) != 0) {
2771
2772                                         playlist->clear_changes ();
2773
2774                                         /* XXX need to consider musical time selections here at some point */
2775
2776                                         double speed = rtv->track()->speed();
2777
2778
2779                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2780
2781                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2782                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2783
2784                                                 latest_regionviews.clear ();
2785
2786                                                 playlist->partition ((framepos_t)((*t).start * speed),
2787                                                                 (framepos_t)((*t).end * speed), false);
2788
2789                                                 c.disconnect ();
2790
2791                                                 if (!latest_regionviews.empty()) {
2792
2793                                                         rtv->view()->foreach_regionview (sigc::bind (
2794                                                                                 sigc::ptr_fun (add_if_covered),
2795                                                                                 &(*t), &new_selection));
2796
2797                                                         if (!in_command) {
2798                                                                 begin_reversible_command (_("separate"));
2799                                                                 in_command = true;
2800                                                         }
2801
2802                                                         /* pick up changes to existing regions */
2803
2804                                                         vector<Command*> cmds;
2805                                                         playlist->rdiff (cmds);
2806                                                         _session->add_commands (cmds);
2807
2808                                                         /* pick up changes to the playlist itself (adds/removes)
2809                                                          */
2810
2811                                                         _session->add_command(new StatefulDiffCommand (playlist));
2812                                                 }
2813                                         }
2814                                 }
2815                         }
2816                 }
2817         }
2818
2819         if (in_command) {
2820 //              selection->set (new_selection);
2821
2822                 commit_reversible_command ();
2823         }
2824 }
2825
2826 struct PlaylistState {
2827     boost::shared_ptr<Playlist> playlist;
2828     XMLNode*  before;
2829 };
2830
2831 /** Take tracks from get_tracks_for_range_action and cut any regions
2832  *  on those tracks so that the tracks are empty over the time
2833  *  selection.
2834  */
2835 void
2836 Editor::separate_region_from_selection ()
2837 {
2838         /* preferentially use *all* ranges in the time selection if we're in range mode
2839            to allow discontiguous operation, since get_edit_op_range() currently
2840            returns a single range.
2841         */
2842
2843         if (!selection->time.empty()) {
2844
2845                 separate_regions_between (selection->time);
2846
2847         } else {
2848
2849                 framepos_t start;
2850                 framepos_t end;
2851
2852                 if (get_edit_op_range (start, end)) {
2853
2854                         AudioRange ar (start, end, 1);
2855                         TimeSelection ts;
2856                         ts.push_back (ar);
2857
2858                         separate_regions_between (ts);
2859                 }
2860         }
2861 }
2862
2863 void
2864 Editor::separate_region_from_punch ()
2865 {
2866         Location* loc  = _session->locations()->auto_punch_location();
2867         if (loc) {
2868                 separate_regions_using_location (*loc);
2869         }
2870 }
2871
2872 void
2873 Editor::separate_region_from_loop ()
2874 {
2875         Location* loc  = _session->locations()->auto_loop_location();
2876         if (loc) {
2877                 separate_regions_using_location (*loc);
2878         }
2879 }
2880
2881 void
2882 Editor::separate_regions_using_location (Location& loc)
2883 {
2884         if (loc.is_mark()) {
2885                 return;
2886         }
2887
2888         AudioRange ar (loc.start(), loc.end(), 1);
2889         TimeSelection ts;
2890
2891         ts.push_back (ar);
2892
2893         separate_regions_between (ts);
2894 }
2895
2896 /** Separate regions under the selected region */
2897 void
2898 Editor::separate_under_selected_regions ()
2899 {
2900         vector<PlaylistState> playlists;
2901
2902         RegionSelection rs;
2903
2904         rs = get_regions_from_selection_and_entered();
2905
2906         if (!_session || rs.empty()) {
2907                 return;
2908         }
2909
2910         begin_reversible_command (_("separate region under"));
2911
2912         list<boost::shared_ptr<Region> > regions_to_remove;
2913
2914         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2915                 // we can't just remove the region(s) in this loop because
2916                 // this removes them from the RegionSelection, and they thus
2917                 // disappear from underneath the iterator, and the ++i above
2918                 // SEGVs in a puzzling fashion.
2919
2920                 // so, first iterate over the regions to be removed from rs and
2921                 // add them to the regions_to_remove list, and then
2922                 // iterate over the list to actually remove them.
2923
2924                 regions_to_remove.push_back ((*i)->region());
2925         }
2926
2927         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2928
2929                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2930
2931                 if (!playlist) {
2932                         // is this check necessary?
2933                         continue;
2934                 }
2935
2936                 vector<PlaylistState>::iterator i;
2937
2938                 //only take state if this is a new playlist.
2939                 for (i = playlists.begin(); i != playlists.end(); ++i) {
2940                         if ((*i).playlist == playlist) {
2941                                 break;
2942                         }
2943                 }
2944
2945                 if (i == playlists.end()) {
2946
2947                         PlaylistState before;
2948                         before.playlist = playlist;
2949                         before.before = &playlist->get_state();
2950
2951                         playlist->freeze ();
2952                         playlists.push_back(before);
2953                 }
2954
2955                 //Partition on the region bounds
2956                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2957
2958                 //Re-add region that was just removed due to the partition operation
2959                 playlist->add_region( (*rl), (*rl)->first_frame() );
2960         }
2961
2962         vector<PlaylistState>::iterator pl;
2963
2964         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2965                 (*pl).playlist->thaw ();
2966                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2967         }
2968
2969         commit_reversible_command ();
2970 }
2971
2972 void
2973 Editor::crop_region_to_selection ()
2974 {
2975         if (!selection->time.empty()) {
2976
2977                 crop_region_to (selection->time.start(), selection->time.end_frame());
2978
2979         } else {
2980
2981                 framepos_t start;
2982                 framepos_t end;
2983
2984                 if (get_edit_op_range (start, end)) {
2985                         crop_region_to (start, end);
2986                 }
2987         }
2988
2989 }
2990
2991 void
2992 Editor::crop_region_to (framepos_t start, framepos_t end)
2993 {
2994         vector<boost::shared_ptr<Playlist> > playlists;
2995         boost::shared_ptr<Playlist> playlist;
2996         TrackViewList ts;
2997
2998         if (selection->tracks.empty()) {
2999                 ts = track_views.filter_to_unique_playlists();
3000         } else {
3001                 ts = selection->tracks.filter_to_unique_playlists ();
3002         }
3003
3004         sort_track_selection (ts);
3005
3006         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3007
3008                 RouteTimeAxisView* rtv;
3009
3010                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3011
3012                         boost::shared_ptr<Track> t = rtv->track();
3013
3014                         if (t != 0 && ! t->destructive()) {
3015
3016                                 if ((playlist = rtv->playlist()) != 0) {
3017                                         playlists.push_back (playlist);
3018                                 }
3019                         }
3020                 }
3021         }
3022
3023         if (playlists.empty()) {
3024                 return;
3025         }
3026
3027         framepos_t the_start;
3028         framepos_t the_end;
3029         framepos_t cnt;
3030
3031         begin_reversible_command (_("trim to selection"));
3032
3033         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3034
3035                 boost::shared_ptr<Region> region;
3036
3037                 the_start = start;
3038
3039                 if ((region = (*i)->top_region_at(the_start)) == 0) {
3040                         continue;
3041                 }
3042
3043                 /* now adjust lengths to that we do the right thing
3044                    if the selection extends beyond the region
3045                 */
3046
3047                 the_start = max (the_start, (framepos_t) region->position());
3048                 if (max_framepos - the_start < region->length()) {
3049                         the_end = the_start + region->length() - 1;
3050                 } else {
3051                         the_end = max_framepos;
3052                 }
3053                 the_end = min (end, the_end);
3054                 cnt = the_end - the_start + 1;
3055
3056                 region->clear_changes ();
3057                 region->trim_to (the_start, cnt);
3058                 _session->add_command (new StatefulDiffCommand (region));
3059         }
3060
3061         commit_reversible_command ();
3062 }
3063
3064 void
3065 Editor::region_fill_track ()
3066 {
3067         RegionSelection rs = get_regions_from_selection_and_entered ();
3068
3069         if (!_session || rs.empty()) {
3070                 return;
3071         }
3072
3073         framepos_t const end = _session->current_end_frame ();
3074
3075         begin_reversible_command (Operations::region_fill);
3076
3077         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3078
3079                 boost::shared_ptr<Region> region ((*i)->region());
3080
3081                 boost::shared_ptr<Playlist> pl = region->playlist();
3082
3083                 if (end <= region->last_frame()) {
3084                         return;
3085                 }
3086
3087                 double times = (double) (end - region->last_frame()) / (double) region->length();
3088
3089                 if (times == 0) {
3090                         return;
3091                 }
3092
3093                 pl->clear_changes ();
3094                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3095                 _session->add_command (new StatefulDiffCommand (pl));
3096         }
3097
3098         commit_reversible_command ();
3099 }
3100
3101 void
3102 Editor::region_fill_selection ()
3103 {
3104         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3105                 return;
3106         }
3107
3108         if (selection->time.empty()) {
3109                 return;
3110         }
3111
3112         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3113         if (region == 0) {
3114                 return;
3115         }
3116
3117         framepos_t start = selection->time[clicked_selection].start;
3118         framepos_t end = selection->time[clicked_selection].end;
3119
3120         boost::shared_ptr<Playlist> playlist;
3121
3122         if (selection->tracks.empty()) {
3123                 return;
3124         }
3125
3126         framepos_t selection_length = end - start;
3127         float times = (float)selection_length / region->length();
3128
3129         begin_reversible_command (Operations::fill_selection);
3130
3131         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3132
3133         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3134
3135                 if ((playlist = (*i)->playlist()) == 0) {
3136                         continue;
3137                 }
3138
3139                 playlist->clear_changes ();
3140                 playlist->add_region (RegionFactory::create (region, true), start, times);
3141                 _session->add_command (new StatefulDiffCommand (playlist));
3142         }
3143
3144         commit_reversible_command ();
3145 }
3146
3147 void
3148 Editor::set_region_sync_position ()
3149 {
3150         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3151 }
3152
3153 void
3154 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3155 {
3156         bool in_command = false;
3157
3158         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3159
3160                 if (!(*r)->region()->covers (where)) {
3161                         continue;
3162                 }
3163
3164                 boost::shared_ptr<Region> region ((*r)->region());
3165
3166                 if (!in_command) {
3167                         begin_reversible_command (_("set sync point"));
3168                         in_command = true;
3169                 }
3170
3171                 region->clear_changes ();
3172                 region->set_sync_position (where);
3173                 _session->add_command(new StatefulDiffCommand (region));
3174         }
3175
3176         if (in_command) {
3177                 commit_reversible_command ();
3178         }
3179 }
3180
3181 /** Remove the sync positions of the selection */
3182 void
3183 Editor::remove_region_sync ()
3184 {
3185         RegionSelection rs = get_regions_from_selection_and_entered ();
3186
3187         if (rs.empty()) {
3188                 return;
3189         }
3190
3191         begin_reversible_command (_("remove region sync"));
3192
3193         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3194
3195                 (*i)->region()->clear_changes ();
3196                 (*i)->region()->clear_sync_position ();
3197                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3198         }
3199
3200         commit_reversible_command ();
3201 }
3202
3203 void
3204 Editor::naturalize_region ()
3205 {
3206         RegionSelection rs = get_regions_from_selection_and_entered ();
3207
3208         if (rs.empty()) {
3209                 return;
3210         }
3211
3212         if (rs.size() > 1) {
3213                 begin_reversible_command (_("move regions to original position"));
3214         } else {
3215                 begin_reversible_command (_("move region to original position"));
3216         }
3217
3218         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3219                 (*i)->region()->clear_changes ();
3220                 (*i)->region()->move_to_natural_position ();
3221                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3222         }
3223
3224         commit_reversible_command ();
3225 }
3226
3227 void
3228 Editor::align_regions (RegionPoint what)
3229 {
3230         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3231
3232         if (rs.empty()) {
3233                 return;
3234         }
3235
3236         begin_reversible_command (_("align selection"));
3237
3238         framepos_t const position = get_preferred_edit_position ();
3239
3240         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3241                 align_region_internal ((*i)->region(), what, position);
3242         }
3243
3244         commit_reversible_command ();
3245 }
3246
3247 struct RegionSortByTime {
3248     bool operator() (const RegionView* a, const RegionView* b) {
3249             return a->region()->position() < b->region()->position();
3250     }
3251 };
3252
3253 void
3254 Editor::align_regions_relative (RegionPoint point)
3255 {
3256         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3257
3258         if (rs.empty()) {
3259                 return;
3260         }
3261
3262         framepos_t const position = get_preferred_edit_position ();
3263
3264         framepos_t distance = 0;
3265         framepos_t pos = 0;
3266         int dir = 1;
3267
3268         list<RegionView*> sorted;
3269         rs.by_position (sorted);
3270
3271         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3272
3273         switch (point) {
3274         case Start:
3275                 pos = position;
3276                 if (position > r->position()) {
3277                         distance = position - r->position();
3278                 } else {
3279                         distance = r->position() - position;
3280                         dir = -1;
3281                 }
3282                 break;
3283
3284         case End:
3285                 if (position > r->last_frame()) {
3286                         distance = position - r->last_frame();
3287                         pos = r->position() + distance;
3288                 } else {
3289                         distance = r->last_frame() - position;
3290                         pos = r->position() - distance;
3291                         dir = -1;
3292                 }
3293                 break;
3294
3295         case SyncPoint:
3296                 pos = r->adjust_to_sync (position);
3297                 if (pos > r->position()) {
3298                         distance = pos - r->position();
3299                 } else {
3300                         distance = r->position() - pos;
3301                         dir = -1;
3302                 }
3303                 break;
3304         }
3305
3306         if (pos == r->position()) {
3307                 return;
3308         }
3309
3310         begin_reversible_command (_("align selection (relative)"));
3311
3312         /* move first one specially */
3313
3314         r->clear_changes ();
3315         r->set_position (pos);
3316         _session->add_command(new StatefulDiffCommand (r));
3317
3318         /* move rest by the same amount */
3319
3320         sorted.pop_front();
3321
3322         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3323
3324                 boost::shared_ptr<Region> region ((*i)->region());
3325
3326                 region->clear_changes ();
3327
3328                 if (dir > 0) {
3329                         region->set_position (region->position() + distance);
3330                 } else {
3331                         region->set_position (region->position() - distance);
3332                 }
3333
3334                 _session->add_command(new StatefulDiffCommand (region));
3335
3336         }
3337
3338         commit_reversible_command ();
3339 }
3340
3341 void
3342 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3343 {
3344         begin_reversible_command (_("align region"));
3345         align_region_internal (region, point, position);
3346         commit_reversible_command ();
3347 }
3348
3349 void
3350 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3351 {
3352         region->clear_changes ();
3353
3354         switch (point) {
3355         case SyncPoint:
3356                 region->set_position (region->adjust_to_sync (position));
3357                 break;
3358
3359         case End:
3360                 if (position > region->length()) {
3361                         region->set_position (position - region->length());
3362                 }
3363                 break;
3364
3365         case Start:
3366                 region->set_position (position);
3367                 break;
3368         }
3369
3370         _session->add_command(new StatefulDiffCommand (region));
3371 }
3372
3373 void
3374 Editor::trim_region_front ()
3375 {
3376         trim_region (true);
3377 }
3378
3379 void
3380 Editor::trim_region_back ()
3381 {
3382         trim_region (false);
3383 }
3384
3385 void
3386 Editor::trim_region (bool front)
3387 {
3388         framepos_t where = get_preferred_edit_position();
3389         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3390
3391         if (rs.empty()) {
3392                 return;
3393         }
3394
3395         begin_reversible_command (front ? _("trim front") : _("trim back"));
3396
3397         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3398                 if (!(*i)->region()->locked()) {
3399
3400                         (*i)->region()->clear_changes ();
3401
3402                         if (front) {
3403                                 (*i)->region()->trim_front (where);
3404                                 maybe_locate_with_edit_preroll ( where );
3405                         } else {
3406                                 (*i)->region()->trim_end (where);
3407                                 maybe_locate_with_edit_preroll ( where );
3408                         }
3409
3410                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3411                 }
3412         }
3413
3414         commit_reversible_command ();
3415 }
3416
3417 /** Trim the end of the selected regions to the position of the edit cursor */
3418 void
3419 Editor::trim_region_to_loop ()
3420 {
3421         Location* loc = _session->locations()->auto_loop_location();
3422         if (!loc) {
3423                 return;
3424         }
3425         trim_region_to_location (*loc, _("trim to loop"));
3426 }
3427
3428 void
3429 Editor::trim_region_to_punch ()
3430 {
3431         Location* loc = _session->locations()->auto_punch_location();
3432         if (!loc) {
3433                 return;
3434         }
3435         trim_region_to_location (*loc, _("trim to punch"));
3436 }
3437
3438 void
3439 Editor::trim_region_to_location (const Location& loc, const char* str)
3440 {
3441         RegionSelection rs = get_regions_from_selection_and_entered ();
3442
3443         begin_reversible_command (str);
3444
3445         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3446                 RegionView* rv = (*x);
3447
3448                 /* require region to span proposed trim */
3449                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3450                 case Evoral::OverlapInternal:
3451                         break;
3452                 default:
3453                         continue;
3454                 }
3455
3456                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3457                 if (!tav) {
3458                         return;
3459                 }
3460
3461                 float speed = 1.0;
3462                 framepos_t start;
3463                 framepos_t end;
3464
3465                 if (tav->track() != 0) {
3466                         speed = tav->track()->speed();
3467                 }
3468
3469                 start = session_frame_to_track_frame (loc.start(), speed);
3470                 end = session_frame_to_track_frame (loc.end(), speed);
3471
3472                 rv->region()->clear_changes ();
3473                 rv->region()->trim_to (start, (end - start));
3474                 _session->add_command(new StatefulDiffCommand (rv->region()));
3475         }
3476
3477         commit_reversible_command ();
3478 }
3479
3480 void
3481 Editor::trim_region_to_previous_region_end ()
3482 {
3483         return trim_to_region(false);
3484 }
3485
3486 void
3487 Editor::trim_region_to_next_region_start ()
3488 {
3489         return trim_to_region(true);
3490 }
3491
3492 void
3493 Editor::trim_to_region(bool forward)
3494 {
3495         RegionSelection rs = get_regions_from_selection_and_entered ();
3496
3497         begin_reversible_command (_("trim to region"));
3498
3499         boost::shared_ptr<Region> next_region;
3500
3501         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3502
3503                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3504
3505                 if (!arv) {
3506                         continue;
3507                 }
3508
3509                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3510
3511                 if (!atav) {
3512                         return;
3513                 }
3514
3515                 float speed = 1.0;
3516
3517                 if (atav->track() != 0) {
3518                         speed = atav->track()->speed();
3519                 }
3520
3521
3522                 boost::shared_ptr<Region> region = arv->region();
3523                 boost::shared_ptr<Playlist> playlist (region->playlist());
3524
3525                 region->clear_changes ();
3526
3527                 if (forward) {
3528
3529                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3530
3531                     if (!next_region) {
3532                         continue;
3533                     }
3534
3535                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3536                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3537                 }
3538                 else {
3539
3540                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3541
3542                     if(!next_region){
3543                         continue;
3544                     }
3545
3546                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3547
3548                     arv->region_changed (ARDOUR::bounds_change);
3549                 }
3550
3551                 _session->add_command(new StatefulDiffCommand (region));
3552         }
3553
3554         commit_reversible_command ();
3555 }
3556
3557 void
3558 Editor::unfreeze_route ()
3559 {
3560         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3561                 return;
3562         }
3563
3564         clicked_routeview->track()->unfreeze ();
3565 }
3566
3567 void*
3568 Editor::_freeze_thread (void* arg)
3569 {
3570         return static_cast<Editor*>(arg)->freeze_thread ();
3571 }
3572
3573 void*
3574 Editor::freeze_thread ()
3575 {
3576         /* create event pool because we may need to talk to the session */
3577         SessionEvent::create_per_thread_pool ("freeze events", 64);
3578         /* create per-thread buffers for process() tree to use */
3579         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3580         current_interthread_info->done = true;
3581         return 0;
3582 }
3583
3584 void
3585 Editor::freeze_route ()
3586 {
3587         if (!_session) {
3588                 return;
3589         }
3590
3591         /* stop transport before we start. this is important */
3592
3593         _session->request_transport_speed (0.0);
3594         
3595         /* wait for just a little while, because the above call is asynchronous */
3596
3597         Glib::usleep (250000);
3598
3599         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3600                 return;
3601         }
3602
3603         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3604                 MessageDialog d (
3605                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3606                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3607                         );
3608                 d.set_title (_("Cannot freeze"));
3609                 d.run ();
3610                 return;
3611         }
3612
3613         if (clicked_routeview->track()->has_external_redirects()) {
3614                 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"
3615                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3616                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3617
3618                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3619                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3620                 d.set_title (_("Freeze Limits"));
3621
3622                 int response = d.run ();
3623
3624                 switch (response) {
3625                 case Gtk::RESPONSE_CANCEL:
3626                         return;
3627                 default:
3628                         break;
3629                 }
3630         }
3631
3632         InterThreadInfo itt;
3633         current_interthread_info = &itt;
3634
3635         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3636
3637         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3638
3639         set_canvas_cursor (_cursors->wait);
3640
3641         while (!itt.done && !itt.cancel) {
3642                 gtk_main_iteration ();
3643         }
3644
3645         current_interthread_info = 0;
3646         set_canvas_cursor (current_canvas_cursor);
3647 }
3648
3649 void
3650 Editor::bounce_range_selection (bool replace, bool enable_processing)
3651 {
3652         if (selection->time.empty()) {
3653                 return;
3654         }
3655
3656         TrackSelection views = selection->tracks;
3657
3658         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3659
3660                 if (enable_processing) {
3661
3662                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3663
3664                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3665                                 MessageDialog d (
3666                                         _("You can't perform this operation because the processing of the signal "
3667                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3668                                           "You can do this without processing, which is a different operation.")
3669                                         );
3670                                 d.set_title (_("Cannot bounce"));
3671                                 d.run ();
3672                                 return;
3673                         }
3674                 }
3675         }
3676
3677         framepos_t start = selection->time[clicked_selection].start;
3678         framepos_t end = selection->time[clicked_selection].end;
3679         framepos_t cnt = end - start + 1;
3680
3681         begin_reversible_command (_("bounce range"));
3682
3683         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3684
3685                 RouteTimeAxisView* rtv;
3686
3687                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3688                         continue;
3689                 }
3690
3691                 boost::shared_ptr<Playlist> playlist;
3692
3693                 if ((playlist = rtv->playlist()) == 0) {
3694                         return;
3695                 }
3696
3697                 InterThreadInfo itt;
3698
3699                 playlist->clear_changes ();
3700                 playlist->clear_owned_changes ();
3701
3702                 boost::shared_ptr<Region> r;
3703
3704                 if (enable_processing) {
3705                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3706                 } else {
3707                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3708                 }
3709
3710                 if (!r) {
3711                         continue;
3712                 }
3713
3714                 if (replace) {
3715                         list<AudioRange> ranges;
3716                         ranges.push_back (AudioRange (start, start+cnt, 0));
3717                         playlist->cut (ranges); // discard result
3718                         playlist->add_region (r, start);
3719                 }
3720
3721                 vector<Command*> cmds;
3722                 playlist->rdiff (cmds);
3723                 _session->add_commands (cmds);
3724
3725                 _session->add_command (new StatefulDiffCommand (playlist));
3726         }
3727
3728         commit_reversible_command ();
3729 }
3730
3731 /** Delete selected regions, automation points or a time range */
3732 void
3733 Editor::delete_ ()
3734 {
3735         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3736         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3737         //TODO:  perhaps someday we need to accomodate the other bindings such as mute, solo, etc.
3738         if ( current_mixer_strip && current_mixer_strip->is_selected() )
3739                 current_mixer_strip->delete_processors ();
3740         else
3741                 cut_copy (Delete);
3742 }
3743
3744 /** Cut selected regions, automation points or a time range */
3745 void
3746 Editor::cut ()
3747 {
3748         cut_copy (Cut);
3749 }
3750
3751 /** Copy selected regions, automation points or a time range */
3752 void
3753 Editor::copy ()
3754 {
3755         cut_copy (Copy);
3756 }
3757
3758
3759 /** @return true if a Cut, Copy or Clear is possible */
3760 bool
3761 Editor::can_cut_copy () const
3762 {
3763         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3764                 return true;
3765
3766         return false;
3767 }
3768
3769
3770 /** Cut, copy or clear selected regions, automation points or a time range.
3771  * @param op Operation (Delete, Cut, Copy or Clear)
3772  */
3773 void
3774 Editor::cut_copy (CutCopyOp op)
3775 {
3776         /* only cancel selection if cut/copy is successful.*/
3777
3778         string opname;
3779
3780         switch (op) {
3781         case Delete:
3782                 opname = _("delete");
3783                 break;
3784         case Cut:
3785                 opname = _("cut");
3786                 break;
3787         case Copy:
3788                 opname = _("copy");
3789                 break;
3790         case Clear:
3791                 opname = _("clear");
3792                 break;
3793         }
3794
3795         /* if we're deleting something, and the mouse is still pressed,
3796            the thing we started a drag for will be gone when we release
3797            the mouse button(s). avoid this. see part 2 at the end of
3798            this function.
3799         */
3800
3801         if (op == Delete || op == Cut || op == Clear) {
3802                 if (_drags->active ()) {
3803                         _drags->abort ();
3804                 }
3805         }
3806
3807         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
3808                 cut_buffer->clear ();
3809
3810         if (entered_marker) {
3811
3812                 /* cut/delete op while pointing at a marker */
3813
3814                 bool ignored;
3815                 Location* loc = find_location_from_marker (entered_marker, ignored);
3816
3817                 if (_session && loc) {
3818                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3819                 }
3820
3821                 _drags->abort ();
3822                 return;
3823         }
3824
3825         if (internal_editing()) {
3826
3827                 switch (effective_mouse_mode()) {
3828                 case MouseObject:
3829                 case MouseRange:
3830                         begin_reversible_command (opname + ' ' + X_("MIDI"));
3831                         cut_copy_midi (op);
3832                         commit_reversible_command ();
3833                         break;
3834                 default:
3835                         break;
3836                 }
3837
3838                 return;
3839         }
3840
3841         bool did_edit = false;
3842
3843         if (!selection->points.empty()) {
3844                 begin_reversible_command (opname + _(" points"));
3845                 did_edit = true;
3846                 cut_copy_points (op);
3847                 if (op == Cut || op == Delete) {
3848                         selection->clear_points ();
3849                 }
3850         } else if (!selection->regions.empty() || !selection->points.empty()) {
3851
3852                 string thing_name;
3853
3854                 if (selection->regions.empty()) {
3855                         thing_name = _("points");
3856                 } else if (selection->points.empty()) {
3857                         thing_name = _("regions");
3858                 } else {
3859                         thing_name = _("objects");
3860                 }
3861         
3862                 begin_reversible_command (opname + ' ' + thing_name);
3863                 did_edit = true;
3864
3865                 if (!selection->regions.empty()) {
3866                         cut_copy_regions (op, selection->regions);
3867                         
3868                         if (op == Cut || op == Delete) {
3869                                 selection->clear_regions ();
3870                         }
3871                 }
3872                 
3873                 if (!selection->points.empty()) {
3874                         cut_copy_points (op);
3875                         
3876                         if (op == Cut || op == Delete) {
3877                                 selection->clear_points ();
3878                         }
3879                 }
3880         } else if (selection->time.empty()) {
3881                 framepos_t start, end;
3882                 /* no time selection, see if we can get an edit range
3883                    and use that.
3884                 */
3885                 if (get_edit_op_range (start, end)) {
3886                         selection->set (start, end);
3887                 }
3888         } else if (!selection->time.empty()) {
3889                 begin_reversible_command (opname + _(" range"));
3890
3891                 did_edit = true;
3892                 cut_copy_ranges (op);
3893                 
3894                 if (op == Cut || op == Delete) {
3895                         selection->clear_time ();
3896                 }
3897         }
3898         
3899         if (did_edit) {
3900                 commit_reversible_command ();   
3901         }
3902         
3903         if (op == Delete || op == Cut || op == Clear) {
3904                 _drags->abort ();
3905         }
3906 }
3907
3908 struct AutomationRecord {
3909         AutomationRecord () : state (0) {}
3910         AutomationRecord (XMLNode* s) : state (s) {}
3911         
3912         XMLNode* state; ///< state before any operation
3913         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3914 };
3915
3916 /** Cut, copy or clear selected automation points.
3917  *  @param op Operation (Cut, Copy or Clear)
3918  */
3919 void
3920 Editor::cut_copy_points (CutCopyOp op)
3921 {
3922         if (selection->points.empty ()) {
3923                 return;
3924         }
3925
3926         /* XXX: not ideal, as there may be more than one track involved in the point selection */
3927         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3928
3929         /* Keep a record of the AutomationLists that we end up using in this operation */
3930         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3931         Lists lists;
3932
3933         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3934         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3935                 boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3936                 if (lists.find (al) == lists.end ()) {
3937                         /* We haven't seen this list yet, so make a record for it.  This includes
3938                            taking a copy of its current state, in case this is needed for undo later.
3939                         */
3940                         lists[al] = AutomationRecord (&al->get_state ());
3941                 }
3942         }
3943
3944         if (op == Cut || op == Copy) {
3945                 /* This operation will involve putting things in the cut buffer, so create an empty
3946                    ControlList for each of our source lists to put the cut buffer data in.
3947                 */
3948                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3949                         i->second.copy = i->first->create (i->first->parameter ());
3950                 }
3951
3952                 /* Add all selected points to the relevant copy ControlLists */
3953                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3954                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3955                         AutomationList::const_iterator j = (*i)->model ();
3956                         lists[al].copy->add ((*j)->when, (*j)->value);
3957                 }
3958
3959                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3960                         /* Correct this copy list so that it starts at time 0 */
3961                         double const start = i->second.copy->front()->when;
3962                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3963                                 (*j)->when -= start;
3964                         }
3965
3966                         /* And add it to the cut buffer */
3967                         cut_buffer->add (i->second.copy);
3968                 }
3969         }
3970                 
3971         if (op == Delete || op == Cut) {
3972                 /* This operation needs to remove things from the main AutomationList, so do that now */
3973                 
3974                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3975                         i->first->freeze ();
3976                 }
3977
3978                 /* Remove each selected point from its AutomationList */
3979                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3980                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3981                         al->erase ((*i)->model ());
3982                 }
3983
3984                 /* Thaw the lists and add undo records for them */
3985                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3986                         boost::shared_ptr<AutomationList> al = i->first;
3987                         al->thaw ();
3988                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3989                 }
3990         }
3991 }
3992
3993 /** Cut, copy or clear selected automation points.
3994  * @param op Operation (Cut, Copy or Clear)
3995  */
3996 void
3997 Editor::cut_copy_midi (CutCopyOp op)
3998 {
3999         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4000                 MidiRegionView* mrv = *i;
4001                 mrv->cut_copy_clear (op);
4002         }
4003 }
4004
4005
4006
4007 struct lt_playlist {
4008     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4009             return a.playlist < b.playlist;
4010     }
4011 };
4012
4013 struct PlaylistMapping {
4014     TimeAxisView* tv;
4015     boost::shared_ptr<Playlist> pl;
4016
4017     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4018 };
4019
4020 /** Remove `clicked_regionview' */
4021 void
4022 Editor::remove_clicked_region ()
4023 {
4024         if (clicked_routeview == 0 || clicked_regionview == 0) {
4025                 return;
4026         }
4027
4028         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4029
4030         playlist->clear_changes ();
4031         playlist->clear_owned_changes ();
4032         playlist->remove_region (clicked_regionview->region());
4033         if (Config->get_edit_mode() == Ripple)
4034                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4035
4036         /* We might have removed regions, which alters other regions' layering_index,
4037            so we need to do a recursive diff here.
4038         */
4039         vector<Command*> cmds;
4040         playlist->rdiff (cmds);
4041         _session->add_commands (cmds);
4042         
4043         _session->add_command(new StatefulDiffCommand (playlist));
4044         commit_reversible_command ();
4045 }
4046
4047
4048 /** Remove the selected regions */
4049 void
4050 Editor::remove_selected_regions ()
4051 {
4052         RegionSelection rs = get_regions_from_selection_and_entered ();
4053
4054         if (!_session || rs.empty()) {
4055                 return;
4056         }
4057
4058         begin_reversible_command (_("remove region"));
4059
4060         list<boost::shared_ptr<Region> > regions_to_remove;
4061
4062         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4063                 // we can't just remove the region(s) in this loop because
4064                 // this removes them from the RegionSelection, and they thus
4065                 // disappear from underneath the iterator, and the ++i above
4066                 // SEGVs in a puzzling fashion.
4067
4068                 // so, first iterate over the regions to be removed from rs and
4069                 // add them to the regions_to_remove list, and then
4070                 // iterate over the list to actually remove them.
4071
4072                 regions_to_remove.push_back ((*i)->region());
4073         }
4074
4075         vector<boost::shared_ptr<Playlist> > playlists;
4076
4077         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4078
4079                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4080
4081                 if (!playlist) {
4082                         // is this check necessary?
4083                         continue;
4084                 }
4085
4086                 /* get_regions_from_selection_and_entered() guarantees that
4087                    the playlists involved are unique, so there is no need
4088                    to check here.
4089                 */
4090
4091                 playlists.push_back (playlist);
4092
4093                 playlist->clear_changes ();
4094                 playlist->clear_owned_changes ();
4095                 playlist->freeze ();
4096                 playlist->remove_region (*rl);
4097                 if (Config->get_edit_mode() == Ripple)
4098                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4099
4100         }
4101
4102         vector<boost::shared_ptr<Playlist> >::iterator pl;
4103
4104         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4105                 (*pl)->thaw ();
4106
4107                 /* We might have removed regions, which alters other regions' layering_index,
4108                    so we need to do a recursive diff here.
4109                 */
4110                 vector<Command*> cmds;
4111                 (*pl)->rdiff (cmds);
4112                 _session->add_commands (cmds);
4113                 
4114                 _session->add_command(new StatefulDiffCommand (*pl));
4115         }
4116
4117         commit_reversible_command ();
4118 }
4119
4120 /** Cut, copy or clear selected regions.
4121  * @param op Operation (Cut, Copy or Clear)
4122  */
4123 void
4124 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4125 {
4126         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4127            a map when we want ordered access to both elements. i think.
4128         */
4129
4130         vector<PlaylistMapping> pmap;
4131
4132         framepos_t first_position = max_framepos;
4133
4134         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4135         FreezeList freezelist;
4136
4137         /* get ordering correct before we cut/copy */
4138
4139         rs.sort_by_position_and_track ();
4140
4141         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4142
4143                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4144
4145                 if (op == Cut || op == Clear || op == Delete) {
4146                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4147
4148                         if (pl) {
4149                                 FreezeList::iterator fl;
4150
4151                                 // only take state if this is a new playlist.
4152                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4153                                         if ((*fl) == pl) {
4154                                                 break;
4155                                         }
4156                                 }
4157
4158                                 if (fl == freezelist.end()) {
4159                                         pl->clear_changes();
4160                                         pl->clear_owned_changes ();
4161                                         pl->freeze ();
4162                                         freezelist.insert (pl);
4163                                 }
4164                         }
4165                 }
4166
4167                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4168                 vector<PlaylistMapping>::iterator z;
4169
4170                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4171                         if ((*z).tv == tv) {
4172                                 break;
4173                         }
4174                 }
4175
4176                 if (z == pmap.end()) {
4177                         pmap.push_back (PlaylistMapping (tv));
4178                 }
4179         }
4180
4181         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4182
4183                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4184
4185                 if (!pl) {
4186                         /* region not yet associated with a playlist (e.g. unfinished
4187                            capture pass.
4188                         */
4189                         ++x;
4190                         continue;
4191                 }
4192
4193                 TimeAxisView& tv = (*x)->get_time_axis_view();
4194                 boost::shared_ptr<Playlist> npl;
4195                 RegionSelection::iterator tmp;
4196
4197                 tmp = x;
4198                 ++tmp;
4199
4200                 if (op != Delete) {
4201
4202                         vector<PlaylistMapping>::iterator z;
4203                         
4204                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4205                                 if ((*z).tv == &tv) {
4206                                         break;
4207                                 }
4208                         }
4209                         
4210                         assert (z != pmap.end());
4211                         
4212                         if (!(*z).pl) {
4213                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4214                                 npl->freeze();
4215                                 (*z).pl = npl;
4216                         } else {
4217                                 npl = (*z).pl;
4218                         }
4219                 }
4220
4221                 boost::shared_ptr<Region> r = (*x)->region();
4222                 boost::shared_ptr<Region> _xx;
4223
4224                 assert (r != 0);
4225
4226                 switch (op) {
4227                 case Delete:
4228                         pl->remove_region (r);
4229                         if (Config->get_edit_mode() == Ripple)
4230                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4231                         break;
4232                         
4233                 case Cut:
4234                         _xx = RegionFactory::create (r);
4235                         npl->add_region (_xx, r->position() - first_position);
4236                         pl->remove_region (r);
4237                         if (Config->get_edit_mode() == Ripple)
4238                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4239                         break;
4240
4241                 case Copy:
4242                         /* copy region before adding, so we're not putting same object into two different playlists */
4243                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4244                         break;
4245
4246                 case Clear:
4247                         pl->remove_region (r);
4248                         if (Config->get_edit_mode() == Ripple)
4249                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4250                         break;
4251                 }
4252
4253                 x = tmp;
4254         }
4255
4256         if (op != Delete) {
4257
4258                 list<boost::shared_ptr<Playlist> > foo;
4259                 
4260                 /* the pmap is in the same order as the tracks in which selected regions occured */
4261                 
4262                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4263                         if ((*i).pl) {
4264                                 (*i).pl->thaw();
4265                                 foo.push_back ((*i).pl);
4266                         }
4267                 }
4268                 
4269                 if (!foo.empty()) {
4270                         cut_buffer->set (foo);
4271                 }
4272                 
4273                 if (pmap.empty()) {
4274                         _last_cut_copy_source_track = 0;
4275                 } else {
4276                         _last_cut_copy_source_track = pmap.front().tv;
4277                 }
4278         }
4279
4280         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4281                 (*pl)->thaw ();
4282
4283                 /* We might have removed regions, which alters other regions' layering_index,
4284                    so we need to do a recursive diff here.
4285                 */
4286                 vector<Command*> cmds;
4287                 (*pl)->rdiff (cmds);
4288                 _session->add_commands (cmds);
4289                 
4290                 _session->add_command (new StatefulDiffCommand (*pl));
4291         }
4292 }
4293
4294 void
4295 Editor::cut_copy_ranges (CutCopyOp op)
4296 {
4297         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4298
4299         /* Sort the track selection now, so that it if is used, the playlists
4300            selected by the calls below to cut_copy_clear are in the order that
4301            their tracks appear in the editor.  This makes things like paste
4302            of ranges work properly.
4303         */
4304
4305         sort_track_selection (ts);
4306
4307         if (ts.empty()) {
4308                 if (!entered_track) {
4309                         return;
4310                 }
4311                 ts.push_back (entered_track);
4312         } 
4313
4314         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4315                 (*i)->cut_copy_clear (*selection, op);
4316         }
4317 }
4318
4319 void
4320 Editor::paste (float times, bool from_context)
4321 {
4322         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4323
4324         paste_internal (get_preferred_edit_position (false, from_context), times);
4325 }
4326
4327 void
4328 Editor::mouse_paste ()
4329 {
4330         framepos_t where;
4331         bool ignored;
4332
4333         if (!mouse_frame (where, ignored)) {
4334                 return;
4335         }
4336
4337         snap_to (where);
4338         paste_internal (where, 1);
4339 }
4340
4341 void
4342 Editor::paste_internal (framepos_t position, float times)
4343 {
4344         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4345
4346         if (internal_editing()) {
4347                 if (cut_buffer->midi_notes.empty()) {
4348                         return;
4349                 }
4350         } else {
4351                 if (cut_buffer->empty()) {
4352                         return;
4353                 }
4354         }
4355
4356         if (position == max_framepos) {
4357                 position = get_preferred_edit_position();
4358                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4359         }
4360
4361         TrackViewList ts;
4362         TrackViewList::iterator i;
4363         size_t nth;
4364
4365         /* get everything in the correct order */
4366
4367         if (_edit_point == Editing::EditAtMouse && entered_track) {
4368                 /* With the mouse edit point, paste onto the track under the mouse */
4369                 ts.push_back (entered_track);
4370         } else if (!selection->tracks.empty()) {
4371                 /* Otherwise, if there are some selected tracks, paste to them */
4372                 ts = selection->tracks.filter_to_unique_playlists ();
4373                 sort_track_selection (ts);
4374         } else if (_last_cut_copy_source_track) {
4375                 /* Otherwise paste to the track that the cut/copy came from;
4376                    see discussion in mantis #3333.
4377                 */
4378                 ts.push_back (_last_cut_copy_source_track);
4379         }
4380
4381         if (internal_editing ()) {
4382
4383                 /* undo/redo is handled by individual tracks/regions */
4384
4385                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4386
4387                         RegionSelection rs;
4388                         RegionSelection::iterator r;
4389                         MidiNoteSelection::iterator cb;
4390
4391                         get_regions_at (rs, position, ts);
4392
4393                         for (cb = cut_buffer->midi_notes.begin(), r = rs.begin();
4394                              cb != cut_buffer->midi_notes.end() && r != rs.end(); ++r) {
4395                                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4396                                 if (mrv) {
4397                                         mrv->paste (position, times, **cb);
4398                                         ++cb;
4399                                 }
4400                         }
4401                 }
4402
4403         } else {
4404
4405                 /* we do redo (do you do voodoo?) */
4406
4407                 begin_reversible_command (Operations::paste);
4408
4409                 for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4410                         (*i)->paste (position, times, *cut_buffer, nth);
4411                 }
4412
4413                 commit_reversible_command ();
4414         }
4415 }
4416
4417 void
4418 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4419 {
4420         boost::shared_ptr<Playlist> playlist;
4421         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4422         RegionSelection foo;
4423
4424         framepos_t const start_frame = regions.start ();
4425         framepos_t const end_frame = regions.end_frame ();
4426
4427         begin_reversible_command (Operations::duplicate_region);
4428
4429         selection->clear_regions ();
4430
4431         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4432
4433                 boost::shared_ptr<Region> r ((*i)->region());
4434
4435                 TimeAxisView& tv = (*i)->get_time_axis_view();
4436                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4437                 latest_regionviews.clear ();
4438                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4439
4440                 playlist = (*i)->region()->playlist();
4441                 playlist->clear_changes ();
4442                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4443                 _session->add_command(new StatefulDiffCommand (playlist));
4444
4445                 c.disconnect ();
4446
4447                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4448         }
4449
4450         commit_reversible_command ();
4451
4452         if (!foo.empty()) {
4453                 selection->set (foo);
4454         }
4455 }
4456
4457 void
4458 Editor::duplicate_selection (float times)
4459 {
4460         if (selection->time.empty() || selection->tracks.empty()) {
4461                 return;
4462         }
4463
4464         boost::shared_ptr<Playlist> playlist;
4465         vector<boost::shared_ptr<Region> > new_regions;
4466         vector<boost::shared_ptr<Region> >::iterator ri;
4467
4468         create_region_from_selection (new_regions);
4469
4470         if (new_regions.empty()) {
4471                 return;
4472         }
4473
4474         begin_reversible_command (_("duplicate selection"));
4475
4476         ri = new_regions.begin();
4477
4478         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4479
4480         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4481                 if ((playlist = (*i)->playlist()) == 0) {
4482                         continue;
4483                 }
4484                 playlist->clear_changes ();
4485                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4486                 _session->add_command (new StatefulDiffCommand (playlist));
4487
4488                 ++ri;
4489                 if (ri == new_regions.end()) {
4490                         --ri;
4491                 }
4492         }
4493
4494         commit_reversible_command ();
4495 }
4496
4497 /** Reset all selected points to the relevant default value */
4498 void
4499 Editor::reset_point_selection ()
4500 {
4501         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4502                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4503                 (*j)->value = (*i)->line().the_list()->default_value ();
4504         }
4505 }
4506
4507 void
4508 Editor::center_playhead ()
4509 {
4510         float const page = _visible_canvas_width * samples_per_pixel;
4511         center_screen_internal (playhead_cursor->current_frame (), page);
4512 }
4513
4514 void
4515 Editor::center_edit_point ()
4516 {
4517         float const page = _visible_canvas_width * samples_per_pixel;
4518         center_screen_internal (get_preferred_edit_position(), page);
4519 }
4520
4521 /** Caller must begin and commit a reversible command */
4522 void
4523 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4524 {
4525         playlist->clear_changes ();
4526         playlist->clear ();
4527         _session->add_command (new StatefulDiffCommand (playlist));
4528 }
4529
4530 void
4531 Editor::nudge_track (bool use_edit, bool forwards)
4532 {
4533         boost::shared_ptr<Playlist> playlist;
4534         framepos_t distance;
4535         framepos_t next_distance;
4536         framepos_t start;
4537
4538         if (use_edit) {
4539                 start = get_preferred_edit_position();
4540         } else {
4541                 start = 0;
4542         }
4543
4544         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4545                 return;
4546         }
4547
4548         if (selection->tracks.empty()) {
4549                 return;
4550         }
4551
4552         begin_reversible_command (_("nudge track"));
4553
4554         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4555
4556         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4557
4558                 if ((playlist = (*i)->playlist()) == 0) {
4559                         continue;
4560                 }
4561
4562                 playlist->clear_changes ();
4563                 playlist->clear_owned_changes ();
4564
4565                 playlist->nudge_after (start, distance, forwards);
4566
4567                 vector<Command*> cmds;
4568
4569                 playlist->rdiff (cmds);
4570                 _session->add_commands (cmds);
4571
4572                 _session->add_command (new StatefulDiffCommand (playlist));
4573         }
4574
4575         commit_reversible_command ();
4576 }
4577
4578 void
4579 Editor::remove_last_capture ()
4580 {
4581         vector<string> choices;
4582         string prompt;
4583
4584         if (!_session) {
4585                 return;
4586         }
4587
4588         if (Config->get_verify_remove_last_capture()) {
4589                 prompt  = _("Do you really want to destroy the last capture?"
4590                             "\n(This is destructive and cannot be undone)");
4591
4592                 choices.push_back (_("No, do nothing."));
4593                 choices.push_back (_("Yes, destroy it."));
4594
4595                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4596
4597                 if (prompter.run () == 1) {
4598                         _session->remove_last_capture ();
4599                         _regions->redisplay ();
4600                 }
4601
4602         } else {
4603                 _session->remove_last_capture();
4604                 _regions->redisplay ();
4605         }
4606 }
4607
4608 void
4609 Editor::normalize_region ()
4610 {
4611         if (!_session) {
4612                 return;
4613         }
4614
4615         RegionSelection rs = get_regions_from_selection_and_entered ();
4616
4617         if (rs.empty()) {
4618                 return;
4619         }
4620
4621         NormalizeDialog dialog (rs.size() > 1);
4622
4623         if (dialog.run () == RESPONSE_CANCEL) {
4624                 return;
4625         }
4626
4627         set_canvas_cursor (_cursors->wait);
4628         gdk_flush ();
4629
4630         /* XXX: should really only count audio regions here */
4631         int const regions = rs.size ();
4632
4633         /* Make a list of the selected audio regions' maximum amplitudes, and also
4634            obtain the maximum amplitude of them all.
4635         */
4636         list<double> max_amps;
4637         double max_amp = 0;
4638         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4639                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4640                 if (arv) {
4641                         dialog.descend (1.0 / regions);
4642                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4643
4644                         if (a == -1) {
4645                                 /* the user cancelled the operation */
4646                                 set_canvas_cursor (current_canvas_cursor);
4647                                 return;
4648                         }
4649
4650                         max_amps.push_back (a);
4651                         max_amp = max (max_amp, a);
4652                         dialog.ascend ();
4653                 }
4654         }
4655
4656         begin_reversible_command (_("normalize"));
4657
4658         list<double>::const_iterator a = max_amps.begin ();
4659
4660         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4661                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4662                 if (!arv) {
4663                         continue;
4664                 }
4665
4666                 arv->region()->clear_changes ();
4667
4668                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4669
4670                 arv->audio_region()->normalize (amp, dialog.target ());
4671                 _session->add_command (new StatefulDiffCommand (arv->region()));
4672
4673                 ++a;
4674         }
4675
4676         commit_reversible_command ();
4677         set_canvas_cursor (current_canvas_cursor);
4678 }
4679
4680
4681 void
4682 Editor::reset_region_scale_amplitude ()
4683 {
4684         if (!_session) {
4685                 return;
4686         }
4687
4688         RegionSelection rs = get_regions_from_selection_and_entered ();
4689
4690         if (rs.empty()) {
4691                 return;
4692         }
4693
4694         begin_reversible_command ("reset gain");
4695
4696         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4697                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4698                 if (!arv)
4699                         continue;
4700                 arv->region()->clear_changes ();
4701                 arv->audio_region()->set_scale_amplitude (1.0f);
4702                 _session->add_command (new StatefulDiffCommand (arv->region()));
4703         }
4704
4705         commit_reversible_command ();
4706 }
4707
4708 void
4709 Editor::adjust_region_gain (bool up)
4710 {
4711         RegionSelection rs = get_regions_from_selection_and_entered ();
4712
4713         if (!_session || rs.empty()) {
4714                 return;
4715         }
4716
4717         begin_reversible_command ("adjust region gain");
4718
4719         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4720                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4721                 if (!arv) {
4722                         continue;
4723                 }
4724
4725                 arv->region()->clear_changes ();
4726
4727                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4728
4729                 if (up) {
4730                         dB += 1;
4731                 } else {
4732                         dB -= 1;
4733                 }
4734
4735                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4736                 _session->add_command (new StatefulDiffCommand (arv->region()));
4737         }
4738
4739         commit_reversible_command ();
4740 }
4741
4742
4743 void
4744 Editor::reverse_region ()
4745 {
4746         if (!_session) {
4747                 return;
4748         }
4749
4750         Reverse rev (*_session);
4751         apply_filter (rev, _("reverse regions"));
4752 }
4753
4754 void
4755 Editor::strip_region_silence ()
4756 {
4757         if (!_session) {
4758                 return;
4759         }
4760
4761         RegionSelection rs = get_regions_from_selection_and_entered ();
4762
4763         if (rs.empty()) {
4764                 return;
4765         }
4766
4767         std::list<RegionView*> audio_only;
4768
4769         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4770                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4771                 if (arv) {
4772                         audio_only.push_back (arv);
4773                 }
4774         }
4775
4776         StripSilenceDialog d (_session, audio_only);
4777         int const r = d.run ();
4778
4779         d.drop_rects ();
4780
4781         if (r == Gtk::RESPONSE_OK) {
4782                 ARDOUR::AudioIntervalMap silences;
4783                 d.silences (silences);
4784                 StripSilence s (*_session, silences, d.fade_length());
4785                 apply_filter (s, _("strip silence"), &d);
4786         }
4787 }
4788
4789 Command*
4790 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4791 {
4792         Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4793         mrv.selection_as_notelist (selected, true);
4794
4795         vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4796         v.push_back (selected);
4797
4798         framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4799         double     pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4800
4801         return op (mrv.midi_region()->model(), pos_beats, v);
4802 }
4803
4804 void
4805 Editor::apply_midi_note_edit_op (MidiOperator& op)
4806 {
4807         Command* cmd;
4808
4809         RegionSelection rs = get_regions_from_selection_and_entered ();
4810
4811         if (rs.empty()) {
4812                 return;
4813         }
4814
4815         begin_reversible_command (op.name ());
4816
4817         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4818                 RegionSelection::iterator tmp = r;
4819                 ++tmp;
4820
4821                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4822
4823                 if (mrv) {
4824                         cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4825                         if (cmd) {
4826                                 (*cmd)();
4827                                 _session->add_command (cmd);
4828                         }
4829                 }
4830
4831                 r = tmp;
4832         }
4833
4834         commit_reversible_command ();
4835 }
4836
4837 void
4838 Editor::fork_region ()
4839 {
4840         RegionSelection rs = get_regions_from_selection_and_entered ();
4841
4842         if (rs.empty()) {
4843                 return;
4844         }
4845
4846         begin_reversible_command (_("Fork Region(s)"));
4847
4848         set_canvas_cursor (_cursors->wait);
4849         gdk_flush ();
4850
4851         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4852                 RegionSelection::iterator tmp = r;
4853                 ++tmp;
4854
4855                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4856
4857                 if (mrv) {
4858                         try {
4859                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4860                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4861                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4862                                 
4863                                 playlist->clear_changes ();
4864                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4865                                 _session->add_command(new StatefulDiffCommand (playlist));
4866                         } catch (...) {
4867                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4868                         }
4869                 }
4870
4871                 r = tmp;
4872         }
4873
4874         commit_reversible_command ();
4875
4876         set_canvas_cursor (current_canvas_cursor);
4877 }
4878
4879 void
4880 Editor::quantize_region ()
4881 {
4882         int selected_midi_region_cnt = 0;
4883
4884         if (!_session) {
4885                 return;
4886         }
4887
4888         RegionSelection rs = get_regions_from_selection_and_entered ();
4889
4890         if (rs.empty()) {
4891                 return;
4892         }
4893
4894         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4895                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4896                 if (mrv) {
4897                         selected_midi_region_cnt++;
4898                 }
4899         }
4900
4901         if (selected_midi_region_cnt == 0) {
4902                 return;
4903         }
4904
4905         QuantizeDialog* qd = new QuantizeDialog (*this);
4906
4907         qd->present ();
4908         const int r = qd->run ();
4909         qd->hide ();
4910
4911         if (r == Gtk::RESPONSE_OK) {
4912                 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4913                                 qd->start_grid_size(), qd->end_grid_size(),
4914                                 qd->strength(), qd->swing(), qd->threshold());
4915
4916                 apply_midi_note_edit_op (quant);
4917         }
4918 }
4919
4920 void
4921 Editor::insert_patch_change (bool from_context)
4922 {
4923         RegionSelection rs = get_regions_from_selection_and_entered ();
4924
4925         if (rs.empty ()) {
4926                 return;
4927         }
4928
4929         const framepos_t p = get_preferred_edit_position (false, from_context);
4930
4931         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4932            there may be more than one, but the PatchChangeDialog can only offer
4933            one set of patch menus.
4934         */
4935         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4936
4937         Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4938         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4939
4940         if (d.run() == RESPONSE_CANCEL) {
4941                 return;
4942         }
4943
4944         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4945                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
4946                 if (mrv) {
4947                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
4948                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
4949                         }
4950                 }
4951         }
4952 }
4953
4954 void
4955 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
4956 {
4957         RegionSelection rs = get_regions_from_selection_and_entered ();
4958
4959         if (rs.empty()) {
4960                 return;
4961         }
4962
4963         begin_reversible_command (command);
4964
4965         set_canvas_cursor (_cursors->wait);
4966         gdk_flush ();
4967
4968         int n = 0;
4969         int const N = rs.size ();
4970
4971         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4972                 RegionSelection::iterator tmp = r;
4973                 ++tmp;
4974
4975                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4976                 if (arv) {
4977                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4978
4979                         if (progress) {
4980                                 progress->descend (1.0 / N);
4981                         }
4982
4983                         if (arv->audio_region()->apply (filter, progress) == 0) {
4984
4985                                 playlist->clear_changes ();
4986                                 playlist->clear_owned_changes ();
4987
4988                                 if (filter.results.empty ()) {
4989
4990                                         /* no regions returned; remove the old one */
4991                                         playlist->remove_region (arv->region ());
4992
4993                                 } else {
4994
4995                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4996
4997                                         /* first region replaces the old one */
4998                                         playlist->replace_region (arv->region(), *res, (*res)->position());
4999                                         ++res;
5000
5001                                         /* add the rest */
5002                                         while (res != filter.results.end()) {
5003                                                 playlist->add_region (*res, (*res)->position());
5004                                                 ++res;
5005                                         }
5006
5007                                 }
5008
5009                                 /* We might have removed regions, which alters other regions' layering_index,
5010                                    so we need to do a recursive diff here.
5011                                 */
5012                                 vector<Command*> cmds;
5013                                 playlist->rdiff (cmds);
5014                                 _session->add_commands (cmds);
5015                                 
5016                                 _session->add_command(new StatefulDiffCommand (playlist));
5017                         } else {
5018                                 goto out;
5019                         }
5020
5021                         if (progress) {
5022                                 progress->ascend ();
5023                         }
5024                 }
5025
5026                 r = tmp;
5027                 ++n;
5028         }
5029
5030         commit_reversible_command ();
5031
5032   out:
5033         set_canvas_cursor (current_canvas_cursor);
5034 }
5035
5036 void
5037 Editor::external_edit_region ()
5038 {
5039         /* more to come */
5040 }
5041
5042 void
5043 Editor::reset_region_gain_envelopes ()
5044 {
5045         RegionSelection rs = get_regions_from_selection_and_entered ();
5046
5047         if (!_session || rs.empty()) {
5048                 return;
5049         }
5050
5051         _session->begin_reversible_command (_("reset region gain"));
5052
5053         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5054                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5055                 if (arv) {
5056                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5057                         XMLNode& before (alist->get_state());
5058
5059                         arv->audio_region()->set_default_envelope ();
5060                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5061                 }
5062         }
5063
5064         _session->commit_reversible_command ();
5065 }
5066
5067 void
5068 Editor::set_region_gain_visibility (RegionView* rv)
5069 {
5070         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5071         if (arv) {
5072                 arv->update_envelope_visibility();
5073         }
5074 }
5075
5076 void
5077 Editor::set_gain_envelope_visibility ()
5078 {
5079         if (!_session) {
5080                 return;
5081         }
5082
5083         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5084                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5085                 if (v) {
5086                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5087                 }
5088         }
5089 }
5090
5091 void
5092 Editor::toggle_gain_envelope_active ()
5093 {
5094         if (_ignore_region_action) {
5095                 return;
5096         }
5097
5098         RegionSelection rs = get_regions_from_selection_and_entered ();
5099
5100         if (!_session || rs.empty()) {
5101                 return;
5102         }
5103
5104         _session->begin_reversible_command (_("region gain envelope active"));
5105
5106         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5107                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5108                 if (arv) {
5109                         arv->region()->clear_changes ();
5110                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5111                         _session->add_command (new StatefulDiffCommand (arv->region()));
5112                 }
5113         }
5114
5115         _session->commit_reversible_command ();
5116 }
5117
5118 void
5119 Editor::toggle_region_lock ()
5120 {
5121         if (_ignore_region_action) {
5122                 return;
5123         }
5124
5125         RegionSelection rs = get_regions_from_selection_and_entered ();
5126
5127         if (!_session || rs.empty()) {
5128                 return;
5129         }
5130
5131         _session->begin_reversible_command (_("toggle region lock"));
5132
5133         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5134                 (*i)->region()->clear_changes ();
5135                 (*i)->region()->set_locked (!(*i)->region()->locked());
5136                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5137         }
5138
5139         _session->commit_reversible_command ();
5140 }
5141
5142 void
5143 Editor::toggle_region_video_lock ()
5144 {
5145         if (_ignore_region_action) {
5146                 return;
5147         }
5148
5149         RegionSelection rs = get_regions_from_selection_and_entered ();
5150
5151         if (!_session || rs.empty()) {
5152                 return;
5153         }
5154
5155         _session->begin_reversible_command (_("Toggle Video Lock"));
5156
5157         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5158                 (*i)->region()->clear_changes ();
5159                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5160                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5161         }
5162
5163         _session->commit_reversible_command ();
5164 }
5165
5166 void
5167 Editor::toggle_region_lock_style ()
5168 {
5169         if (_ignore_region_action) {
5170                 return;
5171         }
5172
5173         RegionSelection rs = get_regions_from_selection_and_entered ();
5174
5175         if (!_session || rs.empty()) {
5176                 return;
5177         }
5178
5179         _session->begin_reversible_command (_("region lock style"));
5180
5181         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5182                 (*i)->region()->clear_changes ();
5183                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5184                 (*i)->region()->set_position_lock_style (ns);
5185                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5186         }
5187
5188         _session->commit_reversible_command ();
5189 }
5190
5191 void
5192 Editor::toggle_opaque_region ()
5193 {
5194         if (_ignore_region_action) {
5195                 return;
5196         }
5197
5198         RegionSelection rs = get_regions_from_selection_and_entered ();
5199
5200         if (!_session || rs.empty()) {
5201                 return;
5202         }
5203
5204         _session->begin_reversible_command (_("change region opacity"));
5205
5206         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5207                 (*i)->region()->clear_changes ();
5208                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5209                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5210         }
5211
5212         _session->commit_reversible_command ();
5213 }
5214
5215 void
5216 Editor::toggle_record_enable ()
5217 {
5218         bool new_state = false;
5219         bool first = true;
5220         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5221                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5222                 if (!rtav)
5223                         continue;
5224                 if (!rtav->is_track())
5225                         continue;
5226
5227                 if (first) {
5228                         new_state = !rtav->track()->record_enabled();
5229                         first = false;
5230                 }
5231
5232                 rtav->track()->set_record_enabled (new_state, this);
5233         }
5234 }
5235
5236 void
5237 Editor::toggle_solo ()
5238 {
5239         bool new_state = false;
5240         bool first = true;
5241         boost::shared_ptr<RouteList> rl (new RouteList);
5242
5243         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5244                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5245
5246                 if (!rtav) {
5247                         continue;
5248                 }
5249
5250                 if (first) {
5251                         new_state = !rtav->route()->soloed ();
5252                         first = false;
5253                 }
5254
5255                 rl->push_back (rtav->route());
5256         }
5257
5258         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5259 }
5260
5261 void
5262 Editor::toggle_mute ()
5263 {
5264         bool new_state = false;
5265         bool first = true;
5266         boost::shared_ptr<RouteList> rl (new RouteList);
5267
5268         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5269                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5270
5271                 if (!rtav) {
5272                         continue;
5273                 }
5274
5275                 if (first) {
5276                         new_state = !rtav->route()->muted();
5277                         first = false;
5278                 }
5279
5280                 rl->push_back (rtav->route());
5281         }
5282
5283         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5284 }
5285
5286 void
5287 Editor::toggle_solo_isolate ()
5288 {
5289 }
5290
5291
5292 void
5293 Editor::fade_range ()
5294 {
5295         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5296
5297         begin_reversible_command (_("fade range"));
5298
5299         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5300                 (*i)->fade_range (selection->time);
5301         }
5302
5303         commit_reversible_command ();
5304 }
5305
5306
5307 void
5308 Editor::set_fade_length (bool in)
5309 {
5310         RegionSelection rs = get_regions_from_selection_and_entered ();
5311
5312         if (rs.empty()) {
5313                 return;
5314         }
5315
5316         /* we need a region to measure the offset from the start */
5317
5318         RegionView* rv = rs.front ();
5319
5320         framepos_t pos = get_preferred_edit_position();
5321         framepos_t len;
5322         char const * cmd;
5323
5324         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5325                 /* edit point is outside the relevant region */
5326                 return;
5327         }
5328
5329         if (in) {
5330                 if (pos <= rv->region()->position()) {
5331                         /* can't do it */
5332                         return;
5333                 }
5334                 len = pos - rv->region()->position();
5335                 cmd = _("set fade in length");
5336         } else {
5337                 if (pos >= rv->region()->last_frame()) {
5338                         /* can't do it */
5339                         return;
5340                 }
5341                 len = rv->region()->last_frame() - pos;
5342                 cmd = _("set fade out length");
5343         }
5344
5345         begin_reversible_command (cmd);
5346
5347         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5348                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5349
5350                 if (!tmp) {
5351                         return;
5352                 }
5353
5354                 boost::shared_ptr<AutomationList> alist;
5355                 if (in) {
5356                         alist = tmp->audio_region()->fade_in();
5357                 } else {
5358                         alist = tmp->audio_region()->fade_out();
5359                 }
5360
5361                 XMLNode &before = alist->get_state();
5362
5363                 if (in) {
5364                         tmp->audio_region()->set_fade_in_length (len);
5365                         tmp->audio_region()->set_fade_in_active (true);
5366                 } else {
5367                         tmp->audio_region()->set_fade_out_length (len);
5368                         tmp->audio_region()->set_fade_out_active (true);
5369                 }
5370
5371                 XMLNode &after = alist->get_state();
5372                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5373         }
5374
5375         commit_reversible_command ();
5376 }
5377
5378 void
5379 Editor::set_fade_in_shape (FadeShape shape)
5380 {
5381         RegionSelection rs = get_regions_from_selection_and_entered ();
5382
5383         if (rs.empty()) {
5384                 return;
5385         }
5386
5387         begin_reversible_command (_("set fade in shape"));
5388
5389         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5390                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5391
5392                 if (!tmp) {
5393                         return;
5394                 }
5395
5396                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5397                 XMLNode &before = alist->get_state();
5398
5399                 tmp->audio_region()->set_fade_in_shape (shape);
5400
5401                 XMLNode &after = alist->get_state();
5402                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5403         }
5404
5405         commit_reversible_command ();
5406
5407 }
5408
5409 void
5410 Editor::set_fade_out_shape (FadeShape shape)
5411 {
5412         RegionSelection rs = get_regions_from_selection_and_entered ();
5413
5414         if (rs.empty()) {
5415                 return;
5416         }
5417
5418         begin_reversible_command (_("set fade out shape"));
5419
5420         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5421                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5422
5423                 if (!tmp) {
5424                         return;
5425                 }
5426
5427                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5428                 XMLNode &before = alist->get_state();
5429
5430                 tmp->audio_region()->set_fade_out_shape (shape);
5431
5432                 XMLNode &after = alist->get_state();
5433                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5434         }
5435
5436         commit_reversible_command ();
5437 }
5438
5439 void
5440 Editor::set_fade_in_active (bool yn)
5441 {
5442         RegionSelection rs = get_regions_from_selection_and_entered ();
5443
5444         if (rs.empty()) {
5445                 return;
5446         }
5447
5448         begin_reversible_command (_("set fade in active"));
5449
5450         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5451                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5452
5453                 if (!tmp) {
5454                         return;
5455                 }
5456
5457
5458                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5459
5460                 ar->clear_changes ();
5461                 ar->set_fade_in_active (yn);
5462                 _session->add_command (new StatefulDiffCommand (ar));
5463         }
5464
5465         commit_reversible_command ();
5466 }
5467
5468 void
5469 Editor::set_fade_out_active (bool yn)
5470 {
5471         RegionSelection rs = get_regions_from_selection_and_entered ();
5472
5473         if (rs.empty()) {
5474                 return;
5475         }
5476
5477         begin_reversible_command (_("set fade out active"));
5478
5479         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5480                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5481
5482                 if (!tmp) {
5483                         return;
5484                 }
5485
5486                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5487
5488                 ar->clear_changes ();
5489                 ar->set_fade_out_active (yn);
5490                 _session->add_command(new StatefulDiffCommand (ar));
5491         }
5492
5493         commit_reversible_command ();
5494 }
5495
5496 void
5497 Editor::toggle_region_fades (int dir)
5498 {
5499         if (_ignore_region_action) {
5500                 return;
5501         }
5502         
5503         boost::shared_ptr<AudioRegion> ar;
5504         bool yn = false;
5505
5506         RegionSelection rs = get_regions_from_selection_and_entered ();
5507
5508         if (rs.empty()) {
5509                 return;
5510         }
5511
5512         RegionSelection::iterator i;
5513         for (i = rs.begin(); i != rs.end(); ++i) {
5514                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5515                         if (dir == -1) {
5516                                 yn = ar->fade_out_active ();
5517                         } else {
5518                                 yn = ar->fade_in_active ();
5519                         }
5520                         break;
5521                 }
5522         }
5523
5524         if (i == rs.end()) {
5525                 return;
5526         }
5527
5528         /* XXX should this undo-able? */
5529
5530         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5531                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5532                         continue;
5533                 }
5534                 if (dir == 1 || dir == 0) {
5535                         ar->set_fade_in_active (!yn);
5536                 }
5537
5538                 if (dir == -1 || dir == 0) {
5539                         ar->set_fade_out_active (!yn);
5540                 }
5541         }
5542 }
5543
5544
5545 /** Update region fade visibility after its configuration has been changed */
5546 void
5547 Editor::update_region_fade_visibility ()
5548 {
5549         bool _fade_visibility = _session->config.get_show_region_fades ();
5550
5551         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5552                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5553                 if (v) {
5554                         if (_fade_visibility) {
5555                                 v->audio_view()->show_all_fades ();
5556                         } else {
5557                                 v->audio_view()->hide_all_fades ();
5558                         }
5559                 }
5560         }
5561 }
5562
5563 void
5564 Editor::set_edit_point ()
5565 {
5566         framepos_t where;
5567         bool ignored;
5568
5569         if (!mouse_frame (where, ignored)) {
5570                 return;
5571         }
5572
5573         snap_to (where);
5574
5575         if (selection->markers.empty()) {
5576
5577                 mouse_add_new_marker (where);
5578
5579         } else {
5580                 bool ignored;
5581
5582                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5583
5584                 if (loc) {
5585                         loc->move_to (where);
5586                 }
5587         }
5588 }
5589
5590 void
5591 Editor::set_playhead_cursor ()
5592 {
5593         if (entered_marker) {
5594                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5595         } else {
5596                 framepos_t where;
5597                 bool ignored;
5598
5599                 if (!mouse_frame (where, ignored)) {
5600                         return;
5601                 }
5602
5603                 snap_to (where);
5604
5605                 if (_session) {
5606                         _session->request_locate (where, _session->transport_rolling());
5607                 }
5608         }
5609
5610         if ( Config->get_follow_edits() )
5611                 cancel_time_selection();
5612 }
5613
5614 void
5615 Editor::split_region ()
5616 {
5617         if ( !selection->time.empty()) {
5618                 separate_regions_between (selection->time);
5619                 return;
5620         }
5621
5622         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5623
5624         framepos_t where = get_preferred_edit_position ();
5625
5626         if (rs.empty()) {
5627                 return;
5628         }
5629
5630         split_regions_at (where, rs);
5631 }
5632
5633 struct EditorOrderRouteSorter {
5634     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5635             return a->order_key () < b->order_key ();
5636     }
5637 };
5638
5639 void
5640 Editor::select_next_route()
5641 {
5642         if (selection->tracks.empty()) {
5643                 selection->set (track_views.front());
5644                 return;
5645         }
5646
5647         TimeAxisView* current = selection->tracks.front();
5648
5649         RouteUI *rui;
5650         do {
5651                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5652                         if (*i == current) {
5653                                 ++i;
5654                                 if (i != track_views.end()) {
5655                                         current = (*i);
5656                                 } else {
5657                                         current = (*(track_views.begin()));
5658                                         //selection->set (*(track_views.begin()));
5659                                 }
5660                                 break;
5661                         }
5662                 }
5663                 rui = dynamic_cast<RouteUI *>(current);
5664         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5665
5666         selection->set(current);
5667
5668         ensure_time_axis_view_is_visible (*current, false);
5669 }
5670
5671 void
5672 Editor::select_prev_route()
5673 {
5674         if (selection->tracks.empty()) {
5675                 selection->set (track_views.front());
5676                 return;
5677         }
5678
5679         TimeAxisView* current = selection->tracks.front();
5680
5681         RouteUI *rui;
5682         do {
5683                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5684                         if (*i == current) {
5685                                 ++i;
5686                                 if (i != track_views.rend()) {
5687                                         current = (*i);
5688                                 } else {
5689                                         current = *(track_views.rbegin());
5690                                 }
5691                                 break;
5692                         }
5693                 }
5694                 rui = dynamic_cast<RouteUI *>(current);
5695         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5696
5697         selection->set (current);
5698
5699         ensure_time_axis_view_is_visible (*current, false);
5700 }
5701
5702 void
5703 Editor::set_loop_from_selection (bool play)
5704 {
5705         if (_session == 0 || selection->time.empty()) {
5706                 return;
5707         }
5708
5709         framepos_t start = selection->time[clicked_selection].start;
5710         framepos_t end = selection->time[clicked_selection].end;
5711
5712         set_loop_range (start, end,  _("set loop range from selection"));
5713
5714         if (play) {
5715                 _session->request_play_loop (true);
5716                 _session->request_locate (start, true);
5717         }
5718 }
5719
5720 void
5721 Editor::set_loop_from_edit_range (bool play)
5722 {
5723         if (_session == 0) {
5724                 return;
5725         }
5726
5727         framepos_t start;
5728         framepos_t end;
5729
5730         if (!get_edit_op_range (start, end)) {
5731                 return;
5732         }
5733
5734         set_loop_range (start, end,  _("set loop range from edit range"));
5735
5736         if (play) {
5737                 _session->request_play_loop (true);
5738                 _session->request_locate (start, true);
5739         }
5740 }
5741
5742 void
5743 Editor::set_loop_from_region (bool play)
5744 {
5745         framepos_t start = max_framepos;
5746         framepos_t end = 0;
5747
5748         RegionSelection rs = get_regions_from_selection_and_entered ();
5749
5750         if (rs.empty()) {
5751                 return;
5752         }
5753
5754         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5755                 if ((*i)->region()->position() < start) {
5756                         start = (*i)->region()->position();
5757                 }
5758                 if ((*i)->region()->last_frame() + 1 > end) {
5759                         end = (*i)->region()->last_frame() + 1;
5760                 }
5761         }
5762
5763         set_loop_range (start, end, _("set loop range from region"));
5764
5765         if (play) {
5766                 _session->request_play_loop (true);
5767                 _session->request_locate (start, true);
5768         }
5769 }
5770
5771 void
5772 Editor::set_punch_from_selection ()
5773 {
5774         if (_session == 0 || selection->time.empty()) {
5775                 return;
5776         }
5777
5778         framepos_t start = selection->time[clicked_selection].start;
5779         framepos_t end = selection->time[clicked_selection].end;
5780
5781         set_punch_range (start, end,  _("set punch range from selection"));
5782 }
5783
5784 void
5785 Editor::set_punch_from_edit_range ()
5786 {
5787         if (_session == 0) {
5788                 return;
5789         }
5790
5791         framepos_t start;
5792         framepos_t end;
5793
5794         if (!get_edit_op_range (start, end)) {
5795                 return;
5796         }
5797
5798         set_punch_range (start, end,  _("set punch range from edit range"));
5799 }
5800
5801 void
5802 Editor::set_punch_from_region ()
5803 {
5804         framepos_t start = max_framepos;
5805         framepos_t end = 0;
5806
5807         RegionSelection rs = get_regions_from_selection_and_entered ();
5808
5809         if (rs.empty()) {
5810                 return;
5811         }
5812
5813         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5814                 if ((*i)->region()->position() < start) {
5815                         start = (*i)->region()->position();
5816                 }
5817                 if ((*i)->region()->last_frame() + 1 > end) {
5818                         end = (*i)->region()->last_frame() + 1;
5819                 }
5820         }
5821
5822         set_punch_range (start, end, _("set punch range from region"));
5823 }
5824
5825 void
5826 Editor::pitch_shift_region ()
5827 {
5828         RegionSelection rs = get_regions_from_selection_and_entered ();
5829
5830         RegionSelection audio_rs;
5831         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5832                 if (dynamic_cast<AudioRegionView*> (*i)) {
5833                         audio_rs.push_back (*i);
5834                 }
5835         }
5836
5837         if (audio_rs.empty()) {
5838                 return;
5839         }
5840
5841         pitch_shift (audio_rs, 1.2);
5842 }
5843
5844 void
5845 Editor::transpose_region ()
5846 {
5847         RegionSelection rs = get_regions_from_selection_and_entered ();
5848
5849         list<MidiRegionView*> midi_region_views;
5850         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5851                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5852                 if (mrv) {
5853                         midi_region_views.push_back (mrv);
5854                 }
5855         }
5856
5857         TransposeDialog d;
5858         int const r = d.run ();
5859         if (r != RESPONSE_ACCEPT) {
5860                 return;
5861         }
5862
5863         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5864                 (*i)->midi_region()->transpose (d.semitones ());
5865         }
5866 }
5867
5868 void
5869 Editor::set_tempo_from_region ()
5870 {
5871         RegionSelection rs = get_regions_from_selection_and_entered ();
5872
5873         if (!_session || rs.empty()) {
5874                 return;
5875         }
5876
5877         RegionView* rv = rs.front();
5878
5879         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5880 }
5881
5882 void
5883 Editor::use_range_as_bar ()
5884 {
5885         framepos_t start, end;
5886         if (get_edit_op_range (start, end)) {
5887                 define_one_bar (start, end);
5888         }
5889 }
5890
5891 void
5892 Editor::define_one_bar (framepos_t start, framepos_t end)
5893 {
5894         framepos_t length = end - start;
5895
5896         const Meter& m (_session->tempo_map().meter_at (start));
5897
5898         /* length = 1 bar */
5899
5900         /* now we want frames per beat.
5901            we have frames per bar, and beats per bar, so ...
5902         */
5903
5904         /* XXXX METER MATH */
5905
5906         double frames_per_beat = length / m.divisions_per_bar();
5907
5908         /* beats per minute = */
5909
5910         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5911
5912         /* now decide whether to:
5913
5914             (a) set global tempo
5915             (b) add a new tempo marker
5916
5917         */
5918
5919         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5920
5921         bool do_global = false;
5922
5923         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5924
5925                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5926                    at the start, or create a new marker
5927                 */
5928
5929                 vector<string> options;
5930                 options.push_back (_("Cancel"));
5931                 options.push_back (_("Add new marker"));
5932                 options.push_back (_("Set global tempo"));
5933
5934                 Choice c (
5935                         _("Define one bar"),
5936                         _("Do you want to set the global tempo or add a new tempo marker?"),
5937                         options
5938                         );
5939
5940                 c.set_default_response (2);
5941
5942                 switch (c.run()) {
5943                 case 0:
5944                         return;
5945
5946                 case 2:
5947                         do_global = true;
5948                         break;
5949
5950                 default:
5951                         do_global = false;
5952                 }
5953
5954         } else {
5955
5956                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5957                    if the marker is at the region starter, change it, otherwise add
5958                    a new tempo marker
5959                 */
5960         }
5961
5962         begin_reversible_command (_("set tempo from region"));
5963         XMLNode& before (_session->tempo_map().get_state());
5964
5965         if (do_global) {
5966                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5967         } else if (t.frame() == start) {
5968                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5969         } else {
5970                 Timecode::BBT_Time bbt;
5971                 _session->tempo_map().bbt_time (start, bbt);
5972                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
5973         }
5974
5975         XMLNode& after (_session->tempo_map().get_state());
5976
5977         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
5978         commit_reversible_command ();
5979 }
5980
5981 void
5982 Editor::split_region_at_transients ()
5983 {
5984         AnalysisFeatureList positions;
5985
5986         RegionSelection rs = get_regions_from_selection_and_entered ();
5987
5988         if (!_session || rs.empty()) {
5989                 return;
5990         }
5991
5992         _session->begin_reversible_command (_("split regions"));
5993
5994         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5995
5996                 RegionSelection::iterator tmp;
5997
5998                 tmp = i;
5999                 ++tmp;
6000
6001                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6002
6003                 if (ar && (ar->get_transients (positions) == 0)) {
6004                         split_region_at_points ((*i)->region(), positions, true);
6005                         positions.clear ();
6006                 }
6007
6008                 i = tmp;
6009         }
6010
6011         _session->commit_reversible_command ();
6012
6013 }
6014
6015 void
6016 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6017 {
6018         bool use_rhythmic_rodent = false;
6019
6020         boost::shared_ptr<Playlist> pl = r->playlist();
6021
6022         list<boost::shared_ptr<Region> > new_regions;
6023
6024         if (!pl) {
6025                 return;
6026         }
6027
6028         if (positions.empty()) {
6029                 return;
6030         }
6031
6032
6033         if (positions.size() > 20 && can_ferret) {
6034                 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);
6035                 MessageDialog msg (msgstr,
6036                                    false,
6037                                    Gtk::MESSAGE_INFO,
6038                                    Gtk::BUTTONS_OK_CANCEL);
6039
6040                 if (can_ferret) {
6041                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6042                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6043                 } else {
6044                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6045                 }
6046
6047                 msg.set_title (_("Excessive split?"));
6048                 msg.present ();
6049
6050                 int response = msg.run();
6051                 msg.hide ();
6052
6053                 switch (response) {
6054                 case RESPONSE_OK:
6055                         break;
6056                 case RESPONSE_APPLY:
6057                         use_rhythmic_rodent = true;
6058                         break;
6059                 default:
6060                         return;
6061                 }
6062         }
6063
6064         if (use_rhythmic_rodent) {
6065                 show_rhythm_ferret ();
6066                 return;
6067         }
6068
6069         AnalysisFeatureList::const_iterator x;
6070
6071         pl->clear_changes ();
6072         pl->clear_owned_changes ();
6073
6074         x = positions.begin();
6075
6076         if (x == positions.end()) {
6077                 return;
6078         }
6079
6080         pl->freeze ();
6081         pl->remove_region (r);
6082
6083         framepos_t pos = 0;
6084
6085         while (x != positions.end()) {
6086
6087                 /* deal with positons that are out of scope of present region bounds */
6088                 if (*x <= 0 || *x > r->length()) {
6089                         ++x;
6090                         continue;
6091                 }
6092
6093                 /* file start = original start + how far we from the initial position ?
6094                  */
6095
6096                 framepos_t file_start = r->start() + pos;
6097
6098                 /* length = next position - current position
6099                  */
6100
6101                 framepos_t len = (*x) - pos;
6102
6103                 /* XXX we do we really want to allow even single-sample regions?
6104                    shouldn't we have some kind of lower limit on region size?
6105                 */
6106
6107                 if (len <= 0) {
6108                         break;
6109                 }
6110
6111                 string new_name;
6112
6113                 if (RegionFactory::region_name (new_name, r->name())) {
6114                         break;
6115                 }
6116
6117                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6118
6119                 PropertyList plist;
6120
6121                 plist.add (ARDOUR::Properties::start, file_start);
6122                 plist.add (ARDOUR::Properties::length, len);
6123                 plist.add (ARDOUR::Properties::name, new_name);
6124                 plist.add (ARDOUR::Properties::layer, 0);
6125
6126                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6127                 /* because we set annouce to false, manually add the new region to the
6128                    RegionFactory map
6129                 */
6130                 RegionFactory::map_add (nr);
6131
6132                 pl->add_region (nr, r->position() + pos);
6133
6134                 if (select_new) {
6135                         new_regions.push_front(nr);
6136                 }
6137
6138                 pos += len;
6139                 ++x;
6140         }
6141
6142         string new_name;
6143
6144         RegionFactory::region_name (new_name, r->name());
6145
6146         /* Add the final region */
6147         PropertyList plist;
6148
6149         plist.add (ARDOUR::Properties::start, r->start() + pos);
6150         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6151         plist.add (ARDOUR::Properties::name, new_name);
6152         plist.add (ARDOUR::Properties::layer, 0);
6153
6154         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6155         /* because we set annouce to false, manually add the new region to the
6156            RegionFactory map
6157         */
6158         RegionFactory::map_add (nr);
6159         pl->add_region (nr, r->position() + pos);
6160
6161         if (select_new) {
6162                 new_regions.push_front(nr);
6163         }
6164
6165         pl->thaw ();
6166
6167         /* We might have removed regions, which alters other regions' layering_index,
6168            so we need to do a recursive diff here.
6169         */
6170         vector<Command*> cmds;
6171         pl->rdiff (cmds);
6172         _session->add_commands (cmds);
6173         
6174         _session->add_command (new StatefulDiffCommand (pl));
6175
6176         if (select_new) {
6177
6178                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6179                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6180                 }
6181         }
6182 }
6183
6184 void
6185 Editor::place_transient()
6186 {
6187         if (!_session) {
6188                 return;
6189         }
6190
6191         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6192
6193         if (rs.empty()) {
6194                 return;
6195         }
6196
6197         framepos_t where = get_preferred_edit_position();
6198
6199         _session->begin_reversible_command (_("place transient"));
6200
6201         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6202                 framepos_t position = (*r)->region()->position();
6203                 (*r)->region()->add_transient(where - position);
6204         }
6205
6206         _session->commit_reversible_command ();
6207 }
6208
6209 void
6210 Editor::remove_transient(ArdourCanvas::Item* item)
6211 {
6212         if (!_session) {
6213                 return;
6214         }
6215
6216         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6217         assert (_line);
6218
6219         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6220         _arv->remove_transient (*(float*) _line->get_data ("position"));
6221 }
6222
6223 void
6224 Editor::snap_regions_to_grid ()
6225 {
6226         list <boost::shared_ptr<Playlist > > used_playlists;
6227
6228         RegionSelection rs = get_regions_from_selection_and_entered ();
6229
6230         if (!_session || rs.empty()) {
6231                 return;
6232         }
6233
6234         _session->begin_reversible_command (_("snap regions to grid"));
6235
6236         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6237
6238                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6239
6240                 if (!pl->frozen()) {
6241                         /* we haven't seen this playlist before */
6242
6243                         /* remember used playlists so we can thaw them later */
6244                         used_playlists.push_back(pl);
6245                         pl->freeze();
6246                 }
6247
6248                 framepos_t start_frame = (*r)->region()->first_frame ();
6249                 snap_to (start_frame);
6250                 (*r)->region()->set_position (start_frame);
6251         }
6252
6253         while (used_playlists.size() > 0) {
6254                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6255                 (*i)->thaw();
6256                 used_playlists.pop_front();
6257         }
6258
6259         _session->commit_reversible_command ();
6260 }
6261
6262 void
6263 Editor::close_region_gaps ()
6264 {
6265         list <boost::shared_ptr<Playlist > > used_playlists;
6266
6267         RegionSelection rs = get_regions_from_selection_and_entered ();
6268
6269         if (!_session || rs.empty()) {
6270                 return;
6271         }
6272
6273         Dialog dialog (_("Close Region Gaps"));
6274
6275         Table table (2, 3);
6276         table.set_spacings (12);
6277         table.set_border_width (12);
6278         Label* l = manage (left_aligned_label (_("Crossfade length")));
6279         table.attach (*l, 0, 1, 0, 1);
6280
6281         SpinButton spin_crossfade (1, 0);
6282         spin_crossfade.set_range (0, 15);
6283         spin_crossfade.set_increments (1, 1);
6284         spin_crossfade.set_value (5);
6285         table.attach (spin_crossfade, 1, 2, 0, 1);
6286
6287         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6288
6289         l = manage (left_aligned_label (_("Pull-back length")));
6290         table.attach (*l, 0, 1, 1, 2);
6291
6292         SpinButton spin_pullback (1, 0);
6293         spin_pullback.set_range (0, 100);
6294         spin_pullback.set_increments (1, 1);
6295         spin_pullback.set_value(30);
6296         table.attach (spin_pullback, 1, 2, 1, 2);
6297
6298         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6299
6300         dialog.get_vbox()->pack_start (table);
6301         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6302         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6303         dialog.show_all ();
6304
6305         if (dialog.run () == RESPONSE_CANCEL) {
6306                 return;
6307         }
6308
6309         framepos_t crossfade_len = spin_crossfade.get_value();
6310         framepos_t pull_back_frames = spin_pullback.get_value();
6311
6312         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6313         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6314
6315         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6316
6317         _session->begin_reversible_command (_("close region gaps"));
6318
6319         int idx = 0;
6320         boost::shared_ptr<Region> last_region;
6321
6322         rs.sort_by_position_and_track();
6323
6324         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6325
6326                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6327
6328                 if (!pl->frozen()) {
6329                         /* we haven't seen this playlist before */
6330
6331                         /* remember used playlists so we can thaw them later */
6332                         used_playlists.push_back(pl);
6333                         pl->freeze();
6334                 }
6335
6336                 framepos_t position = (*r)->region()->position();
6337
6338                 if (idx == 0 || position < last_region->position()){
6339                         last_region = (*r)->region();
6340                         idx++;
6341                         continue;
6342                 }
6343
6344                 (*r)->region()->trim_front( (position - pull_back_frames));
6345                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6346
6347                 last_region = (*r)->region();
6348
6349                 idx++;
6350         }
6351
6352         while (used_playlists.size() > 0) {
6353                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6354                 (*i)->thaw();
6355                 used_playlists.pop_front();
6356         }
6357
6358         _session->commit_reversible_command ();
6359 }
6360
6361 void
6362 Editor::tab_to_transient (bool forward)
6363 {
6364         AnalysisFeatureList positions;
6365
6366         RegionSelection rs = get_regions_from_selection_and_entered ();
6367
6368         if (!_session) {
6369                 return;
6370         }
6371
6372         framepos_t pos = _session->audible_frame ();
6373
6374         if (!selection->tracks.empty()) {
6375
6376                 /* don't waste time searching for transients in duplicate playlists.
6377                  */
6378
6379                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6380
6381                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6382
6383                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6384
6385                         if (rtv) {
6386                                 boost::shared_ptr<Track> tr = rtv->track();
6387                                 if (tr) {
6388                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6389                                         if (pl) {
6390                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6391
6392                                                 if (result >= 0) {
6393                                                         positions.push_back (result);
6394                                                 }
6395                                         }
6396                                 }
6397                         }
6398                 }
6399
6400         } else {
6401
6402                 if (rs.empty()) {
6403                         return;
6404                 }
6405
6406                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6407                         (*r)->region()->get_transients (positions);
6408                 }
6409         }
6410
6411         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6412
6413         if (forward) {
6414                 AnalysisFeatureList::iterator x;
6415
6416                 for (x = positions.begin(); x != positions.end(); ++x) {
6417                         if ((*x) > pos) {
6418                                 break;
6419                         }
6420                 }
6421
6422                 if (x != positions.end ()) {
6423                         _session->request_locate (*x);
6424                 }
6425
6426         } else {
6427                 AnalysisFeatureList::reverse_iterator x;
6428
6429                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6430                         if ((*x) < pos) {
6431                                 break;
6432                         }
6433                 }
6434
6435                 if (x != positions.rend ()) {
6436                         _session->request_locate (*x);
6437                 }
6438         }
6439 }
6440
6441 void
6442 Editor::playhead_forward_to_grid ()
6443 {
6444         if (!_session) {
6445                 return;
6446         }
6447         
6448         framepos_t pos = playhead_cursor->current_frame ();
6449         if (pos < max_framepos - 1) {
6450                 pos += 2;
6451                 snap_to_internal (pos, 1, false);
6452                 _session->request_locate (pos);
6453         }
6454 }
6455
6456
6457 void
6458 Editor::playhead_backward_to_grid ()
6459 {
6460         if (!_session) {
6461                 return;
6462         }
6463         
6464         framepos_t pos = playhead_cursor->current_frame ();
6465         if (pos > 2) {
6466                 pos -= 2;
6467                 snap_to_internal (pos, -1, false);
6468                 _session->request_locate (pos);
6469         }
6470 }
6471
6472 void
6473 Editor::set_track_height (Height h)
6474 {
6475         TrackSelection& ts (selection->tracks);
6476
6477         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6478                 (*x)->set_height_enum (h);
6479         }
6480 }
6481
6482 void
6483 Editor::toggle_tracks_active ()
6484 {
6485         TrackSelection& ts (selection->tracks);
6486         bool first = true;
6487         bool target = false;
6488
6489         if (ts.empty()) {
6490                 return;
6491         }
6492
6493         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6494                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6495
6496                 if (rtv) {
6497                         if (first) {
6498                                 target = !rtv->_route->active();
6499                                 first = false;
6500                         }
6501                         rtv->_route->set_active (target, this);
6502                 }
6503         }
6504 }
6505
6506 void
6507 Editor::remove_tracks ()
6508 {
6509         TrackSelection& ts (selection->tracks);
6510
6511         if (ts.empty()) {
6512                 return;
6513         }
6514
6515         vector<string> choices;
6516         string prompt;
6517         int ntracks = 0;
6518         int nbusses = 0;
6519         const char* trackstr;
6520         const char* busstr;
6521         vector<boost::shared_ptr<Route> > routes;
6522         bool special_bus = false;
6523
6524         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6525                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6526                 if (!rtv) {
6527                         continue;
6528                 }
6529                 if (rtv->is_track()) {
6530                         ntracks++;
6531                 } else {
6532                         nbusses++;
6533                 }
6534                 routes.push_back (rtv->_route);
6535
6536                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6537                         special_bus = true;
6538                 }
6539         }
6540
6541         if (special_bus && !Config->get_allow_special_bus_removal()) {
6542                 MessageDialog msg (_("That would be bad news ...."),
6543                                    false,
6544                                    Gtk::MESSAGE_INFO,
6545                                    Gtk::BUTTONS_OK);
6546                 msg.set_secondary_text (string_compose (_(
6547                                                                 "Removing the master or monitor bus is such a bad idea\n\
6548 that %1 is not going to allow it.\n\
6549 \n\
6550 If you really want to do this sort of thing\n\
6551 edit your ardour.rc file to set the\n\
6552 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6553
6554                 msg.present ();
6555                 msg.run ();
6556                 return;
6557         }
6558
6559         if (ntracks + nbusses == 0) {
6560                 return;
6561         }
6562
6563         if (ntracks > 1) {
6564                 trackstr = _("tracks");
6565         } else {
6566                 trackstr = _("track");
6567         }
6568
6569         if (nbusses > 1) {
6570                 busstr = _("busses");
6571         } else {
6572                 busstr = _("bus");
6573         }
6574
6575         if (ntracks) {
6576                 if (nbusses) {
6577                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6578                                                     "(You may also lose the playlists associated with the %2)\n\n"
6579                                                     "This action cannot be undone, and the session file will be overwritten!"),
6580                                                   ntracks, trackstr, nbusses, busstr);
6581                 } else {
6582                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6583                                                     "(You may also lose the playlists associated with the %2)\n\n"
6584                                                     "This action cannot be undone, and the session file will be overwritten!"),
6585                                                   ntracks, trackstr);
6586                 }
6587         } else if (nbusses) {
6588                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6589                                             "This action cannot be undon, and the session file will be overwritten"),
6590                                           nbusses, busstr);
6591         }
6592
6593         choices.push_back (_("No, do nothing."));
6594         if (ntracks + nbusses > 1) {
6595                 choices.push_back (_("Yes, remove them."));
6596         } else {
6597                 choices.push_back (_("Yes, remove it."));
6598         }
6599
6600         string title;
6601         if (ntracks) {
6602                 title = string_compose (_("Remove %1"), trackstr);
6603         } else {
6604                 title = string_compose (_("Remove %1"), busstr);
6605         }
6606
6607         Choice prompter (title, prompt, choices);
6608
6609         if (prompter.run () != 1) {
6610                 return;
6611         }
6612
6613         {
6614                 Session::StateProtector sp (_session);
6615                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6616                         _session->remove_route (*x);
6617                 }
6618         }
6619 }
6620
6621 void
6622 Editor::do_insert_time ()
6623 {
6624         if (selection->tracks.empty()) {
6625                 return;
6626         }
6627
6628         InsertTimeDialog d (*this);
6629         int response = d.run ();
6630
6631         if (response != RESPONSE_OK) {
6632                 return;
6633         }
6634
6635         if (d.distance() == 0) {
6636                 return;
6637         }
6638
6639         InsertTimeOption opt = d.intersected_region_action ();
6640
6641         insert_time (
6642                 get_preferred_edit_position(),
6643                 d.distance(),
6644                 opt,
6645                 d.all_playlists(),
6646                 d.move_glued(),
6647                 d.move_markers(),
6648                 d.move_glued_markers(),
6649                 d.move_locked_markers(),
6650                 d.move_tempos()
6651                 );
6652 }
6653
6654 void
6655 Editor::insert_time (
6656         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6657         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6658         )
6659 {
6660         bool commit = false;
6661
6662         if (Config->get_edit_mode() == Lock) {
6663                 return;
6664         }
6665
6666         begin_reversible_command (_("insert time"));
6667
6668         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6669
6670         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6671
6672                 /* regions */
6673
6674                 /* don't operate on any playlist more than once, which could
6675                  * happen if "all playlists" is enabled, but there is more
6676                  * than 1 track using playlists "from" a given track.
6677                  */
6678
6679                 set<boost::shared_ptr<Playlist> > pl;
6680
6681                 if (all_playlists) {
6682                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6683                         if (rtav) {
6684                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6685                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6686                                         pl.insert (*p);
6687                                 }
6688                         }
6689                 } else {
6690                         if ((*x)->playlist ()) {
6691                                 pl.insert ((*x)->playlist ());
6692                         }
6693                 }
6694                 
6695                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6696
6697                         (*i)->clear_changes ();
6698                         (*i)->clear_owned_changes ();
6699
6700                         if (opt == SplitIntersected) {
6701                                 (*i)->split (pos);
6702                         }
6703
6704                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6705
6706                         vector<Command*> cmds;
6707                         (*i)->rdiff (cmds);
6708                         _session->add_commands (cmds);
6709
6710                         _session->add_command (new StatefulDiffCommand (*i));
6711                         commit = true;
6712                 }
6713
6714                 /* automation */
6715                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6716                 if (rtav) {
6717                         rtav->route ()->shift (pos, frames);
6718                         commit = true;
6719                 }
6720         }
6721
6722         /* markers */
6723         if (markers_too) {
6724                 bool moved = false;
6725                 XMLNode& before (_session->locations()->get_state());
6726                 Locations::LocationList copy (_session->locations()->list());
6727
6728                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6729
6730                         Locations::LocationList::const_iterator tmp;
6731
6732                         bool const was_locked = (*i)->locked ();
6733                         if (locked_markers_too) {
6734                                 (*i)->unlock ();
6735                         }
6736
6737                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6738
6739                                 if ((*i)->start() >= pos) {
6740                                         (*i)->set_start ((*i)->start() + frames);
6741                                         if (!(*i)->is_mark()) {
6742                                                 (*i)->set_end ((*i)->end() + frames);
6743                                         }
6744                                         moved = true;
6745                                 }
6746
6747                         }
6748
6749                         if (was_locked) {
6750                                 (*i)->lock ();
6751                         }
6752                 }
6753
6754                 if (moved) {
6755                         XMLNode& after (_session->locations()->get_state());
6756                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6757                 }
6758         }
6759
6760         if (tempo_too) {
6761                 _session->tempo_map().insert_time (pos, frames);
6762         }
6763
6764         if (commit) {
6765                 commit_reversible_command ();
6766         }
6767 }
6768
6769 void
6770 Editor::fit_selected_tracks ()
6771 {
6772         if (!selection->tracks.empty()) {
6773                 fit_tracks (selection->tracks);
6774         } else {
6775                 TrackViewList tvl;
6776
6777                 /* no selected tracks - use tracks with selected regions */
6778
6779                 if (!selection->regions.empty()) {
6780                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6781                                 tvl.push_back (&(*r)->get_time_axis_view ());
6782                         }
6783
6784                         if (!tvl.empty()) {
6785                                 fit_tracks (tvl);
6786                         }
6787                 } else if (internal_editing()) {
6788                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6789                            the entered track
6790                         */
6791                         if (entered_track) {
6792                                 tvl.push_back (entered_track);
6793                                 fit_tracks (tvl);
6794                         }
6795                 }
6796         }
6797
6798 }
6799
6800 void
6801 Editor::fit_tracks (TrackViewList & tracks)
6802 {
6803         if (tracks.empty()) {
6804                 return;
6805         }
6806
6807         uint32_t child_heights = 0;
6808         int visible_tracks = 0;
6809
6810         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6811
6812                 if (!(*t)->marked_for_display()) {
6813                         continue;
6814                 }
6815
6816                 child_heights += (*t)->effective_height() - (*t)->current_height();
6817                 ++visible_tracks;
6818         }
6819
6820         /* compute the per-track height from:
6821
6822            total canvas visible height - 
6823                  height that will be taken by visible children of selected
6824                  tracks - height of the ruler/hscroll area 
6825         */
6826         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6827         double first_y_pos = DBL_MAX;
6828
6829         if (h < TimeAxisView::preset_height (HeightSmall)) {
6830                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6831                 /* too small to be displayed */
6832                 return;
6833         }
6834
6835         undo_visual_stack.push_back (current_visual_state (true));
6836         no_save_visual = true;
6837
6838         /* build a list of all tracks, including children */
6839
6840         TrackViewList all;
6841         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6842                 all.push_back (*i);
6843                 TimeAxisView::Children c = (*i)->get_child_list ();
6844                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6845                         all.push_back (j->get());
6846                 }
6847         }
6848
6849         bool prev_was_selected = false;
6850         bool is_selected = tracks.contains (all.front());
6851         bool next_is_selected;
6852
6853         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6854
6855                 TrackViewList::iterator next;
6856
6857                 next = t;
6858                 ++next;
6859
6860                 if (next != all.end()) {
6861                         next_is_selected = tracks.contains (*next);
6862                 } else {
6863                         next_is_selected = false;
6864                 }
6865
6866                 if ((*t)->marked_for_display ()) {
6867                         if (is_selected) {
6868                                 (*t)->set_height (h);
6869                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6870                         } else {
6871                                 if (prev_was_selected && next_is_selected) {
6872                                         hide_track_in_display (*t);
6873                                 }
6874                         }
6875                 }
6876
6877                 prev_was_selected = is_selected;
6878                 is_selected = next_is_selected;
6879         }
6880
6881         /*
6882            set the controls_layout height now, because waiting for its size
6883            request signal handler will cause the vertical adjustment setting to fail
6884         */
6885
6886         controls_layout.property_height () = _full_canvas_height;
6887         vertical_adjustment.set_value (first_y_pos);
6888
6889         redo_visual_stack.push_back (current_visual_state (true));
6890
6891         visible_tracks_selector.set_text (_("Sel"));
6892 }
6893
6894 void
6895 Editor::save_visual_state (uint32_t n)
6896 {
6897         while (visual_states.size() <= n) {
6898                 visual_states.push_back (0);
6899         }
6900
6901         if (visual_states[n] != 0) {
6902                 delete visual_states[n];
6903         }
6904
6905         visual_states[n] = current_visual_state (true);
6906         gdk_beep ();
6907 }
6908
6909 void
6910 Editor::goto_visual_state (uint32_t n)
6911 {
6912         if (visual_states.size() <= n) {
6913                 return;
6914         }
6915
6916         if (visual_states[n] == 0) {
6917                 return;
6918         }
6919
6920         use_visual_state (*visual_states[n]);
6921 }
6922
6923 void
6924 Editor::start_visual_state_op (uint32_t n)
6925 {
6926         save_visual_state (n);
6927         
6928         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6929         char buf[32];
6930         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6931         pup->set_text (buf);
6932         pup->touch();
6933 }
6934
6935 void
6936 Editor::cancel_visual_state_op (uint32_t n)
6937 {
6938         goto_visual_state (n);
6939 }
6940
6941 void
6942 Editor::toggle_region_mute ()
6943 {
6944         if (_ignore_region_action) {
6945                 return;
6946         }
6947
6948         RegionSelection rs = get_regions_from_selection_and_entered ();
6949
6950         if (rs.empty ()) {
6951                 return;
6952         }
6953
6954         if (rs.size() > 1) {
6955                 begin_reversible_command (_("mute regions"));
6956         } else {
6957                 begin_reversible_command (_("mute region"));
6958         }
6959
6960         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
6961
6962                 (*i)->region()->playlist()->clear_changes ();
6963                 (*i)->region()->set_muted (!(*i)->region()->muted ());
6964                 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
6965
6966         }
6967
6968         commit_reversible_command ();
6969 }
6970
6971 void
6972 Editor::combine_regions ()
6973 {
6974         /* foreach track with selected regions, take all selected regions
6975            and join them into a new region containing the subregions (as a
6976            playlist)
6977         */
6978
6979         typedef set<RouteTimeAxisView*> RTVS;
6980         RTVS tracks;
6981
6982         if (selection->regions.empty()) {
6983                 return;
6984         }
6985
6986         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
6987                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
6988
6989                 if (rtv) {
6990                         tracks.insert (rtv);
6991                 }
6992         }
6993
6994         begin_reversible_command (_("combine regions"));
6995
6996         vector<RegionView*> new_selection;
6997
6998         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
6999                 RegionView* rv;
7000
7001                 if ((rv = (*i)->combine_regions ()) != 0) {
7002                         new_selection.push_back (rv);
7003                 }
7004         }
7005
7006         selection->clear_regions ();
7007         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7008                 selection->add (*i);
7009         }
7010
7011         commit_reversible_command ();
7012 }
7013
7014 void
7015 Editor::uncombine_regions ()
7016 {
7017         typedef set<RouteTimeAxisView*> RTVS;
7018         RTVS tracks;
7019
7020         if (selection->regions.empty()) {
7021                 return;
7022         }
7023
7024         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7025                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7026
7027                 if (rtv) {
7028                         tracks.insert (rtv);
7029                 }
7030         }
7031
7032         begin_reversible_command (_("uncombine regions"));
7033
7034         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7035                 (*i)->uncombine_regions ();
7036         }
7037
7038         commit_reversible_command ();
7039 }
7040
7041 void
7042 Editor::toggle_midi_input_active (bool flip_others)
7043 {
7044         bool onoff = false;
7045         boost::shared_ptr<RouteList> rl (new RouteList);
7046
7047         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7048                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7049
7050                 if (!rtav) {
7051                         continue;
7052                 }
7053
7054                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7055
7056                 if (mt) {
7057                         rl->push_back (rtav->route());
7058                         onoff = !mt->input_active();
7059                 }
7060         }
7061         
7062         _session->set_exclusive_input_active (rl, onoff, flip_others);
7063 }
7064
7065 void
7066 Editor::lock ()
7067 {
7068         if (!lock_dialog) {
7069                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7070
7071                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7072                 lock_dialog->get_vbox()->pack_start (*padlock);
7073
7074                 ArdourButton* b = manage (new ArdourButton);
7075                 b->set_name ("lock button");
7076                 b->set_markup (string_compose ("<span size=\"large\" weight=\"bold\">%1</span>", _("Click to unlock")));
7077                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7078                 lock_dialog->get_vbox()->pack_start (*b);
7079                 
7080                 lock_dialog->get_vbox()->show_all ();
7081                 lock_dialog->set_size_request (200, 200);
7082         }
7083         
7084 #ifdef __APPLE__
7085         /* The global menu bar continues to be accessible to applications
7086            with modal dialogs, which means that we need to desensitize
7087            all items in the menu bar. Since those items are really just
7088            proxies for actions, that means disabling all actions.
7089         */
7090         ActionManager::disable_all_actions ();
7091 #endif
7092         lock_dialog->present ();
7093 }
7094
7095 void
7096 Editor::unlock ()
7097 {
7098         lock_dialog->hide ();
7099         
7100 #ifdef __APPLE__
7101         ActionManager::pop_action_state ();
7102 #endif  
7103
7104         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7105                 start_lock_event_timing ();
7106         }
7107 }
7108
7109 void
7110 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7111 {
7112         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7113 }
7114
7115 void
7116 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7117 {
7118         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7119         Gtkmm2ext::UI::instance()->flush_pending ();
7120 }
7121
7122 void
7123 Editor::bring_all_sources_into_session ()
7124 {
7125         if (!_session) {
7126                 return;
7127         }
7128
7129         Gtk::Label msg;
7130         ArdourDialog w (_("Moving embedded files into session folder"));
7131         w.get_vbox()->pack_start (msg);
7132         w.present ();
7133         
7134         /* flush all pending GUI events because we're about to start copying
7135          * files
7136          */
7137         
7138         Gtkmm2ext::UI::instance()->flush_pending ();
7139
7140         cerr << " Do it\n";
7141
7142         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7143 }