add set loop/punch from edit-range; don't select track when propagating region list...
[ardour.git] / gtk2_ardour / editor_ops.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <unistd.h>
21
22 #include <cstdlib>
23 #include <cmath>
24 #include <string>
25 #include <map>
26
27 #include <pbd/error.h>
28 #include <pbd/basename.h>
29 #include <pbd/pthread_utils.h>
30 #include <pbd/memento_command.h>
31
32 #include <gtkmm2ext/utils.h>
33 #include <gtkmm2ext/choice.h>
34 #include <gtkmm2ext/window_title.h>
35
36 #include <ardour/audioengine.h>
37 #include <ardour/session.h>
38 #include <ardour/audioplaylist.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audio_diskstream.h>
41 #include <ardour/utils.h>
42 #include <ardour/location.h>
43 #include <ardour/named_selection.h>
44 #include <ardour/audio_track.h>
45 #include <ardour/audioplaylist.h>
46 #include <ardour/region_factory.h>
47 #include <ardour/playlist_factory.h>
48 #include <ardour/reverse.h>
49
50 #include "ardour_ui.h"
51 #include "editor.h"
52 #include "time_axis_view.h"
53 #include "audio_time_axis.h"
54 #include "automation_time_axis.h"
55 #include "streamview.h"
56 #include "audio_region_view.h"
57 #include "rgb_macros.h"
58 #include "selection_templates.h"
59 #include "selection.h"
60 #include "editing.h"
61 #include "gtk-custom-hruler.h"
62 #include "gui_thread.h"
63
64 #include "i18n.h"
65
66 using namespace std;
67 using namespace ARDOUR;
68 using namespace PBD;
69 using namespace sigc;
70 using namespace Gtk;
71 using namespace Gtkmm2ext;
72 using namespace Editing;
73
74 /***********************************************************************
75   Editor operations
76  ***********************************************************************/
77
78 void
79 Editor::undo (uint32_t n)
80 {
81         if (session) {
82                 session->undo (n);
83         }
84 }
85
86 void
87 Editor::redo (uint32_t n)
88 {
89         if (session) {
90                 session->redo (n);
91         }
92 }
93
94 void
95 Editor::split_region ()
96 {
97         split_region_at (get_preferred_edit_position());
98 }
99
100 void
101 Editor::split_region_at (nframes_t where)
102 {
103         split_regions_at (where, selection->regions);
104 }
105
106 void
107 Editor::split_regions_at (nframes_t where, RegionSelection& regions)
108 {
109         if (regions.empty()) {
110                 return;
111         }
112
113         begin_reversible_command (_("split"));
114
115         // if splitting a single region, and snap-to is using
116         // region boundaries, don't pay attention to them
117
118         if (regions.size() == 1) {
119                 switch (snap_type) {
120                 case SnapToRegionStart:
121                 case SnapToRegionSync:
122                 case SnapToRegionEnd:
123                         break;
124                 default:
125                         snap_to (where);
126                 }
127         } else {
128                 snap_to (where);
129         }
130                 
131
132         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
133
134                 RegionSelection::iterator tmp;
135
136                 /* XXX this test needs to be more complicated, to make sure we really
137                    have something to split.
138                 */
139                 
140                 if (!(*a)->region()->covers (where)) {
141                         ++a;
142                         continue;
143                 }
144
145                 tmp = a;
146                 ++tmp;
147
148                 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
149
150                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
151
152                 if (arv) {
153                         _new_regionviews_show_envelope = arv->envelope_visible();
154                 }
155                 
156                 if (pl) {
157                         XMLNode &before = pl->get_state();
158                         pl->split_region ((*a)->region(), where);
159                         XMLNode &after = pl->get_state();
160                         session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
161                 }
162
163                 a = tmp;
164         }
165         
166         commit_reversible_command ();
167         _new_regionviews_show_envelope = false;
168 }
169
170 void
171 Editor::remove_clicked_region ()
172 {
173         if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
174                 return;
175         }
176
177         boost::shared_ptr<Playlist> playlist = clicked_audio_trackview->playlist();
178         
179         begin_reversible_command (_("remove region"));
180         XMLNode &before = playlist->get_state();
181         playlist->remove_region (clicked_regionview->region());
182         XMLNode &after = playlist->get_state();
183         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
184         commit_reversible_command ();
185 }
186
187 void
188 Editor::destroy_clicked_region ()
189 {
190         uint32_t selected = selection->regions.size();
191
192         if (!session || !selected) {
193                 return;
194         }
195
196         vector<string> choices;
197         string prompt;
198         
199         prompt  = string_compose (_(" This is destructive, will possibly delete audio files\n\
200 It cannot be undone\n\
201 Do you really want to destroy %1 ?"),
202                            (selected > 1 ? 
203                             _("these regions") : _("this region")));
204
205         choices.push_back (_("No, do nothing."));
206
207         if (selected > 1) {
208                 choices.push_back (_("Yes, destroy them."));
209         } else {
210                 choices.push_back (_("Yes, destroy it."));
211         }
212
213         Gtkmm2ext::Choice prompter (prompt, choices);
214         
215         if (prompter.run() == 0) { /* first choice */
216                 return;
217         }
218
219         if (selected) {
220                 list<boost::shared_ptr<Region> > r;
221
222                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
223                         r.push_back ((*i)->region());
224                 }
225
226                 session->destroy_regions (r);
227         } 
228 }
229
230 boost::shared_ptr<Region>
231 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
232 {
233         RegionView* rv;
234         boost::shared_ptr<Region> region;
235         nframes_t start = 0;
236
237         if (selection->time.start () == selection->time.end_frame ()) {
238                 
239                 /* no current selection-> is there a selected regionview? */
240
241                 if (selection->regions.empty()) {
242                         return region;
243                 }
244
245         } 
246
247         if (!selection->regions.empty()) {
248
249                 rv = *(selection->regions.begin());
250                 (*tv) = &rv->get_time_axis_view();
251                 region = rv->region();
252
253         } else if (!selection->tracks.empty()) {
254
255                 (*tv) = selection->tracks.front();
256
257                 RouteTimeAxisView* rtv;
258
259                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
260                         boost::shared_ptr<Playlist> pl;
261                         
262                         if ((pl = rtv->playlist()) == 0) {
263                                 return region;
264                         }
265                         
266                         region = pl->top_region_at (start);
267                 }
268         } 
269         
270         return region;
271 }
272         
273 void
274 Editor::extend_selection_to_end_of_region (bool next)
275 {
276         TimeAxisView *tv;
277         boost::shared_ptr<Region> region;
278         nframes_t start;
279
280         if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
281                 return;
282         }
283
284         if (region && selection->time.start () == selection->time.end_frame ()) {
285                 start = region->position();
286         } else {
287                 start = selection->time.start ();
288         }
289
290         /* Try to leave the selection with the same route if possible */
291
292         if ((tv = selection->time.track) == 0) {
293                 return;
294         }
295
296         begin_reversible_command (_("extend selection"));
297         selection->set (tv, start, region->position() + region->length());
298         commit_reversible_command ();
299 }
300
301 void
302 Editor::extend_selection_to_start_of_region (bool previous)
303 {
304         TimeAxisView *tv;
305         boost::shared_ptr<Region> region;
306         nframes_t end;
307
308         if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
309                 return;
310         }
311
312         if (region && selection->time.start () == selection->time.end_frame ()) {
313                 end = region->position() + region->length();
314         } else {
315                 end = selection->time.end_frame ();
316         }
317
318         /* Try to leave the selection with the same route if possible */
319         
320         if ((tv = selection->time.track) == 0) {
321                 return;
322         }
323
324         begin_reversible_command (_("extend selection"));
325         selection->set (tv, region->position(), end);
326         commit_reversible_command ();
327 }
328
329
330 void
331 Editor::nudge_forward (bool next)
332 {
333         nframes_t distance;
334         nframes_t next_distance;
335
336         if (!session) return;
337         
338         if (!selection->regions.empty()) {
339
340                 begin_reversible_command (_("nudge forward"));
341
342                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
343                         boost::shared_ptr<Region> r ((*i)->region());
344                         
345                         distance = get_nudge_distance (r->position(), next_distance);
346
347                         if (next) {
348                                 distance = next_distance;
349                         }
350
351                         XMLNode &before = r->playlist()->get_state();
352                         r->set_position (r->position() + distance, this);
353                         XMLNode &after = r->playlist()->get_state();
354                         session->add_command (new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
355                 }
356
357                 commit_reversible_command ();
358
359                 
360         } else if (!selection->markers.empty()) {
361
362                 bool ignored;
363                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
364
365                 if (loc) {
366                         distance = get_nudge_distance (loc->start(), next_distance);
367                         loc->set_start (loc->start() + distance);
368                 }
369                 
370         } else {
371                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
372                 session->request_locate (playhead_cursor->current_frame + distance);
373         }
374 }
375                 
376 void
377 Editor::nudge_backward (bool next)
378 {
379         nframes_t distance;
380         nframes_t next_distance;
381
382         if (!session) return;
383         
384         if (!selection->regions.empty()) {
385
386                 begin_reversible_command (_("nudge forward"));
387
388                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
389                         boost::shared_ptr<Region> r ((*i)->region());
390
391                         distance = get_nudge_distance (r->position(), next_distance);
392                         
393                         if (next) {
394                                 distance = next_distance;
395                         }
396
397                         XMLNode &before = r->playlist()->get_state();
398                         
399                         if (r->position() > distance) {
400                                 r->set_position (r->position() - distance, this);
401                         } else {
402                                 r->set_position (0, this);
403                         }
404                         XMLNode &after = r->playlist()->get_state();
405                         session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
406                 }
407
408                 commit_reversible_command ();
409
410         } else {
411
412                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
413
414                 if (playhead_cursor->current_frame > distance) {
415                         session->request_locate (playhead_cursor->current_frame - distance);
416                 } else {
417                         session->goto_start();
418                 }
419         }
420 }
421
422 void
423 Editor::nudge_forward_capture_offset ()
424 {
425         nframes_t distance;
426
427         if (!session) return;
428         
429         if (!selection->regions.empty()) {
430
431                 begin_reversible_command (_("nudge forward"));
432
433                 distance = session->worst_output_latency();
434
435                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
436                         boost::shared_ptr<Region> r ((*i)->region());
437                         
438                         XMLNode &before = r->playlist()->get_state();
439                         r->set_position (r->position() + distance, this);
440                         XMLNode &after = r->playlist()->get_state();
441                         session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
442                 }
443
444                 commit_reversible_command ();
445
446         } 
447 }
448                 
449 void
450 Editor::nudge_backward_capture_offset ()
451 {
452         nframes_t distance;
453
454         if (!session) return;
455         
456         if (!selection->regions.empty()) {
457
458                 begin_reversible_command (_("nudge forward"));
459
460                 distance = session->worst_output_latency();
461
462                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
463                         boost::shared_ptr<Region> r ((*i)->region());
464
465                         XMLNode &before = r->playlist()->get_state();
466                         
467                         if (r->position() > distance) {
468                                 r->set_position (r->position() - distance, this);
469                         } else {
470                                 r->set_position (0, this);
471                         }
472                         XMLNode &after = r->playlist()->get_state();
473                         session->add_command(new MementoCommand<Playlist>(*(r->playlist()), &before, &after));
474                 }
475
476                 commit_reversible_command ();
477         }
478 }
479
480 /* DISPLAY MOTION */
481
482 void
483 Editor::move_to_start ()
484 {
485         session->goto_start ();
486 }
487
488 void
489 Editor::move_to_end ()
490 {
491
492         session->request_locate (session->current_end_frame());
493 }
494
495 void
496 Editor::build_region_boundary_cache ()
497 {
498         nframes_t pos = 0;
499         vector<RegionPoint> interesting_points;
500         boost::shared_ptr<Region> r;
501         TrackViewList tracks;
502         bool at_end = false;
503
504         region_boundary_cache.clear ();
505
506         if (session == 0) {
507                 return;
508         }
509         
510         switch (snap_type) {
511         case SnapToRegionStart:
512                 interesting_points.push_back (Start);
513                 break;
514         case SnapToRegionEnd:
515                 interesting_points.push_back (End);
516                 break;  
517         case SnapToRegionSync:
518                 interesting_points.push_back (SyncPoint);
519                 break;  
520         case SnapToRegionBoundary:
521                 interesting_points.push_back (Start);
522                 interesting_points.push_back (End);
523                 break;  
524         default:
525                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
526                 /*NOTREACHED*/
527                 return;
528         }
529         
530         TimeAxisView *ontrack = 0;
531         TrackViewList tlist;
532
533         if (!selection->tracks.empty()) {
534                 tlist = selection->tracks;
535         } else {
536                 tlist = track_views;
537         }
538
539         while (pos < session->current_end_frame() && !at_end) {
540
541                 nframes_t rpos;
542                 nframes_t lpos = max_frames;
543
544                 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
545
546                         if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
547                                 if (*p == interesting_points.back()) {
548                                         at_end = true;
549                                 }
550                                 /* move to next point type */
551                                 continue;
552                         }
553
554                         switch (*p) {
555                         case Start:
556                                 rpos = r->first_frame();
557                                 break;
558
559                         case End:
560                                 rpos = r->last_frame();
561                                 break;  
562
563                         case SyncPoint:
564                                 rpos = r->adjust_to_sync (r->first_frame());
565                                 break;
566
567                         default:
568                                 break;
569                         }
570                         
571                         float speed = 1.0f;
572                         AudioTimeAxisView *atav;
573                         
574                         if (ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
575                                 if (atav->get_diskstream() != 0) {
576                                         speed = atav->get_diskstream()->speed();
577                                 }
578                         }
579                         
580                         rpos = track_frame_to_session_frame (rpos, speed);
581
582                         if (rpos < lpos) {
583                                 lpos = rpos;
584                         }
585
586                         /* prevent duplicates, but we don't use set<> because we want to be able
587                            to sort later.
588                         */
589
590                         vector<nframes_t>::iterator ri; 
591                         
592                         for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
593                                 if (*ri == rpos) {
594                                         break;
595                                 }
596                         }
597
598                         if (ri == region_boundary_cache.end()) {
599                                 region_boundary_cache.push_back (rpos);
600                         }
601                 }
602
603                 pos = lpos + 1;
604         }
605
606         /* finally sort to be sure that the order is correct */
607
608         sort (region_boundary_cache.begin(), region_boundary_cache.end());
609 }
610
611 boost::shared_ptr<Region>
612 Editor::find_next_region (nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
613 {
614         TrackViewList::iterator i;
615         nframes_t closest = max_frames;
616         boost::shared_ptr<Region> ret;
617         nframes_t rpos = 0;
618
619         float track_speed;
620         nframes_t track_frame;
621         AudioTimeAxisView *atav;
622
623         for (i = tracks.begin(); i != tracks.end(); ++i) {
624
625                 nframes_t distance;
626                 boost::shared_ptr<Region> r;
627                 
628                 track_speed = 1.0f;
629                 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
630                         if (atav->get_diskstream()!=0)
631                                 track_speed = atav->get_diskstream()->speed();
632                 }
633
634                 track_frame = session_frame_to_track_frame(frame, track_speed);
635
636                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
637                         continue;
638                 }
639
640                 switch (point) {
641                 case Start:
642                         rpos = r->first_frame ();
643                         break;
644
645                 case End:
646                         rpos = r->last_frame ();
647                         break;
648
649                 case SyncPoint:
650                         rpos = r->adjust_to_sync (r->first_frame());
651                         break;
652                 }
653
654                 // rpos is a "track frame", converting it to "session frame"
655                 rpos = track_frame_to_session_frame(rpos, track_speed);
656
657                 if (rpos > frame) {
658                         distance = rpos - frame;
659                 } else {
660                         distance = frame - rpos;
661                 }
662
663                 if (distance < closest) {
664                         closest = distance;
665                         if (ontrack != 0)
666                                 *ontrack = (*i);
667                         ret = r;
668                 }
669         }
670
671         return ret;
672 }
673
674 nframes64_t
675 Editor::find_next_region_boundary (nframes64_t pos, int32_t dir, const TrackViewList& tracks)
676 {
677         nframes64_t distance = max_frames;
678         nframes64_t current_nearest = -1;
679
680         for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
681                 nframes64_t contender;
682                 nframes64_t d;
683
684                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
685
686                 if (!rtv) {
687                         continue;
688                 }
689
690                 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
691                         continue;
692                 }
693
694                 d = ::llabs (pos - contender);
695
696                 if (d < distance) {
697                         current_nearest = contender;
698                         distance = d;
699                 }
700         }
701         
702         return current_nearest;
703 }
704
705 void
706 Editor::cursor_to_region_boundary (Cursor* cursor, int32_t dir)
707 {
708         nframes64_t pos = cursor->current_frame;
709         nframes64_t target;
710
711         if (!session) {
712                 return;
713         }
714
715         // so we don't find the current region again..
716         if (dir > 0 || pos > 0) {
717                 pos += dir;
718         }
719
720         if (!selection->tracks.empty()) {
721                 
722                 target = find_next_region_boundary (pos, dir, selection->tracks);
723                 
724         } else {
725                 
726                 target = find_next_region_boundary (pos, dir, track_views);
727         }
728         
729         if (target < 0) {
730                 return;
731         }
732
733
734         if (cursor == playhead_cursor) {
735                 session->request_locate (target);
736         } else {
737                 cursor->set_position (target);
738         }
739 }
740
741 void
742 Editor::cursor_to_next_region_boundary (Cursor* cursor)
743 {
744         cursor_to_region_boundary (cursor, 1);
745 }
746
747 void
748 Editor::cursor_to_previous_region_boundary (Cursor* cursor)
749 {
750         cursor_to_region_boundary (cursor, -1);
751 }
752
753 void
754 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
755 {
756         boost::shared_ptr<Region> r;
757         nframes_t pos = cursor->current_frame;
758
759         if (!session) {
760                 return;
761         }
762
763         TimeAxisView *ontrack = 0;
764
765         // so we don't find the current region again..
766         if (dir>0 || pos>0)
767                 pos+=dir;
768
769         if (!selection->tracks.empty()) {
770                 
771                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
772                 
773         } else if (clicked_trackview) {
774                 
775                 TrackViewList t;
776                 t.push_back (clicked_trackview);
777                 
778                 r = find_next_region (pos, point, dir, t, &ontrack);
779                 
780         } else {
781                 
782                 r = find_next_region (pos, point, dir, track_views, &ontrack);
783         }
784
785         if (r == 0) {
786                 return;
787         }
788         
789         switch (point){
790         case Start:
791                 pos = r->first_frame ();
792                 break;
793
794         case End:
795                 pos = r->last_frame ();
796                 break;
797
798         case SyncPoint:
799                 pos = r->adjust_to_sync (r->first_frame());
800                 break;  
801         }
802         
803         float speed = 1.0f;
804         AudioTimeAxisView *atav;
805
806         if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
807                 if (atav->get_diskstream() != 0) {
808                         speed = atav->get_diskstream()->speed();
809                 }
810         }
811
812         pos = track_frame_to_session_frame(pos, speed);
813         
814         if (cursor == playhead_cursor) {
815                 session->request_locate (pos);
816         } else {
817                 cursor->set_position (pos);
818         }
819 }
820
821 void
822 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
823 {
824         cursor_to_region_point (cursor, point, 1);
825 }
826
827 void
828 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
829 {
830         cursor_to_region_point (cursor, point, -1);
831 }
832
833 void
834 Editor::cursor_to_selection_start (Cursor *cursor)
835 {
836         nframes_t pos = 0;
837         switch (mouse_mode) {
838         case MouseObject:
839                 if (!selection->regions.empty()) {
840                         pos = selection->regions.start();
841                 }
842                 break;
843
844         case MouseRange:
845                 if (!selection->time.empty()) {
846                         pos = selection->time.start ();
847                 }
848                 break;
849
850         default:
851                 return;
852         }
853
854         if (cursor == playhead_cursor) {
855                 session->request_locate (pos);
856         } else {
857                 cursor->set_position (pos);
858         }
859 }
860
861 void
862 Editor::cursor_to_selection_end (Cursor *cursor)
863 {
864         nframes_t pos = 0;
865
866         switch (mouse_mode) {
867         case MouseObject:
868                 if (!selection->regions.empty()) {
869                         pos = selection->regions.end_frame();
870                 }
871                 break;
872
873         case MouseRange:
874                 if (!selection->time.empty()) {
875                         pos = selection->time.end_frame ();
876                 }
877                 break;
878
879         default:
880                 return;
881         }
882
883         if (cursor == playhead_cursor) {
884                 session->request_locate (pos);
885         } else {
886                 cursor->set_position (pos);
887         }
888 }
889
890 void
891 Editor::selected_marker_to_region_boundary (int32_t dir)
892 {
893         nframes64_t target;
894         Location* loc;
895         bool ignored;
896
897         if (!session) {
898                 return;
899         }
900
901         if (selection->markers.empty()) {
902                 nframes64_t mouse;
903                 bool ignored;
904
905                 if (!mouse_frame (mouse, ignored)) {
906                         return;
907                 }
908                 
909                 add_location_mark (mouse);
910         }
911
912         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
913                 return;
914         }
915
916         nframes64_t pos = loc->start();
917
918         // so we don't find the current region again..
919         if (dir > 0 || pos > 0) {
920                 pos += dir;
921         }
922
923         if (!selection->tracks.empty()) {
924                 
925                 target = find_next_region_boundary (pos, dir, selection->tracks);
926                 
927         } else {
928                 
929                 target = find_next_region_boundary (pos, dir, track_views);
930         }
931         
932         if (target < 0) {
933                 return;
934         }
935
936         loc->move_to (target);
937 }
938
939 void
940 Editor::selected_marker_to_next_region_boundary ()
941 {
942         selected_marker_to_region_boundary (1);
943 }
944
945 void
946 Editor::selected_marker_to_previous_region_boundary ()
947 {
948         selected_marker_to_region_boundary (-1);
949 }
950
951 void
952 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
953 {
954         boost::shared_ptr<Region> r;
955         nframes_t pos;
956         Location* loc;
957         bool ignored;
958
959         if (!session || selection->markers.empty()) {
960                 return;
961         }
962
963         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
964                 return;
965         }
966
967         TimeAxisView *ontrack = 0;
968
969         pos = loc->start();
970
971         // so we don't find the current region again..
972         if (dir>0 || pos>0)
973                 pos+=dir;
974
975         if (!selection->tracks.empty()) {
976                 
977                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
978                 
979         } else if (clicked_trackview) {
980                 
981                 TrackViewList t;
982                 t.push_back (clicked_trackview);
983                 
984                 r = find_next_region (pos, point, dir, t, &ontrack);
985                 
986         } else {
987                 
988                 r = find_next_region (pos, point, dir, track_views, &ontrack);
989         }
990
991         if (r == 0) {
992                 return;
993         }
994         
995         switch (point){
996         case Start:
997                 pos = r->first_frame ();
998                 break;
999
1000         case End:
1001                 pos = r->last_frame ();
1002                 break;
1003
1004         case SyncPoint:
1005                 pos = r->adjust_to_sync (r->first_frame());
1006                 break;  
1007         }
1008         
1009         float speed = 1.0f;
1010         AudioTimeAxisView *atav;
1011
1012         if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
1013                 if (atav->get_diskstream() != 0) {
1014                         speed = atav->get_diskstream()->speed();
1015                 }
1016         }
1017
1018         pos = track_frame_to_session_frame(pos, speed);
1019
1020         loc->move_to (pos);
1021 }
1022
1023 void
1024 Editor::selected_marker_to_next_region_point (RegionPoint point)
1025 {
1026         selected_marker_to_region_point (point, 1);
1027 }
1028
1029 void
1030 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1031 {
1032         selected_marker_to_region_point (point, -1);
1033 }
1034
1035 void
1036 Editor::selected_marker_to_selection_start ()
1037 {
1038         nframes_t pos = 0;
1039         Location* loc;
1040         bool ignored;
1041
1042         if (!session || selection->markers.empty()) {
1043                 return;
1044         }
1045
1046         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1047                 return;
1048         }
1049
1050         switch (mouse_mode) {
1051         case MouseObject:
1052                 if (!selection->regions.empty()) {
1053                         pos = selection->regions.start();
1054                 }
1055                 break;
1056
1057         case MouseRange:
1058                 if (!selection->time.empty()) {
1059                         pos = selection->time.start ();
1060                 }
1061                 break;
1062
1063         default:
1064                 return;
1065         }
1066
1067         loc->move_to (pos);
1068 }
1069
1070 void
1071 Editor::selected_marker_to_selection_end ()
1072 {
1073         nframes_t pos = 0;
1074         Location* loc;
1075         bool ignored;
1076
1077         if (!session || selection->markers.empty()) {
1078                 return;
1079         }
1080
1081         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1082                 return;
1083         }
1084
1085         switch (mouse_mode) {
1086         case MouseObject:
1087                 if (!selection->regions.empty()) {
1088                         pos = selection->regions.end_frame();
1089                 }
1090                 break;
1091
1092         case MouseRange:
1093                 if (!selection->time.empty()) {
1094                         pos = selection->time.end_frame ();
1095                 }
1096                 break;
1097
1098         default:
1099                 return;
1100         }
1101
1102         loc->move_to (pos);
1103 }
1104
1105 void
1106 Editor::scroll_playhead (bool forward)
1107 {
1108         nframes_t pos = playhead_cursor->current_frame;
1109         nframes_t delta = (nframes_t) floor (current_page_frames() / 0.8);
1110
1111         if (forward) {
1112                 if (pos == max_frames) {
1113                         return;
1114                 }
1115
1116                 if (pos < max_frames - delta) {
1117                         pos += delta ;
1118                 } else {
1119                         pos = max_frames;
1120                 } 
1121
1122         } else {
1123
1124                 if (pos == 0) {
1125                         return;
1126                 } 
1127
1128                 if (pos > delta) {
1129                         pos -= delta;
1130                 } else {
1131                         pos = 0;
1132                 }
1133         }
1134
1135         session->request_locate (pos);
1136 }
1137
1138 void
1139 Editor::playhead_backward ()
1140 {
1141         nframes_t pos;
1142         nframes_t cnt;
1143         float prefix;
1144         bool was_floating;
1145
1146         if (get_prefix (prefix, was_floating)) {
1147                 cnt = 1;
1148         } else {
1149                 if (was_floating) {
1150                         cnt = (nframes_t) floor (prefix * session->frame_rate ());
1151                 } else {
1152                         cnt = (nframes_t) prefix;
1153                 }
1154         }
1155
1156         pos = playhead_cursor->current_frame;
1157
1158         if ((nframes_t) pos < cnt) {
1159                 pos = 0;
1160         } else {
1161                 pos -= cnt;
1162         }
1163         
1164         /* XXX this is completely insane. with the current buffering
1165            design, we'll force a complete track buffer flush and
1166            reload, just to move 1 sample !!!
1167         */
1168
1169         session->request_locate (pos);
1170 }
1171
1172 void
1173 Editor::playhead_forward ()
1174 {
1175         nframes_t pos;
1176         nframes_t cnt;
1177         bool was_floating;
1178         float prefix;
1179
1180         if (get_prefix (prefix, was_floating)) {
1181                 cnt = 1;
1182         } else {
1183                 if (was_floating) {
1184                         cnt = (nframes_t) floor (prefix * session->frame_rate ());
1185                 } else {
1186                         cnt = (nframes_t) floor (prefix);
1187                 }
1188         }
1189
1190         pos = playhead_cursor->current_frame;
1191         
1192         /* XXX this is completely insane. with the current buffering
1193            design, we'll force a complete track buffer flush and
1194            reload, just to move 1 sample !!!
1195         */
1196
1197         session->request_locate (pos+cnt);
1198 }
1199
1200 void
1201 Editor::cursor_align (bool playhead_to_edit)
1202 {
1203         if (!session) {
1204                 return;
1205         }
1206
1207         if (playhead_to_edit) {
1208
1209                 if (selection->markers.empty()) {
1210                         return;
1211                 }
1212                 
1213                 session->request_locate (selection->markers.front()->position(), session->transport_rolling());
1214         
1215         } else {
1216
1217                 /* move selected markers to playhead */
1218                 
1219                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1220                         bool ignored;
1221                         
1222                         Location* loc = find_location_from_marker (*i, ignored);
1223                         
1224                         if (loc->is_mark()) {
1225                                 loc->set_start (playhead_cursor->current_frame);
1226                         } else {
1227                                 loc->set (playhead_cursor->current_frame,
1228                                           playhead_cursor->current_frame + loc->length());
1229                         }
1230                 }
1231         }
1232 }
1233
1234 void
1235 Editor::edit_cursor_backward ()
1236 {
1237         nframes64_t pos;
1238         nframes64_t cnt;
1239         float prefix;
1240         bool was_floating;
1241
1242         if (get_prefix (prefix, was_floating)) {
1243                 cnt = 1;
1244         } else {
1245                 if (was_floating) {
1246                         cnt = (nframes_t) floor (prefix * session->frame_rate ());
1247                 } else {
1248                         cnt = (nframes_t) prefix;
1249                 }
1250         }
1251
1252         if ((pos = get_preferred_edit_position()) < 0) {
1253                 return;
1254         }
1255
1256         if (pos < cnt) {
1257                 pos = 0;
1258         } else {
1259                 pos -= cnt;
1260         }
1261         
1262         // EDIT CURSOR edit_cursor->set_position (pos);
1263 }
1264
1265 void
1266 Editor::edit_cursor_forward ()
1267 {
1268         //nframes_t pos;
1269         nframes_t cnt;
1270         bool was_floating;
1271         float prefix;
1272
1273         if (get_prefix (prefix, was_floating)) {
1274                 cnt = 1;
1275         } else {
1276                 if (was_floating) {
1277                         cnt = (nframes_t) floor (prefix * session->frame_rate ());
1278                 } else {
1279                         cnt = (nframes_t) floor (prefix);
1280                 }
1281         }
1282
1283         // pos = edit_cursor->current_frame;
1284         // EDIT CURSOR edit_cursor->set_position (pos+cnt);
1285 }
1286
1287 void
1288 Editor::goto_frame ()
1289 {
1290         float prefix;
1291         bool was_floating;
1292         nframes_t frame;
1293
1294         if (get_prefix (prefix, was_floating)) {
1295                 return;
1296         }
1297
1298         if (was_floating) {
1299                 frame = (nframes_t) floor (prefix * session->frame_rate());
1300         } else {
1301                 frame = (nframes_t) floor (prefix);
1302         }
1303
1304         session->request_locate (frame);
1305 }
1306
1307 void
1308 Editor::scroll_backward (float pages)
1309 {
1310         nframes_t frame;
1311         nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1312         bool was_floating;
1313         float prefix;
1314         nframes_t cnt;
1315         
1316         if (get_prefix (prefix, was_floating)) {
1317                 cnt = (nframes_t) floor (pages * one_page);
1318         } else {
1319                 if (was_floating) {
1320                         cnt = (nframes_t) floor (prefix * session->frame_rate());
1321                 } else {
1322                         cnt = (nframes_t) floor (prefix * one_page);
1323                 }
1324         }
1325
1326         if (leftmost_frame < cnt) {
1327                 frame = 0;
1328         } else {
1329                 frame = leftmost_frame - cnt;
1330         }
1331
1332         reset_x_origin (frame);
1333 }
1334
1335 void
1336 Editor::scroll_forward (float pages)
1337 {
1338         nframes_t frame;
1339         nframes_t one_page = (nframes_t) rint (canvas_width * frames_per_unit);
1340         bool was_floating;
1341         float prefix;
1342         nframes_t cnt;
1343         
1344         if (get_prefix (prefix, was_floating)) {
1345                 cnt = (nframes_t) floor (pages * one_page);
1346         } else {
1347                 if (was_floating) {
1348                         cnt = (nframes_t) floor (prefix * session->frame_rate());
1349                 } else {
1350                         cnt = (nframes_t) floor (prefix * one_page);
1351                 }
1352         }
1353
1354         if (max_frames - cnt < leftmost_frame) {
1355                 frame = max_frames - cnt;
1356         } else {
1357                 frame = leftmost_frame + cnt;
1358         }
1359
1360         reset_x_origin (frame);
1361 }
1362
1363 void
1364 Editor::scroll_tracks_down ()
1365 {
1366         float prefix;
1367         bool was_floating;
1368         int cnt;
1369
1370         if (get_prefix (prefix, was_floating)) {
1371                 cnt = 1;
1372         } else {
1373                 cnt = (int) floor (prefix);
1374         }
1375
1376         double vert_value = vertical_adjustment.get_value() + (cnt *
1377                 vertical_adjustment.get_page_size());
1378         if (vert_value > vertical_adjustment.get_upper() - canvas_height) {
1379                 vert_value = vertical_adjustment.get_upper() - canvas_height;
1380         }
1381         vertical_adjustment.set_value (vert_value);
1382 }
1383
1384 void
1385 Editor::scroll_tracks_up ()
1386 {
1387         float prefix;
1388         bool was_floating;
1389         int cnt;
1390
1391         if (get_prefix (prefix, was_floating)) {
1392                 cnt = 1;
1393         } else {
1394                 cnt = (int) floor (prefix);
1395         }
1396
1397         vertical_adjustment.set_value (vertical_adjustment.get_value() - (cnt * vertical_adjustment.get_page_size()));
1398 }
1399
1400 void
1401 Editor::scroll_tracks_down_line ()
1402 {
1403
1404         Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1405         double vert_value = adj->get_value() + 20;
1406
1407         if (vert_value>adj->get_upper() - canvas_height) {
1408                 vert_value = adj->get_upper() - canvas_height;
1409         }
1410         adj->set_value (vert_value);
1411 }
1412
1413 void
1414 Editor::scroll_tracks_up_line ()
1415 {
1416         Gtk::Adjustment* adj = edit_vscrollbar.get_adjustment();
1417         adj->set_value (adj->get_value() - 20);
1418 }
1419
1420 /* ZOOM */
1421
1422 void
1423 Editor::temporal_zoom_step (bool coarser)
1424 {
1425         ENSURE_GUI_THREAD (bind (mem_fun (*this, &Editor::temporal_zoom_step), coarser));
1426
1427         double nfpu;
1428
1429         nfpu = frames_per_unit;
1430         
1431         if (coarser) { 
1432                 nfpu *= 1.61803399;
1433         } else { 
1434                 nfpu = max(1.0,(nfpu/1.61803399));
1435         }
1436
1437         temporal_zoom (nfpu);
1438 }       
1439
1440 void
1441 Editor::temporal_zoom (gdouble fpu)
1442 {
1443         if (!session) return;
1444         
1445         nframes64_t current_page = current_page_frames();
1446         nframes64_t current_leftmost = leftmost_frame;
1447         nframes64_t current_rightmost;
1448         nframes64_t current_center;
1449         nframes64_t new_page;
1450         nframes64_t leftmost_after_zoom = 0;
1451         nframes64_t where;
1452         bool in_track_canvas;
1453         double nfpu;
1454
1455         nfpu = fpu;
1456         
1457         new_page = (nframes_t) floor (canvas_width * nfpu);
1458
1459         switch (zoom_focus) {
1460         case ZoomFocusLeft:
1461                 leftmost_after_zoom = current_leftmost;
1462                 break;
1463                 
1464         case ZoomFocusRight:
1465                 current_rightmost = leftmost_frame + current_page;
1466                 if (current_rightmost > new_page) {
1467                         leftmost_after_zoom = current_rightmost - new_page;
1468                 } else {
1469                         leftmost_after_zoom = 0;
1470                 }
1471                 break;
1472                 
1473         case ZoomFocusCenter:
1474                 current_center = current_leftmost + (current_page/2); 
1475                 if (current_center > (new_page/2)) {
1476                         leftmost_after_zoom = current_center - (new_page / 2);
1477                 } else {
1478                         leftmost_after_zoom = 0;
1479                 }
1480                 break;
1481                 
1482         case ZoomFocusPlayhead:
1483                 /* try to keep the playhead in the center */
1484                 if (playhead_cursor->current_frame > new_page/2) {
1485                         leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1486                 } else {
1487                         leftmost_after_zoom = 0;
1488                 }
1489                 break;
1490
1491         case ZoomFocusMouse:
1492                 /* try to keep the mouse over the same point in the display */
1493
1494                 if (!mouse_frame (where, in_track_canvas)) {
1495                         /* use playhead instead */
1496                         where = playhead_cursor->current_frame;
1497
1498                         if (where > new_page/2) {
1499                                 leftmost_after_zoom = where - (new_page/2);
1500                         } else {
1501                                 leftmost_after_zoom = 0;
1502                         }
1503
1504                 } else {
1505
1506                         double l = - ((new_page * ((where - current_leftmost)/(double)current_page)) - where);
1507
1508                         if (l < 0) {
1509                                 leftmost_after_zoom = 0;
1510                         } else if (l > max_frames) { 
1511                                 leftmost_after_zoom = max_frames - new_page;
1512                         } else {
1513                                 leftmost_after_zoom = (nframes64_t) l;
1514                         }
1515                 }
1516
1517                 break;
1518
1519         case ZoomFocusEdit:
1520                 /* try to keep the edit point in the center */
1521                 if (get_preferred_edit_position() > new_page/2) {
1522                         leftmost_after_zoom = get_preferred_edit_position() - (new_page/2);
1523                 } else {
1524                         leftmost_after_zoom = 0;
1525                 }
1526                 break;
1527                 
1528         }
1529  
1530         // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1531
1532 //      begin_reversible_command (_("zoom"));
1533 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1534 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1535 //      commit_reversible_command ();
1536         
1537         // cerr << "repos & zoom to " << leftmost_after_zoom << " @ " << nfpu << endl;
1538
1539         reposition_and_zoom (leftmost_after_zoom, nfpu);
1540 }       
1541
1542 void
1543 Editor::temporal_zoom_selection ()
1544 {
1545         if (!selection) return;
1546         
1547         if (selection->time.empty()) {
1548                 return;
1549         }
1550
1551         nframes_t start = selection->time[clicked_selection].start;
1552         nframes_t end = selection->time[clicked_selection].end;
1553
1554         temporal_zoom_by_frame (start, end, "zoom to selection");
1555 }
1556
1557 void
1558 Editor::temporal_zoom_session ()
1559 {
1560         ENSURE_GUI_THREAD (mem_fun (*this, &Editor::temporal_zoom_session));
1561
1562         if (session) {
1563                 temporal_zoom_by_frame (session->current_start_frame(), session->current_end_frame(), "zoom to session");
1564         }
1565 }
1566
1567 void
1568 Editor::temporal_zoom_by_frame (nframes_t start, nframes_t end, const string & op)
1569 {
1570         if (!session) return;
1571
1572         if ((start == 0 && end == 0) || end < start) {
1573                 return;
1574         }
1575
1576         nframes_t range = end - start;
1577
1578         double new_fpu = (double)range / (double)canvas_width;
1579 //      double p2 = 1.0;
1580
1581 //      while (p2 < new_fpu) {
1582 //              p2 *= 2.0;
1583 //      }
1584 //      new_fpu = p2;
1585         
1586         nframes_t new_page = (nframes_t) floor (canvas_width * new_fpu);
1587         nframes_t middle = (nframes_t) floor( (double)start + ((double)range / 2.0f ));
1588         nframes_t new_leftmost = (nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1589
1590         if (new_leftmost > middle) new_leftmost = 0;
1591
1592 //      begin_reversible_command (op);
1593 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1594 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1595 //      commit_reversible_command ();
1596
1597         reposition_and_zoom (new_leftmost, new_fpu);
1598 }
1599
1600 void 
1601 Editor::temporal_zoom_to_frame (bool coarser, nframes_t frame)
1602 {
1603         if (!session) return;
1604         
1605         double range_before = frame - leftmost_frame;
1606         double new_fpu;
1607         
1608         new_fpu = frames_per_unit;
1609         
1610         if (coarser) { 
1611                 new_fpu *= 1.61803399;
1612                 range_before *= 1.61803399;
1613         } else { 
1614                 new_fpu = max(1.0,(new_fpu/1.61803399));
1615                 range_before /= 1.61803399;
1616         }
1617
1618         if (new_fpu == frames_per_unit) return;
1619
1620         nframes_t new_leftmost = frame - (nframes_t)range_before;
1621
1622         if (new_leftmost > frame) new_leftmost = 0;
1623
1624 //      begin_reversible_command (_("zoom to frame"));
1625 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1626 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1627 //      commit_reversible_command ();
1628
1629         reposition_and_zoom (new_leftmost, new_fpu);
1630 }
1631
1632 void
1633 Editor::add_location_from_selection ()
1634 {
1635         string rangename;
1636
1637         if (selection->time.empty()) {
1638                 return;
1639         }
1640
1641         if (session == 0 || clicked_trackview == 0) {
1642                 return;
1643         }
1644
1645         nframes_t start = selection->time[clicked_selection].start;
1646         nframes_t end = selection->time[clicked_selection].end;
1647
1648         session->locations()->next_available_name(rangename,"selection");
1649         Location *location = new Location (start, end, rangename, Location::IsRangeMarker);
1650
1651         session->begin_reversible_command (_("add marker"));
1652         XMLNode &before = session->locations()->get_state();
1653         session->locations()->add (location, true);
1654         XMLNode &after = session->locations()->get_state();
1655         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1656         session->commit_reversible_command ();
1657 }
1658
1659 void
1660 Editor::add_location_mark (nframes64_t where)
1661 {
1662         string markername;
1663
1664         select_new_marker = true;
1665
1666         session->locations()->next_available_name(markername,"mark");
1667         Location *location = new Location (where, where, markername, Location::IsMark);
1668         session->begin_reversible_command (_("add marker"));
1669         XMLNode &before = session->locations()->get_state();
1670         session->locations()->add (location, true);
1671         XMLNode &after = session->locations()->get_state();
1672         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1673         session->commit_reversible_command ();
1674 }
1675
1676 void
1677 Editor::add_location_from_playhead_cursor ()
1678 {
1679         add_location_mark (session->audible_frame());
1680 }
1681
1682 void
1683 Editor::add_location_from_audio_region ()
1684 {
1685         if (selection->regions.empty()) {
1686                 return;
1687         }
1688
1689         RegionView* rv = *(selection->regions.begin());
1690         boost::shared_ptr<Region> region = rv->region();
1691         
1692         Location *location = new Location (region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
1693         session->begin_reversible_command (_("add marker"));
1694         XMLNode &before = session->locations()->get_state();
1695         session->locations()->add (location, true);
1696         XMLNode &after = session->locations()->get_state();
1697         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1698         session->commit_reversible_command ();
1699 }
1700
1701 void
1702 Editor::amplitude_zoom_step (bool in)
1703 {
1704         gdouble zoom = 1.0;
1705
1706         if (in) {
1707                 zoom *= 2.0;
1708         } else {
1709                 if (zoom > 2.0) {
1710                         zoom /= 2.0;
1711                 } else {
1712                         zoom = 1.0;
1713                 }
1714         }
1715
1716 #ifdef FIX_FOR_CANVAS
1717         /* XXX DO SOMETHING */
1718 #endif
1719 }       
1720
1721
1722 /* DELETION */
1723
1724
1725 void
1726 Editor::delete_sample_forward ()
1727 {
1728 }
1729
1730 void
1731 Editor::delete_sample_backward ()
1732 {
1733 }
1734
1735 void
1736 Editor::delete_screen ()
1737 {
1738 }
1739
1740 /* SEARCH */
1741
1742 void
1743 Editor::search_backwards ()
1744 {
1745         /* what ? */
1746 }
1747
1748 void
1749 Editor::search_forwards ()
1750 {
1751         /* what ? */
1752 }
1753
1754 /* MARKS */
1755
1756 void
1757 Editor::jump_forward_to_mark ()
1758 {
1759         if (!session) {
1760                 return;
1761         }
1762         
1763         Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1764
1765         if (location) {
1766                 session->request_locate (location->start(), session->transport_rolling());
1767         } else {
1768                 session->request_locate (session->current_end_frame());
1769         }
1770 }
1771
1772 void
1773 Editor::jump_backward_to_mark ()
1774 {
1775         if (!session) {
1776                 return;
1777         }
1778
1779         Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1780         
1781         if (location) {
1782                 session->request_locate (location->start(), session->transport_rolling());
1783         } else {
1784                 session->goto_start ();
1785         }
1786 }
1787
1788 void
1789 Editor::set_mark ()
1790 {
1791         nframes_t pos;
1792         float prefix;
1793         bool was_floating;
1794         string markername;
1795
1796         if (get_prefix (prefix, was_floating)) {
1797                 pos = session->audible_frame ();
1798         } else {
1799                 if (was_floating) {
1800                         pos = (nframes_t) floor (prefix * session->frame_rate ());
1801                 } else {
1802                         pos = (nframes_t) floor (prefix);
1803                 }
1804         }
1805
1806         session->locations()->next_available_name(markername,"mark");
1807         session->locations()->add (new Location (pos, 0, markername, Location::IsMark), true);
1808 }
1809
1810 void
1811 Editor::clear_markers ()
1812 {
1813         if (session) {
1814                 session->begin_reversible_command (_("clear markers"));
1815                 XMLNode &before = session->locations()->get_state();
1816                 session->locations()->clear_markers ();
1817                 XMLNode &after = session->locations()->get_state();
1818                 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1819                 session->commit_reversible_command ();
1820         }
1821 }
1822
1823 void
1824 Editor::clear_ranges ()
1825 {
1826         if (session) {
1827                 session->begin_reversible_command (_("clear ranges"));
1828                 XMLNode &before = session->locations()->get_state();
1829                 
1830                 Location * looploc = session->locations()->auto_loop_location();
1831                 Location * punchloc = session->locations()->auto_punch_location();
1832                 
1833                 session->locations()->clear_ranges ();
1834                 // re-add these
1835                 if (looploc) session->locations()->add (looploc);
1836                 if (punchloc) session->locations()->add (punchloc);
1837                 
1838                 XMLNode &after = session->locations()->get_state();
1839                 session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1840                 session->commit_reversible_command ();
1841         }
1842 }
1843
1844 void
1845 Editor::clear_locations ()
1846 {
1847         session->begin_reversible_command (_("clear locations"));
1848         XMLNode &before = session->locations()->get_state();
1849         session->locations()->clear ();
1850         XMLNode &after = session->locations()->get_state();
1851         session->add_command(new MementoCommand<Locations>(*(session->locations()), &before, &after));
1852         session->commit_reversible_command ();
1853         session->locations()->clear ();
1854 }
1855
1856 void
1857 Editor::unhide_markers ()
1858 {
1859         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1860                 Location *l = (*i).first;
1861                 if (l->is_hidden() && l->is_mark()) {
1862                         l->set_hidden(false, this);
1863                 }
1864         }
1865 }
1866
1867 void
1868 Editor::unhide_ranges ()
1869 {
1870         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
1871                 Location *l = (*i).first;
1872                 if (l->is_hidden() && l->is_range_marker()) { 
1873                         l->set_hidden(false, this);
1874                 }
1875         }
1876 }
1877
1878 /* INSERT/REPLACE */
1879
1880 void
1881 Editor::insert_region_list_drag (boost::shared_ptr<AudioRegion> region, int x, int y)
1882 {
1883         double wx, wy;
1884         double cx, cy;
1885         TimeAxisView *tv;
1886         nframes_t where;
1887         AudioTimeAxisView *atv = 0;
1888         boost::shared_ptr<Playlist> playlist;
1889         
1890         track_canvas.window_to_world (x, y, wx, wy);
1891         wx += horizontal_adjustment.get_value();
1892         wy += vertical_adjustment.get_value();
1893
1894         GdkEvent event;
1895         event.type = GDK_BUTTON_RELEASE;
1896         event.button.x = wx;
1897         event.button.y = wy;
1898         
1899         where = event_frame (&event, &cx, &cy);
1900
1901         if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1902                 /* clearly outside canvas area */
1903                 return;
1904         }
1905         
1906         if ((tv = trackview_by_y_position (cy)) == 0) {
1907                 return;
1908         }
1909         
1910         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1911                 return;
1912         }
1913
1914         if ((playlist = atv->playlist()) == 0) {
1915                 return;
1916         }
1917         
1918         snap_to (where);
1919         
1920         begin_reversible_command (_("insert dragged region"));
1921         XMLNode &before = playlist->get_state();
1922         playlist->add_region (RegionFactory::create (region), where, 1.0);
1923         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1924         commit_reversible_command ();
1925 }
1926
1927 void
1928 Editor::insert_region_list_selection (float times)
1929 {
1930         RouteTimeAxisView *tv = 0;
1931         boost::shared_ptr<Playlist> playlist;
1932
1933         if (clicked_audio_trackview != 0) {
1934                 tv = clicked_audio_trackview;
1935         } else if (!selection->tracks.empty()) {
1936                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1937                         return;
1938                 }
1939         } else if (entered_track != 0) {
1940                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
1941                         return;
1942                 }
1943         } else {
1944                 return;
1945         }
1946
1947         if ((playlist = tv->playlist()) == 0) {
1948                 return;
1949         }
1950         
1951         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
1952         
1953         if (selected->count_selected_rows() != 1) {
1954                 return;
1955         }
1956         
1957         TreeView::Selection::ListHandle_Path rows = selected->get_selected_rows ();
1958
1959         /* only one row selected, so rows.begin() is it */
1960
1961         TreeIter iter;
1962
1963         if ((iter = region_list_model->get_iter (*rows.begin()))) {
1964
1965                 boost::shared_ptr<Region> region = (*iter)[region_list_columns.region];
1966                 
1967                 begin_reversible_command (_("insert region"));
1968                 XMLNode &before = playlist->get_state();
1969                 playlist->add_region ((RegionFactory::create (region)), get_preferred_edit_position(), times);
1970                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
1971                 commit_reversible_command ();
1972         } 
1973 }
1974
1975 /* BUILT-IN EFFECTS */
1976
1977 void
1978 Editor::reverse_selection ()
1979 {
1980
1981 }
1982
1983 /* GAIN ENVELOPE EDITING */
1984
1985 void
1986 Editor::edit_envelope ()
1987 {
1988 }
1989
1990 /* PLAYBACK */
1991
1992 void
1993 Editor::transition_to_rolling (bool fwd)
1994 {
1995         if (!session) {
1996                 return;
1997         }
1998
1999         switch (Config->get_slave_source()) {
2000         case None:
2001         case JACK:
2002                 break;
2003         default:
2004                 /* transport controlled by the master */
2005                 return;
2006         }
2007
2008         if (session->is_auditioning()) {
2009                 session->cancel_audition ();
2010                 return;
2011         }
2012         
2013         session->request_transport_speed (fwd ? 1.0f : -1.0f);
2014 }
2015
2016 void
2017 Editor::toggle_playback (bool with_abort)
2018 {
2019         if (!session) {
2020                 return;
2021         }
2022
2023         switch (Config->get_slave_source()) {
2024         case None:
2025         case JACK:
2026                 break;
2027         default:
2028                 /* transport controlled by the master */
2029                 return;
2030         }
2031
2032         if (session->is_auditioning()) {
2033                 session->cancel_audition ();
2034                 return;
2035         }
2036         
2037         if (session->transport_rolling()) {
2038                 session->request_stop (with_abort);
2039                 if (session->get_play_loop()) {
2040                         session->request_play_loop (false);
2041                 }
2042         } else {
2043                 session->request_transport_speed (1.0f);
2044         }
2045 }
2046
2047 void
2048 Editor::play_from_start ()
2049 {
2050         session->request_locate (session->current_start_frame(), true);
2051 }
2052
2053 void
2054 Editor::play_from_edit_point ()
2055 {
2056         session->request_locate (get_preferred_edit_position(), true);
2057 }
2058
2059 void
2060 Editor::play_selection ()
2061 {
2062         if (selection->time.empty()) {
2063                 return;
2064         }
2065
2066         session->request_play_range (true);
2067 }
2068
2069 void
2070 Editor::play_selected_region ()
2071 {
2072         if (!selection->regions.empty()) {
2073                 RegionView *rv = *(selection->regions.begin());
2074
2075                 session->request_bounded_roll (rv->region()->position(), rv->region()->last_frame());   
2076         }
2077 }
2078
2079 void
2080 Editor::loop_selected_region ()
2081 {
2082         if (!selection->regions.empty()) {
2083                 RegionView *rv = *(selection->regions.begin());
2084                 Location* tll;
2085
2086                 if ((tll = transport_loop_location()) != 0)  {
2087
2088                         tll->set (rv->region()->position(), rv->region()->last_frame());
2089                         
2090                         // enable looping, reposition and start rolling
2091
2092                         session->request_play_loop (true);
2093                         session->request_locate (tll->start(), false);
2094                         session->request_transport_speed (1.0f);
2095                 }
2096         }
2097 }
2098
2099 void
2100 Editor::play_location (Location& location)
2101 {
2102         if (location.start() <= location.end()) {
2103                 return;
2104         }
2105
2106         session->request_bounded_roll (location.start(), location.end());
2107 }
2108
2109 void
2110 Editor::loop_location (Location& location)
2111 {
2112         if (location.start() <= location.end()) {
2113                 return;
2114         }
2115
2116         Location* tll;
2117
2118         if ((tll = transport_loop_location()) != 0) {
2119                 tll->set (location.start(), location.end());
2120
2121                 // enable looping, reposition and start rolling
2122                 session->request_play_loop (true);
2123                 session->request_locate (tll->start(), true);
2124         }
2125 }
2126
2127 void
2128 Editor::raise_region ()
2129 {
2130         selection->foreach_region (&Region::raise);
2131 }
2132
2133 void
2134 Editor::raise_region_to_top ()
2135 {
2136         selection->foreach_region (&Region::raise_to_top);
2137 }
2138
2139 void
2140 Editor::lower_region ()
2141 {
2142         selection->foreach_region (&Region::lower);
2143 }
2144
2145 void
2146 Editor::lower_region_to_bottom ()
2147 {
2148         selection->foreach_region (&Region::lower_to_bottom);
2149 }
2150
2151 void
2152 Editor::edit_region ()
2153 {
2154         if (clicked_regionview == 0) {
2155                 return;
2156         }
2157         
2158         clicked_regionview->show_region_editor ();
2159 }
2160
2161 void
2162 Editor::rename_region ()
2163 {
2164         Dialog dialog;
2165         Entry  entry;
2166         Button ok_button (_("OK"));
2167         Button cancel_button (_("Cancel"));
2168
2169         if (selection->regions.empty()) {
2170                 return;
2171         }
2172
2173         WindowTitle title(Glib::get_application_name());
2174         title += _("Rename Region");
2175
2176         dialog.set_title (title.get_string());
2177         dialog.set_name ("RegionRenameWindow");
2178         dialog.set_size_request (300, -1);
2179         dialog.set_position (Gtk::WIN_POS_MOUSE);
2180         dialog.set_modal (true);
2181
2182         dialog.get_vbox()->set_border_width (10);
2183         dialog.get_vbox()->pack_start (entry);
2184         dialog.get_action_area()->pack_start (ok_button);
2185         dialog.get_action_area()->pack_start (cancel_button);
2186
2187         entry.set_name ("RegionNameDisplay");
2188         ok_button.set_name ("EditorGTKButton");
2189         cancel_button.set_name ("EditorGTKButton");
2190
2191         region_renamed = false;
2192
2193         entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2194         ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
2195         cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
2196
2197         /* recurse */
2198
2199         dialog.show_all ();
2200         Main::run ();
2201
2202         if (region_renamed) {
2203                 (*selection->regions.begin())->region()->set_name (entry.get_text());
2204                 redisplay_regions ();
2205         }
2206 }
2207
2208 void
2209 Editor::rename_region_finished (bool status)
2210
2211 {
2212         region_renamed = status;
2213         Main::quit ();
2214 }
2215
2216 void
2217 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2218 {
2219         if (session->is_auditioning()) {
2220                 session->cancel_audition ();
2221         } 
2222
2223         // note: some potential for creativity here, because region doesn't
2224         // have to belong to the playlist that Route is handling
2225
2226         // bool was_soloed = route.soloed();
2227
2228         route.set_solo (true, this);
2229         
2230         session->request_bounded_roll (region->position(), region->position() + region->length());
2231         
2232         /* XXX how to unset the solo state ? */
2233 }
2234
2235 void
2236 Editor::audition_selected_region ()
2237 {
2238         if (!selection->regions.empty()) {
2239                 RegionView* rv = *(selection->regions.begin());
2240                 session->audition_region (rv->region());
2241         }
2242 }
2243
2244 void
2245 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2246 {
2247         session->audition_region (region);
2248 }
2249
2250 void
2251 Editor::build_interthread_progress_window ()
2252 {
2253         interthread_progress_window = new ArdourDialog (X_("interthread progress"), true);
2254
2255         interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
2256         
2257         interthread_progress_window->get_vbox()->pack_start (interthread_progress_label, false, false);
2258         interthread_progress_window->get_vbox()->pack_start (interthread_progress_bar,false, false);
2259
2260         // GTK2FIX: this button needs a modifiable label
2261
2262         Button* b = interthread_progress_window->add_button (Stock::CANCEL, RESPONSE_CANCEL);
2263         b->signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
2264
2265         interthread_cancel_button.add (interthread_cancel_label);
2266
2267         interthread_progress_window->set_default_size (200, 100);
2268 }
2269
2270 void
2271 Editor::interthread_cancel_clicked ()
2272 {
2273         if (current_interthread_info) {
2274                 current_interthread_info->cancel = true;
2275         }
2276 }
2277
2278 void
2279 Editor::region_from_selection ()
2280 {
2281         if (clicked_trackview == 0) {
2282                 return;
2283         }
2284
2285         if (selection->time.empty()) {
2286                 return;
2287         }
2288
2289         nframes_t start = selection->time[clicked_selection].start;
2290         nframes_t end = selection->time[clicked_selection].end;
2291
2292         nframes_t selection_cnt = end - start + 1;
2293         
2294         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2295                 boost::shared_ptr<AudioRegion> current;
2296                 boost::shared_ptr<Region> current_r;
2297                 boost::shared_ptr<Playlist> pl;
2298
2299                 nframes_t internal_start;
2300                 string new_name;
2301
2302                 if ((pl = (*i)->playlist()) == 0) {
2303                         continue;
2304                 }
2305
2306                 if ((current_r = pl->top_region_at (start)) == 0) {
2307                         continue;
2308                 }
2309
2310                 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2311                 // FIXME: audio only
2312                 if (current != 0) {
2313                         internal_start = start - current->position();
2314                         session->region_name (new_name, current->name(), true);
2315                         boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2316                 }
2317         }
2318 }       
2319
2320 void
2321 Editor::create_region_from_selection (vector<boost::shared_ptr<AudioRegion> >& new_regions)
2322 {
2323         if (selection->time.empty() || selection->tracks.empty()) {
2324                 return;
2325         }
2326
2327         nframes_t start = selection->time[clicked_selection].start;
2328         nframes_t end = selection->time[clicked_selection].end;
2329         
2330         sort_track_selection ();
2331
2332         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2333
2334                 boost::shared_ptr<AudioRegion> current;
2335                 boost::shared_ptr<Region> current_r;
2336                 boost::shared_ptr<Playlist> playlist;
2337                 nframes_t internal_start;
2338                 string new_name;
2339
2340                 if ((playlist = (*i)->playlist()) == 0) {
2341                         continue;
2342                 }
2343
2344                 if ((current_r = playlist->top_region_at(start)) == 0) {
2345                         continue;
2346                 }
2347
2348                 if ((current = boost::dynamic_pointer_cast<AudioRegion>(current_r)) == 0) {
2349                         continue;
2350                 }
2351         
2352                 internal_start = start - current->position();
2353                 session->region_name (new_name, current->name(), true);
2354                 
2355                 new_regions.push_back (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (current, internal_start, end - start + 1, new_name)));
2356         }
2357 }
2358
2359 void
2360 Editor::split_multichannel_region ()
2361 {
2362         if (selection->regions.empty()) {
2363                 return;
2364         }
2365
2366         vector<boost::shared_ptr<AudioRegion> > v;
2367
2368         for (list<RegionView*>::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2369
2370                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(*x);
2371                 
2372                 if (!arv || arv->audio_region()->n_channels() < 2) {
2373                         continue;
2374                 }
2375
2376                 (arv)->audio_region()->separate_by_channel (*session, v);
2377         }
2378 }
2379
2380 void
2381 Editor::new_region_from_selection ()
2382 {
2383         region_from_selection ();
2384         cancel_selection ();
2385 }
2386
2387 static void
2388 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2389 {
2390         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2391         case OverlapNone:
2392                 break;
2393         default:
2394                 rs->push_back (rv);
2395         }
2396 }
2397
2398 void
2399 Editor::separate_regions_between (const TimeSelection& ts)
2400 {
2401         bool in_command = false;
2402         boost::shared_ptr<Playlist> playlist;
2403         RegionSelection new_selection;
2404                 
2405         sort_track_selection ();
2406
2407         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2408
2409                 AudioTimeAxisView* atv;
2410
2411                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2412
2413                         if (atv->is_audio_track()) {
2414
2415                                 /* no edits to destructive tracks */
2416
2417                                 if (atv->audio_track()->audio_diskstream()->destructive()) {
2418                                         continue;
2419                                 }
2420                                         
2421                                 if ((playlist = atv->playlist()) != 0) {
2422
2423
2424                                         XMLNode *before;
2425                                         bool got_some;
2426
2427                                         before = &(playlist->get_state());
2428                                         got_some = false;
2429
2430                                         /* XXX need to consider musical time selections here at some point */
2431
2432                                         double speed = atv->get_diskstream()->speed();
2433
2434
2435                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2436
2437                                                 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
2438                                                 latest_regionviews.clear ();
2439
2440                                                 playlist->partition ((nframes_t)((*t).start * speed), (nframes_t)((*t).end * speed), true);
2441
2442                                                 c.disconnect ();
2443
2444                                                 if (!latest_regionviews.empty()) {
2445                                                         
2446                                                         got_some = true;
2447
2448                                                         atv->view()->foreach_regionview (bind (sigc::ptr_fun (add_if_covered), &(*t), &new_selection));
2449                                                         
2450                                                         if (!in_command) {
2451                                                                 begin_reversible_command (_("separate"));
2452                                                                 in_command = true;
2453                                                         }
2454                                                         
2455                                                         session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2456                                                         
2457                                                 } 
2458                                         }
2459
2460                                         if (!got_some) {
2461                                                 delete before;
2462                                         }
2463                                 }
2464                         }
2465                 }
2466         }
2467
2468         if (in_command) {
2469                 selection->set (new_selection);
2470                 set_mouse_mode (MouseObject);
2471
2472                 commit_reversible_command ();
2473         }
2474 }
2475
2476 void
2477 Editor::separate_region_from_selection ()
2478 {
2479         /* preferentially use *all* ranges in the time selection if we're in range mode
2480            to allow discontiguous operation, since get_edit_op_range() currently
2481            returns a single range.
2482         */
2483         if (mouse_mode == MouseRange && !selection->time.empty()) {
2484
2485                 separate_regions_between (selection->time);
2486
2487         } else {
2488
2489                 nframes64_t start;
2490                 nframes64_t end;
2491                 
2492                 if (get_edit_op_range (start, end)) {
2493                         
2494                         AudioRange ar (start, end, 1);
2495                         TimeSelection ts;
2496                         ts.push_back (ar);
2497
2498                         /* force track selection */
2499
2500                         ensure_entered_region_selected ();
2501                         
2502                         separate_regions_between (ts);
2503                 }
2504         }
2505 }
2506
2507 void
2508 Editor::separate_regions_using_location (Location& loc)
2509 {
2510         if (loc.is_mark()) {
2511                 return;
2512         }
2513
2514         AudioRange ar (loc.start(), loc.end(), 1);
2515         TimeSelection ts;
2516
2517         ts.push_back (ar);
2518
2519         separate_regions_between (ts);
2520 }
2521
2522 void
2523 Editor::crop_region_to_selection ()
2524 {
2525         ensure_entered_region_selected (true);
2526
2527         if (!selection->time.empty()) {
2528
2529                 crop_region_to (selection->time.start(), selection->time.end_frame());
2530
2531         } else if (_edit_point != EditAtPlayhead) {
2532
2533                 nframes64_t start;
2534                 nframes64_t end;
2535
2536                 if (get_edit_op_range (start, end)) {
2537                         crop_region_to (start, end);
2538                 }
2539         }
2540                 
2541 }               
2542
2543 void
2544 Editor::crop_region_to (nframes_t start, nframes_t end)
2545 {
2546         vector<boost::shared_ptr<Playlist> > playlists;
2547         boost::shared_ptr<Playlist> playlist;
2548         TrackSelection* ts;
2549
2550         if (selection->tracks.empty()) {
2551                 ts = &track_views;
2552         } else {
2553                 sort_track_selection ();
2554                 ts = &selection->tracks;
2555         }
2556         
2557         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
2558                 
2559                 AudioTimeAxisView* atv;
2560                 
2561                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2562                         
2563                         if (atv->is_audio_track()) {
2564                                 
2565                                 /* no edits to destructive tracks */
2566
2567                                 if (atv->audio_track()->audio_diskstream()->destructive()) {
2568                                         continue;
2569                                 }
2570
2571                                 if ((playlist = atv->playlist()) != 0) {
2572                                         playlists.push_back (playlist);
2573                                 }
2574                         }
2575                 }
2576         }
2577
2578         if (playlists.empty()) {
2579                 return;
2580         }
2581                 
2582         nframes_t the_start;
2583         nframes_t the_end;
2584         nframes_t cnt;
2585         
2586         begin_reversible_command (_("trim to selection"));
2587         
2588         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2589                 
2590                 boost::shared_ptr<Region> region;
2591         
2592                 the_start = start;
2593         
2594                 if ((region = (*i)->top_region_at(the_start)) == 0) {
2595                         continue;
2596                 }
2597                 
2598                 /* now adjust lengths to that we do the right thing
2599                    if the selection extends beyond the region
2600                 */
2601                 
2602                 the_start = max (the_start, region->position());
2603                 if (max_frames - the_start < region->length()) {
2604                         the_end = the_start + region->length() - 1;
2605                 } else {
2606                         the_end = max_frames;
2607                 }
2608                 the_end = min (end, the_end);
2609                 cnt = the_end - the_start + 1;
2610                 
2611                 XMLNode &before = (*i)->get_state();
2612                 region->trim_to (the_start, cnt, this);
2613                 XMLNode &after = (*i)->get_state();
2614                 session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2615         }
2616         
2617         commit_reversible_command ();
2618 }               
2619
2620 void
2621 Editor::region_fill_track ()
2622 {
2623         nframes_t end;
2624
2625         if (!session || selection->regions.empty()) {
2626                 return;
2627         }
2628
2629         end = session->current_end_frame ();
2630
2631         begin_reversible_command (_("region fill"));
2632
2633         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2634
2635                 boost::shared_ptr<Region> region ((*i)->region());
2636                 
2637                 // FIXME
2638                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2639                 if (!ar)
2640                         continue;
2641
2642                 boost::shared_ptr<Playlist> pl = region->playlist();
2643
2644                 if (end <= region->last_frame()) {
2645                         return;
2646                 }
2647
2648                 double times = (double) (end - region->last_frame()) / (double) region->length();
2649
2650                 if (times == 0) {
2651                         return;
2652                 }
2653
2654                 XMLNode &before = pl->get_state();
2655                 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2656                 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2657         }
2658
2659         commit_reversible_command ();
2660 }
2661
2662 void
2663 Editor::region_fill_selection ()
2664 {
2665         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2666                 return;
2667         }
2668
2669         if (selection->time.empty()) {
2670                 return;
2671         }
2672
2673
2674         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2675
2676         if (selected->count_selected_rows() != 1) {
2677                 return;
2678         }
2679
2680         TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2681         boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2682
2683         nframes_t start = selection->time[clicked_selection].start;
2684         nframes_t end = selection->time[clicked_selection].end;
2685
2686         boost::shared_ptr<Playlist> playlist; 
2687
2688         if (selection->tracks.empty()) {
2689                 return;
2690         }
2691
2692         nframes_t selection_length = end - start;
2693         float times = (float)selection_length / region->length();
2694         
2695         begin_reversible_command (_("fill selection"));
2696         
2697         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2698
2699                 if ((playlist = (*i)->playlist()) == 0) {
2700                         continue;
2701                 }               
2702                 
2703                 XMLNode &before = playlist->get_state();
2704                 playlist->add_region (RegionFactory::create (region), start, times);
2705                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2706         }
2707         
2708         commit_reversible_command ();                   
2709 }
2710
2711 void
2712 Editor::set_region_sync_from_edit_point ()
2713 {
2714         nframes64_t where = get_preferred_edit_position ();
2715         ensure_entered_region_selected (true);
2716         set_sync_point (where, selection->regions);
2717 }
2718
2719 void
2720 Editor::set_sync_point (nframes64_t where, const RegionSelection& rs)
2721 {
2722         bool in_command = false;
2723
2724         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
2725                 
2726                 if (!(*r)->region()->covers (where)) {
2727                         continue;
2728                 }
2729
2730                 boost::shared_ptr<Region> region ((*r)->region());
2731
2732                 if (!in_command) {
2733                         begin_reversible_command (_("set sync point"));
2734                         in_command = true;
2735                 }
2736
2737                 XMLNode &before = region->playlist()->get_state();
2738                 region->set_sync_position (get_preferred_edit_position());
2739                 XMLNode &after = region->playlist()->get_state();
2740                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2741         }
2742
2743         if (in_command) {
2744                 commit_reversible_command ();
2745         }
2746 }
2747
2748 void
2749 Editor::remove_region_sync ()
2750 {
2751         if (clicked_regionview) {
2752                 boost::shared_ptr<Region> region (clicked_regionview->region());
2753                 begin_reversible_command (_("remove sync"));
2754                 XMLNode &before = region->playlist()->get_state();
2755                 region->clear_sync_position ();
2756                 XMLNode &after = region->playlist()->get_state();
2757                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2758                 commit_reversible_command ();
2759         }
2760 }
2761
2762 void
2763 Editor::naturalize ()
2764 {
2765         if (selection->regions.empty()) {
2766                 return;
2767         }
2768         begin_reversible_command (_("naturalize"));
2769         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2770                 XMLNode &before = (*i)->region()->get_state();
2771                 (*i)->region()->move_to_natural_position (this);
2772                 XMLNode &after = (*i)->region()->get_state();
2773                 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2774         }
2775         commit_reversible_command ();
2776 }
2777
2778 void
2779 Editor::align (RegionPoint what)
2780 {
2781         ensure_entered_region_selected ();
2782
2783         nframes64_t where = get_preferred_edit_position();
2784
2785         if (!selection->regions.empty()) {
2786                 align_selection (what, where, selection->regions);
2787         } else {
2788
2789                 RegionSelection rs;
2790                 rs = get_regions_at (where, selection->tracks);
2791                 align_selection (what, where, rs);
2792         }
2793 }
2794
2795 void
2796 Editor::align_relative (RegionPoint what)
2797 {
2798         nframes64_t where = get_preferred_edit_position();
2799
2800         if (!selection->regions.empty()) {
2801                 align_selection_relative (what, where, selection->regions);
2802         } else {
2803
2804                 RegionSelection rs;
2805                 rs = get_regions_at (where, selection->tracks);
2806                 align_selection_relative (what, where, rs);
2807         }
2808 }
2809
2810 struct RegionSortByTime {
2811     bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2812             return a->region()->position() < b->region()->position();
2813     }
2814 };
2815
2816 void
2817 Editor::align_selection_relative (RegionPoint point, nframes_t position, const RegionSelection& rs)
2818 {
2819         if (rs.empty()) {
2820                 return;
2821         }
2822
2823         nframes_t distance;
2824         nframes_t pos = 0;
2825         int dir;
2826
2827         list<RegionView*> sorted;
2828         rs.by_position (sorted);
2829         boost::shared_ptr<Region> r ((*sorted.begin())->region());
2830
2831         switch (point) {
2832         case Start:
2833                 pos = r->first_frame ();
2834                 break;
2835
2836         case End:
2837                 pos = r->last_frame();
2838                 break;
2839
2840         case SyncPoint:
2841                 pos = r->adjust_to_sync (r->first_frame());
2842                 break;  
2843         }
2844
2845         if (pos > position) {
2846                 distance = pos - position;
2847                 dir = -1;
2848         } else {
2849                 distance = position - pos;
2850                 dir = 1;
2851         }
2852
2853         begin_reversible_command (_("align selection (relative)"));
2854
2855         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2856
2857                 boost::shared_ptr<Region> region ((*i)->region());
2858
2859                 XMLNode &before = region->playlist()->get_state();
2860                 
2861                 if (dir > 0) {
2862                         region->set_position (region->position() + distance, this);
2863                 } else {
2864                         region->set_position (region->position() - distance, this);
2865                 }
2866
2867                 XMLNode &after = region->playlist()->get_state();
2868                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2869
2870         }
2871
2872         commit_reversible_command ();
2873 }
2874
2875 void
2876 Editor::align_selection (RegionPoint point, nframes_t position, const RegionSelection& rs)
2877 {
2878         if (rs.empty()) {
2879                 return;
2880         }
2881
2882         begin_reversible_command (_("align selection"));
2883
2884         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
2885                 align_region_internal ((*i)->region(), point, position);
2886         }
2887
2888         commit_reversible_command ();
2889 }
2890
2891 void
2892 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2893 {
2894         begin_reversible_command (_("align region"));
2895         align_region_internal (region, point, position);
2896         commit_reversible_command ();
2897 }
2898
2899 void
2900 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, nframes_t position)
2901 {
2902         XMLNode &before = region->playlist()->get_state();
2903
2904         switch (point) {
2905         case SyncPoint:
2906                 region->set_position (region->adjust_to_sync (position), this);
2907                 break;
2908
2909         case End:
2910                 if (position > region->length()) {
2911                         region->set_position (position - region->length(), this);
2912                 }
2913                 break;
2914
2915         case Start:
2916                 region->set_position (position, this);
2917                 break;
2918         }
2919
2920         XMLNode &after = region->playlist()->get_state();
2921         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2922 }       
2923
2924 void
2925 Editor::trim_region_to_loop ()
2926 {
2927         Location* loc = session->locations()->auto_loop_location();
2928         if (!loc) {
2929                 return;
2930         }
2931         trim_region_to_location (*loc, _("trim to loop"));
2932 }
2933
2934 void
2935 Editor::trim_region_to_punch ()
2936 {
2937         Location* loc = session->locations()->auto_punch_location();
2938         if (!loc) {
2939                 return;
2940         }
2941         trim_region_to_location (*loc, _("trim to punch"));
2942 }
2943
2944 void
2945 Editor::trim_region_to_location (const Location& loc, const char* str)
2946 {
2947         ensure_entered_region_selected ();
2948
2949         RegionSelection& rs (get_regions_for_action ());
2950
2951         begin_reversible_command (str);
2952
2953         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
2954                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
2955
2956                 if (!arv) {
2957                         continue;
2958                 }
2959
2960                 /* require region to span proposed trim */
2961
2962                 switch (arv->region()->coverage (loc.start(), loc.end())) {
2963                 case OverlapInternal:
2964                         break;
2965                 default:
2966                         continue;
2967                 }
2968                                 
2969                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
2970
2971                 if (!atav) {
2972                         return;
2973                 }
2974
2975                 float speed = 1.0;
2976                 nframes_t start;
2977                 nframes_t end;
2978
2979                 if (atav->get_diskstream() != 0) {
2980                         speed = atav->get_diskstream()->speed();
2981                 }
2982
2983                 start = session_frame_to_track_frame (loc.start(), speed);
2984                 end = session_frame_to_track_frame (loc.end(), speed);
2985
2986                 XMLNode &before = arv->region()->playlist()->get_state();
2987                 arv->region()->trim_to (start, (end - start), this);
2988                 XMLNode &after = arv->region()->playlist()->get_state();
2989                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
2990         }
2991                 
2992         commit_reversible_command ();
2993 }
2994
2995 void
2996 Editor::trim_region_to_edit_point ()
2997 {
2998         RegionSelection& rs (get_regions_for_action ());
2999         nframes64_t where = get_preferred_edit_position();
3000
3001         begin_reversible_command (_("trim region start to edit point"));
3002
3003         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3004                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3005
3006                 if (!arv) {
3007                         continue;
3008                 }
3009
3010                 /* require region to cover trim */
3011
3012                 if (!arv->region()->covers (where)) {
3013                         continue;
3014                 }
3015
3016                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3017
3018                 if (!atav) {
3019                         return;
3020                 }
3021
3022                 float speed = 1.0;
3023
3024                 if (atav->get_diskstream() != 0) {
3025                         speed = atav->get_diskstream()->speed();
3026                 }
3027
3028                 XMLNode &before = arv->region()->playlist()->get_state();
3029                 arv->region()->trim_end( session_frame_to_track_frame(where, speed), this);
3030                 XMLNode &after = arv->region()->playlist()->get_state();
3031                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
3032         }
3033                 
3034         commit_reversible_command ();
3035 }
3036
3037 void
3038 Editor::trim_region_from_edit_point ()
3039 {
3040         RegionSelection& rs (get_regions_for_action ());
3041         nframes64_t where = get_preferred_edit_position();
3042
3043         begin_reversible_command (_("trim region end to edit point"));
3044
3045         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3046                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3047
3048                 if (!arv) {
3049                         continue;
3050                 }
3051
3052                 /* require region to cover trim */
3053
3054                 if (!arv->region()->covers (where)) {
3055                         continue;
3056                 }
3057
3058                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3059
3060                 if (!atav) {
3061                         return;
3062                 }
3063
3064                 float speed = 1.0;
3065
3066                 if (atav->get_diskstream() != 0) {
3067                         speed = atav->get_diskstream()->speed();
3068                 }
3069
3070                 XMLNode &before = arv->region()->playlist()->get_state();
3071                 arv->region()->trim_front ( session_frame_to_track_frame(where, speed), this);
3072                 XMLNode &after = arv->region()->playlist()->get_state();
3073                 session->add_command(new MementoCommand<Playlist>(*(arv->region()->playlist()), &before, &after));
3074         }
3075                 
3076         commit_reversible_command ();
3077 }
3078
3079 void
3080 Editor::unfreeze_route ()
3081 {
3082         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
3083                 return;
3084         }
3085         
3086         clicked_audio_trackview->audio_track()->unfreeze ();
3087 }
3088
3089 void*
3090 Editor::_freeze_thread (void* arg)
3091 {
3092         PBD::ThreadCreated (pthread_self(), X_("Freeze"));
3093         return static_cast<Editor*>(arg)->freeze_thread ();
3094 }
3095
3096 void*
3097 Editor::freeze_thread ()
3098 {
3099         clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
3100         return 0;
3101 }
3102
3103 gint
3104 Editor::freeze_progress_timeout (void *arg)
3105 {
3106         interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
3107         return !(current_interthread_info->done || current_interthread_info->cancel);
3108 }
3109
3110 void
3111 Editor::freeze_route ()
3112 {
3113         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
3114                 return;
3115         }
3116         
3117         InterThreadInfo itt;
3118
3119         if (interthread_progress_window == 0) {
3120                 build_interthread_progress_window ();
3121         }
3122
3123         WindowTitle title(Glib::get_application_name());
3124         title += _("Freeze");
3125         interthread_progress_window->set_title (title.get_string());
3126         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
3127         interthread_progress_window->show_all ();
3128         interthread_progress_bar.set_fraction (0.0f);
3129         interthread_progress_label.set_text ("");
3130         interthread_cancel_label.set_text (_("Cancel Freeze"));
3131         current_interthread_info = &itt;
3132
3133         interthread_progress_connection = 
3134           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
3135
3136         itt.done = false;
3137         itt.cancel = false;
3138         itt.progress = 0.0f;
3139         
3140         pthread_attr_t attr;
3141         pthread_attr_init(&attr);
3142         pthread_attr_setstacksize(&attr, 500000);
3143
3144         pthread_create (&itt.thread, &attr, _freeze_thread, this);
3145
3146         pthread_attr_destroy(&attr);
3147
3148         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
3149
3150         while (!itt.done && !itt.cancel) {
3151                 gtk_main_iteration ();
3152         }
3153
3154         interthread_progress_connection.disconnect ();
3155         interthread_progress_window->hide_all ();
3156         current_interthread_info = 0;
3157         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3158 }
3159
3160 void
3161 Editor::bounce_range_selection ()
3162 {
3163         if (selection->time.empty()) {
3164                 return;
3165         }
3166
3167         TrackSelection views = selection->tracks;
3168
3169         nframes_t start = selection->time[clicked_selection].start;
3170         nframes_t end = selection->time[clicked_selection].end;
3171         nframes_t cnt = end - start + 1;
3172
3173         begin_reversible_command (_("bounce range"));
3174
3175         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3176
3177                 AudioTimeAxisView* atv;
3178
3179                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
3180                         continue;
3181                 }
3182                 
3183                 boost::shared_ptr<Playlist> playlist;
3184                 
3185                 if ((playlist = atv->playlist()) == 0) {
3186                         return;
3187                 }
3188
3189                 InterThreadInfo itt;
3190                 
3191                 itt.done = false;
3192                 itt.cancel = false;
3193                 itt.progress = false;
3194
3195                 XMLNode &before = playlist->get_state();
3196                 atv->audio_track()->bounce_range (start, cnt, itt);
3197                 XMLNode &after = playlist->get_state();
3198                 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
3199         }
3200         
3201         commit_reversible_command ();
3202 }
3203
3204 void
3205 Editor::cut ()
3206 {
3207         cut_copy (Cut);
3208 }
3209
3210 void
3211 Editor::copy ()
3212 {
3213         cut_copy (Copy);
3214 }
3215
3216 void 
3217 Editor::cut_copy (CutCopyOp op)
3218 {
3219         /* only cancel selection if cut/copy is successful.*/
3220
3221         string opname;
3222
3223         switch (op) {
3224         case Cut:
3225                 opname = _("cut");
3226                 break;
3227         case Copy:
3228                 opname = _("copy");
3229                 break;
3230         case Clear:
3231                 opname = _("clear");
3232                 break;
3233         }
3234         
3235         cut_buffer->clear ();
3236
3237         if (entered_marker) {
3238
3239                 /* cut/delete op while pointing at a marker */
3240
3241                 bool ignored;
3242                 Location* loc = find_location_from_marker (entered_marker, ignored);
3243
3244                 if (session && loc) {
3245                         Glib::signal_idle().connect (bind (mem_fun(*this, &Editor::really_remove_marker), loc));
3246                 }
3247
3248                 return;
3249         }
3250
3251         switch (current_mouse_mode()) {
3252         case MouseObject: 
3253                 cerr << "cutting in object mode\n";
3254                 if (!selection->regions.empty() || !selection->points.empty()) {
3255
3256                         begin_reversible_command (opname + _(" objects"));
3257
3258                         if (!selection->regions.empty()) {
3259                                 cerr << "have regions to cut" << endl;
3260                                 cut_copy_regions (op);
3261                                 
3262                                 if (op == Cut) {
3263                                         selection->clear_regions ();
3264                                 }
3265                         }
3266
3267                         if (!selection->points.empty()) {
3268                                 cut_copy_points (op);
3269
3270                                 if (op == Cut) {
3271                                         selection->clear_points ();
3272                                 }
3273                         }
3274
3275                         commit_reversible_command ();   
3276                         break; // terminate case statement here
3277                 } 
3278                 cerr << "nope, now cutting time range" << endl;
3279                 if (!selection->time.empty()) {
3280                         /* don't cause suprises */
3281                         break;
3282                 }
3283                 // fall thru if there was nothing selected
3284                 
3285         case MouseRange:
3286                 if (selection->time.empty()) {
3287                         nframes64_t start, end;
3288                         cerr << "no time selection, get edit op range" << endl;
3289                         if (!get_edit_op_range (start, end)) {
3290                                 cerr << "no edit op range" << endl;
3291                                 return;
3292                         }
3293                         selection->set ((TimeAxisView*) 0, start, end);
3294                 }
3295                         
3296                 begin_reversible_command (opname + _(" range"));
3297                 cut_copy_ranges (op);
3298                 commit_reversible_command ();
3299                 
3300                 if (op == Cut) {
3301                         selection->clear_time ();
3302                 }
3303
3304                 break;
3305                 
3306         default:
3307                 break;
3308         }
3309 }
3310
3311 void
3312 Editor::cut_copy_points (CutCopyOp op)
3313 {
3314         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3315
3316                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3317
3318                 if (atv) {
3319                         atv->cut_copy_clear_objects (selection->points, op);
3320                 } 
3321         }
3322 }
3323
3324 struct PlaylistState {
3325     boost::shared_ptr<Playlist> playlist;
3326     XMLNode*  before;
3327 };
3328
3329 struct lt_playlist {
3330     bool operator () (const PlaylistState& a, const PlaylistState& b) {
3331             return a.playlist < b.playlist;
3332     }
3333 };
3334         
3335 struct PlaylistMapping { 
3336     TimeAxisView* tv;
3337     boost::shared_ptr<AudioPlaylist> pl;
3338
3339     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
3340 };
3341
3342 void
3343 Editor::cut_copy_regions (CutCopyOp op)
3344 {
3345         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
3346            a map when we want ordered access to both elements. i think.
3347         */
3348
3349         vector<PlaylistMapping> pmap;
3350
3351         nframes_t first_position = max_frames;
3352         
3353         set<PlaylistState, lt_playlist> freezelist;
3354         pair<set<PlaylistState, lt_playlist>::iterator,bool> insert_result;
3355         
3356         /* get ordering correct before we cut/copy */
3357         
3358         selection->regions.sort_by_position_and_track ();
3359
3360         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
3361
3362                 first_position = min ((*x)->region()->position(), first_position);
3363
3364                 if (op == Cut || op == Clear) {
3365                         boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3366
3367                         if (pl) {
3368
3369                                 PlaylistState before;
3370                                 before.playlist = pl;
3371                                 before.before = &pl->get_state();
3372                                 
3373                                 insert_result = freezelist.insert (before);
3374                                 
3375                                 if (insert_result.second) {
3376                                         pl->freeze ();
3377                                 }
3378                         }
3379                 }
3380
3381                 TimeAxisView* tv = &(*x)->get_trackview();
3382                 vector<PlaylistMapping>::iterator z;
3383
3384                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3385                         if ((*z).tv == tv) {
3386                                 break;
3387                         }
3388                 }
3389                 
3390                 if (z == pmap.end()) {
3391                         pmap.push_back (PlaylistMapping (tv));
3392                 }
3393         }
3394
3395         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3396
3397                 boost::shared_ptr<AudioPlaylist> pl = boost::dynamic_pointer_cast<AudioPlaylist>((*x)->region()->playlist());
3398                 
3399                 if (!pl) {
3400                         /* impossible, but this handles it for the future */
3401                         continue;
3402                 }
3403
3404                 TimeAxisView& tv = (*x)->get_trackview();
3405                 boost::shared_ptr<AudioPlaylist> npl;
3406                 RegionSelection::iterator tmp;
3407                 
3408                 tmp = x;
3409                 ++tmp;
3410
3411                 vector<PlaylistMapping>::iterator z;
3412                 
3413                 for (z = pmap.begin(); z != pmap.end(); ++z) {
3414                         if ((*z).tv == &tv) {
3415                                 break;
3416                         }
3417                 }
3418                 
3419                 assert (z != pmap.end());
3420                 
3421                 if (!(*z).pl) {
3422                         npl = boost::dynamic_pointer_cast<AudioPlaylist> (PlaylistFactory::create (*session, "cutlist", true));
3423                         npl->freeze();
3424                         (*z).pl = npl;
3425                 } else {
3426                         npl = (*z).pl;
3427                 }
3428                 
3429                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3430                 boost::shared_ptr<Region> _xx;
3431                 
3432                 switch (op) {
3433                 case Cut:
3434                         if (!ar) break;
3435                         
3436                         _xx = RegionFactory::create ((*x)->region());
3437                         npl->add_region (_xx, (*x)->region()->position() - first_position);
3438                         pl->remove_region (((*x)->region()));
3439                         break;
3440                         
3441                 case Copy:
3442                         if (!ar) break;
3443
3444                         /* copy region before adding, so we're not putting same object into two different playlists */
3445                         npl->add_region (RegionFactory::create ((*x)->region()), (*x)->region()->position() - first_position);
3446                         break;
3447                         
3448                 case Clear:
3449                         pl->remove_region (((*x)->region()));
3450                         break;
3451                 }
3452
3453                 x = tmp;
3454         }
3455         
3456         list<boost::shared_ptr<Playlist> > foo;
3457         
3458         /* the pmap is in the same order as the tracks in which selected regions occured */
3459         
3460         for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3461                 (*i).pl->thaw();
3462                 foo.push_back ((*i).pl);
3463         }
3464         
3465
3466         if (!foo.empty()) {
3467                 cut_buffer->set (foo);
3468         }
3469
3470         for (set<PlaylistState, lt_playlist>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3471                 (*pl).playlist->thaw ();
3472                 session->add_command (new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
3473         }
3474 }
3475
3476 void
3477 Editor::cut_copy_ranges (CutCopyOp op)
3478 {
3479         TrackSelection* ts;
3480
3481         if (selection->tracks.empty()) {
3482                 ts = &track_views;
3483         } else {
3484                 ts = &selection->tracks;
3485         }
3486
3487         for (TrackSelection::iterator i = ts->begin(); i != ts->end(); ++i) {
3488                 (*i)->cut_copy_clear (*selection, op);
3489         }
3490 }
3491
3492 void
3493 Editor::paste (float times)
3494 {
3495         paste_internal (get_preferred_edit_position(), times);
3496 }
3497
3498 void
3499 Editor::mouse_paste ()
3500 {
3501         nframes64_t where;
3502         bool ignored;
3503
3504         if (!mouse_frame (where, ignored)) {
3505                 return;
3506         }
3507
3508         snap_to (where);
3509         paste_internal (where, 1);
3510 }
3511
3512 void
3513 Editor::paste_internal (nframes_t position, float times)
3514 {
3515         bool commit = false;
3516
3517         if (cut_buffer->empty()) {
3518                 return;
3519         }
3520
3521         if (position == max_frames) {
3522                 position = get_preferred_edit_position();
3523         }
3524
3525         begin_reversible_command (_("paste"));
3526
3527         TrackSelection ts;
3528         TrackSelection::iterator i;
3529         size_t nth;
3530
3531         /* get everything in the correct order */
3532
3533
3534         if (!selection->tracks.empty()) {
3535                 sort_track_selection ();
3536                 ts = selection->tracks;
3537         } else if (entered_track) {
3538                 ts.push_back (entered_track);
3539         }
3540
3541         for (nth = 0, i = ts.begin(); i != ts.end(); ++i, ++nth) {
3542
3543                 /* undo/redo is handled by individual tracks */
3544
3545                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3546                         commit = true;
3547                 }
3548         }
3549         
3550         if (commit) {
3551                 commit_reversible_command ();
3552         }
3553 }
3554
3555 void
3556 Editor::paste_named_selection (float times)
3557 {
3558         TrackSelection::iterator t;
3559
3560         Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3561
3562         if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3563                 return;
3564         }
3565
3566         TreeModel::iterator i = selected->get_selected();
3567         NamedSelection* ns = (*i)[named_selection_columns.selection];
3568
3569         list<boost::shared_ptr<Playlist> >::iterator chunk;
3570         list<boost::shared_ptr<Playlist> >::iterator tmp;
3571
3572         chunk = ns->playlists.begin();
3573                 
3574         begin_reversible_command (_("paste chunk"));
3575         
3576         sort_track_selection ();
3577
3578         for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3579                 
3580                 AudioTimeAxisView* atv;
3581                 boost::shared_ptr<Playlist> pl;
3582                 boost::shared_ptr<AudioPlaylist> apl;
3583
3584                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3585                         continue;
3586                 }
3587
3588                 if ((pl = atv->playlist()) == 0) {
3589                         continue;
3590                 }
3591                 
3592                 if ((apl = boost::dynamic_pointer_cast<AudioPlaylist> (pl)) == 0) {
3593                         continue;
3594                 }
3595
3596                 tmp = chunk;
3597                 ++tmp;
3598
3599                 XMLNode &before = apl->get_state();
3600                 apl->paste (*chunk, get_preferred_edit_position(), times);
3601                 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3602
3603                 if (tmp != ns->playlists.end()) {
3604                         chunk = tmp;
3605                 }
3606         }
3607
3608         commit_reversible_command();
3609 }
3610
3611 void
3612 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3613 {
3614         boost::shared_ptr<Playlist> playlist; 
3615         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
3616         RegionSelection foo;
3617
3618         begin_reversible_command (_("duplicate region"));
3619
3620         selection->clear_regions ();
3621
3622         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3623
3624                 boost::shared_ptr<Region> r ((*i)->region());
3625
3626                 TimeAxisView& tv = (*i)->get_time_axis_view();
3627                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3628
3629                 latest_regionviews.clear ();
3630                 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3631                 
3632                 playlist = (*i)->region()->playlist();
3633                 XMLNode &before = playlist->get_state();
3634                 playlist->duplicate (r, r->last_frame() + 1, times);
3635                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3636
3637                 c.disconnect ();
3638                 
3639                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
3640         }
3641
3642         commit_reversible_command ();
3643
3644         if (!foo.empty()) {
3645                 selection->set (foo);
3646         }
3647 }
3648
3649 void
3650 Editor::duplicate_selection (float times)
3651 {
3652         if (selection->time.empty() || selection->tracks.empty()) {
3653                 return;
3654         }
3655
3656         boost::shared_ptr<Playlist> playlist; 
3657         vector<boost::shared_ptr<AudioRegion> > new_regions;
3658         vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3659                 
3660         create_region_from_selection (new_regions);
3661
3662         if (new_regions.empty()) {
3663                 return;
3664         }
3665         
3666         begin_reversible_command (_("duplicate selection"));
3667
3668         ri = new_regions.begin();
3669
3670         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3671                 if ((playlist = (*i)->playlist()) == 0) {
3672                         continue;
3673                 }
3674                 XMLNode &before = playlist->get_state();
3675                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3676                 XMLNode &after = playlist->get_state();
3677                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3678
3679                 ++ri;
3680                 if (ri == new_regions.end()) {
3681                         --ri;
3682                 }
3683         }
3684
3685         commit_reversible_command ();
3686 }
3687
3688 void
3689 Editor::reset_point_selection ()
3690 {
3691         /* reset all selected points to the relevant default value */
3692
3693         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3694                 
3695                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3696                 
3697                 if (atv) {
3698                         atv->reset_objects (selection->points);
3699                 } 
3700         }
3701 }
3702
3703 void
3704 Editor::center_playhead ()
3705 {
3706         float page = canvas_width * frames_per_unit;
3707         center_screen_internal (playhead_cursor->current_frame, page);
3708 }
3709
3710 void
3711 Editor::center_edit_point ()
3712 {
3713         float page = canvas_width * frames_per_unit;
3714         center_screen_internal (get_preferred_edit_position(), page);
3715 }
3716
3717 void
3718 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
3719 {
3720         begin_reversible_command (_("clear playlist"));
3721         XMLNode &before = playlist->get_state();
3722         playlist->clear ();
3723         XMLNode &after = playlist->get_state();
3724         session->add_command (new MementoCommand<Playlist>(*playlist.get(), &before, &after));
3725         commit_reversible_command ();
3726 }
3727
3728 void
3729 Editor::nudge_track (bool use_edit, bool forwards)
3730 {
3731         boost::shared_ptr<Playlist> playlist; 
3732         nframes_t distance;
3733         nframes_t next_distance;
3734         nframes_t start;
3735
3736         if (use_edit) {
3737                 start = get_preferred_edit_position();
3738         } else {
3739                 start = 0;
3740         }
3741
3742         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3743                 return;
3744         }
3745         
3746         if (selection->tracks.empty()) {
3747                 return;
3748         }
3749         
3750         begin_reversible_command (_("nudge track"));
3751         
3752         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3753
3754                 if ((playlist = (*i)->playlist()) == 0) {
3755                         continue;
3756                 }               
3757                 
3758                 XMLNode &before = playlist->get_state();
3759                 playlist->nudge_after (start, distance, forwards);
3760                 XMLNode &after = playlist->get_state();
3761                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3762         }
3763         
3764         commit_reversible_command ();                   
3765 }
3766
3767 void
3768 Editor::remove_last_capture ()
3769 {
3770         vector<string> choices;
3771         string prompt;
3772         
3773         if (!session) {
3774                 return;
3775         }
3776
3777         if (Config->get_verify_remove_last_capture()) {
3778                 prompt  = _("Do you really want to destroy the last capture?"
3779                             "\n(This is destructive and cannot be undone)");
3780
3781                 choices.push_back (_("No, do nothing."));
3782                 choices.push_back (_("Yes, destroy it."));
3783                 
3784                 Gtkmm2ext::Choice prompter (prompt, choices);
3785                 
3786                 if (prompter.run () == 1) {
3787                         session->remove_last_capture ();
3788                 }
3789
3790         } else {
3791                 session->remove_last_capture();
3792         }
3793 }
3794
3795 void
3796 Editor::normalize_region ()
3797 {
3798         if (!session) {
3799                 return;
3800         }
3801
3802         if (selection->regions.empty()) {
3803                 return;
3804         }
3805
3806         begin_reversible_command (_("normalize"));
3807
3808         track_canvas.get_window()->set_cursor (*wait_cursor);
3809         gdk_flush ();
3810
3811         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3812                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3813                 if (!arv)
3814                         continue;
3815                 XMLNode &before = arv->region()->get_state();
3816                 arv->audio_region()->normalize_to (0.0f);
3817                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3818         }
3819
3820         commit_reversible_command ();
3821         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3822 }
3823
3824
3825 void
3826 Editor::denormalize_region ()
3827 {
3828         if (!session) {
3829                 return;
3830         }
3831
3832         if (selection->regions.empty()) {
3833                 return;
3834         }
3835
3836         begin_reversible_command ("denormalize");
3837
3838         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3839                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3840                 if (!arv)
3841                         continue;
3842                 XMLNode &before = arv->region()->get_state();
3843                 arv->audio_region()->set_scale_amplitude (1.0f);
3844                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3845         }
3846
3847         commit_reversible_command ();
3848 }
3849
3850
3851 void
3852 Editor::reverse_region ()
3853 {
3854         if (!session) {
3855                 return;
3856         }
3857
3858         Reverse rev (*session);
3859         apply_filter (rev, _("reverse regions"));
3860 }
3861
3862 void
3863 Editor::apply_filter (AudioFilter& filter, string command)
3864 {
3865         if (selection->regions.empty()) {
3866                 return;
3867         }
3868
3869         begin_reversible_command (command);
3870
3871         track_canvas.get_window()->set_cursor (*wait_cursor);
3872         gdk_flush ();
3873
3874         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3875                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3876                 if (!arv)
3877                         continue;
3878
3879                 boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
3880
3881                 RegionSelection::iterator tmp;
3882                 
3883                 tmp = r;
3884                 ++tmp;
3885
3886                 if (arv->audio_region()->apply (filter) == 0) {
3887
3888                         XMLNode &before = playlist->get_state();
3889                         playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3890                         XMLNode &after = playlist->get_state();
3891                         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3892                 } else {
3893                         goto out;
3894                 }
3895
3896                 r = tmp;
3897         }
3898
3899         commit_reversible_command ();
3900         selection->regions.clear ();
3901
3902   out:
3903         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3904 }
3905
3906 void
3907 Editor::region_selection_op (void (Region::*pmf)(void))
3908 {
3909         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3910                 Region* region = (*i)->region().get();
3911                 (region->*pmf)();
3912         }
3913 }
3914
3915
3916 void
3917 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3918 {
3919         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3920                 Region* region = (*i)->region().get();
3921                 (region->*pmf)(arg);
3922         }
3923 }
3924
3925 void
3926 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3927 {
3928         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3929                 Region* region = (*i)->region().get();
3930                 (region->*pmf)(yn);
3931         }
3932 }
3933
3934 void
3935 Editor::external_edit_region ()
3936 {
3937         if (!clicked_regionview) {
3938                 return;
3939         }
3940
3941         /* more to come */
3942 }
3943
3944 void
3945 Editor::brush (nframes_t pos)
3946 {
3947         RegionSelection sel;
3948         snap_to (pos);
3949
3950         if (selection->regions.empty()) {
3951                 /* XXX get selection from region list */
3952         } else { 
3953                 sel = selection->regions;
3954         }
3955
3956         if (sel.empty()) {
3957                 return;
3958         }
3959
3960         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3961                 mouse_brush_insert_region ((*i), pos);
3962         }
3963 }
3964
3965 void
3966 Editor::reset_region_gain_envelopes ()
3967 {
3968         if (!session || selection->regions.empty()) {
3969                 return;
3970         }
3971
3972         session->begin_reversible_command (_("reset region gain"));
3973
3974         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3975                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3976                 if (arv) {
3977                         AutomationList& alist (arv->audio_region()->envelope());
3978                         XMLNode& before (alist.get_state());
3979
3980                         arv->audio_region()->set_default_envelope ();
3981                         session->add_command (new MementoCommand<AutomationList>(arv->audio_region()->envelope(), &before, &alist.get_state()));
3982                 }
3983         }
3984
3985         session->commit_reversible_command ();
3986 }
3987
3988 void
3989 Editor::toggle_gain_envelope_visibility ()
3990 {
3991         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3992                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3993                 if (arv) {
3994                         bool x = region_envelope_visible_item->get_active();
3995                         if (x != arv->envelope_visible()) {
3996                                 arv->set_envelope_visible (x);
3997                         }
3998                 }
3999         }
4000 }
4001
4002 void
4003 Editor::toggle_gain_envelope_active ()
4004 {
4005         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4006                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4007                 if (arv) {
4008                         bool x = region_envelope_active_item->get_active();
4009                         if (x != arv->audio_region()->envelope_active()) {
4010                                 arv->audio_region()->set_envelope_active (x);
4011                         }
4012                 }
4013         }
4014 }
4015
4016 void
4017 Editor::toggle_region_lock ()
4018 {
4019         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4020                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4021                 if (arv) {
4022                         bool x = region_lock_item->get_active();
4023                         if (x != arv->audio_region()->locked()) {
4024                                 arv->audio_region()->set_locked (x);
4025                         }
4026                 }
4027         }
4028 }
4029
4030 void
4031 Editor::toggle_region_mute ()
4032 {
4033         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4034                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4035                 if (arv) {
4036                         bool x = region_mute_item->get_active();
4037                         if (x != arv->audio_region()->muted()) {
4038                                 arv->audio_region()->set_muted (x);
4039                         }
4040                 }
4041         }
4042 }
4043
4044 void
4045 Editor::toggle_region_opaque ()
4046 {
4047         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
4048                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
4049                 if (arv) {
4050                         bool x = region_opaque_item->get_active();
4051                         if (x != arv->audio_region()->opaque()) {
4052                                 arv->audio_region()->set_opaque (x);
4053                         }
4054                 }
4055         }
4056 }
4057
4058 void
4059 Editor::set_fade_length (bool in)
4060 {
4061         ensure_entered_region_selected ();
4062
4063         /* we need a region to measure the offset from the start */
4064
4065         RegionView* rv;
4066
4067         if (entered_regionview) {
4068                 rv = entered_regionview;
4069         } else if (!selection->regions.empty()) {
4070                 rv = selection->regions.front();
4071         } else {
4072                 return;
4073         }
4074
4075         nframes64_t pos = get_preferred_edit_position();
4076         nframes_t len;
4077         char* cmd;
4078
4079         if (in) {
4080                 if (pos <= rv->region()->position()) {
4081                         /* can't do it */
4082                         return;
4083                 }
4084                 len = pos - rv->region()->position();
4085                 cmd = _("set fade in length");
4086         } else {
4087                 if (pos >= rv->region()->last_frame()) {
4088                         /* can't do it */
4089                         return;
4090                 }
4091                 len = rv->region()->last_frame() - pos;
4092                 cmd = _("set fade out length");
4093         }
4094
4095         begin_reversible_command (cmd);
4096
4097         RegionSelection& rs (get_regions_for_action());
4098
4099         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4100                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4101
4102                 if (!tmp) {
4103                         return;
4104                 }
4105
4106                 AutomationList& alist = tmp->audio_region()->fade_in();
4107                 XMLNode &before = alist.get_state();
4108
4109                 if (in) {
4110                         tmp->audio_region()->set_fade_in_length (len);
4111                 } else {
4112                         tmp->audio_region()->set_fade_out_length (len);
4113                 }
4114                 
4115                 XMLNode &after = alist.get_state();
4116                 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
4117         }
4118
4119         commit_reversible_command ();
4120 }
4121
4122 void
4123 Editor::set_fade_in_shape (AudioRegion::FadeShape shape)
4124 {
4125         begin_reversible_command (_("set fade in shape"));
4126
4127         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
4128                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4129
4130                 if (!tmp) {
4131                         return;
4132                 }
4133
4134                 AutomationList& alist = tmp->audio_region()->fade_in();
4135                 XMLNode &before = alist.get_state();
4136
4137                 tmp->audio_region()->set_fade_in_shape (shape);
4138                 
4139                 XMLNode &after = alist.get_state();
4140                 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
4141         }
4142
4143         commit_reversible_command ();
4144 }
4145
4146 void
4147 Editor::set_fade_out_shape (AudioRegion::FadeShape shape)
4148 {
4149         begin_reversible_command (_("set fade out shape"));
4150
4151         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
4152                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4153
4154                 if (!tmp) {
4155                         return;
4156                 }
4157
4158                 AutomationList& alist = tmp->audio_region()->fade_out();
4159                 XMLNode &before = alist.get_state();
4160
4161                 tmp->audio_region()->set_fade_out_shape (shape);
4162                 
4163                 XMLNode &after = alist.get_state();
4164                 session->add_command(new MementoCommand<AutomationList>(alist, &before, &after));
4165         }
4166
4167         commit_reversible_command ();
4168 }
4169
4170 void
4171 Editor::set_fade_in_active (bool yn)
4172 {
4173         begin_reversible_command (_("set fade in active"));
4174
4175         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
4176                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4177
4178                 if (!tmp) {
4179                         return;
4180                 }
4181
4182
4183                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4184
4185                 XMLNode &before = ar->get_state();
4186
4187                 ar->set_fade_in_active (yn);
4188                 
4189                 XMLNode &after = ar->get_state();
4190                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4191         }
4192 }
4193
4194 void
4195 Editor::set_fade_out_active (bool yn)
4196 {
4197         begin_reversible_command (_("set fade out active"));
4198
4199         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
4200                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
4201
4202                 if (!tmp) {
4203                         return;
4204                 }
4205
4206                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
4207
4208                 XMLNode &before = ar->get_state();
4209
4210                 ar->set_fade_out_active (yn);
4211                 
4212                 XMLNode &after = ar->get_state();
4213                 session->add_command(new MementoCommand<AudioRegion>(*ar, &before, &after));
4214         }
4215 }
4216
4217
4218 /** Update crossfade visibility after its configuration has been changed */
4219 void
4220 Editor::update_xfade_visibility ()
4221 {
4222         _xfade_visibility = Config->get_xfades_visible ();
4223         
4224         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4225                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
4226                 if (v) {
4227                         if (_xfade_visibility) {
4228                                 v->show_all_xfades ();
4229                         } else {
4230                                 v->hide_all_xfades ();
4231                         }
4232                 }
4233         }
4234 }
4235
4236 void
4237 Editor::set_edit_point ()
4238 {
4239         nframes64_t where;
4240         bool ignored;
4241
4242         if (!mouse_frame (where, ignored)) {
4243                 return;
4244         }
4245         
4246         snap_to (where);
4247
4248         if (selection->markers.empty()) {
4249                 
4250                 mouse_add_new_marker (where);
4251
4252         } else {
4253                 bool ignored;
4254
4255                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
4256
4257                 if (loc) {
4258                         loc->move_to (where);
4259                 }
4260         }
4261 }
4262
4263 void
4264 Editor::set_playhead_cursor ()
4265 {
4266         if (entered_marker) {
4267                 session->request_locate (entered_marker->position(), session->transport_rolling());
4268         } else {
4269                 nframes64_t where;
4270                 bool ignored;
4271
4272                 if (!mouse_frame (where, ignored)) {
4273                         return;
4274                 }
4275                         
4276                 snap_to (where);
4277                 
4278                 if (session) {
4279                         session->request_locate (where, session->transport_rolling());
4280                 }
4281         }
4282 }
4283
4284 void
4285 Editor::split ()
4286 {
4287         ensure_entered_region_selected ();
4288
4289         nframes64_t where = get_preferred_edit_position();
4290
4291         if (!selection->regions.empty()) {
4292                 
4293                 split_regions_at (where, selection->regions);
4294
4295         } else {
4296                 
4297                 RegionSelection rs;
4298                 rs = get_regions_at (where, selection->tracks);
4299                 split_regions_at (where, rs);
4300         }
4301 }
4302
4303 void
4304 Editor::ensure_entered_track_selected (bool op_really_wants_one_track_if_none_are_selected)
4305 {
4306         if (entered_track && mouse_mode == MouseObject) {
4307                 if (!selection->tracks.empty()) {
4308                         if (!selection->selected (entered_track)) {
4309                                 selection->add (entered_track);
4310                         }
4311                 } else {
4312                         /* there is no selection, but this operation requires/prefers selected objects */
4313
4314                         if (op_really_wants_one_track_if_none_are_selected) {
4315                                 selection->set (entered_track);
4316                         }
4317                 }
4318         }
4319 }
4320
4321 void
4322 Editor::ensure_entered_region_selected (bool op_really_wants_one_region_if_none_are_selected)
4323 {
4324         if (entered_regionview && mouse_mode == MouseObject) {
4325
4326                 /* heuristic:
4327
4328                    - if there is no existing selection, don't change it. the operation will thus apply to "all"
4329
4330                    - if there is an existing selection, but the entered regionview isn't in it, add it. this
4331                        avoids key-mouse ops on unselected regions from interfering with an existing selection,
4332                        but also means that the operation will apply to the pointed-at region.
4333                 */
4334
4335                 if (!selection->regions.empty()) {
4336                         if (find (selection->regions.begin(), selection->regions.end(), entered_regionview) != selection->regions.end()) {
4337                                 selection->add (entered_regionview);
4338                         }
4339                 } else {
4340                         /* there is no selection, but this operation requires/prefers selected objects */
4341
4342                         if (op_really_wants_one_region_if_none_are_selected) {
4343                                 selection->set (entered_regionview, false);
4344                         }
4345                 }
4346         }
4347 }
4348
4349 void
4350 Editor::trim_region_front ()
4351 {
4352         trim_region (true);
4353 }
4354
4355 void
4356 Editor::trim_region_back ()
4357 {
4358         trim_region (false);
4359 }
4360
4361 void
4362 Editor::trim_region (bool front)
4363 {
4364         nframes64_t where = get_preferred_edit_position();
4365         RegionSelection& rs = get_regions_for_action ();
4366
4367         if (rs.empty()) {
4368                 return;
4369         }
4370
4371         begin_reversible_command (front ? _("trim front") : _("trim back"));
4372
4373         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
4374                 if (!(*i)->region()->locked()) {
4375                         boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
4376                         XMLNode &before = pl->get_state();
4377                         if (front) {
4378                                 (*i)->region()->trim_front (where, this);       
4379                         } else {
4380                                 (*i)->region()->trim_end (where, this); 
4381                         }
4382                         XMLNode &after = pl->get_state();
4383                         session->add_command(new MementoCommand<Playlist>(*pl.get(), &before, &after));
4384                 }
4385         }
4386         commit_reversible_command ();
4387 }
4388
4389 struct EditorOrderRouteSorter {
4390     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
4391             /* use of ">" forces the correct sort order */
4392             return a->order_key ("editor") < b->order_key ("editor");
4393     }
4394 };
4395
4396 void
4397 Editor::select_next_route()
4398 {
4399         if (selection->tracks.empty()) {
4400                 selection->set (track_views.front());
4401                 return;
4402         }
4403
4404         TimeAxisView* current = selection->tracks.front();
4405
4406         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4407                 if (*i == current) {
4408                         ++i;
4409                         if (i != track_views.end()) {
4410                                 selection->set (*i);
4411                         } else {
4412                                 selection->set (*(track_views.begin()));
4413                         }
4414                         break;
4415                 }
4416         }
4417 }
4418
4419 void
4420 Editor::select_prev_route()
4421 {
4422         if (selection->tracks.empty()) {
4423                 selection->set (track_views.front());
4424                 return;
4425         }
4426
4427         TimeAxisView* current = selection->tracks.front();
4428
4429         for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
4430                 if (*i == current) {
4431                         ++i;
4432                         if (i != track_views.rend()) {
4433                                 selection->set (*i);
4434                         } else {
4435                                 selection->set (*(track_views.rbegin()));
4436                         }
4437                         break;
4438                 }
4439         }
4440 }
4441
4442 void
4443 Editor::set_loop_from_selection (bool play)
4444 {
4445         if (session == 0 || selection->time.empty()) {
4446                 return;
4447         }
4448
4449         nframes_t start = selection->time[clicked_selection].start;
4450         nframes_t end = selection->time[clicked_selection].end;
4451         
4452         set_loop_range (start, end,  _("set loop range from selection"));
4453
4454         if (play) {
4455                 session->request_play_loop (true);
4456                 session->request_locate (start, true);
4457         }
4458 }
4459
4460 void
4461 Editor::set_loop_from_edit_range (bool play)
4462 {
4463         if (session == 0) {
4464                 return;
4465         }
4466
4467         nframes64_t start;
4468         nframes64_t end;
4469         
4470         if (!get_edit_op_range (start, end)) {
4471                 return;
4472         }
4473
4474         set_loop_range (start, end,  _("set loop range from edit range"));
4475
4476         if (play) {
4477                 session->request_play_loop (true);
4478                 session->request_locate (start, true);
4479         }
4480 }
4481
4482 void
4483 Editor::set_punch_from_selection ()
4484 {
4485         if (session == 0 || selection->time.empty()) {
4486                 return;
4487         }
4488
4489         nframes_t start = selection->time[clicked_selection].start;
4490         nframes_t end = selection->time[clicked_selection].end;
4491         
4492         set_punch_range (start, end,  _("set punch range from selection"));
4493 }
4494
4495 void
4496 Editor::set_punch_from_edit_range ()
4497 {
4498         if (session == 0) {
4499                 return;
4500         }
4501
4502         nframes64_t start;
4503         nframes64_t end;
4504         
4505         if (!get_edit_op_range (start, end)) {
4506                 return;
4507         }
4508
4509         set_punch_range (start, end,  _("set punch range from edit range"));
4510 }
4511