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