Merged with trunk R920.
[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 "audio_region_view.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.125f;
144                  Config->set_meter_falloff_slowest(true);
145                  break;
146                 case 2:
147                  val = 0.250f;
148                  Config->set_meter_falloff_slow(true);
149                  break;
150                 case 3:
151                  val = 0.375f;
152                  Config->set_meter_falloff_medium(true);
153                  break;
154                 case 4:
155                  val = 0.500f;
156                  Config->set_meter_falloff_fast(true);
157                  break;
158                 case 5:
159                  val = 0.750f;
160                  Config->set_meter_falloff_faster(true);
161                  break;
162                 case 6:
163                  val = 0.875f;
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->regions);
191 }
192
193 void
194 Editor::split_regions_at (jack_nframes_t where, RegionSelection& regions)
195 {
196         begin_reversible_command (_("split"));
197
198         snap_to (where);
199         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
200
201                 RegionSelection::iterator tmp;
202                 
203                 tmp = a;
204                 ++tmp;
205
206                 Playlist* pl = (*a)->region()->playlist();
207
208                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*a);
209                 if (arv)
210                         _new_regionviews_show_envelope = arv->envelope_visible();
211                 
212                 if (pl) {
213                         XMLNode &before = pl->get_state();
214                         pl->split_region ((*a)->region(), where);
215                         XMLNode &after = pl->get_state();
216                         session->add_command(new MementoCommand<Playlist>(*pl, &before, &after));
217                 }
218
219                 a = tmp;
220     }
221
222         commit_reversible_command ();
223         _new_regionviews_show_envelope = false;
224 }
225
226 void
227 Editor::remove_clicked_region ()
228 {
229         if (clicked_routeview == 0 || clicked_regionview == 0) {
230                 return;
231         }
232
233         Playlist* playlist = clicked_routeview->playlist();
234         
235         begin_reversible_command (_("remove region"));
236         XMLNode &before = playlist->get_state();
237         playlist->remove_region (clicked_regionview->region());
238         XMLNode &after = playlist->get_state();
239         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
240         commit_reversible_command ();
241 }
242
243 void
244 Editor::destroy_clicked_region ()
245 {
246         int32_t selected = selection->regions.size();
247
248         if (!session || clicked_regionview == 0 && selected == 0) {
249                 return;
250         }
251
252         vector<string> choices;
253         string prompt;
254         
255         prompt  = string_compose (_(" This is destructive, will possibly delete audio files\n\
256 It cannot be undone\n\
257 Do you really want to destroy %1 ?"),
258                            (selected > 1 ? 
259                             _("these regions") : _("this region")));
260
261         choices.push_back (_("No, do nothing."));
262
263         if (selected > 1) {
264                 choices.push_back (_("Yes, destroy them."));
265         } else {
266                 choices.push_back (_("Yes, destroy it."));
267         }
268
269         Gtkmm2ext::Choice prompter (prompt, choices);
270         
271         if (prompter.run() == 0) { /* first choice */
272                 return;
273         }
274
275         if (selected > 0) {
276                 list<boost::shared_ptr<Region> > r;
277
278                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
279                         r.push_back ((*i)->region());
280                 }
281
282                 session->destroy_regions (r);
283
284         } else if (clicked_regionview) {
285                 session->destroy_region (clicked_regionview->region());
286         } 
287 }
288
289 boost::shared_ptr<Region>
290 Editor::select_region_for_operation (int dir, TimeAxisView **tv)
291 {
292         RegionView* rv;
293         boost::shared_ptr<Region> region;
294         jack_nframes_t start = 0;
295
296         if (selection->time.start () == selection->time.end_frame ()) {
297                 
298                 /* no current selection-> is there a selected regionview? */
299
300                 if (selection->regions.empty()) {
301                         return region;
302                 }
303
304         } 
305
306         if (!selection->regions.empty()) {
307
308                 rv = *(selection->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                 RouteTimeAxisView* rtv;
317
318                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*tv)) != 0) {
319                         Playlist *pl;
320                         
321                         if ((pl = rtv->playlist()) == 0) {
322                                 return region;
323                         }
324                         
325                         region = 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         boost::shared_ptr<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         boost::shared_ptr<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->regions.empty()) {
398
399                 begin_reversible_command (_("nudge forward"));
400
401                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
402                         boost::shared_ptr<Region> 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->regions.empty()) {
433
434                 begin_reversible_command (_("nudge forward"));
435
436                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
437                         boost::shared_ptr<Region> 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->regions.empty()) {
478
479                 begin_reversible_command (_("nudge forward"));
480
481                 distance = session->worst_output_latency();
482
483                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
484                         boost::shared_ptr<Region> 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->regions.empty()) {
505
506                 begin_reversible_command (_("nudge forward"));
507
508                 distance = session->worst_output_latency();
509
510                 for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
511                         boost::shared_ptr<Region> 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         boost::shared_ptr<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_axisview) {
587
588                         TrackViewList t;
589                         t.push_back (clicked_axisview);
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 boost::shared_ptr<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         boost::shared_ptr<Region> ret;
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                 boost::shared_ptr<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         boost::shared_ptr<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_axisview) {
727                 
728                 TrackViewList t;
729                 t.push_back (clicked_axisview);
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->regions.empty()) {
793                         pos = selection->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->regions.empty()) {
822                         pos = selection->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 *= 1.61803399;
1114         } else { 
1115                 nfpu = max(1.0,(nfpu/1.61803399));
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         double range_before = frame - leftmost_frame;
1255         double new_fpu;
1256         
1257         new_fpu = frames_per_unit;
1258         
1259         if (coarser) { 
1260                 new_fpu *= 1.61803399;
1261                 range_before *= 1.61803399;
1262         } else { 
1263                 new_fpu = max(1.0,(new_fpu/1.61803399));
1264                 range_before /= 1.61803399;
1265         }
1266
1267         if (new_fpu == frames_per_unit) return;
1268
1269         jack_nframes_t new_leftmost = frame - (jack_nframes_t)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_axisview == 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->regions.empty()) {
1323                 return;
1324         }
1325
1326         RegionView* rv = *(selection->regions.begin());
1327         boost::shared_ptr<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_axisview) {
1344                 return;
1345         }
1346         
1347         clicked_axisview->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_axisview) {
1394                 return;
1395         }
1396         
1397         clicked_axisview->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->regions.empty()) {
1456                 return;
1457         }
1458
1459         RegionView* rv = *(selection->regions.begin());
1460         boost::shared_ptr<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 (boost::shared_ptr<Region> 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 (RegionFactory::create (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         RouteTimeAxisView *tv = 0;
1844         Playlist *playlist;
1845
1846         if (clicked_routeview != 0) {
1847                 tv = clicked_routeview;
1848         } else if (!selection->tracks.empty()) {
1849                 if ((tv = dynamic_cast<RouteTimeAxisView*>(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         boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
1868
1869         begin_reversible_command (_("insert region"));
1870         XMLNode &before = playlist->get_state();
1871         playlist->add_region ((RegionFactory::create (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->regions.empty()) {
1945                 RegionView *rv = *(selection->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->regions.empty()) {
1955                 RegionView *rv = *(selection->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->regions.empty()) {
2005                 bool yn = ! (*selection->regions.begin())->region()->muted();
2006                 selection->foreach_region (&Region::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->regions.empty()) {
2016                 bool yn = ! (*selection->regions.begin())->region()->opaque();
2017                 selection->foreach_region (&Region::set_opaque, yn);
2018         }
2019 }
2020
2021 void
2022 Editor::raise_region ()
2023 {
2024         selection->foreach_region (&Region::raise);
2025 }
2026
2027 void
2028 Editor::raise_region_to_top ()
2029 {
2030         selection->foreach_region (&Region::raise_to_top);
2031 }
2032
2033 void
2034 Editor::lower_region ()
2035 {
2036         selection->foreach_region (&Region::lower);
2037 }
2038
2039 void
2040 Editor::lower_region_to_bottom ()
2041 {
2042         selection->foreach_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->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->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 (boost::shared_ptr<Region> 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->regions.empty()) {
2130                 RegionView* rv = *(selection->regions.begin());
2131                 session->audition_region (rv->region());
2132         }
2133 }
2134
2135 void
2136 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> 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_axisview == 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                 boost::shared_ptr<AudioRegion> current;
2187                 boost::shared_ptr<Region> current_r;
2188                 Playlist *pl;
2189
2190                 jack_nframes_t internal_start;
2191                 string new_name;
2192
2193                 if ((pl = (*i)->playlist()) == 0) {
2194                         continue;
2195                 }
2196
2197                 if ((current_r = pl->top_region_at (start)) == 0) {
2198                         continue;
2199                 }
2200
2201                 current = boost::dynamic_pointer_cast<AudioRegion> (current_r);
2202                 assert(current); // FIXME
2203                 if (current != 0) {
2204                         internal_start = start - current->position();
2205                         session->region_name (new_name, current->name(), true);
2206                         boost::shared_ptr<Region> region (RegionFactory::create (current, internal_start, selection_cnt, new_name));
2207                 }
2208         }
2209 }       
2210
2211 void
2212 Editor::create_region_from_selection (vector<boost::shared_ptr<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                 boost::shared_ptr<AudioRegion> current;
2224                 boost::shared_ptr<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 = boost::dynamic_pointer_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 (boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (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         AudioRegionView* clicked_arv = dynamic_cast<AudioRegionView*>(clicked_regionview);
2254         
2255         if (!clicked_arv || clicked_arv->audio_region()->n_channels() < 2) {
2256                 return;
2257         }
2258
2259         clicked_arv->audio_region()->separate_by_channel (*session, v);
2260
2261         /* nothing else to do, really */
2262 }
2263
2264 void
2265 Editor::new_region_from_selection ()
2266 {
2267         region_from_selection ();
2268         cancel_selection ();
2269 }
2270
2271 void
2272 Editor::separate_region_from_selection ()
2273 {
2274         // FIXME: TYPE
2275         
2276         bool doing_undo = false;
2277
2278         if (selection->time.empty()) {
2279                 return;
2280         }
2281
2282         Playlist *playlist;
2283                 
2284         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2285
2286                 AudioTimeAxisView* atv;
2287
2288                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2289
2290                         if (atv->is_audio_track()) {
2291                                         
2292                                 if ((playlist = atv->playlist()) != 0) {
2293                                         if (!doing_undo) {
2294                                                 begin_reversible_command (_("separate"));
2295                                                 doing_undo = true;
2296                                         }
2297                                         XMLNode *before;
2298                                         if (doing_undo) 
2299                                             before = &(playlist->get_state());
2300                         
2301                                         /* XXX need to consider musical time selections here at some point */
2302
2303                                         double speed = atv->get_diskstream()->speed();
2304
2305                                         for (list<AudioRange>::iterator t = selection->time.begin(); t != selection->time.end(); ++t) {
2306                                                 playlist->partition ((jack_nframes_t)((*t).start * speed), (jack_nframes_t)((*t).end * speed), true);
2307                                         }
2308
2309                                         if (doing_undo) 
2310                                             session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2311                                 }
2312                         }
2313                 }
2314         }
2315
2316         if (doing_undo) commit_reversible_command ();
2317 }
2318
2319 void
2320 Editor::separate_regions_using_location (Location& loc)
2321 {
2322         // FIXME: TYPE
2323         
2324         bool doing_undo = false;
2325
2326         if (loc.is_mark()) {
2327                 return;
2328         }
2329
2330         Playlist *playlist;
2331
2332         /* XXX i'm unsure as to whether this should operate on selected tracks only 
2333            or the entire enchillada. uncomment the below line to correct the behaviour 
2334            (currently set for all tracks)
2335         */
2336
2337         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {    
2338         //for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2339
2340                 AudioTimeAxisView* atv;
2341
2342                 if ((atv = dynamic_cast<AudioTimeAxisView*> ((*i))) != 0) {
2343
2344                         if (atv->is_audio_track()) {
2345                                         
2346                                 if ((playlist = atv->playlist()) != 0) {
2347                                         XMLNode *before;
2348                                         if (!doing_undo) {
2349                                                 begin_reversible_command (_("separate"));
2350                                                 doing_undo = true;
2351                                         }
2352                                         if (doing_undo) 
2353                                             before = &(playlist->get_state());
2354                                             
2355                         
2356                                         /* XXX need to consider musical time selections here at some point */
2357
2358                                         double speed = atv->get_diskstream()->speed();
2359
2360
2361                                         playlist->partition ((jack_nframes_t)(loc.start() * speed), (jack_nframes_t)(loc.end() * speed), true);
2362                                         if (doing_undo) 
2363                                             session->add_command(new MementoCommand<Playlist>(*playlist, before, &playlist->get_state()));
2364                                 }
2365                         }
2366                 }
2367         }
2368
2369         if (doing_undo) commit_reversible_command ();
2370 }
2371
2372 void
2373 Editor::crop_region_to_selection ()
2374 {
2375         if (selection->time.empty()) {
2376                 return;
2377         }
2378
2379         vector<Playlist*> playlists;
2380         Playlist *playlist;
2381
2382         if (clicked_axisview != 0) {
2383
2384                 if ((playlist = clicked_axisview->playlist()) == 0) {
2385                         return;
2386                 }
2387
2388                 playlists.push_back (playlist);
2389
2390         } else {
2391                 
2392                 for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2393
2394                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i);
2395
2396                         if (rtv && rtv->is_track()) {
2397
2398                                 if ((playlist = rtv->playlist()) != 0) {
2399                                         playlists.push_back (playlist);
2400                                 }
2401                         }
2402                 }
2403         }
2404
2405         if (!playlists.empty()) {
2406
2407                 jack_nframes_t start;
2408                 jack_nframes_t end;
2409                 jack_nframes_t cnt;
2410
2411                 begin_reversible_command (_("trim to selection"));
2412
2413                 for (vector<Playlist*>::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2414                         
2415                         boost::shared_ptr<Region> region;
2416                         
2417                         start = selection->time.start();
2418
2419                         if ((region = (*i)->top_region_at(start)) == 0) {
2420                                 continue;
2421                         }
2422                         
2423                         /* now adjust lengths to that we do the right thing
2424                            if the selection extends beyond the region
2425                         */
2426                         
2427                         start = max (start, region->position());
2428                         end = min (selection->time.end_frame(), start + region->length() - 1);
2429                         cnt = end - start + 1;
2430
2431                         XMLNode &before = (*i)->get_state();
2432                         region->trim_to (start, cnt, this);
2433                         XMLNode &after = (*i)->get_state();
2434                         session->add_command (new MementoCommand<Playlist>(*(*i), &before, &after));
2435                 }
2436
2437                 commit_reversible_command ();
2438         }
2439 }               
2440
2441 void
2442 Editor::region_fill_track ()
2443 {
2444         jack_nframes_t end;
2445
2446         if (!session || selection->regions.empty()) {
2447                 return;
2448         }
2449
2450         end = session->current_end_frame ();
2451
2452         begin_reversible_command (_("region fill"));
2453
2454         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2455
2456                 boost::shared_ptr<Region> region ((*i)->region());
2457                 
2458                 // FIXME
2459                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>(region);
2460                 assert(ar);
2461
2462                 Playlist* pl = region->playlist();
2463
2464                 if (end <= region->last_frame()) {
2465                         return;
2466                 }
2467
2468                 double times = (double) (end - region->last_frame()) / (double) region->length();
2469
2470                 if (times == 0) {
2471                         return;
2472                 }
2473
2474                 XMLNode &before = pl->get_state();
2475                 pl->add_region (RegionFactory::create (ar), ar->last_frame(), times);
2476                 session->add_command (new MementoCommand<Playlist>(*pl, &before, &pl->get_state()));
2477         }
2478
2479         commit_reversible_command ();
2480 }
2481
2482 void
2483 Editor::region_fill_selection ()
2484 {
2485         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
2486                 return;
2487         }
2488
2489         if (selection->time.empty()) {
2490                 return;
2491         }
2492
2493
2494         Glib::RefPtr<TreeSelection> selected = region_list_display.get_selection();
2495
2496         if (selected->count_selected_rows() != 1) {
2497                 return;
2498         }
2499
2500         TreeModel::iterator i = region_list_display.get_selection()->get_selected();
2501         boost::shared_ptr<Region> region = (*i)[region_list_columns.region];
2502
2503         jack_nframes_t start = selection->time[clicked_selection].start;
2504         jack_nframes_t end = selection->time[clicked_selection].end;
2505
2506         Playlist *playlist; 
2507
2508         if (selection->tracks.empty()) {
2509                 return;
2510         }
2511
2512         jack_nframes_t selection_length = end - start;
2513         float times = (float)selection_length / region->length();
2514         
2515         begin_reversible_command (_("fill selection"));
2516         
2517         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
2518
2519                 if ((playlist = (*i)->playlist()) == 0) {
2520                         continue;
2521                 }               
2522                 
2523                 XMLNode &before = playlist->get_state();
2524                 playlist->add_region (RegionFactory::create (region), start, times);
2525                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
2526         }
2527         
2528         commit_reversible_command ();                   
2529 }
2530
2531 void
2532 Editor::set_a_regions_sync_position (boost::shared_ptr<Region> region, jack_nframes_t position)
2533 {
2534
2535         if (!region->covers (position)) {
2536           error << _("Programming error. that region doesn't cover that position") << __FILE__ << " +" << __LINE__ << endmsg;
2537                 return;
2538         }
2539         begin_reversible_command (_("set region sync position"));
2540         XMLNode &before = region->playlist()->get_state();
2541         region->set_sync_position (position);
2542         XMLNode &after = region->playlist()->get_state();
2543         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2544         commit_reversible_command ();
2545 }
2546
2547 void
2548 Editor::set_region_sync_from_edit_cursor ()
2549 {
2550         if (clicked_regionview == 0) {
2551                 return;
2552         }
2553
2554         if (!clicked_regionview->region()->covers (edit_cursor->current_frame)) {
2555                 error << _("Place the edit cursor at the desired sync point") << endmsg;
2556                 return;
2557         }
2558
2559         boost::shared_ptr<Region> region (clicked_regionview->region());
2560         begin_reversible_command (_("set sync from edit cursor"));
2561         XMLNode &before = region->playlist()->get_state();
2562         region->set_sync_position (edit_cursor->current_frame);
2563         XMLNode &after = region->playlist()->get_state();
2564         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2565         commit_reversible_command ();
2566 }
2567
2568 void
2569 Editor::remove_region_sync ()
2570 {
2571         if (clicked_regionview) {
2572                 boost::shared_ptr<Region> region (clicked_regionview->region());
2573                 begin_reversible_command (_("remove sync"));
2574                 XMLNode &before = region->playlist()->get_state();
2575                 region->clear_sync_position ();
2576                 XMLNode &after = region->playlist()->get_state();
2577                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2578                 commit_reversible_command ();
2579         }
2580 }
2581
2582 void
2583 Editor::naturalize ()
2584 {
2585         if (selection->regions.empty()) {
2586                 return;
2587         }
2588         begin_reversible_command (_("naturalize"));
2589         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2590                 XMLNode &before = (*i)->region()->get_state();
2591                 (*i)->region()->move_to_natural_position (this);
2592                 XMLNode &after = (*i)->region()->get_state();
2593                 session->add_command (new MementoCommand<Region>(*((*i)->region().get()), &before, &after));
2594         }
2595         commit_reversible_command ();
2596 }
2597
2598 void
2599 Editor::align (RegionPoint what)
2600 {
2601         align_selection (what, edit_cursor->current_frame);
2602 }
2603
2604 void
2605 Editor::align_relative (RegionPoint what)
2606 {
2607         align_selection_relative (what, edit_cursor->current_frame);
2608 }
2609
2610 struct RegionSortByTime {
2611     bool operator() (const RegionView* a, const RegionView* b) {
2612             return a->region()->position() < b->region()->position();
2613     }
2614 };
2615
2616 void
2617 Editor::align_selection_relative (RegionPoint point, jack_nframes_t position)
2618 {
2619         if (selection->regions.empty()) {
2620                 return;
2621         }
2622
2623         jack_nframes_t distance;
2624         jack_nframes_t pos = 0;
2625         int dir;
2626
2627         list<RegionView*> sorted;
2628         selection->regions.by_position (sorted);
2629         boost::shared_ptr<Region> r ((*sorted.begin())->region());
2630
2631         switch (point) {
2632         case Start:
2633                 pos = r->first_frame ();
2634                 break;
2635
2636         case End:
2637                 pos = r->last_frame();
2638                 break;
2639
2640         case SyncPoint:
2641                 pos = r->adjust_to_sync (r->first_frame());
2642                 break;  
2643         }
2644
2645         if (pos > position) {
2646                 distance = pos - position;
2647                 dir = -1;
2648         } else {
2649                 distance = position - pos;
2650                 dir = 1;
2651         }
2652
2653         begin_reversible_command (_("align selection (relative)"));
2654
2655         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2656
2657                 boost::shared_ptr<Region> region ((*i)->region());
2658
2659                 XMLNode &before = region->playlist()->get_state();
2660                 
2661                 if (dir > 0) {
2662                         region->set_position (region->position() + distance, this);
2663                 } else {
2664                         region->set_position (region->position() - distance, this);
2665                 }
2666
2667                 XMLNode &after = region->playlist()->get_state();
2668                 session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2669
2670         }
2671
2672         commit_reversible_command ();
2673 }
2674
2675 void
2676 Editor::align_selection (RegionPoint point, jack_nframes_t position)
2677 {
2678         if (selection->regions.empty()) {
2679                 return;
2680         }
2681
2682         begin_reversible_command (_("align selection"));
2683
2684         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2685                 align_region_internal ((*i)->region(), point, position);
2686         }
2687
2688         commit_reversible_command ();
2689 }
2690
2691 void
2692 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, jack_nframes_t position)
2693 {
2694         begin_reversible_command (_("align region"));
2695         align_region_internal (region, point, position);
2696         commit_reversible_command ();
2697 }
2698
2699 void
2700 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, jack_nframes_t position)
2701 {
2702         XMLNode &before = region->playlist()->get_state();
2703
2704         switch (point) {
2705         case SyncPoint:
2706                 region->set_position (region->adjust_to_sync (position), this);
2707                 break;
2708
2709         case End:
2710                 if (position > region->length()) {
2711                         region->set_position (position - region->length(), this);
2712                 }
2713                 break;
2714
2715         case Start:
2716                 region->set_position (position, this);
2717                 break;
2718         }
2719
2720         XMLNode &after = region->playlist()->get_state();
2721         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2722 }       
2723
2724 void
2725 Editor::trim_region_to_edit_cursor ()
2726 {
2727         if (clicked_regionview == 0) {
2728                 return;
2729         }
2730
2731         boost::shared_ptr<Region> region (clicked_regionview->region());
2732
2733         float speed = 1.0f;
2734         AudioTimeAxisView *atav;
2735
2736         if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2737                 if (atav->get_diskstream() != 0) {
2738                         speed = atav->get_diskstream()->speed();
2739                 }
2740         }
2741
2742         begin_reversible_command (_("trim to edit"));
2743         XMLNode &before = region->playlist()->get_state();
2744         region->trim_end( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2745         XMLNode &after = region->playlist()->get_state();
2746         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2747         commit_reversible_command ();
2748 }
2749
2750 void
2751 Editor::trim_region_from_edit_cursor ()
2752 {
2753         if (clicked_regionview == 0) {
2754                 return;
2755         }
2756
2757         boost::shared_ptr<Region> region (clicked_regionview->region());
2758
2759         float speed = 1.0f;
2760         AudioTimeAxisView *atav;
2761
2762         if ( clicked_axisview != 0 && (atav = dynamic_cast<AudioTimeAxisView*>(clicked_axisview)) != 0 ) {
2763                 if (atav->get_diskstream() != 0) {
2764                         speed = atav->get_diskstream()->speed();
2765                 }
2766         }
2767
2768         begin_reversible_command (_("trim to edit"));
2769         XMLNode &before = region->playlist()->get_state();
2770         region->trim_front ( session_frame_to_track_frame(edit_cursor->current_frame, speed), this);
2771         XMLNode &after = region->playlist()->get_state();
2772         session->add_command(new MementoCommand<Playlist>(*(region->playlist()), &before, &after));
2773         commit_reversible_command ();
2774 }
2775
2776 void
2777 Editor::unfreeze_route ()
2778 {
2779         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2780                 return;
2781         }
2782         
2783         clicked_routeview->track()->unfreeze ();
2784 }
2785
2786 void*
2787 Editor::_freeze_thread (void* arg)
2788 {
2789         PBD::ThreadCreated (pthread_self(), X_("Freeze"));
2790         return static_cast<Editor*>(arg)->freeze_thread ();
2791 }
2792
2793 void*
2794 Editor::freeze_thread ()
2795 {
2796         clicked_routeview->audio_track()->freeze (*current_interthread_info);
2797         return 0;
2798 }
2799
2800 gint
2801 Editor::freeze_progress_timeout (void *arg)
2802 {
2803         interthread_progress_bar.set_fraction (current_interthread_info->progress/100);
2804         return !(current_interthread_info->done || current_interthread_info->cancel);
2805 }
2806
2807 void
2808 Editor::freeze_route ()
2809 {
2810         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
2811                 return;
2812         }
2813         
2814         InterThreadInfo itt;
2815
2816         if (interthread_progress_window == 0) {
2817                 build_interthread_progress_window ();
2818         }
2819         
2820         interthread_progress_window->set_title (_("ardour: freeze"));
2821         interthread_progress_window->set_position (Gtk::WIN_POS_MOUSE);
2822         interthread_progress_window->show_all ();
2823         interthread_progress_bar.set_fraction (0.0f);
2824         interthread_progress_label.set_text ("");
2825         interthread_cancel_label.set_text (_("Cancel Freeze"));
2826         current_interthread_info = &itt;
2827
2828         interthread_progress_connection = 
2829           Glib::signal_timeout().connect (bind (mem_fun(*this, &Editor::freeze_progress_timeout), (gpointer) 0), 100);
2830
2831         itt.done = false;
2832         itt.cancel = false;
2833         itt.progress = 0.0f;
2834
2835         pthread_create (&itt.thread, 0, _freeze_thread, this);
2836
2837         track_canvas.get_window()->set_cursor (Gdk::Cursor (Gdk::WATCH));
2838
2839         while (!itt.done && !itt.cancel) {
2840                 gtk_main_iteration ();
2841         }
2842
2843         interthread_progress_connection.disconnect ();
2844         interthread_progress_window->hide_all ();
2845         current_interthread_info = 0;
2846         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
2847 }
2848
2849 void
2850 Editor::bounce_range_selection ()
2851 {
2852         if (selection->time.empty()) {
2853                 return;
2854         }
2855
2856         TrackViewList *views = get_valid_views (selection->time.track, selection->time.group);
2857
2858         jack_nframes_t start = selection->time[clicked_selection].start;
2859         jack_nframes_t end = selection->time[clicked_selection].end;
2860         jack_nframes_t cnt = end - start + 1;
2861         
2862         begin_reversible_command (_("bounce range"));
2863
2864         for (TrackViewList::iterator i = views->begin(); i != views->end(); ++i) {
2865
2866                 AudioTimeAxisView* atv;
2867
2868                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*i)) == 0) {
2869                         continue;
2870                 }
2871                 
2872                 Playlist* playlist;
2873                 
2874                 if ((playlist = atv->playlist()) == 0) {
2875                         return;
2876                 }
2877
2878                 InterThreadInfo itt;
2879                 
2880                 itt.done = false;
2881                 itt.cancel = false;
2882                 itt.progress = false;
2883                 
2884                 XMLNode &before = playlist->get_state();
2885                 atv->audio_track()->bounce_range (start, cnt, itt);
2886                 XMLNode &after = playlist->get_state();
2887                 session->add_command (new MementoCommand<Playlist> (*playlist, &before, &after));
2888         }
2889         
2890         commit_reversible_command ();
2891         
2892         delete views;
2893 }
2894
2895 void
2896 Editor::cut ()
2897 {
2898         cut_copy (Cut);
2899 }
2900
2901 void
2902 Editor::copy ()
2903 {
2904         cut_copy (Copy);
2905 }
2906
2907 void 
2908 Editor::cut_copy (CutCopyOp op)
2909 {
2910         /* only cancel selection if cut/copy is successful.*/
2911
2912         string opname;
2913
2914         switch (op) {
2915         case Cut:
2916                 opname = _("cut");
2917                 break;
2918         case Copy:
2919                 opname = _("copy");
2920                 break;
2921         case Clear:
2922                 opname = _("clear");
2923                 break;
2924         }
2925         
2926         cut_buffer->clear ();
2927
2928         switch (current_mouse_mode()) {
2929         case MouseObject: 
2930                 if (!selection->regions.empty() || !selection->points.empty()) {
2931
2932                         begin_reversible_command (opname + _(" objects"));
2933
2934                         if (!selection->regions.empty()) {
2935                                 
2936                                 cut_copy_regions (op);
2937                                 
2938                                 if (op == Cut) {
2939                                         selection->clear_regions ();
2940                                 }
2941                         }
2942
2943                         if (!selection->points.empty()) {
2944                                 cut_copy_points (op);
2945
2946                                 if (op == Cut) {
2947                                         selection->clear_points ();
2948                                 }
2949                         }
2950
2951                         commit_reversible_command ();   
2952                 }
2953                 break;
2954                 
2955         case MouseRange:
2956                 if (!selection->time.empty()) {
2957
2958                         begin_reversible_command (opname + _(" range"));
2959                         cut_copy_ranges (op);
2960                         commit_reversible_command ();
2961
2962                         if (op == Cut) {
2963                                 selection->clear_time ();
2964                         }
2965                         
2966                 }
2967                 break;
2968                 
2969         default:
2970                 break;
2971         }
2972 }
2973
2974 void
2975 Editor::cut_copy_points (CutCopyOp op)
2976 {
2977         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
2978
2979                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
2980
2981                 if (atv) {
2982                         atv->cut_copy_clear_objects (selection->points, op);
2983                 } 
2984         }
2985 }
2986
2987 void
2988 Editor::cut_copy_regions (CutCopyOp op)
2989 {
2990         typedef std::map<AudioPlaylist*,AudioPlaylist*> PlaylistMapping;
2991         PlaylistMapping pmap;
2992         jack_nframes_t first_position = max_frames;
2993         set<Playlist*> freezelist;
2994         pair<set<Playlist*>::iterator,bool> insert_result;
2995
2996         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ++x) {
2997                 first_position = min ((*x)->region()->position(), first_position);
2998
2999                 if (op == Cut || op == Clear) {
3000                         AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
3001                         if (pl) {
3002                                 insert_result = freezelist.insert (pl);
3003                                 if (insert_result.second) {
3004                                         pl->freeze ();
3005                                         session->add_command (new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
3006                                 }
3007                         }
3008                 }
3009         }
3010
3011         for (RegionSelection::iterator x = selection->regions.begin(); x != selection->regions.end(); ) {
3012
3013                 AudioPlaylist *pl = dynamic_cast<AudioPlaylist*>((*x)->region()->playlist());
3014                 AudioPlaylist* npl;
3015                 RegionSelection::iterator tmp;
3016                 
3017                 tmp = x;
3018                 ++tmp;
3019
3020                 if (pl) {
3021
3022                         PlaylistMapping::iterator pi = pmap.find (pl);
3023                         
3024                         if (pi == pmap.end()) {
3025                                 npl = new AudioPlaylist (*session, "cutlist", true);
3026                                 npl->freeze();
3027                                 pmap[pl] = npl;
3028                         } else {
3029                                 npl = pi->second;
3030                         }
3031
3032                         // FIXME
3033                         boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion>((*x)->region());
3034                         switch (op) {
3035                         case Cut:
3036                                 if (!ar) break;
3037
3038                                 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3039                                 pl->remove_region (((*x)->region()));
3040                                 break;
3041
3042                         case Copy:
3043                                 if (!ar) break;
3044
3045                                 npl->add_region (RegionFactory::create (ar), (*x)->region()->position() - first_position);
3046                                 break;
3047
3048                         case Clear:
3049                                 pl->remove_region (((*x)->region()));
3050                                 break;
3051                         }
3052                 }
3053
3054                 x = tmp;
3055         }
3056
3057         list<Playlist*> foo;
3058
3059         for (PlaylistMapping::iterator i = pmap.begin(); i != pmap.end(); ++i) {
3060                 foo.push_back (i->second);
3061         }
3062
3063         if (!foo.empty()) {
3064                 cut_buffer->set (foo);
3065         }
3066         
3067         for (set<Playlist*>::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
3068                 (*pl)->thaw ();
3069                 session->add_command (new MementoCommand<Playlist>(*(*pl), 0, &(*pl)->get_state()));
3070         }
3071 }
3072
3073 void
3074 Editor::cut_copy_ranges (CutCopyOp op)
3075 {
3076         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3077                 (*i)->cut_copy_clear (*selection, op);
3078         }
3079 }
3080
3081 void
3082 Editor::paste (float times)
3083 {
3084         paste_internal (edit_cursor->current_frame, times);
3085 }
3086
3087 void
3088 Editor::mouse_paste ()
3089 {
3090         int x, y;
3091         double wx, wy;
3092
3093         track_canvas.get_pointer (x, y);
3094         track_canvas.window_to_world (x, y, wx, wy);
3095         wx += horizontal_adjustment.get_value();
3096         wy += vertical_adjustment.get_value();
3097
3098         GdkEvent event;
3099         event.type = GDK_BUTTON_RELEASE;
3100         event.button.x = wx;
3101         event.button.y = wy;
3102         
3103         jack_nframes_t where = event_frame (&event, 0, 0);
3104         snap_to (where);
3105         paste_internal (where, 1);
3106 }
3107
3108 void
3109 Editor::paste_internal (jack_nframes_t position, float times)
3110 {
3111         bool commit = false;
3112
3113         if (cut_buffer->empty() || selection->tracks.empty()) {
3114                 return;
3115         }
3116
3117         if (position == max_frames) {
3118                 position = edit_cursor->current_frame;
3119         }
3120
3121         begin_reversible_command (_("paste"));
3122
3123         TrackSelection::iterator i;
3124         size_t nth;
3125
3126         for (nth = 0, i = selection->tracks.begin(); i != selection->tracks.end(); ++i, ++nth) {
3127                 
3128                 /* undo/redo is handled by individual tracks */
3129
3130                 if ((*i)->paste (position, times, *cut_buffer, nth)) {
3131                         commit = true;
3132                 }
3133         }
3134
3135         if (commit) {
3136                 commit_reversible_command ();
3137         }
3138 }
3139
3140 void
3141 Editor::paste_named_selection (float times)
3142 {
3143         TrackSelection::iterator t;
3144
3145         Glib::RefPtr<TreeSelection> selected = named_selection_display.get_selection();
3146
3147         if (selected->count_selected_rows() != 1 || selection->tracks.empty()) {
3148                 return;
3149         }
3150
3151         TreeModel::iterator i = selected->get_selected();
3152         NamedSelection* ns = (*i)[named_selection_columns.selection];
3153
3154         list<Playlist*>::iterator chunk;
3155         list<Playlist*>::iterator tmp;
3156
3157         chunk = ns->playlists.begin();
3158                 
3159         begin_reversible_command (_("paste chunk"));
3160
3161         for (t = selection->tracks.begin(); t != selection->tracks.end(); ++t) {
3162                 
3163                 AudioTimeAxisView* atv;
3164                 Playlist* pl;
3165                 AudioPlaylist* apl;
3166
3167                 if ((atv = dynamic_cast<AudioTimeAxisView*> (*t)) == 0) {
3168                         continue;
3169                 }
3170
3171                 if ((pl = atv->playlist()) == 0) {
3172                         continue;
3173                 }
3174
3175                 if ((apl = dynamic_cast<AudioPlaylist*> (pl)) == 0) {
3176                         continue;
3177                 }
3178
3179                 tmp = chunk;
3180                 ++tmp;
3181
3182                 XMLNode &before = apl->get_state();
3183                 apl->paste (**chunk, edit_cursor->current_frame, times);
3184                 session->add_command(new MementoCommand<AudioPlaylist>(*apl, &before, &apl->get_state()));
3185
3186                 if (tmp != ns->playlists.end()) {
3187                         chunk = tmp;
3188                 }
3189         }
3190
3191         commit_reversible_command();
3192 }
3193
3194 void
3195 Editor::duplicate_some_regions (RegionSelection& regions, float times)
3196 {
3197         Playlist *playlist; 
3198         RegionSelection sel = regions; // clear (below) will clear the argument list
3199                 
3200         begin_reversible_command (_("duplicate region"));
3201
3202         selection->clear_regions ();
3203
3204         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
3205
3206                 boost::shared_ptr<Region> r ((*i)->region());
3207
3208                 TimeAxisView& tv = (*i)->get_time_axis_view();
3209                 AudioTimeAxisView* atv = dynamic_cast<AudioTimeAxisView*> (&tv);
3210                 sigc::connection c = atv->view()->RegionViewAdded.connect (mem_fun(*this, &Editor::collect_new_region_view));
3211                 
3212                 playlist = (*i)->region()->playlist();
3213                 XMLNode &before = playlist->get_state();
3214                 playlist->duplicate (r, r->last_frame(), times);
3215                 session->add_command(new MementoCommand<Playlist>(*playlist, &before, &playlist->get_state()));
3216
3217                 c.disconnect ();
3218
3219                 if (latest_regionview) {
3220                         selection->add (latest_regionview);
3221                 }
3222         }
3223                 
3224
3225         commit_reversible_command ();
3226 }
3227
3228 void
3229 Editor::duplicate_selection (float times)
3230 {
3231         if (selection->time.empty() || selection->tracks.empty()) {
3232                 return;
3233         }
3234
3235         Playlist *playlist; 
3236         vector<boost::shared_ptr<AudioRegion> > new_regions;
3237         vector<boost::shared_ptr<AudioRegion> >::iterator ri;
3238                 
3239         create_region_from_selection (new_regions);
3240
3241         if (new_regions.empty()) {
3242                 return;
3243         }
3244         
3245         begin_reversible_command (_("duplicate selection"));
3246
3247         ri = new_regions.begin();
3248
3249         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3250                 if ((playlist = (*i)->playlist()) == 0) {
3251                         continue;
3252                 }
3253                 XMLNode &before = playlist->get_state();
3254                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
3255                 XMLNode &after = playlist->get_state();
3256                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3257
3258                 ++ri;
3259                 if (ri == new_regions.end()) {
3260                         --ri;
3261                 }
3262         }
3263
3264         commit_reversible_command ();
3265 }
3266
3267 void
3268 Editor::reset_point_selection ()
3269 {
3270         /* reset all selected points to the relevant default value */
3271
3272         cerr << "point selection has " << selection->points.size() << " entries\n";
3273         
3274         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3275                 
3276                 AutomationTimeAxisView* atv = dynamic_cast<AutomationTimeAxisView*>(&(*i).track);
3277                 
3278                 if (atv) {
3279                         atv->reset_objects (selection->points);
3280                 } 
3281         }
3282 }
3283
3284 void
3285 Editor::center_playhead ()
3286 {
3287         float page = canvas_width * frames_per_unit;
3288
3289         center_screen_internal (playhead_cursor->current_frame, page);
3290 }
3291
3292 void
3293 Editor::center_edit_cursor ()
3294 {
3295         float page = canvas_width * frames_per_unit;
3296
3297         center_screen_internal (edit_cursor->current_frame, page);
3298 }
3299
3300 void
3301 Editor::clear_playlist (Playlist& playlist)
3302 {
3303         begin_reversible_command (_("clear playlist"));
3304         XMLNode &before = playlist.get_state();
3305         playlist.clear ();
3306         XMLNode &after = playlist.get_state();
3307         session->add_command (new MementoCommand<Playlist>(playlist, &before, &after));
3308         commit_reversible_command ();
3309 }
3310
3311 void
3312 Editor::nudge_track (bool use_edit_cursor, bool forwards)
3313 {
3314         Playlist *playlist; 
3315         jack_nframes_t distance;
3316         jack_nframes_t next_distance;
3317         jack_nframes_t start;
3318
3319         if (use_edit_cursor) {
3320                 start = edit_cursor->current_frame;
3321         } else {
3322                 start = 0;
3323         }
3324
3325         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
3326                 return;
3327         }
3328         
3329         if (selection->tracks.empty()) {
3330                 return;
3331         }
3332         
3333         begin_reversible_command (_("nudge track"));
3334         
3335         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
3336
3337                 if ((playlist = (*i)->playlist()) == 0) {
3338                         continue;
3339                 }               
3340                 
3341                 XMLNode &before = playlist->get_state();
3342                 playlist->nudge_after (start, distance, forwards);
3343                 XMLNode &after = playlist->get_state();
3344                 session->add_command (new MementoCommand<Playlist>(*playlist, &before, &after));
3345         }
3346         
3347         commit_reversible_command ();                   
3348 }
3349
3350 void
3351 Editor::remove_last_capture ()
3352 {
3353         vector<string> choices;
3354         string prompt;
3355         
3356         if (!session) {
3357                 return;
3358         }
3359
3360         if (Config->get_verify_remove_last_capture()) {
3361                 prompt  = _("Do you really want to destroy the last capture?"
3362                             "\n(This is destructive and cannot be undone)");
3363
3364                 choices.push_back (_("No, do nothing."));
3365                 choices.push_back (_("Yes, destroy it."));
3366                 
3367                 Gtkmm2ext::Choice prompter (prompt, choices);
3368                 
3369                 if (prompter.run () == 1) {
3370                         session->remove_last_capture ();
3371                 }
3372
3373         } else {
3374                 session->remove_last_capture();
3375         }
3376 }
3377
3378 void
3379 Editor::normalize_region ()
3380 {
3381         if (!session) {
3382                 return;
3383         }
3384
3385         if (selection->regions.empty()) {
3386                 return;
3387         }
3388
3389         begin_reversible_command (_("normalize"));
3390
3391         track_canvas.get_window()->set_cursor (*wait_cursor);
3392         gdk_flush ();
3393
3394         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3395                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3396                 if (!arv)
3397                         continue;
3398                 XMLNode &before = arv->region()->get_state();
3399                 arv->audio_region()->normalize_to (0.0f);
3400                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3401         }
3402
3403         commit_reversible_command ();
3404         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3405 }
3406
3407
3408 void
3409 Editor::denormalize_region ()
3410 {
3411         if (!session) {
3412                 return;
3413         }
3414
3415         if (selection->regions.empty()) {
3416                 return;
3417         }
3418
3419         begin_reversible_command ("denormalize");
3420
3421         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
3422                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3423                 if (!arv)
3424                         continue;
3425                 XMLNode &before = arv->region()->get_state();
3426                 arv->audio_region()->set_scale_amplitude (1.0f);
3427                 session->add_command (new MementoCommand<Region>(*(arv->region().get()), &before, &arv->region()->get_state()));
3428         }
3429
3430         commit_reversible_command ();
3431 }
3432
3433
3434 void
3435 Editor::reverse_region ()
3436 {
3437         if (!session) {
3438                 return;
3439         }
3440
3441         Reverse rev (*session);
3442         apply_filter (rev, _("reverse regions"));
3443 }
3444
3445 void
3446 Editor::apply_filter (AudioFilter& filter, string command)
3447 {
3448         if (selection->regions.empty()) {
3449                 return;
3450         }
3451
3452         begin_reversible_command (command);
3453
3454         track_canvas.get_window()->set_cursor (*wait_cursor);
3455         gdk_flush ();
3456
3457         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ) {
3458                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
3459                 if (!arv)
3460                         continue;
3461
3462                 Playlist* playlist = arv->region()->playlist();
3463
3464                 RegionSelection::iterator tmp;
3465                 
3466                 tmp = r;
3467                 ++tmp;
3468
3469                 if (arv->audio_region()->apply (filter) == 0) {
3470
3471                         XMLNode &before = playlist->get_state();
3472                         playlist->replace_region (arv->region(), filter.results.front(), arv->region()->position());
3473                         XMLNode &after = playlist->get_state();
3474                         session->add_command(new MementoCommand<Playlist>(*playlist, &before, &after));
3475                 } else {
3476                         goto out;
3477                 }
3478
3479                 r = tmp;
3480         }
3481
3482         commit_reversible_command ();
3483         selection->regions.clear ();
3484
3485   out:
3486         track_canvas.get_window()->set_cursor (*current_canvas_cursor);
3487 }
3488
3489 void
3490 Editor::region_selection_op (void (Region::*pmf)(void))
3491 {
3492         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3493                 Region* region = (*i)->region().get();
3494                 (region->*pmf)();
3495         }
3496 }
3497
3498
3499 void
3500 Editor::region_selection_op (void (Region::*pmf)(void*), void *arg)
3501 {
3502         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3503                 Region* region = (*i)->region().get();
3504                 (region->*pmf)(arg);
3505         }
3506 }
3507
3508 void
3509 Editor::region_selection_op (void (Region::*pmf)(bool), bool yn)
3510 {
3511         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3512                 Region* region = (*i)->region().get();
3513                 (region->*pmf)(yn);
3514         }
3515 }
3516
3517 void
3518 Editor::external_edit_region ()
3519 {
3520         if (!clicked_regionview) {
3521                 return;
3522         }
3523
3524         /* more to come */
3525 }
3526
3527 void
3528 Editor::brush (jack_nframes_t pos)
3529 {
3530         RegionSelection sel;
3531         snap_to (pos);
3532
3533         if (selection->regions.empty()) {
3534                 /* XXX get selection from region list */
3535         } else { 
3536                 sel = selection->regions;
3537         }
3538
3539         if (sel.empty()) {
3540                 return;
3541         }
3542
3543         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3544                 mouse_brush_insert_region ((*i), pos);
3545         }
3546 }
3547
3548 void
3549 Editor::toggle_gain_envelope_visibility ()
3550 {
3551         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3552                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3553                 if (arv)
3554                         arv->set_envelope_visible (!arv->envelope_visible());
3555         }
3556 }
3557
3558 void
3559 Editor::toggle_gain_envelope_active ()
3560 {
3561         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
3562                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
3563                 if (arv)
3564                         arv->audio_region()->set_envelope_active (true);
3565         }
3566 }