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