option editor and some prompters, misc stuff. this commit message contains no apostro...
[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     $Id$
19 */
20
21 #include <unistd.h>
22
23 #include <cstdlib>
24 #include <cmath>
25 #include <string>
26 #include <map>
27
28 #include <sndfile.h>
29
30 #include <pbd/error.h>
31 #include <pbd/basename.h>
32 #include <pbd/pthread_utils.h>
33
34 #include <gtkmm2ext/utils.h>
35 #include <gtkmm2ext/choice.h>
36
37 #include <ardour/audioengine.h>
38 #include <ardour/session.h>
39 #include <ardour/audioplaylist.h>
40 #include <ardour/audioregion.h>
41 #include <ardour/diskstream.h>
42 #include <ardour/filesource.h>
43 #include <ardour/sndfilesource.h>
44 #include <ardour/utils.h>
45 #include <ardour/location.h>
46 #include <ardour/named_selection.h>
47 #include <ardour/audio_track.h>
48 #include <ardour/audioplaylist.h>
49 #include <ardour/region_factory.h>
50 #include <ardour/reverse.h>
51
52 #include "ardour_ui.h"
53 #include "editor.h"
54 #include "time_axis_view.h"
55 #include "audio_time_axis.h"
56 #include "automation_time_axis.h"
57 #include "streamview.h"
58 #include "regionview.h"
59 #include "rgb_macros.h"
60 #include "selection_templates.h"
61 #include "selection.h"
62 #include "sfdb_ui.h"
63 #include "editing.h"
64 #include "gtk-custom-hruler.h"
65
66 #include "i18n.h"
67
68 using namespace std;
69 using namespace ARDOUR;
70 using namespace sigc;
71 using namespace Gtk;
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 int
95 Editor::ensure_cursor (jack_nframes_t *pos)
96 {
97         *pos = edit_cursor->current_frame;
98         return 0;
99 }
100
101 void
102 Editor::split_region ()
103 {
104         split_region_at (edit_cursor->current_frame);
105 }
106
107 void
108 Editor::split_region_at (jack_nframes_t where)
109 {
110         split_regions_at (where, selection->audio_regions);
111 }
112
113 void
114 Editor::split_regions_at (jack_nframes_t where, AudioRegionSelection& regions)
115 {
116         begin_reversible_command (_("split"));
117
118         snap_to (where);
119         for (AudioRegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
120
121                 AudioRegionSelection::iterator tmp;
122                 
123                 tmp = a;
124                 ++tmp;
125
126                 Playlist* pl = (*a)->region.playlist();
127
128                 _new_regionviews_show_envelope = (*a)->envelope_visible();
129                 
130                 if (pl) {
131                         session->add_undo (pl->get_memento());
132                         pl->split_region ((*a)->region, where);
133                         session->add_redo_no_execute (pl->get_memento());
134                 }
135
136                 a = tmp;
137     }
138
139         commit_reversible_command ();
140         _new_regionviews_show_envelope = false;
141 }
142
143 void
144 Editor::remove_clicked_region ()
145 {
146         if (clicked_audio_trackview == 0 || clicked_regionview == 0) {
147                 return;
148         }
149
150         Playlist* playlist = clicked_audio_trackview->playlist();
151         
152         begin_reversible_command (_("remove region"));
153         session->add_undo (playlist->get_memento());
154         playlist->remove_region (&clicked_regionview->region);
155         session->add_redo_no_execute (playlist->get_memento());
156         commit_reversible_command ();
157 }
158
159 void
160 Editor::destroy_clicked_region ()
161 {
162         int32_t selected = selection->audio_regions.size();
163
164         if (!session || clicked_regionview == 0 && selected == 0) {
165                 return;
166         }
167
168         vector<string> choices;
169         string prompt;
170         
171         prompt  = string_compose (_(" This is destructive, will possibly delete audio files\n\
172 It cannot be undone\n\
173 Do you really want to destroy %1 ?"),
174                            (selected > 1 ? 
175                             _("these regions") : _("this region")));
176
177         if (selected > 1) {
178                 choices.push_back (_("Yes, destroy them."));
179         } else {
180                 choices.push_back (_("Yes, destroy it."));
181         }
182
183         choices.push_back (_("No, do nothing."));
184
185         Gtkmm2ext::Choice prompter (prompt, choices);
186
187         prompter.chosen.connect (Gtk::Main::quit.slot());
188         prompter.show_all ();
189
190         Gtk::Main::run ();
191
192         if (prompter.get_choice() != 0) {
193                 return;
194         }
195
196         if (selected > 0) {
197                 list<Region*> r;
198
199                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
200                         r.push_back (&(*i)->region);
201                 }
202
203                 session->destroy_regions (r);
204
205         } else if (clicked_regionview) {
206                 session->destroy_region (&clicked_regionview->region);
207         } 
208 }
209
210 AudioRegion *
211 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
212 {
213         AudioRegionView* rv;
214         AudioRegion *region;
215         jack_nframes_t start = 0;
216
217         if (selection->time.start () == selection->time.end_frame ()) {
218                 
219                 /* no current selection-> is there a selected regionview? */
220
221                 if (selection->audio_regions.empty()) {
222                         return 0;
223                 }
224
225         } 
226
227         region = 0;
228
229         if (!selection->audio_regions.empty()) {
230
231                 rv = *(selection->audio_regions.begin());
232                 (*tv) = &rv->get_time_axis_view();
233                 region = &rv->region;
234
235         } else if (!selection->tracks.empty()) {
236
237                 (*tv) = selection->tracks.front();
238
239                 AudioTimeAxisView* atv;
240
241                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*tv)) != 0) {
242                         Playlist *pl;
243                         
244                         if ((pl = atv->playlist()) == 0) {
245                                 return 0;
246                         }
247                         
248                         region = dynamic_cast<AudioRegion*> (pl->top_region_at (start));
249                 }
250         } 
251         
252         return region;
253 }
254         
255 void
256 Editor::extend_selection_to_end_of_region (bool next)
257 {
258         TimeAxisView *tv;
259         Region *region;
260         jack_nframes_t start;
261
262         if ((region = select_region_for_operation (next ? 1 : 0, &tv)) == 0) {
263                 return;
264         }
265
266         if (region && selection->time.start () == selection->time.end_frame ()) {
267                 start = region->position();
268         } else {
269                 start = selection->time.start ();
270         }
271
272         /* Try to leave the selection with the same route if possible */
273
274         if ((tv = selection->time.track) == 0) {
275                 return;
276         }
277
278         begin_reversible_command (_("extend selection"));
279         selection->set (tv, start, region->position() + region->length());
280         commit_reversible_command ();
281 }
282
283 void
284 Editor::extend_selection_to_start_of_region (bool previous)
285 {
286         TimeAxisView *tv;
287         Region *region;
288         jack_nframes_t end;
289
290         if ((region = select_region_for_operation (previous ? -1 : 0, &tv)) == 0) {
291                 return;
292         }
293
294         if (region && selection->time.start () == selection->time.end_frame ()) {
295                 end = region->position() + region->length();
296         } else {
297                 end = selection->time.end_frame ();
298         }
299
300         /* Try to leave the selection with the same route if possible */
301         
302         if ((tv = selection->time.track) == 0) {
303                 return;
304         }
305
306         begin_reversible_command (_("extend selection"));
307         selection->set (tv, region->position(), end);
308         commit_reversible_command ();
309 }
310
311
312 void
313 Editor::nudge_forward (bool next)
314 {
315         jack_nframes_t distance;
316         jack_nframes_t next_distance;
317
318         if (!session) return;
319         
320         if (!selection->audio_regions.empty()) {
321
322                 begin_reversible_command (_("nudge forward"));
323
324                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
325                         AudioRegion& r ((*i)->region);
326                         
327                         distance = get_nudge_distance (r.position(), next_distance);
328
329                         if (next) {
330                                 distance = next_distance;
331                         }
332
333                         session->add_undo (r.playlist()->get_memento());
334                         r.set_position (r.position() + distance, this);
335                         session->add_redo_no_execute (r.playlist()->get_memento());
336                 }
337
338                 commit_reversible_command ();
339
340         } else {
341                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
342                 session->request_locate (playhead_cursor->current_frame + distance);
343         }
344 }
345                 
346 void
347 Editor::nudge_backward (bool next)
348 {
349         jack_nframes_t distance;
350         jack_nframes_t next_distance;
351
352         if (!session) return;
353         
354         if (!selection->audio_regions.empty()) {
355
356                 begin_reversible_command (_("nudge forward"));
357
358                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
359                         AudioRegion& r ((*i)->region);
360
361                         distance = get_nudge_distance (r.position(), next_distance);
362                         
363                         if (next) {
364                                 distance = next_distance;
365                         }
366
367                         session->add_undo (r.playlist()->get_memento());
368                         
369                         if (r.position() > distance) {
370                                 r.set_position (r.position() - distance, this);
371                         } else {
372                                 r.set_position (0, this);
373                         }
374                         session->add_redo_no_execute (r.playlist()->get_memento());
375                 }
376
377                 commit_reversible_command ();
378
379         } else {
380
381                 distance = get_nudge_distance (playhead_cursor->current_frame, next_distance);
382
383                 if (playhead_cursor->current_frame > distance) {
384                         session->request_locate (playhead_cursor->current_frame - distance);
385                 } else {
386                         session->request_locate (0);
387                 }
388         }
389 }
390
391 void
392 Editor::nudge_forward_capture_offset ()
393 {
394         jack_nframes_t distance;
395
396         if (!session) return;
397         
398         if (!selection->audio_regions.empty()) {
399
400                 begin_reversible_command (_("nudge forward"));
401
402                 distance = session->worst_output_latency();
403
404                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
405                         AudioRegion& r ((*i)->region);
406                         
407                         session->add_undo (r.playlist()->get_memento());
408                         r.set_position (r.position() + distance, this);
409                         session->add_redo_no_execute (r.playlist()->get_memento());
410                 }
411
412                 commit_reversible_command ();
413
414         } 
415 }
416                 
417 void
418 Editor::nudge_backward_capture_offset ()
419 {
420         jack_nframes_t distance;
421
422         if (!session) return;
423         
424         if (!selection->audio_regions.empty()) {
425
426                 begin_reversible_command (_("nudge forward"));
427
428                 distance = session->worst_output_latency();
429
430                 for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
431                         AudioRegion& r ((*i)->region);
432
433                         session->add_undo (r.playlist()->get_memento());
434                         
435                         if (r.position() > distance) {
436                                 r.set_position (r.position() - distance, this);
437                         } else {
438                                 r.set_position (0, this);
439                         }
440                         session->add_redo_no_execute (r.playlist()->get_memento());
441                 }
442
443                 commit_reversible_command ();
444         }
445 }
446
447 /* DISPLAY MOTION */
448
449 void
450 Editor::move_to_start ()
451 {
452         session->request_locate (0);
453 }
454
455 void
456 Editor::move_to_end ()
457 {
458
459         session->request_locate (session->current_end_frame());
460 }
461
462 void
463 Editor::build_region_boundary_cache ()
464 {
465         jack_nframes_t pos = 0;
466         RegionPoint point;
467         Region *r;
468         TrackViewList tracks;
469
470         region_boundary_cache.clear ();
471
472         if (session == 0) {
473                 return;
474         }
475         
476         switch (snap_type) {
477         case SnapToRegionStart:
478                 point = Start;
479                 break;
480         case SnapToRegionEnd:
481                 point = End;
482                 break;  
483         case SnapToRegionSync:
484                 point = SyncPoint;
485                 break;  
486         case SnapToRegionBoundary:
487                 point = Start;
488                 break;  
489         default:
490                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), snap_type) << endmsg;
491                 /*NOTREACHED*/
492                 return;
493         }
494         
495         TimeAxisView *ontrack = 0;
496
497         while (pos < session->current_end_frame()) {
498
499                 if (!selection->tracks.empty()) {
500
501                         if ((r = find_next_region (pos, point, 1, selection->tracks, &ontrack)) == 0) {
502                                 break;
503                         }
504
505                 } else if (clicked_trackview) {
506
507                         TrackViewList t;
508                         t.push_back (clicked_trackview);
509
510                         if ((r = find_next_region (pos, point, 1, t, &ontrack)) == 0) {
511                                 break;
512                         }
513
514                 } else {
515
516                         if ((r = find_next_region (pos, point, 1, track_views, &ontrack)) == 0) {
517                                 break;
518                         }
519                 }
520
521                 jack_nframes_t rpos;
522                 
523                 switch (snap_type) {
524                 case SnapToRegionStart:
525                         rpos = r->first_frame();
526                         break;
527                 case SnapToRegionEnd:
528                         rpos = r->last_frame();
529                         break;  
530                 case SnapToRegionSync:
531                         rpos = r->adjust_to_sync (r->first_frame());
532                         break;
533
534                 case SnapToRegionBoundary:
535                         rpos = r->last_frame();
536                         break;  
537                 default:
538                         break;
539                 }
540                 
541                 float speed = 1.0f;
542                 AudioTimeAxisView *atav;
543
544                 if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
545                         if (atav->get_diskstream() != 0) {
546                                 speed = atav->get_diskstream()->speed();
547                         }
548                 }
549
550                 rpos = (jack_nframes_t) floor ( (float) rpos / speed );
551
552                 if (region_boundary_cache.empty() || rpos != region_boundary_cache.back()) {
553                         if (snap_type == SnapToRegionBoundary) {
554                                 region_boundary_cache.push_back (r->first_frame());
555                         }
556                         region_boundary_cache.push_back (rpos);
557                 }
558
559                 pos = rpos + 1;
560         }
561 }
562
563 Region*
564 Editor::find_next_region (jack_nframes_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
565 {
566         TrackViewList::iterator i;
567         jack_nframes_t closest = max_frames;
568         Region* ret = 0;
569         jack_nframes_t rpos = 0;
570
571         float track_speed;
572         jack_nframes_t track_frame;
573         AudioTimeAxisView *atav;
574
575         for (i = tracks.begin(); i != tracks.end(); ++i) {
576
577                 jack_nframes_t distance;
578                 Region* r;
579
580                 track_speed = 1.0f;
581                 if ( (atav = dynamic_cast<AudioTimeAxisView*>(*i)) != 0 ) {
582                         if (atav->get_diskstream()!=0)
583                                 track_speed = atav->get_diskstream()->speed();
584                 }
585
586                 track_frame = (jack_nframes_t) floor ( (float) frame * track_speed );
587
588                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
589                         continue;
590                 }
591
592                 switch (point) {
593                 case Start:
594                         rpos = r->first_frame ();
595                         break;
596
597                 case End:
598                         rpos = r->last_frame ();
599                         break;
600
601                 case SyncPoint:
602                         rpos = r->adjust_to_sync (r->first_frame());
603                         break;
604                 }
605                 // rpos is a "track frame", converting it to "time frame"
606                 rpos = (jack_nframes_t) floor ( (float) rpos / track_speed );
607
608                 if (rpos > frame) {
609                         distance = rpos - frame;
610                 } else {
611                         distance = frame - rpos;
612                 }
613
614                 if (distance < closest) {
615                         closest = distance;
616                         if (ontrack != 0)
617                                 *ontrack = (*i);
618                         ret = r;
619                 }
620         }
621
622         return ret;
623 }
624
625 void
626 Editor::cursor_to_region_point (Cursor* cursor, RegionPoint point, int32_t dir)
627 {
628         Region* r;
629         jack_nframes_t pos = cursor->current_frame;
630
631         if (!session) {
632                 return;
633         }
634
635         TimeAxisView *ontrack = 0;
636
637         // so we don't find the current region again..
638         if (dir>0 || pos>0)
639                 pos+=dir;
640
641         if (!selection->tracks.empty()) {
642                 
643                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
644                 
645         } else if (clicked_trackview) {
646                 
647                 TrackViewList t;
648                 t.push_back (clicked_trackview);
649                 
650                 r = find_next_region (pos, point, dir, t, &ontrack);
651                 
652         } else {
653                 
654                 r = find_next_region (pos, point, dir, track_views, &ontrack);
655         }
656
657         if (r == 0) {
658                 return;
659         }
660         
661         switch (point){
662         case Start:
663                 pos = r->first_frame ();
664                 break;
665
666         case End:
667                 pos = r->last_frame ();
668                 break;
669
670         case SyncPoint:
671                 pos = r->adjust_to_sync (r->first_frame());
672                 break;  
673         }
674         
675         float speed = 1.0f;
676         AudioTimeAxisView *atav;
677
678         if ( ontrack != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(ontrack)) != 0 ) {
679                 if (atav->get_diskstream() != 0) {
680                         speed = atav->get_diskstream()->speed();
681                 }
682         }
683
684         pos = (jack_nframes_t) floor ( (float) pos / speed );
685         
686         
687         if (cursor == playhead_cursor) {
688                 session->request_locate (pos);
689         } else {
690                 cursor->set_position (pos);
691         }
692 }
693
694 void
695 Editor::cursor_to_next_region_point (Cursor* cursor, RegionPoint point)
696 {
697         cursor_to_region_point (cursor, point, 1);
698 }
699
700 void
701 Editor::cursor_to_previous_region_point (Cursor* cursor, RegionPoint point)
702 {
703         cursor_to_region_point (cursor, point, -1);
704 }
705
706 void
707 Editor::cursor_to_selection_start (Cursor *cursor)
708 {
709         jack_nframes_t pos = 0;
710         switch (mouse_mode) {
711         case MouseObject:
712                 if (!selection->audio_regions.empty()) {
713                         pos = selection->audio_regions.start();
714                 }
715                 break;
716
717         case MouseRange:
718                 if (!selection->time.empty()) {
719                         pos = selection->time.start ();
720                 }
721                 break;
722
723         default:
724                 return;
725         }
726
727         if (cursor == playhead_cursor) {
728                 session->request_locate (pos);
729         } else {
730                 cursor->set_position (pos);
731         }
732 }
733
734 void
735 Editor::cursor_to_selection_end (Cursor *cursor)
736 {
737         jack_nframes_t pos = 0;
738
739         switch (mouse_mode) {
740         case MouseObject:
741                 if (!selection->audio_regions.empty()) {
742                         pos = selection->audio_regions.end_frame();
743                 }
744                 break;
745
746         case MouseRange:
747                 if (!selection->time.empty()) {
748                         pos = selection->time.end_frame ();
749                 }
750                 break;
751
752         default:
753                 return;
754         }
755
756         if (cursor == playhead_cursor) {
757                 session->request_locate (pos);
758         } else {
759                 cursor->set_position (pos);
760         }
761 }
762
763 void
764 Editor::playhead_backward ()
765 {
766         jack_nframes_t pos;
767         jack_nframes_t cnt;
768         float prefix;
769         bool was_floating;
770
771         if (get_prefix (prefix, was_floating)) {
772                 cnt = 1;
773         } else {
774                 if (was_floating) {
775                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
776                 } else {
777                         cnt = (jack_nframes_t) prefix;
778                 }
779         }
780
781         pos = playhead_cursor->current_frame;
782
783         if ((jack_nframes_t) pos < cnt) {
784                 pos = 0;
785         } else {
786                 pos -= cnt;
787         }
788         
789         /* XXX this is completely insane. with the current buffering
790            design, we'll force a complete track buffer flush and
791            reload, just to move 1 sample !!!
792         */
793
794         session->request_locate (pos);
795 }
796
797 void
798 Editor::playhead_forward ()
799 {
800         jack_nframes_t pos;
801         jack_nframes_t cnt;
802         bool was_floating;
803         float prefix;
804
805         if (get_prefix (prefix, was_floating)) {
806                 cnt = 1;
807         } else {
808                 if (was_floating) {
809                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
810                 } else {
811                         cnt = (jack_nframes_t) floor (prefix);
812                 }
813         }
814
815         pos = playhead_cursor->current_frame;
816         
817         /* XXX this is completely insane. with the current buffering
818            design, we'll force a complete track buffer flush and
819            reload, just to move 1 sample !!!
820         */
821
822         session->request_locate (pos+cnt);
823 }
824
825 void
826 Editor::cursor_align (bool playhead_to_edit)
827 {
828         if (playhead_to_edit) {
829                 if (session) {
830                         session->request_locate (edit_cursor->current_frame);
831                 }
832         } else {
833                 edit_cursor->set_position (playhead_cursor->current_frame);
834         }
835 }
836
837 void
838 Editor::edit_cursor_backward ()
839 {
840         jack_nframes_t pos;
841         jack_nframes_t cnt;
842         float prefix;
843         bool was_floating;
844
845         if (get_prefix (prefix, was_floating)) {
846                 cnt = 1;
847         } else {
848                 if (was_floating) {
849                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
850                 } else {
851                         cnt = (jack_nframes_t) prefix;
852                 }
853         }
854
855         pos = edit_cursor->current_frame;
856
857         if ((jack_nframes_t) pos < cnt) {
858                 pos = 0;
859         } else {
860                 pos -= cnt;
861         }
862         
863         edit_cursor->set_position (pos);
864 }
865
866 void
867 Editor::edit_cursor_forward ()
868 {
869         jack_nframes_t pos;
870         jack_nframes_t cnt;
871         bool was_floating;
872         float prefix;
873
874         if (get_prefix (prefix, was_floating)) {
875                 cnt = 1;
876         } else {
877                 if (was_floating) {
878                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate ());
879                 } else {
880                         cnt = (jack_nframes_t) floor (prefix);
881                 }
882         }
883
884         pos = edit_cursor->current_frame;
885         edit_cursor->set_position (pos+cnt);
886 }
887
888 void
889 Editor::goto_frame ()
890 {
891         float prefix;
892         bool was_floating;
893         jack_nframes_t frame;
894
895         if (get_prefix (prefix, was_floating)) {
896                 return;
897         }
898
899         if (was_floating) {
900                 frame = (jack_nframes_t) floor (prefix * session->frame_rate());
901         } else {
902                 frame = (jack_nframes_t) floor (prefix);
903         }
904
905         session->request_locate (frame);
906 }
907
908 void
909 Editor::scroll_backward (float pages)
910 {
911         jack_nframes_t frame;
912         jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
913         bool was_floating;
914         float prefix;
915         jack_nframes_t cnt;
916         
917         if (get_prefix (prefix, was_floating)) {
918                 cnt = (jack_nframes_t) floor (pages * one_page);
919         } else {
920                 if (was_floating) {
921                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
922                 } else {
923                         cnt = (jack_nframes_t) floor (prefix * one_page);
924                 }
925         }
926
927         if (leftmost_frame < cnt) {
928                 frame = 0;
929         } else {
930                 frame = leftmost_frame - cnt;
931         }
932
933         reposition_x_origin (frame);
934 }
935
936 void
937 Editor::scroll_forward (float pages)
938 {
939         jack_nframes_t frame;
940         jack_nframes_t one_page = (jack_nframes_t) rint (canvas_width * frames_per_unit);
941         bool was_floating;
942         float prefix;
943         jack_nframes_t cnt;
944         
945         if (get_prefix (prefix, was_floating)) {
946                 cnt = (jack_nframes_t) floor (pages * one_page);
947         } else {
948                 if (was_floating) {
949                         cnt = (jack_nframes_t) floor (prefix * session->frame_rate());
950                 } else {
951                         cnt = (jack_nframes_t) floor (prefix * one_page);
952                 }
953         }
954
955         if (ULONG_MAX - cnt < leftmost_frame) {
956                 frame = ULONG_MAX - cnt;
957         } else {
958                 frame = leftmost_frame + cnt;
959         }
960
961         reposition_x_origin (frame);
962 }
963
964 void
965 Editor::scroll_tracks_down ()
966 {
967         float prefix;
968         bool was_floating;
969         int cnt;
970
971         if (get_prefix (prefix, was_floating)) {
972                 cnt = 1;
973         } else {
974                 cnt = (int) floor (prefix);
975         }
976
977         Gtk::Adjustment *adj = track_canvas_scroller.get_vadjustment();
978         adj->set_value (adj->get_value() + (cnt * adj->get_page_size()));
979 }
980
981 void
982 Editor::scroll_tracks_up ()
983 {
984         float prefix;
985         bool was_floating;
986         int cnt;
987
988         if (get_prefix (prefix, was_floating)) {
989                 cnt = 1;
990         } else {
991                 cnt = (int) floor (prefix);
992         }
993
994         Gtk::Adjustment *adj = track_canvas_scroller.get_vadjustment();
995         adj->set_value (adj->get_value() - (cnt * adj->get_page_size()));
996 }
997
998 void
999 Editor::scroll_tracks_down_line ()
1000 {
1001         edit_vscrollbar.default_vmotion (0, 10);
1002 }
1003
1004 void
1005 Editor::scroll_tracks_up_line ()
1006 {
1007         edit_vscrollbar.default_vmotion (0, -10);
1008 }
1009
1010 /* ZOOM */
1011
1012 void
1013 Editor::temporal_zoom_step (bool coarser)
1014 {
1015         double nfpu;
1016
1017         nfpu = frames_per_unit;
1018         
1019         if (coarser) { 
1020                 nfpu *= 2.0;
1021         } else { 
1022                 nfpu = max(1.0,(nfpu/2.0));
1023         }
1024
1025         temporal_zoom (nfpu);
1026 }       
1027
1028 void
1029 Editor::temporal_zoom (gdouble fpu)
1030 {
1031         if (!session) return;
1032         
1033         jack_nframes_t current_page = current_page_frames();
1034         jack_nframes_t current_leftmost = leftmost_frame;
1035         jack_nframes_t current_rightmost;
1036         jack_nframes_t current_center;
1037         jack_nframes_t new_page;
1038         jack_nframes_t leftmost_after_zoom = 0;
1039         double nfpu;
1040
1041         nfpu = fpu;
1042         
1043         new_page = (jack_nframes_t) floor (canvas_width * nfpu);
1044
1045         switch (zoom_focus) {
1046         case ZoomFocusLeft:
1047                 leftmost_after_zoom = current_leftmost;
1048                 break;
1049                 
1050         case ZoomFocusRight:
1051                 current_rightmost = leftmost_frame + current_page;
1052                 if (current_rightmost > new_page) {
1053                         leftmost_after_zoom = current_rightmost - new_page;
1054                 } else {
1055                         leftmost_after_zoom = 0;
1056                 }
1057                 break;
1058                 
1059         case ZoomFocusCenter:
1060                 current_center = current_leftmost + (current_page/2); 
1061                 if (current_center > (new_page/2)) {
1062                         leftmost_after_zoom = current_center - (new_page / 2);
1063                 } else {
1064                         leftmost_after_zoom = 0;
1065                 }
1066                 break;
1067                 
1068         case ZoomFocusPlayhead:
1069                 /* try to keep the playhead in the center */
1070                 if (playhead_cursor->current_frame > new_page/2) {
1071                         leftmost_after_zoom = playhead_cursor->current_frame - (new_page/2);
1072                 } else {
1073                         leftmost_after_zoom = 0;
1074                 }
1075                 break;
1076
1077         case ZoomFocusEdit:
1078                 /* try to keep the edit cursor in the center */
1079                 if (edit_cursor->current_frame > leftmost_frame + (new_page/2)) {
1080                         leftmost_after_zoom = edit_cursor->current_frame - (new_page/2);
1081                 } else {
1082                         leftmost_after_zoom = 0;
1083                 }
1084                 break;
1085                 
1086         }
1087  
1088         // leftmost_after_zoom = min (leftmost_after_zoom, session->current_end_frame());
1089
1090 //      begin_reversible_command (_("zoom"));
1091 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), current_leftmost, frames_per_unit));
1092 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_after_zoom, nfpu));
1093 //      commit_reversible_command ();
1094
1095         reposition_and_zoom (leftmost_after_zoom, nfpu);
1096 }       
1097
1098 void
1099 Editor::temporal_zoom_selection ()
1100 {
1101         if (!selection) return;
1102         
1103         if (selection->time.empty()) {
1104                 return;
1105         }
1106
1107         jack_nframes_t start = selection->time[clicked_selection].start;
1108         jack_nframes_t end = selection->time[clicked_selection].end;
1109
1110         temporal_zoom_by_frame (start, end, "zoom to selection");
1111 }
1112
1113 void
1114 Editor::temporal_zoom_session ()
1115 {
1116         if (session) {
1117                 temporal_zoom_by_frame (0, session->current_end_frame(), "zoom to session");
1118         }
1119 }
1120
1121 void
1122 Editor::temporal_zoom_by_frame (jack_nframes_t start, jack_nframes_t end, string op)
1123 {
1124         if (!session) return;
1125
1126         if ((start == 0 && end == 0) || end < start) {
1127                 return;
1128         }
1129
1130         jack_nframes_t range = end - start;
1131
1132         double new_fpu = (double)range / (double)canvas_width;
1133 //      double p2 = 1.0;
1134
1135 //      while (p2 < new_fpu) {
1136 //              p2 *= 2.0;
1137 //      }
1138 //      new_fpu = p2;
1139         
1140         jack_nframes_t new_page = (jack_nframes_t) floor (canvas_width * new_fpu);
1141         jack_nframes_t middle = (jack_nframes_t) floor( (double)start + ((double)range / 2.0f ));
1142         jack_nframes_t new_leftmost = (jack_nframes_t) floor( (double)middle - ((double)new_page/2.0f));
1143
1144         if (new_leftmost > middle) new_leftmost = 0;
1145
1146 //      begin_reversible_command (op);
1147 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1148 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1149 //      commit_reversible_command ();
1150
1151         reposition_and_zoom (new_leftmost, new_fpu);
1152 }
1153
1154 void 
1155 Editor::temporal_zoom_to_frame (bool coarser, jack_nframes_t frame)
1156 {
1157         if (!session) return;
1158         
1159         jack_nframes_t range_before = frame - leftmost_frame;
1160         double new_fpu;
1161         
1162         new_fpu = frames_per_unit;
1163         
1164         if (coarser) { 
1165                 new_fpu *= 2.0;
1166                 range_before *= 2;
1167         } else { 
1168                 new_fpu = max(1.0,(new_fpu/2.0));
1169                 range_before /= 2;
1170         }
1171
1172         if (new_fpu == frames_per_unit) return;
1173
1174         jack_nframes_t new_leftmost = frame - range_before;
1175
1176         if (new_leftmost > frame) new_leftmost = 0;
1177
1178 //      begin_reversible_command (_("zoom to frame"));
1179 //      session->add_undo (bind (mem_fun(*this, &Editor::reposition_and_zoom), leftmost_frame, frames_per_unit));
1180 //      session->add_redo (bind (mem_fun(*this, &Editor::reposition_and_zoom), new_leftmost, new_fpu));
1181 //      commit_reversible_command ();
1182
1183         reposition_and_zoom (new_leftmost, new_fpu);
1184 }
1185
1186 void
1187 Editor::select_all_in_track (bool add)
1188 {
1189         list<Selectable *> touched;
1190
1191         if (!clicked_trackview) {
1192                 return;
1193         }
1194         
1195         clicked_trackview->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1196
1197         if (add) {
1198                 selection->add (touched);
1199         } else {
1200                 selection->set (touched);
1201         }
1202 }
1203
1204 void
1205 Editor::select_all (bool add)
1206 {
1207         list<Selectable *> touched;
1208         
1209         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1210                 if ((*iter)->hidden()) {
1211                         continue;
1212                 }
1213                 (*iter)->get_selectables (0, max_frames, 0, DBL_MAX, touched);
1214         }
1215
1216         if (add) {
1217                 selection->add (touched);
1218         } else {
1219                 selection->set (touched);
1220         }
1221
1222 }
1223
1224 void
1225 Editor::invert_selection_in_track ()
1226 {
1227         list<Selectable *> touched;
1228
1229         if (!clicked_trackview) {
1230                 return;
1231         }
1232         
1233         clicked_trackview->get_inverted_selectables (*selection, touched);
1234         selection->set (touched);
1235 }
1236
1237 void
1238 Editor::invert_selection ()
1239 {
1240         list<Selectable *> touched;
1241         
1242         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1243                 if ((*iter)->hidden()) {
1244                         continue;
1245                 }
1246                 (*iter)->get_inverted_selectables (*selection, touched);
1247         }
1248
1249         selection->set (touched);
1250 }
1251
1252 bool
1253 Editor::select_all_within (jack_nframes_t start, jack_nframes_t end, double top, double bot, bool add)
1254 {
1255         list<Selectable *> touched;
1256         
1257         for (TrackViewList::iterator iter = track_views.begin(); iter != track_views.end(); ++iter) {
1258                 if ((*iter)->hidden()) {
1259                         continue;
1260                 }
1261                 (*iter)->get_selectables (start, end, top, bot, touched);
1262         }
1263
1264         if (add) {
1265                 selection->add (touched);
1266         } else {
1267                 selection->set (touched);
1268         }
1269
1270         return !touched.empty();
1271 }
1272
1273 void
1274 Editor::set_selection_from_punch()
1275 {
1276         Location* location;
1277
1278         if ((location = session->locations()->auto_punch_location()) == 0)  {
1279                 return;
1280         }
1281
1282         set_selection_from_range (*location);
1283 }
1284
1285 void
1286 Editor::set_selection_from_loop()
1287 {
1288         Location* location;
1289
1290         if ((location = session->locations()->auto_loop_location()) == 0)  {
1291                 return;
1292         }
1293
1294         set_selection_from_range (*location);
1295 }
1296
1297 void
1298 Editor::set_selection_from_range (Location& range)
1299 {
1300         if (clicked_trackview == 0) {
1301                 return;
1302         }
1303         
1304         begin_reversible_command (_("set selection from range"));
1305         selection->set (0, range.start(), range.end());
1306         commit_reversible_command ();
1307 }
1308
1309 void
1310 Editor::amplitude_zoom_step (bool in)
1311 {
1312         gdouble zoom = 1.0;
1313
1314         if (in) {
1315                 zoom *= 2.0;
1316         } else {
1317                 if (zoom > 2.0) {
1318                         zoom /= 2.0;
1319                 } else {
1320                         zoom = 1.0;
1321                 }
1322         }
1323
1324 #ifdef FIX_FOR_CANVAS
1325         /* XXX DO SOMETHING */
1326 #endif
1327 }       
1328
1329
1330 /* DELETION */
1331
1332
1333 void
1334 Editor::delete_sample_forward ()
1335 {
1336 }
1337
1338 void
1339 Editor::delete_sample_backward ()
1340 {
1341 }
1342
1343 void
1344 Editor::delete_screen ()
1345 {
1346 }
1347
1348 /* SEARCH */
1349
1350 void
1351 Editor::search_backwards ()
1352 {
1353         /* what ? */
1354 }
1355
1356 void
1357 Editor::search_forwards ()
1358 {
1359         /* what ? */
1360 }
1361
1362 /* MARKS */
1363
1364 void
1365 Editor::jump_forward_to_mark ()
1366 {
1367         if (!session) {
1368                 return;
1369         }
1370         
1371         Location *location = session->locations()->first_location_after (playhead_cursor->current_frame);
1372
1373         if (location) {
1374                 session->request_locate (location->start(), session->transport_rolling());
1375         } else {
1376                 session->request_locate (session->current_end_frame());
1377         }
1378 }
1379
1380 void
1381 Editor::jump_backward_to_mark ()
1382 {
1383         if (!session) {
1384                 return;
1385         }
1386
1387         Location *location = session->locations()->first_location_before (playhead_cursor->current_frame);
1388         
1389         if (location) {
1390                 session->request_locate (location->start(), session->transport_rolling());
1391         } else {
1392                 session->request_locate (0);
1393         }
1394 }
1395
1396 void
1397 Editor::set_mark ()
1398 {
1399         jack_nframes_t pos;
1400         float prefix;
1401         bool was_floating;
1402
1403         if (get_prefix (prefix, was_floating)) {
1404                 pos = session->audible_frame ();
1405         } else {
1406                 if (was_floating) {
1407                         pos = (jack_nframes_t) floor (prefix * session->frame_rate ());
1408                 } else {
1409                         pos = (jack_nframes_t) floor (prefix);
1410                 }
1411         }
1412
1413         session->locations()->add (new Location (pos, 0, "mark", Location::IsMark), true);
1414 }
1415
1416 void
1417 Editor::clear_markers ()
1418 {
1419         if (session) {
1420                 session->begin_reversible_command (_("clear markers"));
1421                 session->add_undo (session->locations()->get_memento());
1422                 session->locations()->clear_markers ();
1423                 session->add_redo_no_execute (session->locations()->get_memento());
1424                 session->commit_reversible_command ();
1425         }
1426 }
1427
1428 void
1429 Editor::clear_ranges ()
1430 {
1431         if (session) {
1432                 session->begin_reversible_command (_("clear ranges"));
1433                 session->add_undo (session->locations()->get_memento());
1434                 
1435                 Location * looploc = session->locations()->auto_loop_location();
1436                 Location * punchloc = session->locations()->auto_punch_location();
1437                 
1438                 session->locations()->clear_ranges ();
1439                 // re-add these
1440                 if (looploc) session->locations()->add (looploc);
1441                 if (punchloc) session->locations()->add (punchloc);
1442                 
1443                 session->add_redo_no_execute (session->locations()->get_memento());
1444                 session->commit_reversible_command ();
1445         }
1446 }
1447
1448 void
1449 Editor::clear_locations ()
1450 {
1451         session->begin_reversible_command (_("clear locations"));
1452         session->add_undo (session->locations()->get_memento());
1453         session->locations()->clear ();
1454         session->add_redo_no_execute (session->locations()->get_memento());
1455         session->commit_reversible_command ();
1456         session->locations()->clear ();
1457 }
1458
1459 /* INSERT/REPLACE */
1460
1461 void
1462 Editor::insert_region_list_drag (AudioRegion& region)
1463 {
1464         gint x, y;
1465         double wx, wy;
1466         double cx, cy;
1467         TimeAxisView *tv;
1468         jack_nframes_t where;
1469         AudioTimeAxisView *atv = 0;
1470         Playlist *playlist;
1471         
1472         track_canvas.get_pointer (x, y);
1473
1474         gnome_canvas_window_to_world (GNOME_CANVAS(track_canvas), x, y, &wx, &wy);
1475         
1476         GdkEvent event;
1477         event.type = GDK_BUTTON_RELEASE;
1478         event.button.x = wx;
1479         event.button.y = wy;
1480         
1481         where = event_frame (&event, &cx, &cy);
1482
1483         if (where < leftmost_frame || where > leftmost_frame + current_page_frames()) {
1484                 /* clearly outside canvas area */
1485                 return;
1486         }
1487         
1488         if ((tv = trackview_by_y_position (cy)) == 0) {
1489                 return;
1490         }
1491         
1492         if ((atv = dynamic_cast<AudioTimeAxisView*>(tv)) == 0) {
1493                 return;
1494         }
1495
1496         if ((playlist = atv->playlist()) == 0) {
1497                 return;
1498         }
1499         
1500         snap_to (where);
1501         
1502         begin_reversible_command (_("insert dragged region"));
1503         session->add_undo (playlist->get_memento());
1504         playlist->add_region (*(new AudioRegion (region)), where, 1.0);
1505         session->add_redo_no_execute (playlist->get_memento());
1506         commit_reversible_command ();
1507 }
1508
1509 void
1510 Editor::insert_region_list_selection (float times)
1511 {
1512         AudioTimeAxisView *tv = 0;
1513         Playlist *playlist;
1514
1515         if (clicked_audio_trackview != 0) {
1516                 tv = clicked_audio_trackview;
1517         } else if (!selection->tracks.empty()) {
1518                 if ((tv = dynamic_cast<AudioTimeAxisView*>(selection->tracks.front())) == 0) {
1519                         return;
1520                 }
1521         } else {
1522                 return;
1523         }
1524
1525         if ((playlist = tv->playlist()) == 0) {
1526                 return;
1527         }
1528         
1529         Gtk::CTree_Helpers::SelectionList& selected = region_list_display.selection();
1530         
1531         if (selected.empty()) {
1532                 return;
1533         }
1534         
1535         Region* region = reinterpret_cast<Region *> (selected.front().get_data ());
1536
1537         begin_reversible_command (_("insert region"));
1538         session->add_undo (playlist->get_memento());
1539         playlist->add_region (*(createRegion (*region)), edit_cursor->current_frame, times);
1540         session->add_redo_no_execute (playlist->get_memento());
1541         commit_reversible_command ();
1542 }
1543
1544
1545 /* BUILT-IN EFFECTS */
1546
1547 void
1548 Editor::reverse_selection ()
1549 {
1550
1551 }
1552
1553 /* GAIN ENVELOPE EDITING */
1554
1555 void
1556 Editor::edit_envelope ()
1557 {
1558 }
1559
1560 /* PLAYBACK */
1561
1562 void
1563 Editor::toggle_playback (bool with_abort)
1564 {
1565         if (!session) {
1566                 return;
1567         }
1568
1569         switch (session->slave_source()) {
1570         case Session::None:
1571         case Session::JACK:
1572                 break;
1573         default:
1574                 /* transport controlled by the master */
1575                 return;
1576         }
1577
1578         if (session->is_auditioning()) {
1579                 session->cancel_audition ();
1580                 return;
1581         }
1582         
1583         if (session->transport_rolling()) {
1584                 session->request_stop (with_abort);
1585                 if (session->get_auto_loop()) {
1586                         session->request_auto_loop (false);
1587                 }
1588         } else {
1589                 session->request_transport_speed (1.0f);
1590         }
1591 }
1592
1593 void
1594 Editor::play_from_start ()
1595 {
1596         session->request_locate (0, true);
1597 }
1598
1599 void
1600 Editor::play_selection ()
1601 {
1602         if (selection->time.empty()) {
1603                 return;
1604         }
1605
1606         session->request_play_range (true);
1607 }
1608
1609 void
1610 Editor::play_selected_region ()
1611 {
1612         if (!selection->audio_regions.empty()) {
1613                 AudioRegionView *rv = *(selection->audio_regions.begin());
1614
1615                 session->request_bounded_roll (rv->region.position(), rv->region.last_frame()); 
1616         }
1617 }
1618
1619 void
1620 Editor::toggle_loop_playback ()
1621 {
1622         if (session) {
1623                 session->request_auto_loop (true);
1624         }
1625 }
1626
1627 void
1628 Editor::loop_selected_region ()
1629 {
1630         if (!selection->audio_regions.empty()) {
1631                 AudioRegionView *rv = *(selection->audio_regions.begin());
1632                 Location* tll;
1633
1634                 if ((tll = transport_loop_location()) != 0)  {
1635
1636                         tll->set (rv->region.position(), rv->region.last_frame());
1637                         
1638                         // enable looping, reposition and start rolling
1639
1640                         session->request_auto_loop (true);
1641                         session->request_locate (tll->start(), false);
1642                         session->request_transport_speed (1.0f);
1643                 }
1644         }
1645 }
1646
1647 void
1648 Editor::play_location (Location& location)
1649 {
1650         if (location.start() <= location.end()) {
1651                 return;
1652         }
1653
1654         session->request_bounded_roll (location.start(), location.end());
1655 }
1656
1657 void
1658 Editor::loop_location (Location& location)
1659 {
1660         if (location.start() <= location.end()) {
1661                 return;
1662         }
1663
1664         Location* tll;
1665
1666         if ((tll = transport_loop_location()) != 0) {
1667                 tll->set (location.start(), location.end());
1668
1669                 // enable looping, reposition and start rolling
1670                 session->request_auto_loop (true);
1671                 session->request_locate (tll->start(), true);
1672         }
1673 }
1674
1675 void 
1676 Editor::toggle_region_mute ()
1677 {
1678         if (clicked_regionview) {
1679                 clicked_regionview->region.set_muted (!clicked_regionview->region.muted());
1680         } else if (!selection->audio_regions.empty()) {
1681                 bool yn = ! (*selection->audio_regions.begin())->region.muted();
1682                 selection->foreach_audio_region (&AudioRegion::set_muted, yn);
1683         }
1684 }
1685
1686 void
1687 Editor::toggle_region_opaque ()
1688 {
1689         if (clicked_regionview) {
1690                 clicked_regionview->region.set_opaque (!clicked_regionview->region.opaque());
1691         } else if (!selection->audio_regions.empty()) {
1692                 bool yn = ! (*selection->audio_regions.begin())->region.opaque();
1693                 selection->foreach_audio_region (&Region::set_opaque, yn);
1694         }
1695 }
1696
1697 void
1698 Editor::raise_region ()
1699 {
1700         selection->foreach_audio_region (&Region::raise);
1701 }
1702
1703 void
1704 Editor::raise_region_to_top ()
1705 {
1706         selection->foreach_audio_region (&Region::raise_to_top);
1707 }
1708
1709 void
1710 Editor::lower_region ()
1711 {
1712         selection->foreach_audio_region (&Region::lower);
1713 }
1714
1715 void
1716 Editor::lower_region_to_bottom ()
1717 {
1718         selection->foreach_audio_region (&Region::lower_to_bottom);
1719 }
1720
1721 void
1722 Editor::edit_region ()
1723 {
1724         if (clicked_regionview == 0) {
1725                 return;
1726         }
1727         
1728         clicked_regionview->show_region_editor ();
1729 }
1730
1731 void
1732 Editor::rename_region ()
1733 {
1734         Dialog dialog;
1735         Entry  entry;
1736         Button ok_button (_("OK"));
1737         Button cancel_button (_("Cancel"));
1738
1739         if (selection->audio_regions.empty()) {
1740                 return;
1741         }
1742
1743         dialog.set_title (_("ardour: rename region"));
1744         dialog.set_name ("RegionRenameWindow");
1745         dialog.set_size_request (300, -1);
1746         dialog.set_position (Gtk::WIN_POS_MOUSE);
1747         dialog.set_modal (true);
1748
1749         dialog.get_vbox()->set_border_width (10);
1750         dialog.get_vbox()->pack_start (entry);
1751         dialog.get_action_area()->pack_start (ok_button);
1752         dialog.get_action_area()->pack_start (cancel_button);
1753
1754         entry.set_name ("RegionNameDisplay");
1755         ok_button.set_name ("EditorGTKButton");
1756         cancel_button.set_name ("EditorGTKButton");
1757
1758         region_renamed = false;
1759
1760         entry.signal_activate().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1761         ok_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), true));
1762         cancel_button.signal_clicked().connect (bind (mem_fun(*this, &Editor::rename_region_finished), false));
1763
1764         /* recurse */
1765
1766         dialog.show_all ();
1767         ARDOUR_UI::instance()->allow_focus (true);
1768         Main::run ();
1769         ARDOUR_UI::instance()->allow_focus (false);
1770
1771         if (region_renamed) {
1772                 (*selection->audio_regions.begin())->region.set_name (entry.get_text());
1773                 redisplay_regions ();
1774         }
1775 }
1776
1777 void
1778 Editor::rename_region_finished (bool status)
1779
1780 {
1781         region_renamed = status;
1782         Main::quit ();
1783 }
1784
1785 void
1786 Editor::audition_playlist_region_via_route (AudioRegion& region, Route& route)
1787 {
1788         if (session->is_auditioning()) {
1789                 session->cancel_audition ();
1790         } 
1791
1792         // note: some potential for creativity here, because region doesn't
1793         // have to belong to the playlist that Route is handling
1794
1795         // bool was_soloed = route.soloed();
1796
1797         route.set_solo (true, this);
1798         
1799         session->request_bounded_roll (region.position(), region.position() + region.length());
1800         
1801         /* XXX how to unset the solo state ? */
1802 }
1803
1804 void
1805 Editor::audition_selected_region ()
1806 {
1807         if (!selection->audio_regions.empty()) {
1808                 AudioRegionView* rv = *(selection->audio_regions.begin());
1809                 session->audition_region (rv->region);
1810         }
1811 }
1812
1813 void
1814 Editor::audition_playlist_region_standalone (AudioRegion& region)
1815 {
1816         session->audition_region (region);
1817 }
1818
1819 void
1820 Editor::build_interthread_progress_window ()
1821 {
1822         interthread_progress_window = new ArdourDialog (X_("interthread progress"));
1823
1824         interthread_progress_bar.set_orientation (Gtk::PROGRESS_LEFT_TO_RIGHT);
1825         
1826         interthread_progress_vbox.set_border_width (10);
1827         interthread_progress_vbox.set_spacing (5);
1828         interthread_progress_vbox.pack_start (interthread_progress_label, false, false);
1829         interthread_progress_vbox.pack_start (interthread_progress_bar,false, false);
1830         interthread_progress_vbox.pack_start (interthread_cancel_button,false, false);
1831
1832         interthread_cancel_button.add (interthread_cancel_label);
1833
1834         interthread_cancel_button.signal_clicked().connect (mem_fun(*this, &Editor::interthread_cancel_clicked));
1835         
1836         interthread_progress_window->set_modal (true);
1837         interthread_progress_window->set_default_size (200, 100);
1838         interthread_progress_window->add (interthread_progress_vbox);
1839 }
1840
1841 void
1842 Editor::interthread_cancel_clicked ()
1843 {
1844         if (current_interthread_info) {
1845                 current_interthread_info->cancel = true;
1846         }
1847 }
1848
1849 void *
1850 Editor::_import_thread (void *arg)
1851 {
1852         PBD::ThreadCreated (pthread_self(), X_("Import"));
1853
1854         Editor *ed = (Editor *) arg;
1855         return ed->import_thread ();
1856 }
1857
1858 void *
1859 Editor::import_thread ()
1860 {
1861         session->import_audiofile (import_status);
1862         return 0;
1863 }
1864
1865 gint
1866 Editor::import_progress_timeout (void *arg)
1867 {
1868         interthread_progress_label.set_text (import_status.doing_what);
1869
1870         if (import_status.freeze) {
1871                 interthread_cancel_button.set_sensitive(false);
1872         } else {
1873                 interthread_cancel_button.set_sensitive(true);
1874         }
1875
1876         if (import_status.doing_what == "building peak files") {
1877                 interthread_progress_bar.set_activity_mode (true);
1878                 return FALSE;
1879         } else {
1880                 interthread_progress_bar.set_fraction (import_status.progress/100);
1881         }
1882
1883         return !(import_status.done || import_status.cancel);
1884 }
1885
1886 void
1887 Editor::import_audio (bool as_tracks)
1888 {
1889         if (session == 0) {
1890                 warning << _("You can't import an audiofile until you have a session loaded.") << endmsg;
1891                 return;
1892         }
1893
1894         string str;
1895
1896         if (as_tracks) {
1897                 str =_("Import selected as tracks");
1898         } else {
1899                 str = _("Import selected to region list");
1900         }
1901
1902         SoundFileOmega sfdb (str);
1903         sfdb.Imported.connect (bind (mem_fun (*this, &Editor::do_import), as_tracks));
1904
1905         sfdb.run();
1906 }
1907
1908 void
1909 Editor::catch_new_audio_region (AudioRegion* ar)
1910 {
1911         last_audio_region = ar;
1912 }
1913
1914 void
1915 Editor::do_import (vector<string> paths, bool split, bool as_tracks)
1916 {
1917         sigc::connection c;
1918         
1919         /* SFDB sets "multichan" to true to indicate "split channels"
1920            so reverse the setting to match the way libardour
1921            interprets it.
1922         */
1923         
1924         import_status.multichan = !split;
1925
1926         if (interthread_progress_window == 0) {
1927                 build_interthread_progress_window ();
1928         }
1929         
1930         interthread_progress_window->set_title (_("ardour: audio import in progress"));
1931         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
1932         interthread_progress_window->show_all ();
1933         interthread_progress_bar.set_fraction (0.0f);
1934         interthread_cancel_label.set_text (_("Cancel Import"));
1935         current_interthread_info = &import_status;
1936
1937         c = session->AudioRegionAdded.connect (mem_fun(*this, &Editor::catch_new_audio_region));
1938
1939         for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i ) {
1940
1941                 interthread_progress_window->set_title (string_compose (_("ardour: importing %1"), (*i)));
1942         
1943                 import_status.pathname = (*i);
1944                 import_status.done = false;
1945                 import_status.cancel = false;
1946                 import_status.freeze = false;
1947                 import_status.done = 0.0;
1948                 
1949                 interthread_progress_connection = 
1950                   Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::import_progress_timeout), (gpointer) 0), 100);
1951                 
1952                 last_audio_region = 0;
1953                 
1954                 pthread_create_and_store ("import", &import_status.thread, 0, _import_thread, this);
1955                 pthread_detach (import_status.thread);
1956                 
1957                 while (!(import_status.done || import_status.cancel)) {
1958                         gtk_main_iteration ();
1959                 }
1960                 
1961                 import_status.done = true;
1962                 interthread_progress_connection.disconnect ();
1963
1964                 if (as_tracks && last_audio_region != 0) {
1965                         uint32_t channels = last_audio_region->n_channels();
1966
1967                         AudioTrack* at = session->new_audio_track (channels, channels);
1968                         AudioRegion* copy = new AudioRegion (*last_audio_region);
1969                         at->disk_stream().playlist()->add_region (*copy, 0);
1970                 }
1971         }
1972
1973         c.disconnect ();
1974         interthread_progress_window->hide_all ();
1975 }
1976
1977 int
1978 Editor::reject_because_rate_differs (string path, SF_INFO& finfo, string action, bool multiple_pending)
1979 {
1980         if (!session) {
1981                 return 1;
1982         }
1983
1984         if (finfo.samplerate != (int) session->frame_rate()) {
1985                 vector<string> choices;
1986
1987                 choices.push_back (string_compose (_("%1 it anyway"), action));
1988
1989                 if (multiple_pending) {
1990                         /* XXX assumptions about sentence structure
1991                            here for translators. Sorry.
1992                         */
1993                         choices.push_back (string_compose (_("Don't %1 it"), action));
1994                         choices.push_back (string_compose (_("%1 all without questions"), action));
1995                         choices.push_back (_("Cancel entire import"));
1996                 } else {
1997                         choices.push_back (_("Cancel"));
1998                 }
1999
2000                 Gtkmm2ext::Choice rate_choice (
2001                         string_compose (_("%1\nThis audiofile's sample rate doesn't match the session sample rate!"), path),
2002                         choices);
2003
2004                 rate_choice.chosen.connect (Main::quit.slot());
2005                 rate_choice.show_all ();
2006
2007                 Main::run ();
2008
2009                 switch (rate_choice.get_choice()) {
2010                 case 0: /* do it anyway */
2011                         return 0;
2012                 case 1: /* don't import this one */
2013                         return 1;
2014                 case 2: /* do the rest without asking */
2015                         return -1;
2016                 case 3: /* stop a multi-file import */
2017                 default:
2018                         return -2;
2019                 }
2020         }
2021
2022         return 0;
2023 }
2024
2025 void 
2026 Editor::embed_audio ()
2027 {
2028         if (session == 0) {
2029                 warning << _("You can't embed an audiofile until you have a session loaded.") << endmsg;
2030                 return;
2031         }
2032
2033         SoundFileOmega sfdb (_("Add to External Region list"));
2034         sfdb.Embedded.connect (mem_fun (*this, &Editor::do_embed_sndfiles));
2035
2036         sfdb.run ();
2037 }
2038
2039 void
2040 Editor::do_embed_sndfiles (vector<string> paths, bool split)
2041 {
2042         bool multiple_files = paths.size() > 1;
2043         bool check_sample_rate = true;
2044
2045         for (vector<string>::iterator i = paths.begin(); i != paths.end(); ++i) {
2046                 embed_sndfile (*i, split, multiple_files, check_sample_rate);
2047         }
2048
2049         session->save_state ("");
2050 }
2051
2052 void
2053 Editor::embed_sndfile (string path, bool split, bool multiple_files, bool& check_sample_rate)
2054 {
2055         SndFileSource *source = 0; /* keep g++ quiet */
2056         AudioRegion::SourceList sources;
2057         string idspec;
2058         string linked_path;
2059         SNDFILE *sf;
2060         SF_INFO finfo;
2061
2062         /* lets see if we can link it into the session */
2063         
2064         linked_path = session->sound_dir();
2065         linked_path += PBD::basename (path);
2066
2067         if (link (path.c_str(), linked_path.c_str()) == 0) {
2068
2069                 /* there are many reasons why link(2) might have failed.
2070                    but if it succeeds, we now have a link in the
2071                    session sound dir that will protect against
2072                    unlinking of the original path. nice.
2073                 */
2074
2075                 path = linked_path;
2076         }
2077
2078         memset (&finfo, 0, sizeof(finfo));
2079
2080         /* note that we temporarily truncated _id at the colon */
2081         
2082         if ((sf = sf_open (path.c_str(), SFM_READ, &finfo)) == 0) {
2083                 char errbuf[256];
2084                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2085                 error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), selection, errbuf) << endmsg;
2086                 return;
2087         }
2088         sf_close (sf);
2089         sf = 0;
2090         
2091         if (check_sample_rate) {
2092                 switch (reject_because_rate_differs (path, finfo, "Embed", multiple_files)) {
2093                 case 0:
2094                         break;
2095                 case 1:
2096                         return;
2097                 case -1:
2098                         check_sample_rate = false;
2099                         break;
2100                         
2101                 case -2:
2102                 default:
2103                         return;
2104                 }
2105         }
2106
2107         track_canvas_scroller.get_window()->set_cursor (GDK_WATCH);
2108         ARDOUR_UI::instance()->flush_pending ();
2109
2110         /* make the proper number of channels in the region */
2111
2112         for (int n=0; n < finfo.channels; ++n)
2113         {
2114                 idspec = path;
2115                 idspec += string_compose(":%1", n);
2116                 
2117                 try {
2118                         source = new SndFileSource (idspec.c_str());
2119                         sources.push_back(source);
2120                 } 
2121
2122                 catch (failed_constructor& err) {
2123                         error << string_compose(_("could not open %1"), path) << endmsg;
2124                         goto out;
2125                 }
2126
2127                 ARDOUR_UI::instance()->flush_pending ();
2128         }
2129
2130         if (sources.size() > 0) {
2131
2132                 string region_name = PBD::basename_nosuffix (path);
2133                 region_name += "-0";
2134
2135                 /* The created region isn't dropped.  It emits a signal
2136                    that is picked up by the session. 
2137                 */
2138
2139                 new AudioRegion (sources, 0, sources[0]->length(), region_name, 0,
2140                                  Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External));
2141                 
2142                 /* make sure we can see it in the list */
2143
2144                 Gtk::CTree_Helpers::RowList::iterator external_node;
2145                 external_node = region_list_display.rows().begin();
2146                 ++external_node; /* its the second node, always */
2147                 external_node->expand_recursive ();
2148
2149                 ARDOUR_UI::instance()->flush_pending ();
2150         }
2151
2152   out:
2153         track_canvas_scroller.get_window()->set_cursor (current_canvas_cursor);
2154 }
2155
2156 void
2157 Editor::insert_sndfile (bool as_tracks)
2158 {
2159 //      SoundFileSelector& sfdb (ARDOUR_UI::instance()->get_sfdb_window());
2160         sigc::connection c;
2161         string str;
2162
2163         if (as_tracks) {
2164
2165 //              c = sfdb.Action.connect (mem_fun(*this, &Editor::insert_paths_as_new_tracks));
2166                 str = _("Insert selected as new tracks");
2167
2168         } else {
2169
2170                 jack_nframes_t pos;
2171
2172                 if (clicked_audio_trackview == 0) {
2173                         return;
2174                 }
2175
2176                 if (ensure_cursor (&pos)) {
2177                         return;
2178                 }
2179
2180 //              c = sfdb.Action.connect (bind (mem_fun(*this, &Editor::do_insert_sndfile), pos));
2181                 str = _("Insert selected");
2182         }
2183
2184 //      sfdb.run (str, false);
2185 //      c.disconnect ();
2186 }
2187
2188 void
2189 Editor::insert_paths_as_new_tracks (vector<string> paths, bool split)
2190 {
2191         SNDFILE *sf;
2192         SF_INFO finfo;
2193         bool multiple_files;
2194         bool check_sample_rate = true;
2195
2196         multiple_files = paths.size() > 1;      
2197
2198         for (vector<string>::iterator p = paths.begin(); p != paths.end(); ++p) {
2199                 
2200                 memset (&finfo, 0, sizeof(finfo));
2201                 
2202                 if ((sf = sf_open ((*p).c_str(), SFM_READ, &finfo)) == 0) {
2203                         char errbuf[256];
2204                         sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2205                         error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), (*p), errbuf) << endmsg;
2206                         continue;
2207                 }
2208                 
2209                 sf_close (sf);
2210                 sf = 0;
2211                 
2212                 /* add a new track */
2213                 
2214                 if (check_sample_rate) {
2215                         switch (reject_because_rate_differs (*p, finfo, "Insert", multiple_files)) {
2216                         case 0:
2217                                 break;
2218                         case 1:
2219                                 continue;
2220                         case -1:
2221                                 check_sample_rate = false;
2222                                 break;
2223                                 
2224                         case -2:
2225                                 return;
2226                         }
2227                 }
2228                 
2229                 uint32_t input_chan = finfo.channels;
2230                 uint32_t output_chan;
2231                 
2232                 if (session->get_output_auto_connect() & Session::AutoConnectMaster) {
2233                         output_chan = (session->master_out() ? session->master_out()->n_inputs() : input_chan);
2234                 } else {
2235                         output_chan = input_chan;
2236                 }
2237                 
2238                 (void) session->new_audio_track (input_chan, output_chan);
2239
2240
2241                 /* get the last (most recently added) track view */
2242         
2243                 AudioTimeAxisView* tv;
2244         
2245                 if ((tv = dynamic_cast<AudioTimeAxisView*>(track_views.back())) == 0) {
2246                         fatal << _("programming error: ")
2247                               << X_("last trackview after new_audio_track is not an audio track!")
2248                               << endmsg;
2249                         /*NOTREACHED*/
2250                 }
2251                 
2252                 jack_nframes_t pos = 0;
2253                 insert_sndfile_into (*p, true, tv, pos, false);
2254         }
2255 }
2256
2257 void
2258 Editor::do_insert_sndfile (vector<string> paths, bool split, jack_nframes_t pos)
2259 {
2260         for (vector<string>::iterator x = paths.begin(); x != paths.end(); ++x) {
2261                 insert_sndfile_into (*x, !split, clicked_audio_trackview, pos);
2262         }
2263 }
2264
2265 void
2266 Editor::insert_sndfile_into (string path, bool multi, AudioTimeAxisView* tv, jack_nframes_t& pos, bool prompt)
2267 {
2268         SndFileSource *source = 0; /* keep g++ quiet */
2269         AudioRegion::SourceList sources;
2270         string idspec;
2271         SNDFILE *sf;
2272         SF_INFO finfo;
2273
2274         memset (&finfo, 0, sizeof(finfo));
2275
2276         /* note that we temporarily truncated _id at the colon */
2277         
2278         if ((sf = sf_open (path.c_str(), SFM_READ, &finfo)) == 0) {
2279                 char errbuf[256];
2280                 sf_error_str (0, errbuf, sizeof (errbuf) - 1);
2281                 error << string_compose(_("Editor: cannot open file \"%1\" (%2)"), path, errbuf) << endmsg;
2282                 return;
2283         }
2284         sf_close (sf);
2285         sf = 0;
2286         
2287         if (prompt && (reject_because_rate_differs (path, finfo, "Insert", false) != 0)) {
2288                 return;
2289         }
2290
2291         track_canvas_scroller.get_window()->set_cursor (GDK_WATCH);
2292         ARDOUR_UI::instance()->flush_pending ();
2293
2294         /* make the proper number of channels in the region */
2295
2296         for (int n=0; n < finfo.channels; ++n)
2297         {
2298                 idspec = path;
2299                 idspec += string_compose(":%1", n);
2300
2301                 try {
2302                         source = new SndFileSource (idspec.c_str());
2303                         sources.push_back(source);
2304                 } 
2305
2306                 catch (failed_constructor& err) {
2307                         error << string_compose(_("could not open %1"), path) << endmsg;
2308                         goto out;
2309                 }
2310
2311                 ARDOUR_UI::instance()->flush_pending ();
2312         }
2313
2314         if (sources.size() > 0) {
2315
2316                 string region_name = region_name_from_path (PBD::basename (path));
2317                 
2318                 AudioRegion *region = new AudioRegion (sources, 0, sources[0]->length(), region_name, 
2319                                                        0, /* irrelevant these days */
2320                                                        Region::Flag (Region::DefaultFlags|Region::WholeFile|Region::External));
2321
2322                 begin_reversible_command (_("insert sndfile"));
2323                 session->add_undo (tv->playlist()->get_memento());
2324                 tv->playlist()->add_region (*region, pos);
2325                 session->add_redo_no_execute (tv->playlist()->get_memento());
2326                 commit_reversible_command ();
2327                 
2328                 pos += sources[0]->length();
2329
2330                 ARDOUR_UI::instance()->flush_pending ();
2331         }
2332
2333   out:
2334         track_canvas_scroller.get_window()->set_cursor (current_canvas_cursor);
2335         return;
2336 }
2337
2338 void
2339 Editor::region_from_selection ()
2340 {
2341         if (clicked_trackview == 0) {
2342                 return;
2343         }
2344
2345         if (selection->time.empty()) {
2346                 return;
2347         }
2348
2349         jack_nframes_t start = selection->time[clicked_selection].start;
2350         jack_nframes_t end = selection->time[clicked_selection].end;
2351
2352         jack_nframes_t selection_cnt = end - start + 1;
2353         
2354         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2355
2356                 AudioRegion *region;
2357                 AudioRegion *current;
2358                 Region* current_r;
2359                 Playlist *pl;
2360
2361                 jack_nframes_t internal_start;
2362                 string new_name;
2363
2364                 if ((pl = (*i)->playlist()) == 0) {
2365                         continue;
2366                 }
2367
2368                 if ((current_r = pl->top_region_at (start)) == 0) {
2369                         continue;
2370                 }
2371
2372                 if ((current = dynamic_cast<AudioRegion*> (current_r)) != 0) {
2373                         internal_start = start - current->position();
2374                         session->region_name (new_name, current->name(), true);
2375                         region = new AudioRegion (*current, internal_start, selection_cnt, new_name);
2376                 }
2377         }
2378 }       
2379
2380 void
2381 Editor::create_region_from_selection (vector<AudioRegion *>& new_regions)
2382 {
2383         if (selection->time.empty() || selection->tracks.empty()) {
2384                 return;
2385         }
2386
2387         jack_nframes_t start = selection->time[clicked_selection].start;
2388         jack_nframes_t end = selection->time[clicked_selection].end;
2389         
2390         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2391
2392                 AudioRegion* current;
2393                 Region* current_r;
2394                 Playlist* playlist;
2395                 jack_nframes_t internal_start;
2396                 string new_name;
2397
2398                 if ((playlist = (*i)->playlist()) == 0) {
2399                         continue;
2400                 }
2401
2402                 if ((current_r = playlist->top_region_at(start)) == 0) {
2403                         continue;
2404                 }
2405
2406                 if ((current = dynamic_cast<AudioRegion*>(current_r)) == 0) {
2407                         continue;
2408                 }
2409         
2410                 internal_start = start - current->position();
2411                 session->region_name (new_name, current->name(), true);
2412                 
2413                 new_regions.push_back (new AudioRegion (*current, internal_start, end - start + 1, new_name));
2414         }
2415 }
2416
2417 void
2418 Editor::split_multichannel_region ()
2419 {
2420         vector<AudioRegion*> v;
2421
2422         if (!clicked_regionview || clicked_regionview->region.n_channels() < 2) {
2423                 return;
2424         }
2425
2426         clicked_regionview->region.separate_by_channel (*session, v);
2427
2428         /* nothing else to do, really */
2429 }
2430
2431 void
2432 Editor::new_region_from_selection ()
2433 {
2434         region_from_selection ();
2435         cancel_selection ();
2436 }
2437
2438 void
2439 Editor::separate_region_from_selection ()
2440 {
2441         bool doing_undo = false;
2442
2443         if (selection->time.empty()) {
2444                 return;
2445         }
2446
2447         Playlist *playlist;
2448                 
2449         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2450
2451                 AudioTimeAxisView* atv;
2452
2453                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2454
2455                         if (atv->is_audio_track()) {
2456                                         
2457                                 if ((playlist = atv->playlist()) != 0) {
2458                                         if (!doing_undo) {
2459                                                 begin_reversible_command (_("separate"));
2460                                                 doing_undo = true;
2461                                         }
2462                                         if (doing_undo) session->add_undo ((playlist)->get_memento());
2463                         
2464                                         /* XXX need to consider musical time selections here at some point */
2465
2466                                         double speed = atv->get_diskstream()->speed();
2467
2468                                         for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2469                                                 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2470                                         }
2471
2472                                         if (doing_undo) session->add_redo_no_execute (playlist->get_memento());
2473                                 }
2474                         }
2475                 }
2476         }
2477
2478         if (doing_undo) commit_reversible_command ();
2479 }
2480
2481 void
2482 Editor::crop_region_to_selection ()
2483 {
2484         if (selection->time.empty()) {
2485                 return;
2486         }
2487
2488         vector<Playlist*> playlists;
2489         Playlist *playlist;
2490
2491         if (clicked_trackview != 0) {
2492
2493                 if ((playlist = clicked_trackview->playlist()) == 0) {
2494                         return;
2495                 }
2496
2497                 playlists.push_back (playlist);
2498
2499         } else {
2500                 
2501                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2502
2503                         AudioTimeAxisView* atv;
2504
2505                         if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2506
2507                                 if (atv->is_audio_track()) {
2508                                         
2509                                         if ((playlist = atv->playlist()) != 0) {
2510                                                 playlists.push_back (playlist);
2511                                         }
2512                                 }
2513                         }
2514                 }
2515         }
2516
2517         if (!playlists.empty()) {
2518
2519                 jack_nframes_t start;
2520                 jack_nframes_t end;
2521                 jack_nframes_t cnt;
2522
2523                 begin_reversible_command (_("trim to selection"));
2524
2525                 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2526                         
2527                         Region *region;
2528                         
2529                         start = selection->time.start();
2530
2531                         if ((region = (*i)->top_region_at(start)) == 0) {
2532                                 continue;
2533                         }
2534                         
2535                         /* now adjust lengths to that we do the right thing
2536                            if the selection extends beyond the region
2537                         */
2538                         
2539                         start = max (start, region->position());
2540                         end = min (selection->time.end_frame(), start + region->length() - 1);
2541                         cnt = end - start + 1;
2542
2543                         session->add_undo ((*i)->get_memento());
2544                         region->trim_to (start, cnt, this);
2545                         session->add_redo_no_execute ((*i)->get_memento());
2546                 }
2547
2548                 commit_reversible_command ();
2549         }
2550 }               
2551
2552 void
2553 Editor::region_fill_track ()
2554 {
2555         jack_nframes_t end;
2556
2557         if (!session || selection->audio_regions.empty()) {
2558                 return;
2559         }
2560
2561         end = session->current_end_frame ();
2562
2563         begin_reversible_command (_("region fill"));
2564
2565         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2566
2567                 AudioRegion& region ((*i)->region);
2568                 Playlist* pl = region.playlist();
2569
2570                 if (end <= region.last_frame()) {
2571                         return;
2572                 }
2573
2574                 double times = (double) (end - region.last_frame()) / (double) region.length();
2575
2576                 if (times == 0) {
2577                         return;
2578                 }
2579
2580                 session->add_undo (pl->get_memento());
2581                 pl->add_region (*(new AudioRegion (region)), region.last_frame(), times);
2582                 session->add_redo_no_execute (pl->get_memento());
2583         }
2584
2585         commit_reversible_command ();
2586 }
2587
2588 void
2589 Editor::region_fill_selection ()
2590 {
2591         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2592                 return;
2593         }
2594
2595         if (selection->time.empty()) {
2596                 return;
2597         }
2598
2599         Region *region;
2600
2601         Gtk::CTree_Helpers::SelectionList& selected = region_list_display.selection();
2602         
2603         if (selected.empty()) {
2604                 return;
2605         }
2606
2607         region = reinterpret_cast<Region *> (selected.front().get_data());
2608
2609         jack_nframes_t start = selection->time[clicked_selection].start;
2610         jack_nframes_t end = selection->time[clicked_selection].end;
2611
2612         Playlist *playlist; 
2613
2614         if (selection->tracks.empty()) {
2615                 return;
2616         }
2617
2618         jack_nframes_t selection_length = end - start;
2619         float times = (float)selection_length / region->length();
2620         
2621         begin_reversible_command (_("fill selection"));
2622         
2623         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2624
2625                 if ((playlist = (*i)->playlist()) == 0) {
2626                         continue;
2627                 }               
2628                 
2629                 session->add_undo (playlist->get_memento());
2630                 playlist->add_region (*(createRegion (*region)), start, times);
2631                 session->add_redo_no_execute (playlist->get_memento());
2632         }
2633         
2634         commit_reversible_command ();                   
2635 }
2636         
2637 void
2638 Editor::set_region_sync_from_edit_cursor ()
2639 {
2640         if (clicked_regionview == 0) {
2641                 return;
2642         }
2643
2644         if (!clicked_regionview->region.covers (edit_cursor->current_frame)) {
2645                 error << _("Place the edit cursor at the desired sync point") << endmsg;
2646                 return;
2647         }
2648
2649         Region& region (clicked_regionview->region);
2650
2651         begin_reversible_command (_("set sync from edit cursor"));
2652         session->add_undo (region.playlist()->get_memento());
2653         region.set_sync_position (edit_cursor->current_frame);
2654         session->add_redo_no_execute (region.playlist()->get_memento());
2655         commit_reversible_command ();
2656 }
2657
2658 void
2659 Editor::remove_region_sync ()
2660 {
2661         if (clicked_regionview) {
2662                 Region& region (clicked_regionview->region);
2663                 begin_reversible_command (_("remove sync"));
2664                 session->add_undo (region.playlist()->get_memento());
2665                 region.clear_sync_position ();
2666                 session->add_redo_no_execute (region.playlist()->get_memento());
2667                 commit_reversible_command ();
2668         }
2669 }
2670
2671 void
2672 Editor::naturalize ()
2673 {
2674         if (selection->audio_regions.empty()) {
2675                 return;
2676         }
2677         begin_reversible_command (_("naturalize"));
2678         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2679                 session->add_undo ((*i)->region.get_memento());
2680                 (*i)->region.move_to_natural_position (this);
2681                 session->add_redo_no_execute ((*i)->region.get_memento());
2682         }
2683         commit_reversible_command ();
2684 }
2685
2686 void
2687 Editor::align (RegionPoint what)
2688 {
2689         align_selection (what, edit_cursor->current_frame);
2690 }
2691
2692 void
2693 Editor::align_relative (RegionPoint what)
2694 {
2695         align_selection_relative (what, edit_cursor->current_frame);
2696 }
2697
2698 struct RegionSortByTime {
2699     bool operator() (const AudioRegionView* a, const AudioRegionView* b) {
2700             return a->region.position() < b->region.position();
2701     }
2702 };
2703
2704 void
2705 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2706 {
2707         if (selection->audio_regions.empty()) {
2708                 return;
2709         }
2710
2711         jack_nframes_t distance;
2712         jack_nframes_t pos = 0;
2713         int dir;
2714
2715         list<AudioRegionView*> sorted;
2716         selection->audio_regions.by_position (sorted);
2717         Region& r ((*sorted.begin())->region);
2718
2719         switch (point) {
2720         case Start:
2721                 pos = r.first_frame ();
2722                 break;
2723
2724         case End:
2725                 pos = r.last_frame();
2726                 break;
2727
2728         case SyncPoint:
2729                 pos = r.adjust_to_sync (r.first_frame());
2730                 break;  
2731         }
2732
2733         if (pos > position) {
2734                 distance = pos - position;
2735                 dir = -1;
2736         } else {
2737                 distance = position - pos;
2738                 dir = 1;
2739         }
2740
2741         begin_reversible_command (_("align selection (relative)"));
2742
2743         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2744
2745                 Region& region ((*i)->region);
2746
2747                 session->add_undo (region.playlist()->get_memento());
2748                 
2749                 if (dir > 0) {
2750                         region.set_position (region.position() + distance, this);
2751                 } else {
2752                         region.set_position (region.position() - distance, this);
2753                 }
2754
2755                 session->add_redo_no_execute (region.playlist()->get_memento());
2756
2757         }
2758
2759         commit_reversible_command ();
2760 }
2761
2762 void
2763 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2764 {
2765         if (selection->audio_regions.empty()) {
2766                 return;
2767         }
2768
2769         begin_reversible_command (_("align selection"));
2770
2771         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
2772                 align_region_internal ((*i)->region, point, position);
2773         }
2774
2775         commit_reversible_command ();
2776 }
2777
2778 void
2779 Editor::align_region (Region& region, RegionPoint point, jack_nframes_t position)
2780 {
2781         begin_reversible_command (_("align region"));
2782         align_region_internal (region, point, position);
2783         commit_reversible_command ();
2784 }
2785
2786 void
2787 Editor::align_region_internal (Region& region, RegionPoint point, jack_nframes_t position)
2788 {
2789         session->add_undo (region.playlist()->get_memento());
2790
2791         switch (point) {
2792         case SyncPoint:
2793                 region.set_position (region.adjust_to_sync (position), this);
2794                 break;
2795
2796         case End:
2797                 if (position > region.length()) {
2798                         region.set_position (position - region.length(), this);
2799                 }
2800                 break;
2801
2802         case Start:
2803                 region.set_position (position, this);
2804                 break;
2805         }
2806
2807         session->add_redo_no_execute (region.playlist()->get_memento());
2808 }       
2809
2810 void
2811 Editor::trim_region_to_edit_cursor ()
2812 {
2813         if (clicked_regionview == 0) {
2814                 return;
2815         }
2816
2817         Region& region (clicked_regionview->region);
2818
2819         float speed = 1.0f;
2820         AudioTimeAxisView *atav;
2821
2822         if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2823                 if (atav->get_diskstream() != 0) {
2824                         speed = atav->get_diskstream()->speed();
2825                 }
2826         }
2827
2828         begin_reversible_command (_("trim to edit"));
2829         session->add_undo (region.playlist()->get_memento());
2830         region.trim_end ( (jack_nframes_t) floor( (float)edit_cursor->current_frame * speed), this);
2831         session->add_redo_no_execute (region.playlist()->get_memento());
2832         commit_reversible_command ();
2833 }
2834
2835 void
2836 Editor::trim_region_from_edit_cursor ()
2837 {
2838         if (clicked_regionview == 0) {
2839                 return;
2840         }
2841
2842         Region& region (clicked_regionview->region);
2843
2844         float speed = 1.0f;
2845         AudioTimeAxisView *atav;
2846
2847         if ( clicked_trackview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_trackview)) != 0 ) {
2848                 if (atav->get_diskstream() != 0) {
2849                         speed = atav->get_diskstream()->speed();
2850                 }
2851         }
2852
2853         begin_reversible_command (_("trim to edit"));
2854         session->add_undo (region.playlist()->get_memento());
2855         region.trim_front ( (jack_nframes_t) floor( (float)edit_cursor->current_frame * speed), this);
2856         session->add_redo_no_execute (region.playlist()->get_memento());
2857         commit_reversible_command ();
2858 }
2859
2860 void
2861 Editor::unfreeze_route ()
2862 {
2863         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2864                 return;
2865         }
2866         
2867         clicked_audio_trackview->audio_track()->unfreeze ();
2868 }
2869
2870 void*
2871 Editor::_freeze_thread (void* arg)
2872 {
2873         PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2874         return static_cast<Editor*>(arg)->freeze_thread ();
2875 }
2876
2877 void*
2878 Editor::freeze_thread ()
2879 {
2880         clicked_audio_trackview->audio_track()->freeze (*current_interthread_info);
2881         return 0;
2882 }
2883
2884 gint
2885 Editor::freeze_progress_timeout (void *arg)
2886 {
2887         interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2888         return !(current_interthread_info->done || current_interthread_info->cancel);
2889 }
2890
2891 void
2892 Editor::freeze_route ()
2893 {
2894         if (clicked_audio_trackview == 0 || !clicked_audio_trackview->is_audio_track()) {
2895                 return;
2896         }
2897         
2898         InterThreadInfo itt;
2899
2900         if (interthread_progress_window == 0) {
2901                 build_interthread_progress_window ();
2902         }
2903         
2904         interthread_progress_window->set_title (_("ardour: freeze"));
2905         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2906         interthread_progress_window->show_all ();
2907         interthread_progress_bar.set_fraction (0.0f);
2908         interthread_progress_label.set_text ("");
2909         interthread_cancel_label.set_text (_("Cancel Freeze"));
2910         current_interthread_info = &itt;
2911
2912         interthread_progress_connection = 
2913           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2914
2915         itt.done = false;
2916         itt.cancel = false;
2917         itt.progress = 0.0f;
2918
2919         pthread_create (&itt.thread, 0, _freeze_thread, this);
2920
2921         track_canvas_scroller.get_window()->set_cursor (Gdk::WATCH);
2922
2923         while (!itt.done && !itt.cancel) {
2924                 gtk_main_iteration ();
2925         }
2926
2927         interthread_progress_connection.disconnect ();
2928         interthread_progress_window->hide_all ();
2929         current_interthread_info = 0;
2930         track_canvas_scroller.get_window()->set_cursor (current_canvas_cursor);
2931 }
2932
2933 void
2934 Editor::bounce_range_selection ()
2935 {
2936         if (selection->time.empty()) {
2937                 return;
2938         }
2939
2940         TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2941
2942         jack_nframes_t start = selection->time[clicked_selection].start;
2943         jack_nframes_t end = selection->time[clicked_selection].end;
2944         jack_nframes_t cnt = end - start + 1;
2945         
2946         begin_reversible_command (_("bounce range"));
2947
2948         for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2949
2950                 AudioTimeAxisView* atv;
2951
2952                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2953                         continue;
2954                 }
2955                 
2956                 Playlist* playlist;
2957                 
2958                 if ((playlist = atv->playlist()) == 0) {
2959                         return;
2960                 }
2961
2962                 InterThreadInfo itt;
2963                 
2964                 itt.done = false;
2965                 itt.cancel = false;
2966                 itt.progress = false;
2967                 
2968                 session->add_undo (playlist->get_memento());
2969                 atv->audio_track()->bounce_range (start, cnt, itt);
2970                 session->add_redo_no_execute (playlist->get_memento());
2971         }
2972         
2973         commit_reversible_command ();
2974         
2975         delete views;
2976 }
2977
2978 void
2979 Editor::cut ()
2980 {
2981         cut_copy (Cut);
2982 }
2983
2984 void
2985 Editor::copy ()
2986 {
2987         cut_copy (Copy);
2988 }
2989
2990 void 
2991 Editor::cut_copy (CutCopyOp op)
2992 {
2993         /* only cancel selection if cut/copy is successful.*/
2994
2995         string opname;
2996
2997         switch (op) {
2998         case Cut:
2999                 opname = _("cut");
3000                 break;
3001         case Copy:
3002                 opname = _("copy");
3003                 break;
3004         case Clear:
3005                 opname = _("clear");
3006                 break;
3007         }
3008         
3009         cut_buffer->clear ();
3010
3011         switch (current_mouse_mode()) {
3012         case MouseObject: 
3013                 if (!selection->audio_regions.empty() || !selection->points.empty()) {
3014
3015                         begin_reversible_command (opname + _(" objects"));
3016
3017                         if (!selection->audio_regions.empty()) {
3018                                 
3019                                 cut_copy_regions (op);
3020                                 
3021                                 if (op == Cut) {
3022                                         selection->clear_audio_regions ();
3023                                 }
3024                         }
3025
3026                         if (!selection->points.empty()) {
3027                                 cut_copy_points (op);
3028
3029                                 if (op == Cut) {
3030                                         selection->clear_points ();
3031                                 }
3032                         }
3033
3034                         commit_reversible_command ();   
3035                 }
3036                 break;
3037                 
3038         case MouseRange:
3039                 if (!selection->time.empty()) {
3040
3041                         begin_reversible_command (opname + _(" range"));
3042                         cut_copy_ranges (op);
3043                         commit_reversible_command ();
3044
3045                         if (op == Cut) {
3046                                 selection->clear_time ();
3047                         }
3048                         
3049                 }
3050                 break;
3051                 
3052         default:
3053                 break;
3054         }
3055 }
3056
3057 void
3058 Editor::cut_copy_points (CutCopyOp op)
3059 {
3060         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3061
3062                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3063
3064                 if (atv) {
3065                         atv->cut_copy_clear_objects (selection->points, op);
3066                 } 
3067         }
3068 }
3069
3070 void
3071 Editor::cut_copy_regions (CutCopyOp op)
3072 {
3073         typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
3074         PlaylistMapping pmap;
3075         jack_nframes_t first_position = max_frames;
3076         set<Playlist*> freezelist;
3077         pair<set<Playlist*>::iterator,bool> insert_result;
3078
3079         for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ++x) {
3080                 first_position = min ((*x)->region.position(), first_position);
3081
3082                 if (op == Cut || op == Clear) {
3083                         AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
3084                         if (pl) {
3085                                 insert_result = freezelist.insert (pl);
3086                                 if (insert_result.second) {
3087                                         pl->freeze ();
3088                                         session->add_undo (pl->get_memento());
3089                                 }
3090                         }
3091                 }
3092         }
3093
3094         for (AudioRegionSelection::iterator x = selection->audio_regions.begin(); x != selection->audio_regions.end(); ) {
3095
3096                 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region.playlist());
3097                 AudioPlaylist* npl;
3098                 AudioRegionSelection::iterator tmp;
3099                 
3100                 tmp = x;
3101                 ++tmp;
3102
3103                 if (pl) {
3104
3105                         PlaylistMapping::iterator pi = pmap.find (pl);
3106                         
3107                         if (pi == pmap.end()) {
3108                                 npl = new AudioPlaylist (*session, "cutlist", true);
3109                                 npl->freeze();
3110                                 pmap[pl] = npl;
3111                         } else {
3112                                 npl = pi->second;
3113                         }
3114
3115                         switch (op) {
3116                         case Cut:
3117                                 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3118                                 pl->remove_region (&((*x)->region));
3119                                 break;
3120
3121                         case Copy:
3122                                 npl->add_region (*(new AudioRegion ((*x)->region)), (*x)->region.position() - first_position);
3123                                 break;
3124
3125                         case Clear:
3126                                 pl->remove_region (&((*x)->region));
3127                                 break;
3128                         }
3129                 }
3130
3131                 x = tmp;
3132         }
3133
3134         list<Playlist*> foo;
3135
3136         for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3137                 foo.push_back (i->second);
3138         }
3139
3140         if (!foo.empty()) {
3141                 cut_buffer->set (foo);
3142         }
3143         
3144         for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3145                 (*pl)->thaw ();
3146                 session->add_redo_no_execute ((*pl)->get_memento());
3147         }
3148 }
3149
3150 void
3151 Editor::cut_copy_ranges (CutCopyOp op)
3152 {
3153         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3154                 (*i)->cut_copy_clear (*selection, op);
3155         }
3156 }
3157
3158 void
3159 Editor::paste (float times)
3160 {
3161         paste_internal (edit_cursor->current_frame, times);
3162 }
3163
3164 void
3165 Editor::mouse_paste ()
3166 {
3167         gint x, y;
3168         double wx, wy;
3169         track_canvas.get_pointer (x, y);
3170
3171         gnome_canvas_window_to_world (GNOME_CANVAS(track_canvas), x, y, &wx, &wy);
3172         
3173         GdkEvent event;
3174         event.type = GDK_BUTTON_RELEASE;
3175         event.button.x = wx;
3176         event.button.y = wy;
3177         
3178         jack_nframes_t where = event_frame (&event, 0, 0);
3179         snap_to (where);
3180         paste_internal (where, 1);
3181 }
3182
3183 void
3184 Editor::paste_internal (jack_nframes_t position, float times)
3185 {
3186         bool commit = false;
3187
3188         if (cut_buffer->empty() || selection->tracks.empty()) {
3189                 return;
3190         }
3191
3192         if (position == max_frames) {
3193                 position = edit_cursor->current_frame;
3194         }
3195
3196         begin_reversible_command (_("paste"));
3197
3198         TrackSelection::iterator i;
3199         size_t nth;
3200
3201         for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3202                 
3203                 /* undo/redo is handled by individual tracks */
3204
3205                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3206                         commit = true;
3207                 }
3208         }
3209
3210         if (commit) {
3211                 commit_reversible_command ();
3212         }
3213 }
3214
3215 void
3216 Editor::paste_named_selection (float times)
3217 {
3218         Gtk::CList_Helpers::SelectionList& selected = named_selection_display.selection();
3219         TrackSelection::iterator i;
3220
3221         if (selected.empty() || selection->tracks.empty()) {
3222                 return;
3223         }
3224
3225         NamedSelection* ns = static_cast<NamedSelection*> (selected.front()->get_data ());
3226         list<Playlist*>::iterator chunk;
3227         list<Playlist*>::iterator tmp;
3228
3229         chunk = ns->playlists.begin();
3230                 
3231         begin_reversible_command (_("paste chunk"));
3232
3233         for (i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3234                 
3235                 AudioTimeAxisView* atv;
3236                 Playlist* pl;
3237                 AudioPlaylist* apl;
3238
3239                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
3240                         continue;
3241                 }
3242
3243                 if ((pl = atv->playlist()) == 0) {
3244                         continue;
3245                 }
3246
3247                 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3248                         continue;
3249                 }
3250
3251                 tmp = chunk;
3252                 ++tmp;
3253
3254                 session->add_undo (apl->get_memento());
3255                 apl->paste (**chunk, edit_cursor->current_frame, times);
3256                 session->add_redo_no_execute (apl->get_memento());
3257
3258                 if (tmp != ns->playlists.end()) {
3259                         chunk = tmp;
3260                 }
3261         }
3262
3263         commit_reversible_command();
3264 }
3265
3266 void
3267 Editor::duplicate_some_regions (AudioRegionSelection& regions, float times)
3268 {
3269         Playlist *playlist; 
3270         
3271         begin_reversible_command (_("duplicate region"));
3272
3273         for (AudioRegionSelection::iterator i = regions.begin(); i != regions.end(); ++i) {
3274
3275                 Region& r ((*i)->region);
3276                 
3277                 playlist = (*i)->region.playlist();
3278                 session->add_undo (playlist->get_memento());
3279                 playlist->duplicate (r, r.last_frame(), times);
3280                 session->add_redo_no_execute (playlist->get_memento());
3281
3282         }
3283
3284         commit_reversible_command ();
3285 }
3286
3287 void
3288 Editor::duplicate_selection (float times)
3289 {
3290         if (selection->time.empty() || selection->tracks.empty()) {
3291                 return;
3292         }
3293
3294         Playlist *playlist; 
3295         vector<AudioRegion*> new_regions;
3296         vector<AudioRegion*>::iterator ri;
3297                 
3298         create_region_from_selection (new_regions);
3299
3300         if (new_regions.empty()) {
3301                 return;
3302         }
3303         
3304         begin_reversible_command (_("duplicate selection"));
3305
3306         ri = new_regions.begin();
3307
3308         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3309                 if ((playlist = (*i)->playlist()) == 0) {
3310                         continue;
3311                 }
3312                 session->add_undo (playlist->get_memento());
3313                 playlist->duplicate (**ri, selection->time[clicked_selection].end, times);
3314                 session->add_redo_no_execute (playlist->get_memento());
3315
3316                 ++ri;
3317                 if (ri == new_regions.end()) {
3318                         --ri;
3319                 }
3320         }
3321
3322         commit_reversible_command ();
3323 }
3324
3325 void
3326 Editor::center_playhead ()
3327 {
3328         float page = canvas_width * frames_per_unit;
3329
3330         center_screen_internal (playhead_cursor->current_frame, page);
3331 }
3332
3333 void
3334 Editor::center_edit_cursor ()
3335 {
3336         float page = canvas_width * frames_per_unit;
3337
3338         center_screen_internal (edit_cursor->current_frame, page);
3339 }
3340
3341 void
3342 Editor::clear_playlist (Playlist& playlist)
3343 {
3344         begin_reversible_command (_("clear playlist"));
3345         session->add_undo (playlist.get_memento());
3346         playlist.clear ();
3347         session->add_redo_no_execute (playlist.get_memento());
3348         commit_reversible_command ();
3349 }
3350
3351 void
3352 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3353 {
3354         Playlist *playlist; 
3355         jack_nframes_t distance;
3356         jack_nframes_t next_distance;
3357         jack_nframes_t start;
3358
3359         if (use_edit_cursor) {
3360                 start = edit_cursor->current_frame;
3361         } else {
3362                 start = 0;
3363         }
3364
3365         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3366                 return;
3367         }
3368         
3369         if (selection->tracks.empty()) {
3370                 return;
3371         }
3372         
3373         begin_reversible_command (_("nudge track"));
3374         
3375         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3376
3377                 if ((playlist = (*i)->playlist()) == 0) {
3378                         continue;
3379                 }               
3380                 
3381                 session->add_undo (playlist->get_memento());
3382                 playlist->nudge_after (start, distance, forwards);
3383                 session->add_redo_no_execute (playlist->get_memento());
3384         }
3385         
3386         commit_reversible_command ();                   
3387 }
3388
3389 void
3390 Editor::toggle_xfades_active ()
3391 {
3392         if (session) {
3393                 session->set_crossfades_active (!session->get_crossfades_active());
3394         }
3395 }
3396
3397 void
3398 Editor::toggle_follow_playhead ()
3399 {
3400         set_follow_playhead (!_follow_playhead);
3401 }
3402
3403 void
3404 Editor::set_xfade_visibility (bool yn)
3405 {
3406         
3407 }
3408
3409 void
3410 Editor::toggle_xfade_visibility ()
3411 {
3412         set_xfade_visibility (!xfade_visibility());
3413 }
3414
3415 void
3416 Editor::remove_last_capture ()
3417 {
3418         vector<string> choices;
3419         string prompt;
3420         
3421         if (!session) {
3422                 return;
3423         }
3424
3425         if (Config->get_verify_remove_last_capture()) {
3426                 prompt  = _("Do you really want to destroy the last capture?"
3427                             "\n(This is destructive and cannot be undone)");
3428
3429                 choices.push_back (_("Yes, destroy it."));
3430                 choices.push_back (_("No, do nothing."));
3431
3432                 Gtkmm2ext::Choice prompter (prompt, choices);
3433
3434                 prompter.chosen.connect (Gtk::Main::quit.slot());
3435                 prompter.show_all ();
3436
3437                 Gtk::Main::run ();
3438
3439                 if (prompter.get_choice() == 0) {
3440                         session->remove_last_capture ();
3441                 }
3442         } else {
3443                 session->remove_last_capture();
3444         }
3445 }
3446
3447 void
3448 Editor::normalize_region ()
3449 {
3450         if (!session) {
3451                 return;
3452         }
3453
3454         if (selection->audio_regions.empty()) {
3455                 return;
3456         }
3457
3458         begin_reversible_command (_("normalize"));
3459
3460         track_canvas_scroller.get_window()->set_cursor (wait_cursor);
3461         gdk_flush ();
3462
3463         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3464                 session->add_undo ((*r)->region.get_memento());
3465                 (*r)->region.normalize_to (0.0f);
3466                 session->add_redo_no_execute ((*r)->region.get_memento());
3467         }
3468
3469         commit_reversible_command ();
3470         gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
3471 }
3472
3473
3474 void
3475 Editor::denormalize_region ()
3476 {
3477         if (!session) {
3478                 return;
3479         }
3480
3481         if (selection->audio_regions.empty()) {
3482                 return;
3483         }
3484
3485         begin_reversible_command ("denormalize");
3486
3487         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ++r) {
3488                 session->add_undo ((*r)->region.get_memento());
3489                 (*r)->region.set_scale_amplitude (1.0f);
3490                 session->add_redo_no_execute ((*r)->region.get_memento());
3491         }
3492
3493         commit_reversible_command ();
3494 }
3495
3496
3497 void
3498 Editor::reverse_region ()
3499 {
3500         if (!session) {
3501                 return;
3502         }
3503
3504         Reverse rev (*session);
3505         apply_filter (rev, _("reverse regions"));
3506 }
3507
3508 void
3509 Editor::apply_filter (AudioFilter& filter, string command)
3510 {
3511         if (selection->audio_regions.empty()) {
3512                 return;
3513         }
3514
3515         begin_reversible_command (command);
3516
3517         track_canvas_scroller.get_window()->set_cursor (wait_cursor);
3518         gdk_flush ();
3519
3520         for (AudioRegionSelection::iterator r = selection->audio_regions.begin(); r != selection->audio_regions.end(); ) {
3521
3522                 AudioRegion& region ((*r)->region);
3523                 Playlist* playlist = region.playlist();
3524
3525                 AudioRegionSelection::iterator tmp;
3526                 
3527                 tmp = r;
3528                 ++tmp;
3529
3530                 if (region.apply (filter) == 0) {
3531
3532                         session->add_undo (playlist->get_memento());
3533                         playlist->replace_region (region, *(filter.results.front()), region.position());
3534                         session->add_redo_no_execute (playlist->get_memento());
3535                 } else {
3536                         goto out;
3537                 }
3538
3539                 r = tmp;
3540         }
3541
3542         commit_reversible_command ();
3543         selection->audio_regions.clear ();
3544
3545   out:
3546         gdk_window_set_cursor (track_canvas_scroller.get_window()->gobj(), current_canvas_cursor);
3547 }
3548
3549 void
3550 Editor::region_selection_op (void (Region::*pmf)(void))
3551 {
3552         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3553                 ((*i)->region.*pmf)();
3554         }
3555 }
3556
3557
3558 void
3559 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3560 {
3561         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3562                 ((*i)->region.*pmf)(arg);
3563         }
3564 }
3565
3566 void
3567 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3568 {
3569         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3570                 ((*i)->region.*pmf)(yn);
3571         }
3572 }
3573
3574 void
3575 Editor::external_edit_region ()
3576 {
3577         if (!clicked_regionview) {
3578                 return;
3579         }
3580
3581         /* more to come */
3582 }
3583
3584 void
3585 Editor::brush (jack_nframes_t pos)
3586 {
3587         AudioRegionSelection sel;
3588         snap_to (pos);
3589
3590         if (selection->audio_regions.empty()) {
3591                 /* XXX get selection from region list */
3592         } else { 
3593                 sel = selection->audio_regions;
3594         }
3595
3596         if (sel.empty()) {
3597                 return;
3598         }
3599
3600         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3601                 mouse_brush_insert_region ((*i), pos);
3602         }
3603 }
3604
3605 void
3606 Editor::toggle_gain_envelope_visibility ()
3607 {
3608         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3609                 (*i)->set_envelope_visible (!(*i)->envelope_visible());
3610         }
3611 }
3612
3613 void
3614 Editor::toggle_gain_envelope_active ()
3615 {
3616         for (AudioRegionSelection::iterator i = selection->audio_regions.begin(); i != selection->audio_regions.end(); ++i) {
3617                 AudioRegion* ar = dynamic_cast<AudioRegion*>(&(*i)->region);
3618                 if (ar) {
3619                         ar->set_envelope_active (true);
3620                 }
3621         }
3622 }