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