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