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