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