fix typo in last commit - move start & end, not start & start
[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         nframes_t extra_samples = unit_to_frame (one_centimeter_in_pixels);
1733         
1734         if (start > extra_samples) {
1735                 start -= extra_samples;
1736         } else {
1737                 start = 0;
1738         } 
1739
1740         if (max_frames - extra_samples > end) {
1741                 end += extra_samples;
1742         } else {
1743                 end = max_frames;
1744         }
1745
1746         temporal_zoom_by_frame (start, end, "zoom to region");
1747
1748         if (both_axes) {
1749                 double per_track_height = (canvas_height - 10.0) / tracks.size();
1750                 
1751                 /* set visible track heights appropriately */
1752                 
1753                 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1754                         (*t)->set_height_scaling_factor (per_track_height/(*t)->height);
1755                 }
1756                 
1757                 /* hide irrelevant tracks */
1758                 
1759                 no_route_list_redisplay = true;
1760
1761                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1762                         if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1763                                 hide_track_in_display (**i, true);
1764                         }
1765                 }
1766
1767                 no_route_list_redisplay = false;
1768                 redisplay_route_list ();
1769
1770                 vertical_adjustment.set_value (std::max (top_y_position - 5.0, 0.0));
1771         }
1772
1773         zoomed_to_region = true;
1774 }
1775
1776 void
1777 Editor::toggle_zoom_region (bool both_axes)
1778 {
1779         if (zoomed_to_region) {
1780                 swap_visual_state ();
1781         } else {
1782                 temporal_zoom_region (both_axes);
1783         }
1784 }
1785
1786 void
1787 Editor::temporal_zoom_selection ()
1788 {
1789         if (!selection) return;
1790         
1791         if (selection->time.empty()) {
1792                 return;
1793         }
1794
1795         nframes_t start = selection->time[clicked_selection].start;
1796         nframes_t end = selection->time[clicked_selection].end;
1797
1798         temporal_zoom_by_frame (start, end, "zoom to selection");
1799 }
1800
1801 void
1802 Editor::temporal_zoom_session ()
1803 {
1804         ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1805
1806         if (session) {
1807                 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1808         }
1809 }
1810
1811 void
1812 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1813 {
1814         if (!session) return;
1815
1816         if ((start == 0 && end == 0) || end < start) {
1817                 return;
1818         }
1819
1820         nframes_t range = end - start;
1821
1822         double new_fpu = (double)range / (double)canvas_width;
1823 //      double p2 = 1.0;
1824
1825 //      while (p2 < new_fpu) {
1826 //              p2 *= 2.0;
1827 //      }
1828 //      new_fpu = p2;
1829         
1830         nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1831         nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1832         nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1833
1834         if (new_leftmost > middle) new_leftmost = 0;
1835
1836 //      begin_reversible_command (op);
1837 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1838 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1839 //      commit_reversible_command ();
1840
1841         reposition_and_zoom (new_leftmost, new_fpu);
1842 }
1843
1844 void 
1845 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1846 {
1847         if (!session) return;
1848         
1849         double range_before = frame - leftmost_frame;
1850         double new_fpu;
1851         
1852         new_fpu = frames_per_unit;
1853         
1854         if (coarser) { 
1855                 new_fpu *= 1.61803399;
1856                 range_before *= 1.61803399;
1857         } else { 
1858                 new_fpu = max(1.0,(new_fpu/1.61803399));
1859                 range_before /= 1.61803399;
1860         }
1861
1862         if (new_fpu == frames_per_unit) return;
1863
1864         nframes_t new_leftmost = frame - (nframes_t)range_before;
1865
1866         if (new_leftmost > frame) new_leftmost = 0;
1867
1868 //      begin_reversible_command (_("zoom to frame"));
1869 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1870 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1871 //      commit_reversible_command ();
1872
1873         reposition_and_zoom (new_leftmost, new_fpu);
1874 }
1875
1876
1877 bool
1878 Editor::choose_new_marker_name(string &name) {
1879
1880         if (!Config->get_name_new_markers()) {
1881                 /* don't prompt user for a new name */
1882                 return true;
1883         }
1884
1885         ArdourPrompter dialog (true);
1886
1887         dialog.set_prompt (_("New Name:"));
1888
1889         WindowTitle title(Glib::get_application_name());
1890         title += _("Name New Location Marker");
1891
1892         dialog.set_title(title.get_string());
1893
1894         dialog.set_name ("MarkNameWindow");
1895         dialog.set_size_request (250, -1);
1896         dialog.set_position (Gtk::WIN_POS_MOUSE);
1897
1898         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1899         dialog.set_initial_text (name);
1900
1901         dialog.show ();
1902
1903         switch (dialog.run ()) {
1904         case RESPONSE_ACCEPT:
1905                 break;
1906         default:
1907                 return false;
1908         }
1909         
1910         dialog.get_result(name);
1911         return true;
1912
1913 }
1914
1915
1916 void
1917 Editor::add_location_from_selection ()
1918 {
1919         string rangename;
1920
1921         if (selection->time.empty()) {
1922                 return;
1923         }
1924
1925         if (session == 0 || clicked_trackview == 0) {
1926                 return;
1927         }
1928
1929         nframes_t start = selection->time[clicked_selection].start;
1930         nframes_t end = selection->time[clicked_selection].end;
1931
1932         session->locations()->next_available_name(rangename,"selection");
1933         Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1934
1935         session->begin_reversible_command (_("add marker"));
1936         XMLNode &before = session->locations()->get_state();
1937         session->locations()->add (location, true);
1938         XMLNode &after = session->locations()->get_state();
1939         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1940         session->commit_reversible_command ();
1941 }
1942
1943 void
1944 Editor::add_location_mark (nframes64_t where)
1945 {
1946         string markername;
1947
1948         select_new_marker = true;
1949
1950         session->locations()->next_available_name(markername,"mark");
1951         if (!choose_new_marker_name(markername)) {
1952                 return;
1953         }
1954         Location *location = new Location (where, where, markername, Location::IsMark);
1955         session->begin_reversible_command (_("add marker"));
1956         XMLNode &before = session->locations()->get_state();
1957         session->locations()->add (location, true);
1958         XMLNode &after = session->locations()->get_state();
1959         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1960         session->commit_reversible_command ();
1961 }
1962
1963 void
1964 Editor::add_location_from_playhead_cursor ()
1965 {
1966         add_location_mark (session->audible_frame());
1967 }
1968
1969 void
1970 Editor::add_location_from_audio_region ()
1971 {
1972         RegionSelection rs; 
1973
1974         get_regions_for_action (rs);
1975
1976         if (rs.empty()) {
1977                 return;
1978         }
1979
1980         RegionView* rv = *(rs.begin());
1981         boost::shared_ptr<Region> region = rv->region();
1982         
1983         Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1984         session->begin_reversible_command (_("add marker"));
1985         XMLNode &before = session->locations()->get_state();
1986         session->locations()->add (location, true);
1987         XMLNode &after = session->locations()->get_state();
1988         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1989         session->commit_reversible_command ();
1990 }
1991
1992 void
1993 Editor::amplitude_zoom_step (bool in)
1994 {
1995         gdouble zoom = 1.0;
1996
1997         if (in) {
1998                 zoom *= 2.0;
1999         } else {
2000                 if (zoom > 2.0) {
2001                         zoom /= 2.0;
2002                 } else {
2003                         zoom = 1.0;
2004                 }
2005         }
2006
2007 #ifdef FIX_FOR_CANVAS
2008         /* XXX DO SOMETHING */
2009 #endif
2010 }       
2011
2012
2013 /* DELETION */
2014
2015
2016 void
2017 Editor::delete_sample_forward ()
2018 {
2019 }
2020
2021 void
2022 Editor::delete_sample_backward ()
2023 {
2024 }
2025
2026 void
2027 Editor::delete_screen ()
2028 {
2029 }
2030
2031 /* SEARCH */
2032
2033 void
2034 Editor::search_backwards ()
2035 {
2036         /* what ? */
2037 }
2038
2039 void
2040 Editor::search_forwards ()
2041 {
2042         /* what ? */
2043 }
2044
2045 /* MARKS */
2046
2047 void
2048 Editor::jump_forward_to_mark ()
2049 {
2050         if (!session) {
2051                 return;
2052         }
2053         
2054         Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
2055
2056         if (location) {
2057                 session->request_locate (location->start(), session->transport_rolling());
2058         } else {
2059                 session->request_locate (session->current_end_frame());
2060         }
2061 }
2062
2063 void
2064 Editor::jump_backward_to_mark ()
2065 {
2066         if (!session) {
2067                 return;
2068         }
2069
2070         Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
2071         
2072         if (location) {
2073                 session->request_locate (location->start(), session->transport_rolling());
2074         } else {
2075                 session->goto_start ();
2076         }
2077 }
2078
2079 void
2080 Editor::set_mark ()
2081 {
2082         nframes_t pos;
2083         float prefix;
2084         bool was_floating;
2085         string markername;
2086
2087         if (get_prefix (prefix, was_floating)) {
2088                 pos = session->audible_frame ();
2089         } else {
2090                 if (was_floating) {
2091                         pos = (nframes_t) floor (prefix * session->frame_rate ());
2092                 } else {
2093                         pos = (nframes_t) floor (prefix);
2094                 }
2095         }
2096
2097         session->locations()->next_available_name(markername,"mark");
2098         if (!choose_new_marker_name(markername)) {
2099                 return;
2100         }
2101         session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
2102 }
2103
2104 void
2105 Editor::clear_markers ()
2106 {
2107         if (session) {
2108                 session->begin_reversible_command (_("clear markers"));
2109                 XMLNode &before = session->locations()->get_state();
2110                 session->locations()->clear_markers ();
2111                 XMLNode &after = session->locations()->get_state();
2112                 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
2113                 session->commit_reversible_command ();
2114         }
2115 }
2116
2117 void
2118 Editor::clear_ranges ()
2119 {
2120         if (session) {
2121                 session->begin_reversible_command (_("clear ranges"));
2122                 XMLNode &before = session->locations()->get_state();
2123                 
2124                 Location * looploc = session->locations()->auto_loop_location();
2125                 Location * punchloc = session->locations()->auto_punch_location();
2126                 
2127                 session->locations()->clear_ranges ();
2128                 // re-add these
2129                 if (looploc) session->locations()->add (looploc);
2130                 if (punchloc) session->locations()->add (punchloc);
2131                 
2132                 XMLNode &after = session->locations()->get_state();
2133                 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
2134                 session->commit_reversible_command ();
2135         }
2136 }
2137
2138 void
2139 Editor::clear_locations ()
2140 {
2141         session->begin_reversible_command (_("clear locations"));
2142         XMLNode &before = session->locations()->get_state();
2143         session->locations()->clear ();
2144         XMLNode &after = session->locations()->get_state();
2145         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
2146         session->commit_reversible_command ();
2147         session->locations()->clear ();
2148 }
2149
2150 void
2151 Editor::unhide_markers ()
2152 {
2153         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2154                 Location *l = (*i).first;
2155                 if (l->is_hidden() && l->is_mark()) {
2156                         l->set_hidden(false, this);
2157                 }
2158         }
2159 }
2160
2161 void
2162 Editor::unhide_ranges ()
2163 {
2164         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2165                 Location *l = (*i).first;
2166                 if (l->is_hidden() && l->is_range_marker()) { 
2167                         l->set_hidden(false, this);
2168                 }
2169         }
2170 }
2171
2172 /* INSERT/REPLACE */
2173
2174 void
2175 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
2176 {
2177         double wx, wy;
2178         double cx, cy;
2179         TimeAxisView *tv;
2180         nframes_t where;
2181         AudioTimeAxisView *atv = 0;
2182         boost::shared_ptr<Playlist> playlist;
2183         
2184         track_canvas->window_to_world (x, y, wx, wy);
2185         wx += horizontal_adjustment.get_value();
2186         wy += vertical_adjustment.get_value();
2187
2188         GdkEvent event;
2189         event.type = GDK_BUTTON_RELEASE;
2190         event.button.x = wx;
2191         event.button.y = wy;
2192         
2193         where = event_frame (&event, &cx, &cy);
2194
2195         if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
2196                 /* clearly outside canvas area */
2197                 return;
2198         }
2199         
2200         if ((tv = trackview_by_y_position (cy)) == 0) {
2201                 return;
2202         }
2203         
2204         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
2205                 return;
2206         }
2207
2208         if ((playlist = atv->playlist()) == 0) {
2209                 return;
2210         }
2211         
2212         snap_to (where);
2213         
2214         begin_reversible_command (_("insert dragged region"));
2215         XMLNode &before = playlist->get_state();
2216         playlist->add_region (RegionFactory::create (region), where, 1.0);
2217         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2218         commit_reversible_command ();
2219 }
2220
2221 void
2222 Editor::insert_region_list_selection (float times)
2223 {
2224         RouteTimeAxisView *tv = 0;
2225         boost::shared_ptr<Playlist> playlist;
2226
2227         if (clicked_audio_trackview != 0) {
2228                 tv = clicked_audio_trackview;
2229         } else if (!selection->tracks.empty()) {
2230                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2231                         return;
2232                 }
2233         } else if (entered_track != 0) {
2234                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2235                         return;
2236                 }
2237         } else {
2238                 return;
2239         }
2240
2241         if ((playlist = tv->playlist()) == 0) {
2242                 return;
2243         }
2244         
2245         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2246         
2247         if (selected->count_selected_rows() != 1) {
2248                 return;
2249         }
2250         
2251         TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
2252
2253         /* only one row selected, so rows.begin() is it */
2254
2255         TreeIter iter;
2256
2257         if ((iter = region_list_model->get_iter (*rows.begin()))) {
2258
2259                 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
2260                 
2261                 begin_reversible_command (_("insert region"));
2262                 XMLNode &before = playlist->get_state();
2263                 playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
2264                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2265                 commit_reversible_command ();
2266         } 
2267 }
2268
2269 /* BUILT-IN EFFECTS */
2270
2271 void
2272 Editor::reverse_selection ()
2273 {
2274
2275 }
2276
2277 /* GAIN ENVELOPE EDITING */
2278
2279 void
2280 Editor::edit_envelope ()
2281 {
2282 }
2283
2284 /* PLAYBACK */
2285
2286 void
2287 Editor::transition_to_rolling (bool fwd)
2288 {
2289         if (!session) {
2290                 return;
2291         }
2292
2293         switch (Config->get_slave_source()) {
2294         case None:
2295         case JACK:
2296                 break;
2297         default:
2298                 /* transport controlled by the master */
2299                 return;
2300         }
2301
2302         if (session->is_auditioning()) {
2303                 session->cancel_audition ();
2304                 return;
2305         }
2306         
2307         session->request_transport_speed (fwd ? 1.0f : -1.0f);
2308 }
2309
2310 void
2311 Editor::toggle_playback (bool with_abort)
2312 {
2313         if (!session) {
2314                 return;
2315         }
2316
2317         switch (Config->get_slave_source()) {
2318         case None:
2319         case JACK:
2320                 break;
2321         default:
2322                 /* transport controlled by the master */
2323                 return;
2324         }
2325
2326         if (session->is_auditioning()) {
2327                 session->cancel_audition ();
2328                 return;
2329         }
2330         
2331         if (session->transport_rolling()) {
2332                 session->request_stop (with_abort);
2333                 if (session->get_play_loop()) {
2334                         session->request_play_loop (false);
2335                 }
2336         } else {
2337                 session->request_transport_speed (1.0f);
2338         }
2339 }
2340
2341 void
2342 Editor::play_from_start ()
2343 {
2344         session->request_locate (session->current_start_frame(), true);
2345 }
2346
2347 void
2348 Editor::play_from_edit_point ()
2349 {
2350         session->request_locate (get_preferred_edit_position(), true);
2351 }
2352
2353 void
2354 Editor::play_from_edit_point_and_return ()
2355 {
2356         nframes64_t start_frame;
2357         nframes64_t return_frame;
2358
2359         start_frame = get_preferred_edit_position (true);
2360
2361         if (session->transport_rolling()) {
2362                 session->request_locate (start_frame, false);
2363                 return;
2364         }
2365
2366         /* don't reset the return frame if its already set */
2367
2368         if ((return_frame = session->requested_return_frame()) < 0) {
2369                 return_frame = session->audible_frame();
2370         }
2371
2372         if (start_frame >= 0) {
2373                 session->request_roll_at_and_return (start_frame, return_frame);
2374         }
2375 }
2376
2377 void
2378 Editor::play_selection ()
2379 {
2380         if (selection->time.empty()) {
2381                 return;
2382         }
2383
2384         session->request_play_range (true);
2385 }
2386
2387 void
2388 Editor::loop_selected_region ()
2389 {
2390         RegionSelection rs; 
2391
2392         get_regions_for_action (rs);
2393
2394         if (!rs.empty()) {
2395                 RegionView *rv = *(rs.begin());
2396                 Location* tll;
2397
2398                 if ((tll = transport_loop_location()) != 0)  {
2399
2400                         tll->set (rv->region()->position(), rv->region()->last_frame());
2401                         
2402                         // enable looping, reposition and start rolling
2403
2404                         session->request_play_loop (true);
2405                         session->request_locate (tll->start(), false);
2406                         session->request_transport_speed (1.0f);
2407                 }
2408         }
2409 }
2410
2411 void
2412 Editor::play_location (Location& location)
2413 {
2414         if (location.start() <= location.end()) {
2415                 return;
2416         }
2417
2418         session->request_bounded_roll (location.start(), location.end());
2419 }
2420
2421 void
2422 Editor::loop_location (Location& location)
2423 {
2424         if (location.start() <= location.end()) {
2425                 return;
2426         }
2427
2428         Location* tll;
2429
2430         if ((tll = transport_loop_location()) != 0) {
2431                 tll->set (location.start(), location.end());
2432
2433                 // enable looping, reposition and start rolling
2434                 session->request_play_loop (true);
2435                 session->request_locate (tll->start(), true);
2436         }
2437 }
2438
2439 void
2440 Editor::raise_region ()
2441 {
2442         selection->foreach_region (&Region::raise);
2443 }
2444
2445 void
2446 Editor::raise_region_to_top ()
2447 {
2448         selection->foreach_region (&Region::raise_to_top);
2449 }
2450
2451 void
2452 Editor::lower_region ()
2453 {
2454         selection->foreach_region (&Region::lower);
2455 }
2456
2457 void
2458 Editor::lower_region_to_bottom ()
2459 {
2460         selection->foreach_region (&Region::lower_to_bottom);
2461 }
2462
2463 void
2464 Editor::edit_region ()
2465 {
2466         if (clicked_regionview == 0) {
2467                 return;
2468         }
2469         
2470         clicked_regionview->show_region_editor ();
2471 }
2472
2473 void
2474 Editor::rename_region()
2475 {
2476         RegionSelection rs; 
2477
2478         get_regions_for_action (rs);
2479
2480         if (rs.empty()) {
2481                 return;
2482         }
2483
2484         WindowTitle title (Glib::get_application_name());
2485         title += _("Rename Region");
2486
2487         ArdourDialog d (*this, title.get_string(), true, false);
2488         Entry entry;
2489         Label label (_("New name:"));
2490         HBox hbox;
2491
2492         hbox.set_spacing (6);
2493         hbox.pack_start (label, false, false);
2494         hbox.pack_start (entry, true, true);
2495
2496         d.get_vbox()->set_border_width (12);
2497         d.get_vbox()->pack_start (hbox, false, false);
2498
2499         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2500         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2501
2502         d.set_size_request (300, -1);
2503         d.set_position (Gtk::WIN_POS_MOUSE);
2504
2505         entry.set_text (rs.front()->region()->name());
2506         entry.select_region (0, -1);
2507
2508         entry.signal_activate().connect (bind (mem_fun (d, &Dialog::response), RESPONSE_OK));
2509         
2510         d.show_all ();
2511         
2512         entry.grab_focus();
2513
2514         int ret = d.run();
2515
2516         d.hide ();
2517
2518         if (ret == RESPONSE_OK) {
2519                 std::string str = entry.get_text();
2520                 strip_whitespace_edges (str);
2521                 if (!str.empty()) {
2522                         rs.front()->region()->set_name (str);
2523                         redisplay_regions ();
2524                 }
2525         }
2526 }
2527
2528 void
2529 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2530 {
2531         if (session->is_auditioning()) {
2532                 session->cancel_audition ();
2533         } 
2534
2535         // note: some potential for creativity here, because region doesn't
2536         // have to belong to the playlist that Route is handling
2537
2538         // bool was_soloed = route.soloed();
2539
2540         route.set_solo (true, this);
2541         
2542         session->request_bounded_roll (region->position(), region->position() + region->length());
2543         
2544         /* XXX how to unset the solo state ? */
2545 }
2546
2547 void
2548 Editor::play_edit_range ()
2549 {
2550         nframes64_t start, end;
2551
2552         if (get_edit_op_range (start, end)) {
2553                 session->request_bounded_roll (start, end);
2554         }
2555 }
2556
2557 void
2558 Editor::play_selected_region ()
2559 {
2560         nframes64_t start = max_frames;
2561         nframes64_t end = 0;
2562         RegionSelection rs; 
2563
2564         get_regions_for_action (rs);
2565          
2566         if (rs.empty()) {
2567                 return;
2568         }
2569
2570         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2571                 if ((*i)->region()->position() < start) {
2572                         start = (*i)->region()->position();
2573                 }
2574                 if ((*i)->region()->last_frame() + 1 > end) {
2575                         end = (*i)->region()->last_frame() + 1;
2576                 }
2577         }
2578
2579         session->request_stop ();
2580         session->request_bounded_roll (start, end);
2581 }
2582
2583 void
2584 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2585 {
2586         session->audition_region (region);
2587 }
2588
2589 void
2590 Editor::build_interthread_progress_window ()
2591 {
2592         interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2593
2594         interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2595         
2596         interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2597         interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2598
2599         // GTK2FIX: this button needs a modifiable label
2600
2601         Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2602         b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2603
2604         interthread_cancel_button.add (interthread_cancel_label);
2605
2606         interthread_progress_window->set_default_size (200, 100);
2607 }
2608
2609 void
2610 Editor::interthread_cancel_clicked ()
2611 {
2612         if (current_interthread_info) {
2613                 current_interthread_info->cancel = true;
2614         }
2615 }
2616
2617 void
2618 Editor::region_from_selection ()
2619 {
2620         if (clicked_trackview == 0) {
2621                 return;
2622         }
2623
2624         if (selection->time.empty()) {
2625                 return;
2626         }
2627
2628         nframes_t start = selection->time[clicked_selection].start;
2629         nframes_t end = selection->time[clicked_selection].end;
2630
2631         nframes_t selection_cnt = end - start + 1;
2632         
2633         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2634                 boost::shared_ptr<AudioRegion> current;
2635                 boost::shared_ptr<Region> current_r;
2636                 boost::shared_ptr<Playlist> pl;
2637
2638                 nframes_t internal_start;
2639                 string new_name;
2640
2641                 if ((pl = (*i)->playlist()) == 0) {
2642                         continue;
2643                 }
2644
2645                 if ((current_r = pl->top_region_at (start)) == 0) {
2646                         continue;
2647                 }
2648
2649                 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2650                 // FIXME: audio only
2651                 if (current != 0) {
2652                         internal_start = start - current->position();
2653                         session->region_name (new_name, current->name(), true);
2654                         boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2655                 }
2656         }
2657 }       
2658
2659 void
2660 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2661 {
2662         if (selection->time.empty() || selection->tracks.empty()) {
2663                 return;
2664         }
2665
2666         nframes_t start = selection->time[clicked_selection].start;
2667         nframes_t end = selection->time[clicked_selection].end;
2668         
2669         sort_track_selection ();
2670
2671         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2672
2673                 boost::shared_ptr<AudioRegion> current;
2674                 boost::shared_ptr<Region> current_r;
2675                 boost::shared_ptr<Playlist> playlist;
2676                 nframes_t internal_start;
2677                 string new_name;
2678
2679                 if ((playlist = (*i)->playlist()) == 0) {
2680                         continue;
2681                 }
2682
2683                 if ((current_r = playlist->top_region_at(start)) == 0) {
2684                         continue;
2685                 }
2686
2687                 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2688                         continue;
2689                 }
2690         
2691                 internal_start = start - current->position();
2692                 session->region_name (new_name, current->name(), true);
2693                 
2694                 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2695         }
2696 }
2697
2698 void
2699 Editor::split_multichannel_region ()
2700 {
2701         RegionSelection rs; 
2702
2703         get_regions_for_action (rs);
2704
2705         if (rs.empty()) {
2706                 return;
2707         }
2708
2709         vector<boost::shared_ptr<AudioRegion> > v;
2710
2711         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2712
2713                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
2714                 
2715                 if (!arv || arv->audio_region()->n_channels() < 2) {
2716                         continue;
2717                 }
2718
2719                 (arv)->audio_region()->separate_by_channel (*session, v);
2720         }
2721 }
2722
2723 void
2724 Editor::new_region_from_selection ()
2725 {
2726         region_from_selection ();
2727         cancel_selection ();
2728 }
2729
2730 static void
2731 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2732 {
2733         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2734         case OverlapNone:
2735                 break;
2736         default:
2737                 rs->push_back (rv);
2738         }
2739 }
2740
2741 void
2742 Editor::separate_regions_between (const TimeSelection& ts)
2743 {
2744         bool in_command = false;
2745         boost::shared_ptr<Playlist> playlist;
2746         RegionSelection new_selection;
2747         TrackSelection tmptracks;
2748
2749         if (selection->tracks.empty()) {
2750                 
2751                 /* use tracks with selected regions */
2752
2753                 RegionSelection rs; 
2754
2755                 get_regions_for_action (rs);
2756
2757                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2758                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2759
2760                         if (find (tmptracks.begin(), tmptracks.end(), tv) == tmptracks.end()) {
2761                                 tmptracks.push_back (tv);
2762                         }
2763                 }
2764
2765                 if (tmptracks.empty()) {
2766                         /* no regions selected: do nothing */
2767                         return;
2768                 }
2769
2770         } else {
2771
2772                 tmptracks = selection->tracks;
2773
2774         }
2775
2776         sort_track_selection (&tmptracks);
2777
2778         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2779
2780                 AudioTimeAxisView* atv;
2781
2782                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2783
2784                         if (atv->is_audio_track()) {
2785
2786                                 /* no edits to destructive tracks */
2787
2788                                 if (atv->audio_track()->audio_diskstream()->destructive()) {
2789                                         continue;
2790                                 }
2791                                         
2792                                 if ((playlist = atv->playlist()) != 0) {
2793
2794
2795                                         XMLNode *before;
2796                                         bool got_some;
2797
2798                                         before = &(playlist->get_state());
2799                                         got_some = false;
2800
2801                                         /* XXX need to consider musical time selections here at some point */
2802
2803                                         double speed = atv->get_diskstream()->speed();
2804
2805
2806                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2807
2808                                                 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2809                                                 latest_regionviews.clear ();
2810
2811                                                 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2812
2813                                                 c.disconnect ();
2814
2815                                                 if (!latest_regionviews.empty()) {
2816                                                         
2817                                                         got_some = true;
2818
2819                                                         atv->view()->foreach_regionview (bind (sigc::ptr_fun (add_if_covered), &(*t), &new_selection));
2820                                                         
2821                                                         if (!in_command) {
2822                                                                 begin_reversible_command (_("separate"));
2823                                                                 in_command = true;
2824                                                         }
2825                                                         
2826                                                         session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2827                                                         
2828                                                 } 
2829                                         }
2830
2831                                         if (!got_some) {
2832                                                 delete before;
2833                                         }
2834                                 }
2835                         }
2836                 }
2837         }
2838
2839         if (in_command) {
2840                 selection->set (new_selection);
2841                 set_mouse_mode (MouseObject);
2842
2843                 commit_reversible_command ();
2844         }
2845 }
2846
2847 void
2848 Editor::separate_region_from_selection ()
2849 {
2850         /* preferentially use *all* ranges in the time selection if we're in range mode
2851            to allow discontiguous operation, since get_edit_op_range() currently
2852            returns a single range.
2853         */
2854
2855         if (mouse_mode == MouseRange && !selection->time.empty()) {
2856
2857                 separate_regions_between (selection->time);
2858
2859         } else {
2860
2861                 nframes64_t start;
2862                 nframes64_t end;
2863                 
2864                 if (get_edit_op_range (start, end)) {
2865                         
2866                         AudioRange ar (start, end, 1);
2867                         TimeSelection ts;
2868                         ts.push_back (ar);
2869
2870                         separate_regions_between (ts);
2871                 }
2872         }
2873 }
2874
2875 void
2876 Editor::separate_region_from_punch ()
2877 {
2878         Location* loc  = session->locations()->auto_punch_location();
2879         if (loc) {
2880                 separate_regions_using_location (*loc);
2881         }
2882 }
2883
2884 void
2885 Editor::separate_region_from_loop ()
2886 {
2887         Location* loc  = session->locations()->auto_loop_location();
2888         if (loc) {
2889                 separate_regions_using_location (*loc);
2890         }
2891 }
2892
2893 void
2894 Editor::separate_regions_using_location (Location& loc)
2895 {
2896         if (loc.is_mark()) {
2897                 return;
2898         }
2899
2900         AudioRange ar (loc.start(), loc.end(), 1);
2901         TimeSelection ts;
2902
2903         ts.push_back (ar);
2904
2905         separate_regions_between (ts);
2906 }
2907
2908 void
2909 Editor::crop_region_to_selection ()
2910 {
2911         if (!selection->time.empty()) {
2912
2913                 crop_region_to (selection->time.start(), selection->time.end_frame());
2914
2915         } else {
2916
2917                 nframes64_t start;
2918                 nframes64_t end;
2919
2920                 if (get_edit_op_range (start, end)) {
2921                         crop_region_to (start, end);
2922                 }
2923         }
2924                 
2925 }               
2926
2927 void
2928 Editor::crop_region_to (nframes_t start, nframes_t end)
2929 {
2930         vector<boost::shared_ptr<Playlist> > playlists;
2931         boost::shared_ptr<Playlist> playlist;
2932         TrackSelection* ts;
2933
2934         if (selection->tracks.empty()) {
2935                 ts = &track_views;
2936         } else {
2937                 sort_track_selection ();
2938                 ts = &selection->tracks;
2939         }
2940         
2941         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2942                 
2943                 AudioTimeAxisView* atv;
2944                 
2945                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2946                         
2947                         if (atv->is_audio_track()) {
2948                                 
2949                                 /* no edits to destructive tracks */
2950
2951                                 if (atv->audio_track()->audio_diskstream()->destructive()) {
2952                                         continue;
2953                                 }
2954
2955                                 if ((playlist = atv->playlist()) != 0) {
2956                                         playlists.push_back (playlist);
2957                                 }
2958                         }
2959                 }
2960         }
2961
2962         if (playlists.empty()) {
2963                 return;
2964         }
2965                 
2966         nframes_t the_start;
2967         nframes_t the_end;
2968         nframes_t cnt;
2969         
2970         begin_reversible_command (_("trim to selection"));
2971         
2972         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2973                 
2974                 boost::shared_ptr<Region> region;
2975         
2976                 the_start = start;
2977         
2978                 if ((region = (*i)->top_region_at(the_start)) == 0) {
2979                         continue;
2980                 }
2981                 
2982                 /* now adjust lengths to that we do the right thing
2983                    if the selection extends beyond the region
2984                 */
2985                 
2986                 the_start = max (the_start, region->position());
2987                 if (max_frames - the_start < region->length()) {
2988                         the_end = the_start + region->length() - 1;
2989                 } else {
2990                         the_end = max_frames;
2991                 }
2992                 the_end = min (end, the_end);
2993                 cnt = the_end - the_start + 1;
2994                 
2995                 XMLNode &before = (*i)->get_state();
2996                 region->trim_to (the_start, cnt, this);
2997                 XMLNode &after = (*i)->get_state();
2998                 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2999         }
3000         
3001         commit_reversible_command ();
3002 }               
3003
3004 void
3005 Editor::region_fill_track ()
3006 {
3007         nframes_t end;
3008         RegionSelection rs; 
3009
3010         get_regions_for_action (rs);
3011
3012         if (!session || rs.empty()) {
3013                 return;
3014         }
3015
3016         end = session->current_end_frame ();
3017
3018         begin_reversible_command (_("region fill"));
3019
3020         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3021
3022                 boost::shared_ptr<Region> region ((*i)->region());
3023                 
3024                 // FIXME
3025                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
3026                 if (!ar)
3027                         continue;
3028
3029                 boost::shared_ptr<Playlist> pl = region->playlist();
3030
3031                 if (end <= region->last_frame()) {
3032                         return;
3033                 }
3034
3035                 double times = (double) (end - region->last_frame()) / (double) region->length();
3036
3037                 if (times == 0) {
3038                         return;
3039                 }
3040
3041                 XMLNode &before = pl->get_state();
3042                 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
3043                 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
3044         }
3045
3046         commit_reversible_command ();
3047 }
3048
3049 void
3050 Editor::region_fill_selection ()
3051 {
3052         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
3053                 return;
3054         }
3055
3056         if (selection->time.empty()) {
3057                 return;
3058         }
3059
3060
3061         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
3062
3063         if (selected->count_selected_rows() != 1) {
3064                 return;
3065         }
3066
3067         TreeModel::iterator i = region_list_display.get_selection()->get_selected();
3068         boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
3069
3070         nframes_t start = selection->time[clicked_selection].start;
3071         nframes_t end = selection->time[clicked_selection].end;
3072
3073         boost::shared_ptr<Playlist> playlist; 
3074
3075         if (selection->tracks.empty()) {
3076                 return;
3077         }
3078
3079         nframes_t selection_length = end - start;
3080         float times = (float)selection_length / region->length();
3081         
3082         begin_reversible_command (_("fill selection"));
3083         
3084         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3085
3086                 if ((playlist = (*i)->playlist()) == 0) {
3087                         continue;
3088                 }               
3089                 
3090                 XMLNode &before = playlist->get_state();
3091                 playlist->add_region (RegionFactory::create (region), start, times);
3092                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3093         }
3094         
3095         commit_reversible_command ();                   
3096 }
3097
3098 void
3099 Editor::set_region_sync_from_edit_point ()
3100 {
3101         nframes64_t where = get_preferred_edit_position ();
3102         RegionSelection rs;
3103         get_regions_for_action (rs);
3104         set_sync_point (where, rs);
3105 }
3106
3107 void
3108 Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
3109 {
3110         bool in_command = false;
3111
3112         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3113                 
3114                 if (!(*r)->region()->covers (where)) {
3115                         continue;
3116                 }
3117
3118                 boost::shared_ptr<Region> region ((*r)->region());
3119
3120                 if (!in_command) {
3121                         begin_reversible_command (_("set sync point"));
3122                         in_command = true;
3123                 }
3124
3125                 XMLNode &before = region->playlist()->get_state();
3126                 region->set_sync_position (get_preferred_edit_position());
3127                 XMLNode &after = region->playlist()->get_state();
3128                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3129         }
3130
3131         if (in_command) {
3132                 commit_reversible_command ();
3133         }
3134 }
3135
3136 void
3137 Editor::remove_region_sync ()
3138 {
3139         if (clicked_regionview) {
3140                 boost::shared_ptr<Region> region (clicked_regionview->region());
3141                 begin_reversible_command (_("remove sync"));
3142                 XMLNode &before = region->playlist()->get_state();
3143                 region->clear_sync_position ();
3144                 XMLNode &after = region->playlist()->get_state();
3145                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3146                 commit_reversible_command ();
3147         }
3148 }
3149
3150 void
3151 Editor::naturalize ()
3152 {
3153         RegionSelection rs; 
3154
3155         get_regions_for_action (rs);
3156
3157         if (rs.empty()) {
3158                 return;
3159         }
3160
3161         begin_reversible_command (_("naturalize"));
3162         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3163                 XMLNode &before = (*i)->region()->get_state();
3164                 (*i)->region()->move_to_natural_position (this);
3165                 XMLNode &after = (*i)->region()->get_state();
3166                 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
3167         }
3168         commit_reversible_command ();
3169 }
3170
3171 void
3172 Editor::align (RegionPoint what)
3173 {
3174         RegionSelection rs; 
3175
3176         get_regions_for_action (rs);
3177         nframes64_t where = get_preferred_edit_position();
3178
3179         if (!rs.empty()) {
3180                 align_selection (what, where, rs);
3181         } else {
3182
3183                 RegionSelection rs;
3184                 get_regions_at (rs, where, selection->tracks);
3185                 align_selection (what, where, rs);
3186         }
3187 }
3188
3189 void
3190 Editor::align_relative (RegionPoint what)
3191 {
3192         nframes64_t where = get_preferred_edit_position();
3193         RegionSelection rs; 
3194
3195         get_regions_for_action (rs);
3196
3197         if (!rs.empty()) {
3198                 align_selection_relative (what, where, rs);
3199         } 
3200 }
3201
3202 struct RegionSortByTime {
3203     bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
3204             return a->region()->position() < b->region()->position();
3205     }
3206 };
3207
3208 void
3209 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
3210 {
3211         if (rs.empty()) {
3212                 return;
3213         }
3214
3215         nframes_t distance;
3216         nframes_t pos = 0;
3217         int dir;
3218
3219         list<RegionView*> sorted;
3220         rs.by_position (sorted);
3221         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3222
3223         switch (point) {
3224         case Start:
3225                 pos = position;
3226                 if (position > r->position()) {
3227                         distance = position - r->position();
3228                         dir = 1;
3229                 } else {
3230                         distance = r->position() - position;
3231                         dir = -1;
3232                 }
3233                 break;
3234                 
3235         case End:
3236                 if (position > r->last_frame()) {
3237                         distance = position - r->last_frame();
3238                         pos = r->position() + distance;
3239                         dir = 1;
3240                 } else {
3241                         distance = r->last_frame() - position;
3242                         pos = r->position() - distance;
3243                         dir = -1;
3244                 }
3245                 break;
3246
3247         case SyncPoint:
3248                 pos = r->adjust_to_sync (position);
3249                 if (pos > r->position()) {
3250                         distance = pos - r->position();
3251                         dir = 1;
3252                 } else {
3253                         distance = r->position() - pos;
3254                         dir = -1;
3255                 }
3256                 break;  
3257         }
3258
3259         if (pos == r->position()) {
3260                 return;
3261         }
3262
3263         begin_reversible_command (_("align selection (relative)"));
3264
3265         /* move first one specially */
3266
3267         XMLNode &before = r->playlist()->get_state();
3268         r->set_position (pos, this);
3269         XMLNode &after = r->playlist()->get_state();
3270         session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
3271
3272         /* move rest by the same amount */
3273         
3274         sorted.pop_front();
3275         
3276         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3277
3278                 boost::shared_ptr<Region> region ((*i)->region());
3279
3280                 XMLNode &before = region->playlist()->get_state();
3281                 
3282                 if (dir > 0) {
3283                         region->set_position (region->position() + distance, this);
3284                 } else {
3285                         region->set_position (region->position() - distance, this);
3286                 }
3287
3288                 XMLNode &after = region->playlist()->get_state();
3289                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3290
3291         }
3292
3293         commit_reversible_command ();
3294 }
3295
3296 void
3297 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
3298 {
3299         if (rs.empty()) {
3300                 return;
3301         }
3302
3303         begin_reversible_command (_("align selection"));
3304
3305         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3306                 align_region_internal ((*i)->region(), point, position);
3307         }
3308
3309         commit_reversible_command ();
3310 }
3311
3312 void
3313 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
3314 {
3315         begin_reversible_command (_("align region"));
3316         align_region_internal (region, point, position);
3317         commit_reversible_command ();
3318 }
3319
3320 void
3321 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
3322 {
3323         XMLNode &before = region->playlist()->get_state();
3324
3325         switch (point) {
3326         case SyncPoint:
3327                 region->set_position (region->adjust_to_sync (position), this);
3328                 break;
3329
3330         case End:
3331                 if (position > region->length()) {
3332                         region->set_position (position - region->length(), this);
3333                 }
3334                 break;
3335
3336         case Start:
3337                 region->set_position (position, this);
3338                 break;
3339         }
3340
3341         XMLNode &after = region->playlist()->get_state();
3342         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3343 }       
3344
3345 void
3346 Editor::trim_region_to_loop ()
3347 {
3348         Location* loc = session->locations()->auto_loop_location();
3349         if (!loc) {
3350                 return;
3351         }
3352         trim_region_to_location (*loc, _("trim to loop"));
3353 }
3354
3355 void
3356 Editor::trim_region_to_punch ()
3357 {
3358         Location* loc = session->locations()->auto_punch_location();
3359         if (!loc) {
3360                 return;
3361         }
3362         trim_region_to_location (*loc, _("trim to punch"));
3363 }
3364
3365 void
3366 Editor::trim_region_to_location (const Location& loc, const char* str)
3367 {
3368         RegionSelection rs;
3369
3370         get_regions_for_action (rs);
3371
3372         begin_reversible_command (str);
3373
3374         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3375                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3376
3377                 if (!arv) {
3378                         continue;
3379                 }
3380
3381                 /* require region to span proposed trim */
3382
3383                 switch (arv->region()->coverage (loc.start(), loc.end())) {
3384                 case OverlapInternal:
3385                         break;
3386                 default:
3387                         continue;
3388                 }
3389                                 
3390                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3391
3392                 if (!atav) {
3393                         return;
3394                 }
3395
3396                 float speed = 1.0;
3397                 nframes_t start;
3398                 nframes_t end;
3399
3400                 if (atav->get_diskstream() != 0) {
3401                         speed = atav->get_diskstream()->speed();
3402                 }
3403
3404                 start = session_frame_to_track_frame (loc.start(), speed);
3405                 end = session_frame_to_track_frame (loc.end(), speed);
3406
3407                 XMLNode &before = arv->region()->playlist()->get_state();
3408                 arv->region()->trim_to (start, (end - start), this);
3409                 XMLNode &after = arv->region()->playlist()->get_state();
3410                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
3411         }
3412                 
3413         commit_reversible_command ();
3414 }
3415
3416 void
3417 Editor::trim_region_to_edit_point ()
3418 {
3419         RegionSelection rs;
3420         
3421         get_regions_for_action (rs);
3422
3423         nframes64_t where = get_preferred_edit_position();
3424
3425         begin_reversible_command (_("trim region start to edit point"));
3426
3427         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3428                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3429
3430                 if (!arv) {
3431                         continue;
3432                 }
3433
3434                 /* require region to cover trim */
3435
3436                 if (!arv->region()->covers (where)) {
3437                         continue;
3438                 }
3439
3440                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3441
3442                 if (!atav) {
3443                         return;
3444                 }
3445
3446                 float speed = 1.0;
3447
3448                 if (atav->get_diskstream() != 0) {
3449                         speed = atav->get_diskstream()->speed();
3450                 }
3451
3452                 XMLNode &before = arv->region()->playlist()->get_state();
3453                 arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
3454                 XMLNode &after = arv->region()->playlist()->get_state();
3455                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
3456         }
3457                 
3458         commit_reversible_command ();
3459 }
3460
3461 void
3462 Editor::trim_region_from_edit_point ()
3463 {
3464         RegionSelection rs;
3465
3466         get_regions_for_action (rs);
3467
3468         nframes64_t where = get_preferred_edit_position();
3469
3470         begin_reversible_command (_("trim region end to edit point"));
3471
3472         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3473                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3474
3475                 if (!arv) {
3476                         continue;
3477                 }
3478
3479                 /* require region to cover trim */
3480
3481                 if (!arv->region()->covers (where)) {
3482                         continue;
3483                 }
3484
3485                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3486
3487                 if (!atav) {
3488                         return;
3489                 }
3490
3491                 float speed = 1.0;
3492
3493                 if (atav->get_diskstream() != 0) {
3494                         speed = atav->get_diskstream()->speed();
3495                 }
3496
3497                 XMLNode &before = arv->region()->playlist()->get_state();
3498                 arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
3499                 XMLNode &after = arv->region()->playlist()->get_state();
3500                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
3501         }
3502                 
3503         commit_reversible_command ();
3504 }
3505
3506 void
3507 Editor::unfreeze_route ()
3508 {
3509         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
3510                 return;
3511         }
3512         
3513         clicked_audio_trackview->audio_track()->unfreeze ();
3514 }
3515
3516 void*
3517 Editor::_freeze_thread (void* arg)
3518 {
3519         PBD::ThreadCreated (pthread_self(), X_("Freeze"));
3520         return static_cast<Editor*>(arg)->freeze_thread ();
3521 }
3522
3523 void*
3524 Editor::freeze_thread ()
3525 {
3526         clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
3527         return 0;
3528 }
3529
3530 gint
3531 Editor::freeze_progress_timeout (void *arg)
3532 {
3533         interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
3534         return !(current_interthread_info->done || current_interthread_info->cancel);
3535 }
3536
3537 void
3538 Editor::freeze_route ()
3539 {
3540         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
3541                 return;
3542         }
3543         
3544         InterThreadInfo itt;
3545
3546         if (interthread_progress_window == 0) {
3547                 build_interthread_progress_window ();
3548         }
3549
3550         WindowTitle title(Glib::get_application_name());
3551         title += _("Freeze");
3552         interthread_progress_window->set_title (title.get_string());
3553         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
3554         interthread_progress_window->show_all ();
3555         interthread_progress_bar.set_fraction (0.0f);
3556         interthread_progress_label.set_text ("");
3557         interthread_cancel_label.set_text (_("Cancel Freeze"));
3558         current_interthread_info = &itt;
3559
3560         interthread_progress_connection = 
3561           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
3562
3563         itt.done = false;
3564         itt.cancel = false;
3565         itt.progress = 0.0f;
3566         
3567         pthread_attr_t attr;
3568         pthread_attr_init(&attr);
3569         pthread_attr_setstacksize(&attr, 500000);
3570
3571         pthread_create (&itt.thread, &attr, _freeze_thread, this);
3572
3573         pthread_attr_destroy(&attr);
3574
3575         track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
3576
3577         while (!itt.done && !itt.cancel) {
3578                 gtk_main_iteration ();
3579         }
3580
3581         interthread_progress_connection.disconnect ();
3582         interthread_progress_window->hide_all ();
3583         current_interthread_info = 0;
3584         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
3585 }
3586
3587 void
3588 Editor::bounce_range_selection ()
3589 {
3590         if (selection->time.empty()) {
3591                 return;
3592         }
3593
3594         TrackSelection views = selection->tracks;
3595
3596         nframes_t start = selection->time[clicked_selection].start;
3597         nframes_t end = selection->time[clicked_selection].end;
3598         nframes_t cnt = end - start + 1;
3599
3600         begin_reversible_command (_("bounce range"));
3601
3602         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3603
3604                 AudioTimeAxisView* atv;
3605
3606                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
3607                         continue;
3608                 }
3609                 
3610                 boost::shared_ptr<Playlist> playlist;
3611                 
3612                 if ((playlist = atv->playlist()) == 0) {
3613                         return;
3614                 }
3615
3616                 InterThreadInfo itt;
3617                 
3618                 itt.done = false;
3619                 itt.cancel = false;
3620                 itt.progress = false;
3621
3622                 XMLNode &before = playlist->get_state();
3623                 atv->audio_track()->bounce_range (start, cnt, itt);
3624                 XMLNode &after = playlist->get_state();
3625                 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
3626         }
3627         
3628         commit_reversible_command ();
3629 }
3630
3631 void
3632 Editor::cut ()
3633 {
3634         cut_copy (Cut);
3635 }
3636
3637 void
3638 Editor::copy ()
3639 {
3640         cut_copy (Copy);
3641 }
3642
3643 void 
3644 Editor::cut_copy (CutCopyOp op)
3645 {
3646         /* only cancel selection if cut/copy is successful.*/
3647
3648         string opname;
3649
3650         switch (op) {
3651         case Cut:
3652                 opname = _("cut");
3653                 break;
3654         case Copy:
3655                 opname = _("copy");
3656                 break;
3657         case Clear:
3658                 opname = _("clear");
3659                 break;
3660         }
3661         
3662         cut_buffer->clear ();
3663
3664         if (entered_marker) {
3665
3666                 /* cut/delete op while pointing at a marker */
3667
3668                 bool ignored;
3669                 Location* loc = find_location_from_marker (entered_marker, ignored);
3670
3671                 if (session && loc) {
3672                         Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
3673                 }
3674
3675                 return;
3676         }
3677
3678         RegionSelection rs; 
3679
3680         /* we only want to cut regions if some are selected */
3681
3682         if (!selection->regions.empty()) {
3683                 get_regions_for_action (rs);
3684         }
3685
3686         switch (current_mouse_mode()) {
3687         case MouseObject: 
3688                 if (!rs.empty() || !selection->points.empty()) {
3689
3690                         begin_reversible_command (opname + _(" objects"));
3691
3692                         if (!rs.empty()) {
3693                                 cut_copy_regions (op, rs);
3694                                 
3695                                 if (op == Cut) {
3696                                         selection->clear_regions ();
3697                                 }
3698                         }
3699
3700                         if (!selection->points.empty()) {
3701                                 cut_copy_points (op);
3702
3703                                 if (op == Cut) {
3704                                         selection->clear_points ();
3705                                 }
3706                         }
3707
3708                         commit_reversible_command ();   
3709                         break; // terminate case statement here
3710                 } 
3711                 if (!selection->time.empty()) {
3712                         /* don't cause suprises */
3713                         break;
3714                 }
3715                 // fall thru if there was nothing selected
3716                 
3717         case MouseRange:
3718                 if (selection->time.empty()) {
3719                         nframes64_t start, end;
3720                         if (!get_edit_op_range (start, end)) {
3721                                 return;
3722                         }
3723                         selection->set ((TimeAxisView*) 0, start, end);
3724                 }
3725                         
3726                 begin_reversible_command (opname + _(" range"));
3727                 cut_copy_ranges (op);
3728                 commit_reversible_command ();
3729                 
3730                 if (op == Cut) {
3731                         selection->clear_time ();
3732                 }
3733
3734                 break;
3735                 
3736         default:
3737                 break;
3738         }
3739 }
3740
3741 void
3742 Editor::cut_copy_points (CutCopyOp op)
3743 {
3744         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3745
3746                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3747
3748                 if (atv) {
3749                         atv->cut_copy_clear_objects (selection->points, op);
3750                 } 
3751         }
3752 }
3753
3754 struct PlaylistState {
3755     boost::shared_ptr<Playlist> playlist;
3756     XMLNode*  before;
3757 };
3758
3759 struct lt_playlist {
3760     bool operator () (const PlaylistState& a, const PlaylistState& b) {
3761             return a.playlist < b.playlist;
3762     }
3763 };
3764         
3765 struct PlaylistMapping { 
3766     TimeAxisView* tv;
3767     boost::shared_ptr<AudioPlaylist> pl;
3768
3769     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3770 };
3771
3772 void
3773 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
3774 {
3775         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3776            a map when we want ordered access to both elements. i think.
3777         */
3778
3779         vector<PlaylistMapping> pmap;
3780
3781         nframes_t first_position = max_frames;
3782         
3783         set<PlaylistState, lt_playlist> freezelist;
3784         pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3785         
3786         /* get ordering correct before we cut/copy */
3787         
3788         rs.sort_by_position_and_track ();
3789
3790         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3791
3792                 first_position = min ((*x)->region()->position(), first_position);
3793
3794                 if (op == Cut || op == Clear) {
3795                         boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3796
3797                         if (pl) {
3798
3799                                 PlaylistState before;
3800                                 before.playlist = pl;
3801                                 before.before = &pl->get_state();
3802                                 
3803                                 insert_result = freezelist.insert (before);
3804                                 
3805                                 if (insert_result.second) {
3806                                         pl->freeze ();
3807                                 }
3808                         }
3809                 }
3810
3811                 TimeAxisView* tv = &(*x)->get_trackview();
3812                 vector<PlaylistMapping>::iterator z;
3813
3814                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3815                         if ((*z).tv == tv) {
3816                                 break;
3817                         }
3818                 }
3819                 
3820                 if (z == pmap.end()) {
3821                         pmap.push_back (PlaylistMapping (tv));
3822                 }
3823         }
3824
3825         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
3826
3827                 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3828                 
3829                 if (!pl) {
3830                         /* impossible, but this handles it for the future */
3831                         continue;
3832                 }
3833
3834                 TimeAxisView& tv = (*x)->get_trackview();
3835                 boost::shared_ptr<AudioPlaylist> npl;
3836                 RegionSelection::iterator tmp;
3837                 
3838                 tmp = x;
3839                 ++tmp;
3840
3841                 vector<PlaylistMapping>::iterator z;
3842                 
3843                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3844                         if ((*z).tv == &tv) {
3845                                 break;
3846                         }
3847                 }
3848                 
3849                 assert (z != pmap.end());
3850                 
3851                 if (!(*z).pl) {
3852                         npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3853                         npl->freeze();
3854                         (*z).pl = npl;
3855                 } else {
3856                         npl = (*z).pl;
3857                 }
3858                 
3859                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3860                 boost::shared_ptr<Region> _xx;
3861                 
3862                 switch (op) {
3863                 case Cut:
3864                         if (!ar) break;
3865                         
3866                         _xx = RegionFactory::create ((*x)->region());
3867                         npl->add_region (_xx, (*x)->region()->position() - first_position);
3868                         pl->remove_region (((*x)->region()));
3869                         break;
3870                         
3871                 case Copy:
3872                         if (!ar) break;
3873
3874                         /* copy region before adding, so we're not putting same object into two different playlists */
3875                         npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3876                         break;
3877                         
3878                 case Clear:
3879                         pl->remove_region (((*x)->region()));
3880                         break;
3881                 }
3882
3883                 x = tmp;
3884         }
3885         
3886         list<boost::shared_ptr<Playlist> > foo;
3887         
3888         /* the pmap is in the same order as the tracks in which selected regions occured */
3889         
3890         for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3891                 (*i).pl->thaw();
3892                 foo.push_back ((*i).pl);
3893         }
3894         
3895
3896         if (!foo.empty()) {
3897                 cut_buffer->set (foo);
3898         }
3899
3900         for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3901                 (*pl).playlist->thaw ();
3902                 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3903         }
3904 }
3905
3906 void
3907 Editor::cut_copy_ranges (CutCopyOp op)
3908 {
3909         TrackSelection* ts;
3910         TrackSelection entered;
3911
3912         if (selection->tracks.empty()) {
3913                 if (!entered_track) {
3914                         return;
3915                 }
3916                 entered.push_back (entered_track);
3917                 ts = &entered;
3918         } else {
3919                 ts = &selection->tracks;
3920         }
3921
3922         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3923                 (*i)->cut_copy_clear (*selection, op);
3924         }
3925 }
3926
3927 void
3928 Editor::paste (float times)
3929 {
3930         paste_internal (get_preferred_edit_position(), times);
3931 }
3932
3933 void
3934 Editor::mouse_paste ()
3935 {
3936         nframes64_t where;
3937         bool ignored;
3938
3939         if (!mouse_frame (where, ignored)) {
3940                 return;
3941         }
3942
3943         snap_to (where);
3944         paste_internal (where, 1);
3945 }
3946
3947 void
3948 Editor::paste_internal (nframes_t position, float times)
3949 {
3950         bool commit = false;
3951
3952         if (cut_buffer->empty()) {
3953                 return;
3954         }
3955
3956         if (position == max_frames) {
3957                 position = get_preferred_edit_position();
3958         }
3959
3960         begin_reversible_command (_("paste"));
3961
3962         TrackSelection ts;
3963         TrackSelection::iterator i;
3964         size_t nth;
3965
3966         /* get everything in the correct order */
3967
3968
3969         if (!selection->tracks.empty()) {
3970                 sort_track_selection ();
3971                 ts = selection->tracks;
3972         } else if (entered_track) {
3973                 ts.push_back (entered_track);
3974         }
3975
3976         for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
3977
3978                 /* undo/redo is handled by individual tracks */
3979
3980                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3981                         commit = true;
3982                 }
3983         }
3984         
3985         if (commit) {
3986                 commit_reversible_command ();
3987         }
3988 }
3989
3990 void
3991 Editor::paste_named_selection (float times)
3992 {
3993         TrackSelection::iterator t;
3994
3995         Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3996
3997         if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3998                 return;
3999         }
4000
4001         TreeModel::iterator i = selected->get_selected();
4002         NamedSelection* ns = (*i)[named_selection_columns.selection];
4003
4004         list<boost::shared_ptr<Playlist> >::iterator chunk;
4005         list<boost::shared_ptr<Playlist> >::iterator tmp;
4006
4007         chunk = ns->playlists.begin();
4008                 
4009         begin_reversible_command (_("paste chunk"));
4010         
4011         sort_track_selection ();
4012
4013         for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
4014                 
4015                 AudioTimeAxisView* atv;
4016                 boost::shared_ptr<Playlist> pl;
4017                 boost::shared_ptr<AudioPlaylist> apl;
4018
4019                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
4020                         continue;
4021                 }
4022
4023                 if ((pl = atv->playlist()) == 0) {
4024                         continue;
4025                 }
4026                 
4027                 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
4028                         continue;
4029                 }
4030
4031                 tmp = chunk;
4032                 ++tmp;
4033
4034                 XMLNode &before = apl->get_state();
4035                 apl->paste (*chunk, get_preferred_edit_position(), times);
4036                 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
4037
4038                 if (tmp != ns->playlists.end()) {
4039                         chunk = tmp;
4040                 }
4041         }
4042
4043         commit_reversible_command();
4044 }
4045
4046 void
4047 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4048 {
4049         boost::shared_ptr<Playlist> playlist; 
4050         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4051         RegionSelection foo;
4052
4053         begin_reversible_command (_("duplicate region"));
4054
4055         selection->clear_regions ();
4056
4057         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4058
4059                 boost::shared_ptr<Region> r ((*i)->region());
4060
4061                 TimeAxisView& tv = (*i)->get_time_axis_view();
4062                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
4063
4064                 latest_regionviews.clear ();
4065                 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
4066                 
4067                 playlist = (*i)->region()->playlist();
4068                 XMLNode &before = playlist->get_state();
4069                 playlist->duplicate (r, r->last_frame() + 1, times);
4070                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
4071
4072                 c.disconnect ();
4073                 
4074                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4075         }
4076
4077         commit_reversible_command ();
4078
4079         if (!foo.empty()) {
4080                 selection->set (foo);
4081         }
4082 }
4083
4084 void
4085 Editor::duplicate_selection (float times)
4086 {
4087         if (selection->time.empty() || selection->tracks.empty()) {
4088                 return;
4089         }
4090
4091         boost::shared_ptr<Playlist> playlist; 
4092         vector<boost::shared_ptr<AudioRegion> > new_regions;
4093         vector<boost::shared_ptr<AudioRegion> >::iterator ri;
4094                 
4095         create_region_from_selection (new_regions);
4096
4097         if (new_regions.empty()) {
4098                 return;
4099         }
4100         
4101         begin_reversible_command (_("duplicate selection"));
4102
4103         ri = new_regions.begin();
4104
4105         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4106                 if ((playlist = (*i)->playlist()) == 0) {
4107                         continue;
4108                 }
4109                 XMLNode &before = playlist->get_state();
4110                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4111                 XMLNode &after = playlist->get_state();
4112                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
4113
4114                 ++ri;
4115                 if (ri == new_regions.end()) {
4116                         --ri;
4117                 }
4118         }
4119
4120         commit_reversible_command ();
4121 }
4122
4123 void
4124 Editor::reset_point_selection ()
4125 {
4126         /* reset all selected points to the relevant default value */
4127
4128         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4129                 
4130                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
4131                 
4132                 if (atv) {
4133                         atv->reset_objects (selection->points);
4134                 } 
4135         }
4136 }
4137
4138 void
4139 Editor::center_playhead ()
4140 {
4141         float page = canvas_width * frames_per_unit;
4142         center_screen_internal (playhead_cursor->current_frame, page);
4143 }
4144
4145 void
4146 Editor::center_edit_point ()
4147 {
4148         float page = canvas_width * frames_per_unit;
4149         center_screen_internal (get_preferred_edit_position(), page);
4150 }
4151
4152 void
4153 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4154 {
4155         begin_reversible_command (_("clear playlist"));
4156         XMLNode &before = playlist->get_state();
4157         playlist->clear ();
4158         XMLNode &after = playlist->get_state();
4159         session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
4160         commit_reversible_command ();
4161 }
4162
4163 void
4164 Editor::nudge_track (bool use_edit, bool forwards)
4165 {
4166         boost::shared_ptr<Playlist> playlist; 
4167         nframes_t distance;
4168         nframes_t next_distance;
4169         nframes_t start;
4170
4171         if (use_edit) {
4172                 start = get_preferred_edit_position();
4173         } else {
4174                 start = 0;
4175         }
4176
4177         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4178                 return;
4179         }
4180         
4181         if (selection->tracks.empty()) {
4182                 return;
4183         }
4184         
4185         begin_reversible_command (_("nudge track"));
4186         
4187         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4188
4189                 if ((playlist = (*i)->playlist()) == 0) {
4190                         continue;
4191                 }               
4192                 
4193                 XMLNode &before = playlist->get_state();
4194                 playlist->nudge_after (start, distance, forwards);
4195                 XMLNode &after = playlist->get_state();
4196                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
4197         }
4198         
4199         commit_reversible_command ();                   
4200 }
4201
4202 void
4203 Editor::remove_last_capture ()
4204 {
4205         vector<string> choices;
4206         string prompt;
4207         
4208         if (!session) {
4209                 return;
4210         }
4211
4212         if (Config->get_verify_remove_last_capture()) {
4213                 prompt  = _("Do you really want to destroy the last capture?"
4214                             "\n(This is destructive and cannot be undone)");
4215
4216                 choices.push_back (_("No, do nothing."));
4217                 choices.push_back (_("Yes, destroy it."));
4218                 
4219                 Gtkmm2ext::Choice prompter (prompt, choices);
4220                 
4221                 if (prompter.run () == 1) {
4222                         session->remove_last_capture ();
4223                 }
4224
4225         } else {
4226                 session->remove_last_capture();
4227         }
4228 }
4229
4230 void
4231 Editor::normalize_region ()
4232 {
4233         RegionSelection rs; 
4234
4235         get_regions_for_action (rs);
4236         
4237         if (!session) {
4238                 return;
4239         }
4240
4241         if (rs.empty()) {
4242                 return;
4243         }
4244
4245         begin_reversible_command (_("normalize"));
4246
4247         track_canvas->get_window()->set_cursor (*wait_cursor);
4248         gdk_flush ();
4249
4250         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4251                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4252                 if (!arv)
4253                         continue;
4254                 XMLNode &before = arv->region()->get_state();
4255                 arv->audio_region()->normalize_to (0.0f);
4256                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4257         }
4258
4259         commit_reversible_command ();
4260         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
4261 }
4262
4263
4264 void
4265 Editor::denormalize_region ()
4266 {
4267         if (!session) {
4268                 return;
4269         }
4270
4271         RegionSelection rs; 
4272
4273         get_regions_for_action (rs);
4274
4275         if (rs.empty()) {
4276                 return;
4277         }
4278
4279         begin_reversible_command ("denormalize");
4280
4281         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4282                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4283                 if (!arv)
4284                         continue;
4285                 XMLNode &before = arv->region()->get_state();
4286                 arv->audio_region()->set_scale_amplitude (1.0f);
4287                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4288         }
4289
4290         commit_reversible_command ();
4291 }
4292
4293 void
4294 Editor::adjust_region_scale_amplitude (bool up)
4295 {
4296         if (!session) {
4297                 return;
4298         }
4299
4300         RegionSelection rs; 
4301
4302         get_regions_for_action (rs);
4303
4304         if (rs.empty()) {
4305                 return;
4306         }
4307
4308         begin_reversible_command ("denormalize");
4309
4310         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4311                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4312                 if (!arv)
4313                         continue;
4314                 XMLNode &before = arv->region()->get_state();
4315                 
4316                 double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ());
4317                 
4318                 if (up) {
4319                         fraction += 0.05;
4320                         fraction = min (fraction, 1.0);
4321                 } else {
4322                         fraction -= 0.05;
4323                         fraction = max (fraction, 0.0);
4324                 }
4325
4326                 if (!up && fraction <= 0) {
4327                         continue;
4328                 }
4329
4330                 fraction = slider_position_to_gain (fraction);
4331                 fraction = coefficient_to_dB (fraction);
4332                 fraction = dB_to_coefficient (fraction);
4333
4334                 if (up && fraction >= 2.0) {
4335                         continue;
4336                 }
4337                 
4338                 arv->audio_region()->set_scale_amplitude (fraction);
4339                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4340         }
4341
4342         commit_reversible_command ();
4343 }
4344
4345
4346 void
4347 Editor::reverse_region ()
4348 {
4349         if (!session) {
4350                 return;
4351         }
4352
4353         Reverse rev (*session);
4354         apply_filter (rev, _("reverse regions"));
4355 }
4356
4357 void
4358 Editor::apply_filter (AudioFilter& filter, string command)
4359 {
4360         RegionSelection rs; 
4361
4362         get_regions_for_action (rs);
4363
4364         if (rs.empty()) {
4365                 return;
4366         }
4367
4368         begin_reversible_command (command);
4369
4370         track_canvas->get_window()->set_cursor (*wait_cursor);
4371         gdk_flush ();
4372
4373         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4374                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4375                 if (!arv)
4376                         continue;
4377
4378                 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4379
4380                 RegionSelection::iterator tmp;
4381                 
4382                 tmp = r;
4383                 ++tmp;
4384
4385                 if (arv->audio_region()->apply (filter) == 0) {
4386
4387                         XMLNode &before = playlist->get_state();
4388                         playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
4389                         XMLNode &after = playlist->get_state();
4390                         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
4391                 } else {
4392                         goto out;
4393                 }
4394
4395                 r = tmp;
4396         }
4397
4398         commit_reversible_command ();
4399         rs.clear ();
4400
4401   out:
4402         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
4403 }
4404
4405 void
4406 Editor::region_selection_op (void (Region::*pmf)(void))
4407 {
4408         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4409                 Region* region = (*i)->region().get();
4410                 (region->*pmf)();
4411         }
4412 }
4413
4414
4415 void
4416 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
4417 {
4418         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4419                 Region* region = (*i)->region().get();
4420                 (region->*pmf)(arg);
4421         }
4422 }
4423
4424 void
4425 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
4426 {
4427         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4428                 Region* region = (*i)->region().get();
4429                 (region->*pmf)(yn);
4430         }
4431 }
4432
4433 void
4434 Editor::external_edit_region ()
4435 {
4436         if (!clicked_regionview) {
4437                 return;
4438         }
4439
4440         /* more to come */
4441 }
4442
4443 void
4444 Editor::brush (nframes_t pos)
4445 {
4446         RegionSelection sel;
4447         RegionSelection rs; 
4448
4449         get_regions_for_action (rs);
4450
4451         snap_to (pos);
4452
4453         if (rs.empty()) {
4454                 return;
4455         }
4456
4457         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4458                 mouse_brush_insert_region ((*i), pos);
4459         }
4460 }
4461
4462 void
4463 Editor::reset_region_gain_envelopes ()
4464 {
4465         RegionSelection rs; 
4466
4467         get_regions_for_action (rs);
4468
4469         if (!session || rs.empty()) {
4470                 return;
4471         }
4472
4473         session->begin_reversible_command (_("reset region gain"));
4474
4475         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4476                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4477                 if (arv) {
4478                         AutomationList& alist (arv->audio_region()->envelope());
4479                         XMLNode& before (alist.get_state());
4480
4481                         arv->audio_region()->set_default_envelope ();
4482                         session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
4483                 }
4484         }
4485
4486         session->commit_reversible_command ();
4487 }
4488
4489 void
4490 Editor::toggle_gain_envelope_visibility ()
4491 {
4492         RegionSelection rs; 
4493
4494         get_regions_for_action (rs);
4495
4496         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4497                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4498                 if (arv) {
4499                         arv->set_envelope_visible (!arv->envelope_visible());
4500                 }
4501         }
4502 }
4503
4504 void
4505 Editor::toggle_gain_envelope_active ()
4506 {
4507         RegionSelection rs; 
4508
4509         get_regions_for_action (rs);
4510
4511         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4512                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4513                 if (arv) {
4514                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4515                 }
4516         }
4517 }
4518
4519 void
4520 Editor::toggle_region_lock ()
4521 {
4522         RegionSelection rs; 
4523
4524         get_regions_for_action (rs);
4525
4526         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4527                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4528                 if (arv) {
4529                         arv->audio_region()->set_locked (!arv->audio_region()->locked());
4530                 }
4531         }
4532 }
4533
4534 void
4535 Editor::set_region_lock_style (Region::PositionLockStyle ps)
4536 {
4537         RegionSelection rs; 
4538
4539         get_regions_for_action (rs);
4540
4541         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4542                 (*i)->region()->set_position_lock_style (ps);
4543         }
4544 }
4545
4546
4547 void
4548 Editor::toggle_region_mute ()
4549 {
4550         RegionSelection rs; 
4551
4552         get_regions_for_action (rs);
4553
4554         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4555                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4556                 if (arv) {
4557                         arv->audio_region()->set_muted (!arv->audio_region()->muted());
4558                 }
4559         }
4560 }
4561
4562 void
4563 Editor::toggle_region_opaque ()
4564 {
4565         RegionSelection rs; 
4566
4567         get_regions_for_action (rs);
4568
4569         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4570                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4571                 if (arv) {
4572                         arv->audio_region()->set_opaque (!arv->audio_region()->opaque());
4573                 }
4574         }
4575 }
4576
4577 void
4578 Editor::set_fade_length (bool in)
4579 {
4580         RegionSelection rs; 
4581
4582         get_regions_for_action (rs);
4583
4584         /* we need a region to measure the offset from the start */
4585
4586         RegionView* rv;
4587
4588         if (!rs.empty()) {
4589                 rv = rs.front();
4590         } else if (entered_regionview) {
4591                 rv = entered_regionview;
4592         } else {
4593                 return;
4594         }
4595
4596         nframes64_t pos = get_preferred_edit_position();
4597         nframes_t len;
4598         char* cmd;
4599         
4600         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
4601                 /* edit point is outside the relevant region */
4602                 return;
4603         }
4604
4605         if (in) {
4606                 if (pos <= rv->region()->position()) {
4607                         /* can't do it */
4608                         return;
4609                 }
4610                 len = pos - rv->region()->position();
4611                 cmd = _("set fade in length");
4612         } else {
4613                 if (pos >= rv->region()->last_frame()) {
4614                         /* can't do it */
4615                         return;
4616                 }
4617                 len = rv->region()->last_frame() - pos;
4618                 cmd = _("set fade out length");
4619         }
4620
4621         begin_reversible_command (cmd);
4622
4623         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4624                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4625
4626                 if (!tmp) {
4627                         return;
4628                 }
4629
4630                 AutomationList* alist;
4631                 if (in) {
4632                         alist = &tmp->audio_region()->fade_in();
4633                 } else {
4634                         alist = &tmp->audio_region()->fade_out();
4635                 }
4636
4637                 XMLNode &before = alist->get_state();
4638
4639                 if (in) {
4640                         tmp->audio_region()->set_fade_in_length (len);
4641                         tmp->audio_region()->set_fade_in_active (true);
4642                 } else {
4643                         tmp->audio_region()->set_fade_out_length (len);
4644                         tmp->audio_region()->set_fade_out_active (true);
4645                 }
4646                 
4647                 XMLNode &after = alist->get_state();
4648                 session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
4649         }
4650
4651         commit_reversible_command ();
4652 }
4653
4654
4655 void
4656 Editor::toggle_fade_active (bool in)
4657 {
4658         RegionSelection rs; 
4659
4660         get_regions_for_action (rs);
4661
4662         if (rs.empty()) {
4663                 return;
4664         }
4665
4666         const char* cmd = (in ? _("toggle fade in active") : _("toggle fade out active"));
4667         bool have_switch = false;
4668         bool yn;
4669
4670         begin_reversible_command (cmd);
4671
4672         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4673                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4674                 
4675                 if (!tmp) {
4676                         return;
4677                 }
4678
4679                 boost::shared_ptr<AudioRegion> region (tmp->audio_region());
4680
4681                 /* make the behaviour consistent across all regions */
4682                 
4683                 if (!have_switch) {
4684                         if (in) {
4685                                 yn = region->fade_in_active();
4686                         } else {
4687                                 yn = region->fade_out_active();
4688                         }
4689                         have_switch = true;
4690                 }
4691
4692                 XMLNode &before = region->get_state();
4693                 if (in) {
4694                         region->set_fade_in_active (!yn);
4695                 } else {
4696                         region->set_fade_out_active (!yn);
4697                 }
4698                 XMLNode &after = region->get_state();
4699                 session->add_command(new MementoCommand<AudioRegion>(*region.get(), &before, &after));
4700         }
4701
4702         commit_reversible_command ();
4703 }
4704
4705 void
4706 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
4707 {
4708         RegionSelection rs; 
4709
4710         get_regions_for_action (rs);
4711
4712         if (rs.empty()) {
4713                 return;
4714         }
4715
4716         begin_reversible_command (_("set fade in shape"));
4717
4718         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4719                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4720
4721                 if (!tmp) {
4722                         return;
4723                 }
4724
4725                 AutomationList& alist = tmp->audio_region()->fade_in();
4726                 XMLNode &before = alist.get_state();
4727
4728                 tmp->audio_region()->set_fade_in_shape (shape);
4729                 
4730                 XMLNode &after = alist.get_state();
4731                 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
4732         }
4733
4734         commit_reversible_command ();
4735                 
4736 }
4737
4738 void
4739 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
4740 {
4741         RegionSelection rs; 
4742
4743         get_regions_for_action (rs);
4744
4745         if (rs.empty()) {
4746                 return;
4747         }
4748
4749         begin_reversible_command (_("set fade out shape"));
4750
4751         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4752                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4753
4754                 if (!tmp) {
4755                         return;
4756                 }
4757
4758                 AutomationList& alist = tmp->audio_region()->fade_out();
4759                 XMLNode &before = alist.get_state();
4760
4761                 tmp->audio_region()->set_fade_out_shape (shape);
4762                 
4763                 XMLNode &after = alist.get_state();
4764                 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
4765         }
4766
4767         commit_reversible_command ();
4768 }
4769
4770 void
4771 Editor::set_fade_in_active (bool yn)
4772 {
4773         RegionSelection rs; 
4774
4775         get_regions_for_action (rs);
4776
4777         if (rs.empty()) {
4778                 return;
4779         }
4780
4781         begin_reversible_command (_("set fade in active"));
4782
4783         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4784                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4785
4786                 if (!tmp) {
4787                         return;
4788                 }
4789
4790
4791                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4792
4793                 XMLNode &before = ar->get_state();
4794
4795                 ar->set_fade_in_active (yn);
4796                 
4797                 XMLNode &after = ar->get_state();
4798                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4799         }
4800
4801         commit_reversible_command ();
4802 }
4803
4804 void
4805 Editor::set_fade_out_active (bool yn)
4806 {
4807         RegionSelection rs; 
4808
4809         get_regions_for_action (rs);
4810
4811         if (rs.empty()) {
4812                 return;
4813         }
4814
4815         begin_reversible_command (_("set fade out active"));
4816
4817         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4818                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4819
4820                 if (!tmp) {
4821                         return;
4822                 }
4823
4824                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4825
4826                 XMLNode &before = ar->get_state();
4827
4828                 ar->set_fade_out_active (yn);
4829                 
4830                 XMLNode &after = ar->get_state();
4831                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4832         }
4833
4834         commit_reversible_command ();
4835 }
4836
4837
4838 /** Update crossfade visibility after its configuration has been changed */
4839 void
4840 Editor::update_xfade_visibility ()
4841 {
4842         _xfade_visibility = Config->get_xfades_visible ();
4843         
4844         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4845                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4846                 if (v) {
4847                         if (_xfade_visibility) {
4848                                 v->show_all_xfades ();
4849                         } else {
4850                                 v->hide_all_xfades ();
4851                         }
4852                 }
4853         }
4854 }
4855
4856 void
4857 Editor::set_edit_point ()
4858 {
4859         nframes64_t where;
4860         bool ignored;
4861
4862         if (!mouse_frame (where, ignored)) {
4863                 return;
4864         }
4865         
4866         snap_to (where);
4867
4868         if (selection->markers.empty()) {
4869                 
4870                 mouse_add_new_marker (where);
4871
4872         } else {
4873                 bool ignored;
4874
4875                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
4876
4877                 if (loc) {
4878                         loc->move_to (where);
4879                 }
4880         }
4881 }
4882
4883 void
4884 Editor::set_playhead_cursor ()
4885 {
4886         if (entered_marker) {
4887                 session->request_locate (entered_marker->position(), session->transport_rolling());
4888         } else {
4889                 nframes64_t where;
4890                 bool ignored;
4891
4892                 if (!mouse_frame (where, ignored)) {
4893                         return;
4894                 }
4895                         
4896                 snap_to (where);
4897                 
4898                 if (session) {
4899                         session->request_locate (where, session->transport_rolling());
4900                 }
4901         }
4902 }
4903
4904 void
4905 Editor::split ()
4906 {
4907         RegionSelection rs; 
4908
4909         get_regions_for_action (rs);
4910
4911         nframes64_t where = get_preferred_edit_position();
4912
4913         if (rs.empty()) {
4914                 return;
4915         }
4916
4917         split_regions_at (where, rs);
4918 }
4919
4920 void
4921 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
4922 {
4923         if (entered_track && mouse_mode == MouseObject) {
4924                 if (!selection->tracks.empty()) {
4925                         if (!selection->selected (entered_track)) {
4926                                 selection->add (entered_track);
4927                         }
4928                 } else {
4929                         /* there is no selection, but this operation requires/prefers selected objects */
4930
4931                         if (op_really_wants_one_track_if_none_are_selected) {
4932                                 selection->set (entered_track);
4933                         }
4934                 }
4935         }
4936 }
4937
4938 void
4939 Editor::trim_region_front ()
4940 {
4941         trim_region (true);
4942 }
4943
4944 void
4945 Editor::trim_region_back ()
4946 {
4947         trim_region (false);
4948 }
4949
4950 void
4951 Editor::trim_region (bool front)
4952 {
4953         nframes64_t where = get_preferred_edit_position();
4954         RegionSelection rs;
4955
4956         get_regions_for_action (rs);
4957
4958         if (rs.empty()) {
4959                 return;
4960         }
4961
4962         begin_reversible_command (front ? _("trim front") : _("trim back"));
4963
4964         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
4965                 if (!(*i)->region()->locked()) {
4966                         boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
4967                         XMLNode &before = pl->get_state();
4968                         if (front) {
4969                                 (*i)->region()->trim_front (where, this);       
4970                         } else {
4971                                 (*i)->region()->trim_end (where, this); 
4972                         }
4973                         XMLNode &after = pl->get_state();
4974                         session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
4975                 }
4976         }
4977
4978         commit_reversible_command ();
4979 }
4980
4981 struct EditorOrderRouteSorter {
4982     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
4983             /* use of ">" forces the correct sort order */
4984             return a->order_key ("editor") < b->order_key ("editor");
4985     }
4986 };
4987
4988 void
4989 Editor::select_next_route()
4990 {
4991         if (selection->tracks.empty()) {
4992                 selection->set (track_views.front());
4993                 return;
4994         }
4995
4996         TimeAxisView* current = selection->tracks.front();
4997
4998         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4999                 if (*i == current) {
5000                         ++i;
5001                         if (i != track_views.end()) {
5002                                 selection->set (*i);
5003                         } else {
5004                                 selection->set (*(track_views.begin()));
5005                         }
5006                         break;
5007                 }
5008         }
5009 }
5010
5011 void
5012 Editor::select_prev_route()
5013 {
5014         if (selection->tracks.empty()) {
5015                 selection->set (track_views.front());
5016                 return;
5017         }
5018
5019         TimeAxisView* current = selection->tracks.front();
5020
5021         for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5022                 if (*i == current) {
5023                         ++i;
5024                         if (i != track_views.rend()) {
5025                                 selection->set (*i);
5026                         } else {
5027                                 selection->set (*(track_views.rbegin()));
5028                         }
5029                         break;
5030                 }
5031         }
5032 }
5033
5034 void
5035 Editor::set_loop_from_selection (bool play)
5036 {
5037         if (session == 0 || selection->time.empty()) {
5038                 return;
5039         }
5040
5041         nframes_t start = selection->time[clicked_selection].start;
5042         nframes_t end = selection->time[clicked_selection].end;
5043         
5044         set_loop_range (start, end,  _("set loop range from selection"));
5045
5046         if (play) {
5047                 session->request_play_loop (true);
5048                 session->request_locate (start, true);
5049         }
5050 }
5051
5052 void
5053 Editor::set_loop_from_edit_range (bool play)
5054 {
5055         if (session == 0) {
5056                 return;
5057         }
5058
5059         nframes64_t start;
5060         nframes64_t end;
5061         
5062         if (!get_edit_op_range (start, end)) {
5063                 return;
5064         }
5065
5066         set_loop_range (start, end,  _("set loop range from edit range"));
5067
5068         if (play) {
5069                 session->request_play_loop (true);
5070                 session->request_locate (start, true);
5071         }
5072 }
5073
5074 void
5075 Editor::set_loop_from_region (bool play)
5076 {
5077         nframes64_t start = max_frames;
5078         nframes64_t end = 0;
5079
5080         RegionSelection rs; 
5081
5082         get_regions_for_action (rs);
5083
5084         if (rs.empty()) {
5085                 return;
5086         }
5087
5088         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5089                 if ((*i)->region()->position() < start) {
5090                         start = (*i)->region()->position();
5091                 }
5092                 if ((*i)->region()->last_frame() + 1 > end) {
5093                         end = (*i)->region()->last_frame() + 1;
5094                 }
5095         }
5096
5097         set_loop_range (start, end, _("set loop range from region"));
5098
5099         if (play) {
5100                 session->request_play_loop (true);
5101                 session->request_locate (start, true);
5102         }
5103 }
5104
5105 void
5106 Editor::set_punch_from_selection ()
5107 {
5108         if (session == 0 || selection->time.empty()) {
5109                 return;
5110         }
5111
5112         nframes_t start = selection->time[clicked_selection].start;
5113         nframes_t end = selection->time[clicked_selection].end;
5114         
5115         set_punch_range (start, end,  _("set punch range from selection"));
5116 }
5117
5118 void
5119 Editor::set_punch_from_edit_range ()
5120 {
5121         if (session == 0) {
5122                 return;
5123         }
5124
5125         nframes64_t start;
5126         nframes64_t end;
5127         
5128         if (!get_edit_op_range (start, end)) {
5129                 return;
5130         }
5131
5132         set_punch_range (start, end,  _("set punch range from edit range"));
5133 }
5134
5135 void
5136 Editor::set_punch_from_region ()
5137 {
5138         nframes64_t start = max_frames;
5139         nframes64_t end = 0;
5140
5141         RegionSelection rs; 
5142
5143         get_regions_for_action (rs);
5144
5145         if (rs.empty()) {
5146                 return;
5147         }
5148
5149         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5150                 if ((*i)->region()->position() < start) {
5151                         start = (*i)->region()->position();
5152                 }
5153                 if ((*i)->region()->last_frame() + 1 > end) {
5154                         end = (*i)->region()->last_frame() + 1;
5155                 }
5156         }
5157
5158         set_punch_range (start, end, _("set punch range from region"));
5159 }
5160
5161 void
5162 Editor::pitch_shift_regions ()
5163 {
5164         RegionSelection rs; 
5165
5166         get_regions_for_action (rs);
5167         
5168         if (rs.empty()) {
5169                 return;
5170         }
5171
5172         pitch_shift (rs, 1.2);
5173 }
5174         
5175 void
5176 Editor::use_region_as_bar ()
5177 {
5178         if (!session) {
5179                 return;
5180         }
5181
5182         RegionSelection rs; 
5183
5184         get_regions_for_action (rs);
5185
5186         if (rs.empty()) {
5187                 return;
5188         }
5189
5190         RegionView* rv = rs.front();
5191
5192         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5193 }
5194
5195 void
5196 Editor::use_range_as_bar ()
5197 {
5198         nframes64_t start, end;
5199         if (get_edit_op_range (start, end)) {
5200                 define_one_bar (start, end);
5201         }
5202 }
5203
5204 void
5205 Editor::define_one_bar (nframes64_t start, nframes64_t end)
5206 {
5207         nframes64_t length = end - start;
5208         
5209         const Meter& m (session->tempo_map().meter_at (start));
5210
5211         /* length = 1 bar */
5212
5213         /* now we want frames per beat.
5214            we have frames per bar, and beats per bar, so ...
5215         */
5216
5217         double frames_per_beat = length / m.beats_per_bar();
5218         
5219         /* beats per minute = */
5220
5221         double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat;
5222
5223         /* now decide whether to:
5224
5225             (a) set global tempo 
5226             (b) add a new tempo marker
5227
5228         */
5229
5230         const TempoSection& t (session->tempo_map().tempo_section_at (start));
5231
5232         bool do_global = false;
5233
5234         if ((session->tempo_map().n_tempos() == 1) && (session->tempo_map().n_meters() == 1)) {
5235                 
5236                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5237                    at the start, or create a new marker
5238                 */
5239
5240                 vector<string> options;
5241                 options.push_back (_("Cancel"));
5242                 options.push_back (_("Add new marker"));
5243                 options.push_back (_("Set global tempo"));
5244                 Choice c (_("Do you want to set the global tempo or add new tempo marker?"),
5245                           options);
5246                 c.set_default_response (2);
5247
5248                 switch (c.run()) {
5249                 case 0:
5250                         return;
5251
5252                 case 2:
5253                         do_global = true;
5254                         break;
5255
5256                 default:
5257                         do_global = false;
5258                 }
5259
5260         } else {
5261
5262                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5263                    if the marker is at the region starter, change it, otherwise add
5264                    a new tempo marker 
5265                 */
5266         }
5267
5268         begin_reversible_command (_("set tempo from region"));
5269         XMLNode& before (session->tempo_map().get_state());
5270
5271         if (do_global) {
5272                 session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5273         } else if (t.frame() == start) {
5274                 session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5275         } else {
5276                 session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5277         }
5278
5279         XMLNode& after (session->tempo_map().get_state());
5280
5281         session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
5282         commit_reversible_command ();
5283 }
5284
5285 void
5286 Editor::split_region_at_transients ()
5287 {
5288         AnalysisFeatureList positions;
5289
5290         if (!session) {
5291                 return;
5292         }
5293
5294         RegionSelection rs; 
5295
5296         get_regions_for_action (rs);
5297
5298         if (rs.empty()) {
5299                 return;
5300         }
5301
5302         session->begin_reversible_command (_("split regions"));
5303
5304         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5305
5306                 RegionSelection::iterator tmp;
5307
5308                 tmp = i;
5309                 ++tmp;
5310
5311                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5312                 
5313                 if (ar && (ar->get_transients (positions) == 0)) {
5314                         split_region_at_points ((*i)->region(), positions, true);
5315                         positions.clear ();
5316                 }
5317                 
5318                 i = tmp;
5319         }
5320
5321         session->commit_reversible_command ();
5322
5323 }
5324
5325 void
5326 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret)
5327 {
5328         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> (r);
5329         bool use_rhythmic_rodent = false;
5330
5331         if (!ar) {
5332                 return;
5333         }
5334         
5335         boost::shared_ptr<Playlist> pl = ar->playlist();
5336         
5337         if (!pl) {
5338                 return;
5339         }
5340         
5341         if (positions.empty()) {
5342                 return;
5343         }
5344
5345
5346         if (positions.size() > 20) {
5347                 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);
5348                 MessageDialog msg (msgstr,
5349                                    false,
5350                                    Gtk::MESSAGE_INFO,
5351                                    Gtk::BUTTONS_OK_CANCEL);
5352
5353                 if (can_ferret) {
5354                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5355                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5356                 } else {
5357                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
5358                 }
5359
5360                 msg.set_title (_("Excessive split?"));
5361                 msg.present ();
5362
5363                 int response = msg.run();
5364                 msg.hide ();
5365                 switch (response) {
5366                 case RESPONSE_OK:
5367                         break;
5368                 case RESPONSE_APPLY:
5369                         use_rhythmic_rodent = true;
5370                         break;
5371                 default:
5372                         return;
5373                 }
5374         }
5375         
5376         if (use_rhythmic_rodent) {
5377                 show_rhythm_ferret ();
5378                 return;
5379         }
5380
5381         AnalysisFeatureList::const_iterator x;  
5382         
5383         nframes64_t pos = ar->position();
5384
5385         XMLNode& before (pl->get_state());
5386         
5387         x = positions.begin();
5388         
5389         while (x != positions.end()) {
5390                 if ((*x) > pos) {
5391                         break;
5392                 }
5393                 ++x;
5394         }
5395         
5396         if (x == positions.end()) {
5397                 return;
5398         }
5399         
5400         pl->freeze ();
5401         pl->remove_region (ar);
5402         
5403         while (x != positions.end()) {
5404                 
5405                 /* file start = original start + how far we from the initial position ? 
5406                  */
5407                 
5408                 nframes64_t file_start = ar->start() + (pos - ar->position());
5409
5410                 /* length = next position - current position
5411                  */
5412                 
5413                 nframes64_t len = (*x) - pos;
5414
5415                 /* XXX we do we really want to allow even single-sample regions?
5416                    shouldn't we have some kind of lower limit on region size?
5417                 */
5418
5419                 if (len <= 0) {
5420                         break;
5421                 }
5422                 
5423                 string new_name;
5424                 
5425                 if (session->region_name (new_name, ar->name())) {
5426                         break;
5427                 }
5428                 
5429                 /* do NOT announce new regions 1 by one, just wait till they are all done */
5430
5431                 boost::shared_ptr<Region> r = RegionFactory::create (ar->get_sources(), file_start, len, new_name, 0, Region::DefaultFlags, false);
5432                 pl->add_region (r, pos);
5433
5434                 pos += len;
5435                 ++x;
5436
5437                 if (*x > ar->last_frame()) {
5438
5439                         /* add final fragment */
5440                         
5441                         file_start = ar->start() + (pos - ar->position());
5442                         len = ar->last_frame() - pos;
5443
5444                         boost::shared_ptr<Region> r = RegionFactory::create (ar->get_sources(), file_start, len, new_name, 0, Region::DefaultFlags);
5445                         pl->add_region (r, pos);
5446
5447                         break;
5448                 }
5449         } 
5450
5451         pl->thaw ();
5452
5453         XMLNode& after (pl->get_state());
5454         
5455         session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
5456 }
5457
5458 void
5459 Editor::tab_to_transient (bool forward)
5460 {
5461         AnalysisFeatureList positions;
5462
5463         if (!session) {
5464                 return;
5465         }
5466
5467         nframes64_t pos = session->audible_frame ();
5468
5469         if (!selection->tracks.empty()) {
5470
5471                 for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
5472
5473                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
5474
5475                         if (rtv) {
5476                                 boost::shared_ptr<Diskstream> ds = rtv->get_diskstream();
5477                                 if (ds) {
5478                                         boost::shared_ptr<Playlist> pl = rtv->get_diskstream()->playlist ();
5479                                         if (pl) {
5480                                                 nframes64_t result = pl->find_next_transient (pos, forward ? 1 : -1);
5481                                                 
5482                                                 if (result >= 0) {
5483                                                         positions.push_back (result);
5484                                                 }
5485                                         }
5486                                 }
5487                         }
5488                 }
5489
5490         } else {
5491                 
5492                 RegionSelection rs; 
5493
5494                 get_regions_for_action (rs);
5495         
5496                 if (rs.empty()) {
5497                         return;
5498                 }
5499                 
5500                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
5501                         (*r)->region()->get_transients (positions);
5502                 }
5503         }
5504
5505         TransientDetector::cleanup_transients (positions, session->frame_rate(), 3.0);
5506
5507         if (forward) {
5508                 AnalysisFeatureList::iterator x;
5509
5510                 for (x = positions.begin(); x != positions.end(); ++x) {
5511                         if ((*x) > pos) {
5512                                 break;
5513                         }
5514                 }
5515
5516                 if (x != positions.end ()) {
5517                         session->request_locate (*x);
5518                 }
5519
5520         } else {
5521                 AnalysisFeatureList::reverse_iterator x;
5522
5523                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
5524                         if ((*x) < pos) {
5525                                 break;
5526                         }
5527                 }
5528
5529                 if (x != positions.rend ()) {
5530                         session->request_locate (*x);
5531                 }
5532         }
5533 }
5534
5535 void
5536 Editor::playhead_forward_to_grid ()
5537 {
5538         if (!session) return;
5539         nframes64_t pos = playhead_cursor->current_frame;
5540         if (pos < max_frames) {
5541                 pos++;
5542                 snap_to_internal (pos, 1, false);
5543                 session->request_locate (pos);
5544         }
5545 }
5546
5547
5548 void
5549 Editor::playhead_backward_to_grid ()
5550 {
5551         if (!session) return;
5552         nframes64_t pos = playhead_cursor->current_frame;
5553         if (pos > 1) {
5554                 pos--;
5555                 snap_to_internal (pos, -1, false);
5556                 session->request_locate (pos);
5557         }
5558 }
5559
5560 void
5561 Editor::set_track_height (uint32_t h)
5562 {
5563         TrackSelection& ts (selection->tracks);
5564
5565         if (ts.empty()) {
5566                 return;
5567         }
5568
5569         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5570                 (*x)->set_height (h);
5571         }
5572 }
5573
5574 void
5575 Editor::set_track_height_largest ()
5576 {
5577         set_track_height (TimeAxisView::hLargest);
5578 }
5579 void
5580 Editor::set_track_height_large ()
5581 {
5582         set_track_height (TimeAxisView::hLarge);
5583 }
5584 void
5585 Editor::set_track_height_larger ()
5586 {
5587         set_track_height (TimeAxisView::hLarger);
5588 }
5589 void
5590 Editor::set_track_height_normal ()
5591 {
5592         set_track_height (TimeAxisView::hNormal);
5593 }
5594 void
5595 Editor::set_track_height_smaller ()
5596 {
5597         set_track_height (TimeAxisView::hSmaller);
5598 }
5599 void
5600 Editor::set_track_height_small ()
5601 {
5602         set_track_height (TimeAxisView::hSmall);
5603 }
5604
5605 void
5606 Editor::toggle_tracks_active ()
5607 {
5608         TrackSelection& ts (selection->tracks);
5609         bool first = true;
5610         bool target = false;
5611
5612         if (ts.empty()) {
5613                 return;
5614         }
5615
5616         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5617                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
5618
5619                 if (rtv) {
5620                         if (first) {
5621                                 target = !rtv->_route->active();
5622                                 first = false;
5623                         }
5624                         rtv->_route->set_active (target);
5625                 }
5626         }
5627 }
5628
5629 void
5630 Editor::remove_tracks ()
5631 {
5632         TrackSelection& ts (selection->tracks);
5633
5634         if (ts.empty()) {
5635                 return;
5636         }
5637
5638         vector<string> choices;
5639         string prompt;
5640         int ntracks = 0;
5641         int nbusses = 0;
5642         const char* trackstr;
5643         const char* busstr;
5644         vector<boost::shared_ptr<Route> > routes;
5645
5646         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5647                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
5648                 if (rtv) {
5649                         if (rtv->is_track()) {
5650                                 ntracks++;
5651                         } else {
5652                                 nbusses++;
5653                         }
5654                 }
5655                 routes.push_back (rtv->_route);
5656         }
5657         
5658         if (ntracks + nbusses == 0) {
5659                 return;
5660         }
5661
5662         if (ntracks > 1) {
5663                 trackstr = _("tracks");
5664         } else {
5665                 trackstr = _("track");
5666         }
5667
5668         if (nbusses > 1) {
5669                 busstr = _("busses");
5670         } else {
5671                 busstr = _("bus");
5672         }
5673
5674         if (ntracks) {
5675                 if (nbusses) {
5676                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
5677                                                     "(You may also lose the playlists associated with the %2)\n\n"
5678                                                     "This action cannot be undone!"),
5679                                                   ntracks, trackstr, nbusses, busstr);
5680                 } else {
5681                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
5682                                                     "(You may also lose the playlists associated with the %2)\n\n"
5683                                                     "This action cannot be undone!"),
5684                                                   ntracks, trackstr);
5685                 }
5686         } else if (nbusses) {
5687                 prompt  = string_compose (_("Do you really want to remove %1 %2?"),
5688                                           nbusses, busstr);
5689         }
5690
5691         choices.push_back (_("No, do nothing."));
5692         if (ntracks + nbusses > 1) {
5693                 choices.push_back (_("Yes, remove them."));
5694         } else {
5695                 choices.push_back (_("Yes, remove it."));
5696         }
5697
5698         Choice prompter (prompt, choices);
5699
5700         if (prompter.run () != 1) {
5701                 return;
5702         }
5703
5704         for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
5705                 session->remove_route (*x);
5706         }
5707 }
5708
5709 void
5710 Editor::set_waveform_scale (WaveformScale ws)
5711 {
5712         TrackSelection& ts (selection->tracks);
5713
5714         if (ts.empty()) {
5715                 return;
5716         }
5717
5718         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
5719                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (*x);
5720                 if (atv) {
5721                         atv->set_waveform_scale (ws);
5722                 }
5723         }
5724 }       
5725
5726 void
5727 Editor::do_insert_time ()
5728 {
5729         if (selection->tracks.empty()) {
5730                 return;
5731         }
5732
5733         nframes64_t pos = get_preferred_edit_position ();
5734         ArdourDialog d (*this, _("Insert Time"));
5735         VButtonBox button_box;
5736         VBox option_box;
5737         RadioButtonGroup group;
5738         RadioButton leave_button (group, _("Stay in position"));
5739         RadioButton move_button (group, _("Move"));
5740         RadioButton split_button (group, _("Split & Later Section Moves"));
5741         Label intersect_option_label (_("Intersected regions should:"));
5742         CheckButton glue_button (_("Move Glued Regions"));
5743         CheckButton marker_button (_("Move Markers"));
5744         AudioClock clock ("insertTimeClock", true, X_("InsertTimeClock"), true, true, true);
5745         HBox clock_box;
5746
5747         clock.set (0);
5748         clock.set_session (session);
5749         clock.set_bbt_reference (pos);
5750
5751         clock_box.pack_start (clock, false, true);
5752
5753         option_box.set_spacing (6);
5754         option_box.pack_start (intersect_option_label, false, false);
5755         option_box.pack_start (button_box, false, false);
5756         option_box.pack_start (glue_button, false, false);
5757         option_box.pack_start (marker_button, false, false);
5758
5759         button_box.pack_start (leave_button, false, false);
5760         button_box.pack_start (move_button, false, false);
5761         button_box.pack_start (split_button, false, false);
5762                                       
5763         d.get_vbox()->set_border_width (12);
5764         d.get_vbox()->pack_start (clock_box, false, false);
5765         d.get_vbox()->pack_start (option_box, false, false);
5766         
5767         leave_button.show ();
5768         move_button.show ();
5769         split_button.show ();
5770         intersect_option_label.show ();
5771         option_box.show ();
5772         button_box.show ();
5773         glue_button.show ();
5774         clock.show_all();
5775         clock_box.show ();
5776         marker_button.show ();
5777
5778         d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
5779         d.add_button (Gtk::Stock::OK, Gtk::RESPONSE_OK);
5780         d.show ();
5781
5782         int response = d.run ();
5783
5784         if (response != RESPONSE_OK) {
5785                 return;
5786         }
5787         
5788         nframes_t distance = clock.current_duration (pos);
5789
5790         if (distance == 0) {
5791                 return;
5792         }
5793
5794         InsertTimeOption opt;
5795
5796         if (leave_button.get_active()) {
5797                 opt = LeaveIntersected;
5798         } else if (move_button.get_active()) {
5799                 opt = MoveIntersected;
5800         } else {
5801                 opt = SplitIntersected;
5802         }
5803
5804         insert_time (pos, distance, opt, glue_button.get_active(), marker_button.get_active());
5805 }
5806
5807 void
5808 Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt, 
5809                      bool ignore_music_glue, bool markers_too)
5810 {
5811         bool commit = false;
5812
5813         if (Config->get_edit_mode() == Lock) {
5814                 return;
5815         }
5816
5817         begin_reversible_command (_("insert time"));
5818
5819         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
5820                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
5821                 
5822                 if (!pl) {
5823                         continue;
5824                 }
5825
5826                 XMLNode &before = pl->get_state();
5827
5828                 if (opt == SplitIntersected) {
5829                         pl->split (pos);
5830                 }
5831                 
5832                 pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
5833
5834                 XMLNode &after = pl->get_state();
5835
5836                 session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
5837                 commit = true;
5838         }
5839
5840         if (markers_too) {
5841                 bool moved = false;
5842                 XMLNode& before (session->locations()->get_state());
5843                 Locations::LocationList copy (session->locations()->list());
5844
5845                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
5846                         
5847                         Locations::LocationList::const_iterator tmp;
5848
5849                         if ((*i)->start() >= pos) {
5850                                 (*i)->set_start ((*i)->start() + frames);
5851                                 if (!(*i)->is_mark()) {
5852                                         (*i)->set_end ((*i)->end() + frames);
5853                                 }
5854                                 moved = true;
5855                         }
5856                 }
5857
5858                 if (moved) {
5859                         XMLNode& after (session->locations()->get_state());
5860                         session->add_command (new MementoCommand<Locations>(*session->locations(), &before, &after));
5861                 }
5862         }
5863
5864         if (commit) {
5865                 commit_reversible_command ();
5866         }
5867 }