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