region trimming and height patch from lincoln. great work
[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         TrackSelection tracks = get_tracks_for_range_action ();
2697
2698         nframes64_t selection_cnt = end - start + 1;
2699         
2700         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2701                 boost::shared_ptr<Region> current;
2702                 boost::shared_ptr<Playlist> pl;
2703                 nframes64_t internal_start;
2704                 string new_name;
2705
2706                 if ((pl = (*i)->playlist()) == 0) {
2707                         continue;
2708                 }
2709
2710                 if ((current = pl->top_region_at (start)) == 0) {
2711                         continue;
2712                 }
2713
2714                 internal_start = start - current->position();
2715                 session->region_name (new_name, current->name(), true);
2716                 boost::shared_ptr<Region> region (RegionFactory::create (current,
2717                                 internal_start, selection_cnt, new_name));
2718         }
2719 }       
2720
2721 void
2722 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2723 {
2724         if (selection->time.empty() || selection->tracks.empty()) {
2725                 return;
2726         }
2727
2728         nframes64_t start = selection->time[clicked_selection].start;
2729         nframes64_t end = selection->time[clicked_selection].end;
2730         
2731         sort_track_selection ();
2732
2733         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2734                 boost::shared_ptr<Region> current;
2735                 boost::shared_ptr<Playlist> playlist;
2736                 nframes64_t internal_start;
2737                 string new_name;
2738
2739                 if ((playlist = (*i)->playlist()) == 0) {
2740                         continue;
2741                 }
2742
2743                 if ((current = playlist->top_region_at(start)) == 0) {
2744                         continue;
2745                 }
2746
2747                 internal_start = start - current->position();
2748                 session->region_name (new_name, current->name(), true);
2749
2750                 new_regions.push_back (RegionFactory::create (current,
2751                                         internal_start, end - start + 1, new_name));
2752         }
2753 }
2754
2755 void
2756 Editor::split_multichannel_region ()
2757 {
2758         RegionSelection rs; 
2759
2760         get_regions_for_action (rs);
2761
2762         if (rs.empty()) {
2763                 return;
2764         }
2765
2766         vector< boost::shared_ptr<Region> > v;
2767
2768         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2769                 (*x)->region()->separate_by_channel (*session, v);
2770         }
2771 }
2772
2773 void
2774 Editor::new_region_from_selection ()
2775 {
2776         region_from_selection ();
2777         cancel_selection ();
2778 }
2779
2780 static void
2781 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2782 {
2783         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2784         case OverlapNone:
2785                 break;
2786         default:
2787                 rs->push_back (rv);
2788         }
2789 }
2790
2791 /** Return either:
2792  *    - selected tracks, or if there are none...
2793  *    - tracks containing selected regions, or if there are none...
2794  *    - all tracks
2795  * @return tracks.
2796  */
2797 TrackSelection
2798 Editor::get_tracks_for_range_action () const
2799 {
2800         TrackSelection t;
2801         
2802         if (selection->tracks.empty()) {
2803                 
2804                 /* use tracks with selected regions */
2805
2806                 RegionSelection rs = selection->regions;
2807
2808                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2809                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2810
2811                         if (!t.contains (tv)) {
2812                                 t.push_back (tv);
2813                         }
2814                 }
2815
2816                 if (t.empty()) {
2817                         /* no regions and no tracks: use all tracks */
2818                         t = track_views;
2819                 }
2820
2821         } else {
2822
2823                 t = selection->tracks;
2824         }
2825
2826         return t;
2827 }
2828
2829 void
2830 Editor::separate_regions_between (const TimeSelection& ts)
2831 {
2832         bool in_command = false;
2833         boost::shared_ptr<Playlist> playlist;
2834         RegionSelection new_selection;
2835
2836         TrackSelection tmptracks = get_tracks_for_range_action ();
2837         sort_track_selection (&tmptracks);
2838
2839         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2840
2841                 RouteTimeAxisView* rtv;
2842
2843                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2844
2845                         if (rtv->is_track()) {
2846
2847                                 /* no edits to destructive tracks */
2848
2849                                 if (rtv->track()->diskstream()->destructive()) {
2850                                         continue;
2851                                 }
2852                                         
2853                                 if ((playlist = rtv->playlist()) != 0) {
2854
2855                                         XMLNode *before;
2856                                         bool got_some;
2857
2858                                         before = &(playlist->get_state());
2859                                         got_some = false;
2860
2861                                         /* XXX need to consider musical time selections here at some point */
2862
2863                                         double speed = rtv->get_diskstream()->speed();
2864
2865
2866                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2867
2868                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2869                                                                 mem_fun(*this, &Editor::collect_new_region_view));
2870                                                 latest_regionviews.clear ();
2871
2872                                                 playlist->partition ((nframes64_t)((*t).start * speed),
2873                                                                 (nframes64_t)((*t).end * speed), true);
2874
2875                                                 c.disconnect ();
2876
2877                                                 if (!latest_regionviews.empty()) {
2878                                                         
2879                                                         got_some = true;
2880
2881                                                         rtv->view()->foreach_regionview (bind (
2882                                                                                 sigc::ptr_fun (add_if_covered),
2883                                                                                 &(*t), &new_selection));
2884                                                         
2885                                                         if (!in_command) {
2886                                                                 begin_reversible_command (_("separate"));
2887                                                                 in_command = true;
2888                                                         }
2889                                                         
2890                                                         session->add_command(new MementoCommand<Playlist>(
2891                                                                         *playlist, before, &playlist->get_state()));
2892                                                 } 
2893                                         }
2894
2895                                         if (!got_some) {
2896                                                 delete before;
2897                                         }
2898                                 }
2899                         }
2900                 }
2901         }
2902
2903         if (in_command) {
2904                 selection->set (new_selection);
2905                 set_mouse_mode (MouseObject);
2906
2907                 commit_reversible_command ();
2908         }
2909 }
2910
2911 /** Take tracks from get_tracks_for_range_action and cut any regions
2912  *  on those tracks so that the tracks are empty over the time
2913  *  selection.
2914  */
2915 void
2916 Editor::separate_region_from_selection ()
2917 {
2918         /* preferentially use *all* ranges in the time selection if we're in range mode
2919            to allow discontiguous operation, since get_edit_op_range() currently
2920            returns a single range.
2921         */
2922
2923         if (mouse_mode == MouseRange && !selection->time.empty()) {
2924
2925                 separate_regions_between (selection->time);
2926
2927         } else {
2928
2929                 nframes64_t start;
2930                 nframes64_t end;
2931                 
2932                 if (get_edit_op_range (start, end)) {
2933                         
2934                         AudioRange ar (start, end, 1);
2935                         TimeSelection ts;
2936                         ts.push_back (ar);
2937
2938                         separate_regions_between (ts);
2939                 }
2940         }
2941 }
2942
2943 void
2944 Editor::separate_region_from_punch ()
2945 {
2946         Location* loc  = session->locations()->auto_punch_location();
2947         if (loc) {
2948                 separate_regions_using_location (*loc);
2949         }
2950 }
2951
2952 void
2953 Editor::separate_region_from_loop ()
2954 {
2955         Location* loc  = session->locations()->auto_loop_location();
2956         if (loc) {
2957                 separate_regions_using_location (*loc);
2958         }
2959 }
2960
2961 void
2962 Editor::separate_regions_using_location (Location& loc)
2963 {
2964         if (loc.is_mark()) {
2965                 return;
2966         }
2967
2968         AudioRange ar (loc.start(), loc.end(), 1);
2969         TimeSelection ts;
2970
2971         ts.push_back (ar);
2972
2973         separate_regions_between (ts);
2974 }
2975
2976 void
2977 Editor::crop_region_to_selection ()
2978 {
2979         if (!selection->time.empty()) {
2980
2981                 crop_region_to (selection->time.start(), selection->time.end_frame());
2982
2983         } else {
2984
2985                 nframes64_t start;
2986                 nframes64_t end;
2987
2988                 if (get_edit_op_range (start, end)) {
2989                         crop_region_to (start, end);
2990                 }
2991         }
2992                 
2993 }               
2994
2995 void
2996 Editor::crop_region_to (nframes64_t start, nframes64_t end)
2997 {
2998         vector<boost::shared_ptr<Playlist> > playlists;
2999         boost::shared_ptr<Playlist> playlist;
3000         TrackSelection* ts;
3001
3002         if (selection->tracks.empty()) {
3003                 ts = &track_views;
3004         } else {
3005                 sort_track_selection ();
3006                 ts = &selection->tracks;
3007         }
3008         
3009         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3010                 
3011                 RouteTimeAxisView* rtv;
3012                 
3013                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3014
3015                         boost::shared_ptr<Track> t = rtv->track();
3016
3017                         if (t != 0 && ! t->diskstream()->destructive()) {
3018                                 
3019                                 if ((playlist = rtv->playlist()) != 0) {
3020                                         playlists.push_back (playlist);
3021                                 }
3022                         }
3023                 }
3024         }
3025
3026         if (playlists.empty()) {
3027                 return;
3028         }
3029                 
3030         nframes64_t the_start;
3031         nframes64_t the_end;
3032         nframes64_t cnt;
3033         
3034         begin_reversible_command (_("trim to selection"));
3035         
3036         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3037                 
3038                 boost::shared_ptr<Region> region;
3039         
3040                 the_start = start;
3041         
3042                 if ((region = (*i)->top_region_at(the_start)) == 0) {
3043                         continue;
3044                 }
3045                 
3046                 /* now adjust lengths to that we do the right thing
3047                    if the selection extends beyond the region
3048                 */
3049                 
3050                 the_start = max (the_start, (nframes64_t) region->position());
3051                 if (max_frames - the_start < region->length()) {
3052                         the_end = the_start + region->length() - 1;
3053                 } else {
3054                         the_end = max_frames;
3055                 }
3056                 the_end = min (end, the_end);
3057                 cnt = the_end - the_start + 1;
3058                 
3059                 XMLNode &before = (*i)->get_state();
3060                 region->trim_to (the_start, cnt, this);
3061                 XMLNode &after = (*i)->get_state();
3062                 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
3063         }
3064         
3065         commit_reversible_command ();
3066 }               
3067
3068 void
3069 Editor::region_fill_track ()
3070 {
3071         nframes64_t end;
3072         RegionSelection rs; 
3073
3074         get_regions_for_action (rs);
3075
3076         if (!session || rs.empty()) {
3077                 return;
3078         }
3079
3080         end = session->current_end_frame ();
3081
3082         begin_reversible_command (_("region fill"));
3083
3084         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3085
3086                 boost::shared_ptr<Region> region ((*i)->region());
3087                 
3088                 // FIXME
3089                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
3090                 assert(ar);
3091
3092                 boost::shared_ptr<Playlist> pl = region->playlist();
3093
3094                 if (end <= region->last_frame()) {
3095                         return;
3096                 }
3097
3098                 double times = (double) (end - region->last_frame()) / (double) region->length();
3099
3100                 if (times == 0) {
3101                         return;
3102                 }
3103
3104                 XMLNode &before = pl->get_state();
3105                 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
3106                 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
3107         }
3108
3109         commit_reversible_command ();
3110 }
3111
3112 void
3113 Editor::region_fill_selection ()
3114 {
3115         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3116                 return;
3117         }
3118
3119         if (selection->time.empty()) {
3120                 return;
3121         }
3122
3123         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3124         if (region == 0) {
3125                 return;
3126         }
3127
3128         nframes64_t start = selection->time[clicked_selection].start;
3129         nframes64_t end = selection->time[clicked_selection].end;
3130
3131         boost::shared_ptr<Playlist> playlist; 
3132
3133         if (selection->tracks.empty()) {
3134                 return;
3135         }
3136
3137         nframes64_t selection_length = end - start;
3138         float times = (float)selection_length / region->length();
3139         
3140         begin_reversible_command (_("fill selection"));
3141         
3142         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3143
3144                 if ((playlist = (*i)->playlist()) == 0) {
3145                         continue;
3146                 }               
3147                 
3148                 XMLNode &before = playlist->get_state();
3149                 playlist->add_region (RegionFactory::create (region), start, times);
3150                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3151         }
3152         
3153         commit_reversible_command ();                   
3154 }
3155
3156 void
3157 Editor::set_region_sync_from_edit_point ()
3158 {
3159         nframes64_t where = get_preferred_edit_position ();
3160         RegionSelection rs;
3161         get_regions_for_action (rs);
3162         set_sync_point (where, rs);
3163 }
3164
3165 void
3166 Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
3167 {
3168         bool in_command = false;
3169
3170         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3171                 
3172                 if (!(*r)->region()->covers (where)) {
3173                         continue;
3174                 }
3175
3176                 boost::shared_ptr<Region> region ((*r)->region());
3177
3178                 if (!in_command) {
3179                         begin_reversible_command (_("set sync point"));
3180                         in_command = true;
3181                 }
3182
3183                 XMLNode &before = region->playlist()->get_state();
3184                 region->set_sync_position (get_preferred_edit_position());
3185                 XMLNode &after = region->playlist()->get_state();
3186                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3187         }
3188
3189         if (in_command) {
3190                 commit_reversible_command ();
3191         }
3192 }
3193
3194 /** Remove the sync positions of the selection */
3195 void
3196 Editor::remove_region_sync ()
3197 {
3198         RegionSelection rs; 
3199
3200         get_regions_for_action (rs);
3201
3202         if (rs.empty()) {
3203                 return;
3204         }
3205
3206         begin_reversible_command (_("remove sync"));
3207         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3208
3209                 XMLNode &before = (*i)->region()->playlist()->get_state();
3210                 (*i)->region()->clear_sync_position ();
3211                 XMLNode &after = (*i)->region()->playlist()->get_state();
3212                 session->add_command(new MementoCommand<Playlist>(*((*i)->region()->playlist()), &before, &after));
3213         }
3214         commit_reversible_command ();
3215 }
3216
3217 void
3218 Editor::naturalize ()
3219 {
3220         RegionSelection rs; 
3221
3222         get_regions_for_action (rs);
3223
3224         if (rs.empty()) {
3225                 return;
3226         }
3227
3228         begin_reversible_command (_("naturalize"));
3229         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3230                 XMLNode &before = (*i)->region()->get_state();
3231                 (*i)->region()->move_to_natural_position (this);
3232                 XMLNode &after = (*i)->region()->get_state();
3233                 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
3234         }
3235         commit_reversible_command ();
3236 }
3237
3238 void
3239 Editor::align (RegionPoint what)
3240 {
3241         RegionSelection rs; 
3242
3243         get_regions_for_action (rs);
3244         nframes64_t where = get_preferred_edit_position();
3245
3246         if (!rs.empty()) {
3247                 align_selection (what, where, rs);
3248         } else {
3249
3250                 RegionSelection rs;
3251                 get_regions_at (rs, where, selection->tracks);
3252                 align_selection (what, where, rs);
3253         }
3254 }
3255
3256 void
3257 Editor::align_relative (RegionPoint what)
3258 {
3259         nframes64_t where = get_preferred_edit_position();
3260         RegionSelection rs; 
3261
3262         get_regions_for_action (rs);
3263
3264         if (!rs.empty()) {
3265                 align_selection_relative (what, where, rs);
3266         } 
3267 }
3268
3269 struct RegionSortByTime {
3270     bool operator() (const RegionView* a, const RegionView* b) {
3271             return a->region()->position() < b->region()->position();
3272     }
3273 };
3274
3275 void
3276 Editor::align_selection_relative (RegionPoint point, nframes64_t position, const RegionSelection& rs)
3277 {
3278         if (rs.empty()) {
3279                 return;
3280         }
3281
3282         nframes64_t distance = 0;
3283         nframes64_t pos = 0;
3284         int dir = 1;
3285
3286         list<RegionView*> sorted;
3287         rs.by_position (sorted);
3288
3289         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3290
3291         switch (point) {
3292         case Start:
3293                 pos = position;
3294                 if (position > r->position()) {
3295                         distance = position - r->position();
3296                 } else {
3297                         distance = r->position() - position;
3298                         dir = -1;
3299                 }
3300                 break;
3301                 
3302         case End:
3303                 if (position > r->last_frame()) {
3304                         distance = position - r->last_frame();
3305                         pos = r->position() + distance;
3306                 } else {
3307                         distance = r->last_frame() - position;
3308                         pos = r->position() - distance;
3309                         dir = -1;
3310                 }
3311                 break;
3312
3313         case SyncPoint:
3314                 pos = r->adjust_to_sync (position);
3315                 if (pos > r->position()) {
3316                         distance = pos - r->position();
3317                 } else {
3318                         distance = r->position() - pos;
3319                         dir = -1;
3320                 }
3321                 break;  
3322         }
3323
3324         if (pos == r->position()) {
3325                 return;
3326         }
3327
3328         begin_reversible_command (_("align selection (relative)"));
3329
3330         /* move first one specially */
3331
3332         XMLNode &before = r->playlist()->get_state();
3333         r->set_position (pos, this);
3334         XMLNode &after = r->playlist()->get_state();
3335         session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
3336
3337         /* move rest by the same amount */
3338         
3339         sorted.pop_front();
3340         
3341         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3342
3343                 boost::shared_ptr<Region> region ((*i)->region());
3344
3345                 XMLNode &before = region->playlist()->get_state();
3346                 
3347                 if (dir > 0) {
3348                         region->set_position (region->position() + distance, this);
3349                 } else {
3350                         region->set_position (region->position() - distance, this);
3351                 }
3352
3353                 XMLNode &after = region->playlist()->get_state();
3354                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3355
3356         }
3357
3358         commit_reversible_command ();
3359 }
3360
3361 void
3362 Editor::align_selection (RegionPoint point, nframes64_t position, const RegionSelection& rs)
3363 {
3364         if (rs.empty()) {
3365                 return;
3366         }
3367
3368         begin_reversible_command (_("align selection"));
3369
3370         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3371                 align_region_internal ((*i)->region(), point, position);
3372         }
3373
3374         commit_reversible_command ();
3375 }
3376
3377 void
3378 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes64_t position)
3379 {
3380         begin_reversible_command (_("align region"));
3381         align_region_internal (region, point, position);
3382         commit_reversible_command ();
3383 }
3384
3385 void
3386 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes64_t position)
3387 {
3388         XMLNode &before = region->playlist()->get_state();
3389
3390         switch (point) {
3391         case SyncPoint:
3392                 region->set_position (region->adjust_to_sync (position), this);
3393                 break;
3394
3395         case End:
3396                 if (position > region->length()) {
3397                         region->set_position (position - region->length(), this);
3398                 }
3399                 break;
3400
3401         case Start:
3402                 region->set_position (position, this);
3403                 break;
3404         }
3405
3406         XMLNode &after = region->playlist()->get_state();
3407         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
3408 }       
3409
3410 void
3411 Editor::trim_region_front ()
3412 {
3413         trim_region (true);
3414 }
3415
3416 void
3417 Editor::trim_region_back ()
3418 {
3419         trim_region (false);
3420 }
3421
3422 void
3423 Editor::trim_region (bool front)
3424 {
3425         nframes64_t where = get_preferred_edit_position();
3426         RegionSelection rs;
3427
3428         get_regions_for_action (rs);
3429
3430         if (rs.empty()) {
3431                 return;
3432         }
3433
3434         begin_reversible_command (front ? _("trim front") : _("trim back"));
3435
3436         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3437                 if (!(*i)->region()->locked()) {
3438                         boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
3439                         XMLNode &before = pl->get_state();
3440                         if (front) {
3441                                 (*i)->region()->trim_front (where, this);       
3442                         } else {
3443                                 (*i)->region()->trim_end (where, this); 
3444                         }
3445                         XMLNode &after = pl->get_state();
3446                         session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
3447                 }
3448         }
3449
3450         commit_reversible_command ();
3451 }
3452
3453 /** Trim the end of the selected regions to the position of the edit cursor */
3454 void
3455 Editor::trim_region_to_loop ()
3456 {
3457         Location* loc = session->locations()->auto_loop_location();
3458         if (!loc) {
3459                 return;
3460         }
3461         trim_region_to_location (*loc, _("trim to loop"));
3462 }
3463
3464 void
3465 Editor::trim_region_to_punch ()
3466 {
3467         Location* loc = session->locations()->auto_punch_location();
3468         if (!loc) {
3469                 return;
3470         }
3471         trim_region_to_location (*loc, _("trim to punch"));
3472 }
3473 void
3474 Editor::trim_region_to_location (const Location& loc, const char* str)
3475 {
3476         RegionSelection rs;
3477
3478         get_regions_for_action (rs);
3479
3480         begin_reversible_command (str);
3481
3482         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3483                 RegionView* rv = (*x);
3484
3485                 /* require region to span proposed trim */
3486                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3487                 case OverlapInternal:
3488                         break;
3489                 default:
3490                         continue;
3491                 }
3492                                 
3493                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3494                 if (!tav) {
3495                         return;
3496                 }
3497
3498                 float speed = 1.0;
3499                 nframes64_t start;
3500                 nframes64_t end;
3501
3502                 if (tav->get_diskstream() != 0) {
3503                         speed = tav->get_diskstream()->speed();
3504                 }
3505                 
3506                 start = session_frame_to_track_frame (loc.start(), speed);
3507                 end = session_frame_to_track_frame (loc.end(), speed);
3508
3509                 XMLNode &before = rv->region()->playlist()->get_state();
3510                 rv->region()->trim_to (start, (end - start), this);
3511                 XMLNode &after = rv->region()->playlist()->get_state();
3512                 session->add_command(new MementoCommand<Playlist>(
3513                                 *(rv->region()->playlist()), &before, &after));
3514         }
3515
3516         commit_reversible_command ();
3517 }
3518
3519 void
3520 Editor::trim_region_to_edit_point ()
3521 {
3522         RegionSelection rs;
3523         
3524         get_regions_for_action (rs);
3525
3526         nframes64_t where = get_preferred_edit_position();
3527
3528         begin_reversible_command (_("trim region start to edit point"));
3529
3530         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3531                 RegionView* rv = (*x);
3532
3533                 /* require region to cover trim */
3534                 if (!rv->region()->covers (where)) {
3535                         continue;
3536                 }
3537
3538                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3539                 if (!tav) {
3540                         return;
3541                 }
3542
3543                 float speed = 1.0;
3544
3545                 if (tav->get_diskstream() != 0) {
3546                         speed = tav->get_diskstream()->speed();
3547                 }
3548
3549                 XMLNode &before = rv->region()->playlist()->get_state();
3550                 rv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
3551                 XMLNode &after = rv->region()->playlist()->get_state();
3552                 session->add_command(new MementoCommand<Playlist>(
3553                                 *(rv->region()->playlist()), &before, &after));
3554         }
3555                 
3556         commit_reversible_command ();
3557 }
3558
3559 void
3560 Editor::trim_region_from_edit_point ()
3561 {
3562         RegionSelection rs;
3563
3564         get_regions_for_action (rs);
3565
3566         nframes64_t where = get_preferred_edit_position();
3567
3568         begin_reversible_command (_("trim region end to edit point"));
3569
3570         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3571                 RegionView* rv = (*x);
3572
3573                 /* require region to cover trim */
3574                 if (!rv->region()->covers (where)) {
3575                         continue;
3576                 }
3577
3578                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3579                 if (!tav) {
3580                         return;
3581                 }
3582
3583                 float speed = 1.0;
3584
3585                 if (tav->get_diskstream() != 0) {
3586                         speed = tav->get_diskstream()->speed();
3587                 }
3588
3589                 XMLNode &before = rv->region()->playlist()->get_state();
3590                 rv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
3591                 XMLNode &after = rv->region()->playlist()->get_state();
3592                 session->add_command(new MementoCommand<Playlist>(
3593                                 *(rv->region()->playlist()), &before, &after));
3594         }
3595                 
3596         commit_reversible_command ();
3597 }
3598
3599 void
3600 Editor::trim_region_to_previous_region_end ()
3601 {
3602         return trim_to_region(false);
3603 }
3604
3605 void
3606 Editor::trim_region_to_next_region_start ()
3607 {
3608         return trim_to_region(true);
3609 }
3610
3611 void
3612 Editor::trim_to_region(bool forward)
3613 {
3614         RegionSelection rs;
3615
3616         get_regions_for_action (rs);
3617
3618         begin_reversible_command (_("trim to region"));
3619
3620         boost::shared_ptr<Region> next_region;
3621
3622         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3623
3624                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3625
3626                 if (!arv) {
3627                         continue;
3628                 }
3629
3630                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3631
3632                 if (!atav) {
3633                         return;
3634                 }
3635
3636                 float speed = 1.0;
3637
3638                 if (atav->get_diskstream() != 0) {
3639                         speed = atav->get_diskstream()->speed();
3640                 }
3641
3642                 
3643                 boost::shared_ptr<Region> region = arv->region();
3644                 boost::shared_ptr<Playlist> playlist (region->playlist());
3645                 
3646                 XMLNode &before = playlist->get_state();
3647
3648                 if(forward){
3649
3650                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3651
3652                     if(!next_region){
3653                         continue;
3654                     }
3655
3656                     region->trim_end((nframes64_t) (next_region->first_frame() * speed), this);
3657                     arv->region_changed (Change (LengthChanged));
3658                 }
3659                 else {
3660
3661                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3662
3663                     if(!next_region){
3664                         continue;
3665                     }
3666
3667                     region->trim_front((nframes64_t) ((next_region->last_frame() + 1) * speed), this);              
3668                     arv->region_changed (Change (LengthChanged|PositionChanged|StartChanged));
3669                 }
3670
3671                 XMLNode &after = playlist->get_state();
3672                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3673         }
3674
3675         commit_reversible_command ();
3676 }
3677
3678 void
3679 Editor::unfreeze_route ()
3680 {
3681         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3682                 return;
3683         }
3684         
3685         clicked_routeview->track()->unfreeze ();
3686 }
3687
3688 void*
3689 Editor::_freeze_thread (void* arg)
3690 {
3691         PBD::notify_gui_about_thread_creation (pthread_self(), X_("Freeze"));
3692         return static_cast<Editor*>(arg)->freeze_thread ();
3693 }
3694
3695 void*
3696 Editor::freeze_thread ()
3697 {
3698         clicked_routeview->audio_track()->freeze (*current_interthread_info);
3699         current_interthread_info->done = true;
3700         return 0;
3701 }
3702
3703 gint
3704 Editor::freeze_progress_timeout (void */*arg*/)
3705 {
3706         interthread_progress_bar.set_fraction (current_interthread_info->progress);
3707         return !(current_interthread_info->done || current_interthread_info->cancel);
3708 }
3709
3710 void
3711 Editor::freeze_route ()
3712 {
3713         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3714                 return;
3715         }
3716         
3717         InterThreadInfo itt;
3718
3719         if (interthread_progress_window == 0) {
3720                 build_interthread_progress_window ();
3721         }
3722
3723         WindowTitle title(Glib::get_application_name());
3724         title += _("Freeze");
3725         interthread_progress_window->set_title (title.get_string());
3726         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
3727         interthread_progress_window->show_all ();
3728         interthread_progress_bar.set_fraction (0.0f);
3729         interthread_progress_label.set_text ("");
3730         interthread_cancel_label.set_text (_("Cancel Freeze"));
3731         current_interthread_info = &itt;
3732
3733         interthread_progress_connection = 
3734           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
3735
3736         itt.done = false;
3737         itt.cancel = false;
3738         itt.progress = 0.0f;
3739         
3740         pthread_attr_t attr;
3741         pthread_attr_init(&attr);
3742         pthread_attr_setstacksize(&attr, 500000);
3743
3744         pthread_create_and_store (X_("freezer"), &itt.thread, &attr, _freeze_thread, this);
3745
3746         pthread_attr_destroy(&attr);
3747
3748         track_canvas->get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
3749
3750         while (!itt.done && !itt.cancel) {
3751                 gtk_main_iteration ();
3752         }
3753
3754         interthread_progress_connection.disconnect ();
3755         interthread_progress_window->hide_all ();
3756         current_interthread_info = 0;
3757         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
3758 }
3759
3760 void
3761 Editor::bounce_range_selection (bool replace, bool enable_processing)
3762 {
3763         if (selection->time.empty()) {
3764                 return;
3765         }
3766
3767         TrackSelection views = selection->tracks;
3768
3769         nframes64_t start = selection->time[clicked_selection].start;
3770         nframes64_t end = selection->time[clicked_selection].end;
3771         nframes64_t cnt = end - start + 1;
3772
3773         begin_reversible_command (_("bounce range"));
3774
3775         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3776
3777                 RouteTimeAxisView* rtv;
3778
3779                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3780                         continue;
3781                 }
3782                 
3783                 boost::shared_ptr<Playlist> playlist;
3784                 
3785                 if ((playlist = rtv->playlist()) == 0) {
3786                         return;
3787                 }
3788
3789                 InterThreadInfo itt;
3790                 
3791                 itt.done = false;
3792                 itt.cancel = false;
3793                 itt.progress = false;
3794
3795                 XMLNode &before = playlist->get_state();
3796                 boost::shared_ptr<Region> r = rtv->track()->bounce_range (start, start+cnt, itt, enable_processing);
3797                 
3798                 if (replace) {
3799                         list<AudioRange> ranges;
3800                         ranges.push_back (AudioRange (start, start+cnt, 0));
3801                         playlist->cut (ranges); // discard result
3802                         playlist->add_region (r, start);
3803                 }
3804
3805                 XMLNode &after = playlist->get_state();
3806                 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
3807         }
3808         
3809         commit_reversible_command ();
3810 }
3811
3812 /** Cut selected regions, automation points or a time range */
3813 void
3814 Editor::cut ()
3815 {
3816         cut_copy (Cut);
3817 }
3818
3819 /** Copy selected regions, automation points or a time range */
3820 void
3821 Editor::copy ()
3822 {
3823         cut_copy (Copy);
3824 }
3825
3826
3827 /** @return true if a Cut, Copy or Clear is possible */
3828 bool
3829 Editor::can_cut_copy () const
3830 {
3831         switch (current_mouse_mode()) {
3832                 
3833         case MouseObject:
3834                 if (!selection->regions.empty() || !selection->points.empty()) {
3835                         return true;
3836                 }
3837                 break;
3838                 
3839         case MouseRange:
3840                 if (!selection->time.empty()) {
3841                         return true;
3842                 }
3843                 break;
3844                 
3845         default:
3846                 break;
3847         }
3848
3849         return false;
3850 }
3851
3852
3853 /** Cut, copy or clear selected regions, automation points or a time range.
3854  * @param op Operation (Cut, Copy or Clear)
3855  */
3856 void 
3857 Editor::cut_copy (CutCopyOp op)
3858 {
3859         /* only cancel selection if cut/copy is successful.*/
3860
3861         string opname;
3862
3863         switch (op) {
3864         case Cut:
3865                 opname = _("cut");
3866                 break;
3867         case Copy:
3868                 opname = _("copy");
3869                 break;
3870         case Clear:
3871                 opname = _("clear");
3872                 break;
3873         }
3874
3875         /* if we're deleting something, and the mouse is still pressed,
3876            the thing we started a drag for will be gone when we release
3877            the mouse button(s). avoid this. see part 2 at the end of
3878            this function.
3879         */
3880
3881         if (op == Cut || op == Clear) {
3882                 if (_drag) {
3883                         _drag->item()->ungrab (0);
3884                         delete _drag;
3885                         _drag = 0;
3886                 }
3887         }
3888         
3889         cut_buffer->clear ();
3890
3891         if (entered_marker) {
3892
3893                 /* cut/delete op while pointing at a marker */
3894
3895                 bool ignored;
3896                 Location* loc = find_location_from_marker (entered_marker, ignored);
3897
3898                 if (session && loc) {
3899                         Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
3900                 }
3901
3902                 break_drag ();
3903                 delete _drag;
3904                 _drag = 0;
3905
3906                 return;
3907         }
3908
3909         RegionSelection rs; 
3910
3911         /* we only want to cut regions if some are selected */
3912
3913         if (!selection->regions.empty()) {
3914                 get_regions_for_action (rs);
3915         }
3916
3917         switch (current_mouse_mode()) {
3918         case MouseObject: 
3919                 if (!rs.empty() || !selection->points.empty()) {
3920
3921                         begin_reversible_command (opname + _(" objects"));
3922
3923                         if (!rs.empty()) {
3924                                 cut_copy_regions (op, rs);
3925                                 
3926                                 if (op == Cut) {
3927                                         selection->clear_regions ();
3928                                 }
3929                         }
3930
3931                         if (!selection->points.empty()) {
3932                                 cut_copy_points (op);
3933
3934                                 if (op == Cut) {
3935                                         selection->clear_points ();
3936                                 }
3937                         }
3938
3939                         commit_reversible_command ();   
3940                         break; // terminate case statement here
3941                 } 
3942                 if (!selection->time.empty()) {
3943                         /* don't cause suprises */
3944                         break;
3945                 }
3946                 // fall thru if there was nothing selected
3947                 
3948         case MouseRange:
3949                 if (selection->time.empty()) {
3950                         nframes64_t start, end;
3951                         if (!get_edit_op_range (start, end)) {
3952                                 return;
3953                         }
3954                         selection->set ((TimeAxisView*) 0, start, end);
3955                 }
3956                         
3957                 begin_reversible_command (opname + _(" range"));
3958                 cut_copy_ranges (op);
3959                 commit_reversible_command ();
3960                 
3961                 if (op == Cut) {
3962                         selection->clear_time ();
3963                 }
3964
3965                 break;
3966                 
3967         default:
3968                 break;
3969         }
3970
3971
3972         if (op == Cut || op == Clear) {
3973                 break_drag ();
3974                 delete _drag;
3975                 _drag = 0;
3976         }
3977 }
3978
3979 /** Cut, copy or clear selected automation points.
3980  * @param op Operation (Cut, Copy or Clear)
3981  */
3982 void
3983 Editor::cut_copy_points (CutCopyOp op)
3984 {
3985         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3986
3987                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3988
3989                 if (atv) {
3990                         atv->cut_copy_clear_objects (selection->points, op);
3991                 } 
3992         }
3993 }
3994
3995 struct PlaylistState {
3996     boost::shared_ptr<Playlist> playlist;
3997     XMLNode*  before;
3998 };
3999
4000 struct lt_playlist {
4001     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4002             return a.playlist < b.playlist;
4003     }
4004 };
4005         
4006 struct PlaylistMapping { 
4007     TimeAxisView* tv;
4008     boost::shared_ptr<Playlist> pl;
4009
4010     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4011 };
4012
4013 /** Remove `clicked_regionview' */
4014 void
4015 Editor::remove_clicked_region ()
4016 {
4017         if (clicked_routeview == 0 || clicked_regionview == 0) {
4018                 return;
4019         }
4020
4021         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4022         
4023         begin_reversible_command (_("remove region"));
4024         XMLNode &before = playlist->get_state();
4025         playlist->remove_region (clicked_regionview->region());
4026         XMLNode &after = playlist->get_state();
4027         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
4028         commit_reversible_command ();
4029 }
4030
4031
4032 /** Remove the selected regions */
4033 void
4034 Editor::remove_selected_regions ()
4035 {
4036         RegionSelection rs; 
4037         get_regions_for_action (rs);
4038         
4039         if (!session) {
4040                 return;
4041         }
4042
4043         if (rs.empty()) {
4044                 return;
4045         }
4046
4047         begin_reversible_command (_("remove region"));
4048
4049         list<boost::shared_ptr<Region> > regions_to_remove;
4050
4051         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4052                 // we can't just remove the region(s) in this loop because
4053                 // this removes them from the RegionSelection, and they thus
4054                 // disappear from underneath the iterator, and the ++i above
4055                 // SEGVs in a puzzling fashion.
4056
4057                 // so, first iterate over the regions to be removed from rs and
4058                 // add them to the regions_to_remove list, and then
4059                 // iterate over the list to actually remove them.
4060                 
4061                 regions_to_remove.push_back ((*i)->region());
4062         }
4063
4064         vector<PlaylistState> playlists;
4065         
4066         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4067
4068                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4069
4070                 if (!playlist) {
4071                         // is this check necessary?
4072                         continue;
4073                 }
4074
4075                 vector<PlaylistState>::iterator i;
4076
4077                 //only take state if this is a new playlist.
4078                 for (i = playlists.begin(); i != playlists.end(); ++i) {
4079                         if ((*i).playlist == playlist) {
4080                                 break;
4081                         }
4082                 }
4083
4084                 if (i == playlists.end()) {
4085
4086                         PlaylistState before;
4087                         before.playlist = playlist;
4088                         before.before = &playlist->get_state();
4089
4090                         playlist->freeze ();
4091                         playlists.push_back(before);
4092                 }
4093
4094                 playlist->remove_region (*rl);          
4095         }
4096
4097         vector<PlaylistState>::iterator pl;
4098
4099         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4100                 (*pl).playlist->thaw ();
4101                 session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
4102         }
4103
4104         commit_reversible_command ();
4105 }
4106
4107 /** Cut, copy or clear selected regions.
4108  * @param op Operation (Cut, Copy or Clear)
4109  */
4110 void
4111 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4112 {
4113         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4114            a map when we want ordered access to both elements. i think.
4115         */
4116
4117         vector<PlaylistMapping> pmap;
4118
4119         nframes64_t first_position = max_frames;
4120         
4121         set<PlaylistState, lt_playlist> freezelist;
4122         pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
4123         
4124         /* get ordering correct before we cut/copy */
4125         
4126         rs.sort_by_position_and_track ();
4127
4128         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4129
4130                 first_position = min ((nframes64_t) (*x)->region()->position(), first_position);
4131
4132                 if (op == Cut || op == Clear) {
4133                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4134
4135                         if (pl) {
4136                                 set<PlaylistState, lt_playlist>::iterator fl;
4137
4138                                 //only take state if this is a new playlist.
4139                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4140                                         if ((*fl).playlist == pl) {
4141                                                 break;
4142                                         }
4143                                 }
4144                 
4145                                 if (fl == freezelist.end()) {
4146                                         PlaylistState before;
4147                                         before.playlist = pl;
4148                                         before.before = &pl->get_state();
4149                                         pl->freeze ();
4150                                         insert_result = freezelist.insert (before);
4151                                 }
4152                         }
4153                 }
4154
4155                 TimeAxisView* tv = &(*x)->get_trackview();
4156                 vector<PlaylistMapping>::iterator z;
4157
4158                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4159                         if ((*z).tv == tv) {
4160                                 break;
4161                         }
4162                 }
4163                 
4164                 if (z == pmap.end()) {
4165                         pmap.push_back (PlaylistMapping (tv));
4166                 }
4167         }
4168
4169         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4170
4171                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4172                 
4173                 if (!pl) {
4174                         /* impossible, but this handles it for the future */
4175                         continue;
4176                 }
4177
4178                 TimeAxisView& tv = (*x)->get_trackview();
4179                 boost::shared_ptr<Playlist> npl;
4180                 RegionSelection::iterator tmp;
4181                 
4182                 tmp = x;
4183                 ++tmp;
4184
4185                 vector<PlaylistMapping>::iterator z;
4186                 
4187                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4188                         if ((*z).tv == &tv) {
4189                                 break;
4190                         }
4191                 }
4192                 
4193                 assert (z != pmap.end());
4194                 
4195                 if (!(*z).pl) {
4196                         npl = PlaylistFactory::create (pl->data_type(), *session, "cutlist", true);
4197                         npl->freeze();
4198                         (*z).pl = npl;
4199                 } else {
4200                         npl = (*z).pl;
4201                 }
4202                 
4203                 boost::shared_ptr<Region> r = (*x)->region();
4204                 boost::shared_ptr<Region> _xx;
4205
4206                 assert (r != 0);
4207
4208                 switch (op) {
4209                 case Cut:
4210                         _xx = RegionFactory::create (r);
4211                         npl->add_region (_xx, r->position() - first_position);
4212                         pl->remove_region (r);
4213                         break;
4214                         
4215                 case Copy:
4216                         /* copy region before adding, so we're not putting same object into two different playlists */
4217                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4218                         break;
4219                         
4220                 case Clear:
4221                         pl->remove_region (r);
4222                         break;
4223                 }
4224
4225                 x = tmp;
4226         }
4227         
4228         list<boost::shared_ptr<Playlist> > foo;
4229         
4230         /* the pmap is in the same order as the tracks in which selected regions occured */
4231         
4232         for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4233                 (*i).pl->thaw();
4234                 foo.push_back ((*i).pl);
4235         }
4236         
4237
4238         if (!foo.empty()) {
4239                 cut_buffer->set (foo);
4240         }
4241
4242         for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4243                 (*pl).playlist->thaw ();
4244                 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
4245         }
4246 }
4247
4248 void
4249 Editor::cut_copy_ranges (CutCopyOp op)
4250 {
4251         TrackSelection* ts;
4252         TrackSelection entered;
4253
4254         if (selection->tracks.empty()) {
4255                 if (!entered_track) {
4256                         return;
4257                 }
4258                 entered.push_back (entered_track);
4259                 ts = &entered;
4260         } else {
4261                 ts = &selection->tracks;
4262         }
4263
4264         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
4265                 (*i)->cut_copy_clear (*selection, op);
4266         }
4267 }
4268
4269 void
4270 Editor::paste (float times)
4271 {
4272         paste_internal (get_preferred_edit_position(), times);
4273 }
4274
4275 void
4276 Editor::mouse_paste ()
4277 {
4278         nframes64_t where;
4279         bool ignored;
4280
4281         if (!mouse_frame (where, ignored)) {
4282                 return;
4283         }
4284
4285         snap_to (where);
4286         paste_internal (where, 1);
4287 }
4288
4289 void
4290 Editor::paste_internal (nframes64_t position, float times)
4291 {
4292         bool commit = false;
4293
4294         if (cut_buffer->empty()) {
4295                 return;
4296         }
4297
4298         if (position == max_frames) {
4299                 position = get_preferred_edit_position();
4300         }
4301
4302         begin_reversible_command (_("paste"));
4303
4304         TrackSelection ts;
4305         TrackSelection::iterator i;
4306         size_t nth;
4307
4308         /* get everything in the correct order */
4309
4310
4311         if (!selection->tracks.empty()) {
4312                 sort_track_selection ();
4313                 ts = selection->tracks;
4314         } else if (entered_track) {
4315                 ts.push_back (entered_track);
4316         }
4317
4318         for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
4319
4320                 /* undo/redo is handled by individual tracks */
4321
4322                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
4323                         commit = true;
4324                 }
4325         }
4326         
4327         if (commit) {
4328                 commit_reversible_command ();
4329         }
4330 }
4331
4332 void
4333 Editor::paste_named_selection (float times)
4334 {
4335         TrackSelection::iterator t;
4336
4337         Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
4338
4339         if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
4340                 return;
4341         }
4342
4343         TreeModel::iterator i = selected->get_selected();
4344         NamedSelection* ns = (*i)[named_selection_columns.selection];
4345
4346         list<boost::shared_ptr<Playlist> >::iterator chunk;
4347         list<boost::shared_ptr<Playlist> >::iterator tmp;
4348
4349         chunk = ns->playlists.begin();
4350                 
4351         begin_reversible_command (_("paste chunk"));
4352         
4353         sort_track_selection ();
4354
4355         for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
4356                 
4357                 RouteTimeAxisView* rtv;
4358                 boost::shared_ptr<Playlist> pl;
4359                 boost::shared_ptr<AudioPlaylist> apl;
4360
4361                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*t)) == 0) {
4362                         continue;
4363                 }
4364
4365                 if ((pl = rtv->playlist()) == 0) {
4366                         continue;
4367                 }
4368                 
4369                 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
4370                         continue;
4371                 }
4372
4373                 tmp = chunk;
4374                 ++tmp;
4375
4376                 XMLNode &before = apl->get_state();
4377                 apl->paste (*chunk, get_preferred_edit_position(), times);
4378                 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
4379
4380                 if (tmp != ns->playlists.end()) {
4381                         chunk = tmp;
4382                 }
4383         }
4384
4385         commit_reversible_command();
4386 }
4387
4388 void
4389 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4390 {
4391         boost::shared_ptr<Playlist> playlist; 
4392         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4393         RegionSelection foo;
4394
4395         begin_reversible_command (_("duplicate region"));
4396
4397         selection->clear_regions ();
4398
4399         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4400
4401                 boost::shared_ptr<Region> r ((*i)->region());
4402
4403                 TimeAxisView& tv = (*i)->get_time_axis_view();
4404                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4405                 latest_regionviews.clear ();
4406                 sigc::connection c = rtv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
4407                 
4408                 playlist = (*i)->region()->playlist();
4409                 XMLNode &before = playlist->get_state();
4410                 playlist->duplicate (r, r->last_frame(), times);
4411                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
4412
4413                 c.disconnect ();
4414                 
4415                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4416         }
4417
4418         commit_reversible_command ();
4419
4420         if (!foo.empty()) {
4421                 selection->set (foo);
4422         }
4423 }
4424
4425 void
4426 Editor::duplicate_selection (float times)
4427 {
4428         if (selection->time.empty() || selection->tracks.empty()) {
4429                 return;
4430         }
4431
4432         boost::shared_ptr<Playlist> playlist; 
4433         vector<boost::shared_ptr<Region> > new_regions;
4434         vector<boost::shared_ptr<Region> >::iterator ri;
4435                 
4436         create_region_from_selection (new_regions);
4437
4438         if (new_regions.empty()) {
4439                 return;
4440         }
4441         
4442         begin_reversible_command (_("duplicate selection"));
4443
4444         ri = new_regions.begin();
4445
4446         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4447                 if ((playlist = (*i)->playlist()) == 0) {
4448                         continue;
4449                 }
4450                 XMLNode &before = playlist->get_state();
4451                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4452                 XMLNode &after = playlist->get_state();
4453                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
4454
4455                 ++ri;
4456                 if (ri == new_regions.end()) {
4457                         --ri;
4458                 }
4459         }
4460
4461         commit_reversible_command ();
4462 }
4463
4464 void
4465 Editor::reset_point_selection ()
4466 {
4467         /* reset all selected points to the relevant default value */
4468
4469         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4470                 
4471                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
4472                 
4473                 if (atv) {
4474                         atv->reset_objects (selection->points);
4475                 } 
4476         }
4477 }
4478
4479 void
4480 Editor::center_playhead ()
4481 {
4482         float page = _canvas_width * frames_per_unit;
4483         center_screen_internal (playhead_cursor->current_frame, page);
4484 }
4485
4486 void
4487 Editor::center_edit_point ()
4488 {
4489         float page = _canvas_width * frames_per_unit;
4490         center_screen_internal (get_preferred_edit_position(), page);
4491 }
4492
4493 void
4494 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4495 {
4496         begin_reversible_command (_("clear playlist"));
4497         XMLNode &before = playlist->get_state();
4498         playlist->clear ();
4499         XMLNode &after = playlist->get_state();
4500         session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
4501         commit_reversible_command ();
4502 }
4503
4504 void
4505 Editor::nudge_track (bool use_edit, bool forwards)
4506 {
4507         boost::shared_ptr<Playlist> playlist; 
4508         nframes64_t distance;
4509         nframes64_t next_distance;
4510         nframes64_t start;
4511
4512         if (use_edit) {
4513                 start = get_preferred_edit_position();
4514         } else {
4515                 start = 0;
4516         }
4517
4518         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4519                 return;
4520         }
4521         
4522         if (selection->tracks.empty()) {
4523                 return;
4524         }
4525         
4526         begin_reversible_command (_("nudge track"));
4527         
4528         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
4529
4530                 if ((playlist = (*i)->playlist()) == 0) {
4531                         continue;
4532                 }               
4533                 
4534                 XMLNode &before = playlist->get_state();
4535                 playlist->nudge_after (start, distance, forwards);
4536                 XMLNode &after = playlist->get_state();
4537                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
4538         }
4539         
4540         commit_reversible_command ();                   
4541 }
4542
4543 void
4544 Editor::remove_last_capture ()
4545 {
4546         vector<string> choices;
4547         string prompt;
4548         
4549         if (!session) {
4550                 return;
4551         }
4552
4553         if (Config->get_verify_remove_last_capture()) {
4554                 prompt  = _("Do you really want to destroy the last capture?"
4555                             "\n(This is destructive and cannot be undone)");
4556
4557                 choices.push_back (_("No, do nothing."));
4558                 choices.push_back (_("Yes, destroy it."));
4559                 
4560                 Gtkmm2ext::Choice prompter (prompt, choices);
4561                 
4562                 if (prompter.run () == 1) {
4563                         session->remove_last_capture ();
4564                 }
4565
4566         } else {
4567                 session->remove_last_capture();
4568         }
4569 }
4570
4571 void
4572 Editor::normalize_region ()
4573 {
4574         if (!session) {
4575                 return;
4576         }
4577
4578         RegionSelection rs; 
4579         get_regions_for_action (rs);
4580
4581         if (rs.empty()) {
4582                 return;
4583         }
4584         
4585         Dialog dialog (rs.size() > 1 ? _("Normalize regions") : _("Normalize region"));
4586         HBox hbox;
4587         hbox.pack_start (*manage (new Label (_("Normalize to:"))));
4588         SpinButton spin (0.2, 2);
4589         spin.set_range (-112, 0);
4590         spin.set_increments (0.1, 1);
4591         spin.set_value (0);
4592         hbox.pack_start (spin);
4593         spin.set_value (_last_normalization_value);
4594         hbox.pack_start (*manage (new Label (_("dbFS"))));
4595         hbox.show_all ();
4596         dialog.get_vbox()->pack_start (hbox);
4597         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
4598         dialog.add_button (_("Normalize"), RESPONSE_ACCEPT);
4599
4600         if (dialog.run () == RESPONSE_CANCEL) {
4601                 return;
4602         }
4603
4604         begin_reversible_command (_("normalize"));
4605
4606         track_canvas->get_window()->set_cursor (*wait_cursor);
4607         gdk_flush ();
4608
4609         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4610                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4611                 if (!arv)
4612                         continue;
4613                 XMLNode &before = arv->region()->get_state();
4614                 arv->audio_region()->normalize_to (spin.get_value());
4615                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4616         }
4617
4618         commit_reversible_command ();
4619         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
4620
4621         _last_normalization_value = spin.get_value ();
4622 }
4623
4624
4625 void
4626 Editor::denormalize_region ()
4627 {
4628         if (!session) {
4629                 return;
4630         }
4631
4632         RegionSelection rs; 
4633
4634         get_regions_for_action (rs);
4635
4636         if (rs.empty()) {
4637                 return;
4638         }
4639
4640         begin_reversible_command ("denormalize");
4641
4642         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4643                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4644                 if (!arv)
4645                         continue;
4646                 XMLNode &before = arv->region()->get_state();
4647                 arv->audio_region()->set_scale_amplitude (1.0f);
4648                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4649         }
4650
4651         commit_reversible_command ();
4652 }
4653
4654 void
4655 Editor::adjust_region_scale_amplitude (bool up)
4656 {
4657         if (!session) {
4658                 return;
4659         }
4660
4661         RegionSelection rs; 
4662
4663         get_regions_for_action (rs);
4664
4665         if (rs.empty()) {
4666                 return;
4667         }
4668
4669         begin_reversible_command ("denormalize");
4670
4671         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4672                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4673                 if (!arv)
4674                         continue;
4675                 XMLNode &before = arv->region()->get_state();
4676                 
4677                 double fraction = gain_to_slider_position (arv->audio_region()->scale_amplitude ());
4678                 
4679                 if (up) {
4680                         fraction += 0.05;
4681                         fraction = min (fraction, 1.0);
4682                 } else {
4683                         fraction -= 0.05;
4684                         fraction = max (fraction, 0.0);
4685                 }
4686
4687                 if (!up && fraction <= 0) {
4688                         continue;
4689                 }
4690
4691                 fraction = slider_position_to_gain (fraction);
4692                 fraction = coefficient_to_dB (fraction);
4693                 fraction = dB_to_coefficient (fraction);
4694
4695                 if (up && fraction >= 2.0) {
4696                         continue;
4697                 }
4698                 
4699                 arv->audio_region()->set_scale_amplitude (fraction);
4700                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
4701         }
4702
4703         commit_reversible_command ();
4704 }
4705
4706
4707 void
4708 Editor::reverse_region ()
4709 {
4710         if (!session) {
4711                 return;
4712         }
4713
4714         Reverse rev (*session);
4715         apply_filter (rev, _("reverse regions"));
4716 }
4717
4718 void
4719 Editor::strip_region_silence ()
4720 {
4721         if (!session) {
4722                 return;
4723         }
4724
4725         RegionSelection rs;
4726         get_regions_for_action (rs);
4727
4728         if (rs.empty()) {
4729                 return;
4730         }
4731
4732         std::list<boost::shared_ptr<AudioRegion> > ar;
4733         
4734         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4735                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4736                 if (arv) {
4737                         ar.push_back (arv->audio_region ());
4738                 }
4739         }
4740         
4741         StripSilenceDialog d (ar);
4742         int const r = d.run ();
4743
4744         if (r == Gtk::RESPONSE_OK) {
4745                 StripSilence s (*session, d.threshold (), d.minimum_length (), d.fade_length ());
4746                 apply_filter (s, _("strip silence"));
4747         }
4748 }
4749
4750
4751 void
4752 Editor::quantize_region ()
4753 {
4754         if (!session) {
4755                 return;
4756         }
4757
4758         // FIXME: varying meter?
4759         Quantize quant (*session, snap_length_beats(0));
4760         apply_filter (quant, _("quantize regions"));
4761 }
4762
4763 void
4764 Editor::apply_filter (Filter& filter, string command)
4765 {
4766         RegionSelection rs; 
4767
4768         get_regions_for_action (rs);
4769
4770         if (rs.empty()) {
4771                 return;
4772         }
4773
4774         begin_reversible_command (command);
4775
4776         track_canvas->get_window()->set_cursor (*wait_cursor);
4777         gdk_flush ();
4778
4779         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4780                 RegionSelection::iterator tmp = r;
4781                 ++tmp;
4782
4783                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4784                 if (mrv) {
4785                         if (mrv->midi_region()->apply(filter) == 0) {
4786                                 mrv->redisplay_model();
4787                         }
4788                 }
4789
4790                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4791                 if (arv) {
4792                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
4793
4794                         if (arv->audio_region()->apply (filter) == 0) {
4795
4796                                 XMLNode &before = playlist->get_state();
4797
4798                                 if (filter.results.empty ()) {
4799
4800                                         /* no regions returned; remove the old one */
4801                                         playlist->remove_region (arv->region ());
4802                                         
4803                                 } else {
4804
4805                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
4806
4807                                         /* first region replaces the old one */
4808                                         playlist->replace_region (arv->region(), *res, (*res)->position());
4809                                         ++res;
4810
4811                                         /* add the rest */
4812                                         while (res != filter.results.end()) {
4813                                                 playlist->add_region (*res, (*res)->position());
4814                                                 ++res;
4815                                         }
4816                                         
4817                                 }
4818
4819                                 XMLNode &after = playlist->get_state();
4820                                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
4821                         } else {
4822                                 goto out;
4823                         }
4824                 }
4825
4826                 r = tmp;
4827         }
4828
4829         commit_reversible_command ();
4830         rs.clear ();
4831
4832   out:
4833         track_canvas->get_window()->set_cursor (*current_canvas_cursor);
4834 }
4835
4836 void
4837 Editor::region_selection_op (void (Region::*pmf)(void))
4838 {
4839         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4840                 Region* region = (*i)->region().get();
4841                 (region->*pmf)();
4842         }
4843 }
4844
4845
4846 void
4847 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
4848 {
4849         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4850                 Region* region = (*i)->region().get();
4851                 (region->*pmf)(arg);
4852         }
4853 }
4854
4855 void
4856 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
4857 {
4858         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4859                 Region* region = (*i)->region().get();
4860                 (region->*pmf)(yn);
4861         }
4862 }
4863
4864 void
4865 Editor::external_edit_region ()
4866 {
4867         /* more to come */
4868 }
4869
4870 void
4871 Editor::brush (nframes64_t pos)
4872 {
4873         RegionSelection sel;
4874         RegionSelection rs; 
4875
4876         get_regions_for_action (rs);
4877
4878         snap_to (pos);
4879
4880         if (rs.empty()) {
4881                 return;
4882         }
4883
4884         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4885                 mouse_brush_insert_region ((*i), pos);
4886         }
4887 }
4888
4889 void
4890 Editor::reset_region_gain_envelopes ()
4891 {
4892         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
4893
4894         if (!session || rs.empty()) {
4895                 return;
4896         }
4897
4898         session->begin_reversible_command (_("reset region gain"));
4899
4900         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4901                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4902                 if (arv) {
4903                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
4904                         XMLNode& before (alist->get_state());
4905
4906                         arv->audio_region()->set_default_envelope ();
4907                         session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
4908                 }
4909         }
4910
4911         session->commit_reversible_command ();
4912 }
4913
4914 void
4915 Editor::toggle_gain_envelope_visibility ()
4916 {
4917         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
4918
4919         if (!session || rs.empty()) {
4920                 return;
4921         }
4922
4923         session->begin_reversible_command (_("region gain envelope visible"));
4924
4925         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4926                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4927                 if (arv) {
4928                         XMLNode &before = arv->region()->get_state ();
4929                         arv->set_envelope_visible (!arv->envelope_visible());
4930                         XMLNode &after = arv->region()->get_state ();
4931                         session->add_command (new MementoCommand<Region> (*(arv->region().get()), &before, &after));
4932                 }
4933         }
4934
4935         session->commit_reversible_command ();
4936 }
4937
4938 void
4939 Editor::toggle_gain_envelope_active ()
4940 {
4941         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
4942
4943         if (!session || rs.empty()) {
4944                 return;
4945         }
4946         
4947         session->begin_reversible_command (_("region gain envelope active"));
4948
4949         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4950                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4951                 if (arv) {
4952                         XMLNode &before = arv->region()->get_state ();
4953                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
4954                         XMLNode &after = arv->region()->get_state ();
4955                         session->add_command (new MementoCommand<Region> (*(arv->region().get()), &before, &after));
4956                 }
4957         }
4958
4959         session->commit_reversible_command ();
4960 }
4961
4962 void
4963 Editor::toggle_region_lock ()
4964 {
4965         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
4966
4967         if (!session || rs.empty()) {
4968                 return;
4969         }
4970         
4971         session->begin_reversible_command (_("region lock"));
4972
4973         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4974                 XMLNode &before = (*i)->region()->get_state ();
4975                 (*i)->region()->set_locked (!(*i)->region()->locked());
4976                 XMLNode &after = (*i)->region()->get_state ();
4977                 session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
4978         }
4979
4980         session->commit_reversible_command ();
4981 }
4982
4983 void
4984 Editor::set_region_lock_style (Region::PositionLockStyle ps)
4985 {
4986         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
4987
4988         if (!session || rs.empty()) {
4989                 return;
4990         }
4991         
4992         session->begin_reversible_command (_("region lock style"));
4993
4994         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4995                 XMLNode &before = (*i)->region()->get_state ();
4996                 (*i)->region()->set_position_lock_style (ps);
4997                 XMLNode &after = (*i)->region()->get_state ();
4998                 session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
4999         }
5000
5001         session->commit_reversible_command ();
5002 }
5003
5004
5005 void
5006 Editor::toggle_region_mute ()
5007 {
5008         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
5009
5010         if (!session || rs.empty()) {
5011                 return;
5012         }
5013         
5014         session->begin_reversible_command (_("region mute"));
5015
5016         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5017                 XMLNode &before = (*i)->region()->get_state ();
5018                 (*i)->region()->set_muted (!(*i)->region()->muted());
5019                 XMLNode &after = (*i)->region()->get_state ();
5020                 session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
5021         }
5022
5023         session->commit_reversible_command ();
5024 }
5025
5026 void
5027 Editor::toggle_region_opaque ()
5028 {
5029         RegionSelection rs = get_equivalent_regions (selection->regions, RouteGroup::Edit);
5030
5031         if (!session || rs.empty()) {
5032                 return;
5033         }
5034         
5035         session->begin_reversible_command (_("region opacity"));
5036
5037         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5038                 XMLNode &before = (*i)->region()->get_state ();
5039                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5040                 XMLNode &after = (*i)->region()->get_state ();
5041                 session->add_command (new MementoCommand<Region> (*((*i)->region().get()), &before, &after));
5042         }
5043
5044         session->commit_reversible_command ();
5045 }
5046
5047 void
5048 Editor::toggle_record_enable ()
5049 {
5050         bool new_state = false;
5051         bool first = true;
5052         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5053                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5054                 if (!rtav)
5055                         continue;
5056                 if (!rtav->is_track())
5057                         continue;
5058
5059                 if (first) {
5060                         new_state = !rtav->track()->record_enabled();
5061                         first = false;
5062                 }
5063
5064                 rtav->track()->set_record_enable(new_state, this);
5065         }
5066 }
5067
5068
5069 void
5070 Editor::set_fade_length (bool in)
5071 {
5072         RegionSelection rs; 
5073
5074         get_regions_for_action (rs, true);
5075
5076         if (rs.empty()) {
5077                 return;
5078         }
5079
5080         /* we need a region to measure the offset from the start */
5081
5082         RegionView* rv = rs.front ();
5083
5084         nframes64_t pos = get_preferred_edit_position();
5085         nframes64_t len;
5086         char* cmd;
5087         
5088         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5089                 /* edit point is outside the relevant region */
5090                 return;
5091         }
5092
5093         if (in) {
5094                 if (pos <= rv->region()->position()) {
5095                         /* can't do it */
5096                         return;
5097                 }
5098                 len = pos - rv->region()->position();
5099                 cmd = _("set fade in length");
5100         } else {
5101                 if (pos >= rv->region()->last_frame()) {
5102                         /* can't do it */
5103                         return;
5104                 }
5105                 len = rv->region()->last_frame() - pos;
5106                 cmd = _("set fade out length");
5107         }
5108
5109         begin_reversible_command (cmd);
5110
5111         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5112                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5113
5114                 if (!tmp) {
5115                         return;
5116                 }
5117
5118                 boost::shared_ptr<AutomationList> alist;
5119                 if (in) {
5120                         alist = tmp->audio_region()->fade_in();
5121                 } else {
5122                         alist = tmp->audio_region()->fade_out();
5123                 }
5124
5125                 XMLNode &before = alist->get_state();
5126
5127                 if (in) {
5128                         tmp->audio_region()->set_fade_in_length (len);
5129                         tmp->audio_region()->set_fade_in_active (true);
5130                 } else {
5131                         tmp->audio_region()->set_fade_out_length (len);
5132                         tmp->audio_region()->set_fade_out_active (true);
5133                 }
5134                 
5135                 XMLNode &after = alist->get_state();
5136                 session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5137         }
5138
5139         commit_reversible_command ();
5140 }
5141
5142 void
5143 Editor::toggle_fade_active (bool in)
5144 {
5145         RegionSelection rs; 
5146
5147         get_regions_for_action (rs);
5148
5149         if (rs.empty()) {
5150                 return;
5151         }
5152
5153         const char* cmd = (in ? _("toggle fade in active") : _("toggle fade out active"));
5154         bool have_switch = false;
5155         bool yn = false;
5156
5157         begin_reversible_command (cmd);
5158
5159         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5160                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5161                 
5162                 if (!tmp) {
5163                         return;
5164                 }
5165
5166                 boost::shared_ptr<AudioRegion> region (tmp->audio_region());
5167
5168                 /* make the behaviour consistent across all regions */
5169                 
5170                 if (!have_switch) {
5171                         if (in) {
5172                                 yn = region->fade_in_active();
5173                         } else {
5174                                 yn = region->fade_out_active();
5175                         }
5176                         have_switch = true;
5177                 }
5178
5179                 XMLNode &before = region->get_state();
5180                 if (in) {
5181                         region->set_fade_in_active (!yn);
5182                 } else {
5183                         region->set_fade_out_active (!yn);
5184                 }
5185                 XMLNode &after = region->get_state();
5186                 session->add_command(new MementoCommand<AudioRegion>(*region.get(), &before, &after));
5187         }
5188
5189         commit_reversible_command ();
5190 }
5191
5192 void
5193 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
5194 {
5195         RegionSelection rs; 
5196
5197         get_regions_for_action (rs);
5198
5199         if (rs.empty()) {
5200                 return;
5201         }
5202
5203         begin_reversible_command (_("set fade in shape"));
5204
5205         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5206                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5207
5208                 if (!tmp) {
5209                         return;
5210                 }
5211
5212                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5213                 XMLNode &before = alist->get_state();
5214
5215                 tmp->audio_region()->set_fade_in_shape (shape);
5216                 
5217                 XMLNode &after = alist->get_state();
5218                 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5219         }
5220
5221         commit_reversible_command ();
5222                 
5223 }
5224
5225 void
5226 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
5227 {
5228         RegionSelection rs; 
5229
5230         get_regions_for_action (rs);
5231
5232         if (rs.empty()) {
5233                 return;
5234         }
5235
5236         begin_reversible_command (_("set fade out shape"));
5237
5238         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5239                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5240
5241                 if (!tmp) {
5242                         return;
5243                 }
5244
5245                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5246                 XMLNode &before = alist->get_state();
5247
5248                 tmp->audio_region()->set_fade_out_shape (shape);
5249                 
5250                 XMLNode &after = alist->get_state();
5251                 session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5252         }
5253
5254         commit_reversible_command ();
5255 }
5256
5257 void
5258 Editor::set_fade_in_active (bool yn)
5259 {
5260         RegionSelection rs; 
5261
5262         get_regions_for_action (rs);
5263
5264         if (rs.empty()) {
5265                 return;
5266         }
5267
5268         begin_reversible_command (_("set fade in active"));
5269
5270         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5271                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5272
5273                 if (!tmp) {
5274                         return;
5275                 }
5276
5277
5278                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5279
5280                 XMLNode &before = ar->get_state();
5281
5282                 ar->set_fade_in_active (yn);
5283                 
5284                 XMLNode &after = ar->get_state();
5285                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
5286         }
5287
5288         commit_reversible_command ();
5289 }
5290
5291 void
5292 Editor::set_fade_out_active (bool yn)
5293 {
5294         RegionSelection rs; 
5295
5296         get_regions_for_action (rs);
5297
5298         if (rs.empty()) {
5299                 return;
5300         }
5301
5302         begin_reversible_command (_("set fade out active"));
5303
5304         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5305                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5306
5307                 if (!tmp) {
5308                         return;
5309                 }
5310
5311                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5312
5313                 XMLNode &before = ar->get_state();
5314
5315                 ar->set_fade_out_active (yn);
5316                 
5317                 XMLNode &after = ar->get_state();
5318                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
5319         }
5320
5321         commit_reversible_command ();
5322 }
5323
5324 void
5325 Editor::toggle_selected_region_fades (int dir)
5326 {
5327         RegionSelection rs;
5328         RegionSelection::iterator i;
5329         boost::shared_ptr<AudioRegion> ar;
5330         bool yn;
5331
5332         get_regions_for_action (rs);
5333         
5334         if (rs.empty()) {
5335                 return;
5336         }
5337
5338         for (i = rs.begin(); i != rs.end(); ++i) {
5339                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5340                         if (dir == -1) {
5341                                 yn = ar->fade_out_active ();
5342                         } else {
5343                                 yn = ar->fade_in_active ();
5344                         }
5345                         break;
5346                 }
5347         }
5348
5349         if (i == rs.end()) {
5350                 return;
5351         }
5352
5353         /* XXX should this undo-able? */
5354
5355         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5356                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5357                         continue;
5358                 }
5359                 if (dir == 1 || dir == 0) {
5360                         ar->set_fade_in_active (!yn);
5361                 }
5362
5363                 if (dir == -1 || dir == 0) {
5364                         ar->set_fade_out_active (!yn);
5365                 }
5366         }
5367 }
5368
5369
5370 /** Update region fade visibility after its configuration has been changed */
5371 void
5372 Editor::update_region_fade_visibility ()
5373 {
5374         bool _fade_visibility = session->config.get_show_region_fades ();
5375
5376         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5377                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5378                 if (v) {
5379                         if (_fade_visibility) {
5380                                 v->audio_view()->show_all_fades ();
5381                         } else {
5382                                 v->audio_view()->hide_all_fades ();
5383                         }
5384                 }
5385         }
5386 }
5387
5388 /** Update crossfade visibility after its configuration has been changed */
5389 void
5390 Editor::update_xfade_visibility ()
5391 {
5392         _xfade_visibility = session->config.get_xfades_visible ();
5393         
5394         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5395                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5396                 if (v) {
5397                         if (_xfade_visibility) {
5398                                 v->show_all_xfades ();
5399                         } else {
5400                                 v->hide_all_xfades ();
5401                         }
5402                 }
5403         }
5404 }
5405
5406 void
5407 Editor::set_edit_point ()
5408 {
5409         nframes64_t where;
5410         bool ignored;
5411
5412         if (!mouse_frame (where, ignored)) {
5413                 return;
5414         }
5415         
5416         snap_to (where);
5417
5418         if (selection->markers.empty()) {
5419                 
5420                 mouse_add_new_marker (where);
5421
5422         } else {
5423                 bool ignored;
5424
5425                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5426
5427                 if (loc) {
5428                         loc->move_to (where);
5429                 }
5430         }
5431 }
5432
5433 void
5434 Editor::set_playhead_cursor ()
5435 {
5436         if (entered_marker) {
5437                 session->request_locate (entered_marker->position(), session->transport_rolling());
5438         } else {
5439                 nframes64_t where;
5440                 bool ignored;
5441
5442                 if (!mouse_frame (where, ignored)) {
5443                         return;
5444                 }
5445                         
5446                 snap_to (where);
5447                 
5448                 if (session) {
5449                         session->request_locate (where, session->transport_rolling());
5450                 }
5451         }
5452 }
5453
5454 void
5455 Editor::split ()
5456 {
5457         RegionSelection rs; 
5458         
5459         get_regions_for_action (rs, true);
5460
5461         nframes64_t where = get_preferred_edit_position();
5462
5463         if (rs.empty()) {
5464                 return;
5465         }
5466
5467         split_regions_at (where, rs);
5468 }
5469
5470 void
5471 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
5472 {
5473         if (entered_track && mouse_mode == MouseObject) {
5474                 if (!selection->tracks.empty()) {
5475                         if (!selection->selected (entered_track)) {
5476                                 selection->add (entered_track);
5477                         }
5478                 } else {
5479                         /* there is no selection, but this operation requires/prefers selected objects */
5480
5481                         if (op_really_wants_one_track_if_none_are_selected) {
5482                                 selection->set (entered_track);
5483                         }
5484                 }
5485         }
5486 }
5487
5488 struct EditorOrderRouteSorter {
5489     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5490             /* use of ">" forces the correct sort order */
5491             return a->order_key ("editor") < b->order_key ("editor");
5492     }
5493 };
5494
5495 void
5496 Editor::select_next_route()
5497 {
5498         if (selection->tracks.empty()) {
5499                 selection->set (track_views.front());
5500                 return;
5501         }
5502
5503         TimeAxisView* current = selection->tracks.front();
5504
5505         RouteUI *rui;
5506         do {
5507                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5508                         if (*i == current) {
5509                                 ++i;
5510                                 if (i != track_views.end()) {
5511                                         current = (*i);
5512                                 } else {
5513                                         current = (*(track_views.begin()));
5514                                         //selection->set (*(track_views.begin()));
5515                                 }
5516                                 break;
5517                         }
5518                 }
5519                 rui = dynamic_cast<RouteUI *>(current);
5520         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5521
5522         selection->set(current);
5523
5524         ensure_track_visible(current);
5525 }
5526
5527 void
5528 Editor::select_prev_route()
5529 {
5530         if (selection->tracks.empty()) {
5531                 selection->set (track_views.front());
5532                 return;
5533         }
5534
5535         TimeAxisView* current = selection->tracks.front();
5536
5537         RouteUI *rui;
5538         do {
5539                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5540                         if (*i == current) {
5541                                 ++i;
5542                                 if (i != track_views.rend()) {
5543                                         current = (*i);
5544                                 } else {
5545                                         current = *(track_views.rbegin());
5546                                 }
5547                                 break;
5548                         }
5549                 }
5550                 rui = dynamic_cast<RouteUI *>(current);
5551         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5552
5553         selection->set (current);
5554
5555         ensure_track_visible(current);
5556 }
5557
5558 void
5559 Editor::ensure_track_visible(TimeAxisView *track)
5560 {
5561         if (track->hidden())
5562                 return;
5563
5564         double const current_view_min_y = vertical_adjustment.get_value();
5565         double const current_view_max_y = vertical_adjustment.get_value() + vertical_adjustment.get_page_size() - canvas_timebars_vsize;
5566
5567         double const track_min_y = track->y_position ();
5568         double const track_max_y = track->y_position () + track->effective_height ();
5569
5570         if (track_min_y >= current_view_min_y &&
5571             track_max_y <= current_view_max_y) {
5572                 return;
5573         }
5574
5575         double new_value;
5576
5577         if (track_min_y < current_view_min_y) {
5578                 // Track is above the current view
5579                 new_value = track_min_y;
5580         } else {
5581                 // Track is below the current view
5582                 new_value = track->y_position () + track->effective_height() + canvas_timebars_vsize - vertical_adjustment.get_page_size();
5583         }
5584
5585         vertical_adjustment.set_value(new_value);
5586 }
5587
5588 void
5589 Editor::set_loop_from_selection (bool play)
5590 {
5591         if (session == 0 || selection->time.empty()) {
5592                 return;
5593         }
5594
5595         nframes64_t start = selection->time[clicked_selection].start;
5596         nframes64_t end = selection->time[clicked_selection].end;
5597         
5598         set_loop_range (start, end,  _("set loop range from selection"));
5599
5600         if (play) {
5601                 session->request_play_loop (true);
5602                 session->request_locate (start, true);
5603         }
5604 }
5605
5606 void
5607 Editor::set_loop_from_edit_range (bool play)
5608 {
5609         if (session == 0) {
5610                 return;
5611         }
5612
5613         nframes64_t start;
5614         nframes64_t end;
5615         
5616         if (!get_edit_op_range (start, end)) {
5617                 return;
5618         }
5619
5620         set_loop_range (start, end,  _("set loop range from edit range"));
5621
5622         if (play) {
5623                 session->request_play_loop (true);
5624                 session->request_locate (start, true);
5625         }
5626 }
5627
5628 void
5629 Editor::set_loop_from_region (bool play)
5630 {
5631         nframes64_t start = max_frames;
5632         nframes64_t end = 0;
5633
5634         RegionSelection rs; 
5635
5636         get_regions_for_action (rs);
5637
5638         if (rs.empty()) {
5639                 return;
5640         }
5641
5642         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5643                 if ((*i)->region()->position() < start) {
5644                         start = (*i)->region()->position();
5645                 }
5646                 if ((*i)->region()->last_frame() + 1 > end) {
5647                         end = (*i)->region()->last_frame() + 1;
5648                 }
5649         }
5650
5651         set_loop_range (start, end, _("set loop range from region"));
5652
5653         if (play) {
5654                 session->request_play_loop (true);
5655                 session->request_locate (start, true);
5656         }
5657 }
5658
5659 void
5660 Editor::set_punch_from_selection ()
5661 {
5662         if (session == 0 || selection->time.empty()) {
5663                 return;
5664         }
5665
5666         nframes64_t start = selection->time[clicked_selection].start;
5667         nframes64_t end = selection->time[clicked_selection].end;
5668         
5669         set_punch_range (start, end,  _("set punch range from selection"));
5670 }
5671
5672 void
5673 Editor::set_punch_from_edit_range ()
5674 {
5675         if (session == 0) {
5676                 return;
5677         }
5678
5679         nframes64_t start;
5680         nframes64_t end;
5681         
5682         if (!get_edit_op_range (start, end)) {
5683                 return;
5684         }
5685
5686         set_punch_range (start, end,  _("set punch range from edit range"));
5687 }
5688
5689 void
5690 Editor::set_punch_from_region ()
5691 {
5692         nframes64_t start = max_frames;
5693         nframes64_t end = 0;
5694
5695         RegionSelection rs; 
5696
5697         get_regions_for_action (rs);
5698
5699         if (rs.empty()) {
5700                 return;
5701         }
5702
5703         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5704                 if ((*i)->region()->position() < start) {
5705                         start = (*i)->region()->position();
5706                 }
5707                 if ((*i)->region()->last_frame() + 1 > end) {
5708                         end = (*i)->region()->last_frame() + 1;
5709                 }
5710         }
5711
5712         set_punch_range (start, end, _("set punch range from region"));
5713 }
5714
5715 void
5716 Editor::pitch_shift_regions ()
5717 {
5718         RegionSelection rs; 
5719
5720         get_regions_for_action (rs);
5721         
5722         if (rs.empty()) {
5723                 return;
5724         }
5725
5726         pitch_shift (rs, 1.2);
5727 }
5728         
5729 void
5730 Editor::use_region_as_bar ()
5731 {
5732         if (!session) {
5733                 return;
5734         }
5735
5736         RegionSelection rs; 
5737
5738         get_regions_for_action (rs);
5739
5740         if (rs.empty()) {
5741                 return;
5742         }
5743
5744         RegionView* rv = rs.front();
5745
5746         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5747 }
5748
5749 void
5750 Editor::use_range_as_bar ()
5751 {
5752         nframes64_t start, end;
5753         if (get_edit_op_range (start, end)) {
5754                 define_one_bar (start, end);
5755         }
5756 }
5757
5758 void
5759 Editor::define_one_bar (nframes64_t start, nframes64_t end)
5760 {
5761         nframes64_t length = end - start;
5762         
5763         const Meter& m (session->tempo_map().meter_at (start));
5764
5765         /* length = 1 bar */
5766
5767         /* now we want frames per beat.
5768            we have frames per bar, and beats per bar, so ...
5769         */
5770
5771         double frames_per_beat = length / m.beats_per_bar();
5772         
5773         /* beats per minute = */
5774
5775         double beats_per_minute = (session->frame_rate() * 60.0) / frames_per_beat;
5776
5777         /* now decide whether to:
5778
5779             (a) set global tempo 
5780             (b) add a new tempo marker
5781
5782         */
5783
5784         const TempoSection& t (session->tempo_map().tempo_section_at (start));
5785
5786         bool do_global = false;
5787
5788         if ((session->tempo_map().n_tempos() == 1) && (session->tempo_map().n_meters() == 1)) {
5789                 
5790                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5791                    at the start, or create a new marker
5792                 */
5793
5794                 vector<string> options;
5795                 options.push_back (_("Cancel"));
5796                 options.push_back (_("Add new marker"));
5797                 options.push_back (_("Set global tempo"));
5798                 Choice c (_("Do you want to set the global tempo or add new tempo marker?"),
5799                           options);
5800                 c.set_default_response (2);
5801
5802                 switch (c.run()) {
5803                 case 0:
5804                         return;
5805
5806                 case 2:
5807                         do_global = true;
5808                         break;
5809
5810                 default:
5811                         do_global = false;
5812                 }
5813
5814         } else {
5815
5816                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
5817                    if the marker is at the region starter, change it, otherwise add
5818                    a new tempo marker 
5819                 */
5820         }
5821
5822         begin_reversible_command (_("set tempo from region"));
5823         XMLNode& before (session->tempo_map().get_state());
5824
5825         if (do_global) {
5826                 session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
5827         } else if (t.frame() == start) {
5828                 session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
5829         } else {
5830                 session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), start);
5831         }
5832
5833         XMLNode& after (session->tempo_map().get_state());
5834
5835         session->add_command (new MementoCommand<TempoMap>(session->tempo_map(), &before, &after));
5836         commit_reversible_command ();
5837 }
5838
5839 void
5840 Editor::split_region_at_transients ()
5841 {
5842         AnalysisFeatureList positions;
5843
5844         if (!session) {
5845                 return;
5846         }
5847
5848         RegionSelection rs; 
5849
5850         get_regions_for_action (rs);
5851
5852         if (rs.empty()) {
5853                 return;
5854         }
5855
5856         session->begin_reversible_command (_("split regions"));
5857
5858         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
5859
5860                 RegionSelection::iterator tmp;
5861
5862                 tmp = i;
5863                 ++tmp;
5864
5865                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
5866                 
5867                 if (ar && (ar->get_transients (positions) == 0)) {
5868                         split_region_at_points ((*i)->region(), positions, true);
5869                         positions.clear ();
5870                 }
5871                 
5872                 i = tmp;
5873         }
5874
5875         session->commit_reversible_command ();
5876
5877 }
5878
5879 void
5880 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret)
5881 {
5882         bool use_rhythmic_rodent = false;
5883
5884         boost::shared_ptr<Playlist> pl = r->playlist();
5885         
5886         if (!pl) {
5887                 return;
5888         }
5889         
5890         if (positions.empty()) {
5891                 return;
5892         }
5893
5894
5895         if (positions.size() > 20) {
5896                 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);
5897                 MessageDialog msg (msgstr,
5898                                    false,
5899                                    Gtk::MESSAGE_INFO,
5900                                    Gtk::BUTTONS_OK_CANCEL);
5901
5902                 if (can_ferret) {
5903                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
5904                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
5905                 } else {
5906                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
5907                 }
5908
5909                 msg.set_title (_("Excessive split?"));
5910                 msg.present ();
5911
5912                 int response = msg.run();
5913                 msg.hide ();
5914                 switch (response) {
5915                 case RESPONSE_OK:
5916                         break;
5917                 case RESPONSE_APPLY:
5918                         use_rhythmic_rodent = true;
5919                         break;
5920                 default:
5921                         return;
5922                 }
5923         }
5924         
5925         if (use_rhythmic_rodent) {
5926                 show_rhythm_ferret ();
5927                 return;
5928         }
5929
5930         AnalysisFeatureList::const_iterator x;  
5931         
5932         nframes64_t pos = r->position();
5933
5934         XMLNode& before (pl->get_state());
5935         
5936         x = positions.begin();
5937         
5938         while (x != positions.end()) {
5939                 if ((*x) > pos) {
5940                         break;
5941                 }
5942                 ++x;
5943         }
5944         
5945         if (x == positions.end()) {
5946                 return;
5947         }
5948         
5949         pl->freeze ();
5950         pl->remove_region (r);
5951         
5952         while (x != positions.end()) {
5953                 
5954                 /* file start = original start + how far we from the initial position ? 
5955                  */
5956                 
5957                 nframes64_t file_start = r->start() + (pos - r->position());
5958
5959                 /* length = next position - current position
5960                  */
5961                 
5962                 nframes64_t len = (*x) - pos;
5963
5964                 /* XXX we do we really want to allow even single-sample regions?
5965                    shouldn't we have some kind of lower limit on region size?
5966                 */
5967
5968                 if (len <= 0) {
5969                         break;
5970                 }
5971                 
5972                 string new_name;
5973                 
5974                 if (session->region_name (new_name, r->name())) {
5975                         break;
5976                 }
5977                 
5978                 /* do NOT announce new regions 1 by one, just wait till they are all done */
5979
5980                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), file_start, len, new_name, 0, Region::DefaultFlags, false);
5981                 pl->add_region (nr, pos);
5982
5983                 pos += len;
5984                 ++x;
5985
5986                 if (*x > r->last_frame()) {
5987
5988                         /* add final fragment */
5989                         
5990                         file_start = r->start() + (pos - r->position());
5991                         len = r->last_frame() - pos;
5992
5993                         nr = RegionFactory::create (r->sources(), file_start, len, new_name, 0, Region::DefaultFlags);
5994                         pl->add_region (nr, pos);
5995
5996                         break;
5997                 }
5998         } 
5999
6000         pl->thaw ();
6001
6002         XMLNode& after (pl->get_state());
6003         
6004         session->add_command (new MementoCommand<Playlist>(*pl, &before, &after));
6005 }
6006
6007 void
6008 Editor::tab_to_transient (bool forward)
6009 {
6010         AnalysisFeatureList positions;
6011
6012         if (!session) {
6013                 return;
6014         }
6015
6016         nframes64_t pos = session->audible_frame ();
6017
6018         if (!selection->tracks.empty()) {
6019
6020                 for (TrackSelection::iterator t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
6021
6022                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6023
6024                         if (rtv) {
6025                                 boost::shared_ptr<Diskstream> ds = rtv->get_diskstream();
6026                                 if (ds) {
6027                                         boost::shared_ptr<Playlist> pl = rtv->get_diskstream()->playlist ();
6028                                         if (pl) {
6029                                                 nframes64_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6030                                                 
6031                                                 if (result >= 0) {
6032                                                         positions.push_back (result);
6033                                                 }
6034                                         }
6035                                 }
6036                         }
6037                 }
6038
6039         } else {
6040                 
6041                 RegionSelection rs; 
6042
6043                 get_regions_for_action (rs);
6044         
6045                 if (rs.empty()) {
6046                         return;
6047                 }
6048                 
6049                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6050                         (*r)->region()->get_transients (positions);
6051                 }
6052         }
6053
6054         TransientDetector::cleanup_transients (positions, session->frame_rate(), 3.0);
6055
6056         if (forward) {
6057                 AnalysisFeatureList::iterator x;
6058
6059                 for (x = positions.begin(); x != positions.end(); ++x) {
6060                         if ((*x) > pos) {
6061                                 break;
6062                         }
6063                 }
6064
6065                 if (x != positions.end ()) {
6066                         session->request_locate (*x);
6067                 }
6068
6069         } else {
6070                 AnalysisFeatureList::reverse_iterator x;
6071
6072                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6073                         if ((*x) < pos) {
6074                                 break;
6075                         }
6076                 }
6077
6078                 if (x != positions.rend ()) {
6079                         session->request_locate (*x);
6080                 }
6081         }
6082 }
6083 void
6084 Editor::playhead_forward_to_grid ()
6085 {
6086         if (!session) return;
6087         nframes64_t pos = playhead_cursor->current_frame;
6088         if (pos < max_frames - 1) {
6089                 pos += 2;
6090                 snap_to_internal (pos, 1, false);
6091                 session->request_locate (pos);
6092         }
6093 }
6094
6095
6096 void
6097 Editor::playhead_backward_to_grid ()
6098 {
6099         if (!session) return;
6100         nframes64_t pos = playhead_cursor->current_frame;
6101         if (pos > 2) {
6102                 pos -= 2;
6103                 snap_to_internal (pos, -1, false);
6104                 session->request_locate (pos);
6105         }
6106 }
6107
6108 void
6109 Editor::set_track_height (uint32_t h)
6110 {
6111         TrackSelection& ts (selection->tracks);
6112
6113         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6114                 (*x)->set_height (h);
6115         }
6116 }
6117
6118 void
6119 Editor::toggle_tracks_active ()
6120 {
6121         TrackSelection& ts (selection->tracks);
6122         bool first = true;
6123         bool target = false;
6124
6125         if (ts.empty()) {
6126                 return;
6127         }
6128
6129         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6130                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6131
6132                 if (rtv) {
6133                         if (first) {
6134                                 target = !rtv->_route->active();
6135                                 first = false;
6136                         }
6137                         rtv->_route->set_active (target);
6138                 }
6139         }
6140 }
6141
6142 void
6143 Editor::remove_tracks ()
6144 {
6145         TrackSelection& ts (selection->tracks);
6146
6147         if (ts.empty()) {
6148                 return;
6149         }
6150
6151         vector<string> choices;
6152         string prompt;
6153         int ntracks = 0;
6154         int nbusses = 0;
6155         const char* trackstr;
6156         const char* busstr;
6157         vector<boost::shared_ptr<Route> > routes;
6158
6159         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6160                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6161                 if (rtv) {
6162                         if (rtv->is_track()) {
6163                                 ntracks++;
6164                         } else {
6165                                 nbusses++;
6166                         }
6167                 }
6168                 routes.push_back (rtv->_route);
6169         }
6170         
6171         if (ntracks + nbusses == 0) {
6172                 return;
6173         }
6174
6175         if (ntracks > 1) {
6176                 trackstr = _("tracks");
6177         } else {
6178                 trackstr = _("track");
6179         }
6180
6181         if (nbusses > 1) {
6182                 busstr = _("busses");
6183         } else {
6184                 busstr = _("bus");
6185         }
6186
6187         if (ntracks) {
6188                 if (nbusses) {
6189                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6190                                                     "(You may also lose the playlists associated with the %2)\n\n"
6191                                                     "This action cannot be undone!"),
6192                                                   ntracks, trackstr, nbusses, busstr);
6193                 } else {
6194                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6195                                                     "(You may also lose the playlists associated with the %2)\n\n"
6196                                                     "This action cannot be undone!"),
6197                                                   ntracks, trackstr);
6198                 }
6199         } else if (nbusses) {
6200                 prompt  = string_compose (_("Do you really want to remove %1 %2?"),
6201                                           nbusses, busstr);
6202         }
6203
6204         choices.push_back (_("No, do nothing."));
6205         if (ntracks + nbusses > 1) {
6206                 choices.push_back (_("Yes, remove them."));
6207         } else {
6208                 choices.push_back (_("Yes, remove it."));
6209         }
6210
6211         Choice prompter (prompt, choices);
6212
6213         if (prompter.run () != 1) {
6214                 return;
6215         }
6216
6217         for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6218                 session->remove_route (*x);
6219         }
6220 }
6221
6222 void
6223 Editor::do_insert_time ()
6224 {
6225         if (selection->tracks.empty()) {
6226                 return;
6227         }
6228
6229         ArdourDialog d (*this, _("Insert Time"));
6230
6231         nframes64_t const pos = get_preferred_edit_position ();
6232         
6233         d.get_vbox()->set_border_width (12);
6234         d.get_vbox()->set_spacing (4);
6235
6236         Table table (2, 2);
6237         table.set_spacings (4);
6238
6239         Label time_label (_("Time to insert:"));
6240         time_label.set_alignment (1, 0.5);
6241         table.attach (time_label, 0, 1, 0, 1, FILL | EXPAND);
6242         AudioClock clock ("insertTimeClock", true, X_("InsertTimeClock"), true, true, true);
6243         clock.set (0);
6244         clock.set_session (session);
6245         clock.set_bbt_reference (pos);  
6246         table.attach (clock, 1, 2, 0, 1);
6247
6248         Label intersected_label (_("Intersected regions should:"));
6249         intersected_label.set_alignment (1, 0.5);
6250         table.attach (intersected_label, 0, 1, 1, 2, FILL | EXPAND);
6251         ComboBoxText intersected_combo;
6252         intersected_combo.append_text (_("stay in position"));
6253         intersected_combo.append_text (_("move"));
6254         intersected_combo.append_text (_("be split"));
6255         intersected_combo.set_active (0);
6256         table.attach (intersected_combo, 1, 2, 1, 2);
6257
6258         d.get_vbox()->pack_start (table);
6259
6260         CheckButton move_glued (_("Move glued regions"));
6261         d.get_vbox()->pack_start (move_glued);
6262         CheckButton move_markers (_("Move markers"));
6263         d.get_vbox()->pack_start (move_markers);
6264         CheckButton move_tempos (_("Move tempo and meter changes"));
6265         d.get_vbox()->pack_start (move_tempos);
6266         
6267         d.add_button (Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
6268         d.add_button (_("Insert time"), Gtk::RESPONSE_OK);
6269         d.show_all ();
6270
6271         int response = d.run ();
6272
6273         if (response != RESPONSE_OK) {
6274                 return;
6275         }
6276
6277         nframes64_t distance = clock.current_duration (pos);
6278
6279         if (distance == 0) {
6280                 return;
6281         }
6282
6283         InsertTimeOption opt;
6284
6285         switch (intersected_combo.get_active_row_number ()) {
6286         case 0:
6287                 opt = LeaveIntersected;
6288                 break;
6289         case 1:
6290                 opt = MoveIntersected;
6291                 break;
6292         case 2:
6293                 opt = SplitIntersected;
6294                 break;
6295         }
6296
6297         insert_time (pos, distance, opt, move_glued.get_active(), move_markers.get_active(), move_tempos.get_active());
6298 }
6299
6300 void
6301 Editor::insert_time (nframes64_t pos, nframes64_t frames, InsertTimeOption opt, 
6302                      bool ignore_music_glue, bool markers_too, bool tempo_too)
6303 {
6304         bool commit = false;
6305
6306         if (Config->get_edit_mode() == Lock) {
6307                 return;
6308         }
6309
6310         begin_reversible_command (_("insert time"));
6311
6312         for (TrackSelection::iterator x = selection->tracks.begin(); x != selection->tracks.end(); ++x) {
6313                 /* regions */
6314                 boost::shared_ptr<Playlist> pl = (*x)->playlist();
6315                 
6316                 if (pl) {
6317
6318                         XMLNode &before = pl->get_state();
6319                         
6320                         if (opt == SplitIntersected) {
6321                                 pl->split (pos);
6322                         }
6323                         
6324                         pl->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6325                         
6326                         XMLNode &after = pl->get_state();
6327                         
6328                         session->add_command (new MementoCommand<Playlist> (*pl, &before, &after));
6329                         commit = true;
6330                 }
6331                         
6332                 /* automation */
6333                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6334                 if (rtav) {
6335                         rtav->route ()->shift (pos, frames);
6336                         commit = true;
6337                 }
6338         }
6339
6340         /* markers */
6341         if (markers_too) {
6342                 bool moved = false;
6343                 XMLNode& before (session->locations()->get_state());
6344                 Locations::LocationList copy (session->locations()->list());
6345
6346                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6347                         
6348                         Locations::LocationList::const_iterator tmp;
6349
6350                         if ((*i)->start() >= pos) {
6351                                 (*i)->set_start ((*i)->start() + frames);
6352                                 if (!(*i)->is_mark()) {
6353                                         (*i)->set_end ((*i)->end() + frames);
6354                                 }
6355                                 moved = true;
6356                         }
6357                 }
6358
6359                 if (moved) {
6360                         XMLNode& after (session->locations()->get_state());
6361                         session->add_command (new MementoCommand<Locations>(*session->locations(), &before, &after));
6362                 }
6363         }
6364
6365         if (tempo_too) {
6366                 session->tempo_map().insert_time (pos, frames);
6367         }
6368
6369         if (commit) {
6370                 commit_reversible_command ();
6371         }
6372 }
6373
6374 void
6375 Editor::fit_selected_tracks ()
6376 {
6377         fit_tracks (selection->tracks);
6378 }
6379
6380 void
6381 Editor::fit_tracks (TrackSelection & tracks)
6382 {
6383         if (tracks.empty()) {
6384                 return;
6385         }
6386
6387         uint32_t child_heights = 0;
6388
6389         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6390
6391                 if (!(*t)->marked_for_display()) {
6392                         continue;
6393                 }
6394
6395                 child_heights += (*t)->effective_height() - (*t)->current_height();
6396         }
6397
6398         uint32_t h = (uint32_t) floor ((_canvas_height - child_heights - canvas_timebars_vsize) / tracks.size());
6399         double first_y_pos = DBL_MAX;
6400
6401         if (h < TimeAxisView::hSmall) {
6402                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6403                 /* too small to be displayed */
6404                 return;
6405         }
6406
6407         undo_visual_stack.push_back (current_visual_state());
6408         
6409         /* operate on all tracks, hide unselected ones that are in the middle of selected ones */
6410         
6411         bool prev_was_selected = false;
6412         bool is_selected = tracks.contains (track_views.front());
6413         bool next_is_selected;
6414
6415         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
6416
6417                 TrackViewList::iterator next;
6418                 
6419                 next = t;
6420                 ++next;
6421                 
6422                 if (next != track_views.end()) {
6423                         next_is_selected = tracks.contains (*next);
6424                 } else {
6425                         next_is_selected = false;
6426                 }
6427
6428                 if (is_selected) {
6429                         (*t)->set_height (h);
6430                         first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6431                 } else {
6432                         if (prev_was_selected && next_is_selected) {
6433                                 hide_track_in_display (**t);
6434                         }
6435                 }
6436
6437                 prev_was_selected = is_selected;
6438                 is_selected = next_is_selected;
6439         }
6440
6441         /* 
6442            set the controls_layout height now, because waiting for its size 
6443            request signal handler will cause the vertical adjustment setting to fail 
6444         */ 
6445
6446         controls_layout.property_height () = full_canvas_height - canvas_timebars_vsize;
6447         vertical_adjustment.set_value (first_y_pos);
6448
6449         redo_visual_stack.push_back (current_visual_state());
6450 }
6451
6452 void
6453 Editor::save_visual_state (uint32_t n)
6454 {
6455         while (visual_states.size() <= n) {
6456                 visual_states.push_back (0);
6457         }
6458
6459         delete visual_states[n];
6460
6461         visual_states[n] = current_visual_state (true);
6462         gdk_beep ();
6463 }
6464
6465 void
6466 Editor::goto_visual_state (uint32_t n)
6467 {
6468         if (visual_states.size() <= n) {
6469                 return;
6470         }
6471
6472         if (visual_states[n] == 0) {
6473                 return;
6474         }
6475
6476         use_visual_state (*visual_states[n]);
6477 }
6478
6479 void
6480 Editor::start_visual_state_op (uint32_t n)
6481 {
6482         cerr << "Start visual op\n";
6483         if (visual_state_op_connection.empty()) {
6484                 visual_state_op_connection = Glib::signal_timeout().connect (bind (mem_fun (*this, &Editor::end_visual_state_op), n), 1000);
6485                 cerr << "\tqueued new timeout\n";
6486         }
6487 }
6488
6489 void
6490 Editor::cancel_visual_state_op (uint32_t n)
6491 {
6492         if (!visual_state_op_connection.empty()) {
6493                 cerr << "cancel visual op, time to goto\n";
6494                 visual_state_op_connection.disconnect();
6495                 goto_visual_state (n);
6496         } else {
6497                 cerr << "cancel visual op, do nothing\n";
6498         }
6499 }
6500
6501 bool
6502 Editor::end_visual_state_op (uint32_t n)
6503 {
6504         visual_state_op_connection.disconnect();
6505         save_visual_state (n);
6506         
6507         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6508         char buf[32];
6509         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6510         pup->set_text (buf);
6511         pup->touch();
6512
6513         return false; // do not call again
6514 }
6515