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