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