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