Fix incredibly unlikely NULL pointer dereference.
[ardour.git] / gtk2_ardour / editor_ops.cc
1 /*
2     Copyright (C) 2000-2004 Paul Davis
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 /* Note: public Editor methods are documented in public_editor.h */
21
22 #include <unistd.h>
23
24 #include <cstdlib>
25 #include <cmath>
26 #include <string>
27 #include <limits>
28 #include <map>
29 #include <set>
30
31 #include "pbd/error.h"
32 #include "pbd/basename.h"
33 #include "pbd/pthread_utils.h"
34 #include "pbd/memento_command.h"
35 #include "pbd/unwind.h"
36 #include "pbd/whitespace.h"
37 #include "pbd/stateful_diff_command.h"
38
39 #include <gtkmm2ext/utils.h>
40 #include <gtkmm2ext/choice.h>
41 #include <gtkmm2ext/popup.h>
42
43 #include "ardour/audio_track.h"
44 #include "ardour/audioregion.h"
45 #include "ardour/dB.h"
46 #include "ardour/location.h"
47 #include "ardour/midi_region.h"
48 #include "ardour/midi_track.h"
49 #include "ardour/operations.h"
50 #include "ardour/playlist_factory.h"
51 #include "ardour/profile.h"
52 #include "ardour/quantize.h"
53 #include "ardour/region_factory.h"
54 #include "ardour/reverse.h"
55 #include "ardour/session.h"
56 #include "ardour/session_playlists.h"
57 #include "ardour/strip_silence.h"
58 #include "ardour/transient_detector.h"
59
60 #include "canvas/canvas.h"
61
62 #include "actions.h"
63 #include "ardour_ui.h"
64 #include "audio_region_view.h"
65 #include "audio_streamview.h"
66 #include "audio_time_axis.h"
67 #include "automation_region_view.h"
68 #include "automation_time_axis.h"
69 #include "control_point.h"
70 #include "debug.h"
71 #include "editing.h"
72 #include "editor.h"
73 #include "editor_cursors.h"
74 #include "editor_drag.h"
75 #include "editor_regions.h"
76 #include "editor_routes.h"
77 #include "gui_thread.h"
78 #include "insert_time_dialog.h"
79 #include "interthread_progress_window.h"
80 #include "item_counts.h"
81 #include "keyboard.h"
82 #include "midi_region_view.h"
83 #include "mixer_strip.h"
84 #include "mouse_cursors.h"
85 #include "normalize_dialog.h"
86 #include "patch_change_dialog.h"
87 #include "quantize_dialog.h"
88 #include "region_gain_line.h"
89 #include "rgb_macros.h"
90 #include "route_time_axis.h"
91 #include "selection.h"
92 #include "selection_templates.h"
93 #include "streamview.h"
94 #include "strip_silence_dialog.h"
95 #include "time_axis_view.h"
96 #include "transpose_dialog.h"
97
98 #include "i18n.h"
99
100 using namespace std;
101 using namespace ARDOUR;
102 using namespace PBD;
103 using namespace Gtk;
104 using namespace Gtkmm2ext;
105 using namespace Editing;
106 using Gtkmm2ext::Keyboard;
107
108 /***********************************************************************
109   Editor operations
110  ***********************************************************************/
111
112 void
113 Editor::undo (uint32_t n)
114 {
115         if (_drags->active ()) {
116                 _drags->abort ();
117         }
118         
119         if (_session) {
120                 _session->undo (n);
121         }
122 }
123
124 void
125 Editor::redo (uint32_t n)
126 {
127         if (_drags->active ()) {
128                 _drags->abort ();
129         }
130         
131         if (_session) {
132                 _session->redo (n);
133         }
134 }
135
136 void
137 Editor::split_regions_at (framepos_t where, RegionSelection& regions)
138 {
139         bool frozen = false;
140
141         RegionSelection pre_selected_regions = selection->regions;
142         bool working_on_selection = !pre_selected_regions.empty();
143
144         list<boost::shared_ptr<Playlist> > used_playlists;
145         list<RouteTimeAxisView*> used_trackviews;
146
147         if (regions.empty()) {
148                 return;
149         }
150
151         begin_reversible_command (_("split"));
152
153         // if splitting a single region, and snap-to is using
154         // region boundaries, don't pay attention to them
155
156         if (regions.size() == 1) {
157                 switch (_snap_type) {
158                 case SnapToRegionStart:
159                 case SnapToRegionSync:
160                 case SnapToRegionEnd:
161                         break;
162                 default:
163                         snap_to (where);
164                 }
165         } else {
166                 snap_to (where);
167
168                 frozen = true;
169                 EditorFreeze(); /* Emit Signal */
170         }
171
172         for (RegionSelection::iterator a = regions.begin(); a != regions.end(); ) {
173
174                 RegionSelection::iterator tmp;
175
176                 /* XXX this test needs to be more complicated, to make sure we really
177                    have something to split.
178                 */
179
180                 if (!(*a)->region()->covers (where)) {
181                         ++a;
182                         continue;
183                 }
184
185                 tmp = a;
186                 ++tmp;
187
188                 boost::shared_ptr<Playlist> pl = (*a)->region()->playlist();
189
190                 if (!pl) {
191                         a = tmp;
192                         continue;
193                 }
194
195                 if (!pl->frozen()) {
196                         /* we haven't seen this playlist before */
197
198                         /* remember used playlists so we can thaw them later */
199                         used_playlists.push_back(pl);
200
201                         TimeAxisView& tv = (*a)->get_time_axis_view();
202                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
203                         if (rtv) {
204                                 used_trackviews.push_back (rtv);
205                         }
206                         pl->freeze();
207                 }
208
209
210                 if (pl) {
211                         pl->clear_changes ();
212                         pl->split_region ((*a)->region(), where);
213                         _session->add_command (new StatefulDiffCommand (pl));
214                 }
215
216                 a = tmp;
217         }
218
219         vector<sigc::connection> region_added_connections;
220
221         for (list<RouteTimeAxisView*>::iterator i = used_trackviews.begin(); i != used_trackviews.end(); ++i) {
222                 region_added_connections.push_back ((*i)->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view)));
223         }
224         
225         latest_regionviews.clear ();
226
227         while (used_playlists.size() > 0) {
228                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
229                 (*i)->thaw();
230                 used_playlists.pop_front();
231         }
232
233         for (vector<sigc::connection>::iterator c = region_added_connections.begin(); c != region_added_connections.end(); ++c) {
234                 (*c).disconnect ();
235         }
236         
237         commit_reversible_command ();
238
239         if (frozen){
240                 EditorThaw(); /* Emit Signal */
241         }
242
243         if (ARDOUR::Profile->get_mixbus()) {
244                 //IFF we were working on selected regions, try to reinstate the other region selections that existed before the freeze/thaw.
245                 _ignore_follow_edits = true;  //a split will change the region selection in mysterious ways;  its not practical or wanted to follow this edit
246                 if( working_on_selection ) {
247                         selection->add ( pre_selected_regions );
248                         selection->add (latest_regionviews);  //these are the new regions created after the split
249                 }
250                 _ignore_follow_edits = false;
251         }
252 }
253
254 /** Move one extreme of the current range selection.  If more than one range is selected,
255  *  the start of the earliest range or the end of the latest range is moved.
256  *
257  *  @param move_end true to move the end of the current range selection, false to move
258  *  the start.
259  *  @param next true to move the extreme to the next region boundary, false to move to
260  *  the previous.
261  */
262 void
263 Editor::move_range_selection_start_or_end_to_region_boundary (bool move_end, bool next)
264 {
265         if (selection->time.start() == selection->time.end_frame()) {
266                 return;
267         }
268
269         framepos_t start = selection->time.start ();
270         framepos_t end = selection->time.end_frame ();
271
272         /* the position of the thing we may move */
273         framepos_t pos = move_end ? end : start;
274         int dir = next ? 1 : -1;
275
276         /* so we don't find the current region again */
277         if (dir > 0 || pos > 0) {
278                 pos += dir;
279         }
280
281         framepos_t const target = get_region_boundary (pos, dir, true, false);
282         if (target < 0) {
283                 return;
284         }
285
286         if (move_end) {
287                 end = target;
288         } else {
289                 start = target;
290         }
291
292         if (end < start) {
293                 return;
294         }
295
296         begin_reversible_command (_("alter selection"));
297         selection->set_preserving_all_ranges (start, end);
298         commit_reversible_command ();
299 }
300
301 bool
302 Editor::nudge_forward_release (GdkEventButton* ev)
303 {
304         if (ev->state & Keyboard::PrimaryModifier) {
305                 nudge_forward (false, true);
306         } else {
307                 nudge_forward (false, false);
308         }
309         return false;
310 }
311
312 bool
313 Editor::nudge_backward_release (GdkEventButton* ev)
314 {
315         if (ev->state & Keyboard::PrimaryModifier) {
316                 nudge_backward (false, true);
317         } else {
318                 nudge_backward (false, false);
319         }
320         return false;
321 }
322
323
324 void
325 Editor::nudge_forward (bool next, bool force_playhead)
326 {
327         framepos_t distance;
328         framepos_t next_distance;
329
330         if (!_session) {
331                 return;
332         }
333
334         RegionSelection rs = get_regions_from_selection_and_entered ();
335
336         if (!force_playhead && !rs.empty()) {
337
338                 begin_reversible_command (_("nudge regions forward"));
339
340                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
341                         boost::shared_ptr<Region> r ((*i)->region());
342
343                         distance = get_nudge_distance (r->position(), next_distance);
344
345                         if (next) {
346                                 distance = next_distance;
347                         }
348
349                         r->clear_changes ();
350                         r->set_position (r->position() + distance);
351                         _session->add_command (new StatefulDiffCommand (r));
352                 }
353
354                 commit_reversible_command ();
355
356
357         } else if (!force_playhead && !selection->markers.empty()) {
358
359                 bool is_start;
360
361                 begin_reversible_command (_("nudge location forward"));
362
363                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
364
365                         Location* loc = find_location_from_marker ((*i), is_start);
366
367                         if (loc) {
368
369                                 XMLNode& before (loc->get_state());
370
371                                 if (is_start) {
372                                         distance = get_nudge_distance (loc->start(), next_distance);
373                                         if (next) {
374                                                 distance = next_distance;
375                                         }
376                                         if (max_framepos - distance > loc->start() + loc->length()) {
377                                                 loc->set_start (loc->start() + distance);
378                                         } else {
379                                                 loc->set_start (max_framepos - loc->length());
380                                         }
381                                 } else {
382                                         distance = get_nudge_distance (loc->end(), next_distance);
383                                         if (next) {
384                                                 distance = next_distance;
385                                         }
386                                         if (max_framepos - distance > loc->end()) {
387                                                 loc->set_end (loc->end() + distance);
388                                         } else {
389                                                 loc->set_end (max_framepos);
390                                         }
391                                 }
392                                 XMLNode& after (loc->get_state());
393                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
394                         }
395                 }
396
397                 commit_reversible_command ();
398
399         } else {
400                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
401                 _session->request_locate (playhead_cursor->current_frame () + distance);
402         }
403 }
404
405 void
406 Editor::nudge_backward (bool next, bool force_playhead)
407 {
408         framepos_t distance;
409         framepos_t next_distance;
410
411         if (!_session) {
412                 return;
413         }
414
415         RegionSelection rs = get_regions_from_selection_and_entered ();
416
417         if (!force_playhead && !rs.empty()) {
418
419                 begin_reversible_command (_("nudge regions backward"));
420
421                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
422                         boost::shared_ptr<Region> r ((*i)->region());
423
424                         distance = get_nudge_distance (r->position(), next_distance);
425
426                         if (next) {
427                                 distance = next_distance;
428                         }
429
430                         r->clear_changes ();
431
432                         if (r->position() > distance) {
433                                 r->set_position (r->position() - distance);
434                         } else {
435                                 r->set_position (0);
436                         }
437                         _session->add_command (new StatefulDiffCommand (r));
438                 }
439
440                 commit_reversible_command ();
441
442         } else if (!force_playhead && !selection->markers.empty()) {
443
444                 bool is_start;
445
446                 begin_reversible_command (_("nudge location forward"));
447
448                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
449
450                         Location* loc = find_location_from_marker ((*i), is_start);
451
452                         if (loc) {
453
454                                 XMLNode& before (loc->get_state());
455
456                                 if (is_start) {
457                                         distance = get_nudge_distance (loc->start(), next_distance);
458                                         if (next) {
459                                                 distance = next_distance;
460                                         }
461                                         if (distance < loc->start()) {
462                                                 loc->set_start (loc->start() - distance);
463                                         } else {
464                                                 loc->set_start (0);
465                                         }
466                                 } else {
467                                         distance = get_nudge_distance (loc->end(), next_distance);
468
469                                         if (next) {
470                                                 distance = next_distance;
471                                         }
472
473                                         if (distance < loc->end() - loc->length()) {
474                                                 loc->set_end (loc->end() - distance);
475                                         } else {
476                                                 loc->set_end (loc->length());
477                                         }
478                                 }
479
480                                 XMLNode& after (loc->get_state());
481                                 _session->add_command (new MementoCommand<Location>(*loc, &before, &after));
482                         }
483                 }
484
485                 commit_reversible_command ();
486
487         } else {
488
489                 distance = get_nudge_distance (playhead_cursor->current_frame (), next_distance);
490
491                 if (playhead_cursor->current_frame () > distance) {
492                         _session->request_locate (playhead_cursor->current_frame () - distance);
493                 } else {
494                         _session->goto_start();
495                 }
496         }
497 }
498
499 void
500 Editor::nudge_forward_capture_offset ()
501 {
502         RegionSelection rs = get_regions_from_selection_and_entered ();
503
504         if (!_session || rs.empty()) {
505                 return;
506         }
507
508         begin_reversible_command (_("nudge forward"));
509
510         framepos_t const distance = _session->worst_output_latency();
511
512         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
513                 boost::shared_ptr<Region> r ((*i)->region());
514
515                 r->clear_changes ();
516                 r->set_position (r->position() + distance);
517                 _session->add_command(new StatefulDiffCommand (r));
518         }
519
520         commit_reversible_command ();
521 }
522
523 void
524 Editor::nudge_backward_capture_offset ()
525 {
526         RegionSelection rs = get_regions_from_selection_and_entered ();
527
528         if (!_session || rs.empty()) {
529                 return;
530         }
531
532         begin_reversible_command (_("nudge backward"));
533
534         framepos_t const distance = _session->worst_output_latency();
535
536         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
537                 boost::shared_ptr<Region> r ((*i)->region());
538
539                 r->clear_changes ();
540
541                 if (r->position() > distance) {
542                         r->set_position (r->position() - distance);
543                 } else {
544                         r->set_position (0);
545                 }
546                 _session->add_command(new StatefulDiffCommand (r));
547         }
548
549         commit_reversible_command ();
550 }
551
552 struct RegionSelectionPositionSorter {
553         bool operator() (RegionView* a, RegionView* b) {
554                 return a->region()->position() < b->region()->position();
555         }
556 };
557
558 void
559 Editor::sequence_regions ()
560 {
561         framepos_t r_end;
562         framepos_t r_end_prev;
563
564         int iCount=0;
565
566         if (!_session) {
567                 return;
568         }
569
570         RegionSelection rs = get_regions_from_selection_and_entered ();
571         rs.sort(RegionSelectionPositionSorter());
572
573         if (!rs.empty()) {
574
575                 begin_reversible_command (_("sequence regions"));
576                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
577                         boost::shared_ptr<Region> r ((*i)->region());
578
579                         r->clear_changes();
580
581                         if(r->locked())
582                         {
583                                 continue;
584                         }
585                         if(r->position_locked())
586                         {
587                                 continue;
588                         }
589                         if(iCount>0)
590                         {
591                                 r_end_prev=r_end;
592                                 r->set_position(r_end_prev);
593                         }
594
595                         _session->add_command (new StatefulDiffCommand (r));
596
597                         r_end=r->position() + r->length();
598
599                         iCount++;
600                 }
601                 commit_reversible_command ();
602         } 
603
604
605
606 /* DISPLAY MOTION */
607
608 void
609 Editor::move_to_start ()
610 {
611         _session->goto_start ();
612 }
613
614 void
615 Editor::move_to_end ()
616 {
617
618         _session->request_locate (_session->current_end_frame());
619 }
620
621 void
622 Editor::build_region_boundary_cache ()
623 {
624         framepos_t pos = 0;
625         vector<RegionPoint> interesting_points;
626         boost::shared_ptr<Region> r;
627         TrackViewList tracks;
628         bool at_end = false;
629
630         region_boundary_cache.clear ();
631
632         if (_session == 0) {
633                 return;
634         }
635
636         switch (_snap_type) {
637         case SnapToRegionStart:
638                 interesting_points.push_back (Start);
639                 break;
640         case SnapToRegionEnd:
641                 interesting_points.push_back (End);
642                 break;
643         case SnapToRegionSync:
644                 interesting_points.push_back (SyncPoint);
645                 break;
646         case SnapToRegionBoundary:
647                 interesting_points.push_back (Start);
648                 interesting_points.push_back (End);
649                 break;
650         default:
651                 fatal << string_compose (_("build_region_boundary_cache called with snap_type = %1"), _snap_type) << endmsg;
652                 abort(); /*NOTREACHED*/
653                 return;
654         }
655
656         TimeAxisView *ontrack = 0;
657         TrackViewList tlist;
658         
659         if (!selection->tracks.empty()) {
660                 tlist = selection->tracks.filter_to_unique_playlists ();
661         } else {
662                 tlist = track_views.filter_to_unique_playlists ();
663         }
664
665         while (pos < _session->current_end_frame() && !at_end) {
666
667                 framepos_t rpos;
668                 framepos_t lpos = max_framepos;
669
670                 for (vector<RegionPoint>::iterator p = interesting_points.begin(); p != interesting_points.end(); ++p) {
671
672                         if ((r = find_next_region (pos, *p, 1, tlist, &ontrack)) == 0) {
673                                 if (*p == interesting_points.back()) {
674                                         at_end = true;
675                                 }
676                                 /* move to next point type */
677                                 continue;
678                         }
679
680                         switch (*p) {
681                         case Start:
682                                 rpos = r->first_frame();
683                                 break;
684
685                         case End:
686                                 rpos = r->last_frame();
687                                 break;
688
689                         case SyncPoint:
690                                 rpos = r->sync_position ();
691                                 break;
692
693                         default:
694                                 break;
695                         }
696
697                         float speed = 1.0f;
698                         RouteTimeAxisView *rtav;
699
700                         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
701                                 if (rtav->track() != 0) {
702                                         speed = rtav->track()->speed();
703                                 }
704                         }
705
706                         rpos = track_frame_to_session_frame (rpos, speed);
707
708                         if (rpos < lpos) {
709                                 lpos = rpos;
710                         }
711
712                         /* prevent duplicates, but we don't use set<> because we want to be able
713                            to sort later.
714                         */
715
716                         vector<framepos_t>::iterator ri;
717
718                         for (ri = region_boundary_cache.begin(); ri != region_boundary_cache.end(); ++ri) {
719                                 if (*ri == rpos) {
720                                         break;
721                                 }
722                         }
723
724                         if (ri == region_boundary_cache.end()) {
725                                 region_boundary_cache.push_back (rpos);
726                         }
727                 }
728
729                 pos = lpos + 1;
730         }
731
732         /* finally sort to be sure that the order is correct */
733
734         sort (region_boundary_cache.begin(), region_boundary_cache.end());
735 }
736
737 boost::shared_ptr<Region>
738 Editor::find_next_region (framepos_t frame, RegionPoint point, int32_t dir, TrackViewList& tracks, TimeAxisView **ontrack)
739 {
740         TrackViewList::iterator i;
741         framepos_t closest = max_framepos;
742         boost::shared_ptr<Region> ret;
743         framepos_t rpos = 0;
744
745         float track_speed;
746         framepos_t track_frame;
747         RouteTimeAxisView *rtav;
748
749         for (i = tracks.begin(); i != tracks.end(); ++i) {
750
751                 framecnt_t distance;
752                 boost::shared_ptr<Region> r;
753
754                 track_speed = 1.0f;
755                 if ( (rtav = dynamic_cast<RouteTimeAxisView*>(*i)) != 0 ) {
756                         if (rtav->track()!=0)
757                                 track_speed = rtav->track()->speed();
758                 }
759
760                 track_frame = session_frame_to_track_frame(frame, track_speed);
761
762                 if ((r = (*i)->find_next_region (track_frame, point, dir)) == 0) {
763                         continue;
764                 }
765
766                 switch (point) {
767                 case Start:
768                         rpos = r->first_frame ();
769                         break;
770
771                 case End:
772                         rpos = r->last_frame ();
773                         break;
774
775                 case SyncPoint:
776                         rpos = r->sync_position ();
777                         break;
778                 }
779
780                 // rpos is a "track frame", converting it to "_session frame"
781                 rpos = track_frame_to_session_frame(rpos, track_speed);
782
783                 if (rpos > frame) {
784                         distance = rpos - frame;
785                 } else {
786                         distance = frame - rpos;
787                 }
788
789                 if (distance < closest) {
790                         closest = distance;
791                         if (ontrack != 0)
792                                 *ontrack = (*i);
793                         ret = r;
794                 }
795         }
796
797         return ret;
798 }
799
800 framepos_t
801 Editor::find_next_region_boundary (framepos_t pos, int32_t dir, const TrackViewList& tracks)
802 {
803         framecnt_t distance = max_framepos;
804         framepos_t current_nearest = -1;
805
806         for (TrackViewList::const_iterator i = tracks.begin(); i != tracks.end(); ++i) {
807                 framepos_t contender;
808                 framecnt_t d;
809
810                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
811
812                 if (!rtv) {
813                         continue;
814                 }
815
816                 if ((contender = rtv->find_next_region_boundary (pos, dir)) < 0) {
817                         continue;
818                 }
819
820                 d = ::llabs (pos - contender);
821
822                 if (d < distance) {
823                         current_nearest = contender;
824                         distance = d;
825                 }
826         }
827
828         return current_nearest;
829 }
830
831 framepos_t
832 Editor::get_region_boundary (framepos_t pos, int32_t dir, bool with_selection, bool only_onscreen)
833 {
834         framepos_t target;
835         TrackViewList tvl;
836
837         if (with_selection && Config->get_region_boundaries_from_selected_tracks()) {
838
839                 if (!selection->tracks.empty()) {
840
841                         target = find_next_region_boundary (pos, dir, selection->tracks);
842
843                 } else {
844
845                         if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
846                                 get_onscreen_tracks (tvl);
847                                 target = find_next_region_boundary (pos, dir, tvl);
848                         } else {
849                                 target = find_next_region_boundary (pos, dir, track_views);
850                         }
851                 }
852
853         } else {
854
855                 if (only_onscreen || Config->get_region_boundaries_from_onscreen_tracks()) {
856                         get_onscreen_tracks (tvl);
857                         target = find_next_region_boundary (pos, dir, tvl);
858                 } else {
859                         target = find_next_region_boundary (pos, dir, track_views);
860                 }
861         }
862
863         return target;
864 }
865
866 void
867 Editor::cursor_to_region_boundary (bool with_selection, int32_t dir)
868 {
869         framepos_t pos = playhead_cursor->current_frame ();
870         framepos_t target;
871
872         if (!_session) {
873                 return;
874         }
875
876         // so we don't find the current region again..
877         if (dir > 0 || pos > 0) {
878                 pos += dir;
879         }
880
881         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
882                 return;
883         }
884
885         _session->request_locate (target);
886 }
887
888 void
889 Editor::cursor_to_next_region_boundary (bool with_selection)
890 {
891         cursor_to_region_boundary (with_selection, 1);
892 }
893
894 void
895 Editor::cursor_to_previous_region_boundary (bool with_selection)
896 {
897         cursor_to_region_boundary (with_selection, -1);
898 }
899
900 void
901 Editor::cursor_to_region_point (EditorCursor* cursor, RegionPoint point, int32_t dir)
902 {
903         boost::shared_ptr<Region> r;
904         framepos_t pos = cursor->current_frame ();
905
906         if (!_session) {
907                 return;
908         }
909
910         TimeAxisView *ontrack = 0;
911
912         // so we don't find the current region again..
913         if (dir>0 || pos>0)
914                 pos+=dir;
915
916         if (!selection->tracks.empty()) {
917
918                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
919
920         } else if (clicked_axisview) {
921
922                 TrackViewList t;
923                 t.push_back (clicked_axisview);
924
925                 r = find_next_region (pos, point, dir, t, &ontrack);
926
927         } else {
928
929                 r = find_next_region (pos, point, dir, track_views, &ontrack);
930         }
931
932         if (r == 0) {
933                 return;
934         }
935
936         switch (point) {
937         case Start:
938                 pos = r->first_frame ();
939                 break;
940
941         case End:
942                 pos = r->last_frame ();
943                 break;
944
945         case SyncPoint:
946                 pos = r->sync_position ();
947                 break;
948         }
949
950         float speed = 1.0f;
951         RouteTimeAxisView *rtav;
952
953         if ( ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0 ) {
954                 if (rtav->track() != 0) {
955                         speed = rtav->track()->speed();
956                 }
957         }
958
959         pos = track_frame_to_session_frame(pos, speed);
960
961         if (cursor == playhead_cursor) {
962                 _session->request_locate (pos);
963         } else {
964                 cursor->set_position (pos);
965         }
966 }
967
968 void
969 Editor::cursor_to_next_region_point (EditorCursor* cursor, RegionPoint point)
970 {
971         cursor_to_region_point (cursor, point, 1);
972 }
973
974 void
975 Editor::cursor_to_previous_region_point (EditorCursor* cursor, RegionPoint point)
976 {
977         cursor_to_region_point (cursor, point, -1);
978 }
979
980 void
981 Editor::cursor_to_selection_start (EditorCursor *cursor)
982 {
983         framepos_t pos = 0;
984
985         switch (mouse_mode) {
986         case MouseObject:
987                 if (!selection->regions.empty()) {
988                         pos = selection->regions.start();
989                 }
990                 break;
991
992         case MouseRange:
993                 if (!selection->time.empty()) {
994                         pos = selection->time.start ();
995                 }
996                 break;
997
998         default:
999                 return;
1000         }
1001
1002         if (cursor == playhead_cursor) {
1003                 _session->request_locate (pos);
1004         } else {
1005                 cursor->set_position (pos);
1006         }
1007 }
1008
1009 void
1010 Editor::cursor_to_selection_end (EditorCursor *cursor)
1011 {
1012         framepos_t pos = 0;
1013
1014         switch (mouse_mode) {
1015         case MouseObject:
1016                 if (!selection->regions.empty()) {
1017                         pos = selection->regions.end_frame();
1018                 }
1019                 break;
1020
1021         case MouseRange:
1022                 if (!selection->time.empty()) {
1023                         pos = selection->time.end_frame ();
1024                 }
1025                 break;
1026
1027         default:
1028                 return;
1029         }
1030
1031         if (cursor == playhead_cursor) {
1032                 _session->request_locate (pos);
1033         } else {
1034                 cursor->set_position (pos);
1035         }
1036 }
1037
1038 void
1039 Editor::selected_marker_to_region_boundary (bool with_selection, int32_t dir)
1040 {
1041         framepos_t target;
1042         Location* loc;
1043         bool ignored;
1044
1045         if (!_session) {
1046                 return;
1047         }
1048
1049         if (selection->markers.empty()) {
1050                 framepos_t mouse;
1051                 bool ignored;
1052
1053                 if (!mouse_frame (mouse, ignored)) {
1054                         return;
1055                 }
1056
1057                 add_location_mark (mouse);
1058         }
1059
1060         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1061                 return;
1062         }
1063
1064         framepos_t pos = loc->start();
1065
1066         // so we don't find the current region again..
1067         if (dir > 0 || pos > 0) {
1068                 pos += dir;
1069         }
1070
1071         if ((target = get_region_boundary (pos, dir, with_selection, false)) < 0) {
1072                 return;
1073         }
1074
1075         loc->move_to (target);
1076 }
1077
1078 void
1079 Editor::selected_marker_to_next_region_boundary (bool with_selection)
1080 {
1081         selected_marker_to_region_boundary (with_selection, 1);
1082 }
1083
1084 void
1085 Editor::selected_marker_to_previous_region_boundary (bool with_selection)
1086 {
1087         selected_marker_to_region_boundary (with_selection, -1);
1088 }
1089
1090 void
1091 Editor::selected_marker_to_region_point (RegionPoint point, int32_t dir)
1092 {
1093         boost::shared_ptr<Region> r;
1094         framepos_t pos;
1095         Location* loc;
1096         bool ignored;
1097
1098         if (!_session || selection->markers.empty()) {
1099                 return;
1100         }
1101
1102         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1103                 return;
1104         }
1105
1106         TimeAxisView *ontrack = 0;
1107
1108         pos = loc->start();
1109
1110         // so we don't find the current region again..
1111         if (dir>0 || pos>0)
1112                 pos+=dir;
1113
1114         if (!selection->tracks.empty()) {
1115
1116                 r = find_next_region (pos, point, dir, selection->tracks, &ontrack);
1117
1118         } else {
1119
1120                 r = find_next_region (pos, point, dir, track_views, &ontrack);
1121         }
1122
1123         if (r == 0) {
1124                 return;
1125         }
1126
1127         switch (point) {
1128         case Start:
1129                 pos = r->first_frame ();
1130                 break;
1131
1132         case End:
1133                 pos = r->last_frame ();
1134                 break;
1135
1136         case SyncPoint:
1137                 pos = r->adjust_to_sync (r->first_frame());
1138                 break;
1139         }
1140
1141         float speed = 1.0f;
1142         RouteTimeAxisView *rtav;
1143
1144         if (ontrack != 0 && (rtav = dynamic_cast<RouteTimeAxisView*>(ontrack)) != 0) {
1145                 if (rtav->track() != 0) {
1146                         speed = rtav->track()->speed();
1147                 }
1148         }
1149
1150         pos = track_frame_to_session_frame(pos, speed);
1151
1152         loc->move_to (pos);
1153 }
1154
1155 void
1156 Editor::selected_marker_to_next_region_point (RegionPoint point)
1157 {
1158         selected_marker_to_region_point (point, 1);
1159 }
1160
1161 void
1162 Editor::selected_marker_to_previous_region_point (RegionPoint point)
1163 {
1164         selected_marker_to_region_point (point, -1);
1165 }
1166
1167 void
1168 Editor::selected_marker_to_selection_start ()
1169 {
1170         framepos_t pos = 0;
1171         Location* loc;
1172         bool ignored;
1173
1174         if (!_session || selection->markers.empty()) {
1175                 return;
1176         }
1177
1178         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1179                 return;
1180         }
1181
1182         switch (mouse_mode) {
1183         case MouseObject:
1184                 if (!selection->regions.empty()) {
1185                         pos = selection->regions.start();
1186                 }
1187                 break;
1188
1189         case MouseRange:
1190                 if (!selection->time.empty()) {
1191                         pos = selection->time.start ();
1192                 }
1193                 break;
1194
1195         default:
1196                 return;
1197         }
1198
1199         loc->move_to (pos);
1200 }
1201
1202 void
1203 Editor::selected_marker_to_selection_end ()
1204 {
1205         framepos_t pos = 0;
1206         Location* loc;
1207         bool ignored;
1208
1209         if (!_session || selection->markers.empty()) {
1210                 return;
1211         }
1212
1213         if ((loc = find_location_from_marker (selection->markers.front(), ignored)) == 0) {
1214                 return;
1215         }
1216
1217         switch (mouse_mode) {
1218         case MouseObject:
1219                 if (!selection->regions.empty()) {
1220                         pos = selection->regions.end_frame();
1221                 }
1222                 break;
1223
1224         case MouseRange:
1225                 if (!selection->time.empty()) {
1226                         pos = selection->time.end_frame ();
1227                 }
1228                 break;
1229
1230         default:
1231                 return;
1232         }
1233
1234         loc->move_to (pos);
1235 }
1236
1237 void
1238 Editor::scroll_playhead (bool forward)
1239 {
1240         framepos_t pos = playhead_cursor->current_frame ();
1241         framecnt_t delta = (framecnt_t) floor (current_page_samples() / 0.8);
1242
1243         if (forward) {
1244                 if (pos == max_framepos) {
1245                         return;
1246                 }
1247
1248                 if (pos < max_framepos - delta) {
1249                         pos += delta ;
1250                 } else {
1251                         pos = max_framepos;
1252                 }
1253
1254         } else {
1255
1256                 if (pos == 0) {
1257                         return;
1258                 }
1259
1260                 if (pos > delta) {
1261                         pos -= delta;
1262                 } else {
1263                         pos = 0;
1264                 }
1265         }
1266
1267         _session->request_locate (pos);
1268 }
1269
1270 void
1271 Editor::cursor_align (bool playhead_to_edit)
1272 {
1273         if (!_session) {
1274                 return;
1275         }
1276
1277         if (playhead_to_edit) {
1278
1279                 if (selection->markers.empty()) {
1280                         return;
1281                 }
1282
1283                 _session->request_locate (selection->markers.front()->position(), _session->transport_rolling());
1284
1285         } else {
1286                 /* move selected markers to playhead */
1287
1288                 for (MarkerSelection::iterator i = selection->markers.begin(); i != selection->markers.end(); ++i) {
1289                         bool ignored;
1290
1291                         Location* loc = find_location_from_marker (*i, ignored);
1292
1293                         if (loc->is_mark()) {
1294                                 loc->set_start (playhead_cursor->current_frame ());
1295                         } else {
1296                                 loc->set (playhead_cursor->current_frame (),
1297                                           playhead_cursor->current_frame () + loc->length());
1298                         }
1299                 }
1300         }
1301 }
1302
1303 void
1304 Editor::scroll_backward (float pages)
1305 {
1306         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1307         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1308
1309         framepos_t frame;
1310         if (leftmost_frame < cnt) {
1311                 frame = 0;
1312         } else {
1313                 frame = leftmost_frame - cnt;
1314         }
1315
1316         reset_x_origin (frame);
1317 }
1318
1319 void
1320 Editor::scroll_forward (float pages)
1321 {
1322         framepos_t const one_page = (framepos_t) rint (_visible_canvas_width * samples_per_pixel);
1323         framepos_t const cnt = (framepos_t) floor (pages * one_page);
1324
1325         framepos_t frame;
1326         if (max_framepos - cnt < leftmost_frame) {
1327                 frame = max_framepos - cnt;
1328         } else {
1329                 frame = leftmost_frame + cnt;
1330         }
1331
1332         reset_x_origin (frame);
1333 }
1334
1335 void
1336 Editor::scroll_tracks_down ()
1337 {
1338         double vert_value = vertical_adjustment.get_value() + vertical_adjustment.get_page_size();
1339         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1340                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1341         }
1342
1343         vertical_adjustment.set_value (vert_value);
1344 }
1345
1346 void
1347 Editor::scroll_tracks_up ()
1348 {
1349         vertical_adjustment.set_value (vertical_adjustment.get_value() - vertical_adjustment.get_page_size());
1350 }
1351
1352 void
1353 Editor::scroll_tracks_down_line ()
1354 {
1355         double vert_value = vertical_adjustment.get_value() + 60;
1356
1357         if (vert_value > vertical_adjustment.get_upper() - _visible_canvas_height) {
1358                 vert_value = vertical_adjustment.get_upper() - _visible_canvas_height;
1359         }
1360
1361         vertical_adjustment.set_value (vert_value);
1362 }
1363
1364 void
1365 Editor::scroll_tracks_up_line ()
1366 {
1367         reset_y_origin (vertical_adjustment.get_value() - 60);
1368 }
1369
1370 bool
1371 Editor::scroll_down_one_track ()
1372 {
1373         TrackViewList::reverse_iterator next = track_views.rend();
1374         std::pair<TimeAxisView*,double> res;
1375         const double top_of_trackviews = vertical_adjustment.get_value();
1376
1377         for (TrackViewList::reverse_iterator t = track_views.rbegin(); t != track_views.rend(); ++t) {
1378                 if ((*t)->hidden()) {
1379                         continue;
1380                 }
1381
1382
1383                 /* If this is the upper-most visible trackview, we want to display
1384                    the one above it (next)
1385                 */
1386
1387                 res = (*t)->covers_y_position (top_of_trackviews);
1388
1389                 if (res.first) {
1390                         break;
1391                 }
1392                 next = t;
1393         }
1394
1395         /* move to the track below the first one that covers the */
1396         
1397         if (next != track_views.rend()) {
1398                 ensure_time_axis_view_is_visible (**next, true);
1399                 return true;
1400         }
1401
1402         return false;
1403 }       
1404
1405 bool
1406 Editor::scroll_up_one_track ()
1407 {
1408         TrackViewList::iterator prev = track_views.end();
1409         std::pair<TimeAxisView*,double> res;
1410         double top_of_trackviews = vertical_adjustment.get_value ();
1411         
1412         for (TrackViewList::iterator t = track_views.begin(); t != track_views.end(); ++t) {
1413
1414                 if ((*t)->hidden()) {
1415                         continue;
1416                 }
1417
1418                 /* find the trackview at the top of the trackview group */
1419                 res = (*t)->covers_y_position (top_of_trackviews);
1420                 
1421                 if (res.first) {
1422                         break;
1423                 }
1424
1425                 prev = t;
1426         }
1427         
1428         if (prev != track_views.end()) {
1429                 ensure_time_axis_view_is_visible (**prev, true);
1430                 return true;
1431         }
1432
1433         return false;
1434 }
1435
1436 /* ZOOM */
1437
1438 void
1439 Editor::tav_zoom_step (bool coarser)
1440 {
1441         DisplaySuspender ds;
1442
1443         TrackViewList* ts;
1444
1445         if (selection->tracks.empty()) {
1446                 ts = &track_views;
1447         } else {
1448                 ts = &selection->tracks;
1449         }
1450         
1451         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1452                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1453                         tv->step_height (coarser);
1454         }
1455 }
1456
1457 void
1458 Editor::tav_zoom_smooth (bool coarser, bool force_all)
1459 {
1460         DisplaySuspender ds;
1461
1462         TrackViewList* ts;
1463
1464         if (selection->tracks.empty() || force_all) {
1465                 ts = &track_views;
1466         } else {
1467                 ts = &selection->tracks;
1468         }
1469         
1470         for (TrackViewList::iterator i = ts->begin(); i != ts->end(); ++i) {
1471                 TimeAxisView *tv = (static_cast<TimeAxisView*>(*i));
1472                 uint32_t h = tv->current_height ();
1473
1474                 if (coarser) {
1475                         if (h > 5) {
1476                                 h -= 5; // pixels
1477                                 if (h >= TimeAxisView::preset_height (HeightSmall)) {
1478                                         tv->set_height (h);
1479                                 }
1480                         }
1481                 } else {
1482                         tv->set_height (h + 5);
1483                 }
1484         }
1485 }
1486
1487
1488 void
1489 Editor::temporal_zoom_step (bool coarser)
1490 {
1491         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_step, coarser)
1492
1493         framecnt_t nspp = samples_per_pixel;
1494
1495         if (coarser) {
1496                 nspp *= 2;
1497         } else {
1498                 nspp /= 2;
1499         }
1500
1501         temporal_zoom (nspp);
1502 }
1503
1504 void
1505 Editor::temporal_zoom (framecnt_t fpp)
1506 {
1507         if (!_session) {
1508                 return;
1509         }
1510
1511         framepos_t current_page = current_page_samples();
1512         framepos_t current_leftmost = leftmost_frame;
1513         framepos_t current_rightmost;
1514         framepos_t current_center;
1515         framepos_t new_page_size;
1516         framepos_t half_page_size;
1517         framepos_t leftmost_after_zoom = 0;
1518         framepos_t where;
1519         bool in_track_canvas;
1520         framecnt_t nfpp;
1521         double l;
1522
1523         if (fpp == samples_per_pixel) {
1524                 return;
1525         }
1526
1527         // Imposing an arbitrary limit to zoom out as too much zoom out produces 
1528         // segfaults for lack of memory. If somebody decides this is not high enough I
1529         // believe it can be raisen to higher values but some limit must be in place.
1530         //
1531         // This constant represents 1 day @ 48kHz on a 1600 pixel wide display
1532         // all of which is used for the editor track displays. The whole day
1533         // would be 4147200000 samples, so 2592000 samples per pixel.
1534
1535         nfpp = min (fpp, (framecnt_t) 2592000);
1536         nfpp = max ((framecnt_t) 1, nfpp);
1537
1538         new_page_size = (framepos_t) floor (_visible_canvas_width * nfpp);
1539         half_page_size = new_page_size / 2;
1540
1541         switch (zoom_focus) {
1542         case ZoomFocusLeft:
1543                 leftmost_after_zoom = current_leftmost;
1544                 break;
1545
1546         case ZoomFocusRight:
1547                 current_rightmost = leftmost_frame + current_page;
1548                 if (current_rightmost < new_page_size) {
1549                         leftmost_after_zoom = 0;
1550                 } else {
1551                         leftmost_after_zoom = current_rightmost - new_page_size;
1552                 }
1553                 break;
1554
1555         case ZoomFocusCenter:
1556                 current_center = current_leftmost + (current_page/2);
1557                 if (current_center < half_page_size) {
1558                         leftmost_after_zoom = 0;
1559                 } else {
1560                         leftmost_after_zoom = current_center - half_page_size;
1561                 }
1562                 break;
1563
1564         case ZoomFocusPlayhead:
1565                 /* centre playhead */
1566                 l = playhead_cursor->current_frame () - (new_page_size * 0.5);
1567
1568                 if (l < 0) {
1569                         leftmost_after_zoom = 0;
1570                 } else if (l > max_framepos) {
1571                         leftmost_after_zoom = max_framepos - new_page_size;
1572                 } else {
1573                         leftmost_after_zoom = (framepos_t) l;
1574                 }
1575                 break;
1576
1577         case ZoomFocusMouse:
1578                 /* try to keep the mouse over the same point in the display */
1579
1580                 if (!mouse_frame (where, in_track_canvas)) {
1581                         /* use playhead instead */
1582                         where = playhead_cursor->current_frame ();
1583
1584                         if (where < half_page_size) {
1585                                 leftmost_after_zoom = 0;
1586                         } else {
1587                                 leftmost_after_zoom = where - half_page_size;
1588                         }
1589
1590                 } else {
1591
1592                         l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1593
1594                         if (l < 0) {
1595                                 leftmost_after_zoom = 0;
1596                         } else if (l > max_framepos) {
1597                                 leftmost_after_zoom = max_framepos - new_page_size;
1598                         } else {
1599                                 leftmost_after_zoom = (framepos_t) l;
1600                         }
1601                 }
1602
1603                 break;
1604
1605         case ZoomFocusEdit:
1606                 /* try to keep the edit point in the same place */
1607                 where = get_preferred_edit_position ();
1608
1609                 if (where > 0) {
1610
1611                         double l = - ((new_page_size * ((where - current_leftmost)/(double)current_page)) - where);
1612
1613                         if (l < 0) {
1614                                 leftmost_after_zoom = 0;
1615                         } else if (l > max_framepos) {
1616                                 leftmost_after_zoom = max_framepos - new_page_size;
1617                         } else {
1618                                 leftmost_after_zoom = (framepos_t) l;
1619                         }
1620
1621                 } else {
1622                         /* edit point not defined */
1623                         return;
1624                 }
1625                 break;
1626
1627         }
1628
1629         // leftmost_after_zoom = min (leftmost_after_zoom, _session->current_end_frame());
1630
1631         reposition_and_zoom (leftmost_after_zoom, nfpp);
1632 }
1633
1634 void
1635 Editor::calc_extra_zoom_edges(framepos_t &start, framepos_t &end)
1636 {
1637         /* this func helps make sure we leave a little space
1638            at each end of the editor so that the zoom doesn't fit the region
1639            precisely to the screen.
1640         */
1641
1642         GdkScreen* screen = gdk_screen_get_default ();
1643         const gint pixwidth = gdk_screen_get_width (screen);
1644         const gint mmwidth = gdk_screen_get_width_mm (screen);
1645         const double pix_per_mm = (double) pixwidth/ (double) mmwidth;
1646         const double one_centimeter_in_pixels = pix_per_mm * 10.0;
1647
1648         const framepos_t range = end - start;
1649         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1650         const framepos_t extra_samples = (framepos_t) floor (one_centimeter_in_pixels * new_fpp);
1651
1652         if (start > extra_samples) {
1653                 start -= extra_samples;
1654         } else {
1655                 start = 0;
1656         }
1657
1658         if (max_framepos - extra_samples > end) {
1659                 end += extra_samples;
1660         } else {
1661                 end = max_framepos;
1662         }
1663 }
1664
1665 void
1666 Editor::temporal_zoom_region (bool both_axes)
1667 {
1668         framepos_t start = max_framepos;
1669         framepos_t end = 0;
1670         set<TimeAxisView*> tracks;
1671
1672         RegionSelection rs = get_regions_from_selection_and_entered ();
1673
1674         if (rs.empty()) {
1675                 return;
1676         }
1677
1678         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
1679
1680                 if ((*i)->region()->position() < start) {
1681                         start = (*i)->region()->position();
1682                 }
1683
1684                 if ((*i)->region()->last_frame() + 1 > end) {
1685                         end = (*i)->region()->last_frame() + 1;
1686                 }
1687
1688                 tracks.insert (&((*i)->get_time_axis_view()));
1689         }
1690
1691         if ((start == 0 && end == 0) || end < start) {
1692                 return;
1693         }
1694
1695         calc_extra_zoom_edges (start, end);
1696
1697         /* if we're zooming on both axes we need to save track heights etc.
1698          */
1699
1700         undo_visual_stack.push_back (current_visual_state (both_axes));
1701
1702         PBD::Unwinder<bool> nsv (no_save_visual, true);
1703
1704         temporal_zoom_by_frame (start, end);
1705         
1706         if (both_axes) {
1707                 uint32_t per_track_height = (uint32_t) floor ((_visible_canvas_height - 10.0) / tracks.size());
1708
1709                 /* set visible track heights appropriately */
1710
1711                 for (set<TimeAxisView*>::iterator t = tracks.begin(); t != tracks.end(); ++t) {
1712                         (*t)->set_height (per_track_height);
1713                 }
1714
1715                 /* hide irrelevant tracks */
1716
1717                 DisplaySuspender ds;
1718
1719                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
1720                         if (find (tracks.begin(), tracks.end(), (*i)) == tracks.end()) {
1721                                 hide_track_in_display (*i);
1722                         }
1723                 }
1724
1725                 vertical_adjustment.set_value (0.0);
1726         }
1727
1728         redo_visual_stack.push_back (current_visual_state (both_axes));
1729 }
1730
1731 void
1732 Editor::zoom_to_region (bool both_axes)
1733 {
1734         temporal_zoom_region (both_axes);
1735 }
1736
1737 void
1738 Editor::temporal_zoom_selection (bool both_axes)
1739 {
1740         if (!selection) return;
1741
1742         //if a range is selected, zoom to that
1743         if (!selection->time.empty()) {
1744
1745                 framepos_t start = selection->time.start();
1746                 framepos_t end = selection->time.end_frame();
1747
1748                 calc_extra_zoom_edges(start, end);
1749
1750                 temporal_zoom_by_frame (start, end);
1751
1752                 if (both_axes)
1753                         fit_selected_tracks();
1754
1755         } else {
1756                 temporal_zoom_region (both_axes);
1757         }
1758
1759
1760 }
1761
1762 void
1763 Editor::temporal_zoom_session ()
1764 {
1765         ENSURE_GUI_THREAD (*this, &Editor::temporal_zoom_session)
1766
1767         if (_session) {
1768                 framecnt_t start = _session->current_start_frame();
1769                 framecnt_t end = _session->current_end_frame();
1770
1771                 if (_session->actively_recording () ) {
1772                         framepos_t cur = playhead_cursor->current_frame ();
1773                         if (cur > end) {
1774                                 /* recording beyond the end marker; zoom out
1775                                  * by 5 seconds more so that if 'follow
1776                                  * playhead' is active we don't immediately
1777                                  * scroll.
1778                                  */
1779                                 end = cur + _session->frame_rate() * 5;
1780                         }
1781                 }
1782
1783                 if ((start == 0 && end == 0) || end < start) {
1784                         return;
1785                 }
1786
1787                 calc_extra_zoom_edges(start, end);
1788
1789                 temporal_zoom_by_frame (start, end);
1790         }
1791 }
1792
1793 void
1794 Editor::temporal_zoom_by_frame (framepos_t start, framepos_t end)
1795 {
1796         if (!_session) return;
1797
1798         if ((start == 0 && end == 0) || end < start) {
1799                 return;
1800         }
1801
1802         framepos_t range = end - start;
1803
1804         const framecnt_t new_fpp = (framecnt_t) ceil ((double) range / (double) _visible_canvas_width);
1805         
1806         framepos_t new_page = range;
1807         framepos_t middle = (framepos_t) floor ((double) start + ((double) range / 2.0f));
1808         framepos_t new_leftmost = (framepos_t) floor ((double) middle - ((double) new_page / 2.0f));
1809
1810         if (new_leftmost > middle) {
1811                 new_leftmost = 0;
1812         }
1813
1814         if (new_leftmost < 0) {
1815                 new_leftmost = 0;
1816         }
1817
1818         reposition_and_zoom (new_leftmost, new_fpp);
1819 }
1820
1821 void
1822 Editor::temporal_zoom_to_frame (bool coarser, framepos_t frame)
1823 {
1824         if (!_session) {
1825                 return;
1826         }
1827
1828         framecnt_t range_before = frame - leftmost_frame;
1829         framecnt_t new_spp;
1830
1831         if (coarser) {
1832                 if (samples_per_pixel <= 1) {
1833                         new_spp = 2;
1834                 } else {
1835                         new_spp = samples_per_pixel + (samples_per_pixel/2);
1836                 }
1837                 range_before += range_before/2;
1838         } else {
1839                 if (samples_per_pixel >= 1) {
1840                         new_spp = samples_per_pixel - (samples_per_pixel/2);
1841                 } else {
1842                         /* could bail out here since we cannot zoom any finer,
1843                            but leave that to the equality test below
1844                         */
1845                         new_spp = samples_per_pixel;
1846                 }
1847
1848                 range_before -= range_before/2;
1849         }
1850
1851         if (new_spp == samples_per_pixel)  {
1852                 return;
1853         }
1854
1855         /* zoom focus is automatically taken as @param frame when this
1856            method is used.
1857         */
1858         
1859         framepos_t new_leftmost = frame - (framepos_t)range_before;
1860
1861         if (new_leftmost > frame) {
1862                 new_leftmost = 0;
1863         }
1864
1865         if (new_leftmost < 0) {
1866                 new_leftmost = 0;
1867         }
1868
1869         reposition_and_zoom (new_leftmost, new_spp);
1870 }
1871
1872
1873 bool
1874 Editor::choose_new_marker_name(string &name) {
1875
1876         if (!Config->get_name_new_markers()) {
1877                 /* don't prompt user for a new name */
1878                 return true;
1879         }
1880
1881         ArdourPrompter dialog (true);
1882
1883         dialog.set_prompt (_("New Name:"));
1884
1885         dialog.set_title (_("New Location Marker"));
1886
1887         dialog.set_name ("MarkNameWindow");
1888         dialog.set_size_request (250, -1);
1889         dialog.set_position (Gtk::WIN_POS_MOUSE);
1890
1891         dialog.add_button (Stock::OK, RESPONSE_ACCEPT);
1892         dialog.set_initial_text (name);
1893
1894         dialog.show ();
1895
1896         switch (dialog.run ()) {
1897         case RESPONSE_ACCEPT:
1898                 break;
1899         default:
1900                 return false;
1901         }
1902
1903         dialog.get_result(name);
1904         return true;
1905
1906 }
1907
1908
1909 void
1910 Editor::add_location_from_selection ()
1911 {
1912         string rangename;
1913
1914         if (selection->time.empty()) {
1915                 return;
1916         }
1917
1918         if (_session == 0 || clicked_axisview == 0) {
1919                 return;
1920         }
1921
1922         framepos_t start = selection->time[clicked_selection].start;
1923         framepos_t end = selection->time[clicked_selection].end;
1924
1925         _session->locations()->next_available_name(rangename,"selection");
1926         Location *location = new Location (*_session, start, end, rangename, Location::IsRangeMarker);
1927
1928         _session->begin_reversible_command (_("add marker"));
1929         XMLNode &before = _session->locations()->get_state();
1930         _session->locations()->add (location, true);
1931         XMLNode &after = _session->locations()->get_state();
1932         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1933         _session->commit_reversible_command ();
1934 }
1935
1936 void
1937 Editor::add_location_mark (framepos_t where)
1938 {
1939         string markername;
1940
1941         select_new_marker = true;
1942
1943         _session->locations()->next_available_name(markername,"mark");
1944         if (!choose_new_marker_name(markername)) {
1945                 return;
1946         }
1947         Location *location = new Location (*_session, where, where, markername, Location::IsMark);
1948         _session->begin_reversible_command (_("add marker"));
1949         XMLNode &before = _session->locations()->get_state();
1950         _session->locations()->add (location, true);
1951         XMLNode &after = _session->locations()->get_state();
1952         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1953         _session->commit_reversible_command ();
1954 }
1955
1956 void
1957 Editor::add_location_from_playhead_cursor ()
1958 {
1959         add_location_mark (_session->audible_frame());
1960 }
1961
1962 void
1963 Editor::remove_location_at_playhead_cursor ()
1964 {
1965         if (_session) {
1966
1967                 //set up for undo
1968                 _session->begin_reversible_command (_("remove marker"));
1969                 XMLNode &before = _session->locations()->get_state();
1970                 bool removed = false;
1971
1972                 //find location(s) at this time
1973                 Locations::LocationList locs;
1974                 _session->locations()->find_all_between (_session->audible_frame(), _session->audible_frame()+1, locs, Location::Flags(0));
1975                 for (Locations::LocationList::iterator i = locs.begin(); i != locs.end(); ++i) {
1976                         if ((*i)->is_mark()) {
1977                                 _session->locations()->remove (*i);
1978                                 removed = true;
1979                         }
1980                 }
1981                 
1982                 //store undo
1983                 if (removed) {
1984                         XMLNode &after = _session->locations()->get_state();
1985                         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
1986                         _session->commit_reversible_command ();
1987                 }
1988         }
1989 }
1990
1991 /** Add a range marker around each selected region */
1992 void
1993 Editor::add_locations_from_region ()
1994 {
1995         RegionSelection rs = get_regions_from_selection_and_entered ();
1996
1997         if (rs.empty()) {
1998                 return;
1999         }
2000
2001         _session->begin_reversible_command (selection->regions.size () > 1 ? _("add markers") : _("add marker"));
2002         XMLNode &before = _session->locations()->get_state();
2003
2004         for (RegionSelection::iterator i = rs.begin (); i != rs.end (); ++i) {
2005
2006                 boost::shared_ptr<Region> region = (*i)->region ();
2007
2008                 Location *location = new Location (*_session, region->position(), region->last_frame(), region->name(), Location::IsRangeMarker);
2009
2010                 _session->locations()->add (location, true);
2011         }
2012
2013         XMLNode &after = _session->locations()->get_state();
2014         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2015         _session->commit_reversible_command ();
2016 }
2017
2018 /** Add a single range marker around all selected regions */
2019 void
2020 Editor::add_location_from_region ()
2021 {
2022         RegionSelection rs = get_regions_from_selection_and_entered ();
2023
2024         if (rs.empty()) {
2025                 return;
2026         }
2027
2028         _session->begin_reversible_command (_("add marker"));
2029         XMLNode &before = _session->locations()->get_state();
2030
2031         string markername;
2032
2033         if (rs.size() > 1) {
2034                 _session->locations()->next_available_name(markername, "regions");
2035         } else {
2036                 RegionView* rv = *(rs.begin());
2037                 boost::shared_ptr<Region> region = rv->region();
2038                 markername = region->name();
2039         }
2040
2041         if (!choose_new_marker_name(markername)) {
2042                 return;
2043         }
2044
2045         // single range spanning all selected
2046         Location *location = new Location (*_session, selection->regions.start(), selection->regions.end_frame(), markername, Location::IsRangeMarker);
2047         _session->locations()->add (location, true);
2048
2049         XMLNode &after = _session->locations()->get_state();
2050         _session->add_command (new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2051         _session->commit_reversible_command ();
2052 }
2053
2054 /* MARKS */
2055
2056 void
2057 Editor::jump_forward_to_mark ()
2058 {
2059         if (!_session) {
2060                 return;
2061         }
2062
2063         framepos_t pos = _session->locations()->first_mark_after (playhead_cursor->current_frame());
2064
2065         if (pos < 0) {
2066                 return;
2067         }
2068         
2069         _session->request_locate (pos, _session->transport_rolling());
2070 }
2071
2072 void
2073 Editor::jump_backward_to_mark ()
2074 {
2075         if (!_session) {
2076                 return;
2077         }
2078
2079         framepos_t pos = _session->locations()->first_mark_before (playhead_cursor->current_frame());
2080
2081         if (pos < 0) {
2082                 return;
2083         }
2084
2085         _session->request_locate (pos, _session->transport_rolling());
2086 }
2087
2088 void
2089 Editor::set_mark ()
2090 {
2091         framepos_t const pos = _session->audible_frame ();
2092
2093         string markername;
2094         _session->locations()->next_available_name (markername, "mark");
2095
2096         if (!choose_new_marker_name (markername)) {
2097                 return;
2098         }
2099
2100         _session->locations()->add (new Location (*_session, pos, 0, markername, Location::IsMark), true);
2101 }
2102
2103 void
2104 Editor::clear_markers ()
2105 {
2106         if (_session) {
2107                 _session->begin_reversible_command (_("clear markers"));
2108                 XMLNode &before = _session->locations()->get_state();
2109                 _session->locations()->clear_markers ();
2110                 XMLNode &after = _session->locations()->get_state();
2111                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2112                 _session->commit_reversible_command ();
2113         }
2114 }
2115
2116 void
2117 Editor::clear_ranges ()
2118 {
2119         if (_session) {
2120                 _session->begin_reversible_command (_("clear ranges"));
2121                 XMLNode &before = _session->locations()->get_state();
2122
2123                 _session->locations()->clear_ranges ();
2124
2125                 XMLNode &after = _session->locations()->get_state();
2126                 _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2127                 _session->commit_reversible_command ();
2128         }
2129 }
2130
2131 void
2132 Editor::clear_locations ()
2133 {
2134         _session->begin_reversible_command (_("clear locations"));
2135         XMLNode &before = _session->locations()->get_state();
2136         _session->locations()->clear ();
2137         XMLNode &after = _session->locations()->get_state();
2138         _session->add_command(new MementoCommand<Locations>(*(_session->locations()), &before, &after));
2139         _session->commit_reversible_command ();
2140         _session->locations()->clear ();
2141 }
2142
2143 void
2144 Editor::unhide_markers ()
2145 {
2146         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2147                 Location *l = (*i).first;
2148                 if (l->is_hidden() && l->is_mark()) {
2149                         l->set_hidden(false, this);
2150                 }
2151         }
2152 }
2153
2154 void
2155 Editor::unhide_ranges ()
2156 {
2157         for (LocationMarkerMap::iterator i = location_markers.begin(); i != location_markers.end(); ++i) {
2158                 Location *l = (*i).first;
2159                 if (l->is_hidden() && l->is_range_marker()) {
2160                         l->set_hidden(false, this);
2161                 }
2162         }
2163 }
2164
2165 /* INSERT/REPLACE */
2166
2167 void
2168 Editor::insert_region_list_selection (float times)
2169 {
2170         RouteTimeAxisView *tv = 0;
2171         boost::shared_ptr<Playlist> playlist;
2172
2173         if (clicked_routeview != 0) {
2174                 tv = clicked_routeview;
2175         } else if (!selection->tracks.empty()) {
2176                 if ((tv = dynamic_cast<RouteTimeAxisView*>(selection->tracks.front())) == 0) {
2177                         return;
2178                 }
2179         } else if (entered_track != 0) {
2180                 if ((tv = dynamic_cast<RouteTimeAxisView*>(entered_track)) == 0) {
2181                         return;
2182                 }
2183         } else {
2184                 return;
2185         }
2186
2187         if ((playlist = tv->playlist()) == 0) {
2188                 return;
2189         }
2190
2191         boost::shared_ptr<Region> region = _regions->get_single_selection ();
2192         if (region == 0) {
2193                 return;
2194         }
2195
2196         begin_reversible_command (_("insert region"));
2197         playlist->clear_changes ();
2198         playlist->add_region ((RegionFactory::create (region, true)), get_preferred_edit_position(), times);
2199         if (Config->get_edit_mode() == Ripple)
2200                 playlist->ripple (get_preferred_edit_position(), region->length() * times, boost::shared_ptr<Region>());
2201
2202         _session->add_command(new StatefulDiffCommand (playlist));
2203         commit_reversible_command ();
2204 }
2205
2206 /* BUILT-IN EFFECTS */
2207
2208 void
2209 Editor::reverse_selection ()
2210 {
2211
2212 }
2213
2214 /* GAIN ENVELOPE EDITING */
2215
2216 void
2217 Editor::edit_envelope ()
2218 {
2219 }
2220
2221 /* PLAYBACK */
2222
2223 void
2224 Editor::transition_to_rolling (bool fwd)
2225 {
2226         if (!_session) {
2227                 return;
2228         }
2229
2230         if (_session->config.get_external_sync()) {
2231                 switch (Config->get_sync_source()) {
2232                 case Engine:
2233                         break;
2234                 default:
2235                         /* transport controlled by the master */
2236                         return;
2237                 }
2238         }
2239
2240         if (_session->is_auditioning()) {
2241                 _session->cancel_audition ();
2242                 return;
2243         }
2244
2245         _session->request_transport_speed (fwd ? 1.0f : -1.0f);
2246 }
2247
2248 void
2249 Editor::play_from_start ()
2250 {
2251         _session->request_locate (_session->current_start_frame(), true);
2252 }
2253
2254 void
2255 Editor::play_from_edit_point ()
2256 {
2257         _session->request_locate (get_preferred_edit_position(), true);
2258 }
2259
2260 void
2261 Editor::play_from_edit_point_and_return ()
2262 {
2263         framepos_t start_frame;
2264         framepos_t return_frame;
2265
2266         start_frame = get_preferred_edit_position (true);
2267
2268         if (_session->transport_rolling()) {
2269                 _session->request_locate (start_frame, false);
2270                 return;
2271         }
2272
2273         /* don't reset the return frame if its already set */
2274
2275         if ((return_frame = _session->requested_return_frame()) < 0) {
2276                 return_frame = _session->audible_frame();
2277         }
2278
2279         if (start_frame >= 0) {
2280                 _session->request_roll_at_and_return (start_frame, return_frame);
2281         }
2282 }
2283
2284 void
2285 Editor::play_selection ()
2286 {
2287         if (selection->time.empty()) {
2288                 return;
2289         }
2290
2291         _session->request_play_range (&selection->time, true);
2292 }
2293
2294 framepos_t
2295 Editor::get_preroll ()
2296 {
2297         return 1.0 /*Config->get_edit_preroll_seconds()*/ * _session->frame_rate();
2298 }
2299
2300
2301 void
2302 Editor::maybe_locate_with_edit_preroll ( framepos_t location )
2303 {
2304         if ( _session->transport_rolling() || !Config->get_follow_edits() || _ignore_follow_edits )
2305                 return;
2306
2307         location -= get_preroll();
2308         
2309         //don't try to locate before the beginning of time
2310         if ( location < 0 ) 
2311                 location = 0;
2312                 
2313         //if follow_playhead is on, keep the playhead on the screen
2314         if ( _follow_playhead )
2315                 if ( location < leftmost_frame ) 
2316                         location = leftmost_frame;
2317
2318         _session->request_locate( location );
2319 }
2320
2321 void
2322 Editor::play_with_preroll ()
2323 {
2324         if (selection->time.empty()) {
2325                 return;
2326         } else {
2327                 framepos_t preroll = get_preroll();
2328                 
2329                 framepos_t start = 0;
2330                 if (selection->time[clicked_selection].start > preroll)
2331                         start = selection->time[clicked_selection].start - preroll;
2332                 
2333                 framepos_t end = selection->time[clicked_selection].end + preroll;
2334                 
2335                 AudioRange ar (start, end, 0);
2336                 list<AudioRange> lar;
2337                 lar.push_back (ar);
2338
2339                 _session->request_play_range (&lar, true);
2340         }
2341 }
2342
2343 void
2344 Editor::play_location (Location& location)
2345 {
2346         if (location.start() <= location.end()) {
2347                 return;
2348         }
2349
2350         _session->request_bounded_roll (location.start(), location.end());
2351 }
2352
2353 void
2354 Editor::loop_location (Location& location)
2355 {
2356         if (location.start() <= location.end()) {
2357                 return;
2358         }
2359
2360         Location* tll;
2361
2362         if ((tll = transport_loop_location()) != 0) {
2363                 tll->set (location.start(), location.end());
2364
2365                 // enable looping, reposition and start rolling
2366                 _session->request_locate (tll->start(), true);
2367                 _session->request_play_loop (true);
2368         }
2369 }
2370
2371 void
2372 Editor::do_layer_operation (LayerOperation op)
2373 {
2374         if (selection->regions.empty ()) {
2375                 return;
2376         }
2377
2378         bool const multiple = selection->regions.size() > 1;
2379         switch (op) {
2380         case Raise:
2381                 if (multiple) {
2382                         begin_reversible_command (_("raise regions"));
2383                 } else {
2384                         begin_reversible_command (_("raise region"));
2385                 }
2386                 break;
2387
2388         case RaiseToTop:
2389                 if (multiple) {
2390                         begin_reversible_command (_("raise regions to top"));
2391                 } else {
2392                         begin_reversible_command (_("raise region to top"));
2393                 }
2394                 break;
2395                 
2396         case Lower:
2397                 if (multiple) {
2398                         begin_reversible_command (_("lower regions"));
2399                 } else {
2400                         begin_reversible_command (_("lower region"));
2401                 }
2402                 break;
2403                 
2404         case LowerToBottom:
2405                 if (multiple) {
2406                         begin_reversible_command (_("lower regions to bottom"));
2407                 } else {
2408                         begin_reversible_command (_("lower region"));
2409                 }
2410                 break;
2411         }
2412
2413         set<boost::shared_ptr<Playlist> > playlists = selection->regions.playlists ();
2414         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2415                 (*i)->clear_owned_changes ();
2416         }
2417         
2418         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
2419                 boost::shared_ptr<Region> r = (*i)->region ();
2420                 switch (op) {
2421                 case Raise:
2422                         r->raise ();
2423                         break;
2424                 case RaiseToTop:
2425                         r->raise_to_top ();
2426                         break;
2427                 case Lower:
2428                         r->lower ();
2429                         break;
2430                 case LowerToBottom:
2431                         r->lower_to_bottom ();
2432                 }
2433         }
2434
2435         for (set<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
2436                 vector<Command*> cmds;
2437                 (*i)->rdiff (cmds);
2438                 _session->add_commands (cmds);
2439         }
2440         
2441         commit_reversible_command ();
2442 }
2443
2444 void
2445 Editor::raise_region ()
2446 {
2447         do_layer_operation (Raise);
2448 }
2449
2450 void
2451 Editor::raise_region_to_top ()
2452 {
2453         do_layer_operation (RaiseToTop);
2454 }
2455
2456 void
2457 Editor::lower_region ()
2458 {
2459         do_layer_operation (Lower);
2460 }
2461
2462 void
2463 Editor::lower_region_to_bottom ()
2464 {
2465         do_layer_operation (LowerToBottom);
2466 }
2467
2468 /** Show the region editor for the selected regions */
2469 void
2470 Editor::show_region_properties ()
2471 {
2472         selection->foreach_regionview (&RegionView::show_region_editor);
2473 }
2474
2475 /** Show the midi list editor for the selected MIDI regions */
2476 void
2477 Editor::show_midi_list_editor ()
2478 {
2479         selection->foreach_midi_regionview (&MidiRegionView::show_list_editor);
2480 }
2481
2482 void
2483 Editor::rename_region ()
2484 {
2485         RegionSelection rs = get_regions_from_selection_and_entered ();
2486
2487         if (rs.empty()) {
2488                 return;
2489         }
2490
2491         ArdourDialog d (*this, _("Rename Region"), true, false);
2492         Entry entry;
2493         Label label (_("New name:"));
2494         HBox hbox;
2495
2496         hbox.set_spacing (6);
2497         hbox.pack_start (label, false, false);
2498         hbox.pack_start (entry, true, true);
2499
2500         d.get_vbox()->set_border_width (12);
2501         d.get_vbox()->pack_start (hbox, false, false);
2502
2503         d.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
2504         d.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
2505
2506         d.set_size_request (300, -1);
2507
2508         entry.set_text (rs.front()->region()->name());
2509         entry.select_region (0, -1);
2510
2511         entry.signal_activate().connect (sigc::bind (sigc::mem_fun (d, &Dialog::response), RESPONSE_OK));
2512
2513         d.show_all ();
2514
2515         entry.grab_focus();
2516
2517         int const ret = d.run();
2518
2519         d.hide ();
2520
2521         if (ret != RESPONSE_OK) {
2522                 return;
2523         }
2524
2525         std::string str = entry.get_text();
2526         strip_whitespace_edges (str);
2527         if (!str.empty()) {
2528                 rs.front()->region()->set_name (str);
2529                 _regions->redisplay ();
2530         }
2531 }
2532
2533 void
2534 Editor::audition_playlist_region_via_route (boost::shared_ptr<Region> region, Route& route)
2535 {
2536         if (_session->is_auditioning()) {
2537                 _session->cancel_audition ();
2538         }
2539
2540         // note: some potential for creativity here, because region doesn't
2541         // have to belong to the playlist that Route is handling
2542
2543         // bool was_soloed = route.soloed();
2544
2545         route.set_solo (true, this);
2546
2547         _session->request_bounded_roll (region->position(), region->position() + region->length());
2548
2549         /* XXX how to unset the solo state ? */
2550 }
2551
2552 /** Start an audition of the first selected region */
2553 void
2554 Editor::play_edit_range ()
2555 {
2556         framepos_t start, end;
2557
2558         if (get_edit_op_range (start, end)) {
2559                 _session->request_bounded_roll (start, end);
2560         }
2561 }
2562
2563 void
2564 Editor::play_selected_region ()
2565 {
2566         framepos_t start = max_framepos;
2567         framepos_t end = 0;
2568
2569         RegionSelection rs = get_regions_from_selection_and_entered ();
2570
2571         if (rs.empty()) {
2572                 return;
2573         }
2574
2575         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2576                 if ((*i)->region()->position() < start) {
2577                         start = (*i)->region()->position();
2578                 }
2579                 if ((*i)->region()->last_frame() + 1 > end) {
2580                         end = (*i)->region()->last_frame() + 1;
2581                 }
2582         }
2583
2584         _session->request_bounded_roll (start, end);
2585 }
2586
2587 void
2588 Editor::audition_playlist_region_standalone (boost::shared_ptr<Region> region)
2589 {
2590         _session->audition_region (region);
2591 }
2592
2593 void
2594 Editor::region_from_selection ()
2595 {
2596         if (clicked_axisview == 0) {
2597                 return;
2598         }
2599
2600         if (selection->time.empty()) {
2601                 return;
2602         }
2603
2604         framepos_t start = selection->time[clicked_selection].start;
2605         framepos_t end = selection->time[clicked_selection].end;
2606
2607         TrackViewList tracks = get_tracks_for_range_action ();
2608
2609         framepos_t selection_cnt = end - start + 1;
2610
2611         for (TrackSelection::iterator i = tracks.begin(); i != tracks.end(); ++i) {
2612                 boost::shared_ptr<Region> current;
2613                 boost::shared_ptr<Playlist> pl;
2614                 framepos_t internal_start;
2615                 string new_name;
2616
2617                 if ((pl = (*i)->playlist()) == 0) {
2618                         continue;
2619                 }
2620
2621                 if ((current = pl->top_region_at (start)) == 0) {
2622                         continue;
2623                 }
2624
2625                 internal_start = start - current->position();
2626                 RegionFactory::region_name (new_name, current->name(), true);
2627
2628                 PropertyList plist;
2629
2630                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2631                 plist.add (ARDOUR::Properties::length, selection_cnt);
2632                 plist.add (ARDOUR::Properties::name, new_name);
2633                 plist.add (ARDOUR::Properties::layer, 0);
2634
2635                 boost::shared_ptr<Region> region (RegionFactory::create (current, plist));
2636         }
2637 }
2638
2639 void
2640 Editor::create_region_from_selection (vector<boost::shared_ptr<Region> >& new_regions)
2641 {
2642         if (selection->time.empty() || selection->tracks.empty()) {
2643                 return;
2644         }
2645
2646         framepos_t start = selection->time[clicked_selection].start;
2647         framepos_t end = selection->time[clicked_selection].end;
2648
2649         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
2650         sort_track_selection (ts);
2651
2652         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
2653                 boost::shared_ptr<Region> current;
2654                 boost::shared_ptr<Playlist> playlist;
2655                 framepos_t internal_start;
2656                 string new_name;
2657
2658                 if ((playlist = (*i)->playlist()) == 0) {
2659                         continue;
2660                 }
2661
2662                 if ((current = playlist->top_region_at(start)) == 0) {
2663                         continue;
2664                 }
2665
2666                 internal_start = start - current->position();
2667                 RegionFactory::region_name (new_name, current->name(), true);
2668
2669                 PropertyList plist;
2670
2671                 plist.add (ARDOUR::Properties::start, current->start() + internal_start);
2672                 plist.add (ARDOUR::Properties::length, end - start + 1);
2673                 plist.add (ARDOUR::Properties::name, new_name);
2674
2675                 new_regions.push_back (RegionFactory::create (current, plist));
2676         }
2677 }
2678
2679 void
2680 Editor::split_multichannel_region ()
2681 {
2682         RegionSelection rs = get_regions_from_selection_and_entered ();
2683
2684         if (rs.empty()) {
2685                 return;
2686         }
2687
2688         vector< boost::shared_ptr<Region> > v;
2689
2690         for (list<RegionView*>::iterator x = rs.begin(); x != rs.end(); ++x) {
2691                 (*x)->region()->separate_by_channel (*_session, v);
2692         }
2693 }
2694
2695 void
2696 Editor::new_region_from_selection ()
2697 {
2698         region_from_selection ();
2699         cancel_selection ();
2700 }
2701
2702 static void
2703 add_if_covered (RegionView* rv, const AudioRange* ar, RegionSelection* rs)
2704 {
2705         switch (rv->region()->coverage (ar->start, ar->end - 1)) {
2706         case Evoral::OverlapNone:
2707                 break;
2708         default:
2709                 rs->push_back (rv);
2710         }
2711 }
2712
2713 /** Return either:
2714  *    - selected tracks, or if there are none...
2715  *    - tracks containing selected regions, or if there are none...
2716  *    - all tracks
2717  * @return tracks.
2718  */
2719 TrackViewList
2720 Editor::get_tracks_for_range_action () const
2721 {
2722         TrackViewList t;
2723
2724         if (selection->tracks.empty()) {
2725
2726                 /* use tracks with selected regions */
2727
2728                 RegionSelection rs = selection->regions;
2729
2730                 for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2731                         TimeAxisView* tv = &(*i)->get_time_axis_view();
2732
2733                         if (!t.contains (tv)) {
2734                                 t.push_back (tv);
2735                         }
2736                 }
2737
2738                 if (t.empty()) {
2739                         /* no regions and no tracks: use all tracks */
2740                         t = track_views;
2741                 }
2742
2743         } else {
2744
2745                 t = selection->tracks;
2746         }
2747
2748         return t.filter_to_unique_playlists();
2749 }
2750
2751 void
2752 Editor::separate_regions_between (const TimeSelection& ts)
2753 {
2754         bool in_command = false;
2755         boost::shared_ptr<Playlist> playlist;
2756         RegionSelection new_selection;
2757
2758         TrackViewList tmptracks = get_tracks_for_range_action ();
2759         sort_track_selection (tmptracks);
2760
2761         for (TrackSelection::iterator i = tmptracks.begin(); i != tmptracks.end(); ++i) {
2762
2763                 RouteTimeAxisView* rtv;
2764
2765                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
2766
2767                         if (rtv->is_track()) {
2768
2769                                 /* no edits to destructive tracks */
2770
2771                                 if (rtv->track()->destructive()) {
2772                                         continue;
2773                                 }
2774
2775                                 if ((playlist = rtv->playlist()) != 0) {
2776
2777                                         playlist->clear_changes ();
2778
2779                                         /* XXX need to consider musical time selections here at some point */
2780
2781                                         double speed = rtv->track()->speed();
2782
2783
2784                                         for (list<AudioRange>::const_iterator t = ts.begin(); t != ts.end(); ++t) {
2785
2786                                                 sigc::connection c = rtv->view()->RegionViewAdded.connect (
2787                                                                 sigc::mem_fun(*this, &Editor::collect_new_region_view));
2788
2789                                                 latest_regionviews.clear ();
2790
2791                                                 playlist->partition ((framepos_t)((*t).start * speed),
2792                                                                 (framepos_t)((*t).end * speed), false);
2793
2794                                                 c.disconnect ();
2795
2796                                                 if (!latest_regionviews.empty()) {
2797
2798                                                         rtv->view()->foreach_regionview (sigc::bind (
2799                                                                                 sigc::ptr_fun (add_if_covered),
2800                                                                                 &(*t), &new_selection));
2801
2802                                                         if (!in_command) {
2803                                                                 begin_reversible_command (_("separate"));
2804                                                                 in_command = true;
2805                                                         }
2806
2807                                                         /* pick up changes to existing regions */
2808
2809                                                         vector<Command*> cmds;
2810                                                         playlist->rdiff (cmds);
2811                                                         _session->add_commands (cmds);
2812
2813                                                         /* pick up changes to the playlist itself (adds/removes)
2814                                                          */
2815
2816                                                         _session->add_command(new StatefulDiffCommand (playlist));
2817                                                 }
2818                                         }
2819                                 }
2820                         }
2821                 }
2822         }
2823
2824         if (in_command) {
2825 //              selection->set (new_selection);
2826
2827                 commit_reversible_command ();
2828         }
2829 }
2830
2831 struct PlaylistState {
2832     boost::shared_ptr<Playlist> playlist;
2833     XMLNode*  before;
2834 };
2835
2836 /** Take tracks from get_tracks_for_range_action and cut any regions
2837  *  on those tracks so that the tracks are empty over the time
2838  *  selection.
2839  */
2840 void
2841 Editor::separate_region_from_selection ()
2842 {
2843         /* preferentially use *all* ranges in the time selection if we're in range mode
2844            to allow discontiguous operation, since get_edit_op_range() currently
2845            returns a single range.
2846         */
2847
2848         if (!selection->time.empty()) {
2849
2850                 separate_regions_between (selection->time);
2851
2852         } else {
2853
2854                 framepos_t start;
2855                 framepos_t end;
2856
2857                 if (get_edit_op_range (start, end)) {
2858
2859                         AudioRange ar (start, end, 1);
2860                         TimeSelection ts;
2861                         ts.push_back (ar);
2862
2863                         separate_regions_between (ts);
2864                 }
2865         }
2866 }
2867
2868 void
2869 Editor::separate_region_from_punch ()
2870 {
2871         Location* loc  = _session->locations()->auto_punch_location();
2872         if (loc) {
2873                 separate_regions_using_location (*loc);
2874         }
2875 }
2876
2877 void
2878 Editor::separate_region_from_loop ()
2879 {
2880         Location* loc  = _session->locations()->auto_loop_location();
2881         if (loc) {
2882                 separate_regions_using_location (*loc);
2883         }
2884 }
2885
2886 void
2887 Editor::separate_regions_using_location (Location& loc)
2888 {
2889         if (loc.is_mark()) {
2890                 return;
2891         }
2892
2893         AudioRange ar (loc.start(), loc.end(), 1);
2894         TimeSelection ts;
2895
2896         ts.push_back (ar);
2897
2898         separate_regions_between (ts);
2899 }
2900
2901 /** Separate regions under the selected region */
2902 void
2903 Editor::separate_under_selected_regions ()
2904 {
2905         vector<PlaylistState> playlists;
2906
2907         RegionSelection rs;
2908
2909         rs = get_regions_from_selection_and_entered();
2910
2911         if (!_session || rs.empty()) {
2912                 return;
2913         }
2914
2915         begin_reversible_command (_("separate region under"));
2916
2917         list<boost::shared_ptr<Region> > regions_to_remove;
2918
2919         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
2920                 // we can't just remove the region(s) in this loop because
2921                 // this removes them from the RegionSelection, and they thus
2922                 // disappear from underneath the iterator, and the ++i above
2923                 // SEGVs in a puzzling fashion.
2924
2925                 // so, first iterate over the regions to be removed from rs and
2926                 // add them to the regions_to_remove list, and then
2927                 // iterate over the list to actually remove them.
2928
2929                 regions_to_remove.push_back ((*i)->region());
2930         }
2931
2932         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
2933
2934                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
2935
2936                 if (!playlist) {
2937                         // is this check necessary?
2938                         continue;
2939                 }
2940
2941                 vector<PlaylistState>::iterator i;
2942
2943                 //only take state if this is a new playlist.
2944                 for (i = playlists.begin(); i != playlists.end(); ++i) {
2945                         if ((*i).playlist == playlist) {
2946                                 break;
2947                         }
2948                 }
2949
2950                 if (i == playlists.end()) {
2951
2952                         PlaylistState before;
2953                         before.playlist = playlist;
2954                         before.before = &playlist->get_state();
2955
2956                         playlist->freeze ();
2957                         playlists.push_back(before);
2958                 }
2959
2960                 //Partition on the region bounds
2961                 playlist->partition ((*rl)->first_frame() - 1, (*rl)->last_frame() + 1, true);
2962
2963                 //Re-add region that was just removed due to the partition operation
2964                 playlist->add_region( (*rl), (*rl)->first_frame() );
2965         }
2966
2967         vector<PlaylistState>::iterator pl;
2968
2969         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
2970                 (*pl).playlist->thaw ();
2971                 _session->add_command(new MementoCommand<Playlist>(*(*pl).playlist, (*pl).before, &(*pl).playlist->get_state()));
2972         }
2973
2974         commit_reversible_command ();
2975 }
2976
2977 void
2978 Editor::crop_region_to_selection ()
2979 {
2980         if (!selection->time.empty()) {
2981
2982                 crop_region_to (selection->time.start(), selection->time.end_frame());
2983
2984         } else {
2985
2986                 framepos_t start;
2987                 framepos_t end;
2988
2989                 if (get_edit_op_range (start, end)) {
2990                         crop_region_to (start, end);
2991                 }
2992         }
2993
2994 }
2995
2996 void
2997 Editor::crop_region_to (framepos_t start, framepos_t end)
2998 {
2999         vector<boost::shared_ptr<Playlist> > playlists;
3000         boost::shared_ptr<Playlist> playlist;
3001         TrackViewList ts;
3002
3003         if (selection->tracks.empty()) {
3004                 ts = track_views.filter_to_unique_playlists();
3005         } else {
3006                 ts = selection->tracks.filter_to_unique_playlists ();
3007         }
3008
3009         sort_track_selection (ts);
3010
3011         for (TrackSelection::iterator i = ts.begin(); i != ts.end(); ++i) {
3012
3013                 RouteTimeAxisView* rtv;
3014
3015                 if ((rtv = dynamic_cast<RouteTimeAxisView*> ((*i))) != 0) {
3016
3017                         boost::shared_ptr<Track> t = rtv->track();
3018
3019                         if (t != 0 && ! t->destructive()) {
3020
3021                                 if ((playlist = rtv->playlist()) != 0) {
3022                                         playlists.push_back (playlist);
3023                                 }
3024                         }
3025                 }
3026         }
3027
3028         if (playlists.empty()) {
3029                 return;
3030         }
3031
3032         framepos_t the_start;
3033         framepos_t the_end;
3034         framepos_t cnt;
3035
3036         begin_reversible_command (_("trim to selection"));
3037
3038         for (vector<boost::shared_ptr<Playlist> >::iterator i = playlists.begin(); i != playlists.end(); ++i) {
3039
3040                 boost::shared_ptr<Region> region;
3041
3042                 the_start = start;
3043
3044                 if ((region = (*i)->top_region_at(the_start)) == 0) {
3045                         continue;
3046                 }
3047
3048                 /* now adjust lengths to that we do the right thing
3049                    if the selection extends beyond the region
3050                 */
3051
3052                 the_start = max (the_start, (framepos_t) region->position());
3053                 if (max_framepos - the_start < region->length()) {
3054                         the_end = the_start + region->length() - 1;
3055                 } else {
3056                         the_end = max_framepos;
3057                 }
3058                 the_end = min (end, the_end);
3059                 cnt = the_end - the_start + 1;
3060
3061                 region->clear_changes ();
3062                 region->trim_to (the_start, cnt);
3063                 _session->add_command (new StatefulDiffCommand (region));
3064         }
3065
3066         commit_reversible_command ();
3067 }
3068
3069 void
3070 Editor::region_fill_track ()
3071 {
3072         RegionSelection rs = get_regions_from_selection_and_entered ();
3073
3074         if (!_session || rs.empty()) {
3075                 return;
3076         }
3077
3078         framepos_t const end = _session->current_end_frame ();
3079
3080         begin_reversible_command (Operations::region_fill);
3081
3082         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3083
3084                 boost::shared_ptr<Region> region ((*i)->region());
3085
3086                 boost::shared_ptr<Playlist> pl = region->playlist();
3087
3088                 if (end <= region->last_frame()) {
3089                         return;
3090                 }
3091
3092                 double times = (double) (end - region->last_frame()) / (double) region->length();
3093
3094                 if (times == 0) {
3095                         return;
3096                 }
3097
3098                 pl->clear_changes ();
3099                 pl->add_region (RegionFactory::create (region, true), region->last_frame(), times);
3100                 _session->add_command (new StatefulDiffCommand (pl));
3101         }
3102
3103         commit_reversible_command ();
3104 }
3105
3106 void
3107 Editor::region_fill_selection ()
3108 {
3109         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3110                 return;
3111         }
3112
3113         if (selection->time.empty()) {
3114                 return;
3115         }
3116
3117         boost::shared_ptr<Region> region = _regions->get_single_selection ();
3118         if (region == 0) {
3119                 return;
3120         }
3121
3122         framepos_t start = selection->time[clicked_selection].start;
3123         framepos_t end = selection->time[clicked_selection].end;
3124
3125         boost::shared_ptr<Playlist> playlist;
3126
3127         if (selection->tracks.empty()) {
3128                 return;
3129         }
3130
3131         framepos_t selection_length = end - start;
3132         float times = (float)selection_length / region->length();
3133
3134         begin_reversible_command (Operations::fill_selection);
3135
3136         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
3137
3138         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
3139
3140                 if ((playlist = (*i)->playlist()) == 0) {
3141                         continue;
3142                 }
3143
3144                 playlist->clear_changes ();
3145                 playlist->add_region (RegionFactory::create (region, true), start, times);
3146                 _session->add_command (new StatefulDiffCommand (playlist));
3147         }
3148
3149         commit_reversible_command ();
3150 }
3151
3152 void
3153 Editor::set_region_sync_position ()
3154 {
3155         set_sync_point (get_preferred_edit_position (), get_regions_from_selection_and_edit_point ());
3156 }
3157
3158 void
3159 Editor::set_sync_point (framepos_t where, const RegionSelection& rs)
3160 {
3161         bool in_command = false;
3162
3163         for (RegionSelection::const_iterator r = rs.begin(); r != rs.end(); ++r) {
3164
3165                 if (!(*r)->region()->covers (where)) {
3166                         continue;
3167                 }
3168
3169                 boost::shared_ptr<Region> region ((*r)->region());
3170
3171                 if (!in_command) {
3172                         begin_reversible_command (_("set sync point"));
3173                         in_command = true;
3174                 }
3175
3176                 region->clear_changes ();
3177                 region->set_sync_position (where);
3178                 _session->add_command(new StatefulDiffCommand (region));
3179         }
3180
3181         if (in_command) {
3182                 commit_reversible_command ();
3183         }
3184 }
3185
3186 /** Remove the sync positions of the selection */
3187 void
3188 Editor::remove_region_sync ()
3189 {
3190         RegionSelection rs = get_regions_from_selection_and_entered ();
3191
3192         if (rs.empty()) {
3193                 return;
3194         }
3195
3196         begin_reversible_command (_("remove region sync"));
3197
3198         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3199
3200                 (*i)->region()->clear_changes ();
3201                 (*i)->region()->clear_sync_position ();
3202                 _session->add_command(new StatefulDiffCommand ((*i)->region()));
3203         }
3204
3205         commit_reversible_command ();
3206 }
3207
3208 void
3209 Editor::naturalize_region ()
3210 {
3211         RegionSelection rs = get_regions_from_selection_and_entered ();
3212
3213         if (rs.empty()) {
3214                 return;
3215         }
3216
3217         if (rs.size() > 1) {
3218                 begin_reversible_command (_("move regions to original position"));
3219         } else {
3220                 begin_reversible_command (_("move region to original position"));
3221         }
3222
3223         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
3224                 (*i)->region()->clear_changes ();
3225                 (*i)->region()->move_to_natural_position ();
3226                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
3227         }
3228
3229         commit_reversible_command ();
3230 }
3231
3232 void
3233 Editor::align_regions (RegionPoint what)
3234 {
3235         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3236
3237         if (rs.empty()) {
3238                 return;
3239         }
3240
3241         begin_reversible_command (_("align selection"));
3242
3243         framepos_t const position = get_preferred_edit_position ();
3244
3245         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
3246                 align_region_internal ((*i)->region(), what, position);
3247         }
3248
3249         commit_reversible_command ();
3250 }
3251
3252 struct RegionSortByTime {
3253     bool operator() (const RegionView* a, const RegionView* b) {
3254             return a->region()->position() < b->region()->position();
3255     }
3256 };
3257
3258 void
3259 Editor::align_regions_relative (RegionPoint point)
3260 {
3261         RegionSelection const rs = get_regions_from_selection_and_edit_point ();
3262
3263         if (rs.empty()) {
3264                 return;
3265         }
3266
3267         framepos_t const position = get_preferred_edit_position ();
3268
3269         framepos_t distance = 0;
3270         framepos_t pos = 0;
3271         int dir = 1;
3272
3273         list<RegionView*> sorted;
3274         rs.by_position (sorted);
3275
3276         boost::shared_ptr<Region> r ((*sorted.begin())->region());
3277
3278         switch (point) {
3279         case Start:
3280                 pos = position;
3281                 if (position > r->position()) {
3282                         distance = position - r->position();
3283                 } else {
3284                         distance = r->position() - position;
3285                         dir = -1;
3286                 }
3287                 break;
3288
3289         case End:
3290                 if (position > r->last_frame()) {
3291                         distance = position - r->last_frame();
3292                         pos = r->position() + distance;
3293                 } else {
3294                         distance = r->last_frame() - position;
3295                         pos = r->position() - distance;
3296                         dir = -1;
3297                 }
3298                 break;
3299
3300         case SyncPoint:
3301                 pos = r->adjust_to_sync (position);
3302                 if (pos > r->position()) {
3303                         distance = pos - r->position();
3304                 } else {
3305                         distance = r->position() - pos;
3306                         dir = -1;
3307                 }
3308                 break;
3309         }
3310
3311         if (pos == r->position()) {
3312                 return;
3313         }
3314
3315         begin_reversible_command (_("align selection (relative)"));
3316
3317         /* move first one specially */
3318
3319         r->clear_changes ();
3320         r->set_position (pos);
3321         _session->add_command(new StatefulDiffCommand (r));
3322
3323         /* move rest by the same amount */
3324
3325         sorted.pop_front();
3326
3327         for (list<RegionView*>::iterator i = sorted.begin(); i != sorted.end(); ++i) {
3328
3329                 boost::shared_ptr<Region> region ((*i)->region());
3330
3331                 region->clear_changes ();
3332
3333                 if (dir > 0) {
3334                         region->set_position (region->position() + distance);
3335                 } else {
3336                         region->set_position (region->position() - distance);
3337                 }
3338
3339                 _session->add_command(new StatefulDiffCommand (region));
3340
3341         }
3342
3343         commit_reversible_command ();
3344 }
3345
3346 void
3347 Editor::align_region (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3348 {
3349         begin_reversible_command (_("align region"));
3350         align_region_internal (region, point, position);
3351         commit_reversible_command ();
3352 }
3353
3354 void
3355 Editor::align_region_internal (boost::shared_ptr<Region> region, RegionPoint point, framepos_t position)
3356 {
3357         region->clear_changes ();
3358
3359         switch (point) {
3360         case SyncPoint:
3361                 region->set_position (region->adjust_to_sync (position));
3362                 break;
3363
3364         case End:
3365                 if (position > region->length()) {
3366                         region->set_position (position - region->length());
3367                 }
3368                 break;
3369
3370         case Start:
3371                 region->set_position (position);
3372                 break;
3373         }
3374
3375         _session->add_command(new StatefulDiffCommand (region));
3376 }
3377
3378 void
3379 Editor::trim_region_front ()
3380 {
3381         trim_region (true);
3382 }
3383
3384 void
3385 Editor::trim_region_back ()
3386 {
3387         trim_region (false);
3388 }
3389
3390 void
3391 Editor::trim_region (bool front)
3392 {
3393         framepos_t where = get_preferred_edit_position();
3394         RegionSelection rs = get_regions_from_selection_and_edit_point ();
3395
3396         if (rs.empty()) {
3397                 return;
3398         }
3399
3400         begin_reversible_command (front ? _("trim front") : _("trim back"));
3401
3402         for (list<RegionView*>::const_iterator i = rs.by_layer().begin(); i != rs.by_layer().end(); ++i) {
3403                 if (!(*i)->region()->locked()) {
3404
3405                         (*i)->region()->clear_changes ();
3406
3407                         if (front) {
3408                                 (*i)->region()->trim_front (where);
3409                                 maybe_locate_with_edit_preroll ( where );
3410                         } else {
3411                                 (*i)->region()->trim_end (where);
3412                                 maybe_locate_with_edit_preroll ( where );
3413                         }
3414
3415                         _session->add_command (new StatefulDiffCommand ((*i)->region()));
3416                 }
3417         }
3418
3419         commit_reversible_command ();
3420 }
3421
3422 /** Trim the end of the selected regions to the position of the edit cursor */
3423 void
3424 Editor::trim_region_to_loop ()
3425 {
3426         Location* loc = _session->locations()->auto_loop_location();
3427         if (!loc) {
3428                 return;
3429         }
3430         trim_region_to_location (*loc, _("trim to loop"));
3431 }
3432
3433 void
3434 Editor::trim_region_to_punch ()
3435 {
3436         Location* loc = _session->locations()->auto_punch_location();
3437         if (!loc) {
3438                 return;
3439         }
3440         trim_region_to_location (*loc, _("trim to punch"));
3441 }
3442
3443 void
3444 Editor::trim_region_to_location (const Location& loc, const char* str)
3445 {
3446         RegionSelection rs = get_regions_from_selection_and_entered ();
3447
3448         begin_reversible_command (str);
3449
3450         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3451                 RegionView* rv = (*x);
3452
3453                 /* require region to span proposed trim */
3454                 switch (rv->region()->coverage (loc.start(), loc.end())) {
3455                 case Evoral::OverlapInternal:
3456                         break;
3457                 default:
3458                         continue;
3459                 }
3460
3461                 RouteTimeAxisView* tav = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
3462                 if (!tav) {
3463                         return;
3464                 }
3465
3466                 float speed = 1.0;
3467                 framepos_t start;
3468                 framepos_t end;
3469
3470                 if (tav->track() != 0) {
3471                         speed = tav->track()->speed();
3472                 }
3473
3474                 start = session_frame_to_track_frame (loc.start(), speed);
3475                 end = session_frame_to_track_frame (loc.end(), speed);
3476
3477                 rv->region()->clear_changes ();
3478                 rv->region()->trim_to (start, (end - start));
3479                 _session->add_command(new StatefulDiffCommand (rv->region()));
3480         }
3481
3482         commit_reversible_command ();
3483 }
3484
3485 void
3486 Editor::trim_region_to_previous_region_end ()
3487 {
3488         return trim_to_region(false);
3489 }
3490
3491 void
3492 Editor::trim_region_to_next_region_start ()
3493 {
3494         return trim_to_region(true);
3495 }
3496
3497 void
3498 Editor::trim_to_region(bool forward)
3499 {
3500         RegionSelection rs = get_regions_from_selection_and_entered ();
3501
3502         begin_reversible_command (_("trim to region"));
3503
3504         boost::shared_ptr<Region> next_region;
3505
3506         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
3507
3508                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (*x);
3509
3510                 if (!arv) {
3511                         continue;
3512                 }
3513
3514                 AudioTimeAxisView* atav = dynamic_cast<AudioTimeAxisView*> (&arv->get_time_axis_view());
3515
3516                 if (!atav) {
3517                         return;
3518                 }
3519
3520                 float speed = 1.0;
3521
3522                 if (atav->track() != 0) {
3523                         speed = atav->track()->speed();
3524                 }
3525
3526
3527                 boost::shared_ptr<Region> region = arv->region();
3528                 boost::shared_ptr<Playlist> playlist (region->playlist());
3529
3530                 region->clear_changes ();
3531
3532                 if (forward) {
3533
3534                     next_region = playlist->find_next_region (region->first_frame(), Start, 1);
3535
3536                     if (!next_region) {
3537                         continue;
3538                     }
3539
3540                     region->trim_end((framepos_t) ( (next_region->first_frame() - 1) * speed));
3541                     arv->region_changed (PropertyChange (ARDOUR::Properties::length));
3542                 }
3543                 else {
3544
3545                     next_region = playlist->find_next_region (region->first_frame(), Start, 0);
3546
3547                     if(!next_region){
3548                         continue;
3549                     }
3550
3551                     region->trim_front((framepos_t) ((next_region->last_frame() + 1) * speed));
3552
3553                     arv->region_changed (ARDOUR::bounds_change);
3554                 }
3555
3556                 _session->add_command(new StatefulDiffCommand (region));
3557         }
3558
3559         commit_reversible_command ();
3560 }
3561
3562 void
3563 Editor::unfreeze_route ()
3564 {
3565         if (clicked_routeview == 0 || !clicked_routeview->is_track()) {
3566                 return;
3567         }
3568
3569         clicked_routeview->track()->unfreeze ();
3570 }
3571
3572 void*
3573 Editor::_freeze_thread (void* arg)
3574 {
3575         return static_cast<Editor*>(arg)->freeze_thread ();
3576 }
3577
3578 void*
3579 Editor::freeze_thread ()
3580 {
3581         /* create event pool because we may need to talk to the session */
3582         SessionEvent::create_per_thread_pool ("freeze events", 64);
3583         /* create per-thread buffers for process() tree to use */
3584         clicked_routeview->audio_track()->freeze_me (*current_interthread_info);
3585         current_interthread_info->done = true;
3586         return 0;
3587 }
3588
3589 void
3590 Editor::freeze_route ()
3591 {
3592         if (!_session) {
3593                 return;
3594         }
3595
3596         /* stop transport before we start. this is important */
3597
3598         _session->request_transport_speed (0.0);
3599         
3600         /* wait for just a little while, because the above call is asynchronous */
3601
3602         Glib::usleep (250000);
3603
3604         if (clicked_routeview == 0 || !clicked_routeview->is_audio_track()) {
3605                 return;
3606         }
3607
3608         if (!clicked_routeview->track()->bounceable (clicked_routeview->track()->main_outs(), true)) {
3609                 MessageDialog d (
3610                         _("This track/bus cannot be frozen because the signal adds or loses channels before reaching the outputs.\n"
3611                           "This is typically caused by plugins that generate stereo output from mono input or vice versa.")
3612                         );
3613                 d.set_title (_("Cannot freeze"));
3614                 d.run ();
3615                 return;
3616         }
3617
3618         if (clicked_routeview->track()->has_external_redirects()) {
3619                 MessageDialog d (string_compose (_("<b>%1</b>\n\nThis track has at least one send/insert/return as part of its signal flow.\n\n"
3620                                                    "Freezing will only process the signal as far as the first send/insert/return."),
3621                                                  clicked_routeview->track()->name()), true, MESSAGE_INFO, BUTTONS_NONE, true);
3622
3623                 d.add_button (_("Freeze anyway"), Gtk::RESPONSE_OK);
3624                 d.add_button (_("Don't freeze"), Gtk::RESPONSE_CANCEL);
3625                 d.set_title (_("Freeze Limits"));
3626
3627                 int response = d.run ();
3628
3629                 switch (response) {
3630                 case Gtk::RESPONSE_CANCEL:
3631                         return;
3632                 default:
3633                         break;
3634                 }
3635         }
3636
3637         InterThreadInfo itt;
3638         current_interthread_info = &itt;
3639
3640         InterthreadProgressWindow ipw (current_interthread_info, _("Freeze"), _("Cancel Freeze"));
3641
3642         pthread_create_and_store (X_("freezer"), &itt.thread, _freeze_thread, this);
3643
3644         set_canvas_cursor (_cursors->wait);
3645
3646         while (!itt.done && !itt.cancel) {
3647                 gtk_main_iteration ();
3648         }
3649
3650         current_interthread_info = 0;
3651         set_canvas_cursor (current_canvas_cursor);
3652 }
3653
3654 void
3655 Editor::bounce_range_selection (bool replace, bool enable_processing)
3656 {
3657         if (selection->time.empty()) {
3658                 return;
3659         }
3660
3661         TrackSelection views = selection->tracks;
3662
3663         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3664
3665                 if (enable_processing) {
3666
3667                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
3668
3669                         if (rtv && rtv->track() && replace && enable_processing && !rtv->track()->bounceable (rtv->track()->main_outs(), false)) {
3670                                 MessageDialog d (
3671                                         _("You can't perform this operation because the processing of the signal "
3672                                           "will cause one or more of the tracks to end up with a region with more channels than this track has inputs.\n\n"
3673                                           "You can do this without processing, which is a different operation.")
3674                                         );
3675                                 d.set_title (_("Cannot bounce"));
3676                                 d.run ();
3677                                 return;
3678                         }
3679                 }
3680         }
3681
3682         framepos_t start = selection->time[clicked_selection].start;
3683         framepos_t end = selection->time[clicked_selection].end;
3684         framepos_t cnt = end - start + 1;
3685
3686         begin_reversible_command (_("bounce range"));
3687
3688         for (TrackViewList::iterator i = views.begin(); i != views.end(); ++i) {
3689
3690                 RouteTimeAxisView* rtv;
3691
3692                 if ((rtv = dynamic_cast<RouteTimeAxisView*> (*i)) == 0) {
3693                         continue;
3694                 }
3695
3696                 boost::shared_ptr<Playlist> playlist;
3697
3698                 if ((playlist = rtv->playlist()) == 0) {
3699                         return;
3700                 }
3701
3702                 InterThreadInfo itt;
3703
3704                 playlist->clear_changes ();
3705                 playlist->clear_owned_changes ();
3706
3707                 boost::shared_ptr<Region> r;
3708
3709                 if (enable_processing) {
3710                         r = rtv->track()->bounce_range (start, start+cnt, itt, rtv->track()->main_outs(), false);
3711                 } else {
3712                         r = rtv->track()->bounce_range (start, start+cnt, itt, boost::shared_ptr<Processor>(), false);
3713                 }
3714
3715                 if (!r) {
3716                         continue;
3717                 }
3718
3719                 if (replace) {
3720                         list<AudioRange> ranges;
3721                         ranges.push_back (AudioRange (start, start+cnt, 0));
3722                         playlist->cut (ranges); // discard result
3723                         playlist->add_region (r, start);
3724                 }
3725
3726                 vector<Command*> cmds;
3727                 playlist->rdiff (cmds);
3728                 _session->add_commands (cmds);
3729
3730                 _session->add_command (new StatefulDiffCommand (playlist));
3731         }
3732
3733         commit_reversible_command ();
3734 }
3735
3736 /** Delete selected regions, automation points or a time range */
3737 void
3738 Editor::delete_ ()
3739 {
3740         //special case: if the user is pointing in the editor/mixer strip, they may be trying to delete a plugin.
3741         //we need this because the editor-mixer strip is in the editor window, so it doesn't get the bindings from the mix window
3742         bool deleted = false;
3743         if ( current_mixer_strip && current_mixer_strip == MixerStrip::entered_mixer_strip() )
3744                 deleted = current_mixer_strip->delete_processors ();
3745
3746         if (!deleted)
3747                 cut_copy (Delete);
3748 }
3749
3750 /** Cut selected regions, automation points or a time range */
3751 void
3752 Editor::cut ()
3753 {
3754         cut_copy (Cut);
3755 }
3756
3757 /** Copy selected regions, automation points or a time range */
3758 void
3759 Editor::copy ()
3760 {
3761         cut_copy (Copy);
3762 }
3763
3764
3765 /** @return true if a Cut, Copy or Clear is possible */
3766 bool
3767 Editor::can_cut_copy () const
3768 {
3769         if (!selection->time.empty() || !selection->regions.empty() || !selection->points.empty())
3770                 return true;
3771
3772         return false;
3773 }
3774
3775
3776 /** Cut, copy or clear selected regions, automation points or a time range.
3777  * @param op Operation (Delete, Cut, Copy or Clear)
3778  */
3779 void
3780 Editor::cut_copy (CutCopyOp op)
3781 {
3782         /* only cancel selection if cut/copy is successful.*/
3783
3784         string opname;
3785
3786         switch (op) {
3787         case Delete:
3788                 opname = _("delete");
3789                 break;
3790         case Cut:
3791                 opname = _("cut");
3792                 break;
3793         case Copy:
3794                 opname = _("copy");
3795                 break;
3796         case Clear:
3797                 opname = _("clear");
3798                 break;
3799         }
3800
3801         /* if we're deleting something, and the mouse is still pressed,
3802            the thing we started a drag for will be gone when we release
3803            the mouse button(s). avoid this. see part 2 at the end of
3804            this function.
3805         */
3806
3807         if (op == Delete || op == Cut || op == Clear) {
3808                 if (_drags->active ()) {
3809                         _drags->abort ();
3810                 }
3811         }
3812
3813         if ( op != Delete )  //"Delete" doesn't change copy/paste buf
3814                 cut_buffer->clear ();
3815
3816         if (entered_marker) {
3817
3818                 /* cut/delete op while pointing at a marker */
3819
3820                 bool ignored;
3821                 Location* loc = find_location_from_marker (entered_marker, ignored);
3822
3823                 if (_session && loc) {
3824                         Glib::signal_idle().connect (sigc::bind (sigc::mem_fun(*this, &Editor::really_remove_marker), loc));
3825                 }
3826
3827                 _drags->abort ();
3828                 return;
3829         }
3830
3831         if (internal_editing()) {
3832
3833                 switch (effective_mouse_mode()) {
3834                 case MouseObject:
3835                 case MouseRange:
3836                         begin_reversible_command (opname + ' ' + X_("MIDI"));
3837                         cut_copy_midi (op);
3838                         commit_reversible_command ();
3839                         break;
3840                 default:
3841                         break;
3842                 }
3843
3844                 return;
3845         }
3846
3847         bool did_edit = false;
3848
3849         if (!selection->regions.empty() || !selection->points.empty()) {
3850                 begin_reversible_command (opname + ' ' + _("objects"));
3851                 did_edit = true;
3852
3853                 if (!selection->regions.empty()) {
3854                         cut_copy_regions (op, selection->regions);
3855                         
3856                         if (op == Cut || op == Delete) {
3857                                 selection->clear_regions ();
3858                         }
3859                 }
3860                 
3861                 if (!selection->points.empty()) {
3862                         cut_copy_points (op);
3863                         
3864                         if (op == Cut || op == Delete) {
3865                                 selection->clear_points ();
3866                         }
3867                 }
3868         } else if (selection->time.empty()) {
3869                 framepos_t start, end;
3870                 /* no time selection, see if we can get an edit range
3871                    and use that.
3872                 */
3873                 if (get_edit_op_range (start, end)) {
3874                         selection->set (start, end);
3875                 }
3876         } else if (!selection->time.empty()) {
3877                 begin_reversible_command (opname + ' ' + _("range"));
3878
3879                 did_edit = true;
3880                 cut_copy_ranges (op);
3881                 
3882                 if (op == Cut || op == Delete) {
3883                         selection->clear_time ();
3884                 }
3885         }
3886         
3887         if (did_edit) {
3888                 /* reset repeated paste state */
3889                 paste_count    = 0;
3890                 last_paste_pos = 0;
3891                 commit_reversible_command ();   
3892         }
3893         
3894         if (op == Delete || op == Cut || op == Clear) {
3895                 _drags->abort ();
3896         }
3897 }
3898
3899 struct AutomationRecord {
3900         AutomationRecord () : state (0) , line(NULL) {}
3901         AutomationRecord (XMLNode* s, const AutomationLine* l) : state (s) , line (l) {}
3902         
3903         XMLNode* state; ///< state before any operation
3904         const AutomationLine* line; ///< line this came from
3905         boost::shared_ptr<Evoral::ControlList> copy; ///< copied events for the cut buffer
3906 };
3907
3908 /** Cut, copy or clear selected automation points.
3909  *  @param op Operation (Cut, Copy or Clear)
3910  */
3911 void
3912 Editor::cut_copy_points (CutCopyOp op)
3913 {
3914         if (selection->points.empty ()) {
3915                 return;
3916         }
3917
3918         /* XXX: not ideal, as there may be more than one track involved in the point selection */
3919         _last_cut_copy_source_track = &selection->points.front()->line().trackview;
3920
3921         /* Keep a record of the AutomationLists that we end up using in this operation */
3922         typedef std::map<boost::shared_ptr<AutomationList>, AutomationRecord> Lists;
3923         Lists lists;
3924
3925         /* Go through all selected points, making an AutomationRecord for each distinct AutomationList */
3926         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3927                 const AutomationLine&                   line = (*i)->line();
3928                 const boost::shared_ptr<AutomationList> al   = line.the_list();
3929                 if (lists.find (al) == lists.end ()) {
3930                         /* We haven't seen this list yet, so make a record for it.  This includes
3931                            taking a copy of its current state, in case this is needed for undo later.
3932                         */
3933                         lists[al] = AutomationRecord (&al->get_state (), &line);
3934                 }
3935         }
3936
3937         if (op == Cut || op == Copy) {
3938                 /* This operation will involve putting things in the cut buffer, so create an empty
3939                    ControlList for each of our source lists to put the cut buffer data in.
3940                 */
3941                 framepos_t start = std::numeric_limits<framepos_t>::max();
3942                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3943                         i->second.copy = i->first->create (i->first->parameter ());
3944
3945                         /* Calculate earliest start position of any point in selection. */
3946                         start = std::min(start, i->second.line->session_position(i->first->begin()));
3947                 }
3948
3949                 /* Add all selected points to the relevant copy ControlLists */
3950                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3951                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3952                         AutomationList::const_iterator j = (*i)->model ();
3953                         lists[al].copy->fast_simple_add ((*j)->when, (*j)->value);
3954                 }
3955
3956                 /* Snap start time backwards, so copy/paste is snap aligned. */
3957                 snap_to(start, RoundDownMaybe);
3958
3959                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3960                         /* Correct this copy list so that it is relative to the earliest
3961                            start time, so relative ordering between points is preserved
3962                            when copying from several lists. */
3963                         const AutomationLine* line        = i->second.line;
3964                         const double          line_offset = line->time_converter().from(start);
3965
3966                         for (AutomationList::iterator j = i->second.copy->begin(); j != i->second.copy->end(); ++j) {
3967                                 (*j)->when -= line_offset;
3968                         }
3969
3970                         /* And add it to the cut buffer */
3971                         cut_buffer->add (i->second.copy);
3972                 }
3973         }
3974                 
3975         if (op == Delete || op == Cut) {
3976                 /* This operation needs to remove things from the main AutomationList, so do that now */
3977                 
3978                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3979                         i->first->freeze ();
3980                 }
3981
3982                 /* Remove each selected point from its AutomationList */
3983                 for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
3984                         boost::shared_ptr<AutomationList> al = (*i)->line().the_list();
3985                         al->erase ((*i)->model ());
3986                 }
3987
3988                 /* Thaw the lists and add undo records for them */
3989                 for (Lists::iterator i = lists.begin(); i != lists.end(); ++i) {
3990                         boost::shared_ptr<AutomationList> al = i->first;
3991                         al->thaw ();
3992                         _session->add_command (new MementoCommand<AutomationList> (*al.get(), i->second.state, &(al->get_state ())));
3993                 }
3994         }
3995 }
3996
3997 /** Cut, copy or clear selected automation points.
3998  * @param op Operation (Cut, Copy or Clear)
3999  */
4000 void
4001 Editor::cut_copy_midi (CutCopyOp op)
4002 {
4003         for (MidiRegionSelection::iterator i = selection->midi_regions.begin(); i != selection->midi_regions.end(); ++i) {
4004                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(*i);
4005                 if (mrv) {
4006                         mrv->cut_copy_clear (op);
4007
4008                         /* XXX: not ideal, as there may be more than one track involved in the selection */
4009                         _last_cut_copy_source_track = &mrv->get_time_axis_view();
4010                 }
4011         }
4012
4013         if (!selection->points.empty()) {
4014                 cut_copy_points (op);
4015                 if (op == Cut || op == Delete) {
4016                         selection->clear_points ();
4017                 }
4018         }
4019 }
4020
4021 struct lt_playlist {
4022     bool operator () (const PlaylistState& a, const PlaylistState& b) {
4023             return a.playlist < b.playlist;
4024     }
4025 };
4026
4027 struct PlaylistMapping {
4028     TimeAxisView* tv;
4029     boost::shared_ptr<Playlist> pl;
4030
4031     PlaylistMapping (TimeAxisView* tvp) : tv (tvp) {}
4032 };
4033
4034 /** Remove `clicked_regionview' */
4035 void
4036 Editor::remove_clicked_region ()
4037 {
4038         if (clicked_routeview == 0 || clicked_regionview == 0) {
4039                 return;
4040         }
4041
4042         boost::shared_ptr<Playlist> playlist = clicked_routeview->playlist();
4043
4044         playlist->clear_changes ();
4045         playlist->clear_owned_changes ();
4046         playlist->remove_region (clicked_regionview->region());
4047         if (Config->get_edit_mode() == Ripple)
4048                 playlist->ripple (clicked_regionview->region()->position(), -clicked_regionview->region()->length(), boost::shared_ptr<Region>());
4049
4050         /* We might have removed regions, which alters other regions' layering_index,
4051            so we need to do a recursive diff here.
4052         */
4053         vector<Command*> cmds;
4054         playlist->rdiff (cmds);
4055         _session->add_commands (cmds);
4056         
4057         _session->add_command(new StatefulDiffCommand (playlist));
4058         commit_reversible_command ();
4059 }
4060
4061
4062 /** Remove the selected regions */
4063 void
4064 Editor::remove_selected_regions ()
4065 {
4066         RegionSelection rs = get_regions_from_selection_and_entered ();
4067
4068         if (!_session || rs.empty()) {
4069                 return;
4070         }
4071
4072         begin_reversible_command (_("remove region"));
4073
4074         list<boost::shared_ptr<Region> > regions_to_remove;
4075
4076         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4077                 // we can't just remove the region(s) in this loop because
4078                 // this removes them from the RegionSelection, and they thus
4079                 // disappear from underneath the iterator, and the ++i above
4080                 // SEGVs in a puzzling fashion.
4081
4082                 // so, first iterate over the regions to be removed from rs and
4083                 // add them to the regions_to_remove list, and then
4084                 // iterate over the list to actually remove them.
4085
4086                 regions_to_remove.push_back ((*i)->region());
4087         }
4088
4089         vector<boost::shared_ptr<Playlist> > playlists;
4090
4091         for (list<boost::shared_ptr<Region> >::iterator rl = regions_to_remove.begin(); rl != regions_to_remove.end(); ++rl) {
4092
4093                 boost::shared_ptr<Playlist> playlist = (*rl)->playlist();
4094
4095                 if (!playlist) {
4096                         // is this check necessary?
4097                         continue;
4098                 }
4099
4100                 /* get_regions_from_selection_and_entered() guarantees that
4101                    the playlists involved are unique, so there is no need
4102                    to check here.
4103                 */
4104
4105                 playlists.push_back (playlist);
4106
4107                 playlist->clear_changes ();
4108                 playlist->clear_owned_changes ();
4109                 playlist->freeze ();
4110                 playlist->remove_region (*rl);
4111                 if (Config->get_edit_mode() == Ripple)
4112                         playlist->ripple ((*rl)->position(), -(*rl)->length(), boost::shared_ptr<Region>());
4113
4114         }
4115
4116         vector<boost::shared_ptr<Playlist> >::iterator pl;
4117
4118         for (pl = playlists.begin(); pl != playlists.end(); ++pl) {
4119                 (*pl)->thaw ();
4120
4121                 /* We might have removed regions, which alters other regions' layering_index,
4122                    so we need to do a recursive diff here.
4123                 */
4124                 vector<Command*> cmds;
4125                 (*pl)->rdiff (cmds);
4126                 _session->add_commands (cmds);
4127                 
4128                 _session->add_command(new StatefulDiffCommand (*pl));
4129         }
4130
4131         commit_reversible_command ();
4132 }
4133
4134 /** Cut, copy or clear selected regions.
4135  * @param op Operation (Cut, Copy or Clear)
4136  */
4137 void
4138 Editor::cut_copy_regions (CutCopyOp op, RegionSelection& rs)
4139 {
4140         /* we can't use a std::map here because the ordering is important, and we can't trivially sort
4141            a map when we want ordered access to both elements. i think.
4142         */
4143
4144         vector<PlaylistMapping> pmap;
4145
4146         framepos_t first_position = max_framepos;
4147
4148         typedef set<boost::shared_ptr<Playlist> > FreezeList;
4149         FreezeList freezelist;
4150
4151         /* get ordering correct before we cut/copy */
4152
4153         rs.sort_by_position_and_track ();
4154
4155         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
4156
4157                 first_position = min ((framepos_t) (*x)->region()->position(), first_position);
4158
4159                 if (op == Cut || op == Clear || op == Delete) {
4160                         boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4161
4162                         if (pl) {
4163                                 FreezeList::iterator fl;
4164
4165                                 // only take state if this is a new playlist.
4166                                 for (fl = freezelist.begin(); fl != freezelist.end(); ++fl) {
4167                                         if ((*fl) == pl) {
4168                                                 break;
4169                                         }
4170                                 }
4171
4172                                 if (fl == freezelist.end()) {
4173                                         pl->clear_changes();
4174                                         pl->clear_owned_changes ();
4175                                         pl->freeze ();
4176                                         freezelist.insert (pl);
4177                                 }
4178                         }
4179                 }
4180
4181                 TimeAxisView* tv = &(*x)->get_time_axis_view();
4182                 vector<PlaylistMapping>::iterator z;
4183
4184                 for (z = pmap.begin(); z != pmap.end(); ++z) {
4185                         if ((*z).tv == tv) {
4186                                 break;
4187                         }
4188                 }
4189
4190                 if (z == pmap.end()) {
4191                         pmap.push_back (PlaylistMapping (tv));
4192                 }
4193         }
4194
4195         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ) {
4196
4197                 boost::shared_ptr<Playlist> pl = (*x)->region()->playlist();
4198
4199                 if (!pl) {
4200                         /* region not yet associated with a playlist (e.g. unfinished
4201                            capture pass.
4202                         */
4203                         ++x;
4204                         continue;
4205                 }
4206
4207                 TimeAxisView& tv = (*x)->get_time_axis_view();
4208                 boost::shared_ptr<Playlist> npl;
4209                 RegionSelection::iterator tmp;
4210
4211                 tmp = x;
4212                 ++tmp;
4213
4214                 if (op != Delete) {
4215
4216                         vector<PlaylistMapping>::iterator z;
4217                         
4218                         for (z = pmap.begin(); z != pmap.end(); ++z) {
4219                                 if ((*z).tv == &tv) {
4220                                         break;
4221                                 }
4222                         }
4223                         
4224                         assert (z != pmap.end());
4225                         
4226                         if (!(*z).pl) {
4227                                 npl = PlaylistFactory::create (pl->data_type(), *_session, "cutlist", true);
4228                                 npl->freeze();
4229                                 (*z).pl = npl;
4230                         } else {
4231                                 npl = (*z).pl;
4232                         }
4233                 }
4234
4235                 boost::shared_ptr<Region> r = (*x)->region();
4236                 boost::shared_ptr<Region> _xx;
4237
4238                 assert (r != 0);
4239
4240                 switch (op) {
4241                 case Delete:
4242                         pl->remove_region (r);
4243                         if (Config->get_edit_mode() == Ripple)
4244                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4245                         break;
4246                         
4247                 case Cut:
4248                         _xx = RegionFactory::create (r);
4249                         npl->add_region (_xx, r->position() - first_position);
4250                         pl->remove_region (r);
4251                         if (Config->get_edit_mode() == Ripple)
4252                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4253                         break;
4254
4255                 case Copy:
4256                         /* copy region before adding, so we're not putting same object into two different playlists */
4257                         npl->add_region (RegionFactory::create (r), r->position() - first_position);
4258                         break;
4259
4260                 case Clear:
4261                         pl->remove_region (r);
4262                         if (Config->get_edit_mode() == Ripple)
4263                                 pl->ripple (r->position(), -r->length(), boost::shared_ptr<Region>());
4264                         break;
4265                 }
4266
4267                 x = tmp;
4268         }
4269
4270         if (op != Delete) {
4271
4272                 list<boost::shared_ptr<Playlist> > foo;
4273                 
4274                 /* the pmap is in the same order as the tracks in which selected regions occured */
4275                 
4276                 for (vector<PlaylistMapping>::iterator i = pmap.begin(); i != pmap.end(); ++i) {
4277                         if ((*i).pl) {
4278                                 (*i).pl->thaw();
4279                                 foo.push_back ((*i).pl);
4280                         }
4281                 }
4282                 
4283                 if (!foo.empty()) {
4284                         cut_buffer->set (foo);
4285                 }
4286                 
4287                 if (pmap.empty()) {
4288                         _last_cut_copy_source_track = 0;
4289                 } else {
4290                         _last_cut_copy_source_track = pmap.front().tv;
4291                 }
4292         }
4293
4294         for (FreezeList::iterator pl = freezelist.begin(); pl != freezelist.end(); ++pl) {
4295                 (*pl)->thaw ();
4296
4297                 /* We might have removed regions, which alters other regions' layering_index,
4298                    so we need to do a recursive diff here.
4299                 */
4300                 vector<Command*> cmds;
4301                 (*pl)->rdiff (cmds);
4302                 _session->add_commands (cmds);
4303                 
4304                 _session->add_command (new StatefulDiffCommand (*pl));
4305         }
4306 }
4307
4308 void
4309 Editor::cut_copy_ranges (CutCopyOp op)
4310 {
4311         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4312
4313         /* Sort the track selection now, so that it if is used, the playlists
4314            selected by the calls below to cut_copy_clear are in the order that
4315            their tracks appear in the editor.  This makes things like paste
4316            of ranges work properly.
4317         */
4318
4319         sort_track_selection (ts);
4320
4321         if (ts.empty()) {
4322                 if (!entered_track) {
4323                         return;
4324                 }
4325                 ts.push_back (entered_track);
4326         } 
4327
4328         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4329                 (*i)->cut_copy_clear (*selection, op);
4330         }
4331 }
4332
4333 void
4334 Editor::paste (float times, bool from_context)
4335 {
4336         DEBUG_TRACE (DEBUG::CutNPaste, "paste to preferred edit pos\n");
4337
4338         paste_internal (get_preferred_edit_position (false, from_context), times);
4339 }
4340
4341 void
4342 Editor::mouse_paste ()
4343 {
4344         framepos_t where;
4345         bool ignored;
4346
4347         if (!mouse_frame (where, ignored)) {
4348                 return;
4349         }
4350
4351         snap_to (where);
4352         paste_internal (where, 1);
4353 }
4354
4355 void
4356 Editor::paste_internal (framepos_t position, float times)
4357 {
4358         DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("apparent paste position is %1\n", position));
4359
4360         if (cut_buffer->empty(internal_editing())) {
4361                 return;
4362         }
4363
4364         if (position == max_framepos) {
4365                 position = get_preferred_edit_position();
4366                 DEBUG_TRACE (DEBUG::CutNPaste, string_compose ("preferred edit position is %1\n", position));
4367         }
4368
4369         if (position == last_paste_pos) {
4370                 /* repeated paste in the same position */
4371                 ++paste_count;
4372         } else {
4373                 /* paste in new location, reset repeated paste state */
4374                 paste_count = 0;
4375                 last_paste_pos = position;
4376         }
4377
4378         /* get everything in the correct order */
4379
4380         TrackViewList ts;
4381         if (!selection->tracks.empty()) {
4382                 /* If there is a track selection, paste into exactly those tracks and
4383                    only those tracks.  This allows the user to be explicit and override
4384                    the below "do the reasonable thing" logic. */
4385                 ts = selection->tracks.filter_to_unique_playlists ();
4386                 sort_track_selection (ts);
4387         } else {
4388                 /* Figure out which track to base the paste at. */
4389                 TimeAxisView* base_track = NULL;
4390                 if (_edit_point == Editing::EditAtMouse && entered_track) {
4391                         /* With the mouse edit point, paste onto the track under the mouse. */
4392                         base_track = entered_track;
4393                 } else if (_edit_point == Editing::EditAtMouse && entered_regionview) {
4394                         /* With the mouse edit point, paste onto the track of the region under the mouse. */
4395                         base_track = &entered_regionview->get_time_axis_view();
4396                 } else if (_last_cut_copy_source_track) {
4397                         /* Paste to the track that the cut/copy came from (see mantis #333). */
4398                         base_track = _last_cut_copy_source_track;
4399                 } else {
4400                         /* This is "impossible" since we've copied... well, do nothing. */
4401                         return;
4402                 }
4403
4404                 /* Walk up to parent if necessary, so base track is a route. */
4405                 while (base_track->get_parent()) {
4406                         base_track = base_track->get_parent();
4407                 }
4408
4409                 /* Add base track and all tracks below it.  The paste logic will select
4410                    the appropriate object types from the cut buffer in relative order. */
4411                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
4412                         if ((*i)->order() >= base_track->order()) {
4413                                 ts.push_back(*i);
4414                         }
4415                 }
4416
4417                 /* Sort tracks so the nth track of type T will pick the nth object of type T. */
4418                 sort_track_selection (ts);
4419
4420                 /* Add automation children of each track in order, for pasting several lines. */
4421                 for (TrackViewList::iterator i = ts.begin(); i != ts.end();) {
4422                         /* Add any automation children for pasting several lines */
4423                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*i++);
4424                         if (!rtv) {
4425                                 continue;
4426                         }
4427
4428                         typedef RouteTimeAxisView::AutomationTracks ATracks;
4429                         const ATracks& atracks = rtv->automation_tracks();
4430                         for (ATracks::const_iterator a = atracks.begin(); a != atracks.end(); ++a) {
4431                                 i = ts.insert(i, a->second.get());
4432                                 ++i;
4433                         }
4434                 }
4435
4436                 /* We now have a list of trackviews starting at base_track, including
4437                    automation children, in the order shown in the editor, e.g. R1,
4438                    R1.A1, R1.A2, R2, R2.A1, ... */
4439         }
4440
4441         if (internal_editing ()) {
4442
4443                 /* undo/redo is handled by individual tracks/regions */
4444
4445                 RegionSelection rs;
4446                 get_regions_at (rs, position, ts);
4447
4448                 ItemCounts counts;
4449                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4450                         MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*r);
4451                         if (mrv) {
4452                                 mrv->paste (position, paste_count, times, *cut_buffer, counts);
4453                         }
4454                 }
4455
4456         } else {
4457
4458                 /* we do redo (do you do voodoo?) */
4459
4460                 begin_reversible_command (Operations::paste);
4461
4462                 ItemCounts counts;
4463                 for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4464                         (*i)->paste (position, paste_count, times, *cut_buffer, counts);
4465                 }
4466
4467                 commit_reversible_command ();
4468         }
4469 }
4470
4471 void
4472 Editor::duplicate_some_regions (RegionSelection& regions, float times)
4473 {
4474         boost::shared_ptr<Playlist> playlist;
4475         RegionSelection sel = regions; // clear (below) may  clear the argument list if its the current region selection
4476         RegionSelection foo;
4477
4478         framepos_t const start_frame = regions.start ();
4479         framepos_t const end_frame = regions.end_frame ();
4480
4481         begin_reversible_command (Operations::duplicate_region);
4482
4483         selection->clear_regions ();
4484
4485         for (RegionSelection::iterator i = sel.begin(); i != sel.end(); ++i) {
4486
4487                 boost::shared_ptr<Region> r ((*i)->region());
4488
4489                 TimeAxisView& tv = (*i)->get_time_axis_view();
4490                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&tv);
4491                 latest_regionviews.clear ();
4492                 sigc::connection c = rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*this, &Editor::collect_new_region_view));
4493
4494                 playlist = (*i)->region()->playlist();
4495                 playlist->clear_changes ();
4496                 playlist->duplicate (r, end_frame + (r->first_frame() - start_frame), times);
4497                 _session->add_command(new StatefulDiffCommand (playlist));
4498
4499                 c.disconnect ();
4500
4501                 foo.insert (foo.end(), latest_regionviews.begin(), latest_regionviews.end());
4502         }
4503
4504         commit_reversible_command ();
4505
4506         if (!foo.empty()) {
4507                 selection->set (foo);
4508         }
4509 }
4510
4511 void
4512 Editor::duplicate_selection (float times)
4513 {
4514         if (selection->time.empty() || selection->tracks.empty()) {
4515                 return;
4516         }
4517
4518         boost::shared_ptr<Playlist> playlist;
4519         vector<boost::shared_ptr<Region> > new_regions;
4520         vector<boost::shared_ptr<Region> >::iterator ri;
4521
4522         create_region_from_selection (new_regions);
4523
4524         if (new_regions.empty()) {
4525                 return;
4526         }
4527
4528         begin_reversible_command (_("duplicate selection"));
4529
4530         ri = new_regions.begin();
4531
4532         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4533
4534         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4535                 if ((playlist = (*i)->playlist()) == 0) {
4536                         continue;
4537                 }
4538                 playlist->clear_changes ();
4539                 playlist->duplicate (*ri, selection->time[clicked_selection].end, times);
4540                 _session->add_command (new StatefulDiffCommand (playlist));
4541
4542                 ++ri;
4543                 if (ri == new_regions.end()) {
4544                         --ri;
4545                 }
4546         }
4547
4548         commit_reversible_command ();
4549 }
4550
4551 /** Reset all selected points to the relevant default value */
4552 void
4553 Editor::reset_point_selection ()
4554 {
4555         for (PointSelection::iterator i = selection->points.begin(); i != selection->points.end(); ++i) {
4556                 ARDOUR::AutomationList::iterator j = (*i)->model ();
4557                 (*j)->value = (*i)->line().the_list()->default_value ();
4558         }
4559 }
4560
4561 void
4562 Editor::center_playhead ()
4563 {
4564         float const page = _visible_canvas_width * samples_per_pixel;
4565         center_screen_internal (playhead_cursor->current_frame (), page);
4566 }
4567
4568 void
4569 Editor::center_edit_point ()
4570 {
4571         float const page = _visible_canvas_width * samples_per_pixel;
4572         center_screen_internal (get_preferred_edit_position(), page);
4573 }
4574
4575 /** Caller must begin and commit a reversible command */
4576 void
4577 Editor::clear_playlist (boost::shared_ptr<Playlist> playlist)
4578 {
4579         playlist->clear_changes ();
4580         playlist->clear ();
4581         _session->add_command (new StatefulDiffCommand (playlist));
4582 }
4583
4584 void
4585 Editor::nudge_track (bool use_edit, bool forwards)
4586 {
4587         boost::shared_ptr<Playlist> playlist;
4588         framepos_t distance;
4589         framepos_t next_distance;
4590         framepos_t start;
4591
4592         if (use_edit) {
4593                 start = get_preferred_edit_position();
4594         } else {
4595                 start = 0;
4596         }
4597
4598         if ((distance = get_nudge_distance (start, next_distance)) == 0) {
4599                 return;
4600         }
4601
4602         if (selection->tracks.empty()) {
4603                 return;
4604         }
4605
4606         begin_reversible_command (_("nudge track"));
4607
4608         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
4609
4610         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
4611
4612                 if ((playlist = (*i)->playlist()) == 0) {
4613                         continue;
4614                 }
4615
4616                 playlist->clear_changes ();
4617                 playlist->clear_owned_changes ();
4618
4619                 playlist->nudge_after (start, distance, forwards);
4620
4621                 vector<Command*> cmds;
4622
4623                 playlist->rdiff (cmds);
4624                 _session->add_commands (cmds);
4625
4626                 _session->add_command (new StatefulDiffCommand (playlist));
4627         }
4628
4629         commit_reversible_command ();
4630 }
4631
4632 void
4633 Editor::remove_last_capture ()
4634 {
4635         vector<string> choices;
4636         string prompt;
4637
4638         if (!_session) {
4639                 return;
4640         }
4641
4642         if (Config->get_verify_remove_last_capture()) {
4643                 prompt  = _("Do you really want to destroy the last capture?"
4644                             "\n(This is destructive and cannot be undone)");
4645
4646                 choices.push_back (_("No, do nothing."));
4647                 choices.push_back (_("Yes, destroy it."));
4648
4649                 Gtkmm2ext::Choice prompter (_("Destroy last capture"), prompt, choices);
4650
4651                 if (prompter.run () == 1) {
4652                         _session->remove_last_capture ();
4653                         _regions->redisplay ();
4654                 }
4655
4656         } else {
4657                 _session->remove_last_capture();
4658                 _regions->redisplay ();
4659         }
4660 }
4661
4662 void
4663 Editor::normalize_region ()
4664 {
4665         if (!_session) {
4666                 return;
4667         }
4668
4669         RegionSelection rs = get_regions_from_selection_and_entered ();
4670
4671         if (rs.empty()) {
4672                 return;
4673         }
4674
4675         NormalizeDialog dialog (rs.size() > 1);
4676
4677         if (dialog.run () == RESPONSE_CANCEL) {
4678                 return;
4679         }
4680
4681         set_canvas_cursor (_cursors->wait);
4682         gdk_flush ();
4683
4684         /* XXX: should really only count audio regions here */
4685         int const regions = rs.size ();
4686
4687         /* Make a list of the selected audio regions' maximum amplitudes, and also
4688            obtain the maximum amplitude of them all.
4689         */
4690         list<double> max_amps;
4691         double max_amp = 0;
4692         for (RegionSelection::const_iterator i = rs.begin(); i != rs.end(); ++i) {
4693                 AudioRegionView const * arv = dynamic_cast<AudioRegionView const *> (*i);
4694                 if (arv) {
4695                         dialog.descend (1.0 / regions);
4696                         double const a = arv->audio_region()->maximum_amplitude (&dialog);
4697
4698                         if (a == -1) {
4699                                 /* the user cancelled the operation */
4700                                 set_canvas_cursor (current_canvas_cursor);
4701                                 return;
4702                         }
4703
4704                         max_amps.push_back (a);
4705                         max_amp = max (max_amp, a);
4706                         dialog.ascend ();
4707                 }
4708         }
4709
4710         begin_reversible_command (_("normalize"));
4711
4712         list<double>::const_iterator a = max_amps.begin ();
4713
4714         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4715                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*r);
4716                 if (!arv) {
4717                         continue;
4718                 }
4719
4720                 arv->region()->clear_changes ();
4721
4722                 double const amp = dialog.normalize_individually() ? *a : max_amp;
4723
4724                 arv->audio_region()->normalize (amp, dialog.target ());
4725                 _session->add_command (new StatefulDiffCommand (arv->region()));
4726
4727                 ++a;
4728         }
4729
4730         commit_reversible_command ();
4731         set_canvas_cursor (current_canvas_cursor);
4732 }
4733
4734
4735 void
4736 Editor::reset_region_scale_amplitude ()
4737 {
4738         if (!_session) {
4739                 return;
4740         }
4741
4742         RegionSelection rs = get_regions_from_selection_and_entered ();
4743
4744         if (rs.empty()) {
4745                 return;
4746         }
4747
4748         begin_reversible_command ("reset gain");
4749
4750         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4751                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4752                 if (!arv)
4753                         continue;
4754                 arv->region()->clear_changes ();
4755                 arv->audio_region()->set_scale_amplitude (1.0f);
4756                 _session->add_command (new StatefulDiffCommand (arv->region()));
4757         }
4758
4759         commit_reversible_command ();
4760 }
4761
4762 void
4763 Editor::adjust_region_gain (bool up)
4764 {
4765         RegionSelection rs = get_regions_from_selection_and_entered ();
4766
4767         if (!_session || rs.empty()) {
4768                 return;
4769         }
4770
4771         begin_reversible_command ("adjust region gain");
4772
4773         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4774                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
4775                 if (!arv) {
4776                         continue;
4777                 }
4778
4779                 arv->region()->clear_changes ();
4780
4781                 double dB = accurate_coefficient_to_dB (arv->audio_region()->scale_amplitude ());
4782
4783                 if (up) {
4784                         dB += 1;
4785                 } else {
4786                         dB -= 1;
4787                 }
4788
4789                 arv->audio_region()->set_scale_amplitude (dB_to_coefficient (dB));
4790                 _session->add_command (new StatefulDiffCommand (arv->region()));
4791         }
4792
4793         commit_reversible_command ();
4794 }
4795
4796
4797 void
4798 Editor::reverse_region ()
4799 {
4800         if (!_session) {
4801                 return;
4802         }
4803
4804         Reverse rev (*_session);
4805         apply_filter (rev, _("reverse regions"));
4806 }
4807
4808 void
4809 Editor::strip_region_silence ()
4810 {
4811         if (!_session) {
4812                 return;
4813         }
4814
4815         RegionSelection rs = get_regions_from_selection_and_entered ();
4816
4817         if (rs.empty()) {
4818                 return;
4819         }
4820
4821         std::list<RegionView*> audio_only;
4822
4823         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
4824                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (*i);
4825                 if (arv) {
4826                         audio_only.push_back (arv);
4827                 }
4828         }
4829
4830         StripSilenceDialog d (_session, audio_only);
4831         int const r = d.run ();
4832
4833         d.drop_rects ();
4834
4835         if (r == Gtk::RESPONSE_OK) {
4836                 ARDOUR::AudioIntervalMap silences;
4837                 d.silences (silences);
4838                 StripSilence s (*_session, silences, d.fade_length());
4839                 apply_filter (s, _("strip silence"), &d);
4840         }
4841 }
4842
4843 Command*
4844 Editor::apply_midi_note_edit_op_to_region (MidiOperator& op, MidiRegionView& mrv)
4845 {
4846         Evoral::Sequence<Evoral::MusicalTime>::Notes selected;
4847         mrv.selection_as_notelist (selected, true);
4848
4849         vector<Evoral::Sequence<Evoral::MusicalTime>::Notes> v;
4850         v.push_back (selected);
4851
4852         framepos_t pos_frames = mrv.midi_region()->position() - mrv.midi_region()->start();
4853         double     pos_beats  = _session->tempo_map().framewalk_to_beats(0, pos_frames);
4854
4855         return op (mrv.midi_region()->model(), pos_beats, v);
4856 }
4857
4858 void
4859 Editor::apply_midi_note_edit_op (MidiOperator& op)
4860 {
4861         Command* cmd;
4862
4863         RegionSelection rs = get_regions_from_selection_and_entered ();
4864
4865         if (rs.empty()) {
4866                 return;
4867         }
4868
4869         begin_reversible_command (op.name ());
4870
4871         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4872                 RegionSelection::iterator tmp = r;
4873                 ++tmp;
4874
4875                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4876
4877                 if (mrv) {
4878                         cmd = apply_midi_note_edit_op_to_region (op, *mrv);
4879                         if (cmd) {
4880                                 (*cmd)();
4881                                 _session->add_command (cmd);
4882                         }
4883                 }
4884
4885                 r = tmp;
4886         }
4887
4888         commit_reversible_command ();
4889 }
4890
4891 void
4892 Editor::fork_region ()
4893 {
4894         RegionSelection rs = get_regions_from_selection_and_entered ();
4895
4896         if (rs.empty()) {
4897                 return;
4898         }
4899
4900         begin_reversible_command (_("Fork Region(s)"));
4901
4902         set_canvas_cursor (_cursors->wait);
4903         gdk_flush ();
4904
4905         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
4906                 RegionSelection::iterator tmp = r;
4907                 ++tmp;
4908
4909                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*>(*r);
4910
4911                 if (mrv) {
4912                         try {
4913                                 boost::shared_ptr<Playlist> playlist = mrv->region()->playlist();
4914                                 boost::shared_ptr<MidiSource> new_source = _session->create_midi_source_by_stealing_name (mrv->midi_view()->track());
4915                                 boost::shared_ptr<MidiRegion> newregion = mrv->midi_region()->clone (new_source);
4916                                 
4917                                 playlist->clear_changes ();
4918                                 playlist->replace_region (mrv->region(), newregion, mrv->region()->position());
4919                                 _session->add_command(new StatefulDiffCommand (playlist));
4920                         } catch (...) {
4921                                 error << string_compose (_("Could not unlink %1"), mrv->region()->name()) << endmsg;
4922                         }
4923                 }
4924
4925                 r = tmp;
4926         }
4927
4928         commit_reversible_command ();
4929
4930         set_canvas_cursor (current_canvas_cursor);
4931 }
4932
4933 void
4934 Editor::quantize_region ()
4935 {
4936         int selected_midi_region_cnt = 0;
4937
4938         if (!_session) {
4939                 return;
4940         }
4941
4942         RegionSelection rs = get_regions_from_selection_and_entered ();
4943
4944         if (rs.empty()) {
4945                 return;
4946         }
4947
4948         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
4949                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*r);
4950                 if (mrv) {
4951                         selected_midi_region_cnt++;
4952                 }
4953         }
4954
4955         if (selected_midi_region_cnt == 0) {
4956                 return;
4957         }
4958
4959         QuantizeDialog* qd = new QuantizeDialog (*this);
4960
4961         qd->present ();
4962         const int r = qd->run ();
4963         qd->hide ();
4964
4965         if (r == Gtk::RESPONSE_OK) {
4966                 Quantize quant (*_session, qd->snap_start(), qd->snap_end(),
4967                                 qd->start_grid_size(), qd->end_grid_size(),
4968                                 qd->strength(), qd->swing(), qd->threshold());
4969
4970                 apply_midi_note_edit_op (quant);
4971         }
4972 }
4973
4974 void
4975 Editor::insert_patch_change (bool from_context)
4976 {
4977         RegionSelection rs = get_regions_from_selection_and_entered ();
4978
4979         if (rs.empty ()) {
4980                 return;
4981         }
4982
4983         const framepos_t p = get_preferred_edit_position (false, from_context);
4984
4985         /* XXX: bit of a hack; use the MIDNAM from the first selected region;
4986            there may be more than one, but the PatchChangeDialog can only offer
4987            one set of patch menus.
4988         */
4989         MidiRegionView* first = dynamic_cast<MidiRegionView*> (rs.front ());
4990
4991         Evoral::PatchChange<Evoral::MusicalTime> empty (0, 0, 0, 0);
4992         PatchChangeDialog d (0, _session, empty, first->instrument_info(), Gtk::Stock::ADD);
4993
4994         if (d.run() == RESPONSE_CANCEL) {
4995                 return;
4996         }
4997
4998         for (RegionSelection::iterator i = rs.begin (); i != rs.end(); ++i) {
4999                 MidiRegionView* const mrv = dynamic_cast<MidiRegionView*> (*i);
5000                 if (mrv) {
5001                         if (p >= mrv->region()->first_frame() && p <= mrv->region()->last_frame()) {
5002                                 mrv->add_patch_change (p - mrv->region()->position(), d.patch ());
5003                         }
5004                 }
5005         }
5006 }
5007
5008 void
5009 Editor::apply_filter (Filter& filter, string command, ProgressReporter* progress)
5010 {
5011         RegionSelection rs = get_regions_from_selection_and_entered ();
5012
5013         if (rs.empty()) {
5014                 return;
5015         }
5016
5017         begin_reversible_command (command);
5018
5019         set_canvas_cursor (_cursors->wait);
5020         gdk_flush ();
5021
5022         int n = 0;
5023         int const N = rs.size ();
5024
5025         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ) {
5026                 RegionSelection::iterator tmp = r;
5027                 ++tmp;
5028
5029                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*r);
5030                 if (arv) {
5031                         boost::shared_ptr<Playlist> playlist = arv->region()->playlist();
5032
5033                         if (progress) {
5034                                 progress->descend (1.0 / N);
5035                         }
5036
5037                         if (arv->audio_region()->apply (filter, progress) == 0) {
5038
5039                                 playlist->clear_changes ();
5040                                 playlist->clear_owned_changes ();
5041
5042                                 if (filter.results.empty ()) {
5043
5044                                         /* no regions returned; remove the old one */
5045                                         playlist->remove_region (arv->region ());
5046
5047                                 } else {
5048
5049                                         std::vector<boost::shared_ptr<Region> >::iterator res = filter.results.begin ();
5050
5051                                         /* first region replaces the old one */
5052                                         playlist->replace_region (arv->region(), *res, (*res)->position());
5053                                         ++res;
5054
5055                                         /* add the rest */
5056                                         while (res != filter.results.end()) {
5057                                                 playlist->add_region (*res, (*res)->position());
5058                                                 ++res;
5059                                         }
5060
5061                                 }
5062
5063                                 /* We might have removed regions, which alters other regions' layering_index,
5064                                    so we need to do a recursive diff here.
5065                                 */
5066                                 vector<Command*> cmds;
5067                                 playlist->rdiff (cmds);
5068                                 _session->add_commands (cmds);
5069                                 
5070                                 _session->add_command(new StatefulDiffCommand (playlist));
5071                         } else {
5072                                 goto out;
5073                         }
5074
5075                         if (progress) {
5076                                 progress->ascend ();
5077                         }
5078                 }
5079
5080                 r = tmp;
5081                 ++n;
5082         }
5083
5084         commit_reversible_command ();
5085
5086   out:
5087         set_canvas_cursor (current_canvas_cursor);
5088 }
5089
5090 void
5091 Editor::external_edit_region ()
5092 {
5093         /* more to come */
5094 }
5095
5096 void
5097 Editor::reset_region_gain_envelopes ()
5098 {
5099         RegionSelection rs = get_regions_from_selection_and_entered ();
5100
5101         if (!_session || rs.empty()) {
5102                 return;
5103         }
5104
5105         _session->begin_reversible_command (_("reset region gain"));
5106
5107         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5108                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5109                 if (arv) {
5110                         boost::shared_ptr<AutomationList> alist (arv->audio_region()->envelope());
5111                         XMLNode& before (alist->get_state());
5112
5113                         arv->audio_region()->set_default_envelope ();
5114                         _session->add_command (new MementoCommand<AutomationList>(*arv->audio_region()->envelope().get(), &before, &alist->get_state()));
5115                 }
5116         }
5117
5118         _session->commit_reversible_command ();
5119 }
5120
5121 void
5122 Editor::set_region_gain_visibility (RegionView* rv)
5123 {
5124         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (rv);
5125         if (arv) {
5126                 arv->update_envelope_visibility();
5127         }
5128 }
5129
5130 void
5131 Editor::set_gain_envelope_visibility ()
5132 {
5133         if (!_session) {
5134                 return;
5135         }
5136
5137         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5138                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5139                 if (v) {
5140                         v->audio_view()->foreach_regionview (sigc::mem_fun (this, &Editor::set_region_gain_visibility));
5141                 }
5142         }
5143 }
5144
5145 void
5146 Editor::toggle_gain_envelope_active ()
5147 {
5148         if (_ignore_region_action) {
5149                 return;
5150         }
5151
5152         RegionSelection rs = get_regions_from_selection_and_entered ();
5153
5154         if (!_session || rs.empty()) {
5155                 return;
5156         }
5157
5158         _session->begin_reversible_command (_("region gain envelope active"));
5159
5160         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5161                 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
5162                 if (arv) {
5163                         arv->region()->clear_changes ();
5164                         arv->audio_region()->set_envelope_active (!arv->audio_region()->envelope_active());
5165                         _session->add_command (new StatefulDiffCommand (arv->region()));
5166                 }
5167         }
5168
5169         _session->commit_reversible_command ();
5170 }
5171
5172 void
5173 Editor::toggle_region_lock ()
5174 {
5175         if (_ignore_region_action) {
5176                 return;
5177         }
5178
5179         RegionSelection rs = get_regions_from_selection_and_entered ();
5180
5181         if (!_session || rs.empty()) {
5182                 return;
5183         }
5184
5185         _session->begin_reversible_command (_("toggle region lock"));
5186
5187         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5188                 (*i)->region()->clear_changes ();
5189                 (*i)->region()->set_locked (!(*i)->region()->locked());
5190                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5191         }
5192
5193         _session->commit_reversible_command ();
5194 }
5195
5196 void
5197 Editor::toggle_region_video_lock ()
5198 {
5199         if (_ignore_region_action) {
5200                 return;
5201         }
5202
5203         RegionSelection rs = get_regions_from_selection_and_entered ();
5204
5205         if (!_session || rs.empty()) {
5206                 return;
5207         }
5208
5209         _session->begin_reversible_command (_("Toggle Video Lock"));
5210
5211         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5212                 (*i)->region()->clear_changes ();
5213                 (*i)->region()->set_video_locked (!(*i)->region()->video_locked());
5214                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5215         }
5216
5217         _session->commit_reversible_command ();
5218 }
5219
5220 void
5221 Editor::toggle_region_lock_style ()
5222 {
5223         if (_ignore_region_action) {
5224                 return;
5225         }
5226
5227         RegionSelection rs = get_regions_from_selection_and_entered ();
5228
5229         if (!_session || rs.empty()) {
5230                 return;
5231         }
5232
5233         _session->begin_reversible_command (_("region lock style"));
5234
5235         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5236                 (*i)->region()->clear_changes ();
5237                 PositionLockStyle const ns = (*i)->region()->position_lock_style() == AudioTime ? MusicTime : AudioTime;
5238                 (*i)->region()->set_position_lock_style (ns);
5239                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5240         }
5241
5242         _session->commit_reversible_command ();
5243 }
5244
5245 void
5246 Editor::toggle_opaque_region ()
5247 {
5248         if (_ignore_region_action) {
5249                 return;
5250         }
5251
5252         RegionSelection rs = get_regions_from_selection_and_entered ();
5253
5254         if (!_session || rs.empty()) {
5255                 return;
5256         }
5257
5258         _session->begin_reversible_command (_("change region opacity"));
5259
5260         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5261                 (*i)->region()->clear_changes ();
5262                 (*i)->region()->set_opaque (!(*i)->region()->opaque());
5263                 _session->add_command (new StatefulDiffCommand ((*i)->region()));
5264         }
5265
5266         _session->commit_reversible_command ();
5267 }
5268
5269 void
5270 Editor::toggle_record_enable ()
5271 {
5272         bool new_state = false;
5273         bool first = true;
5274         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5275                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5276                 if (!rtav)
5277                         continue;
5278                 if (!rtav->is_track())
5279                         continue;
5280
5281                 if (first) {
5282                         new_state = !rtav->track()->record_enabled();
5283                         first = false;
5284                 }
5285
5286                 rtav->track()->set_record_enabled (new_state, this);
5287         }
5288 }
5289
5290 void
5291 Editor::toggle_solo ()
5292 {
5293         bool new_state = false;
5294         bool first = true;
5295         boost::shared_ptr<RouteList> rl (new RouteList);
5296
5297         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5298                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5299
5300                 if (!rtav) {
5301                         continue;
5302                 }
5303
5304                 if (first) {
5305                         new_state = !rtav->route()->soloed ();
5306                         first = false;
5307                 }
5308
5309                 rl->push_back (rtav->route());
5310         }
5311
5312         _session->set_solo (rl, new_state, Session::rt_cleanup, true);
5313 }
5314
5315 void
5316 Editor::toggle_mute ()
5317 {
5318         bool new_state = false;
5319         bool first = true;
5320         boost::shared_ptr<RouteList> rl (new RouteList);
5321
5322         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
5323                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
5324
5325                 if (!rtav) {
5326                         continue;
5327                 }
5328
5329                 if (first) {
5330                         new_state = !rtav->route()->muted();
5331                         first = false;
5332                 }
5333
5334                 rl->push_back (rtav->route());
5335         }
5336
5337         _session->set_mute (rl, new_state, Session::rt_cleanup, true);
5338 }
5339
5340 void
5341 Editor::toggle_solo_isolate ()
5342 {
5343 }
5344
5345
5346 void
5347 Editor::fade_range ()
5348 {
5349         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
5350
5351         begin_reversible_command (_("fade range"));
5352
5353         for (TrackViewList::iterator i = ts.begin(); i != ts.end(); ++i) {
5354                 (*i)->fade_range (selection->time);
5355         }
5356
5357         commit_reversible_command ();
5358 }
5359
5360
5361 void
5362 Editor::set_fade_length (bool in)
5363 {
5364         RegionSelection rs = get_regions_from_selection_and_entered ();
5365
5366         if (rs.empty()) {
5367                 return;
5368         }
5369
5370         /* we need a region to measure the offset from the start */
5371
5372         RegionView* rv = rs.front ();
5373
5374         framepos_t pos = get_preferred_edit_position();
5375         framepos_t len;
5376         char const * cmd;
5377
5378         if (pos > rv->region()->last_frame() || pos < rv->region()->first_frame()) {
5379                 /* edit point is outside the relevant region */
5380                 return;
5381         }
5382
5383         if (in) {
5384                 if (pos <= rv->region()->position()) {
5385                         /* can't do it */
5386                         return;
5387                 }
5388                 len = pos - rv->region()->position();
5389                 cmd = _("set fade in length");
5390         } else {
5391                 if (pos >= rv->region()->last_frame()) {
5392                         /* can't do it */
5393                         return;
5394                 }
5395                 len = rv->region()->last_frame() - pos;
5396                 cmd = _("set fade out length");
5397         }
5398
5399         begin_reversible_command (cmd);
5400
5401         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5402                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5403
5404                 if (!tmp) {
5405                         return;
5406                 }
5407
5408                 boost::shared_ptr<AutomationList> alist;
5409                 if (in) {
5410                         alist = tmp->audio_region()->fade_in();
5411                 } else {
5412                         alist = tmp->audio_region()->fade_out();
5413                 }
5414
5415                 XMLNode &before = alist->get_state();
5416
5417                 if (in) {
5418                         tmp->audio_region()->set_fade_in_length (len);
5419                         tmp->audio_region()->set_fade_in_active (true);
5420                 } else {
5421                         tmp->audio_region()->set_fade_out_length (len);
5422                         tmp->audio_region()->set_fade_out_active (true);
5423                 }
5424
5425                 XMLNode &after = alist->get_state();
5426                 _session->add_command(new MementoCommand<AutomationList>(*alist, &before, &after));
5427         }
5428
5429         commit_reversible_command ();
5430 }
5431
5432 void
5433 Editor::set_fade_in_shape (FadeShape shape)
5434 {
5435         RegionSelection rs = get_regions_from_selection_and_entered ();
5436
5437         if (rs.empty()) {
5438                 return;
5439         }
5440
5441         begin_reversible_command (_("set fade in shape"));
5442
5443         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5444                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5445
5446                 if (!tmp) {
5447                         return;
5448                 }
5449
5450                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
5451                 XMLNode &before = alist->get_state();
5452
5453                 tmp->audio_region()->set_fade_in_shape (shape);
5454
5455                 XMLNode &after = alist->get_state();
5456                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5457         }
5458
5459         commit_reversible_command ();
5460
5461 }
5462
5463 void
5464 Editor::set_fade_out_shape (FadeShape shape)
5465 {
5466         RegionSelection rs = get_regions_from_selection_and_entered ();
5467
5468         if (rs.empty()) {
5469                 return;
5470         }
5471
5472         begin_reversible_command (_("set fade out shape"));
5473
5474         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5475                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5476
5477                 if (!tmp) {
5478                         return;
5479                 }
5480
5481                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
5482                 XMLNode &before = alist->get_state();
5483
5484                 tmp->audio_region()->set_fade_out_shape (shape);
5485
5486                 XMLNode &after = alist->get_state();
5487                 _session->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
5488         }
5489
5490         commit_reversible_command ();
5491 }
5492
5493 void
5494 Editor::set_fade_in_active (bool yn)
5495 {
5496         RegionSelection rs = get_regions_from_selection_and_entered ();
5497
5498         if (rs.empty()) {
5499                 return;
5500         }
5501
5502         begin_reversible_command (_("set fade in active"));
5503
5504         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5505                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5506
5507                 if (!tmp) {
5508                         return;
5509                 }
5510
5511
5512                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5513
5514                 ar->clear_changes ();
5515                 ar->set_fade_in_active (yn);
5516                 _session->add_command (new StatefulDiffCommand (ar));
5517         }
5518
5519         commit_reversible_command ();
5520 }
5521
5522 void
5523 Editor::set_fade_out_active (bool yn)
5524 {
5525         RegionSelection rs = get_regions_from_selection_and_entered ();
5526
5527         if (rs.empty()) {
5528                 return;
5529         }
5530
5531         begin_reversible_command (_("set fade out active"));
5532
5533         for (RegionSelection::iterator x = rs.begin(); x != rs.end(); ++x) {
5534                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*x);
5535
5536                 if (!tmp) {
5537                         return;
5538                 }
5539
5540                 boost::shared_ptr<AudioRegion> ar (tmp->audio_region());
5541
5542                 ar->clear_changes ();
5543                 ar->set_fade_out_active (yn);
5544                 _session->add_command(new StatefulDiffCommand (ar));
5545         }
5546
5547         commit_reversible_command ();
5548 }
5549
5550 void
5551 Editor::toggle_region_fades (int dir)
5552 {
5553         if (_ignore_region_action) {
5554                 return;
5555         }
5556         
5557         boost::shared_ptr<AudioRegion> ar;
5558         bool yn = false;
5559
5560         RegionSelection rs = get_regions_from_selection_and_entered ();
5561
5562         if (rs.empty()) {
5563                 return;
5564         }
5565
5566         RegionSelection::iterator i;
5567         for (i = rs.begin(); i != rs.end(); ++i) {
5568                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) != 0) {
5569                         if (dir == -1) {
5570                                 yn = ar->fade_out_active ();
5571                         } else {
5572                                 yn = ar->fade_in_active ();
5573                         }
5574                         break;
5575                 }
5576         }
5577
5578         if (i == rs.end()) {
5579                 return;
5580         }
5581
5582         /* XXX should this undo-able? */
5583
5584         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5585                 if ((ar = boost::dynamic_pointer_cast<AudioRegion>((*i)->region())) == 0) {
5586                         continue;
5587                 }
5588                 if (dir == 1 || dir == 0) {
5589                         ar->set_fade_in_active (!yn);
5590                 }
5591
5592                 if (dir == -1 || dir == 0) {
5593                         ar->set_fade_out_active (!yn);
5594                 }
5595         }
5596 }
5597
5598
5599 /** Update region fade visibility after its configuration has been changed */
5600 void
5601 Editor::update_region_fade_visibility ()
5602 {
5603         bool _fade_visibility = _session->config.get_show_region_fades ();
5604
5605         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5606                 AudioTimeAxisView* v = dynamic_cast<AudioTimeAxisView*>(*i);
5607                 if (v) {
5608                         if (_fade_visibility) {
5609                                 v->audio_view()->show_all_fades ();
5610                         } else {
5611                                 v->audio_view()->hide_all_fades ();
5612                         }
5613                 }
5614         }
5615 }
5616
5617 void
5618 Editor::set_edit_point ()
5619 {
5620         framepos_t where;
5621         bool ignored;
5622
5623         if (!mouse_frame (where, ignored)) {
5624                 return;
5625         }
5626
5627         snap_to (where);
5628
5629         if (selection->markers.empty()) {
5630
5631                 mouse_add_new_marker (where);
5632
5633         } else {
5634                 bool ignored;
5635
5636                 Location* loc = find_location_from_marker (selection->markers.front(), ignored);
5637
5638                 if (loc) {
5639                         loc->move_to (where);
5640                 }
5641         }
5642 }
5643
5644 void
5645 Editor::set_playhead_cursor ()
5646 {
5647         if (entered_marker) {
5648                 _session->request_locate (entered_marker->position(), _session->transport_rolling());
5649         } else {
5650                 framepos_t where;
5651                 bool ignored;
5652
5653                 if (!mouse_frame (where, ignored)) {
5654                         return;
5655                 }
5656
5657                 snap_to (where);
5658
5659                 if (_session) {
5660                         _session->request_locate (where, _session->transport_rolling());
5661                 }
5662         }
5663
5664         if ( Config->get_follow_edits() )
5665                 cancel_time_selection();
5666 }
5667
5668 void
5669 Editor::split_region ()
5670 {
5671         if ( !selection->time.empty()) {
5672                 separate_regions_between (selection->time);
5673                 return;
5674         }
5675
5676         RegionSelection rs = get_regions_from_selection_and_edit_point ();
5677
5678         framepos_t where = get_preferred_edit_position ();
5679
5680         if (rs.empty()) {
5681                 return;
5682         }
5683
5684         split_regions_at (where, rs);
5685 }
5686
5687 struct EditorOrderRouteSorter {
5688     bool operator() (boost::shared_ptr<Route> a, boost::shared_ptr<Route> b) {
5689             return a->order_key () < b->order_key ();
5690     }
5691 };
5692
5693 void
5694 Editor::select_next_route()
5695 {
5696         if (selection->tracks.empty()) {
5697                 selection->set (track_views.front());
5698                 return;
5699         }
5700
5701         TimeAxisView* current = selection->tracks.front();
5702
5703         RouteUI *rui;
5704         do {
5705                 for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
5706                         if (*i == current) {
5707                                 ++i;
5708                                 if (i != track_views.end()) {
5709                                         current = (*i);
5710                                 } else {
5711                                         current = (*(track_views.begin()));
5712                                         //selection->set (*(track_views.begin()));
5713                                 }
5714                                 break;
5715                         }
5716                 }
5717                 rui = dynamic_cast<RouteUI *>(current);
5718         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5719
5720         selection->set(current);
5721
5722         ensure_time_axis_view_is_visible (*current, false);
5723 }
5724
5725 void
5726 Editor::select_prev_route()
5727 {
5728         if (selection->tracks.empty()) {
5729                 selection->set (track_views.front());
5730                 return;
5731         }
5732
5733         TimeAxisView* current = selection->tracks.front();
5734
5735         RouteUI *rui;
5736         do {
5737                 for (TrackViewList::reverse_iterator i = track_views.rbegin(); i != track_views.rend(); ++i) {
5738                         if (*i == current) {
5739                                 ++i;
5740                                 if (i != track_views.rend()) {
5741                                         current = (*i);
5742                                 } else {
5743                                         current = *(track_views.rbegin());
5744                                 }
5745                                 break;
5746                         }
5747                 }
5748                 rui = dynamic_cast<RouteUI *>(current);
5749         } while ( current->hidden() || (rui != NULL && !rui->route()->active()));
5750
5751         selection->set (current);
5752
5753         ensure_time_axis_view_is_visible (*current, false);
5754 }
5755
5756 void
5757 Editor::set_loop_from_selection (bool play)
5758 {
5759         if (_session == 0 || selection->time.empty()) {
5760                 return;
5761         }
5762
5763         framepos_t start = selection->time[clicked_selection].start;
5764         framepos_t end = selection->time[clicked_selection].end;
5765
5766         set_loop_range (start, end,  _("set loop range from selection"));
5767
5768         if (play) {
5769                 _session->request_locate (start, true);
5770                 _session->request_play_loop (true);
5771         }
5772 }
5773
5774 void
5775 Editor::set_loop_from_edit_range (bool play)
5776 {
5777         if (_session == 0) {
5778                 return;
5779         }
5780
5781         framepos_t start;
5782         framepos_t end;
5783
5784         if (!get_edit_op_range (start, end)) {
5785                 return;
5786         }
5787
5788         set_loop_range (start, end,  _("set loop range from edit range"));
5789
5790         if (play) {
5791                 _session->request_locate (start, true);
5792                 _session->request_play_loop (true);
5793         }
5794 }
5795
5796 void
5797 Editor::set_loop_from_region (bool play)
5798 {
5799         framepos_t start = max_framepos;
5800         framepos_t end = 0;
5801
5802         RegionSelection rs = get_regions_from_selection_and_entered ();
5803
5804         if (rs.empty()) {
5805                 return;
5806         }
5807
5808         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5809                 if ((*i)->region()->position() < start) {
5810                         start = (*i)->region()->position();
5811                 }
5812                 if ((*i)->region()->last_frame() + 1 > end) {
5813                         end = (*i)->region()->last_frame() + 1;
5814                 }
5815         }
5816
5817         set_loop_range (start, end, _("set loop range from region"));
5818
5819         if (play) {
5820                 _session->request_locate (start, true);
5821                 _session->request_play_loop (true);
5822         }
5823 }
5824
5825 void
5826 Editor::set_punch_from_selection ()
5827 {
5828         if (_session == 0 || selection->time.empty()) {
5829                 return;
5830         }
5831
5832         framepos_t start = selection->time[clicked_selection].start;
5833         framepos_t end = selection->time[clicked_selection].end;
5834
5835         set_punch_range (start, end,  _("set punch range from selection"));
5836 }
5837
5838 void
5839 Editor::set_punch_from_edit_range ()
5840 {
5841         if (_session == 0) {
5842                 return;
5843         }
5844
5845         framepos_t start;
5846         framepos_t end;
5847
5848         if (!get_edit_op_range (start, end)) {
5849                 return;
5850         }
5851
5852         set_punch_range (start, end,  _("set punch range from edit range"));
5853 }
5854
5855 void
5856 Editor::set_punch_from_region ()
5857 {
5858         framepos_t start = max_framepos;
5859         framepos_t end = 0;
5860
5861         RegionSelection rs = get_regions_from_selection_and_entered ();
5862
5863         if (rs.empty()) {
5864                 return;
5865         }
5866
5867         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5868                 if ((*i)->region()->position() < start) {
5869                         start = (*i)->region()->position();
5870                 }
5871                 if ((*i)->region()->last_frame() + 1 > end) {
5872                         end = (*i)->region()->last_frame() + 1;
5873                 }
5874         }
5875
5876         set_punch_range (start, end, _("set punch range from region"));
5877 }
5878
5879 void
5880 Editor::pitch_shift_region ()
5881 {
5882         RegionSelection rs = get_regions_from_selection_and_entered ();
5883
5884         RegionSelection audio_rs;
5885         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5886                 if (dynamic_cast<AudioRegionView*> (*i)) {
5887                         audio_rs.push_back (*i);
5888                 }
5889         }
5890
5891         if (audio_rs.empty()) {
5892                 return;
5893         }
5894
5895         pitch_shift (audio_rs, 1.2);
5896 }
5897
5898 void
5899 Editor::transpose_region ()
5900 {
5901         RegionSelection rs = get_regions_from_selection_and_entered ();
5902
5903         list<MidiRegionView*> midi_region_views;
5904         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
5905                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (*i);
5906                 if (mrv) {
5907                         midi_region_views.push_back (mrv);
5908                 }
5909         }
5910
5911         TransposeDialog d;
5912         int const r = d.run ();
5913         if (r != RESPONSE_ACCEPT) {
5914                 return;
5915         }
5916
5917         for (list<MidiRegionView*>::iterator i = midi_region_views.begin(); i != midi_region_views.end(); ++i) {
5918                 (*i)->midi_region()->transpose (d.semitones ());
5919         }
5920 }
5921
5922 void
5923 Editor::set_tempo_from_region ()
5924 {
5925         RegionSelection rs = get_regions_from_selection_and_entered ();
5926
5927         if (!_session || rs.empty()) {
5928                 return;
5929         }
5930
5931         RegionView* rv = rs.front();
5932
5933         define_one_bar (rv->region()->position(), rv->region()->last_frame() + 1);
5934 }
5935
5936 void
5937 Editor::use_range_as_bar ()
5938 {
5939         framepos_t start, end;
5940         if (get_edit_op_range (start, end)) {
5941                 define_one_bar (start, end);
5942         }
5943 }
5944
5945 void
5946 Editor::define_one_bar (framepos_t start, framepos_t end)
5947 {
5948         framepos_t length = end - start;
5949
5950         const Meter& m (_session->tempo_map().meter_at (start));
5951
5952         /* length = 1 bar */
5953
5954         /* now we want frames per beat.
5955            we have frames per bar, and beats per bar, so ...
5956         */
5957
5958         /* XXXX METER MATH */
5959
5960         double frames_per_beat = length / m.divisions_per_bar();
5961
5962         /* beats per minute = */
5963
5964         double beats_per_minute = (_session->frame_rate() * 60.0) / frames_per_beat;
5965
5966         /* now decide whether to:
5967
5968             (a) set global tempo
5969             (b) add a new tempo marker
5970
5971         */
5972
5973         const TempoSection& t (_session->tempo_map().tempo_section_at (start));
5974
5975         bool do_global = false;
5976
5977         if ((_session->tempo_map().n_tempos() == 1) && (_session->tempo_map().n_meters() == 1)) {
5978
5979                 /* only 1 tempo & 1 meter: ask if the user wants to set the tempo
5980                    at the start, or create a new marker
5981                 */
5982
5983                 vector<string> options;
5984                 options.push_back (_("Cancel"));
5985                 options.push_back (_("Add new marker"));
5986                 options.push_back (_("Set global tempo"));
5987
5988                 Choice c (
5989                         _("Define one bar"),
5990                         _("Do you want to set the global tempo or add a new tempo marker?"),
5991                         options
5992                         );
5993
5994                 c.set_default_response (2);
5995
5996                 switch (c.run()) {
5997                 case 0:
5998                         return;
5999
6000                 case 2:
6001                         do_global = true;
6002                         break;
6003
6004                 default:
6005                         do_global = false;
6006                 }
6007
6008         } else {
6009
6010                 /* more than 1 tempo and/or meter section already, go ahead do the "usual":
6011                    if the marker is at the region starter, change it, otherwise add
6012                    a new tempo marker
6013                 */
6014         }
6015
6016         begin_reversible_command (_("set tempo from region"));
6017         XMLNode& before (_session->tempo_map().get_state());
6018
6019         if (do_global) {
6020                 _session->tempo_map().change_initial_tempo (beats_per_minute, t.note_type());
6021         } else if (t.frame() == start) {
6022                 _session->tempo_map().change_existing_tempo_at (start, beats_per_minute, t.note_type());
6023         } else {
6024                 Timecode::BBT_Time bbt;
6025                 _session->tempo_map().bbt_time (start, bbt);
6026                 _session->tempo_map().add_tempo (Tempo (beats_per_minute, t.note_type()), bbt);
6027         }
6028
6029         XMLNode& after (_session->tempo_map().get_state());
6030
6031         _session->add_command (new MementoCommand<TempoMap>(_session->tempo_map(), &before, &after));
6032         commit_reversible_command ();
6033 }
6034
6035 void
6036 Editor::split_region_at_transients ()
6037 {
6038         AnalysisFeatureList positions;
6039
6040         RegionSelection rs = get_regions_from_selection_and_entered ();
6041
6042         if (!_session || rs.empty()) {
6043                 return;
6044         }
6045
6046         _session->begin_reversible_command (_("split regions"));
6047
6048         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ) {
6049
6050                 RegionSelection::iterator tmp;
6051
6052                 tmp = i;
6053                 ++tmp;
6054
6055                 boost::shared_ptr<AudioRegion> ar = boost::dynamic_pointer_cast<AudioRegion> ((*i)->region());
6056
6057                 if (ar && (ar->get_transients (positions) == 0)) {
6058                         split_region_at_points ((*i)->region(), positions, true);
6059                         positions.clear ();
6060                 }
6061
6062                 i = tmp;
6063         }
6064
6065         _session->commit_reversible_command ();
6066
6067 }
6068
6069 void
6070 Editor::split_region_at_points (boost::shared_ptr<Region> r, AnalysisFeatureList& positions, bool can_ferret, bool select_new)
6071 {
6072         bool use_rhythmic_rodent = false;
6073
6074         boost::shared_ptr<Playlist> pl = r->playlist();
6075
6076         list<boost::shared_ptr<Region> > new_regions;
6077
6078         if (!pl) {
6079                 return;
6080         }
6081
6082         if (positions.empty()) {
6083                 return;
6084         }
6085
6086
6087         if (positions.size() > 20 && can_ferret) {
6088                 std::string msgstr = string_compose (_("You are about to split\n%1\ninto %2 pieces.\nThis could take a long time."), r->name(), positions.size() + 1);
6089                 MessageDialog msg (msgstr,
6090                                    false,
6091                                    Gtk::MESSAGE_INFO,
6092                                    Gtk::BUTTONS_OK_CANCEL);
6093
6094                 if (can_ferret) {
6095                         msg.add_button (_("Call for the Ferret!"), RESPONSE_APPLY);
6096                         msg.set_secondary_text (_("Press OK to continue with this split operation\nor ask the Ferret dialog to tune the analysis"));
6097                 } else {
6098                         msg.set_secondary_text (_("Press OK to continue with this split operation"));
6099                 }
6100
6101                 msg.set_title (_("Excessive split?"));
6102                 msg.present ();
6103
6104                 int response = msg.run();
6105                 msg.hide ();
6106
6107                 switch (response) {
6108                 case RESPONSE_OK:
6109                         break;
6110                 case RESPONSE_APPLY:
6111                         use_rhythmic_rodent = true;
6112                         break;
6113                 default:
6114                         return;
6115                 }
6116         }
6117
6118         if (use_rhythmic_rodent) {
6119                 show_rhythm_ferret ();
6120                 return;
6121         }
6122
6123         AnalysisFeatureList::const_iterator x;
6124
6125         pl->clear_changes ();
6126         pl->clear_owned_changes ();
6127
6128         x = positions.begin();
6129
6130         if (x == positions.end()) {
6131                 return;
6132         }
6133
6134         pl->freeze ();
6135         pl->remove_region (r);
6136
6137         framepos_t pos = 0;
6138
6139         while (x != positions.end()) {
6140
6141                 /* deal with positons that are out of scope of present region bounds */
6142                 if (*x <= 0 || *x > r->length()) {
6143                         ++x;
6144                         continue;
6145                 }
6146
6147                 /* file start = original start + how far we from the initial position ?
6148                  */
6149
6150                 framepos_t file_start = r->start() + pos;
6151
6152                 /* length = next position - current position
6153                  */
6154
6155                 framepos_t len = (*x) - pos;
6156
6157                 /* XXX we do we really want to allow even single-sample regions?
6158                    shouldn't we have some kind of lower limit on region size?
6159                 */
6160
6161                 if (len <= 0) {
6162                         break;
6163                 }
6164
6165                 string new_name;
6166
6167                 if (RegionFactory::region_name (new_name, r->name())) {
6168                         break;
6169                 }
6170
6171                 /* do NOT announce new regions 1 by one, just wait till they are all done */
6172
6173                 PropertyList plist;
6174
6175                 plist.add (ARDOUR::Properties::start, file_start);
6176                 plist.add (ARDOUR::Properties::length, len);
6177                 plist.add (ARDOUR::Properties::name, new_name);
6178                 plist.add (ARDOUR::Properties::layer, 0);
6179
6180                 boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6181                 /* because we set annouce to false, manually add the new region to the
6182                    RegionFactory map
6183                 */
6184                 RegionFactory::map_add (nr);
6185
6186                 pl->add_region (nr, r->position() + pos);
6187
6188                 if (select_new) {
6189                         new_regions.push_front(nr);
6190                 }
6191
6192                 pos += len;
6193                 ++x;
6194         }
6195
6196         string new_name;
6197
6198         RegionFactory::region_name (new_name, r->name());
6199
6200         /* Add the final region */
6201         PropertyList plist;
6202
6203         plist.add (ARDOUR::Properties::start, r->start() + pos);
6204         plist.add (ARDOUR::Properties::length, r->last_frame() - (r->position() + pos) + 1);
6205         plist.add (ARDOUR::Properties::name, new_name);
6206         plist.add (ARDOUR::Properties::layer, 0);
6207
6208         boost::shared_ptr<Region> nr = RegionFactory::create (r->sources(), plist, false);
6209         /* because we set annouce to false, manually add the new region to the
6210            RegionFactory map
6211         */
6212         RegionFactory::map_add (nr);
6213         pl->add_region (nr, r->position() + pos);
6214
6215         if (select_new) {
6216                 new_regions.push_front(nr);
6217         }
6218
6219         pl->thaw ();
6220
6221         /* We might have removed regions, which alters other regions' layering_index,
6222            so we need to do a recursive diff here.
6223         */
6224         vector<Command*> cmds;
6225         pl->rdiff (cmds);
6226         _session->add_commands (cmds);
6227         
6228         _session->add_command (new StatefulDiffCommand (pl));
6229
6230         if (select_new) {
6231
6232                 for (list<boost::shared_ptr<Region> >::iterator i = new_regions.begin(); i != new_regions.end(); ++i){
6233                         set_selected_regionview_from_region_list ((*i), Selection::Add);
6234                 }
6235         }
6236 }
6237
6238 void
6239 Editor::place_transient()
6240 {
6241         if (!_session) {
6242                 return;
6243         }
6244
6245         RegionSelection rs = get_regions_from_selection_and_edit_point ();
6246
6247         if (rs.empty()) {
6248                 return;
6249         }
6250
6251         framepos_t where = get_preferred_edit_position();
6252
6253         _session->begin_reversible_command (_("place transient"));
6254
6255         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6256                 framepos_t position = (*r)->region()->position();
6257                 (*r)->region()->add_transient(where - position);
6258         }
6259
6260         _session->commit_reversible_command ();
6261 }
6262
6263 void
6264 Editor::remove_transient(ArdourCanvas::Item* item)
6265 {
6266         if (!_session) {
6267                 return;
6268         }
6269
6270         ArdourCanvas::Line* _line = reinterpret_cast<ArdourCanvas::Line*> (item);
6271         assert (_line);
6272
6273         AudioRegionView* _arv = reinterpret_cast<AudioRegionView*> (item->get_data ("regionview"));
6274         _arv->remove_transient (*(float*) _line->get_data ("position"));
6275 }
6276
6277 void
6278 Editor::snap_regions_to_grid ()
6279 {
6280         list <boost::shared_ptr<Playlist > > used_playlists;
6281
6282         RegionSelection rs = get_regions_from_selection_and_entered ();
6283
6284         if (!_session || rs.empty()) {
6285                 return;
6286         }
6287
6288         _session->begin_reversible_command (_("snap regions to grid"));
6289
6290         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6291
6292                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6293
6294                 if (!pl->frozen()) {
6295                         /* we haven't seen this playlist before */
6296
6297                         /* remember used playlists so we can thaw them later */
6298                         used_playlists.push_back(pl);
6299                         pl->freeze();
6300                 }
6301
6302                 framepos_t start_frame = (*r)->region()->first_frame ();
6303                 snap_to (start_frame);
6304                 (*r)->region()->set_position (start_frame);
6305         }
6306
6307         while (used_playlists.size() > 0) {
6308                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6309                 (*i)->thaw();
6310                 used_playlists.pop_front();
6311         }
6312
6313         _session->commit_reversible_command ();
6314 }
6315
6316 void
6317 Editor::close_region_gaps ()
6318 {
6319         list <boost::shared_ptr<Playlist > > used_playlists;
6320
6321         RegionSelection rs = get_regions_from_selection_and_entered ();
6322
6323         if (!_session || rs.empty()) {
6324                 return;
6325         }
6326
6327         Dialog dialog (_("Close Region Gaps"));
6328
6329         Table table (2, 3);
6330         table.set_spacings (12);
6331         table.set_border_width (12);
6332         Label* l = manage (left_aligned_label (_("Crossfade length")));
6333         table.attach (*l, 0, 1, 0, 1);
6334
6335         SpinButton spin_crossfade (1, 0);
6336         spin_crossfade.set_range (0, 15);
6337         spin_crossfade.set_increments (1, 1);
6338         spin_crossfade.set_value (5);
6339         table.attach (spin_crossfade, 1, 2, 0, 1);
6340
6341         table.attach (*manage (new Label (_("ms"))), 2, 3, 0, 1);
6342
6343         l = manage (left_aligned_label (_("Pull-back length")));
6344         table.attach (*l, 0, 1, 1, 2);
6345
6346         SpinButton spin_pullback (1, 0);
6347         spin_pullback.set_range (0, 100);
6348         spin_pullback.set_increments (1, 1);
6349         spin_pullback.set_value(30);
6350         table.attach (spin_pullback, 1, 2, 1, 2);
6351
6352         table.attach (*manage (new Label (_("ms"))), 2, 3, 1, 2);
6353
6354         dialog.get_vbox()->pack_start (table);
6355         dialog.add_button (Stock::CANCEL, RESPONSE_CANCEL);
6356         dialog.add_button (_("Ok"), RESPONSE_ACCEPT);
6357         dialog.show_all ();
6358
6359         if (dialog.run () == RESPONSE_CANCEL) {
6360                 return;
6361         }
6362
6363         framepos_t crossfade_len = spin_crossfade.get_value();
6364         framepos_t pull_back_frames = spin_pullback.get_value();
6365
6366         crossfade_len = lrintf (crossfade_len * _session->frame_rate()/1000);
6367         pull_back_frames = lrintf (pull_back_frames * _session->frame_rate()/1000);
6368
6369         /* Iterate over the region list and make adjacent regions overlap by crossfade_len_ms */
6370
6371         _session->begin_reversible_command (_("close region gaps"));
6372
6373         int idx = 0;
6374         boost::shared_ptr<Region> last_region;
6375
6376         rs.sort_by_position_and_track();
6377
6378         for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6379
6380                 boost::shared_ptr<Playlist> pl = (*r)->region()->playlist();
6381
6382                 if (!pl->frozen()) {
6383                         /* we haven't seen this playlist before */
6384
6385                         /* remember used playlists so we can thaw them later */
6386                         used_playlists.push_back(pl);
6387                         pl->freeze();
6388                 }
6389
6390                 framepos_t position = (*r)->region()->position();
6391
6392                 if (idx == 0 || position < last_region->position()){
6393                         last_region = (*r)->region();
6394                         idx++;
6395                         continue;
6396                 }
6397
6398                 (*r)->region()->trim_front( (position - pull_back_frames));
6399                 last_region->trim_end( (position - pull_back_frames + crossfade_len));
6400
6401                 last_region = (*r)->region();
6402
6403                 idx++;
6404         }
6405
6406         while (used_playlists.size() > 0) {
6407                 list <boost::shared_ptr<Playlist > >::iterator i = used_playlists.begin();
6408                 (*i)->thaw();
6409                 used_playlists.pop_front();
6410         }
6411
6412         _session->commit_reversible_command ();
6413 }
6414
6415 void
6416 Editor::tab_to_transient (bool forward)
6417 {
6418         AnalysisFeatureList positions;
6419
6420         RegionSelection rs = get_regions_from_selection_and_entered ();
6421
6422         if (!_session) {
6423                 return;
6424         }
6425
6426         framepos_t pos = _session->audible_frame ();
6427
6428         if (!selection->tracks.empty()) {
6429
6430                 /* don't waste time searching for transients in duplicate playlists.
6431                  */
6432
6433                 TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6434
6435                 for (TrackViewList::iterator t = ts.begin(); t != ts.end(); ++t) {
6436
6437                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*t);
6438
6439                         if (rtv) {
6440                                 boost::shared_ptr<Track> tr = rtv->track();
6441                                 if (tr) {
6442                                         boost::shared_ptr<Playlist> pl = tr->playlist ();
6443                                         if (pl) {
6444                                                 framepos_t result = pl->find_next_transient (pos, forward ? 1 : -1);
6445
6446                                                 if (result >= 0) {
6447                                                         positions.push_back (result);
6448                                                 }
6449                                         }
6450                                 }
6451                         }
6452                 }
6453
6454         } else {
6455
6456                 if (rs.empty()) {
6457                         return;
6458                 }
6459
6460                 for (RegionSelection::iterator r = rs.begin(); r != rs.end(); ++r) {
6461                         (*r)->region()->get_transients (positions);
6462                 }
6463         }
6464
6465         TransientDetector::cleanup_transients (positions, _session->frame_rate(), 3.0);
6466
6467         if (forward) {
6468                 AnalysisFeatureList::iterator x;
6469
6470                 for (x = positions.begin(); x != positions.end(); ++x) {
6471                         if ((*x) > pos) {
6472                                 break;
6473                         }
6474                 }
6475
6476                 if (x != positions.end ()) {
6477                         _session->request_locate (*x);
6478                 }
6479
6480         } else {
6481                 AnalysisFeatureList::reverse_iterator x;
6482
6483                 for (x = positions.rbegin(); x != positions.rend(); ++x) {
6484                         if ((*x) < pos) {
6485                                 break;
6486                         }
6487                 }
6488
6489                 if (x != positions.rend ()) {
6490                         _session->request_locate (*x);
6491                 }
6492         }
6493 }
6494
6495 void
6496 Editor::playhead_forward_to_grid ()
6497 {
6498         if (!_session) {
6499                 return;
6500         }
6501         
6502         framepos_t pos = playhead_cursor->current_frame ();
6503         if (pos < max_framepos - 1) {
6504                 pos += 2;
6505                 snap_to_internal (pos, RoundUpAlways, false);
6506                 _session->request_locate (pos);
6507         }
6508 }
6509
6510
6511 void
6512 Editor::playhead_backward_to_grid ()
6513 {
6514         if (!_session) {
6515                 return;
6516         }
6517         
6518         framepos_t pos = playhead_cursor->current_frame ();
6519         if (pos > 2) {
6520                 pos -= 2;
6521                 snap_to_internal (pos, RoundDownAlways, false);
6522                 _session->request_locate (pos);
6523         }
6524 }
6525
6526 void
6527 Editor::set_track_height (Height h)
6528 {
6529         TrackSelection& ts (selection->tracks);
6530
6531         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6532                 (*x)->set_height_enum (h);
6533         }
6534 }
6535
6536 void
6537 Editor::toggle_tracks_active ()
6538 {
6539         TrackSelection& ts (selection->tracks);
6540         bool first = true;
6541         bool target = false;
6542
6543         if (ts.empty()) {
6544                 return;
6545         }
6546
6547         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6548                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(*x);
6549
6550                 if (rtv) {
6551                         if (first) {
6552                                 target = !rtv->_route->active();
6553                                 first = false;
6554                         }
6555                         rtv->_route->set_active (target, this);
6556                 }
6557         }
6558 }
6559
6560 void
6561 Editor::remove_tracks ()
6562 {
6563         TrackSelection& ts (selection->tracks);
6564
6565         if (ts.empty()) {
6566                 return;
6567         }
6568
6569         vector<string> choices;
6570         string prompt;
6571         int ntracks = 0;
6572         int nbusses = 0;
6573         const char* trackstr;
6574         const char* busstr;
6575         vector<boost::shared_ptr<Route> > routes;
6576         bool special_bus = false;
6577
6578         for (TrackSelection::iterator x = ts.begin(); x != ts.end(); ++x) {
6579                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*x);
6580                 if (!rtv) {
6581                         continue;
6582                 }
6583                 if (rtv->is_track()) {
6584                         ntracks++;
6585                 } else {
6586                         nbusses++;
6587                 }
6588                 routes.push_back (rtv->_route);
6589
6590                 if (rtv->route()->is_master() || rtv->route()->is_monitor()) {
6591                         special_bus = true;
6592                 }
6593         }
6594
6595         if (special_bus && !Config->get_allow_special_bus_removal()) {
6596                 MessageDialog msg (_("That would be bad news ...."),
6597                                    false,
6598                                    Gtk::MESSAGE_INFO,
6599                                    Gtk::BUTTONS_OK);
6600                 msg.set_secondary_text (string_compose (_(
6601                                                                 "Removing the master or monitor bus is such a bad idea\n\
6602 that %1 is not going to allow it.\n\
6603 \n\
6604 If you really want to do this sort of thing\n\
6605 edit your ardour.rc file to set the\n\
6606 \"allow-special-bus-removal\" option to be \"yes\""), PROGRAM_NAME));
6607
6608                 msg.present ();
6609                 msg.run ();
6610                 return;
6611         }
6612
6613         if (ntracks + nbusses == 0) {
6614                 return;
6615         }
6616
6617         // XXX should be using gettext plural forms, maybe?
6618         if (ntracks > 1) {
6619                 trackstr = _("tracks");
6620         } else {
6621                 trackstr = _("track");
6622         }
6623
6624         if (nbusses > 1) {
6625                 busstr = _("busses");
6626         } else {
6627                 busstr = _("bus");
6628         }
6629
6630         if (ntracks) {
6631                 if (nbusses) {
6632                         prompt  = string_compose (_("Do you really want to remove %1 %2 and %3 %4?\n"
6633                                                     "(You may also lose the playlists associated with the %2)\n\n"
6634                                                     "This action cannot be undone, and the session file will be overwritten!"),
6635                                                   ntracks, trackstr, nbusses, busstr);
6636                 } else {
6637                         prompt  = string_compose (_("Do you really want to remove %1 %2?\n"
6638                                                     "(You may also lose the playlists associated with the %2)\n\n"
6639                                                     "This action cannot be undone, and the session file will be overwritten!"),
6640                                                   ntracks, trackstr);
6641                 }
6642         } else if (nbusses) {
6643                 prompt  = string_compose (_("Do you really want to remove %1 %2?\n\n"
6644                                             "This action cannot be undone, and the session file will be overwritten"),
6645                                           nbusses, busstr);
6646         }
6647
6648         choices.push_back (_("No, do nothing."));
6649         if (ntracks + nbusses > 1) {
6650                 choices.push_back (_("Yes, remove them."));
6651         } else {
6652                 choices.push_back (_("Yes, remove it."));
6653         }
6654
6655         string title;
6656         if (ntracks) {
6657                 title = string_compose (_("Remove %1"), trackstr);
6658         } else {
6659                 title = string_compose (_("Remove %1"), busstr);
6660         }
6661
6662         Choice prompter (title, prompt, choices);
6663
6664         if (prompter.run () != 1) {
6665                 return;
6666         }
6667
6668         {
6669                 Session::StateProtector sp (_session);
6670                 DisplaySuspender ds;
6671                 for (vector<boost::shared_ptr<Route> >::iterator x = routes.begin(); x != routes.end(); ++x) {
6672                         _session->remove_route (*x);
6673                 }
6674         }
6675 }
6676
6677 void
6678 Editor::do_insert_time ()
6679 {
6680         if (selection->tracks.empty()) {
6681                 return;
6682         }
6683
6684         InsertTimeDialog d (*this);
6685         int response = d.run ();
6686
6687         if (response != RESPONSE_OK) {
6688                 return;
6689         }
6690
6691         if (d.distance() == 0) {
6692                 return;
6693         }
6694
6695         InsertTimeOption opt = d.intersected_region_action ();
6696
6697         insert_time (
6698                 get_preferred_edit_position(),
6699                 d.distance(),
6700                 opt,
6701                 d.all_playlists(),
6702                 d.move_glued(),
6703                 d.move_markers(),
6704                 d.move_glued_markers(),
6705                 d.move_locked_markers(),
6706                 d.move_tempos()
6707                 );
6708 }
6709
6710 void
6711 Editor::insert_time (
6712         framepos_t pos, framecnt_t frames, InsertTimeOption opt,
6713         bool all_playlists, bool ignore_music_glue, bool markers_too, bool glued_markers_too, bool locked_markers_too, bool tempo_too
6714         )
6715 {
6716         bool commit = false;
6717
6718         if (Config->get_edit_mode() == Lock) {
6719                 return;
6720         }
6721
6722         begin_reversible_command (_("insert time"));
6723
6724         TrackViewList ts = selection->tracks.filter_to_unique_playlists ();
6725
6726         for (TrackViewList::iterator x = ts.begin(); x != ts.end(); ++x) {
6727
6728                 /* regions */
6729
6730                 /* don't operate on any playlist more than once, which could
6731                  * happen if "all playlists" is enabled, but there is more
6732                  * than 1 track using playlists "from" a given track.
6733                  */
6734
6735                 set<boost::shared_ptr<Playlist> > pl;
6736
6737                 if (all_playlists) {
6738                         RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6739                         if (rtav) {
6740                                 vector<boost::shared_ptr<Playlist> > all = _session->playlists->playlists_for_track (rtav->track ());
6741                                 for (vector<boost::shared_ptr<Playlist> >::iterator p = all.begin(); p != all.end(); ++p) {
6742                                         pl.insert (*p);
6743                                 }
6744                         }
6745                 } else {
6746                         if ((*x)->playlist ()) {
6747                                 pl.insert ((*x)->playlist ());
6748                         }
6749                 }
6750                 
6751                 for (set<boost::shared_ptr<Playlist> >::iterator i = pl.begin(); i != pl.end(); ++i) {
6752
6753                         (*i)->clear_changes ();
6754                         (*i)->clear_owned_changes ();
6755
6756                         if (opt == SplitIntersected) {
6757                                 (*i)->split (pos);
6758                         }
6759
6760                         (*i)->shift (pos, frames, (opt == MoveIntersected), ignore_music_glue);
6761
6762                         vector<Command*> cmds;
6763                         (*i)->rdiff (cmds);
6764                         _session->add_commands (cmds);
6765
6766                         _session->add_command (new StatefulDiffCommand (*i));
6767                         commit = true;
6768                 }
6769
6770                 /* automation */
6771                 RouteTimeAxisView* rtav = dynamic_cast<RouteTimeAxisView*> (*x);
6772                 if (rtav) {
6773                         rtav->route ()->shift (pos, frames);
6774                         commit = true;
6775                 }
6776         }
6777
6778         /* markers */
6779         if (markers_too) {
6780                 bool moved = false;
6781                 XMLNode& before (_session->locations()->get_state());
6782                 Locations::LocationList copy (_session->locations()->list());
6783
6784                 for (Locations::LocationList::iterator i = copy.begin(); i != copy.end(); ++i) {
6785
6786                         Locations::LocationList::const_iterator tmp;
6787
6788                         bool const was_locked = (*i)->locked ();
6789                         if (locked_markers_too) {
6790                                 (*i)->unlock ();
6791                         }
6792
6793                         if ((*i)->position_lock_style() == AudioTime || glued_markers_too) {
6794
6795                                 if ((*i)->start() >= pos) {
6796                                         (*i)->set_start ((*i)->start() + frames);
6797                                         if (!(*i)->is_mark()) {
6798                                                 (*i)->set_end ((*i)->end() + frames);
6799                                         }
6800                                         moved = true;
6801                                 }
6802
6803                         }
6804
6805                         if (was_locked) {
6806                                 (*i)->lock ();
6807                         }
6808                 }
6809
6810                 if (moved) {
6811                         XMLNode& after (_session->locations()->get_state());
6812                         _session->add_command (new MementoCommand<Locations>(*_session->locations(), &before, &after));
6813                 }
6814         }
6815
6816         if (tempo_too) {
6817                 _session->tempo_map().insert_time (pos, frames);
6818         }
6819
6820         if (commit) {
6821                 commit_reversible_command ();
6822         }
6823 }
6824
6825 void
6826 Editor::fit_selected_tracks ()
6827 {
6828         if (!selection->tracks.empty()) {
6829                 fit_tracks (selection->tracks);
6830         } else {
6831                 TrackViewList tvl;
6832
6833                 /* no selected tracks - use tracks with selected regions */
6834
6835                 if (!selection->regions.empty()) {
6836                         for (RegionSelection::iterator r = selection->regions.begin(); r != selection->regions.end(); ++r) {
6837                                 tvl.push_back (&(*r)->get_time_axis_view ());
6838                         }
6839
6840                         if (!tvl.empty()) {
6841                                 fit_tracks (tvl);
6842                         }
6843                 } else if (internal_editing()) {
6844                         /* no selected tracks, or regions, but in internal edit mode, so follow the mouse and use
6845                            the entered track
6846                         */
6847                         if (entered_track) {
6848                                 tvl.push_back (entered_track);
6849                                 fit_tracks (tvl);
6850                         }
6851                 }
6852         }
6853
6854 }
6855
6856 void
6857 Editor::fit_tracks (TrackViewList & tracks)
6858 {
6859         if (tracks.empty()) {
6860                 return;
6861         }
6862
6863         uint32_t child_heights = 0;
6864         int visible_tracks = 0;
6865
6866         for (TrackSelection::iterator t = tracks.begin(); t != tracks.end(); ++t) {
6867
6868                 if (!(*t)->marked_for_display()) {
6869                         continue;
6870                 }
6871
6872                 child_heights += (*t)->effective_height() - (*t)->current_height();
6873                 ++visible_tracks;
6874         }
6875
6876         /* compute the per-track height from:
6877
6878            total canvas visible height - 
6879                  height that will be taken by visible children of selected
6880                  tracks - height of the ruler/hscroll area 
6881         */
6882         uint32_t h = (uint32_t) floor ((trackviews_height() - child_heights) / visible_tracks);
6883         double first_y_pos = DBL_MAX;
6884
6885         if (h < TimeAxisView::preset_height (HeightSmall)) {
6886                 MessageDialog msg (*this, _("There are too many tracks to fit in the current window"));
6887                 /* too small to be displayed */
6888                 return;
6889         }
6890
6891         undo_visual_stack.push_back (current_visual_state (true));
6892         no_save_visual = true;
6893
6894         /* build a list of all tracks, including children */
6895
6896         TrackViewList all;
6897         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
6898                 all.push_back (*i);
6899                 TimeAxisView::Children c = (*i)->get_child_list ();
6900                 for (TimeAxisView::Children::iterator j = c.begin(); j != c.end(); ++j) {
6901                         all.push_back (j->get());
6902                 }
6903         }
6904
6905         bool prev_was_selected = false;
6906         bool is_selected = tracks.contains (all.front());
6907         bool next_is_selected;
6908
6909         for (TrackViewList::iterator t = all.begin(); t != all.end(); ++t) {
6910
6911                 TrackViewList::iterator next;
6912
6913                 next = t;
6914                 ++next;
6915
6916                 if (next != all.end()) {
6917                         next_is_selected = tracks.contains (*next);
6918                 } else {
6919                         next_is_selected = false;
6920                 }
6921
6922                 if ((*t)->marked_for_display ()) {
6923                         if (is_selected) {
6924                                 (*t)->set_height (h);
6925                                 first_y_pos = std::min ((*t)->y_position (), first_y_pos);
6926                         } else {
6927                                 if (prev_was_selected && next_is_selected) {
6928                                         hide_track_in_display (*t);
6929                                 }
6930                         }
6931                 }
6932
6933                 prev_was_selected = is_selected;
6934                 is_selected = next_is_selected;
6935         }
6936
6937         /*
6938            set the controls_layout height now, because waiting for its size
6939            request signal handler will cause the vertical adjustment setting to fail
6940         */
6941
6942         controls_layout.property_height () = _full_canvas_height;
6943         vertical_adjustment.set_value (first_y_pos);
6944
6945         redo_visual_stack.push_back (current_visual_state (true));
6946
6947         visible_tracks_selector.set_text (_("Sel"));
6948 }
6949
6950 void
6951 Editor::save_visual_state (uint32_t n)
6952 {
6953         while (visual_states.size() <= n) {
6954                 visual_states.push_back (0);
6955         }
6956
6957         if (visual_states[n] != 0) {
6958                 delete visual_states[n];
6959         }
6960
6961         visual_states[n] = current_visual_state (true);
6962         gdk_beep ();
6963 }
6964
6965 void
6966 Editor::goto_visual_state (uint32_t n)
6967 {
6968         if (visual_states.size() <= n) {
6969                 return;
6970         }
6971
6972         if (visual_states[n] == 0) {
6973                 return;
6974         }
6975
6976         use_visual_state (*visual_states[n]);
6977 }
6978
6979 void
6980 Editor::start_visual_state_op (uint32_t n)
6981 {
6982         save_visual_state (n);
6983         
6984         PopUp* pup = new PopUp (WIN_POS_MOUSE, 1000, true);
6985         char buf[32];
6986         snprintf (buf, sizeof (buf), _("Saved view %u"), n+1);
6987         pup->set_text (buf);
6988         pup->touch();
6989 }
6990
6991 void
6992 Editor::cancel_visual_state_op (uint32_t n)
6993 {
6994         goto_visual_state (n);
6995 }
6996
6997 void
6998 Editor::toggle_region_mute ()
6999 {
7000         if (_ignore_region_action) {
7001                 return;
7002         }
7003
7004         RegionSelection rs = get_regions_from_selection_and_entered ();
7005
7006         if (rs.empty ()) {
7007                 return;
7008         }
7009
7010         if (rs.size() > 1) {
7011                 begin_reversible_command (_("mute regions"));
7012         } else {
7013                 begin_reversible_command (_("mute region"));
7014         }
7015
7016         for (RegionSelection::iterator i = rs.begin(); i != rs.end(); ++i) {
7017
7018                 (*i)->region()->playlist()->clear_changes ();
7019                 (*i)->region()->set_muted (!(*i)->region()->muted ());
7020                 _session->add_command (new StatefulDiffCommand ((*i)->region()->playlist()));
7021
7022         }
7023
7024         commit_reversible_command ();
7025 }
7026
7027 void
7028 Editor::combine_regions ()
7029 {
7030         /* foreach track with selected regions, take all selected regions
7031            and join them into a new region containing the subregions (as a
7032            playlist)
7033         */
7034
7035         typedef set<RouteTimeAxisView*> RTVS;
7036         RTVS tracks;
7037
7038         if (selection->regions.empty()) {
7039                 return;
7040         }
7041
7042         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7043                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7044
7045                 if (rtv) {
7046                         tracks.insert (rtv);
7047                 }
7048         }
7049
7050         begin_reversible_command (_("combine regions"));
7051
7052         vector<RegionView*> new_selection;
7053
7054         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7055                 RegionView* rv;
7056
7057                 if ((rv = (*i)->combine_regions ()) != 0) {
7058                         new_selection.push_back (rv);
7059                 }
7060         }
7061
7062         selection->clear_regions ();
7063         for (vector<RegionView*>::iterator i = new_selection.begin(); i != new_selection.end(); ++i) {
7064                 selection->add (*i);
7065         }
7066
7067         commit_reversible_command ();
7068 }
7069
7070 void
7071 Editor::uncombine_regions ()
7072 {
7073         typedef set<RouteTimeAxisView*> RTVS;
7074         RTVS tracks;
7075
7076         if (selection->regions.empty()) {
7077                 return;
7078         }
7079
7080         for (RegionSelection::iterator i = selection->regions.begin(); i != selection->regions.end(); ++i) {
7081                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(&(*i)->get_time_axis_view());
7082
7083                 if (rtv) {
7084                         tracks.insert (rtv);
7085                 }
7086         }
7087
7088         begin_reversible_command (_("uncombine regions"));
7089
7090         for (RTVS::iterator i = tracks.begin(); i != tracks.end(); ++i) {
7091                 (*i)->uncombine_regions ();
7092         }
7093
7094         commit_reversible_command ();
7095 }
7096
7097 void
7098 Editor::toggle_midi_input_active (bool flip_others)
7099 {
7100         bool onoff = false;
7101         boost::shared_ptr<RouteList> rl (new RouteList);
7102
7103         for (TrackSelection::iterator i = selection->tracks.begin(); i != selection->tracks.end(); ++i) {
7104                 RouteTimeAxisView *rtav = dynamic_cast<RouteTimeAxisView *>(*i);
7105
7106                 if (!rtav) {
7107                         continue;
7108                 }
7109
7110                 boost::shared_ptr<MidiTrack> mt = rtav->midi_track();
7111
7112                 if (mt) {
7113                         rl->push_back (rtav->route());
7114                         onoff = !mt->input_active();
7115                 }
7116         }
7117         
7118         _session->set_exclusive_input_active (rl, onoff, flip_others);
7119 }
7120
7121 void
7122 Editor::lock ()
7123 {
7124         if (!lock_dialog) {
7125                 lock_dialog = new Gtk::Dialog (string_compose (_("%1: Locked"), PROGRAM_NAME), true);
7126
7127                 Gtk::Image* padlock = manage (new Gtk::Image (ARDOUR_UI_UTILS::get_icon ("padlock_closed")));
7128                 lock_dialog->get_vbox()->pack_start (*padlock);
7129
7130                 ArdourButton* b = manage (new ArdourButton);
7131                 b->set_name ("lock button");
7132                 b->set_text (_("Click to unlock"));
7133                 b->signal_clicked.connect (sigc::mem_fun (*this, &Editor::unlock));
7134                 lock_dialog->get_vbox()->pack_start (*b);
7135                 
7136                 lock_dialog->get_vbox()->show_all ();
7137                 lock_dialog->set_size_request (200, 200);
7138         }
7139         
7140 #ifdef __APPLE__
7141         /* The global menu bar continues to be accessible to applications
7142            with modal dialogs, which means that we need to desensitize
7143            all items in the menu bar. Since those items are really just
7144            proxies for actions, that means disabling all actions.
7145         */
7146         ActionManager::disable_all_actions ();
7147 #endif
7148         lock_dialog->present ();
7149 }
7150
7151 void
7152 Editor::unlock ()
7153 {
7154         lock_dialog->hide ();
7155         
7156 #ifdef __APPLE__
7157         ActionManager::pop_action_state ();
7158 #endif  
7159
7160         if (ARDOUR_UI::config()->get_lock_gui_after_seconds()) {
7161                 start_lock_event_timing ();
7162         }
7163 }
7164
7165 void
7166 Editor::bring_in_callback (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7167 {
7168         Gtkmm2ext::UI::instance()->call_slot (invalidator (*this), boost::bind (&Editor::update_bring_in_message, this, label, n, total, name));
7169 }
7170
7171 void
7172 Editor::update_bring_in_message (Gtk::Label* label, uint32_t n, uint32_t total, string name)
7173 {
7174         label->set_text (string_compose ("Copying %1, %2 of %3", name, n, total));
7175         Gtkmm2ext::UI::instance()->flush_pending ();
7176 }
7177
7178 void
7179 Editor::bring_all_sources_into_session ()
7180 {
7181         if (!_session) {
7182                 return;
7183         }
7184
7185         Gtk::Label msg;
7186         ArdourDialog w (_("Moving embedded files into session folder"));
7187         w.get_vbox()->pack_start (msg);
7188         w.present ();
7189         
7190         /* flush all pending GUI events because we're about to start copying
7191          * files
7192          */
7193         
7194         Gtkmm2ext::UI::instance()->flush_pending ();
7195
7196         cerr << " Do it\n";
7197
7198         _session->bring_all_sources_into_session (boost::bind (&Editor::bring_in_callback, this, &msg, _1, _2, _3));
7199 }