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