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