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