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