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