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