fix the naming and behavior of always-play-range to match the button, which is follow...
[ardour.git] / gtk2_ardour / editor_drag.cc
1 /*
2     Copyright (C) 2009 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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include <stdint.h>
25 #include <algorithm>
26
27 #include "pbd/memento_command.h"
28 #include "pbd/basename.h"
29 #include "pbd/stateful_diff_command.h"
30
31 #include "gtkmm2ext/utils.h"
32
33 #include "ardour/audioengine.h"
34 #include "ardour/audioregion.h"
35 #include "ardour/audio_track.h"
36 #include "ardour/dB.h"
37 #include "ardour/midi_region.h"
38 #include "ardour/midi_track.h"
39 #include "ardour/operations.h"
40 #include "ardour/region_factory.h"
41 #include "ardour/session.h"
42
43 #include "canvas/scroll_group.h"
44
45 #include "editor.h"
46 #include "i18n.h"
47 #include "keyboard.h"
48 #include "audio_region_view.h"
49 #include "midi_region_view.h"
50 #include "ardour_ui.h"
51 #include "gui_thread.h"
52 #include "control_point.h"
53 #include "region_gain_line.h"
54 #include "editor_drag.h"
55 #include "audio_time_axis.h"
56 #include "midi_time_axis.h"
57 #include "selection.h"
58 #include "midi_selection.h"
59 #include "automation_time_axis.h"
60 #include "debug.h"
61 #include "editor_cursors.h"
62 #include "mouse_cursors.h"
63 #include "note_base.h"
64 #include "patch_change.h"
65 #include "verbose_cursor.h"
66
67 using namespace std;
68 using namespace ARDOUR;
69 using namespace PBD;
70 using namespace Gtk;
71 using namespace Gtkmm2ext;
72 using namespace Editing;
73 using namespace ArdourCanvas;
74
75 using Gtkmm2ext::Keyboard;
76
77 double ControlPointDrag::_zero_gain_fraction = -1.0;
78
79 DragManager::DragManager (Editor* e)
80         : _editor (e)
81         , _ending (false)
82         , _current_pointer_frame (0)
83 {
84 }
85
86 DragManager::~DragManager ()
87 {
88         abort ();
89 }
90
91 /** Call abort for each active drag */
92 void
93 DragManager::abort ()
94 {
95         _ending = true;
96
97         for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
98                 (*i)->abort ();
99                 delete *i;
100         }
101
102         if (!_drags.empty ()) {
103                 _editor->set_follow_playhead (_old_follow_playhead, false);
104         }
105
106         _drags.clear ();
107
108         _ending = false;
109 }
110
111 void
112 DragManager::add (Drag* d)
113 {
114         d->set_manager (this);
115         _drags.push_back (d);
116 }
117
118 void
119 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
120 {
121         d->set_manager (this);
122         _drags.push_back (d);
123         start_grab (e, c);
124 }
125
126 void
127 DragManager::start_grab (GdkEvent* e, Gdk::Cursor* c)
128 {
129         /* Prevent follow playhead during the drag to be nice to the user */
130         _old_follow_playhead = _editor->follow_playhead ();
131         _editor->set_follow_playhead (false);
132
133         _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
134
135         for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
136                 (*i)->start_grab (e, c);
137         }
138 }
139
140 /** Call end_grab for each active drag.
141  *  @return true if any drag reported movement having occurred.
142  */
143 bool
144 DragManager::end_grab (GdkEvent* e)
145 {
146         _ending = true;
147
148         bool r = false;
149         for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
150                 bool const t = (*i)->end_grab (e);
151                 if (t) {
152                         r = true;
153                 }
154                 delete *i;
155         }
156
157         _drags.clear ();
158
159         _ending = false;
160
161         _editor->set_follow_playhead (_old_follow_playhead, false);
162
163         return r;
164 }
165
166 void
167 DragManager::mark_double_click ()
168 {
169         for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
170                 (*i)->set_double_click (true);
171         }
172 }
173
174 bool
175 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
176 {
177         bool r = false;
178
179         /* calling this implies that we expect the event to have canvas
180          * coordinates 
181          *
182          * Can we guarantee that this is true?
183          */
184
185         _current_pointer_frame = _editor->canvas_event_sample (e, &_current_pointer_x, &_current_pointer_y);
186
187         for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
188                 bool const t = (*i)->motion_handler (e, from_autoscroll);
189                 /* run all handlers; return true if at least one of them
190                    returns true (indicating that the event has been handled).
191                 */
192                 if (t) {
193                         r = true;
194                 }
195
196         }
197
198         return r;
199 }
200
201 bool
202 DragManager::have_item (ArdourCanvas::Item* i) const
203 {
204         list<Drag*>::const_iterator j = _drags.begin ();
205         while (j != _drags.end() && (*j)->item () != i) {
206                 ++j;
207         }
208
209         return j != _drags.end ();
210 }
211
212 Drag::Drag (Editor* e, ArdourCanvas::Item* i, bool trackview_only)
213         : _editor (e)
214         , _item (i)
215         , _pointer_frame_offset (0)
216         , _trackview_only (trackview_only)
217         , _move_threshold_passed (false)
218         , _was_double_click (false)
219         , _raw_grab_frame (0)
220         , _grab_frame (0)
221         , _last_pointer_frame (0)
222 {
223
224 }
225
226 void
227 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t /*time*/)
228 {
229         _item->ungrab ();
230         _item = new_item;
231
232         if (cursor == 0) {
233                 _item->grab ();
234         } else {
235                 _item->grab ();
236         }
237 }
238
239 void
240 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
241 {
242         // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
243
244         if (Keyboard::is_button2_event (&event->button)) {
245                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
246                         _y_constrained = true;
247                         _x_constrained = false;
248                 } else {
249                         _y_constrained = false;
250                         _x_constrained = true;
251                 }
252         } else {
253                 _x_constrained = false;
254                 _y_constrained = false;
255         }
256
257         _raw_grab_frame = _editor->canvas_event_sample (event, &_grab_x, &_grab_y);
258         setup_pointer_frame_offset ();
259         _grab_frame = adjusted_frame (_raw_grab_frame, event);
260         _last_pointer_frame = _grab_frame;
261         _last_pointer_x = _grab_x;
262
263         if (_trackview_only) {
264                 _grab_y = _grab_y - _editor->get_trackview_group()->canvas_origin().y;
265         }
266
267         _last_pointer_y = _grab_y;
268
269         if (cursor == 0) {
270                 _item->grab ();
271         } else {
272                 /* CAIROCANVAS need a variant here that passes *cursor */
273                 _item->grab ();
274                 _editor->push_canvas_cursor (cursor);
275         }
276
277         if (_editor->session() && _editor->session()->transport_rolling()) {
278                 _was_rolling = true;
279         } else {
280                 _was_rolling = false;
281         }
282
283         switch (_editor->snap_type()) {
284         case SnapToRegionStart:
285         case SnapToRegionEnd:
286         case SnapToRegionSync:
287         case SnapToRegionBoundary:
288                 _editor->build_region_boundary_cache ();
289                 break;
290         default:
291                 break;
292         }
293 }
294
295 /** Call to end a drag `successfully'.  Ungrabs item and calls
296  *  subclass' finished() method.
297  *
298  *  @param event GDK event, or 0.
299  *  @return true if some movement occurred, otherwise false.
300  */
301 bool
302 Drag::end_grab (GdkEvent* event)
303 {
304         _editor->stop_canvas_autoscroll ();
305
306         _item->ungrab ();
307
308         finished (event, _move_threshold_passed);
309
310         _editor->verbose_cursor()->hide ();
311         _editor->pop_canvas_cursor ();
312
313         return _move_threshold_passed;
314 }
315
316 framepos_t
317 Drag::adjusted_frame (framepos_t f, GdkEvent const * event, bool snap) const
318 {
319         framepos_t pos = 0;
320
321         if (f > _pointer_frame_offset) {
322                 pos = f - _pointer_frame_offset;
323         }
324
325         if (snap) {
326                 _editor->snap_to_with_modifier (pos, event);
327         }
328
329         return pos;
330 }
331
332 framepos_t
333 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
334 {
335         return adjusted_frame (_drags->current_pointer_frame (), event, snap);
336 }
337
338 double
339 Drag::current_pointer_y () const
340 {
341         if (!_trackview_only) {
342                 return _drags->current_pointer_y ();
343         }
344         
345         return _drags->current_pointer_y () - _editor->get_trackview_group()->canvas_origin().y;
346 }
347
348 bool
349 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
350 {
351         /* check to see if we have moved in any way that matters since the last motion event */
352         if (_move_threshold_passed &&
353             (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
354             (!y_movement_matters() || _last_pointer_y == current_pointer_y ()) ) {
355                 return false;
356         }
357
358         pair<framecnt_t, int> const threshold = move_threshold ();
359
360         bool const old_move_threshold_passed = _move_threshold_passed;
361
362         if (!from_autoscroll && !_move_threshold_passed) {
363
364                 bool const xp = (::llabs (_drags->current_pointer_frame () - _raw_grab_frame) >= threshold.first);
365                 bool const yp = (::fabs ((current_pointer_y () - _grab_y)) >= threshold.second);
366
367                 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
368         }
369
370         if (active (_editor->mouse_mode) && _move_threshold_passed) {
371
372                 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
373                         if (!from_autoscroll) {
374                                 _editor->maybe_autoscroll (true, allow_vertical_autoscroll (), false);
375                         }
376
377                         if (!_editor->autoscroll_active() || from_autoscroll) {
378                                 motion (event, _move_threshold_passed != old_move_threshold_passed);
379                                 
380                                 _last_pointer_x = _drags->current_pointer_x ();
381                                 _last_pointer_y = current_pointer_y ();
382                                 _last_pointer_frame = adjusted_current_frame (event);
383                         }
384
385                         return true;
386                 }
387         }
388
389         return false;
390 }
391
392 /** Call to abort a drag.  Ungrabs item and calls subclass's aborted () */
393 void
394 Drag::abort ()
395 {
396         if (_item) {
397                 _item->ungrab ();
398         }
399
400         aborted (_move_threshold_passed);
401
402         _editor->stop_canvas_autoscroll ();
403         _editor->verbose_cursor()->hide ();
404 }
405
406 void
407 Drag::show_verbose_cursor_time (framepos_t frame)
408 {
409         _editor->verbose_cursor()->set_time (frame);
410         _editor->verbose_cursor()->show ();
411 }
412
413 void
414 Drag::show_verbose_cursor_duration (framepos_t start, framepos_t end, double /*xoffset*/)
415 {
416         _editor->verbose_cursor()->set_duration (start, end);
417         _editor->verbose_cursor()->show ();
418 }
419
420 void
421 Drag::show_verbose_cursor_text (string const & text)
422 {
423         _editor->verbose_cursor()->set (text);
424         _editor->verbose_cursor()->show ();
425 }
426
427 boost::shared_ptr<Region>
428 Drag::add_midi_region (MidiTimeAxisView* view)
429 {
430         if (_editor->session()) {
431                 const TempoMap& map (_editor->session()->tempo_map());
432                 framecnt_t pos = grab_frame();
433                 const Meter& m = map.meter_at (pos);
434                 /* not that the frame rate used here can be affected by pull up/down which
435                    might be wrong.
436                 */
437                 framecnt_t len = m.frames_per_bar (map.tempo_at (pos), _editor->session()->frame_rate());
438                 return view->add_region (grab_frame(), len, true);
439         }
440
441         return boost::shared_ptr<Region>();
442 }
443
444 struct EditorOrderTimeAxisViewSorter {
445     bool operator() (TimeAxisView* a, TimeAxisView* b) {
446             RouteTimeAxisView* ra = dynamic_cast<RouteTimeAxisView*> (a);
447             RouteTimeAxisView* rb = dynamic_cast<RouteTimeAxisView*> (b);
448             assert (ra && rb);
449             return ra->route()->order_key () < rb->route()->order_key ();
450     }
451 };
452
453 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
454         : Drag (e, i),
455           _primary (p)
456 {
457         _editor->visible_order_range (&_visible_y_low, &_visible_y_high);
458
459         /* Make a list of tracks to refer to during the drag; we include hidden tracks,
460            as some of the regions we are dragging may be on such tracks.
461         */
462
463         TrackViewList track_views = _editor->track_views;
464         track_views.sort (EditorOrderTimeAxisViewSorter ());
465
466         for (TrackViewList::iterator i = track_views.begin(); i != track_views.end(); ++i) {
467                 _time_axis_views.push_back (*i);
468                 
469                 TimeAxisView::Children children_list = (*i)->get_child_list ();
470                 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
471                         _time_axis_views.push_back (j->get());
472                 }
473         }
474
475         /* the list of views can be empty at this point if this is a region list-insert drag
476          */
477
478         for (list<RegionView*>::const_iterator i = v.begin(); i != v.end(); ++i) {
479                 _views.push_back (DraggingView (*i, this, &(*i)->get_time_axis_view()));
480         }
481
482         RegionView::RegionViewGoingAway.connect (death_connection, invalidator (*this), boost::bind (&RegionDrag::region_going_away, this, _1), gui_context());
483 }
484
485 void
486 RegionDrag::region_going_away (RegionView* v)
487 {
488         list<DraggingView>::iterator i = _views.begin ();
489         while (i != _views.end() && i->view != v) {
490                 ++i;
491         }
492
493         if (i != _views.end()) {
494                 _views.erase (i);
495         }
496 }
497
498 /** Given a TimeAxisView, return the index of it into the _time_axis_views vector,
499  *  or -1 if it is not found.
500  */
501 int
502 RegionDrag::find_time_axis_view (TimeAxisView* t) const
503 {
504         int i = 0;
505         int const N = _time_axis_views.size ();
506         while (i < N && _time_axis_views[i] != t) {
507                 ++i;
508         }
509
510         if (i == N) {
511                 return -1;
512         }
513
514         return i;
515 }
516
517 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
518         : RegionDrag (e, i, p, v)
519         , _brushing (b)
520         , _total_x_delta (0)
521         , _last_pointer_time_axis_view (0)
522         , _last_pointer_layer (0)
523 {
524         DEBUG_TRACE (DEBUG::Drags, "New RegionMotionDrag\n");
525 }
526
527 void
528 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
529 {
530         Drag::start_grab (event, cursor);
531
532         show_verbose_cursor_time (_last_frame_position);
533
534         pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (current_pointer_y ());
535         if (tv.first) {
536                 _last_pointer_time_axis_view = find_time_axis_view (tv.first);
537                 _last_pointer_layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
538         }
539 }
540
541 double
542 RegionMotionDrag::compute_x_delta (GdkEvent const * event, framepos_t* pending_region_position)
543 {
544         /* compute the amount of pointer motion in frames, and where
545            the region would be if we moved it by that much.
546         */
547         *pending_region_position = adjusted_current_frame (event);
548
549         framepos_t sync_frame;
550         framecnt_t sync_offset;
551         int32_t sync_dir;
552
553         sync_offset = _primary->region()->sync_offset (sync_dir);
554
555         /* we don't handle a sync point that lies before zero.
556          */
557         if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
558
559                 sync_frame = *pending_region_position + (sync_dir*sync_offset);
560
561                 _editor->snap_to_with_modifier (sync_frame, event);
562
563                 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
564
565         } else {
566                 *pending_region_position = _last_frame_position;
567         }
568
569         if (*pending_region_position > max_framepos - _primary->region()->length()) {
570                 *pending_region_position = _last_frame_position;
571         }
572
573         double dx = 0;
574
575         /* in locked edit mode, reverse the usual meaning of _x_constrained */
576         bool const x_move_allowed = Config->get_edit_mode() == Lock ? _x_constrained : !_x_constrained;
577
578         if ((*pending_region_position != _last_frame_position) && x_move_allowed) {
579
580                 /* x movement since last time (in pixels) */
581                 dx = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->samples_per_pixel;
582
583                 /* total x movement */
584                 framecnt_t total_dx = *pending_region_position;
585                 if (regions_came_from_canvas()) {
586                         total_dx = total_dx - grab_frame ();
587                 }
588
589                 /* check that no regions have gone off the start of the session */
590                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
591                         if ((i->view->region()->position() + total_dx) < 0) {
592                                 dx = 0;
593                                 *pending_region_position = _last_frame_position;
594                                 break;
595                         }
596                 }
597
598         }
599
600         return dx;
601 }
602
603 bool
604 RegionMotionDrag::y_movement_allowed (int delta_track, double delta_layer) const
605 {
606         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
607                 int const n = i->time_axis_view + delta_track;
608                 if (n < 0 || n >= int (_time_axis_views.size())) {
609                         /* off the top or bottom track */
610                         return false;
611                 }
612
613                 RouteTimeAxisView const * to = dynamic_cast<RouteTimeAxisView const *> (_time_axis_views[n]);
614                 if (to == 0 || !to->is_track() || to->track()->data_type() != i->view->region()->data_type()) {
615                         /* not a track, or the wrong type */
616                         return false;
617                 }
618
619                 double const l = i->layer + delta_layer;
620
621                 /* Note that we allow layer to be up to 0.5 below zero, as this is used by `Expanded'
622                    mode to allow the user to place a region below another on layer 0.
623                 */
624                 if (delta_track == 0 && (l < -0.5 || l >= int (to->view()->layers()))) {
625                         /* Off the top or bottom layer; note that we only refuse if the track hasn't changed.
626                            If it has, the layers will be munged later anyway, so it's ok.
627                         */
628                         return false;
629                 }
630         }
631
632         /* all regions being dragged are ok with this change */
633         return true;
634 }
635
636 void
637 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
638 {
639         double delta_layer = 0;
640         int delta_time_axis_view = 0;
641
642         assert (!_views.empty ());
643
644         /* Note: time axis views in this method are often expressed as an index into the _time_axis_views vector */
645
646         /* Find the TimeAxisView that the pointer is now over */
647         pair<TimeAxisView*, double> const r = _editor->trackview_by_y_position (current_pointer_y ());
648         TimeAxisView* tv = r.first;
649
650         if (tv && tv->view()) {
651                 double layer = r.second;
652
653                 if (first_move && tv->view()->layer_display() == Stacked) {
654                         tv->view()->set_layer_display (Expanded);
655                 }
656
657                 /* Here's the current pointer position in terms of time axis view and layer */
658                 int const current_pointer_time_axis_view = find_time_axis_view (tv);
659                 double const current_pointer_layer = tv->layer_display() == Overlaid ? 0 : layer;
660                 
661                 /* Work out the change in y */
662
663                 delta_time_axis_view = current_pointer_time_axis_view - _last_pointer_time_axis_view;
664                 delta_layer = current_pointer_layer - _last_pointer_layer;
665         } 
666         
667         /* Work out the change in x */
668         framepos_t pending_region_position;
669         double const x_delta = compute_x_delta (event, &pending_region_position);
670         _last_frame_position = pending_region_position;
671
672         /* Verify change in y */
673         if (!y_movement_allowed (delta_time_axis_view, delta_layer)) {
674                 /* this y movement is not allowed, so do no y movement this time */
675                 delta_time_axis_view = 0;
676                 delta_layer = 0;
677         }
678
679         if (x_delta == 0 && (tv && tv->view() && delta_time_axis_view == 0) && delta_layer == 0 && !first_move) {
680                 /* haven't reached next snap point, and we're not switching
681                    trackviews nor layers. nothing to do.
682                 */
683                 return;
684         }
685
686         pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
687
688         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
689
690                 RegionView* rv = i->view;
691
692                 if (rv->region()->locked() || rv->region()->video_locked()) {
693                         continue;
694                 }
695
696                 if (first_move) {
697                         rv->drag_start (); 
698
699                         /* reparent the regionview into a group above all
700                          * others
701                          */
702                         
703                         ArdourCanvas::Item* rvg = rv->get_canvas_group();
704                         Duple rv_canvas_offset = rvg->parent()->canvas_origin ();
705                         Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
706                         rv->get_canvas_group()->reparent (_editor->_drag_motion_group);
707                         /* move the item so that it continues to appear at the
708                            same location now that its parent has changed.
709                         */
710                         rvg->move (rv_canvas_offset - dmg_canvas_offset);
711                 }
712
713                 /* If we have moved tracks, we'll fudge the layer delta so that the
714                    region gets moved back onto layer 0 on its new track; this avoids
715                    confusion when dragging regions from non-zero layers onto different
716                    tracks.
717                 */
718                 double this_delta_layer = delta_layer;
719                 if (delta_time_axis_view != 0) {
720                         this_delta_layer = - i->layer;
721                 }
722
723                 if (tv) {
724
725                         int track_index;
726                         
727                         if (i->time_axis_view >= 0) {
728                                 track_index = i->time_axis_view + delta_time_axis_view;
729                         } else {
730                                 track_index = _time_axis_views.size() - 1 + delta_time_axis_view;
731                         }
732                          
733                         if (track_index < 0 || track_index >= (int) _time_axis_views.size()) {
734                                 continue;
735                         }
736
737                         /* The TimeAxisView that this region is now over */
738                         TimeAxisView* current_tv = _time_axis_views[track_index];
739
740                         /* Ensure it is moved from stacked -> expanded if appropriate */
741                         if (current_tv->view()->layer_display() == Stacked) {
742                                 current_tv->view()->set_layer_display (Expanded);
743                         }
744                 
745                         /* We're only allowed to go -ve in layer on Expanded views */
746                         if (current_tv->view()->layer_display() != Expanded && (i->layer + this_delta_layer) < 0) {
747                                 this_delta_layer = - i->layer;
748                         }
749                 
750                         /* Set height */
751                         rv->set_height (current_tv->view()->child_height ());
752                 
753                         /* Update show/hidden status as the region view may have come from a hidden track,
754                            or have moved to one.
755                         */
756                         if (current_tv->hidden ()) {
757                                 rv->get_canvas_group()->hide ();
758                         } else {
759                                 rv->get_canvas_group()->show ();
760                         }
761
762                         /* Update the DraggingView */
763                         i->time_axis_view = track_index;
764                         i->layer += this_delta_layer;
765
766                         if (_brushing) {
767                                 _editor->mouse_brush_insert_region (rv, pending_region_position);
768                         } else {
769                                 Duple track_origin;
770
771                                 /* Get the y coordinate of the top of the track that this region is now over */
772                                 track_origin = current_tv->canvas_display()->item_to_canvas (track_origin);
773                                 
774                                 /* And adjust for the layer that it should be on */
775                                 StreamView* cv = current_tv->view ();
776                                 switch (cv->layer_display ()) {
777                                 case Overlaid:
778                                         break;
779                                 case Stacked:
780                                         track_origin.y += (cv->layers() - i->layer - 1) * cv->child_height ();
781                                         break;
782                                 case Expanded:
783                                         track_origin.y += (cv->layers() - i->layer - 0.5) * 2 * cv->child_height ();
784                                         break;
785                                 }
786
787                                 /* need to get the parent of the regionview
788                                  * canvas group and get its position in
789                                  * equivalent coordinate space as the trackview
790                                  * we are now dragging over.
791                                  */
792                                 
793                                 /* Now move the region view */
794                                 rv->move (x_delta, track_origin.y - rv->get_canvas_group()->canvas_origin().y);
795                         }
796                 } else {
797
798                         /* Only move the region into the empty dropzone at the bottom if the pointer
799                          * is down there.
800                          */
801
802                         if (current_pointer_y() >= 0) {
803                                 
804                                 Coord last_track_bottom_edge;
805                                 if (!_time_axis_views.empty()) {
806                                         TimeAxisView* last = _time_axis_views.back();
807                                         last_track_bottom_edge = last->canvas_display()->canvas_origin ().y + last->effective_height();
808                                 } else {
809                                         last_track_bottom_edge = 0;
810                                 }
811
812                                 rv->move (x_delta, last_track_bottom_edge - rv->get_canvas_group()->canvas_origin().y);
813                                 i->time_axis_view = -1;
814                         }
815                 }
816                 
817         } /* foreach region */
818
819         _total_x_delta += x_delta;
820
821         if (x_delta != 0 && !_brushing) {
822                 show_verbose_cursor_time (_last_frame_position);
823         }
824
825         _last_pointer_time_axis_view += delta_time_axis_view;
826         _last_pointer_layer += delta_layer;
827 }
828
829 void
830 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
831 {
832         if (_copy && first_move) {
833
834                 /* duplicate the regionview(s) and region(s) */
835
836                 list<DraggingView> new_regionviews;
837
838                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
839
840                         RegionView* rv = i->view;
841                         AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
842                         MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
843
844                         const boost::shared_ptr<const Region> original = rv->region();
845                         boost::shared_ptr<Region> region_copy = RegionFactory::create (original, true);
846                         region_copy->set_position (original->position());
847
848                         RegionView* nrv;
849                         if (arv) {
850                                 boost::shared_ptr<AudioRegion> audioregion_copy
851                                 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
852
853                                 nrv = new AudioRegionView (*arv, audioregion_copy);
854                         } else if (mrv) {
855                                 boost::shared_ptr<MidiRegion> midiregion_copy
856                                         = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
857                                 nrv = new MidiRegionView (*mrv, midiregion_copy);
858                         } else {
859                                 continue;
860                         }
861
862                         nrv->get_canvas_group()->show ();
863                         new_regionviews.push_back (DraggingView (nrv, this, i->initial_time_axis_view));
864
865                         /* swap _primary to the copy */
866
867                         if (rv == _primary) {
868                                 _primary = nrv;
869                         }
870
871                         /* ..and deselect the one we copied */
872
873                         rv->set_selected (false);
874                 }
875
876                 if (!new_regionviews.empty()) {
877
878                         /* reflect the fact that we are dragging the copies */
879
880                         _views = new_regionviews;
881
882                         swap_grab (new_regionviews.front().view->get_canvas_group (), 0, event ? event->motion.time : 0);
883                 }
884         }
885
886         RegionMotionDrag::motion (event, first_move);
887 }
888
889 void
890 RegionMotionDrag::finished (GdkEvent *, bool)
891 {
892         for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
893                 if (!(*i)->view()) {
894                         continue;
895                 }
896
897                 if ((*i)->view()->layer_display() == Expanded) {
898                         (*i)->view()->set_layer_display (Stacked);
899                 }
900         }
901 }
902
903 void
904 RegionMoveDrag::finished (GdkEvent* ev, bool movement_occurred)
905 {
906         RegionMotionDrag::finished (ev, movement_occurred);
907         
908         if (!movement_occurred) {
909                 
910                 /* just a click */
911
912                 if (was_double_click() && !_views.empty()) {
913                         DraggingView dv = _views.front();
914                         dv.view->show_region_editor ();
915                         
916                 }
917
918                 return;
919         }
920
921         /* reverse this here so that we have the correct logic to finalize
922            the drag.
923         */
924
925         if (Config->get_edit_mode() == Lock) {
926                 _x_constrained = !_x_constrained;
927         }
928
929         assert (!_views.empty ());
930
931         /* We might have hidden region views so that they weren't visible during the drag
932            (when they have been reparented).  Now everything can be shown again, as region
933            views are back in their track parent groups.
934         */
935         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
936                 i->view->get_canvas_group()->show ();
937         }
938         
939         bool const changed_position = (_last_frame_position != _primary->region()->position());
940         bool const changed_tracks = (_time_axis_views[_views.front().time_axis_view] != &_views.front().view->get_time_axis_view());
941         framecnt_t const drag_delta = _primary->region()->position() - _last_frame_position;
942         
943         if (_copy) {
944
945                 finished_copy (
946                         changed_position,
947                         changed_tracks,
948                         drag_delta
949                         );
950
951         } else {
952
953                 finished_no_copy (
954                         changed_position,
955                         changed_tracks,
956                         drag_delta
957                         );
958
959         }
960
961         _editor->maybe_locate_with_edit_preroll (_editor->get_selection().regions.start());
962 }
963
964 RouteTimeAxisView*
965 RegionMoveDrag::create_destination_time_axis (boost::shared_ptr<Region> region, TimeAxisView* original)
966 {                       
967         /* Add a new track of the correct type, and return the RouteTimeAxisView that is created to display the
968            new track.
969          */
970                         
971         try {
972                 if (boost::dynamic_pointer_cast<AudioRegion> (region)) {
973                         list<boost::shared_ptr<AudioTrack> > audio_tracks;
974                         audio_tracks = _editor->session()->new_audio_track (region->n_channels(), region->n_channels(), ARDOUR::Normal, 0, 1, region->name());
975                         RouteTimeAxisView* rtav = _editor->axis_view_from_route (audio_tracks.front());
976                         if (rtav) {
977                                 rtav->set_height (original->current_height());
978                         }
979                         return rtav;
980                 } else {
981                         ChanCount one_midi_port (DataType::MIDI, 1);
982                         list<boost::shared_ptr<MidiTrack> > midi_tracks;
983                         midi_tracks = _editor->session()->new_midi_track (one_midi_port, one_midi_port, boost::shared_ptr<ARDOUR::PluginInfo>(), ARDOUR::Normal, 0, 1, region->name());
984                         RouteTimeAxisView* rtav = _editor->axis_view_from_route (midi_tracks.front());
985                         if (rtav) {
986                                 rtav->set_height (original->current_height());
987                         }
988                         return rtav;
989                 }                                               
990         } catch (...) {
991                 error << _("Could not create new track after region placed in the drop zone") << endmsg;
992                 return 0;
993         }
994 }
995
996 void
997 RegionMoveDrag::finished_copy (bool const changed_position, bool const /*changed_tracks*/, framecnt_t const drag_delta)
998 {
999         RegionSelection new_views;
1000         PlaylistSet modified_playlists;
1001         RouteTimeAxisView* new_time_axis_view = 0;      
1002
1003         if (_brushing) {
1004                 /* all changes were made during motion event handlers */
1005
1006                 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
1007                         delete i->view;
1008                 }
1009
1010                 _editor->commit_reversible_command ();
1011                 return;
1012         }
1013
1014         if (_x_constrained) {
1015                 _editor->begin_reversible_command (Operations::fixed_time_region_copy);
1016         } else {
1017                 _editor->begin_reversible_command (Operations::region_copy);
1018         }
1019
1020         /* insert the regions into their new playlists */
1021         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end();) {
1022
1023                 RouteTimeAxisView* dest_rtv = 0;
1024
1025                 if (i->view->region()->locked() || i->view->region()->video_locked()) {
1026                         continue;
1027                 }
1028
1029                 framepos_t where;
1030
1031                 if (changed_position && !_x_constrained) {
1032                         where = i->view->region()->position() - drag_delta;
1033                 } else {
1034                         where = i->view->region()->position();
1035                 }
1036                 
1037                 if (i->time_axis_view < 0) {
1038                         if (!new_time_axis_view) {
1039                                 new_time_axis_view = create_destination_time_axis (i->view->region(), i->initial_time_axis_view);
1040                         }
1041                         dest_rtv = new_time_axis_view;
1042                 } else {
1043                         dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
1044                 }               
1045                 
1046                 if (dest_rtv != 0) {
1047                         RegionView* new_view = insert_region_into_playlist (i->view->region(), dest_rtv, i->layer, where, modified_playlists);
1048                         if (new_view != 0) {
1049                                 new_views.push_back (new_view);
1050                         }
1051                 }
1052         
1053                 /* Delete the copy of the view that was used for dragging. Need to play safe with the iterator
1054                    since deletion will automagically remove it from _views, thus invalidating i as an iterator.
1055                  */
1056
1057                 list<DraggingView>::const_iterator next = i;
1058                 ++next;
1059                 delete i->view;
1060                 i = next;
1061         }
1062
1063         /* If we've created new regions either by copying or moving
1064            to a new track, we want to replace the old selection with the new ones
1065         */
1066
1067         if (new_views.size() > 0) {
1068                 _editor->selection->set (new_views);
1069         }
1070
1071         /* write commands for the accumulated diffs for all our modified playlists */
1072         add_stateful_diff_commands_for_playlists (modified_playlists);
1073
1074         _editor->commit_reversible_command ();
1075 }
1076
1077 void
1078 RegionMoveDrag::finished_no_copy (
1079         bool const changed_position,
1080         bool const changed_tracks,
1081         framecnt_t const drag_delta
1082         )
1083 {
1084         RegionSelection new_views;
1085         PlaylistSet modified_playlists;
1086         PlaylistSet frozen_playlists;
1087         set<RouteTimeAxisView*> views_to_update;
1088         RouteTimeAxisView* new_time_axis_view = 0;
1089
1090         if (_brushing) {
1091                 /* all changes were made during motion event handlers */
1092                 _editor->commit_reversible_command ();
1093                 return;
1094         }
1095
1096         if (_x_constrained) {
1097                 _editor->begin_reversible_command (_("fixed time region drag"));
1098         } else {
1099                 _editor->begin_reversible_command (Operations::region_drag);
1100         }
1101
1102         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ) {
1103
1104                 RegionView* rv = i->view;
1105                 RouteTimeAxisView* dest_rtv = 0;
1106
1107                 if (rv->region()->locked() || rv->region()->video_locked()) {
1108                         ++i;
1109                         continue;
1110                 }
1111                 
1112                 if (i->time_axis_view < 0) {
1113                         if (!new_time_axis_view) {
1114                                 new_time_axis_view = create_destination_time_axis (rv->region(), i->initial_time_axis_view);
1115                         }
1116                         dest_rtv = new_time_axis_view;
1117                 } else {
1118                         dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[i->time_axis_view]);
1119                 }
1120                         
1121                 assert (dest_rtv);
1122
1123                 double const dest_layer = i->layer;
1124                 
1125                 views_to_update.insert (dest_rtv);
1126
1127                 framepos_t where;
1128
1129                 if (changed_position && !_x_constrained) {
1130                         where = rv->region()->position() - drag_delta;
1131                 } else {
1132                         where = rv->region()->position();
1133                 }
1134
1135                 if (changed_tracks) {
1136
1137                         /* insert into new playlist */
1138
1139                         RegionView* new_view = insert_region_into_playlist (
1140                                 RegionFactory::create (rv->region (), true), dest_rtv, dest_layer, where, modified_playlists
1141                                 );
1142
1143                         if (new_view == 0) {
1144                                 ++i;
1145                                 continue;
1146                         }
1147
1148                         new_views.push_back (new_view);
1149
1150                         /* remove from old playlist */
1151
1152                         /* the region that used to be in the old playlist is not
1153                            moved to the new one - we use a copy of it. as a result,
1154                            any existing editor for the region should no longer be
1155                            visible.
1156                         */
1157                         rv->hide_region_editor();
1158
1159
1160                         remove_region_from_playlist (rv->region(), i->initial_playlist, modified_playlists);
1161
1162                 } else {
1163
1164                         boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1165
1166                         /* this movement may result in a crossfade being modified, or a layering change,
1167                            so we need to get undo data from the playlist as well as the region.
1168                         */
1169
1170                         pair<PlaylistSet::iterator, bool> r = modified_playlists.insert (playlist);
1171                         if (r.second) {
1172                                 playlist->clear_changes ();
1173                         }
1174
1175                         rv->region()->clear_changes ();
1176
1177                         /*
1178                            motion on the same track. plonk the previously reparented region
1179                            back to its original canvas group (its streamview).
1180                            No need to do anything for copies as they are fake regions which will be deleted.
1181                         */
1182
1183                         rv->get_canvas_group()->reparent (dest_rtv->view()->canvas_item());
1184                         rv->get_canvas_group()->set_y_position (i->initial_y);
1185                         rv->drag_end ();
1186
1187                         /* just change the model */
1188                         if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
1189                                 playlist->set_layer (rv->region(), dest_layer);
1190                         }
1191
1192                         /* freeze playlist to avoid lots of relayering in the case of a multi-region drag */
1193
1194                         r = frozen_playlists.insert (playlist);
1195
1196                         if (r.second) {
1197                                 playlist->freeze ();
1198                         }
1199
1200                         rv->region()->set_position (where);
1201
1202                         _editor->session()->add_command (new StatefulDiffCommand (rv->region()));
1203                 }
1204
1205                 if (changed_tracks) {
1206
1207                         /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1208                            was selected in all of them, then removing it from a playlist will have removed all
1209                            trace of it from _views (i.e. there were N regions selected, we removed 1,
1210                            but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1211                            corresponding regionview, and _views is now empty).
1212
1213                            This could have invalidated any and all iterators into _views.
1214
1215                            The heuristic we use here is: if the region selection is empty, break out of the loop
1216                            here. if the region selection is not empty, then restart the loop because we know that
1217                            we must have removed at least the region(view) we've just been working on as well as any
1218                            that we processed on previous iterations.
1219
1220                            EXCEPT .... if we are doing a copy drag, then _views hasn't been modified and
1221                            we can just iterate.
1222                         */
1223
1224
1225                         if (_views.empty()) {
1226                                 break;
1227                         } else {
1228                                 i = _views.begin();
1229                         }
1230
1231                 } else {
1232                         ++i;
1233                 }
1234         }
1235
1236         /* If we've created new regions either by copying or moving
1237            to a new track, we want to replace the old selection with the new ones
1238         */
1239
1240         if (new_views.size() > 0) {
1241                 _editor->selection->set (new_views);
1242         }
1243
1244         for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1245                 (*p)->thaw();
1246         }
1247
1248         /* write commands for the accumulated diffs for all our modified playlists */
1249         add_stateful_diff_commands_for_playlists (modified_playlists);
1250
1251         _editor->commit_reversible_command ();
1252
1253         /* We have futzed with the layering of canvas items on our streamviews.
1254            If any region changed layer, this will have resulted in the stream
1255            views being asked to set up their region views, and all will be well.
1256            If not, we might now have badly-ordered region views.  Ask the StreamViews
1257            involved to sort themselves out, just in case.
1258         */
1259
1260         for (set<RouteTimeAxisView*>::iterator i = views_to_update.begin(); i != views_to_update.end(); ++i) {
1261                 (*i)->view()->playlist_layered ((*i)->track ());
1262         }
1263 }
1264
1265 /** Remove a region from a playlist, clearing the diff history of the playlist first if necessary.
1266  *  @param region Region to remove.
1267  *  @param playlist playlist To remove from.
1268  *  @param modified_playlists The playlist will be added to this if it is not there already; used to ensure
1269  *  that clear_changes () is only called once per playlist.
1270  */
1271 void
1272 RegionMoveDrag::remove_region_from_playlist (
1273         boost::shared_ptr<Region> region,
1274         boost::shared_ptr<Playlist> playlist,
1275         PlaylistSet& modified_playlists
1276         )
1277 {
1278         pair<set<boost::shared_ptr<Playlist> >::iterator, bool> r = modified_playlists.insert (playlist);
1279
1280         if (r.second) {
1281                 playlist->clear_changes ();
1282         }
1283
1284         playlist->remove_region (region); // should be no need to ripple; we better already have rippled the playlist in RegionRippleDrag
1285 }
1286
1287
1288 /** Insert a region into a playlist, handling the recovery of the resulting new RegionView, and
1289  *  clearing the playlist's diff history first if necessary.
1290  *  @param region Region to insert.
1291  *  @param dest_rtv Destination RouteTimeAxisView.
1292  *  @param dest_layer Destination layer.
1293  *  @param where Destination position.
1294  *  @param modified_playlists The playlist will be added to this if it is not there already; used to ensure
1295  *  that clear_changes () is only called once per playlist.
1296  *  @return New RegionView, or 0 if no insert was performed.
1297  */
1298 RegionView *
1299 RegionMoveDrag::insert_region_into_playlist (
1300         boost::shared_ptr<Region> region,
1301         RouteTimeAxisView* dest_rtv,
1302         layer_t dest_layer,
1303         framecnt_t where,
1304         PlaylistSet& modified_playlists
1305         )
1306 {
1307         boost::shared_ptr<Playlist> dest_playlist = dest_rtv->playlist ();
1308         if (!dest_playlist) {
1309                 return 0;
1310         }
1311
1312         /* arrange to collect the new region view that will be created as a result of our playlist insertion */
1313         _new_region_view = 0;
1314         sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun (*this, &RegionMoveDrag::collect_new_region_view));
1315
1316         /* clear history for the playlist we are about to insert to, provided we haven't already done so */
1317         pair<PlaylistSet::iterator, bool> r = modified_playlists.insert (dest_playlist);
1318         if (r.second) {
1319                 dest_playlist->clear_changes ();
1320         }
1321
1322         dest_playlist->add_region (region, where);
1323
1324         if (dest_rtv->view()->layer_display() == Stacked || dest_rtv->view()->layer_display() == Expanded) {
1325                 dest_playlist->set_layer (region, dest_layer);
1326         }
1327
1328         c.disconnect ();
1329
1330         assert (_new_region_view);
1331
1332         return _new_region_view;
1333 }
1334
1335 void
1336 RegionMoveDrag::collect_new_region_view (RegionView* rv)
1337 {
1338         _new_region_view = rv;
1339 }
1340
1341 void
1342 RegionMoveDrag::add_stateful_diff_commands_for_playlists (PlaylistSet const & playlists)
1343 {
1344         for (PlaylistSet::const_iterator i = playlists.begin(); i != playlists.end(); ++i) {
1345                 StatefulDiffCommand* c = new StatefulDiffCommand (*i);
1346                 if (!c->empty()) {
1347                         _editor->session()->add_command (c);
1348                 } else {
1349                         delete c;
1350                 }
1351         }
1352 }
1353
1354
1355 void
1356 RegionMoveDrag::aborted (bool movement_occurred)
1357 {
1358         if (_copy) {
1359
1360                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1361                         delete i->view;
1362                 }
1363
1364                 _views.clear ();
1365
1366         } else {
1367                 RegionMotionDrag::aborted (movement_occurred);
1368         }
1369 }
1370
1371 void
1372 RegionMotionDrag::aborted (bool)
1373 {
1374         for (vector<TimeAxisView*>::iterator i = _time_axis_views.begin(); i != _time_axis_views.end(); ++i) {
1375
1376                 StreamView* sview = (*i)->view();
1377
1378                 if (sview) {
1379                         if (sview->layer_display() == Expanded) {
1380                                 sview->set_layer_display (Stacked);
1381                         }
1382                 }
1383         }
1384         
1385         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1386                 RegionView* rv = i->view;
1387                 TimeAxisView* tv = &(rv->get_time_axis_view ());
1388                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1389                 assert (rtv);
1390                 rv->get_canvas_group()->reparent (rtv->view()->canvas_item());
1391                 rv->get_canvas_group()->set_y_position (0);
1392                 rv->drag_end ();
1393                 rv->move (-_total_x_delta, 0);
1394                 rv->set_height (rtv->view()->child_height ());
1395         }
1396 }
1397
1398 /** @param b true to brush, otherwise false.
1399  *  @param c true to make copies of the regions being moved, otherwise false.
1400  */
1401 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1402         : RegionMotionDrag (e, i, p, v, b),
1403           _copy (c)
1404 {
1405         DEBUG_TRACE (DEBUG::Drags, "New RegionMoveDrag\n");
1406
1407         double speed = 1;
1408         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (&_primary->get_time_axis_view ());
1409         if (rtv && rtv->is_track()) {
1410                 speed = rtv->track()->speed ();
1411         }
1412
1413         _last_frame_position = static_cast<framepos_t> (_primary->region()->position() / speed);
1414 }
1415
1416 void
1417 RegionMoveDrag::setup_pointer_frame_offset ()
1418 {
1419         _pointer_frame_offset = raw_grab_frame() - _last_frame_position;
1420 }
1421
1422 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, framepos_t pos)
1423         : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1424 {
1425         DEBUG_TRACE (DEBUG::Drags, "New RegionInsertDrag\n");
1426
1427         assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1428                 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1429
1430         _primary = v->view()->create_region_view (r, false, false);
1431
1432         _primary->get_canvas_group()->show ();
1433         _primary->set_position (pos, 0);
1434         _views.push_back (DraggingView (_primary, this, v));
1435
1436         _last_frame_position = pos;
1437
1438         _item = _primary->get_canvas_group ();
1439 }
1440
1441 void
1442 RegionInsertDrag::finished (GdkEvent *, bool)
1443 {
1444         RouteTimeAxisView* dest_rtv = dynamic_cast<RouteTimeAxisView*> (_time_axis_views[_views.front().time_axis_view]);
1445
1446         _primary->get_canvas_group()->reparent (dest_rtv->view()->canvas_item());
1447         _primary->get_canvas_group()->set_y_position (0);
1448
1449         boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1450
1451         _editor->begin_reversible_command (Operations::insert_region);
1452         playlist->clear_changes ();
1453         playlist->add_region (_primary->region (), _last_frame_position);
1454
1455         // Mixbus doesn't seem to ripple when inserting regions from the list: should we? yes, probably
1456         if (Config->get_edit_mode() == Ripple) {
1457                 playlist->ripple (_last_frame_position, _primary->region()->length(), _primary->region());
1458         }
1459
1460         _editor->session()->add_command (new StatefulDiffCommand (playlist));
1461         _editor->commit_reversible_command ();
1462
1463         delete _primary;
1464         _primary = 0;
1465         _views.clear ();
1466 }
1467
1468 void
1469 RegionInsertDrag::aborted (bool)
1470 {
1471         delete _primary;
1472         _primary = 0;
1473         _views.clear ();
1474 }
1475
1476 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1477         : RegionMoveDrag (e, i, p, v, false, false)
1478 {
1479         DEBUG_TRACE (DEBUG::Drags, "New RegionSpliceDrag\n");
1480 }
1481
1482 struct RegionSelectionByPosition {
1483     bool operator() (RegionView*a, RegionView* b) {
1484             return a->region()->position () < b->region()->position();
1485     }
1486 };
1487
1488 void
1489 RegionSpliceDrag::motion (GdkEvent* event, bool)
1490 {
1491         /* Which trackview is this ? */
1492
1493         pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1494         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1495
1496         /* The region motion is only processed if the pointer is over
1497            an audio track.
1498         */
1499
1500         if (!tv || !tv->is_track()) {
1501                 /* To make sure we hide the verbose canvas cursor when the mouse is
1502                    not held over an audio track.
1503                 */
1504                 _editor->verbose_cursor()->hide ();
1505                 return;
1506         } else {
1507                 _editor->verbose_cursor()->show ();
1508         }
1509
1510         int dir;
1511
1512         if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1513                 dir = 1;
1514         } else {
1515                 dir = -1;
1516         }
1517
1518         RegionSelection copy;
1519         _editor->selection->regions.by_position(copy);
1520
1521         framepos_t const pf = adjusted_current_frame (event);
1522
1523         for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1524
1525                 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1526
1527                 if (!atv) {
1528                         continue;
1529                 }
1530
1531                 boost::shared_ptr<Playlist> playlist;
1532
1533                 if ((playlist = atv->playlist()) == 0) {
1534                         continue;
1535                 }
1536
1537                 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1538                         continue;
1539                 }
1540
1541                 if (dir > 0) {
1542                         if (pf < (*i)->region()->last_frame() + 1) {
1543                                 continue;
1544                         }
1545                 } else {
1546                         if (pf > (*i)->region()->first_frame()) {
1547                                 continue;
1548                         }
1549                 }
1550
1551
1552                 playlist->shuffle ((*i)->region(), dir);
1553         }
1554 }
1555
1556 void
1557 RegionSpliceDrag::finished (GdkEvent* event, bool movement_occurred)
1558 {
1559         RegionMoveDrag::finished (event, movement_occurred);
1560 }
1561
1562 void
1563 RegionSpliceDrag::aborted (bool)
1564 {
1565         /* XXX: TODO */
1566 }
1567
1568 /***
1569  * ripple mode...
1570  */
1571
1572 void
1573 RegionRippleDrag::add_all_after_to_views(TimeAxisView *tav, framepos_t where, const RegionSelection &exclude, bool drag_in_progress)
1574 {
1575
1576         boost::shared_ptr<RegionList> rl = tav->playlist()->regions_with_start_within (Evoral::Range<framepos_t>(where, max_framepos));
1577
1578         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*>(tav);
1579         RegionSelection to_ripple;
1580         for (RegionList::iterator i = rl->begin(); i != rl->end(); ++i) {
1581                 if ((*i)->position() >= where) {
1582                         to_ripple.push_back (rtv->view()->find_view(*i));
1583                 }
1584         }
1585
1586         for (RegionSelection::iterator i = to_ripple.begin(); i != to_ripple.end(); ++i) {
1587                 if (!exclude.contains (*i)) {
1588                         // the selection has already been added to _views
1589
1590                         if (drag_in_progress) {
1591                                 // do the same things that RegionMotionDrag::motion does when
1592                                 // first_move is true, for the region views that we're adding
1593                                 // to _views this time
1594
1595                                 (*i)->drag_start();
1596                                 ArdourCanvas::Item* rvg = (*i)->get_canvas_group();
1597                                 Duple rv_canvas_offset = rvg->item_to_canvas (Duple (0,0));
1598                                 Duple dmg_canvas_offset = _editor->_drag_motion_group->canvas_origin ();
1599                                 rvg->reparent (_editor->_drag_motion_group);
1600
1601                                 // we only need to move in the y direction
1602                                 Duple fudge = rv_canvas_offset - dmg_canvas_offset;
1603                                 fudge.x = 0;
1604                                 rvg->move (fudge);
1605
1606                         }
1607                         _views.push_back (DraggingView (*i, this, tav));
1608                 }
1609         }
1610 }
1611
1612 void
1613 RegionRippleDrag::remove_unselected_from_views(framecnt_t amount, bool move_regions)
1614 {
1615
1616         for (std::list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ) {
1617                 // we added all the regions after the selection 
1618
1619                 std::list<DraggingView>::iterator to_erase = i++;
1620                 if (!_editor->selection->regions.contains (to_erase->view)) {
1621                         // restore the non-selected regions to their original playlist & positions,
1622                         // and then ripple them back by the length of the regions that were dragged away
1623                         // do the same things as RegionMotionDrag::aborted
1624
1625                         RegionView *rv = to_erase->view;
1626                         TimeAxisView* tv = &(rv->get_time_axis_view ());
1627                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1628                         assert (rtv);
1629
1630                         // plonk them back onto their own track
1631                         rv->get_canvas_group()->reparent(rtv->view()->canvas_item());
1632                         rv->get_canvas_group()->set_y_position (0);
1633                         rv->drag_end ();
1634
1635                         if (move_regions) {
1636                                 // move the underlying region to match the view
1637                                 rv->region()->set_position (rv->region()->position() + amount);
1638                         } else {
1639                                 // restore the view to match the underlying region's original position
1640                                 rv->move(-amount, 0);   // second parameter is y delta - seems 0 is OK
1641                         }
1642
1643                         rv->set_height (rtv->view()->child_height ());
1644                         _views.erase (to_erase);
1645                 }
1646         }
1647 }
1648
1649 bool
1650 RegionRippleDrag::y_movement_allowed (int delta_track, double delta_layer) const
1651 {
1652         if (RegionMotionDrag::y_movement_allowed (delta_track, delta_layer)) {
1653                 if (delta_track) {
1654                         return allow_moves_across_tracks;
1655                 } else {
1656                         return true;
1657                 }
1658         }
1659         return false;
1660 }
1661
1662 RegionRippleDrag::RegionRippleDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1663         : RegionMoveDrag (e, i, p, v, false, false)
1664 {
1665         DEBUG_TRACE (DEBUG::Drags, "New RegionRippleDrag\n");
1666         // compute length of selection
1667         RegionSelection selected_regions = _editor->selection->regions;
1668         selection_length = selected_regions.end_frame() - selected_regions.start();
1669
1670         // we'll only allow dragging to another track in ripple mode if all the regions
1671         // being dragged start off on the same track
1672         allow_moves_across_tracks = (selected_regions.playlists().size() == 1);
1673         prev_tav = NULL;
1674         prev_amount = 0;
1675         exclude = new RegionList;
1676         for (RegionSelection::iterator i =selected_regions.begin(); i != selected_regions.end(); ++i) {
1677                 exclude->push_back((*i)->region());
1678         }
1679
1680         // also add regions before start of selection to exclude, to be consistent with how Mixbus does ripple
1681         RegionSelection copy;
1682         selected_regions.by_position(copy); // get selected regions sorted by position into copy
1683
1684         std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = copy.playlists();
1685         std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
1686
1687         for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
1688                 // find ripple start point on each applicable playlist
1689                 RegionView *first_selected_on_this_track = NULL;
1690                 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1691                         if ((*i)->region()->playlist() == (*pi)) {
1692                                 // region is on this playlist - it's the first, because they're sorted
1693                                 first_selected_on_this_track = *i;
1694                                 break;
1695                         }
1696                 }
1697                 assert (first_selected_on_this_track); // we should always find the region in one of the playlists...
1698                 add_all_after_to_views (
1699                                 &first_selected_on_this_track->get_time_axis_view(),
1700                                 first_selected_on_this_track->region()->position(),
1701                                 selected_regions, false);
1702         }
1703
1704         if (allow_moves_across_tracks) {
1705                 orig_tav = &(*selected_regions.begin())->get_time_axis_view();
1706         } else {
1707                 orig_tav = NULL;
1708         }
1709
1710 }
1711
1712 void
1713 RegionRippleDrag::motion (GdkEvent* event, bool first_move)
1714 {
1715         /* Which trackview is this ? */
1716
1717         pair<TimeAxisView*, double> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1718         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1719
1720         /* The region motion is only processed if the pointer is over
1721            an audio track.
1722          */
1723
1724         if (!tv || !tv->is_track()) {
1725                 /* To make sure we hide the verbose canvas cursor when the mouse is
1726                    not held over an audiotrack.
1727                  */
1728                 _editor->verbose_cursor()->hide ();
1729                 return;
1730         }
1731
1732         framepos_t where = adjusted_current_frame (event);
1733         assert (where >= 0);
1734         framepos_t after;
1735         double delta = compute_x_delta (event, &after);
1736
1737         framecnt_t amount = _editor->pixel_to_sample (delta);
1738
1739         if (allow_moves_across_tracks) {
1740                 // all the originally selected regions were on the same track
1741
1742                 framecnt_t adjust = 0;
1743                 if (prev_tav && tv != prev_tav) {
1744                         // dragged onto a different track 
1745                         // remove the unselected regions from _views, restore them to their original positions
1746                         // and add the regions after the drop point on the new playlist to _views instead.
1747                         // undo the effect of rippling the previous playlist, and include the effect of removing
1748                         // the dragged region(s) from this track
1749
1750                         remove_unselected_from_views (prev_amount, false);
1751                         // ripple previous playlist according to the regions that have been removed onto the new playlist
1752                         prev_tav->playlist()->ripple(prev_position, -selection_length, exclude);
1753                         prev_amount = 0;
1754
1755                         // move just the selected regions
1756                         RegionMoveDrag::motion(event, first_move); 
1757
1758                         // ensure that the ripple operation on the new playlist inserts selection_length time 
1759                         adjust = selection_length;
1760                         // ripple the new current playlist
1761                         tv->playlist()->ripple (where, amount+adjust, exclude);
1762
1763                         // add regions after point where drag entered this track to subsequent ripples
1764                         add_all_after_to_views (tv, where, _editor->selection->regions, true);
1765
1766                 } else {
1767                         // motion on same track
1768                         RegionMoveDrag::motion(event, first_move); 
1769                 }
1770                 prev_tav = tv;
1771
1772                 // remember what we've done to this playlist so we can undo it if the selection is dragged to another track
1773                 prev_position = where;
1774         } else {
1775                 // selection encompasses multiple tracks - just drag
1776                 // cross-track drags are forbidden
1777                 RegionMoveDrag::motion(event, first_move); 
1778         }
1779
1780         if (!_x_constrained) {
1781                 prev_amount += amount;
1782         }
1783
1784         _last_frame_position = after;
1785 }
1786
1787 void
1788 RegionRippleDrag::finished (GdkEvent* event, bool movement_occurred)
1789 {
1790         if (!movement_occurred) {
1791                 return;
1792         }
1793
1794         _editor->begin_reversible_command(_("Ripple drag"));
1795         
1796         // remove the regions being rippled from the dragging view, updating them to 
1797         // their new positions
1798         remove_unselected_from_views (prev_amount, true);
1799
1800         if (allow_moves_across_tracks) {
1801                 if (orig_tav) {
1802                         // if regions were dragged across tracks, we've rippled any later
1803                         // regions on the track the regions were dragged off, so we need
1804                         // to add the original track to the undo record
1805                         orig_tav->playlist()->clear_changes();
1806                         vector<Command*> cmds;
1807                         orig_tav->playlist()->rdiff (cmds);
1808                         _editor->session()->add_commands (cmds);
1809                 }
1810                 if (prev_tav && prev_tav != orig_tav) {
1811                         prev_tav->playlist()->clear_changes();
1812                         vector<Command*> cmds;
1813                         prev_tav->playlist()->rdiff (cmds);
1814                         _editor->session()->add_commands (cmds);
1815                 }
1816         } else {
1817                 // selection spanned multiple tracks - all will need adding to undo record
1818
1819                 std::set<boost::shared_ptr<ARDOUR::Playlist> > playlists = _editor->selection->regions.playlists();
1820                 std::set<boost::shared_ptr<ARDOUR::Playlist> >::const_iterator pi;
1821
1822                 for (pi = playlists.begin(); pi != playlists.end(); ++pi) {
1823                         (*pi)->clear_changes();
1824                         vector<Command*> cmds;
1825                         (*pi)->rdiff (cmds);
1826                         _editor->session()->add_commands (cmds);
1827                 }
1828         }
1829
1830         // other modified playlists are added to undo by RegionMoveDrag::finished()
1831         RegionMoveDrag::finished (event, movement_occurred);
1832         _editor->commit_reversible_command();
1833 }
1834
1835 void
1836 RegionRippleDrag::aborted (bool movement_occurred)
1837 {
1838         RegionMoveDrag::aborted (movement_occurred);
1839         _views.clear ();
1840 }
1841
1842
1843 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1844         : Drag (e, i),
1845           _view (dynamic_cast<MidiTimeAxisView*> (v))
1846 {
1847         DEBUG_TRACE (DEBUG::Drags, "New RegionCreateDrag\n");
1848
1849         assert (_view);
1850 }
1851
1852 void
1853 RegionCreateDrag::motion (GdkEvent* event, bool first_move)
1854 {
1855         if (first_move) {
1856                 _region = add_midi_region (_view);
1857                 _view->playlist()->freeze ();
1858         } else {
1859                 if (_region) {
1860                         framepos_t const f = adjusted_current_frame (event);
1861                         if (f < grab_frame()) {
1862                                 _region->set_position (f);
1863                         }
1864
1865                         /* Don't use a zero-length region, and subtract 1 frame from the snapped length
1866                            so that if this region is duplicated, its duplicate starts on
1867                            a snap point rather than 1 frame after a snap point.  Otherwise things get
1868                            a bit confusing as if a region starts 1 frame after a snap point, one cannot
1869                            place snapped notes at the start of the region.
1870                         */
1871
1872                         framecnt_t const len = (framecnt_t) fabs ((double)(f - grab_frame () - 1));
1873                         _region->set_length (len < 1 ? 1 : len);
1874                 }
1875         }
1876 }
1877
1878 void
1879 RegionCreateDrag::finished (GdkEvent*, bool movement_occurred)
1880 {
1881         if (!movement_occurred) {
1882                 add_midi_region (_view);
1883         } else {
1884                 _view->playlist()->thaw ();
1885         }
1886 }
1887
1888 void
1889 RegionCreateDrag::aborted (bool)
1890 {
1891         if (_region) {
1892                 _view->playlist()->thaw ();
1893         }
1894
1895         /* XXX */
1896 }
1897
1898 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1899         : Drag (e, i)
1900         , region (0)
1901 {
1902         DEBUG_TRACE (DEBUG::Drags, "New NoteResizeDrag\n");
1903 }
1904
1905 void
1906 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*ignored*/)
1907 {
1908         Gdk::Cursor* cursor;
1909         NoteBase* cnote = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
1910         assert (cnote);
1911         float x_fraction = cnote->mouse_x_fraction ();
1912
1913         if (x_fraction > 0.0 && x_fraction < 0.25) {
1914                 cursor = _editor->cursors()->left_side_trim;
1915         } else  {
1916                 cursor = _editor->cursors()->right_side_trim;
1917         }
1918
1919         Drag::start_grab (event, cursor);
1920
1921         region = &cnote->region_view();
1922
1923         double const region_start = region->get_position_pixels();
1924         double const middle_point = region_start + cnote->x0() + (cnote->x1() - cnote->x0()) / 2.0L;
1925
1926         if (grab_x() <= middle_point) {
1927                 cursor = _editor->cursors()->left_side_trim;
1928                 at_front = true;
1929         } else {
1930                 cursor = _editor->cursors()->right_side_trim;
1931                 at_front = false;
1932         }
1933
1934         _item->grab ();
1935
1936         if (event->motion.state & Keyboard::PrimaryModifier) {
1937                 relative = false;
1938         } else {
1939                 relative = true;
1940         }
1941
1942         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1943
1944         if (ms.size() > 1) {
1945                 /* has to be relative, may make no sense otherwise */
1946                 relative = true;
1947         }
1948
1949         /* select this note; if it is already selected, preserve the existing selection,
1950            otherwise make this note the only one selected.
1951         */
1952         region->note_selected (cnote, cnote->selected ());
1953
1954         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1955                 MidiRegionSelection::iterator next;
1956                 next = r;
1957                 ++next;
1958                 (*r)->begin_resizing (at_front);
1959                 r = next;
1960         }
1961 }
1962
1963 void
1964 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1965 {
1966         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1967         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1968                 NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
1969                 assert (nb);
1970                 (*r)->update_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
1971         }
1972 }
1973
1974 void
1975 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1976 {
1977         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1978         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1979                 NoteBase* nb = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
1980                 assert (nb);
1981                 (*r)->commit_resizing (nb, at_front, _drags->current_pointer_x() - grab_x(), relative);
1982         }
1983 }
1984
1985 void
1986 NoteResizeDrag::aborted (bool)
1987 {
1988         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1989         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1990                 (*r)->abort_resizing ();
1991         }
1992 }
1993
1994 AVDraggingView::AVDraggingView (RegionView* v)
1995         : view (v)
1996 {
1997         initial_position = v->region()->position ();
1998 }
1999
2000 VideoTimeLineDrag::VideoTimeLineDrag (Editor* e, ArdourCanvas::Item* i)
2001         : Drag (e, i)
2002 {
2003         DEBUG_TRACE (DEBUG::Drags, "New VideoTimeLineDrag\n");
2004
2005         RegionSelection rs;
2006         TrackViewList empty;
2007         empty.clear();
2008         _editor->get_regions_after(rs, (framepos_t) 0, empty);
2009         std::list<RegionView*> views = rs.by_layer();
2010
2011         for (list<RegionView*>::iterator i = views.begin(); i != views.end(); ++i) {
2012                 RegionView* rv = (*i);
2013                 if (!rv->region()->video_locked()) {
2014                         continue;
2015                 }
2016                 _views.push_back (AVDraggingView (rv));
2017         }
2018 }
2019
2020 void
2021 VideoTimeLineDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2022 {
2023         Drag::start_grab (event);
2024         if (_editor->session() == 0) {
2025                 return;
2026         }
2027
2028         _startdrag_video_offset=ARDOUR_UI::instance()->video_timeline->get_offset();
2029         _max_backwards_drag = (
2030                           ARDOUR_UI::instance()->video_timeline->get_duration()
2031                         + ARDOUR_UI::instance()->video_timeline->get_offset()
2032                         - ceil(ARDOUR_UI::instance()->video_timeline->get_apv())
2033                         );
2034
2035         for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2036                 if (i->initial_position < _max_backwards_drag || _max_backwards_drag < 0) {
2037                         _max_backwards_drag = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv (i->initial_position);
2038                 }
2039         }
2040         DEBUG_TRACE (DEBUG::Drags, string_compose("VideoTimeLineDrag: max backwards-drag: %1\n", _max_backwards_drag));
2041
2042         char buf[128];
2043         Timecode::Time timecode;
2044         _editor->session()->sample_to_timecode(abs(_startdrag_video_offset), timecode, true /* use_offset */, false /* use_subframes */ );
2045         snprintf (buf, sizeof (buf), "Video Start:\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32, (_startdrag_video_offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames);
2046         show_verbose_cursor_text (buf);
2047 }
2048
2049 void
2050 VideoTimeLineDrag::motion (GdkEvent* event, bool first_move)
2051 {
2052         if (_editor->session() == 0) {
2053                 return;
2054         }
2055         if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
2056                 return;
2057         }
2058
2059         framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame() + _pointer_frame_offset;
2060         dt = ARDOUR_UI::instance()->video_timeline->quantify_frames_to_apv(_startdrag_video_offset+dt) - _startdrag_video_offset;
2061
2062         if (_max_backwards_drag >= 0 && dt <= - _max_backwards_drag) {
2063                 dt = - _max_backwards_drag;
2064         }
2065
2066         ARDOUR_UI::instance()->video_timeline->set_offset(_startdrag_video_offset+dt);
2067         ARDOUR_UI::instance()->flush_videotimeline_cache(true);
2068
2069         for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2070                 RegionView* rv = i->view;
2071                 DEBUG_TRACE (DEBUG::Drags, string_compose("SHIFT REGION at %1 by %2\n", i->initial_position, dt));
2072                 if (first_move) {
2073                         rv->drag_start ();
2074                         rv->region()->clear_changes ();
2075                         rv->region()->suspend_property_changes();
2076                 }
2077                 rv->region()->set_position(i->initial_position + dt);
2078                 rv->region_changed(ARDOUR::Properties::position);
2079         }
2080
2081         const framepos_t offset = ARDOUR_UI::instance()->video_timeline->get_offset();
2082         Timecode::Time timecode;
2083         Timecode::Time timediff;
2084         char buf[128];
2085         _editor->session()->sample_to_timecode(abs(offset), timecode, true /* use_offset */, false /* use_subframes */ );
2086         _editor->session()->sample_to_timecode(abs(dt), timediff, false /* use_offset */, false /* use_subframes */ );
2087         snprintf (buf, sizeof (buf),
2088                         "%s\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32
2089                         "\n%s\n%c%02" PRId32 ":%02" PRId32 ":%02" PRId32 ":%02" PRId32
2090                         , _("Video Start:"),
2091                                 (offset<0?'-':' '), timecode.hours, timecode.minutes, timecode.seconds, timecode.frames
2092                         , _("Diff:"),
2093                                 (dt<0?'-':' '), timediff.hours, timediff.minutes, timediff.seconds, timediff.frames
2094                                 );
2095         show_verbose_cursor_text (buf);
2096 }
2097
2098 void
2099 VideoTimeLineDrag::finished (GdkEvent * /*event*/, bool movement_occurred)
2100 {
2101         if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
2102                 return;
2103         }
2104
2105         if (!movement_occurred || ! _editor->session()) {
2106                 return;
2107         }
2108
2109         ARDOUR_UI::instance()->flush_videotimeline_cache(true);
2110
2111         _editor->begin_reversible_command (_("Move Video"));
2112
2113         XMLNode &before = ARDOUR_UI::instance()->video_timeline->get_state();
2114         ARDOUR_UI::instance()->video_timeline->save_undo();
2115         XMLNode &after = ARDOUR_UI::instance()->video_timeline->get_state();
2116         _editor->session()->add_command(new MementoCommand<VideoTimeLine>(*(ARDOUR_UI::instance()->video_timeline), &before, &after));
2117
2118         for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2119                 i->view->drag_end();
2120                 i->view->region()->resume_property_changes ();
2121
2122                 _editor->session()->add_command (new StatefulDiffCommand (i->view->region()));
2123         }
2124
2125         _editor->session()->maybe_update_session_range(
2126                         std::max(ARDOUR_UI::instance()->video_timeline->get_offset(), (ARDOUR::frameoffset_t) 0),
2127                         std::max(ARDOUR_UI::instance()->video_timeline->get_offset() + ARDOUR_UI::instance()->video_timeline->get_duration(), (ARDOUR::frameoffset_t) 0)
2128                         );
2129
2130
2131         _editor->commit_reversible_command ();
2132 }
2133
2134 void
2135 VideoTimeLineDrag::aborted (bool)
2136 {
2137         if (ARDOUR_UI::instance()->video_timeline->is_offset_locked()) {
2138                 return;
2139         }
2140         ARDOUR_UI::instance()->video_timeline->set_offset(_startdrag_video_offset);
2141         ARDOUR_UI::instance()->flush_videotimeline_cache(true);
2142
2143         for (list<AVDraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2144                 i->view->region()->resume_property_changes ();
2145                 i->view->region()->set_position(i->initial_position);
2146         }
2147 }
2148
2149 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool preserve_fade_anchor)
2150         : RegionDrag (e, i, p, v)
2151         , _preserve_fade_anchor (preserve_fade_anchor)
2152         , _jump_position_when_done (false)
2153 {
2154         DEBUG_TRACE (DEBUG::Drags, "New TrimDrag\n");
2155 }
2156
2157 void
2158 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2159 {
2160         double speed = 1.0;
2161         TimeAxisView* tvp = &_primary->get_time_axis_view ();
2162         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2163
2164         if (tv && tv->is_track()) {
2165                 speed = tv->track()->speed();
2166         }
2167
2168         framepos_t const region_start = (framepos_t) (_primary->region()->position() / speed);
2169         framepos_t const region_end = (framepos_t) (_primary->region()->last_frame() / speed);
2170         framecnt_t const region_length = (framecnt_t) (_primary->region()->length() / speed);
2171
2172         framepos_t const pf = adjusted_current_frame (event);
2173
2174         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2175                 /* Move the contents of the region around without changing the region bounds */
2176                 _operation = ContentsTrim;
2177                 Drag::start_grab (event, _editor->cursors()->trimmer);
2178         } else {
2179                 /* These will get overridden for a point trim.*/
2180                 if (pf < (region_start + region_length/2)) {
2181                         /* closer to front */
2182                         _operation = StartTrim;
2183
2184                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2185                                 Drag::start_grab (event, _editor->cursors()->anchored_left_side_trim);
2186                         } else {
2187                                 Drag::start_grab (event, _editor->cursors()->left_side_trim);
2188                         }
2189                 } else {
2190                         /* closer to end */
2191                         _operation = EndTrim;
2192                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2193                                 Drag::start_grab (event, _editor->cursors()->anchored_right_side_trim);
2194                         } else {
2195                                 Drag::start_grab (event, _editor->cursors()->right_side_trim);
2196                         }
2197                 }
2198         }
2199
2200         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2201                 _jump_position_when_done = true;
2202         }
2203
2204         switch (_operation) {
2205         case StartTrim:
2206                 show_verbose_cursor_time (region_start);
2207                 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2208                         i->view->trim_front_starting ();
2209                 }
2210                 break;
2211         case EndTrim:
2212                 show_verbose_cursor_time (region_end);
2213                 break;
2214         case ContentsTrim:
2215                 show_verbose_cursor_time (pf);
2216                 break;
2217         }
2218
2219         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2220                 i->view->region()->suspend_property_changes ();
2221         }
2222 }
2223
2224 void
2225 TrimDrag::motion (GdkEvent* event, bool first_move)
2226 {
2227         RegionView* rv = _primary;
2228
2229         double speed = 1.0;
2230         TimeAxisView* tvp = &_primary->get_time_axis_view ();
2231         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
2232         pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
2233         frameoffset_t frame_delta = 0;
2234
2235         if (tv && tv->is_track()) {
2236                 speed = tv->track()->speed();
2237         }
2238
2239         framecnt_t dt = adjusted_current_frame (event) - raw_grab_frame () + _pointer_frame_offset;
2240
2241         if (first_move) {
2242
2243                 string trim_type;
2244
2245                 switch (_operation) {
2246                 case StartTrim:
2247                         trim_type = "Region start trim";
2248                         break;
2249                 case EndTrim:
2250                         trim_type = "Region end trim";
2251                         break;
2252                 case ContentsTrim:
2253                         trim_type = "Region content trim";
2254                         break;
2255                 default:
2256                         assert(0);
2257                         break;
2258                 }
2259
2260                 _editor->begin_reversible_command (trim_type);
2261
2262                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2263                         RegionView* rv = i->view;
2264                         rv->enable_display (false);
2265                         rv->region()->playlist()->clear_owned_changes ();
2266
2267                         AudioRegionView* const arv = dynamic_cast<AudioRegionView*> (rv);
2268
2269                         if (arv) {
2270                                 arv->temporarily_hide_envelope ();
2271                                 arv->drag_start ();
2272                         }
2273
2274                         boost::shared_ptr<Playlist> pl = rv->region()->playlist();
2275                         insert_result = _editor->motion_frozen_playlists.insert (pl);
2276
2277                         if (insert_result.second) {
2278                                 pl->freeze();
2279                         }
2280                 }
2281         }
2282
2283         bool non_overlap_trim = false;
2284
2285         if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2286                 non_overlap_trim = true;
2287         }
2288
2289         /* contstrain trim to fade length */
2290         if (_preserve_fade_anchor) {
2291                 switch (_operation) {
2292                         case StartTrim:
2293                                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2294                                         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2295                                         if (!arv) continue;
2296                                         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2297                                         if (ar->locked()) continue;
2298                                         framecnt_t len = ar->fade_in()->back()->when;
2299                                         if (len < dt) dt = min(dt, len);
2300                                 }
2301                                 break;
2302                         case EndTrim:
2303                                 for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2304                                         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2305                                         if (!arv) continue;
2306                                         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2307                                         if (ar->locked()) continue;
2308                                         framecnt_t len = ar->fade_out()->back()->when;
2309                                         if (len < -dt) dt = max(dt, -len);
2310                                 }
2311                                 break;
2312                         case ContentsTrim:
2313                                 break;
2314                 }
2315         }
2316
2317
2318         switch (_operation) {
2319         case StartTrim:
2320                 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2321                         bool changed = i->view->trim_front (i->initial_position + dt, non_overlap_trim);
2322                         if (changed && _preserve_fade_anchor) {
2323                                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2324                                 if (arv) {
2325                                         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2326                                         framecnt_t len = ar->fade_in()->back()->when;
2327                                         framecnt_t diff = ar->first_frame() - i->initial_position;
2328                                         framepos_t new_length = len - diff;
2329                                         i->anchored_fade_length = min (ar->length(), new_length);
2330                                         //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, true  /*START*/ );
2331                                         arv->reset_fade_in_shape_width (ar, i->anchored_fade_length, true);
2332                                 }
2333                         }
2334                 }
2335                 break;
2336
2337         case EndTrim:
2338                 for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2339                         bool changed = i->view->trim_end (i->initial_end + dt, non_overlap_trim);
2340                         if (changed && _preserve_fade_anchor) {
2341                                 AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2342                                 if (arv) {
2343                                         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2344                                         framecnt_t len = ar->fade_out()->back()->when;
2345                                         framecnt_t diff = 1 + ar->last_frame() - i->initial_end;
2346                                         framepos_t new_length = len + diff;
2347                                         i->anchored_fade_length = min (ar->length(), new_length);
2348                                         //i->anchored_fade_length = ar->verify_xfade_bounds (new_length, false  /*END*/ );
2349                                         arv->reset_fade_out_shape_width (ar, i->anchored_fade_length, true);
2350                                 }
2351                         }
2352                 }
2353                 break;
2354
2355         case ContentsTrim:
2356                 {
2357                         frame_delta = (last_pointer_frame() - adjusted_current_frame(event));
2358
2359                         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2360                                 i->view->move_contents (frame_delta);
2361                         }
2362                 }
2363                 break;
2364         }
2365
2366         switch (_operation) {
2367         case StartTrim:
2368                 show_verbose_cursor_time ((framepos_t) (rv->region()->position() / speed));
2369                 break;
2370         case EndTrim:
2371                 show_verbose_cursor_time ((framepos_t) (rv->region()->last_frame() / speed));
2372                 break;
2373         case ContentsTrim:
2374                 // show_verbose_cursor_time (frame_delta);
2375                 break;
2376         }
2377 }
2378
2379
2380 void
2381 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
2382 {
2383         if (movement_occurred) {
2384                 motion (event, false);
2385
2386                 if (_operation == StartTrim) {
2387                         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2388                                 {
2389                                         /* This must happen before the region's StatefulDiffCommand is created, as it may
2390                                            `correct' (ahem) the region's _start from being negative to being zero.  It
2391                                            needs to be zero in the undo record.
2392                                         */
2393                                         i->view->trim_front_ending ();
2394                                 }
2395                                 if (_preserve_fade_anchor) {
2396                                         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2397                                         if (arv) {
2398                                                 boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2399                                                 arv->reset_fade_in_shape_width (ar, i->anchored_fade_length);
2400                                                 ar->set_fade_in_length(i->anchored_fade_length);
2401                                                 ar->set_fade_in_active(true);
2402                                         }
2403                                 }
2404                                 if (_jump_position_when_done) {
2405                                         i->view->region()->set_position (i->initial_position);
2406                                 }
2407                         }
2408                 } else if (_operation == EndTrim) {
2409                         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2410                                 if (_preserve_fade_anchor) {
2411                                         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (i->view);
2412                                         if (arv) {
2413                                                 boost::shared_ptr<AudioRegion> ar (arv->audio_region());
2414                                                 arv->reset_fade_out_shape_width (ar, i->anchored_fade_length);
2415                                                 ar->set_fade_out_length(i->anchored_fade_length);
2416                                                 ar->set_fade_out_active(true);
2417                                         }
2418                                 }
2419                                 if (_jump_position_when_done) {
2420                                         i->view->region()->set_position (i->initial_end - i->view->region()->length());
2421                                 }
2422                         }
2423                 }
2424
2425                 if (!_views.empty()) {
2426                         if (_operation == StartTrim) {
2427                                 _editor->maybe_locate_with_edit_preroll(
2428                                         _views.begin()->view->region()->position());
2429                         }
2430                         if (_operation == EndTrim) {
2431                                 _editor->maybe_locate_with_edit_preroll(
2432                                         _views.begin()->view->region()->position() +
2433                                         _views.begin()->view->region()->length());
2434                         }
2435                 }
2436         
2437                 if (!_editor->selection->selected (_primary)) {
2438                         _primary->thaw_after_trim ();
2439                 } else {
2440
2441                         set<boost::shared_ptr<Playlist> > diffed_playlists;
2442
2443                         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2444                                 i->view->thaw_after_trim ();
2445                                 i->view->enable_display (true);
2446
2447                                 /* Trimming one region may affect others on the playlist, so we need
2448                                    to get undo Commands from the whole playlist rather than just the
2449                                    region.  Use diffed_playlists to make sure we don't diff a given
2450                                    playlist more than once.
2451                                 */
2452                                 boost::shared_ptr<Playlist> p = i->view->region()->playlist ();
2453                                 if (diffed_playlists.find (p) == diffed_playlists.end()) {
2454                                         vector<Command*> cmds;
2455                                         p->rdiff (cmds);
2456                                         _editor->session()->add_commands (cmds);
2457                                         diffed_playlists.insert (p);
2458                                 }
2459                         }
2460                 }
2461
2462                 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
2463                         (*p)->thaw ();
2464                 }
2465
2466                 _editor->motion_frozen_playlists.clear ();
2467                 _editor->commit_reversible_command();
2468
2469         } else {
2470                 /* no mouse movement */
2471                 _editor->point_trim (event, adjusted_current_frame (event));
2472         }
2473
2474         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2475                 if (_operation == StartTrim) {
2476                         i->view->trim_front_ending ();
2477                 }
2478
2479                 i->view->region()->resume_property_changes ();
2480         }
2481 }
2482
2483 void
2484 TrimDrag::aborted (bool movement_occurred)
2485 {
2486         /* Our motion method is changing model state, so use the Undo system
2487            to cancel.  Perhaps not ideal, as this will leave an Undo point
2488            behind which may be slightly odd from the user's point of view.
2489         */
2490
2491         finished (0, true);
2492
2493         if (movement_occurred) {
2494                 _editor->undo ();
2495         }
2496
2497         for (list<DraggingView>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
2498                 i->view->region()->resume_property_changes ();
2499         }
2500 }
2501
2502 void
2503 TrimDrag::setup_pointer_frame_offset ()
2504 {
2505         list<DraggingView>::iterator i = _views.begin ();
2506         while (i != _views.end() && i->view != _primary) {
2507                 ++i;
2508         }
2509
2510         if (i == _views.end()) {
2511                 return;
2512         }
2513
2514         switch (_operation) {
2515         case StartTrim:
2516                 _pointer_frame_offset = raw_grab_frame() - i->initial_position;
2517                 break;
2518         case EndTrim:
2519                 _pointer_frame_offset = raw_grab_frame() - i->initial_end;
2520                 break;
2521         case ContentsTrim:
2522                 break;
2523         }
2524 }
2525
2526 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2527         : Drag (e, i),
2528           _copy (c)
2529 {
2530         DEBUG_TRACE (DEBUG::Drags, "New MeterMarkerDrag\n");
2531         _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
2532         assert (_marker);
2533 }
2534
2535 void
2536 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2537 {
2538         Drag::start_grab (event, cursor);
2539         show_verbose_cursor_time (adjusted_current_frame(event));
2540 }
2541
2542 void
2543 MeterMarkerDrag::setup_pointer_frame_offset ()
2544 {
2545         _pointer_frame_offset = raw_grab_frame() - _marker->meter().frame();
2546 }
2547
2548 void
2549 MeterMarkerDrag::motion (GdkEvent* event, bool first_move)
2550 {
2551         if (!_marker->meter().movable()) {
2552                 return;
2553         }
2554
2555         if (first_move) {
2556
2557                 // create a dummy marker for visual representation of moving the
2558                 // section, because whether its a copy or not, we're going to 
2559                 // leave or lose the original marker (leave if its a copy; lose if its
2560                 // not, because we'll remove it from the map).
2561                 
2562                 MeterSection section (_marker->meter());
2563
2564                 if (!section.movable()) {
2565                         return;
2566                 }
2567                 
2568                 char name[64];
2569                 snprintf (name, sizeof(name), "%g/%g", _marker->meter().divisions_per_bar(), _marker->meter().note_divisor ());
2570                 
2571                 _marker = new MeterMarker (
2572                         *_editor,
2573                         *_editor->meter_group,
2574                         ARDOUR_UI::config()->get_canvasvar_MeterMarker(),
2575                         name,
2576                         *new MeterSection (_marker->meter())
2577                 );
2578                 
2579                 /* use the new marker for the grab */
2580                 swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME);
2581
2582                 if (!_copy) {
2583                         TempoMap& map (_editor->session()->tempo_map());
2584                         /* get current state */
2585                         before_state = &map.get_state();
2586                         /* remove the section while we drag it */
2587                         map.remove_meter (section, true);
2588                 }
2589         }
2590
2591         framepos_t const pf = adjusted_current_frame (event);
2592         _marker->set_position (pf);
2593         show_verbose_cursor_time (pf);
2594 }
2595
2596 void
2597 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2598 {
2599         if (!movement_occurred) {
2600                 if (was_double_click()) {
2601                         _editor->edit_meter_marker (*_marker);
2602                 }
2603                 return;
2604         }
2605
2606         if (!_marker->meter().movable()) {
2607                 return;
2608         }
2609
2610         motion (event, false);
2611
2612         Timecode::BBT_Time when;
2613
2614         TempoMap& map (_editor->session()->tempo_map());
2615         map.bbt_time (last_pointer_frame(), when);
2616         
2617         if (_copy == true) {
2618                 _editor->begin_reversible_command (_("copy meter mark"));
2619                 XMLNode &before = map.get_state();
2620                 map.add_meter (_marker->meter(), when);
2621                 XMLNode &after = map.get_state();
2622                 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
2623                 _editor->commit_reversible_command ();
2624
2625         } else {
2626                 _editor->begin_reversible_command (_("move meter mark"));
2627
2628                 /* we removed it before, so add it back now */
2629                 
2630                 map.add_meter (_marker->meter(), when);
2631                 XMLNode &after = map.get_state();
2632                 _editor->session()->add_command(new MementoCommand<TempoMap>(map, before_state, &after));
2633                 _editor->commit_reversible_command ();
2634         }
2635
2636         // delete the dummy marker we used for visual representation while moving.
2637         // a new visual marker will show up automatically.
2638         delete _marker;
2639 }
2640
2641 void
2642 MeterMarkerDrag::aborted (bool moved)
2643 {
2644         _marker->set_position (_marker->meter().frame ());
2645
2646         if (moved) {
2647                 TempoMap& map (_editor->session()->tempo_map());
2648                 /* we removed it before, so add it back now */
2649                 map.add_meter (_marker->meter(), _marker->meter().frame());
2650                 // delete the dummy marker we used for visual representation while moving.
2651                 // a new visual marker will show up automatically.
2652                 delete _marker;
2653         }
2654 }
2655
2656 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
2657         : Drag (e, i),
2658           _copy (c)
2659 {
2660         DEBUG_TRACE (DEBUG::Drags, "New TempoMarkerDrag\n");
2661
2662         _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
2663         assert (_marker);
2664 }
2665
2666 void
2667 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2668 {
2669         Drag::start_grab (event, cursor);
2670         show_verbose_cursor_time (adjusted_current_frame (event));
2671 }
2672
2673 void
2674 TempoMarkerDrag::setup_pointer_frame_offset ()
2675 {
2676         _pointer_frame_offset = raw_grab_frame() - _marker->tempo().frame();
2677 }
2678
2679 void
2680 TempoMarkerDrag::motion (GdkEvent* event, bool first_move)
2681 {
2682         if (!_marker->tempo().movable()) {
2683                 return;
2684         }
2685
2686         if (first_move) {
2687
2688                 // create a dummy marker for visual representation of moving the
2689                 // section, because whether its a copy or not, we're going to 
2690                 // leave or lose the original marker (leave if its a copy; lose if its
2691                 // not, because we'll remove it from the map).
2692                 
2693                 // create a dummy marker for visual representation of moving the copy.
2694                 // The actual copying is not done before we reach the finish callback.
2695
2696                 char name[64];
2697                 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2698
2699                 TempoSection section (_marker->tempo());
2700
2701                 _marker = new TempoMarker (
2702                         *_editor,
2703                         *_editor->tempo_group,
2704                         ARDOUR_UI::config()->get_canvasvar_TempoMarker(),
2705                         name,
2706                         *new TempoSection (_marker->tempo())
2707                         );
2708
2709                 /* use the new marker for the grab */
2710                 swap_grab (&_marker->the_item(), 0, GDK_CURRENT_TIME);
2711
2712                 if (!_copy) {
2713                         TempoMap& map (_editor->session()->tempo_map());
2714                         /* get current state */
2715                         before_state = &map.get_state();
2716                         /* remove the section while we drag it */
2717                         map.remove_tempo (section, true);
2718                 }
2719         }
2720
2721         framepos_t const pf = adjusted_current_frame (event);
2722         _marker->set_position (pf);
2723         show_verbose_cursor_time (pf);
2724 }
2725
2726 void
2727 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2728 {
2729         if (!movement_occurred) {
2730                 if (was_double_click()) {
2731                         _editor->edit_tempo_marker (*_marker);
2732                 }
2733                 return;
2734         }
2735
2736         if (!_marker->tempo().movable()) {
2737                 return;
2738         }
2739
2740         motion (event, false);
2741
2742         TempoMap& map (_editor->session()->tempo_map());
2743         framepos_t beat_time = map.round_to_beat (last_pointer_frame(), 0);
2744         Timecode::BBT_Time when;
2745
2746         map.bbt_time (beat_time, when);
2747
2748         if (_copy == true) {
2749                 _editor->begin_reversible_command (_("copy tempo mark"));
2750                 XMLNode &before = map.get_state();
2751                 map.add_tempo (_marker->tempo(), when);
2752                 XMLNode &after = map.get_state();
2753                 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2754                 _editor->commit_reversible_command ();
2755
2756         } else {
2757                 _editor->begin_reversible_command (_("move tempo mark"));
2758                 /* we removed it before, so add it back now */
2759                 map.add_tempo (_marker->tempo(), when);
2760                 XMLNode &after = map.get_state();
2761                 _editor->session()->add_command (new MementoCommand<TempoMap>(map, before_state, &after));
2762                 _editor->commit_reversible_command ();
2763         }
2764
2765         // delete the dummy marker we used for visual representation while moving.
2766         // a new visual marker will show up automatically.
2767         delete _marker;
2768 }
2769
2770 void
2771 TempoMarkerDrag::aborted (bool moved)
2772 {
2773         _marker->set_position (_marker->tempo().frame());
2774         if (moved) {
2775                 TempoMap& map (_editor->session()->tempo_map());
2776                 /* we removed it before, so add it back now */
2777                 map.add_tempo (_marker->tempo(), _marker->tempo().start());
2778                 // delete the dummy marker we used for visual representation while moving.
2779                 // a new visual marker will show up automatically.
2780                 delete _marker;
2781         }
2782 }
2783
2784 CursorDrag::CursorDrag (Editor* e, EditorCursor& c, bool s)
2785         : Drag (e, &c.track_canvas_item(), false)
2786         , _cursor (c)
2787         , _stop (s)
2788 {
2789         DEBUG_TRACE (DEBUG::Drags, "New CursorDrag\n");
2790 }
2791
2792 /** Do all the things we do when dragging the playhead to make it look as though
2793  *  we have located, without actually doing the locate (because that would cause
2794  *  the diskstream buffers to be refilled, which is too slow).
2795  */
2796 void
2797 CursorDrag::fake_locate (framepos_t t)
2798 {
2799         _editor->playhead_cursor->set_position (t);
2800
2801         Session* s = _editor->session ();
2802         if (s->timecode_transmission_suspended ()) {
2803                 framepos_t const f = _editor->playhead_cursor->current_frame ();
2804                 /* This is asynchronous so it will be sent "now"
2805                  */
2806                 s->send_mmc_locate (f);
2807                 /* These are synchronous and will be sent during the next
2808                    process cycle
2809                 */
2810                 s->queue_full_time_code ();
2811                 s->queue_song_position_pointer ();
2812         }
2813
2814         show_verbose_cursor_time (t);
2815         _editor->UpdateAllTransportClocks (t);
2816 }
2817
2818 void
2819 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2820 {
2821         Drag::start_grab (event, c);
2822
2823         _grab_zoom = _editor->samples_per_pixel;
2824
2825         framepos_t where = _editor->canvas_event_sample (event);
2826
2827         _editor->snap_to_with_modifier (where, event);
2828
2829         _editor->_dragging_playhead = true;
2830
2831         Session* s = _editor->session ();
2832
2833         /* grab the track canvas item as well */
2834
2835         _cursor.track_canvas_item().grab();
2836
2837         if (s) {
2838                 if (_was_rolling && _stop) {
2839                         s->request_stop ();
2840                 }
2841
2842                 if (s->is_auditioning()) {
2843                         s->cancel_audition ();
2844                 }
2845
2846
2847                 if (AudioEngine::instance()->connected()) {
2848                         
2849                         /* do this only if we're the engine is connected
2850                          * because otherwise this request will never be
2851                          * serviced and we'll busy wait forever. likewise,
2852                          * notice if we are disconnected while waiting for the
2853                          * request to be serviced.
2854                          */
2855
2856                         s->request_suspend_timecode_transmission ();
2857                         while (AudioEngine::instance()->connected() && !s->timecode_transmission_suspended ()) {
2858                                 /* twiddle our thumbs */
2859                         }
2860                 }
2861         }
2862
2863         fake_locate (where);
2864 }
2865
2866 void
2867 CursorDrag::motion (GdkEvent* event, bool)
2868 {
2869         framepos_t const adjusted_frame = adjusted_current_frame (event);
2870         if (adjusted_frame != last_pointer_frame()) {
2871                 fake_locate (adjusted_frame);
2872         }
2873 }
2874
2875 void
2876 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2877 {
2878         _editor->_dragging_playhead = false;
2879
2880         _cursor.track_canvas_item().ungrab();
2881
2882         if (!movement_occurred && _stop) {
2883                 return;
2884         }
2885
2886         motion (event, false);
2887
2888         Session* s = _editor->session ();
2889         if (s) {
2890                 s->request_locate (_editor->playhead_cursor->current_frame (), _was_rolling);
2891                 _editor->_pending_locate_request = true;
2892                 s->request_resume_timecode_transmission ();
2893         }
2894 }
2895
2896 void
2897 CursorDrag::aborted (bool)
2898 {
2899         _cursor.track_canvas_item().ungrab();
2900
2901         if (_editor->_dragging_playhead) {
2902                 _editor->session()->request_resume_timecode_transmission ();
2903                 _editor->_dragging_playhead = false;
2904         }
2905
2906         _editor->playhead_cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2907 }
2908
2909 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2910         : RegionDrag (e, i, p, v)
2911 {
2912         DEBUG_TRACE (DEBUG::Drags, "New FadeInDrag\n");
2913 }
2914
2915 void
2916 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2917 {
2918         Drag::start_grab (event, cursor);
2919
2920         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
2921         boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
2922
2923         show_verbose_cursor_duration (r->position(), r->position() + r->fade_in()->back()->when, 32);
2924 }
2925
2926 void
2927 FadeInDrag::setup_pointer_frame_offset ()
2928 {
2929         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
2930         boost::shared_ptr<AudioRegion> const r = arv->audio_region ();
2931         _pointer_frame_offset = raw_grab_frame() - ((framecnt_t) r->fade_in()->back()->when + r->position());
2932 }
2933
2934 void
2935 FadeInDrag::motion (GdkEvent* event, bool)
2936 {
2937         framecnt_t fade_length;
2938
2939         framepos_t const pos = adjusted_current_frame (event);
2940
2941         boost::shared_ptr<Region> region = _primary->region ();
2942
2943         if (pos < (region->position() + 64)) {
2944                 fade_length = 64; // this should be a minimum defined somewhere
2945         } else if (pos > region->last_frame()) {
2946                 fade_length = region->length();
2947         } else {
2948                 fade_length = pos - region->position();
2949         }
2950
2951         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2952
2953                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2954
2955                 if (!tmp) {
2956                         continue;
2957                 }
2958
2959                 tmp->reset_fade_in_shape_width (tmp->audio_region(), fade_length);
2960         }
2961
2962         show_verbose_cursor_duration (region->position(), region->position() + fade_length, 32);
2963 }
2964
2965 void
2966 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2967 {
2968         if (!movement_occurred) {
2969                 return;
2970         }
2971
2972         framecnt_t fade_length;
2973
2974         framepos_t const pos = adjusted_current_frame (event);
2975
2976         boost::shared_ptr<Region> region = _primary->region ();
2977
2978         if (pos < (region->position() + 64)) {
2979                 fade_length = 64; // this should be a minimum defined somewhere
2980         } else if (pos > region->last_frame()) {
2981                 fade_length = region->length();
2982         } else {
2983                 fade_length = pos - region->position();
2984         }
2985
2986         _editor->begin_reversible_command (_("change fade in length"));
2987
2988         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
2989
2990                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
2991
2992                 if (!tmp) {
2993                         continue;
2994                 }
2995
2996                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2997                 XMLNode &before = alist->get_state();
2998
2999                 tmp->audio_region()->set_fade_in_length (fade_length);
3000                 tmp->audio_region()->set_fade_in_active (true);
3001
3002                 XMLNode &after = alist->get_state();
3003                 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3004         }
3005
3006         _editor->commit_reversible_command ();
3007 }
3008
3009 void
3010 FadeInDrag::aborted (bool)
3011 {
3012         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
3013                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
3014
3015                 if (!tmp) {
3016                         continue;
3017                 }
3018
3019                 tmp->reset_fade_in_shape_width (tmp->audio_region(), tmp->audio_region()->fade_in()->back()->when);
3020         }
3021 }
3022
3023 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
3024         : RegionDrag (e, i, p, v)
3025 {
3026         DEBUG_TRACE (DEBUG::Drags, "New FadeOutDrag\n");
3027 }
3028
3029 void
3030 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3031 {
3032         Drag::start_grab (event, cursor);
3033
3034         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
3035         boost::shared_ptr<AudioRegion> r = arv->audio_region ();
3036
3037         show_verbose_cursor_duration (r->last_frame() - r->fade_out()->back()->when, r->last_frame());
3038 }
3039
3040 void
3041 FadeOutDrag::setup_pointer_frame_offset ()
3042 {
3043         AudioRegionView* arv = dynamic_cast<AudioRegionView*> (_primary);
3044         boost::shared_ptr<AudioRegion> r = arv->audio_region ();
3045         _pointer_frame_offset = raw_grab_frame() - (r->length() - (framecnt_t) r->fade_out()->back()->when + r->position());
3046 }
3047
3048 void
3049 FadeOutDrag::motion (GdkEvent* event, bool)
3050 {
3051         framecnt_t fade_length;
3052
3053         framepos_t const pos = adjusted_current_frame (event);
3054
3055         boost::shared_ptr<Region> region = _primary->region ();
3056
3057         if (pos > (region->last_frame() - 64)) {
3058                 fade_length = 64; // this should really be a minimum fade defined somewhere
3059         }
3060         else if (pos < region->position()) {
3061                 fade_length = region->length();
3062         }
3063         else {
3064                 fade_length = region->last_frame() - pos;
3065         }
3066
3067         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
3068
3069                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
3070
3071                 if (!tmp) {
3072                         continue;
3073                 }
3074
3075                 tmp->reset_fade_out_shape_width (tmp->audio_region(), fade_length);
3076         }
3077
3078         show_verbose_cursor_duration (region->last_frame() - fade_length, region->last_frame());
3079 }
3080
3081 void
3082 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
3083 {
3084         if (!movement_occurred) {
3085                 return;
3086         }
3087
3088         framecnt_t fade_length;
3089
3090         framepos_t const pos = adjusted_current_frame (event);
3091
3092         boost::shared_ptr<Region> region = _primary->region ();
3093
3094         if (pos > (region->last_frame() - 64)) {
3095                 fade_length = 64; // this should really be a minimum fade defined somewhere
3096         }
3097         else if (pos < region->position()) {
3098                 fade_length = region->length();
3099         }
3100         else {
3101                 fade_length = region->last_frame() - pos;
3102         }
3103
3104         _editor->begin_reversible_command (_("change fade out length"));
3105
3106         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
3107
3108                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
3109
3110                 if (!tmp) {
3111                         continue;
3112                 }
3113
3114                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
3115                 XMLNode &before = alist->get_state();
3116
3117                 tmp->audio_region()->set_fade_out_length (fade_length);
3118                 tmp->audio_region()->set_fade_out_active (true);
3119
3120                 XMLNode &after = alist->get_state();
3121                 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
3122         }
3123
3124         _editor->commit_reversible_command ();
3125 }
3126
3127 void
3128 FadeOutDrag::aborted (bool)
3129 {
3130         for (list<DraggingView>::iterator i = _views.begin(); i != _views.end(); ++i) {
3131                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (i->view);
3132
3133                 if (!tmp) {
3134                         continue;
3135                 }
3136
3137                 tmp->reset_fade_out_shape_width (tmp->audio_region(), tmp->audio_region()->fade_out()->back()->when);
3138         }
3139 }
3140
3141 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
3142         : Drag (e, i)
3143 {
3144         DEBUG_TRACE (DEBUG::Drags, "New MarkerDrag\n");
3145
3146         _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
3147         assert (_marker);
3148
3149         _points.push_back (ArdourCanvas::Duple (0, 0));
3150         _points.push_back (ArdourCanvas::Duple (0, physical_screen_height (_editor->get_window())));
3151 }
3152
3153 MarkerDrag::~MarkerDrag ()
3154 {
3155         for (CopiedLocationInfo::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
3156                 delete i->location;
3157         }
3158 }
3159
3160 MarkerDrag::CopiedLocationMarkerInfo::CopiedLocationMarkerInfo (Location* l, Marker* m)
3161 {
3162         location = new Location (*l);
3163         markers.push_back (m);
3164         move_both = false;
3165 }
3166
3167 void
3168 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3169 {
3170         Drag::start_grab (event, cursor);
3171
3172         bool is_start;
3173
3174         Location *location = _editor->find_location_from_marker (_marker, is_start);
3175         _editor->_dragging_edit_point = true;
3176
3177         update_item (location);
3178
3179         // _drag_line->show();
3180         // _line->raise_to_top();
3181
3182         if (is_start) {
3183                 show_verbose_cursor_time (location->start());
3184         } else {
3185                 show_verbose_cursor_time (location->end());
3186         }
3187
3188         Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3189
3190         switch (op) {
3191         case Selection::Toggle:
3192                 /* we toggle on the button release */
3193                 break;
3194         case Selection::Set:
3195                 if (!_editor->selection->selected (_marker)) {
3196                         _editor->selection->set (_marker);
3197                 }
3198                 break;
3199         case Selection::Extend:
3200         {
3201                 Locations::LocationList ll;
3202                 list<Marker*> to_add;
3203                 framepos_t s, e;
3204                 _editor->selection->markers.range (s, e);
3205                 s = min (_marker->position(), s);
3206                 e = max (_marker->position(), e);
3207                 s = min (s, e);
3208                 e = max (s, e);
3209                 if (e < max_framepos) {
3210                         ++e;
3211                 }
3212                 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
3213                 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
3214                         Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
3215                         if (lm) {
3216                                 if (lm->start) {
3217                                         to_add.push_back (lm->start);
3218                                 }
3219                                 if (lm->end) {
3220                                         to_add.push_back (lm->end);
3221                                 }
3222                         }
3223                 }
3224                 if (!to_add.empty()) {
3225                         _editor->selection->add (to_add);
3226                 }
3227                 break;
3228         }
3229         case Selection::Add:
3230                 _editor->selection->add (_marker);
3231                 break;
3232         }
3233
3234         /* Set up copies for us to manipulate during the drag 
3235          */
3236
3237         for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
3238
3239                 Location* l = _editor->find_location_from_marker (*i, is_start);
3240
3241                 if (!l) {
3242                         continue;
3243                 }
3244
3245                 if (l->is_mark()) {
3246                         _copied_locations.push_back (CopiedLocationMarkerInfo (l, *i));
3247                 } else {
3248                         /* range: check that the other end of the range isn't
3249                            already there.
3250                         */
3251                         CopiedLocationInfo::iterator x;
3252                         for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
3253                                 if (*(*x).location == *l) {
3254                                         break;
3255                                 }
3256                         }
3257                         if (x == _copied_locations.end()) {
3258                                 _copied_locations.push_back (CopiedLocationMarkerInfo (l, *i));
3259                         } else {
3260                                 (*x).markers.push_back (*i);
3261                                 (*x).move_both = true;
3262                         }
3263                 }
3264                         
3265         }
3266 }
3267
3268 void
3269 MarkerDrag::setup_pointer_frame_offset ()
3270 {
3271         bool is_start;
3272         Location *location = _editor->find_location_from_marker (_marker, is_start);
3273         _pointer_frame_offset = raw_grab_frame() - (is_start ? location->start() : location->end());
3274 }
3275
3276 void
3277 MarkerDrag::motion (GdkEvent* event, bool)
3278 {
3279         framecnt_t f_delta = 0;
3280         bool is_start;
3281         bool move_both = false;
3282         Location *real_location;
3283         Location *copy_location = 0;
3284
3285         framepos_t const newframe = adjusted_current_frame (event);
3286         framepos_t next = newframe;
3287
3288         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
3289                 move_both = true;
3290         }
3291
3292         CopiedLocationInfo::iterator x;
3293
3294         /* find the marker we're dragging, and compute the delta */
3295
3296         for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
3297
3298                 copy_location = (*x).location;
3299
3300                 if (find (x->markers.begin(), x->markers.end(), _marker) != x->markers.end()) {
3301
3302                         /* this marker is represented by this
3303                          * CopiedLocationMarkerInfo 
3304                          */
3305
3306                         if ((real_location = _editor->find_location_from_marker (_marker, is_start)) == 0) {
3307                                 /* que pasa ?? */
3308                                 return;
3309                         }
3310
3311                         if (real_location->is_mark()) {
3312                                 f_delta = newframe - copy_location->start();
3313                         } else {
3314
3315
3316                                 switch (_marker->type()) {
3317                                 case Marker::SessionStart:
3318                                 case Marker::RangeStart:
3319                                 case Marker::LoopStart:
3320                                 case Marker::PunchIn:
3321                                         f_delta = newframe - copy_location->start();
3322                                         break;
3323
3324                                 case Marker::SessionEnd:
3325                                 case Marker::RangeEnd:
3326                                 case Marker::LoopEnd:
3327                                 case Marker::PunchOut:
3328                                         f_delta = newframe - copy_location->end();
3329                                         break;
3330                                 default:
3331                                         /* what kind of marker is this ? */
3332                                         return;
3333                                 }
3334                         }
3335
3336                         break;
3337                 }
3338         }
3339
3340         if (x == _copied_locations.end()) {
3341                 /* hmm, impossible - we didn't find the dragged marker */
3342                 return;
3343         }
3344
3345         /* now move them all */
3346
3347         for (x = _copied_locations.begin(); x != _copied_locations.end(); ++x) {
3348
3349                 copy_location = x->location;
3350
3351                 /* call this to find out if its the start or end */
3352
3353                 if ((real_location = _editor->find_location_from_marker (x->markers.front(), is_start)) == 0) {
3354                         continue;
3355                 }
3356
3357                 if (real_location->locked()) {
3358                         continue;
3359                 }
3360
3361                 if (copy_location->is_mark()) {
3362
3363                         /* now move it */
3364
3365                         copy_location->set_start (copy_location->start() + f_delta);
3366
3367                 } else {
3368                         
3369                         framepos_t new_start = copy_location->start() + f_delta;
3370                         framepos_t new_end = copy_location->end() + f_delta;
3371                         
3372                         if (is_start) { // start-of-range marker
3373                                 
3374                                 if (move_both || (*x).move_both) {
3375                                         copy_location->set_start (new_start);
3376                                         copy_location->set_end (new_end);
3377                                 } else  if (new_start < copy_location->end()) {
3378                                         copy_location->set_start (new_start);
3379                                 } else if (newframe > 0) {
3380                                         _editor->snap_to (next, 1, true);
3381                                         copy_location->set_end (next);
3382                                         copy_location->set_start (newframe);
3383                                 }
3384
3385                         } else { // end marker
3386
3387                                 if (move_both || (*x).move_both) {
3388                                         copy_location->set_end (new_end);
3389                                         copy_location->set_start (new_start);
3390                                 } else if (new_end > copy_location->start()) {
3391                                         copy_location->set_end (new_end);
3392                                 } else if (newframe > 0) {
3393                                         _editor->snap_to (next, -1, true);
3394                                         copy_location->set_start (next);
3395                                         copy_location->set_end (newframe);
3396                                 }
3397                         }
3398                 }
3399
3400                 update_item (copy_location);
3401                 
3402                 /* now lookup the actual GUI items used to display this
3403                  * location and move them to wherever the copy of the location
3404                  * is now. This means that the logic in ARDOUR::Location is
3405                  * still enforced, even though we are not (yet) modifying 
3406                  * the real Location itself.
3407                  */
3408                 
3409                 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
3410
3411                 if (lm) {
3412                         lm->set_position (copy_location->start(), copy_location->end());
3413                 }
3414
3415         }
3416
3417         assert (!_copied_locations.empty());
3418
3419         show_verbose_cursor_time (newframe);
3420 }
3421
3422 void
3423 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
3424 {
3425         if (!movement_occurred) {
3426                 
3427                 if (was_double_click()) {
3428                         _editor->rename_marker (_marker);
3429                         return;
3430                 }
3431
3432                 /* just a click, do nothing but finish
3433                    off the selection process
3434                 */
3435
3436                 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
3437
3438                 switch (op) {
3439                 case Selection::Set:
3440                         if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
3441                                 _editor->selection->set (_marker);
3442                         }
3443                         break;
3444
3445                 case Selection::Toggle:
3446                         /* we toggle on the button release, click only */
3447                         _editor->selection->toggle (_marker);
3448                         break;
3449
3450                 case Selection::Extend:
3451                 case Selection::Add:
3452                         break;
3453                 }
3454
3455                 return;
3456         }
3457
3458         _editor->_dragging_edit_point = false;
3459
3460         _editor->begin_reversible_command ( _("move marker") );
3461         XMLNode &before = _editor->session()->locations()->get_state();
3462
3463         MarkerSelection::iterator i;
3464         CopiedLocationInfo::iterator x;
3465         bool is_start;
3466
3467         for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
3468              x != _copied_locations.end() && i != _editor->selection->markers.end();
3469              ++i, ++x) {
3470
3471                 Location * location = _editor->find_location_from_marker (*i, is_start);
3472
3473                 if (location) {
3474
3475                         if (location->locked()) {
3476                                 return;
3477                         }
3478
3479                         if (location->is_mark()) {
3480                                 location->set_start (((*x).location)->start());
3481                         } else {
3482                                 location->set (((*x).location)->start(), ((*x).location)->end());
3483                         }
3484                 }
3485         }
3486
3487         XMLNode &after = _editor->session()->locations()->get_state();
3488         _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3489         _editor->commit_reversible_command ();
3490 }
3491
3492 void
3493 MarkerDrag::aborted (bool)
3494 {
3495         /* XXX: TODO */
3496 }
3497
3498 void
3499 MarkerDrag::update_item (Location*)
3500 {
3501         /* noop */
3502 }
3503
3504 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
3505         : Drag (e, i),
3506           _cumulative_x_drag (0),
3507           _cumulative_y_drag (0)
3508 {
3509         if (_zero_gain_fraction < 0.0) {
3510                 _zero_gain_fraction = gain_to_slider_position_with_max (dB_to_coefficient (0.0), Config->get_max_gain());
3511         }
3512
3513         DEBUG_TRACE (DEBUG::Drags, "New ControlPointDrag\n");
3514
3515         _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
3516         assert (_point);
3517 }
3518
3519
3520 void
3521 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
3522 {
3523         Drag::start_grab (event, _editor->cursors()->fader);
3524
3525         // start the grab at the center of the control point so
3526         // the point doesn't 'jump' to the mouse after the first drag
3527         _fixed_grab_x = _point->get_x();
3528         _fixed_grab_y = _point->get_y();
3529
3530         float const fraction = 1 - (_point->get_y() / _point->line().height());
3531
3532         _point->line().start_drag_single (_point, _fixed_grab_x, fraction);
3533
3534         show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
3535
3536         _pushing = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
3537
3538         if (!_point->can_slide ()) {
3539                 _x_constrained = true;
3540         }
3541 }
3542
3543 void
3544 ControlPointDrag::motion (GdkEvent* event, bool)
3545 {
3546         double dx = _drags->current_pointer_x() - last_pointer_x();
3547         double dy = current_pointer_y() - last_pointer_y();
3548
3549         if (event->button.state & Keyboard::SecondaryModifier) {
3550                 dx *= 0.1;
3551                 dy *= 0.1;
3552         }
3553
3554         /* coordinate in pixels relative to the start of the region (for region-based automation)
3555            or track (for track-based automation) */
3556         double cx = _fixed_grab_x + _cumulative_x_drag + dx;
3557         double cy = _fixed_grab_y + _cumulative_y_drag + dy;
3558
3559         // calculate zero crossing point. back off by .01 to stay on the
3560         // positive side of zero
3561         double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
3562
3563         // make sure we hit zero when passing through
3564         if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
3565                 cy = zero_gain_y;
3566         }
3567
3568         if (_x_constrained) {
3569                 cx = _fixed_grab_x;
3570         }
3571         if (_y_constrained) {
3572                 cy = _fixed_grab_y;
3573         }
3574
3575         _cumulative_x_drag = cx - _fixed_grab_x;
3576         _cumulative_y_drag = cy - _fixed_grab_y;
3577
3578         cx = max (0.0, cx);
3579         cy = max (0.0, cy);
3580         cy = min ((double) _point->line().height(), cy);
3581
3582         framepos_t cx_frames = _editor->pixel_to_sample (cx);
3583
3584         if (!_x_constrained) {
3585                 _editor->snap_to_with_modifier (cx_frames, event);
3586         }
3587
3588         cx_frames = min (cx_frames, _point->line().maximum_time());
3589
3590         float const fraction = 1.0 - (cy / _point->line().height());
3591
3592         _point->line().drag_motion (_editor->sample_to_pixel_unrounded (cx_frames), fraction, false, _pushing, _final_index);
3593
3594         show_verbose_cursor_text (_point->line().get_verbose_cursor_string (fraction));
3595 }
3596
3597 void
3598 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
3599 {
3600         if (!movement_occurred) {
3601
3602                 /* just a click */
3603
3604                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3605                         _editor->reset_point_selection ();
3606                 }
3607
3608         } else {
3609                 motion (event, false);
3610         }
3611
3612         _point->line().end_drag (_pushing, _final_index);
3613         _editor->session()->commit_reversible_command ();
3614 }
3615
3616 void
3617 ControlPointDrag::aborted (bool)
3618 {
3619         _point->line().reset ();
3620 }
3621
3622 bool
3623 ControlPointDrag::active (Editing::MouseMode m)
3624 {
3625         if (m == Editing::MouseGain) {
3626                 /* always active in mouse gain */
3627                 return true;
3628         }
3629
3630         /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
3631         return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
3632 }
3633
3634 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
3635         : Drag (e, i),
3636           _line (0),
3637           _cumulative_y_drag (0)
3638 {
3639         DEBUG_TRACE (DEBUG::Drags, "New LineDrag\n");
3640 }
3641
3642 void
3643 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
3644 {
3645         _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
3646         assert (_line);
3647
3648         _item = &_line->grab_item ();
3649
3650         /* need to get x coordinate in terms of parent (TimeAxisItemView)
3651            origin, and ditto for y.
3652         */
3653
3654         double cx = event->button.x;
3655         double cy = event->button.y;
3656
3657         _line->parent_group().canvas_to_item (cx, cy);
3658
3659         framecnt_t const frame_within_region = (framecnt_t) floor (cx * _editor->samples_per_pixel);
3660
3661         uint32_t before;
3662         uint32_t after;
3663
3664         if (!_line->control_points_adjacent (frame_within_region, before, after)) {
3665                 /* no adjacent points */
3666                 return;
3667         }
3668
3669         Drag::start_grab (event, _editor->cursors()->fader);
3670
3671         /* store grab start in parent frame */
3672
3673         _fixed_grab_x = cx;
3674         _fixed_grab_y = cy;
3675
3676         double fraction = 1.0 - (cy / _line->height());
3677
3678         _line->start_drag_line (before, after, fraction);
3679
3680         show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
3681 }
3682
3683 void
3684 LineDrag::motion (GdkEvent* event, bool)
3685 {
3686         double dy = current_pointer_y() - last_pointer_y();
3687
3688         if (event->button.state & Keyboard::SecondaryModifier) {
3689                 dy *= 0.1;
3690         }
3691
3692         double cy = _fixed_grab_y + _cumulative_y_drag + dy;
3693
3694         _cumulative_y_drag = cy - _fixed_grab_y;
3695
3696         cy = max (0.0, cy);
3697         cy = min ((double) _line->height(), cy);
3698
3699         double const fraction = 1.0 - (cy / _line->height());
3700         uint32_t ignored;
3701
3702         /* we are ignoring x position for this drag, so we can just pass in anything */
3703         _line->drag_motion (0, fraction, true, false, ignored);
3704
3705         show_verbose_cursor_text (_line->get_verbose_cursor_string (fraction));
3706 }
3707
3708 void
3709 LineDrag::finished (GdkEvent* event, bool movement_occured)
3710 {
3711         if (movement_occured) {
3712                 motion (event, false);
3713                 _line->end_drag (false, 0);
3714         } else {
3715                 /* add a new control point on the line */
3716
3717                 AutomationTimeAxisView* atv;
3718
3719                 _line->end_drag (false, 0);
3720
3721                 if ((atv = dynamic_cast<AutomationTimeAxisView*>(_editor->clicked_axisview)) != 0) {
3722                         framepos_t where = _editor->window_event_sample (event, 0, 0);
3723                         atv->add_automation_event (event, where, event->button.y, false);
3724                 }
3725         }
3726
3727         _editor->session()->commit_reversible_command ();
3728 }
3729
3730 void
3731 LineDrag::aborted (bool)
3732 {
3733         _line->reset ();
3734 }
3735
3736 FeatureLineDrag::FeatureLineDrag (Editor* e, ArdourCanvas::Item* i)
3737         : Drag (e, i),
3738           _line (0),
3739           _cumulative_x_drag (0)
3740 {
3741         DEBUG_TRACE (DEBUG::Drags, "New FeatureLineDrag\n");
3742 }
3743
3744 void
3745 FeatureLineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
3746 {
3747         Drag::start_grab (event);
3748
3749         _line = reinterpret_cast<Line*> (_item);
3750         assert (_line);
3751
3752         /* need to get x coordinate in terms of parent (AudioRegionView) origin. */
3753
3754         double cx = event->button.x;
3755         double cy = event->button.y;
3756
3757         _item->parent()->canvas_to_item (cx, cy);
3758
3759         /* store grab start in parent frame */
3760         _region_view_grab_x = cx;
3761
3762         _before = *(float*) _item->get_data ("position");
3763
3764         _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
3765
3766         _max_x = _editor->sample_to_pixel(_arv->get_duration());
3767 }
3768
3769 void
3770 FeatureLineDrag::motion (GdkEvent*, bool)
3771 {
3772         double dx = _drags->current_pointer_x() - last_pointer_x();
3773
3774         double cx = _region_view_grab_x + _cumulative_x_drag + dx;
3775
3776         _cumulative_x_drag += dx;
3777
3778         /* Clamp the min and max extent of the drag to keep it within the region view bounds */
3779
3780         if (cx > _max_x){
3781                 cx = _max_x;
3782         }
3783         else if(cx < 0){
3784                 cx = 0;
3785         }
3786
3787         boost::optional<ArdourCanvas::Rect> bbox = _line->bounding_box ();
3788         assert (bbox);
3789         _line->set (ArdourCanvas::Duple (cx, 2.0), ArdourCanvas::Duple (cx, bbox.get().height ()));
3790
3791         float *pos = new float;
3792         *pos = cx;
3793
3794         _line->set_data ("position", pos);
3795
3796         _before = cx;
3797 }
3798
3799 void
3800 FeatureLineDrag::finished (GdkEvent*, bool)
3801 {
3802         _arv = reinterpret_cast<AudioRegionView*> (_item->get_data ("regionview"));
3803         _arv->update_transient(_before, _before);
3804 }
3805
3806 void
3807 FeatureLineDrag::aborted (bool)
3808 {
3809         //_line->reset ();
3810 }
3811
3812 RubberbandSelectDrag::RubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
3813         : Drag (e, i)
3814         , _vertical_only (false)
3815 {
3816         DEBUG_TRACE (DEBUG::Drags, "New RubberbandSelectDrag\n");
3817 }
3818
3819 void
3820 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3821 {
3822         Drag::start_grab (event);
3823         show_verbose_cursor_time (adjusted_current_frame (event));
3824 }
3825
3826 void
3827 RubberbandSelectDrag::motion (GdkEvent* event, bool)
3828 {
3829         framepos_t start;
3830         framepos_t end;
3831         double y1;
3832         double y2;
3833
3834         framepos_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
3835
3836         framepos_t grab = grab_frame ();
3837         if (Config->get_rubberbanding_snaps_to_grid ()) {
3838                 _editor->snap_to_with_modifier (grab, event);
3839         }
3840
3841         /* base start and end on initial click position */
3842
3843         if (pf < grab) {
3844                 start = pf;
3845                 end = grab;
3846         } else {
3847                 end = pf;
3848                 start = grab;
3849         }
3850
3851         if (current_pointer_y() < grab_y()) {
3852                 y1 = current_pointer_y();
3853                 y2 = grab_y();
3854         } else {
3855                 y2 = current_pointer_y();
3856                 y1 = grab_y();
3857         }
3858
3859         if (start != end || y1 != y2) {
3860
3861                 double x1 = _editor->sample_to_pixel (start);
3862                 double x2 = _editor->sample_to_pixel (end);
3863                 const double min_dimension = 2.0;
3864
3865                 if (_vertical_only) {
3866                         /* fixed 10 pixel width */
3867                         x2 = x1 + 10;
3868                 } else {
3869                         if (x2 < x1) {
3870                                 x2 = min (x1 - min_dimension, x2);
3871                         } else {
3872                                 x2 = max (x1 + min_dimension, x2);
3873                         }
3874                 } 
3875
3876                 if (y2 < y1) {
3877                         y2 = min (y1 - min_dimension, y2);
3878                 } else {
3879                         y2 = max (y1 + min_dimension, y2);
3880                 }
3881
3882                 /* translate rect into item space and set */
3883
3884                 ArdourCanvas::Rect r (x1, y1, x2, y2);
3885
3886                 /* this drag is a _trackview_only == true drag, so the y1 and
3887                  * y2 (computed using current_pointer_y() and grab_y()) will be
3888                  * relative to the top of the trackview group). The
3889                  * rubberband rect has the same parent/scroll offset as the
3890                  * the trackview group, so we can use the "r" rect directly
3891                  * to set the shape of the rubberband.
3892                  */
3893
3894                 _editor->rubberband_rect->set (r);
3895                 _editor->rubberband_rect->show();
3896                 _editor->rubberband_rect->raise_to_top();
3897
3898                 show_verbose_cursor_time (pf);
3899
3900                 do_select_things (event, true);
3901         }
3902 }
3903
3904 void
3905 RubberbandSelectDrag::do_select_things (GdkEvent* event, bool drag_in_progress)
3906 {
3907         framepos_t x1;
3908         framepos_t x2;
3909         
3910         if (grab_frame() < last_pointer_frame()) {
3911                 x1 = grab_frame ();
3912                 x2 = last_pointer_frame ();
3913         } else {
3914                 x2 = grab_frame ();
3915                 x1 = last_pointer_frame ();
3916         }
3917
3918         double y1;
3919         double y2;
3920         
3921         if (current_pointer_y() < grab_y()) {
3922                 y1 = current_pointer_y();
3923                 y2 = grab_y();
3924         } else {
3925                 y2 = current_pointer_y();
3926                 y1 = grab_y();
3927         }
3928
3929         select_things (event->button.state, x1, x2, y1, y2, drag_in_progress);
3930 }
3931
3932 void
3933 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
3934 {
3935         if (movement_occurred) {
3936
3937                 motion (event, false);
3938                 do_select_things (event, false);
3939
3940         } else {
3941
3942                 /* just a click */
3943
3944                 bool do_deselect = true;
3945                 MidiTimeAxisView* mtv;
3946
3947                 if ((mtv = dynamic_cast<MidiTimeAxisView*>(_editor->clicked_axisview)) != 0) {
3948                         /* MIDI track */
3949                         if (_editor->selection->empty()) {
3950                                 /* nothing selected */
3951                                 add_midi_region (mtv);
3952                                 do_deselect = false;
3953                         }
3954                 } 
3955
3956                 /* do not deselect if Primary or Tertiary (toggle-select or
3957                  * extend-select are pressed.
3958                  */
3959
3960                 if (!Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier) && 
3961                     !Keyboard::modifier_state_contains (event->button.state, Keyboard::TertiaryModifier) && 
3962                     do_deselect) {
3963                         deselect_things ();
3964                 }
3965
3966         }
3967
3968         _editor->rubberband_rect->hide();
3969 }
3970
3971 void
3972 RubberbandSelectDrag::aborted (bool)
3973 {
3974         _editor->rubberband_rect->hide ();
3975 }
3976
3977 TimeFXDrag::TimeFXDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, std::list<RegionView*> const & v)
3978         : RegionDrag (e, i, p, v)
3979 {
3980         DEBUG_TRACE (DEBUG::Drags, "New TimeFXDrag\n");
3981 }
3982
3983 void
3984 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3985 {
3986         Drag::start_grab (event, cursor);
3987
3988         show_verbose_cursor_time (adjusted_current_frame (event));
3989 }
3990
3991 void
3992 TimeFXDrag::motion (GdkEvent* event, bool)
3993 {
3994         RegionView* rv = _primary;
3995         StreamView* cv = rv->get_time_axis_view().view ();
3996
3997         pair<TimeAxisView*, double> const tv = _editor->trackview_by_y_position (grab_y());
3998         int layer = tv.first->layer_display() == Overlaid ? 0 : tv.second;
3999         int layers = tv.first->layer_display() == Overlaid ? 1 : cv->layers();
4000
4001         framepos_t const pf = adjusted_current_frame (event);
4002
4003         if (pf > rv->region()->position()) {
4004                 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf, layers, layer);
4005         }
4006
4007         show_verbose_cursor_time (pf);
4008 }
4009
4010 void
4011 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
4012 {
4013         _primary->get_time_axis_view().hide_timestretch ();
4014
4015         if (!movement_occurred) {
4016                 return;
4017         }
4018
4019         if (last_pointer_frame() < _primary->region()->position()) {
4020                 /* backwards drag of the left edge - not usable */
4021                 return;
4022         }
4023
4024         framecnt_t newlen = last_pointer_frame() - _primary->region()->position();
4025
4026         float percentage = (double) newlen / (double) _primary->region()->length();
4027
4028 #ifndef USE_RUBBERBAND
4029         // Soundtouch uses percentage / 100 instead of normal (/ 1)
4030         if (_primary->region()->data_type() == DataType::AUDIO) {
4031                 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
4032         }
4033 #endif
4034
4035         if (!_editor->get_selection().regions.empty()) {
4036                 /* primary will already be included in the selection, and edit
4037                    group shared editing will propagate selection across
4038                    equivalent regions, so just use the current region
4039                    selection.
4040                 */
4041
4042                 if (_editor->time_stretch (_editor->get_selection().regions, percentage) == -1) {
4043                         error << _("An error occurred while executing time stretch operation") << endmsg;
4044                 }
4045         }
4046 }
4047
4048 void
4049 TimeFXDrag::aborted (bool)
4050 {
4051         _primary->get_time_axis_view().hide_timestretch ();
4052 }
4053
4054 ScrubDrag::ScrubDrag (Editor* e, ArdourCanvas::Item* i)
4055         : Drag (e, i)
4056 {
4057         DEBUG_TRACE (DEBUG::Drags, "New ScrubDrag\n");
4058 }
4059
4060 void
4061 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
4062 {
4063         Drag::start_grab (event);
4064 }
4065
4066 void
4067 ScrubDrag::motion (GdkEvent* /*event*/, bool)
4068 {
4069         _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
4070 }
4071
4072 void
4073 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
4074 {
4075         if (movement_occurred && _editor->session()) {
4076                 /* make sure we stop */
4077                 _editor->session()->request_transport_speed (0.0);
4078         }
4079 }
4080
4081 void
4082 ScrubDrag::aborted (bool)
4083 {
4084         /* XXX: TODO */
4085 }
4086
4087 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
4088         : Drag (e, i)
4089         , _operation (o)
4090         , _add (false)
4091         , _extend (false)
4092         , _original_pointer_time_axis (-1)
4093         , _last_pointer_time_axis (-1)
4094         , _time_selection_at_start (!_editor->get_selection().time.empty())
4095 {
4096         DEBUG_TRACE (DEBUG::Drags, "New SelectionDrag\n");
4097         
4098         if (_time_selection_at_start) {
4099                 start_at_start = _editor->get_selection().time.start();
4100                 end_at_start = _editor->get_selection().time.end_frame();
4101         }
4102 }
4103
4104 void
4105 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
4106 {
4107         if (_editor->session() == 0) {
4108                 return;
4109         }
4110
4111         Gdk::Cursor* cursor = 0;
4112
4113         switch (_operation) {
4114         case CreateSelection:
4115                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
4116                         _add = true;
4117                 } else {
4118                         _add = false;
4119                 }
4120                 cursor = _editor->cursors()->selector;
4121                 Drag::start_grab (event, cursor);
4122                 break;
4123
4124         case SelectionStartTrim:
4125                 if (_editor->clicked_axisview) {
4126                         _editor->clicked_axisview->order_selection_trims (_item, true);
4127                 }
4128                 Drag::start_grab (event, _editor->cursors()->left_side_trim);
4129                 break;
4130
4131         case SelectionEndTrim:
4132                 if (_editor->clicked_axisview) {
4133                         _editor->clicked_axisview->order_selection_trims (_item, false);
4134                 }
4135                 Drag::start_grab (event, _editor->cursors()->right_side_trim);
4136                 break;
4137
4138         case SelectionMove:
4139                 Drag::start_grab (event, cursor);
4140                 break;
4141
4142         case SelectionExtend:
4143                 Drag::start_grab (event, cursor);
4144                 break;
4145         }
4146
4147         if (_operation == SelectionMove) {
4148                 show_verbose_cursor_time (_editor->selection->time[_editor->clicked_selection].start);
4149         } else {
4150                 show_verbose_cursor_time (adjusted_current_frame (event));
4151         }
4152
4153         _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
4154 }
4155
4156 void
4157 SelectionDrag::setup_pointer_frame_offset ()
4158 {
4159         switch (_operation) {
4160         case CreateSelection:
4161                 _pointer_frame_offset = 0;
4162                 break;
4163
4164         case SelectionStartTrim:
4165         case SelectionMove:
4166                 _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].start;
4167                 break;
4168
4169         case SelectionEndTrim:
4170                 _pointer_frame_offset = raw_grab_frame() - _editor->selection->time[_editor->clicked_selection].end;
4171                 break;
4172
4173         case SelectionExtend:
4174                 break;
4175         }
4176 }
4177
4178 void
4179 SelectionDrag::motion (GdkEvent* event, bool first_move)
4180 {
4181         framepos_t start = 0;
4182         framepos_t end = 0;
4183         framecnt_t length = 0;
4184         framecnt_t distance = 0;
4185
4186         framepos_t const pending_position = adjusted_current_frame (event);
4187
4188         if (_operation != CreateSelection && pending_position == last_pointer_frame()) {
4189                 return;
4190         }
4191
4192         switch (_operation) {
4193         case CreateSelection:
4194         {
4195                 framepos_t grab = grab_frame ();
4196
4197                 if (first_move) {
4198                         grab = adjusted_current_frame (event, false);
4199                         if (grab < pending_position) {
4200                                 _editor->snap_to (grab, -1);
4201                         }  else {
4202                                 _editor->snap_to (grab, 1);
4203                         }
4204                 }
4205
4206                 if (pending_position < grab) {
4207                         start = pending_position;
4208                         end = grab;
4209                 } else {
4210                         end = pending_position;
4211                         start = grab;
4212                 }
4213
4214                 /* first drag: Either add to the selection
4215                    or create a new selection
4216                 */
4217
4218                 if (first_move) {
4219
4220                         if (_add) {
4221
4222                                 /* adding to the selection */
4223                                 _editor->set_selected_track_as_side_effect (Selection::Add);
4224                                 _editor->clicked_selection = _editor->selection->add (start, end);
4225                                 _add = false;
4226                                 
4227                         } else {
4228
4229                                 /* new selection */
4230
4231                                 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
4232                                         _editor->set_selected_track_as_side_effect (Selection::Set);
4233                                 }
4234
4235                                 _editor->clicked_selection = _editor->selection->set (start, end);
4236                         }
4237                 }
4238                 
4239                 /* select all tracks within the rectangle that we've marked out so far */
4240                 TrackViewList to_be_added_to_selection;
4241                 TrackViewList to_be_removed_from_selection;
4242                 TrackViewList& all_tracks (_editor->track_views);
4243
4244                 ArdourCanvas::Coord const top = grab_y();
4245                 ArdourCanvas::Coord const bottom = current_pointer_y();
4246
4247                 if (top >= 0 && bottom >= 0) {
4248
4249                         for (TrackViewList::const_iterator i = all_tracks.begin(); i != all_tracks.end(); ++i) {
4250                         
4251                                 if ((*i)->covered_by_y_range (top, bottom)) {
4252                                         if (!(*i)->get_selected()) {
4253                                                 to_be_added_to_selection.push_back (*i);
4254                                         }
4255                                 } else {
4256                                         if ((*i)->get_selected()) {
4257                                                 to_be_removed_from_selection.push_back (*i);
4258                                         }
4259                                 }
4260                         }
4261
4262                         if (!to_be_added_to_selection.empty()) {
4263                                 _editor->selection->add (to_be_added_to_selection);
4264                         }
4265                         
4266                         if (!to_be_removed_from_selection.empty()) {
4267                                 _editor->selection->remove (to_be_removed_from_selection);
4268                         }
4269                 }
4270         }
4271         break;
4272
4273         case SelectionStartTrim:
4274
4275                 start = _editor->selection->time[_editor->clicked_selection].start;
4276                 end = _editor->selection->time[_editor->clicked_selection].end;
4277
4278                 if (pending_position > end) {
4279                         start = end;
4280                 } else {
4281                         start = pending_position;
4282                 }
4283                 break;
4284
4285         case SelectionEndTrim:
4286
4287                 start = _editor->selection->time[_editor->clicked_selection].start;
4288                 end = _editor->selection->time[_editor->clicked_selection].end;
4289
4290                 if (pending_position < start) {
4291                         end = start;
4292                 } else {
4293                         end = pending_position;
4294                 }
4295
4296                 break;
4297                 
4298         case SelectionMove:
4299
4300                 start = _editor->selection->time[_editor->clicked_selection].start;
4301                 end = _editor->selection->time[_editor->clicked_selection].end;
4302
4303                 length = end - start;
4304                 distance = pending_position - start;
4305                 start = pending_position;
4306                 _editor->snap_to (start);
4307
4308                 end = start + length;
4309
4310                 break;
4311
4312         case SelectionExtend:
4313                 break;
4314         }
4315
4316         if (start != end) {
4317                 switch (_operation) {
4318                 case SelectionMove:     
4319                         if (_time_selection_at_start) {
4320                                 _editor->selection->move_time (distance);
4321                         }
4322                         break;
4323                 default:
4324                         _editor->selection->replace (_editor->clicked_selection, start, end);
4325                 }
4326         }
4327
4328         if (_operation == SelectionMove) {
4329                 show_verbose_cursor_time(start);
4330         } else {
4331                 show_verbose_cursor_time(pending_position);
4332         }
4333 }
4334
4335 void
4336 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
4337 {
4338         Session* s = _editor->session();
4339
4340         if (movement_occurred) {
4341                 motion (event, false);
4342                 /* XXX this is not object-oriented programming at all. ick */
4343                 if (_editor->selection->time.consolidate()) {
4344                         _editor->selection->TimeChanged ();
4345                 }
4346
4347                 /* XXX what if its a music time selection? */
4348                 if (s) {
4349                         if ( s->get_play_range() && s->transport_rolling() ) {
4350                                 s->request_play_range (&_editor->selection->time, true);
4351                         } else {
4352                                 if (Config->get_follow_edits() && !s->transport_rolling()) {
4353                                         s->request_locate (_editor->get_selection().time.start());
4354                                 }
4355                         }
4356                 }
4357
4358         } else {
4359                 /* just a click, no pointer movement.
4360                  */
4361
4362                 if (_operation == SelectionExtend) {
4363                         if (_time_selection_at_start) {
4364                                 framepos_t pos = adjusted_current_frame (event, false);
4365                                 framepos_t start = min (pos, start_at_start);
4366                                 framepos_t end = max (pos, end_at_start);
4367                                 _editor->selection->set (start, end);
4368                         }
4369                 } else {
4370                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::CopyModifier)) {
4371                                 if (_editor->clicked_selection) {
4372                                         _editor->selection->remove (_editor->clicked_selection);
4373                                 }
4374                         } else {
4375                                 if (!_editor->clicked_selection) {
4376                                         _editor->selection->clear_time();
4377                                 }
4378                         }
4379                 }
4380
4381                 if (_editor->clicked_axisview && !_editor->selection->selected (_editor->clicked_axisview)) {
4382                         _editor->selection->set (_editor->clicked_axisview);
4383                 }
4384                         
4385                 if (s && s->get_play_range () && s->transport_rolling()) {
4386                         s->request_stop (false, false);
4387                 }
4388
4389         }
4390
4391         _editor->stop_canvas_autoscroll ();
4392         _editor->clicked_selection = 0;
4393 }
4394
4395 void
4396 SelectionDrag::aborted (bool)
4397 {
4398         /* XXX: TODO */
4399 }
4400
4401 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
4402         : Drag (e, i, false),
4403           _operation (o),
4404           _copy (false)
4405 {
4406         DEBUG_TRACE (DEBUG::Drags, "New RangeMarkerBarDrag\n");
4407
4408         _drag_rect = new ArdourCanvas::Rectangle (_editor->time_line_group, 
4409                                                   ArdourCanvas::Rect (0.0, 0.0, 0.0,
4410                                                                       physical_screen_height (_editor->get_window())));
4411         _drag_rect->hide ();
4412
4413         _drag_rect->set_fill_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
4414         _drag_rect->set_outline_color (ARDOUR_UI::config()->get_canvasvar_RangeDragRect());
4415 }
4416
4417 void
4418 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
4419 {
4420         if (_editor->session() == 0) {
4421                 return;
4422         }
4423
4424         Gdk::Cursor* cursor = 0;
4425
4426         if (!_editor->temp_location) {
4427                 _editor->temp_location = new Location (*_editor->session());
4428         }
4429
4430         switch (_operation) {
4431         case CreateRangeMarker:
4432         case CreateTransportMarker:
4433         case CreateCDMarker:
4434
4435                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
4436                         _copy = true;
4437                 } else {
4438                         _copy = false;
4439                 }
4440                 cursor = _editor->cursors()->selector;
4441                 break;
4442         }
4443
4444         Drag::start_grab (event, cursor);
4445
4446         show_verbose_cursor_time (adjusted_current_frame (event));
4447 }
4448
4449 void
4450 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
4451 {
4452         framepos_t start = 0;
4453         framepos_t end = 0;
4454         ArdourCanvas::Rectangle *crect;
4455
4456         switch (_operation) {
4457         case CreateRangeMarker:
4458                 crect = _editor->range_bar_drag_rect;
4459                 break;
4460         case CreateTransportMarker:
4461                 crect = _editor->transport_bar_drag_rect;
4462                 break;
4463         case CreateCDMarker:
4464                 crect = _editor->cd_marker_bar_drag_rect;
4465                 break;
4466         default:
4467                 error << string_compose (_("programming_error: %1"), "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()") << endmsg;
4468                 return;
4469                 break;
4470         }
4471
4472         framepos_t const pf = adjusted_current_frame (event);
4473
4474         if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
4475                 framepos_t grab = grab_frame ();
4476                 _editor->snap_to (grab);
4477
4478                 if (pf < grab_frame()) {
4479                         start = pf;
4480                         end = grab;
4481                 } else {
4482                         end = pf;
4483                         start = grab;
4484                 }
4485
4486                 /* first drag: Either add to the selection
4487                    or create a new selection.
4488                 */
4489
4490                 if (first_move) {
4491
4492                         _editor->temp_location->set (start, end);
4493
4494                         crect->show ();
4495
4496                         update_item (_editor->temp_location);
4497                         _drag_rect->show();
4498                         //_drag_rect->raise_to_top();
4499
4500                 }
4501         }
4502
4503         if (start != end) {
4504                 _editor->temp_location->set (start, end);
4505
4506                 double x1 = _editor->sample_to_pixel (start);
4507                 double x2 = _editor->sample_to_pixel (end);
4508                 crect->set_x0 (x1);
4509                 crect->set_x1 (x2);
4510
4511                 update_item (_editor->temp_location);
4512         }
4513
4514         show_verbose_cursor_time (pf);
4515
4516 }
4517
4518 void
4519 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
4520 {
4521         Location * newloc = 0;
4522         string rangename;
4523         int flags;
4524
4525         if (movement_occurred) {
4526                 motion (event, false);
4527                 _drag_rect->hide();
4528
4529                 switch (_operation) {
4530                 case CreateRangeMarker:
4531                 case CreateCDMarker:
4532                     {
4533                         _editor->begin_reversible_command (_("new range marker"));
4534                         XMLNode &before = _editor->session()->locations()->get_state();
4535                         _editor->session()->locations()->next_available_name(rangename,"unnamed");
4536                         if (_operation == CreateCDMarker) {
4537                                 flags = Location::IsRangeMarker | Location::IsCDMarker;
4538                                 _editor->cd_marker_bar_drag_rect->hide();
4539                         }
4540                         else {
4541                                 flags = Location::IsRangeMarker;
4542                                 _editor->range_bar_drag_rect->hide();
4543                         }
4544                         newloc = new Location (
4545                                 *_editor->session(), _editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags
4546                                 );
4547
4548                         _editor->session()->locations()->add (newloc, true);
4549                         XMLNode &after = _editor->session()->locations()->get_state();
4550                         _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
4551                         _editor->commit_reversible_command ();
4552                         break;
4553                     }
4554
4555                 case CreateTransportMarker:
4556                         // popup menu to pick loop or punch
4557                         _editor->new_transport_marker_context_menu (&event->button, _item);
4558                         break;
4559                 }
4560
4561         } else {
4562
4563                 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
4564
4565                 if (_operation == CreateTransportMarker) {
4566
4567                         /* didn't drag, so just locate */
4568
4569                         _editor->session()->request_locate (grab_frame(), _editor->session()->transport_rolling());
4570
4571                 } else if (_operation == CreateCDMarker) {
4572
4573                         /* didn't drag, but mark is already created so do
4574                          * nothing */
4575
4576                 } else { /* operation == CreateRangeMarker */
4577                         
4578
4579                         framepos_t start;
4580                         framepos_t end;
4581
4582                         _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
4583
4584                         if (end == max_framepos) {
4585                                 end = _editor->session()->current_end_frame ();
4586                         }
4587
4588                         if (start == max_framepos) {
4589                                 start = _editor->session()->current_start_frame ();
4590                         }
4591
4592                         switch (_editor->mouse_mode) {
4593                         case MouseObject:
4594                                 /* find the two markers on either side and then make the selection from it */
4595                                 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set, false);
4596                                 break;
4597
4598                         case MouseRange:
4599                                 /* find the two markers on either side of the click and make the range out of it */
4600                                 _editor->selection->set (start, end);
4601                                 break;
4602
4603                         default:
4604                                 break;
4605                         }
4606                 }
4607         }
4608
4609         _editor->stop_canvas_autoscroll ();
4610 }
4611
4612 void
4613 RangeMarkerBarDrag::aborted (bool)
4614 {
4615         /* XXX: TODO */
4616 }
4617
4618 void
4619 RangeMarkerBarDrag::update_item (Location* location)
4620 {
4621         double const x1 = _editor->sample_to_pixel (location->start());
4622         double const x2 = _editor->sample_to_pixel (location->end());
4623
4624         _drag_rect->set_x0 (x1);
4625         _drag_rect->set_x1 (x2);
4626 }
4627
4628 MouseZoomDrag::MouseZoomDrag (Editor* e, ArdourCanvas::Item* i)
4629         : Drag (e, i)
4630         , _zoom_out (false)
4631 {
4632         DEBUG_TRACE (DEBUG::Drags, "New MouseZoomDrag\n");
4633 }
4634
4635 void
4636 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
4637 {
4638         if (Keyboard::the_keyboard().key_is_down (GDK_Control_L)) {
4639                 Drag::start_grab (event, _editor->cursors()->zoom_out);
4640                 _zoom_out = true;
4641         } else {
4642                 Drag::start_grab (event, _editor->cursors()->zoom_in);
4643                 _zoom_out = false;
4644         }
4645
4646         show_verbose_cursor_time (adjusted_current_frame (event));
4647 }
4648
4649 void
4650 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
4651 {
4652         framepos_t start;
4653         framepos_t end;
4654
4655         framepos_t const pf = adjusted_current_frame (event);
4656
4657         framepos_t grab = grab_frame ();
4658         _editor->snap_to_with_modifier (grab, event);
4659
4660         /* base start and end on initial click position */
4661         if (pf < grab) {
4662                 start = pf;
4663                 end = grab;
4664         } else {
4665                 end = pf;
4666                 start = grab;
4667         }
4668
4669         if (start != end) {
4670
4671                 if (first_move) {
4672                         _editor->zoom_rect->show();
4673                         _editor->zoom_rect->raise_to_top();
4674                 }
4675
4676                 _editor->reposition_zoom_rect(start, end);
4677
4678                 show_verbose_cursor_time (pf);
4679         }
4680 }
4681
4682 void
4683 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
4684 {
4685         if (movement_occurred) {
4686                 motion (event, false);
4687
4688                 if (grab_frame() < last_pointer_frame()) {
4689                         _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame());
4690                 } else {
4691                         _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame());
4692                 }
4693         } else {
4694                 if (Keyboard::the_keyboard().key_is_down (GDK_Shift_L)) {
4695                         _editor->tav_zoom_step (_zoom_out);
4696                 } else {
4697                         _editor->temporal_zoom_to_frame (_zoom_out, grab_frame());
4698                 }
4699         }
4700
4701         _editor->zoom_rect->hide();
4702 }
4703
4704 void
4705 MouseZoomDrag::aborted (bool)
4706 {
4707         _editor->zoom_rect->hide ();
4708 }
4709
4710 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
4711         : Drag (e, i)
4712         , _cumulative_dx (0)
4713         , _cumulative_dy (0)
4714 {
4715         DEBUG_TRACE (DEBUG::Drags, "New NoteDrag\n");
4716
4717         _primary = reinterpret_cast<NoteBase*> (_item->get_data ("notebase"));
4718         assert (_primary);
4719         _region = &_primary->region_view ();
4720         _note_height = _region->midi_stream_view()->note_height ();
4721 }
4722
4723 void
4724 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
4725 {
4726         Drag::start_grab (event);
4727
4728         if (!(_was_selected = _primary->selected())) {
4729
4730                 /* tertiary-click means extend selection - we'll do that on button release,
4731                    so don't add it here, because otherwise we make it hard to figure
4732                    out the "extend-to" range.
4733                 */
4734
4735                 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
4736
4737                 if (!extend) {
4738                         bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
4739
4740                         if (add) {
4741                                 _region->note_selected (_primary, true);
4742                         } else {
4743                                 _region->unique_select (_primary);
4744                         }
4745                 }
4746         }
4747 }
4748
4749 /** @return Current total drag x change in frames */
4750 frameoffset_t
4751 NoteDrag::total_dx () const
4752 {
4753         /* dx in frames */
4754         frameoffset_t const dx = _editor->pixel_to_sample (_drags->current_pointer_x() - grab_x());
4755
4756         /* primary note time */
4757         frameoffset_t const n = _region->source_beats_to_absolute_frames (_primary->note()->time ());
4758
4759         /* new time of the primary note in session frames */
4760         frameoffset_t st = n + dx;
4761
4762         framepos_t const rp = _region->region()->position ();
4763
4764         /* prevent the note being dragged earlier than the region's position */
4765         st = max (st, rp);
4766
4767         /* snap and return corresponding delta */
4768         return _region->snap_frame_to_frame (st - rp) + rp - n;
4769 }
4770
4771 /** @return Current total drag y change in note number */
4772 int8_t
4773 NoteDrag::total_dy () const
4774 {
4775         MidiStreamView* msv = _region->midi_stream_view ();
4776         double const y = _region->midi_view()->y_position ();
4777         /* new current note */
4778         uint8_t n = msv->y_to_note (current_pointer_y () - y);
4779         /* clamp */
4780         n = max (msv->lowest_note(), n);
4781         n = min (msv->highest_note(), n);
4782         /* and work out delta */
4783         return n - msv->y_to_note (grab_y() - y);
4784 }
4785
4786 void
4787 NoteDrag::motion (GdkEvent *, bool)
4788 {
4789         /* Total change in x and y since the start of the drag */
4790         frameoffset_t const dx = total_dx ();
4791         int8_t const dy = total_dy ();
4792
4793         /* Now work out what we have to do to the note canvas items to set this new drag delta */
4794         double const tdx = _editor->sample_to_pixel (dx) - _cumulative_dx;
4795         double const tdy = -dy * _note_height - _cumulative_dy;
4796
4797         if (tdx || tdy) {
4798                 _cumulative_dx += tdx;
4799                 _cumulative_dy += tdy;
4800
4801                 int8_t note_delta = total_dy();
4802
4803                 _region->move_selection (tdx, tdy, note_delta);
4804
4805                 /* the new note value may be the same as the old one, but we
4806                  * don't know what that means because the selection may have
4807                  * involved more than one note and we might be doing something
4808                  * odd with them. so show the note value anyway, always.
4809                  */
4810
4811                 char buf[12];
4812                 uint8_t new_note = min (max (_primary->note()->note() + note_delta, 0), 127);
4813                 
4814                 snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (new_note).c_str(),
4815                           (int) floor ((double)new_note));
4816
4817                 show_verbose_cursor_text (buf);
4818         }
4819 }
4820
4821 void
4822 NoteDrag::finished (GdkEvent* ev, bool moved)
4823 {
4824         if (!moved) {
4825                 /* no motion - select note */
4826                 
4827                 if (_editor->current_mouse_mode() == Editing::MouseObject ||
4828                     _editor->current_mouse_mode() == Editing::MouseDraw) {
4829                         
4830                         if (_was_selected) {
4831                                 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
4832                                 if (add) {
4833                                         _region->note_deselected (_primary);
4834                                 }
4835                         } else {
4836                                 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
4837                                 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
4838
4839                                 if (!extend && !add && _region->selection_size() > 1) {
4840                                         _region->unique_select (_primary);
4841                                 } else if (extend) {
4842                                         _region->note_selected (_primary, true, true);
4843                                 } else {
4844                                         /* it was added during button press */
4845                                 }
4846                         }
4847                 }
4848         } else {
4849                 _region->note_dropped (_primary, total_dx(), total_dy());
4850         }
4851 }
4852
4853 void
4854 NoteDrag::aborted (bool)
4855 {
4856         /* XXX: TODO */
4857 }
4858
4859 /** Make an AutomationRangeDrag for lines in an AutomationTimeAxisView */
4860 AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AutomationTimeAxisView* atv, list<AudioRange> const & r)
4861         : Drag (editor, atv->base_item ())
4862         , _ranges (r)
4863         , _nothing_to_drag (false)
4864 {
4865         DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
4866         y_origin = atv->y_position();
4867         setup (atv->lines ());
4868 }
4869
4870 /** Make an AutomationRangeDrag for region gain lines */
4871 AutomationRangeDrag::AutomationRangeDrag (Editor* editor, AudioRegionView* rv, list<AudioRange> const & r)
4872         : Drag (editor, rv->get_canvas_group ())
4873         , _ranges (r)
4874         , _nothing_to_drag (false)
4875 {
4876         DEBUG_TRACE (DEBUG::Drags, "New AutomationRangeDrag\n");
4877
4878         list<boost::shared_ptr<AutomationLine> > lines;
4879         lines.push_back (rv->get_gain_line ());
4880         y_origin = rv->get_time_axis_view().y_position();
4881         setup (lines);
4882 }
4883
4884 /** @param lines AutomationLines to drag.
4885  *  @param offset Offset from the session start to the points in the AutomationLines.
4886  */
4887 void
4888 AutomationRangeDrag::setup (list<boost::shared_ptr<AutomationLine> > const & lines)
4889 {
4890         /* find the lines that overlap the ranges being dragged */
4891         list<boost::shared_ptr<AutomationLine> >::const_iterator i = lines.begin ();
4892         while (i != lines.end ()) {
4893                 list<boost::shared_ptr<AutomationLine> >::const_iterator j = i;
4894                 ++j;
4895
4896                 pair<framepos_t, framepos_t> r = (*i)->get_point_x_range ();
4897
4898                 /* check this range against all the AudioRanges that we are using */
4899                 list<AudioRange>::const_iterator k = _ranges.begin ();
4900                 while (k != _ranges.end()) {
4901                         if (k->coverage (r.first, r.second) != Evoral::OverlapNone) {
4902                                 break;
4903                         }
4904                         ++k;
4905                 }
4906
4907                 /* add it to our list if it overlaps at all */
4908                 if (k != _ranges.end()) {
4909                         Line n;
4910                         n.line = *i;
4911                         n.state = 0;
4912                         n.range = r;
4913                         _lines.push_back (n);
4914                 }
4915
4916                 i = j;
4917         }
4918
4919         /* Now ::lines contains the AutomationLines that somehow overlap our drag */
4920 }
4921
4922 double
4923 AutomationRangeDrag::y_fraction (boost::shared_ptr<AutomationLine> line, double global_y) const
4924 {
4925         return 1.0 - ((global_y - y_origin) / line->height());
4926 }
4927
4928 void
4929 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
4930 {
4931         Drag::start_grab (event, cursor);
4932
4933         /* Get line states before we start changing things */
4934         for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
4935                 i->state = &i->line->get_state ();
4936                 i->original_fraction = y_fraction (i->line, current_pointer_y());
4937         }
4938
4939         if (_ranges.empty()) {
4940
4941                 /* No selected time ranges: drag all points */
4942                 for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
4943                         uint32_t const N = i->line->npoints ();
4944                         for (uint32_t j = 0; j < N; ++j) {
4945                                 i->points.push_back (i->line->nth (j));
4946                         }
4947                 }
4948
4949         } else {
4950
4951                 for (list<AudioRange>::const_iterator i = _ranges.begin(); i != _ranges.end(); ++i) {
4952
4953                         framecnt_t const half = (i->start + i->end) / 2;
4954
4955                         /* find the line that this audio range starts in */
4956                         list<Line>::iterator j = _lines.begin();
4957                         while (j != _lines.end() && (j->range.first > i->start || j->range.second < i->start)) {
4958                                 ++j;
4959                         }
4960
4961                         if (j != _lines.end()) {
4962                                 boost::shared_ptr<AutomationList> the_list = j->line->the_list ();
4963
4964                                 /* j is the line that this audio range starts in; fade into it;
4965                                    64 samples length plucked out of thin air.
4966                                 */
4967
4968                                 framepos_t a = i->start + 64;
4969                                 if (a > half) {
4970                                         a = half;
4971                                 }
4972
4973                                 double const p = j->line->time_converter().from (i->start - j->line->time_converter().origin_b ());
4974                                 double const q = j->line->time_converter().from (a - j->line->time_converter().origin_b ());
4975
4976                                 the_list->add (p, the_list->eval (p));
4977                                 the_list->add (q, the_list->eval (q));
4978                         }
4979
4980                         /* same thing for the end */
4981
4982                         j = _lines.begin();
4983                         while (j != _lines.end() && (j->range.first > i->end || j->range.second < i->end)) {
4984                                 ++j;
4985                         }
4986
4987                         if (j != _lines.end()) {
4988                                 boost::shared_ptr<AutomationList> the_list = j->line->the_list ();
4989
4990                                 /* j is the line that this audio range starts in; fade out of it;
4991                                    64 samples length plucked out of thin air.
4992                                 */
4993
4994                                 framepos_t b = i->end - 64;
4995                                 if (b < half) {
4996                                         b = half;
4997                                 }
4998
4999                                 double const p = j->line->time_converter().from (b - j->line->time_converter().origin_b ());
5000                                 double const q = j->line->time_converter().from (i->end - j->line->time_converter().origin_b ());
5001
5002                                 the_list->add (p, the_list->eval (p));
5003                                 the_list->add (q, the_list->eval (q));
5004                         }
5005                 }
5006
5007                 _nothing_to_drag = true;
5008
5009                 /* Find all the points that should be dragged and put them in the relevant
5010                    points lists in the Line structs.
5011                 */
5012
5013                 for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
5014
5015                         uint32_t const N = i->line->npoints ();
5016                         for (uint32_t j = 0; j < N; ++j) {
5017
5018                                 /* here's a control point on this line */
5019                                 ControlPoint* p = i->line->nth (j);
5020                                 double const w = i->line->time_converter().to ((*p->model())->when) + i->line->time_converter().origin_b ();
5021
5022                                 /* see if it's inside a range */
5023                                 list<AudioRange>::const_iterator k = _ranges.begin ();
5024                                 while (k != _ranges.end() && (k->start >= w || k->end <= w)) {
5025                                         ++k;
5026                                 }
5027
5028                                 if (k != _ranges.end()) {
5029                                         /* dragging this point */
5030                                         _nothing_to_drag = false;
5031                                         i->points.push_back (p);
5032                                 }
5033                         }
5034                 }
5035         }
5036
5037         if (_nothing_to_drag) {
5038                 return;
5039         }
5040
5041         for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
5042                 i->line->start_drag_multiple (i->points, y_fraction (i->line, current_pointer_y()), i->state);
5043         }
5044 }
5045
5046 void
5047 AutomationRangeDrag::motion (GdkEvent*, bool /*first_move*/)
5048 {
5049         if (_nothing_to_drag) {
5050                 return;
5051         }
5052
5053         for (list<Line>::iterator l = _lines.begin(); l != _lines.end(); ++l) {
5054                 float const f = y_fraction (l->line, current_pointer_y());
5055                 /* we are ignoring x position for this drag, so we can just pass in anything */
5056                 uint32_t ignored;
5057                 l->line->drag_motion (0, f, true, false, ignored);
5058                 show_verbose_cursor_text (l->line->get_verbose_cursor_relative_string (l->original_fraction, f));
5059         }
5060 }
5061
5062 void
5063 AutomationRangeDrag::finished (GdkEvent* event, bool)
5064 {
5065         if (_nothing_to_drag) {
5066                 return;
5067         }
5068
5069         motion (event, false);
5070         for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
5071                 i->line->end_drag (false, 0);
5072         }
5073
5074         _editor->session()->commit_reversible_command ();
5075 }
5076
5077 void
5078 AutomationRangeDrag::aborted (bool)
5079 {
5080         for (list<Line>::iterator i = _lines.begin(); i != _lines.end(); ++i) {
5081                 i->line->reset ();
5082         }
5083 }
5084
5085 DraggingView::DraggingView (RegionView* v, RegionDrag* parent, TimeAxisView* itav)
5086         : view (v)
5087         , initial_time_axis_view (itav)
5088 {
5089         /* note that time_axis_view may be null if the regionview was created
5090          * as part of a copy operation.
5091          */
5092         time_axis_view = parent->find_time_axis_view (&v->get_time_axis_view ());
5093         layer = v->region()->layer ();
5094         initial_y = v->get_canvas_group()->position().y;
5095         initial_playlist = v->region()->playlist ();
5096         initial_position = v->region()->position ();
5097         initial_end = v->region()->position () + v->region()->length ();
5098 }
5099
5100 PatchChangeDrag::PatchChangeDrag (Editor* e, PatchChange* i, MidiRegionView* r)
5101         : Drag (e, i->canvas_item ())
5102         , _region_view (r)
5103         , _patch_change (i)
5104         , _cumulative_dx (0)
5105 {
5106         DEBUG_TRACE (DEBUG::Drags, string_compose ("New PatchChangeDrag, patch @ %1, grab @ %2\n",
5107                                                    _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time()),
5108                                                    grab_frame()));
5109 }
5110
5111 void
5112 PatchChangeDrag::motion (GdkEvent* ev, bool)
5113 {
5114         framepos_t f = adjusted_current_frame (ev);
5115         boost::shared_ptr<Region> r = _region_view->region ();
5116         f = max (f, r->position ());
5117         f = min (f, r->last_frame ());
5118
5119         framecnt_t const dxf = f - grab_frame(); // permitted dx in frames
5120         double const dxu = _editor->sample_to_pixel (dxf); // permitted fx in units
5121         _patch_change->move (ArdourCanvas::Duple (dxu - _cumulative_dx, 0));
5122         _cumulative_dx = dxu;
5123 }
5124
5125 void
5126 PatchChangeDrag::finished (GdkEvent* ev, bool movement_occurred)
5127 {
5128         if (!movement_occurred) {
5129                 return;
5130         }
5131
5132         boost::shared_ptr<Region> r (_region_view->region ());
5133         framepos_t f = adjusted_current_frame (ev);
5134         f = max (f, r->position ());
5135         f = min (f, r->last_frame ());
5136
5137         _region_view->move_patch_change (
5138                 *_patch_change,
5139                 _region_view->region_frames_to_region_beats (f - (r->position() - r->start()))
5140                 );
5141 }
5142
5143 void
5144 PatchChangeDrag::aborted (bool)
5145 {
5146         _patch_change->move (ArdourCanvas::Duple (-_cumulative_dx, 0));
5147 }
5148
5149 void
5150 PatchChangeDrag::setup_pointer_frame_offset ()
5151 {
5152         boost::shared_ptr<Region> region = _region_view->region ();
5153         _pointer_frame_offset = raw_grab_frame() - _region_view->source_beats_to_absolute_frames (_patch_change->patch()->time());
5154 }
5155
5156 MidiRubberbandSelectDrag::MidiRubberbandSelectDrag (Editor* e, MidiRegionView* rv)
5157         : RubberbandSelectDrag (e, rv->get_canvas_group ())
5158         , _region_view (rv)
5159 {
5160
5161 }
5162
5163 void
5164 MidiRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool /*drag_in_progress*/)
5165 {
5166         framepos_t const p = _region_view->region()->position ();
5167         double const y = _region_view->midi_view()->y_position ();
5168
5169         x1 = max ((framepos_t) 0, x1 - p);
5170         x2 = max ((framepos_t) 0, x2 - p);
5171         y1 = max (0.0, y1 - y);
5172         y2 = max (0.0, y2 - y);
5173         
5174         _region_view->update_drag_selection (
5175                 _editor->sample_to_pixel (x1),
5176                 _editor->sample_to_pixel (x2),
5177                 y1,
5178                 y2,
5179                 Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier)
5180                 );
5181 }
5182
5183 void
5184 MidiRubberbandSelectDrag::deselect_things ()
5185 {
5186         /* XXX */
5187 }
5188
5189 MidiVerticalSelectDrag::MidiVerticalSelectDrag (Editor* e, MidiRegionView* rv)
5190         : RubberbandSelectDrag (e, rv->get_canvas_group ())
5191         , _region_view (rv)
5192 {
5193         _vertical_only = true;
5194 }
5195
5196 void
5197 MidiVerticalSelectDrag::select_things (int button_state, framepos_t /*x1*/, framepos_t /*x2*/, double y1, double y2, bool /*drag_in_progress*/)
5198 {
5199         double const y = _region_view->midi_view()->y_position ();
5200
5201         y1 = max (0.0, y1 - y);
5202         y2 = max (0.0, y2 - y);
5203         
5204         _region_view->update_vertical_drag_selection (
5205                 y1,
5206                 y2,
5207                 Keyboard::modifier_state_contains (button_state, Keyboard::TertiaryModifier)
5208                 );
5209 }
5210
5211 void
5212 MidiVerticalSelectDrag::deselect_things ()
5213 {
5214         /* XXX */
5215 }
5216
5217 EditorRubberbandSelectDrag::EditorRubberbandSelectDrag (Editor* e, ArdourCanvas::Item* i)
5218         : RubberbandSelectDrag (e, i)
5219 {
5220
5221 }
5222
5223 void
5224 EditorRubberbandSelectDrag::select_things (int button_state, framepos_t x1, framepos_t x2, double y1, double y2, bool drag_in_progress)
5225 {
5226         if (drag_in_progress) {
5227                 /* We just want to select things at the end of the drag, not during it */
5228                 return;
5229         }
5230         
5231         Selection::Operation op = ArdourKeyboard::selection_type (button_state);
5232         
5233         _editor->begin_reversible_command (_("rubberband selection"));
5234         _editor->select_all_within (x1, x2 - 1, y1, y2, _editor->track_views, op, false);
5235         _editor->commit_reversible_command ();
5236 }
5237
5238 void
5239 EditorRubberbandSelectDrag::deselect_things ()
5240 {
5241         if (!getenv("ARDOUR_SAE")) {
5242                 _editor->selection->clear_tracks();
5243         }
5244         _editor->selection->clear_regions();
5245         _editor->selection->clear_points ();
5246         _editor->selection->clear_lines ();
5247 }
5248
5249 NoteCreateDrag::NoteCreateDrag (Editor* e, ArdourCanvas::Item* i, MidiRegionView* rv)
5250         : Drag (e, i)
5251         , _region_view (rv)
5252         , _drag_rect (0)
5253 {
5254         
5255 }
5256
5257 NoteCreateDrag::~NoteCreateDrag ()
5258 {
5259         delete _drag_rect;
5260 }
5261
5262 framecnt_t
5263 NoteCreateDrag::grid_frames (framepos_t t) const
5264 {
5265         bool success;
5266         Evoral::MusicalTime grid_beats = _editor->get_grid_type_as_beats (success, t);
5267         if (!success) {
5268                 grid_beats = 1;
5269         }
5270
5271         return _region_view->region_beats_to_region_frames (grid_beats);
5272 }
5273
5274 void
5275 NoteCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
5276 {
5277         Drag::start_grab (event, cursor);
5278                                                  
5279         _drag_rect = new ArdourCanvas::Rectangle (_region_view->get_canvas_group ());
5280
5281         framepos_t pf = _drags->current_pointer_frame ();
5282         framecnt_t const g = grid_frames (pf);
5283
5284         /* Hack so that we always snap to the note that we are over, instead of snapping
5285            to the next one if we're more than halfway through the one we're over.
5286         */
5287         if (_editor->snap_mode() == SnapNormal && pf > g / 2) {
5288                 pf -= g / 2;
5289         }
5290
5291         _note[0] = adjusted_frame (pf, event) - _region_view->region()->position ();
5292
5293         MidiStreamView* sv = _region_view->midi_stream_view ();
5294         double const x = _editor->sample_to_pixel (_note[0]);
5295         double const y = sv->note_to_y (sv->y_to_note (y_to_region (event->button.y)));
5296
5297         _drag_rect->set (ArdourCanvas::Rect (x, y, x, y + floor (_region_view->midi_stream_view()->note_height ())));
5298         _drag_rect->set_outline_all ();
5299         _drag_rect->set_outline_color (0xffffff99);
5300         _drag_rect->set_fill_color (0xffffff66);
5301 }
5302
5303 void
5304 NoteCreateDrag::motion (GdkEvent* event, bool)
5305 {
5306         _note[1] = max ((framepos_t)0, adjusted_current_frame (event) - _region_view->region()->position ());
5307         double const x = _editor->sample_to_pixel (_note[1]);
5308         if (_note[1] > _note[0]) {
5309                 _drag_rect->set_x1 (x);
5310         } else {
5311                 _drag_rect->set_x0 (x);
5312         }
5313 }
5314
5315 void
5316 NoteCreateDrag::finished (GdkEvent*, bool had_movement)
5317 {
5318         if (!had_movement) {
5319                 return;
5320         }
5321         
5322         framepos_t const start = min (_note[0], _note[1]);
5323         framecnt_t length = (framecnt_t) fabs ((double)(_note[0] - _note[1]));
5324
5325         framecnt_t const g = grid_frames (start);
5326         double const one_tick = 1 / Timecode::BBT_Time::ticks_per_beat;
5327         
5328         if (_editor->snap_mode() == SnapNormal && length < g) {
5329                 length = g - one_tick;
5330         }
5331
5332         double const length_beats = max (one_tick, _region_view->region_frames_to_region_beats (length));
5333
5334         _region_view->create_note_at (start, _drag_rect->y0(), length_beats, false);
5335 }
5336
5337 double
5338 NoteCreateDrag::y_to_region (double y) const
5339 {
5340         double x = 0;
5341         _region_view->get_canvas_group()->canvas_to_item (x, y);
5342         return y;
5343 }
5344
5345 void
5346 NoteCreateDrag::aborted (bool)
5347 {
5348         
5349 }
5350
5351 CrossfadeEdgeDrag::CrossfadeEdgeDrag (Editor* e, AudioRegionView* rv, ArdourCanvas::Item* i, bool start_yn)
5352         : Drag (e, i)
5353         , arv (rv)
5354         , start (start_yn)
5355 {
5356         std::cout << ("CrossfadeEdgeDrag is DEPRECATED.  See TrimDrag::preserve_fade_anchor") << endl;
5357 }
5358
5359 void
5360 CrossfadeEdgeDrag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
5361 {
5362         Drag::start_grab (event, cursor);
5363 }
5364
5365 void
5366 CrossfadeEdgeDrag::motion (GdkEvent*, bool)
5367 {
5368         double distance;
5369         double new_length;
5370         framecnt_t len;
5371
5372         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
5373
5374         if (start) {
5375                 distance = _drags->current_pointer_x() - grab_x();
5376                 len = ar->fade_in()->back()->when;
5377         } else {
5378                 distance = grab_x() - _drags->current_pointer_x();
5379                 len = ar->fade_out()->back()->when;
5380         }
5381
5382         /* how long should it be ? */
5383
5384         new_length = len + _editor->pixel_to_sample (distance);
5385
5386         /* now check with the region that this is legal */
5387
5388         new_length = ar->verify_xfade_bounds (new_length, start);
5389
5390         if (start) {
5391                 arv->reset_fade_in_shape_width (ar, new_length);
5392         } else {
5393                 arv->reset_fade_out_shape_width (ar, new_length);
5394         }
5395 }
5396
5397 void
5398 CrossfadeEdgeDrag::finished (GdkEvent*, bool)
5399 {
5400         double distance;
5401         double new_length;
5402         framecnt_t len;
5403
5404         boost::shared_ptr<AudioRegion> ar (arv->audio_region());
5405
5406         if (start) {
5407                 distance = _drags->current_pointer_x() - grab_x();
5408                 len = ar->fade_in()->back()->when;
5409         } else {
5410                 distance = grab_x() - _drags->current_pointer_x();
5411                 len = ar->fade_out()->back()->when;
5412         }
5413
5414         new_length = ar->verify_xfade_bounds (len + _editor->pixel_to_sample (distance), start);
5415         
5416         _editor->begin_reversible_command ("xfade trim");
5417         ar->playlist()->clear_owned_changes (); 
5418
5419         if (start) {
5420                 ar->set_fade_in_length (new_length);
5421         } else {
5422                 ar->set_fade_out_length (new_length);
5423         }
5424
5425         /* Adjusting the xfade may affect other regions in the playlist, so we need
5426            to get undo Commands from the whole playlist rather than just the
5427            region.
5428         */
5429
5430         vector<Command*> cmds;
5431         ar->playlist()->rdiff (cmds);
5432         _editor->session()->add_commands (cmds);
5433         _editor->commit_reversible_command ();
5434
5435 }
5436
5437 void
5438 CrossfadeEdgeDrag::aborted (bool)
5439 {
5440         if (start) {
5441                 arv->redraw_start_xfade ();
5442         } else {
5443                 arv->redraw_end_xfade ();
5444         }
5445 }
5446