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