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