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