Refix yesterday's patch; ignore motion events that haven't moved anywhere, and don...
[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 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/session.h"
24 #include "ardour/dB.h"
25 #include "ardour/region_factory.h"
26 #include "ardour/midi_diskstream.h"
27 #include "editor.h"
28 #include "i18n.h"
29 #include "keyboard.h"
30 #include "audio_region_view.h"
31 #include "midi_region_view.h"
32 #include "ardour_ui.h"
33 #include "gui_thread.h"
34 #include "control_point.h"
35 #include "utils.h"
36 #include "region_gain_line.h"
37 #include "editor_drag.h"
38 #include "audio_time_axis.h"
39 #include "midi_time_axis.h"
40 #include "canvas-note.h"
41 #include "selection.h"
42 #include "midi_selection.h"
43 #include "automation_time_axis.h"
44
45 using namespace std;
46 using namespace ARDOUR;
47 using namespace PBD;
48 using namespace Gtk;
49 using namespace Editing;
50 using namespace ArdourCanvas;
51
52 using Gtkmm2ext::Keyboard;
53
54 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
55
56 Drag::Drag (Editor* e, ArdourCanvas::Item* i) 
57         : _editor (e)
58         , _item (i)
59         , _pointer_frame_offset (0)
60         , _have_transaction (false)
61         , _move_threshold_passed (false)
62         , _grab_frame (0)
63         , _last_pointer_frame (0)
64         , _current_pointer_frame (0)
65 {
66
67 }
68
69 void
70 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
71 {
72         _item->ungrab (0);
73         _item = new_item;
74
75         if (cursor == 0) {
76                 cursor = _editor->which_grabber_cursor ();
77         }
78
79         _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
80 }
81
82 void
83 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
84 {
85         if (cursor == 0) {
86                 cursor = _editor->which_grabber_cursor ();
87         }
88
89         // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
90
91         if (Keyboard::is_button2_event (&event->button)) {
92                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
93                         _y_constrained = true;
94                         _x_constrained = false;
95                 } else {
96                         _y_constrained = false;
97                         _x_constrained = true;
98                 }
99         } else {
100                 _x_constrained = false;
101                 _y_constrained = false;
102         }
103
104         _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
105         _grab_frame = adjusted_frame (_grab_frame, event);
106         _last_pointer_frame = _grab_frame;
107         _current_pointer_frame = _grab_frame;
108         _current_pointer_x = _grab_x;
109         _current_pointer_y = _grab_y;
110         _last_pointer_x = _current_pointer_x;
111         _last_pointer_y = _current_pointer_y;
112
113         _original_x = 0;
114         _original_y = 0;
115         _item->i2w (_original_x, _original_y);
116
117         _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
118                               *cursor,
119                               event->button.time);
120
121         if (_editor->session() && _editor->session()->transport_rolling()) {
122                 _was_rolling = true;
123         } else {
124                 _was_rolling = false;
125         }
126
127         switch (_editor->snap_type()) {
128         case SnapToRegionStart:
129         case SnapToRegionEnd:
130         case SnapToRegionSync:
131         case SnapToRegionBoundary:
132                 _editor->build_region_boundary_cache ();
133                 break;
134         default:
135                 break;
136         }
137 }
138
139 /** @param event GDK event, or 0.
140  *  @return true if some movement occurred, otherwise false.
141  */
142 bool
143 Drag::end_grab (GdkEvent* event)
144 {
145         _ending = true;
146
147         _editor->stop_canvas_autoscroll ();
148
149         _item->ungrab (event ? event->button.time : 0);
150
151         _last_pointer_x = _current_pointer_x;
152         _last_pointer_y = _current_pointer_y;
153         finished (event, _move_threshold_passed);
154
155         _editor->hide_verbose_canvas_cursor();
156
157         _ending = false;
158
159         return _move_threshold_passed;
160 }
161
162 nframes64_t
163 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
164 {
165         nframes64_t pos = 0;
166
167         if (f > _pointer_frame_offset) {
168                 pos = f - _pointer_frame_offset;
169         }
170
171         if (snap) {
172                 _editor->snap_to_with_modifier (pos, event);
173         }
174
175         return pos;
176 }
177
178 nframes64_t
179 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
180 {
181         return adjusted_frame (_current_pointer_frame, event, snap);
182 }
183
184 bool
185 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
186 {
187         _last_pointer_x = _current_pointer_x;
188         _last_pointer_y = _current_pointer_y;
189         _last_pointer_frame = adjusted_current_frame (event);
190         _current_pointer_frame = _editor->event_frame (event, &_current_pointer_x, &_current_pointer_y);
191
192         /* check to see if we have moved in any way that matters since the last motion event */
193         if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
194              (!y_movement_matters() || _last_pointer_y == _current_pointer_y) ) {
195                 return false;
196         }
197
198         pair<nframes64_t, int> const threshold = move_threshold ();
199
200         bool const old_move_threshold_passed = _move_threshold_passed;
201
202         if (!from_autoscroll && !_move_threshold_passed) {
203
204                 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
205                 bool const yp = (::fabs ((_current_pointer_y - _grab_y)) >= threshold.second);
206
207                 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
208         }
209
210         if (active (_editor->mouse_mode) && _move_threshold_passed) {
211
212                 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
213                         if (!from_autoscroll) {
214                                 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
215                         }
216
217                         motion (event, _move_threshold_passed != old_move_threshold_passed);
218                         return true;
219                 }
220         }
221
222         return false;
223 }
224
225
226 void
227 Drag::break_drag ()
228 {
229         _editor->stop_canvas_autoscroll ();
230         _editor->hide_verbose_canvas_cursor ();
231
232         if (_item) {
233                 _item->ungrab (0);
234
235                 /* put it back where it came from */
236
237                 double cxw, cyw;
238                 cxw = 0;
239                 cyw = 0;
240                 _item->i2w (cxw, cyw);
241                 _item->move (_original_x - cxw, _original_y - cyw);
242         }
243 }
244
245
246 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
247         : Drag (e, i),
248           _primary (p),
249           _views (v)
250 {
251         RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
252 }
253
254 void
255 RegionDrag::region_going_away (RegionView* v)
256 {
257         _views.remove (v);
258 }
259
260 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
261         : RegionDrag (e, i, p, v),
262           _dest_trackview (0),
263           _dest_layer (0),
264           _brushing (b)
265 {
266
267 }
268
269
270 void
271 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
272 {
273         Drag::start_grab (event);
274
275         _editor->show_verbose_time_cursor (_last_frame_position, 10);
276 }
277
278 RegionMotionDrag::TimeAxisViewSummary
279 RegionMotionDrag::get_time_axis_view_summary ()
280 {
281         int32_t children = 0;
282         TimeAxisViewSummary sum;
283
284         _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
285
286         /* get a bitmask representing the visible tracks */
287
288         for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
289                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
290                 TimeAxisView::Children children_list;
291
292                 /* zeroes are audio/MIDI tracks. ones are other types. */
293
294                 if (!rtv->hidden()) {
295
296                         if (!rtv->is_track()) {
297                                 /* not an audio nor MIDI track */
298                                 sum.tracks = sum.tracks |= (0x01 << rtv->order());
299                         }
300
301                         sum.height_list[rtv->order()] = (*i)->current_height();
302                         children = 1;
303
304                         if ((children_list = rtv->get_child_list()).size() > 0) {
305                                 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
306                                         sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
307                                         sum.height_list[rtv->order() + children] = (*j)->current_height();
308                                         children++;
309                                 }
310                         }
311                 }
312         }
313
314         return sum;
315 }
316
317 bool
318 RegionMotionDrag::compute_y_delta (
319         TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
320         int32_t last_pointer_layer, int32_t current_pointer_layer,
321         TimeAxisViewSummary const & tavs,
322         int32_t* pointer_order_span, int32_t* pointer_layer_span,
323         int32_t* canvas_pointer_order_span
324         )
325 {
326         if (_brushing) {
327                 *pointer_order_span = 0;
328                 *pointer_layer_span = 0;
329                 return true;
330         }
331
332         bool clamp_y_axis = false;
333
334         /* the change in track order between this callback and the last */
335         *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
336         /* the change in layer between this callback and the last;
337            only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
338         *pointer_layer_span = last_pointer_layer - current_pointer_layer;
339
340         if (*pointer_order_span != 0) {
341
342                 /* find the actual pointer span, in terms of the number of visible tracks;
343                    to do this, we reduce |pointer_order_span| by the number of hidden tracks
344                    over the span */
345
346                 *canvas_pointer_order_span = *pointer_order_span;
347                 if (last_pointer_view->order() >= current_pointer_view->order()) {
348                         for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
349                                 if (tavs.height_list[y] == 0) {
350                                         *canvas_pointer_order_span--;
351                                 }
352                         }
353                 } else {
354                         for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
355                                 if (tavs.height_list[y] == 0) {
356                                         *canvas_pointer_order_span++;
357                                 }
358                         }
359                 }
360
361                 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
362
363                         RegionView* rv = (*i);
364
365                         if (rv->region()->locked()) {
366                                 continue;
367                         }
368
369                         double ix1, ix2, iy1, iy2;
370                         rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
371                         rv->get_canvas_frame()->i2w (ix1, iy1);
372                         iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
373
374                         /* get the new trackview for this particular region */
375                         pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
376                         assert (tvp.first);
377                         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
378
379                         /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
380                            as surely this is a per-region thing... */
381
382                         clamp_y_axis = y_movement_disallowed (
383                                 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
384                                 );
385
386                         if (clamp_y_axis) {
387                                 break;
388                         }
389                 }
390
391         } else if (_dest_trackview == current_pointer_view) {
392
393                 if (current_pointer_layer == last_pointer_layer) {
394                         /* No movement; clamp */
395                         clamp_y_axis = true;
396                 }
397         }
398
399         if (!clamp_y_axis) {
400                 _dest_trackview = current_pointer_view;
401                 _dest_layer = current_pointer_layer;
402         }
403
404         return clamp_y_axis;
405 }
406
407
408 double
409 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
410 {
411         /* compute the amount of pointer motion in frames, and where
412            the region would be if we moved it by that much.
413         */
414         *pending_region_position = adjusted_current_frame (event);
415         
416         nframes64_t sync_frame;
417         nframes64_t sync_offset;
418         int32_t sync_dir;
419         
420         sync_offset = _primary->region()->sync_offset (sync_dir);
421         
422         /* we don't handle a sync point that lies before zero.
423          */
424         if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
425                 
426                 sync_frame = *pending_region_position + (sync_dir*sync_offset);
427                 
428                 _editor->snap_to_with_modifier (sync_frame, event);
429                 
430                 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
431                 
432         } else {
433                 *pending_region_position = _last_frame_position;
434         }
435
436         if (*pending_region_position > max_frames - _primary->region()->length()) {
437                 *pending_region_position = _last_frame_position;
438         }
439
440         double x_delta = 0;
441
442         if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
443
444                 /* now compute the canvas unit distance we need to move the regionview
445                    to make it appear at the new location.
446                 */
447
448                 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
449
450                 if (*pending_region_position <= _last_frame_position) {
451
452                         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
453
454                                 RegionView* rv = (*i);
455
456                                 // If any regionview is at zero, we need to know so we can stop further leftward motion.
457
458                                 double ix1, ix2, iy1, iy2;
459                                 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
460                                 rv->get_canvas_frame()->i2w (ix1, iy1);
461
462                                 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
463                                         x_delta = 0;
464                                         *pending_region_position = _last_frame_position;
465                                         break;
466                                 }
467                         }
468
469                 }
470
471                 _last_frame_position = *pending_region_position;
472         }
473
474         return x_delta;
475 }
476
477 void
478 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
479 {
480         double y_delta = 0;
481
482         TimeAxisViewSummary tavs = get_time_axis_view_summary ();
483
484         vector<int32_t>::iterator j;
485
486         /* *pointer* variables reflect things about the pointer; as we may be moving
487            multiple regions, much detail must be computed per-region */
488
489         /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
490            current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
491            are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
492            is always 0 regardless of what the region's "real" layer is */
493         RouteTimeAxisView* current_pointer_view;
494         layer_t current_pointer_layer;
495         if (!check_possible (&current_pointer_view, &current_pointer_layer)) {
496                 return;
497         }
498
499         /* TimeAxisView that we were pointing at last time we entered this method */
500         TimeAxisView const * const last_pointer_view = _dest_trackview;
501         /* the order of the track that we were pointing at last time we entered this method */
502         int32_t const last_pointer_order = last_pointer_view->order ();
503         /* the layer that we were pointing at last time we entered this method */
504         layer_t const last_pointer_layer = _dest_layer;
505
506         int32_t pointer_order_span;
507         int32_t pointer_layer_span;
508         int32_t canvas_pointer_order_span;
509
510         bool const clamp_y_axis = compute_y_delta (
511                 last_pointer_view, current_pointer_view,
512                 last_pointer_layer, current_pointer_layer, tavs,
513                 &pointer_order_span, &pointer_layer_span,
514                 &canvas_pointer_order_span
515                 );
516
517         nframes64_t pending_region_position;
518         double const x_delta = compute_x_delta (event, &pending_region_position);
519
520         /*************************************************************
521             PREPARE TO MOVE
522         ************************************************************/
523
524         if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
525                 /* haven't reached next snap point, and we're not switching
526                    trackviews nor layers. nothing to do.
527                 */
528                 return;
529         }
530
531         /*************************************************************
532             MOTION
533         ************************************************************/
534
535         pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
536
537         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
538
539                 RegionView* rv = (*i);
540
541                 if (rv->region()->locked()) {
542                         continue;
543                 }
544
545                 /* here we are calculating the y distance from the
546                    top of the first track view to the top of the region
547                    area of the track view that we're working on */
548
549                 /* this x value is just a dummy value so that we have something
550                    to pass to i2w () */
551
552                 double ix1 = 0;
553
554                 /* distance from the top of this track view to the region area
555                    of our track view is always 1 */
556
557                 double iy1 = 1;
558
559                 /* convert to world coordinates, ie distance from the top of
560                    the ruler section */
561
562                 rv->get_canvas_frame()->i2w (ix1, iy1);
563
564                 /* compensate for the ruler section and the vertical scrollbar position */
565                 iy1 += _editor->get_trackview_group_vertical_offset ();
566
567                 if (first_move) {
568
569                         // hide any dependent views
570
571                         rv->get_time_axis_view().hide_dependent_views (*rv);
572
573                         /*
574                            reparent to a non scrolling group so that we can keep the
575                            region selection above all time axis views.
576                            reparenting means we have to move the rv as the two
577                            parent groups have different coordinates.
578                         */
579
580                         rv->get_canvas_group()->property_y() = iy1 - 1;
581                         rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
582
583                         rv->fake_set_opaque (true);
584                 }
585
586                 /* current view for this particular region */
587                 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
588                 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
589
590                 if (pointer_order_span != 0 && !clamp_y_axis) {
591
592                         /* INTER-TRACK MOVEMENT */
593
594                         /* move through the height list to the track that the region is currently on */
595                         vector<int32_t>::iterator j = tavs.height_list.begin ();
596                         int32_t x = 0;
597                         while (j != tavs.height_list.end () && x != rtv->order ()) {
598                                 ++x;
599                                 ++j;
600                         }
601
602                         y_delta = 0;
603                         int32_t temp_pointer_order_span = canvas_pointer_order_span;
604
605                         if (j != tavs.height_list.end ()) {
606
607                                 /* Account for layers in the original and
608                                    destination tracks.  If we're moving around in layers we assume
609                                    that only one track is involved, so it's ok to use *pointer*
610                                    variables here. */
611
612                                 StreamView* lv = last_pointer_view->view ();
613                                 assert (lv);
614
615                                 /* move to the top of the last trackview */
616                                 if (lv->layer_display () == Stacked) {
617                                         y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
618                                 }
619
620                                 StreamView* cv = current_pointer_view->view ();
621                                 assert (cv);
622
623                                 /* move to the right layer on the current trackview */
624                                 if (cv->layer_display () == Stacked) {
625                                         y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
626                                 }
627
628                                 /* And for being on a non-topmost layer on the new
629                                    track */
630
631                                 while (temp_pointer_order_span > 0) {
632                                         /* we're moving up canvas-wise,
633                                            so we need to find the next track height
634                                         */
635                                         if (j != tavs.height_list.begin()) {
636                                                 j--;
637                                         }
638
639                                         if (x != last_pointer_order) {
640                                                 if ((*j) == 0) {
641                                                         ++temp_pointer_order_span;
642                                                 }
643                                         }
644
645                                         y_delta -= (*j);
646                                         temp_pointer_order_span--;
647                                 }
648
649                                 while (temp_pointer_order_span < 0) {
650
651                                         y_delta += (*j);
652
653                                         if (x != last_pointer_order) {
654                                                 if ((*j) == 0) {
655                                                         --temp_pointer_order_span;
656                                                 }
657                                         }
658
659                                         if (j != tavs.height_list.end()) {
660                                                 j++;
661                                         }
662
663                                         temp_pointer_order_span++;
664                                 }
665
666
667                                 /* find out where we'll be when we move and set height accordingly */
668
669                                 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
670                                 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
671                                 rv->set_height (temp_rtv->view()->child_height());
672
673                                 /* if you un-comment the following, the region colours will follow
674                                    the track colours whilst dragging; personally
675                                    i think this can confuse things, but never mind.
676                                 */
677
678                                 //const GdkColor& col (temp_rtv->view->get_region_color());
679                                 //rv->set_color (const_cast<GdkColor&>(col));
680                         }
681                 }
682
683                 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
684
685                         /* INTER-LAYER MOVEMENT in the same track */
686                         y_delta = rtv->view()->child_height () * pointer_layer_span;
687                 }
688
689
690                 if (_brushing) {
691                         _editor->mouse_brush_insert_region (rv, pending_region_position);
692                 } else {
693                         rv->move (x_delta, y_delta);
694                 }
695
696         } /* foreach region */
697
698         if (first_move) {
699                 _editor->cursor_group->raise_to_top();
700         }
701
702         if (x_delta != 0 && !_brushing) {
703                 _editor->show_verbose_time_cursor (_last_frame_position, 10);
704         }
705 }
706
707 void
708 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
709 {
710         if (_copy && first_move) {
711                 copy_regions (event);
712         }
713
714         RegionMotionDrag::motion (event, first_move);
715 }
716
717 void
718 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
719 {
720         vector<RegionView*> copies;
721         boost::shared_ptr<Diskstream> ds;
722         boost::shared_ptr<Playlist> from_playlist;
723         RegionSelection new_views;
724         typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
725         PlaylistSet modified_playlists;
726         PlaylistSet frozen_playlists;
727         list <sigc::connection> modified_playlist_connections;
728         pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
729         nframes64_t drag_delta;
730         bool changed_tracks, changed_position;
731         map<RegionView*, pair<RouteTimeAxisView*, int> > final;
732         RouteTimeAxisView* source_tv;
733
734         if (!movement_occurred) {
735                 /* just a click */
736                 return;
737         }
738
739         if (_brushing) {
740                 /* all changes were made during motion event handlers */
741
742                 if (_copy) {
743                         for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
744                                 copies.push_back (*i);
745                         }
746                 }
747
748                 goto out;
749         }
750
751         /* reverse this here so that we have the correct logic to finalize
752            the drag.
753         */
754
755         if (Config->get_edit_mode() == Lock) {
756                 _x_constrained = !_x_constrained;
757         }
758
759         if (_copy) {
760                 if (_x_constrained) {
761                         _editor->begin_reversible_command (_("fixed time region copy"));
762                 } else {
763                         _editor->begin_reversible_command (_("region copy"));
764                 }
765         } else {
766                 if (_x_constrained) {
767                         _editor->begin_reversible_command (_("fixed time region drag"));
768                 } else {
769                         _editor->begin_reversible_command (_("region drag"));
770                 }
771         }
772
773         _have_transaction = true;
774
775         changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
776         changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
777
778         drag_delta = _primary->region()->position() - _last_frame_position;
779
780         _editor->update_canvas_now ();
781
782         /* make a list of where each region ended up */
783         final = find_time_axis_views_and_layers ();
784
785         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
786
787                 RegionView* rv = (*i);
788                 RouteTimeAxisView* dest_rtv = final[*i].first;
789                 layer_t dest_layer = final[*i].second;
790
791                 nframes64_t where;
792
793                 if (rv->region()->locked()) {
794                         ++i;
795                         continue;
796                 }
797
798                 if (changed_position && !_x_constrained) {
799                         where = rv->region()->position() - drag_delta;
800                 } else {
801                         where = rv->region()->position();
802                 }
803
804                 boost::shared_ptr<Region> new_region;
805
806                 if (_copy) {
807                         /* we already made a copy */
808                         new_region = rv->region();
809
810                         /* undo the previous hide_dependent_views so that xfades don't
811                            disappear on copying regions
812                         */
813
814                         //rv->get_time_axis_view().reveal_dependent_views (*rv);
815
816                 } else if (changed_tracks && dest_rtv->playlist()) {
817                         new_region = RegionFactory::create (rv->region());
818                 }
819
820                 if (changed_tracks || _copy) {
821
822                         boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
823
824                         if (!to_playlist) {
825                                 ++i;
826                                 continue;
827                         }
828
829                         _editor->latest_regionviews.clear ();
830
831                         sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
832
833                         insert_result = modified_playlists.insert (to_playlist);
834
835                         if (insert_result.second) {
836                                 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
837                         }
838
839                         to_playlist->add_region (new_region, where);
840                         if (dest_rtv->view()->layer_display() == Stacked) {
841                                 new_region->set_layer (dest_layer);
842                                 new_region->set_pending_explicit_relayer (true);
843                         }
844
845                         c.disconnect ();
846
847                         if (!_editor->latest_regionviews.empty()) {
848                                 // XXX why just the first one ? we only expect one
849                                 // commented out in nick_m's canvas reworking. is that intended?
850                                 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
851                                 new_views.push_back (_editor->latest_regionviews.front());
852                         }
853
854                 } else {
855                         /*
856                            motion on the same track. plonk the previously reparented region
857                            back to its original canvas group (its streamview).
858                            No need to do anything for copies as they are fake regions which will be deleted.
859                         */
860
861                         rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
862                         rv->get_canvas_group()->property_y() = 0;
863
864                         /* just change the model */
865
866                         boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
867
868                         if (dest_rtv->view()->layer_display() == Stacked) {
869                                 rv->region()->set_layer (dest_layer);
870                                 rv->region()->set_pending_explicit_relayer (true);
871                         }
872
873                         insert_result = modified_playlists.insert (playlist);
874
875                         if (insert_result.second) {
876                                 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
877                         }
878                         /* freeze to avoid lots of relayering in the case of a multi-region drag */
879                         frozen_insert_result = frozen_playlists.insert(playlist);
880
881                         if (frozen_insert_result.second) {
882                                 playlist->freeze();
883                         }
884
885                         rv->region()->set_position (where, (void*) this);
886                 }
887
888                 if (changed_tracks && !_copy) {
889
890                         /* get the playlist where this drag started. we can't use rv->region()->playlist()
891                            because we may have copied the region and it has not been attached to a playlist.
892                         */
893
894                         source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
895                         ds = source_tv->get_diskstream();
896                         from_playlist = ds->playlist();
897
898                         assert (source_tv);
899                         assert (ds);
900                         assert (from_playlist);
901
902                         /* moved to a different audio track, without copying */
903
904                         /* the region that used to be in the old playlist is not
905                            moved to the new one - we use a copy of it. as a result,
906                            any existing editor for the region should no longer be
907                            visible.
908                         */
909
910                         rv->hide_region_editor();
911                         rv->fake_set_opaque (false);
912
913                         /* remove the region from the old playlist */
914
915                         insert_result = modified_playlists.insert (from_playlist);
916
917                         if (insert_result.second) {
918                                 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
919                         }
920
921                         from_playlist->remove_region (rv->region());
922
923                         /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
924                            was selected in all of them, then removing it from a playlist will have removed all
925                            trace of it from the selection (i.e. there were N regions selected, we removed 1,
926                            but since its the same playlist for N tracks, all N tracks updated themselves, removed the
927                            corresponding regionview, and the selection is now empty).
928
929                            this could have invalidated any and all iterators into the region selection.
930
931                            the heuristic we use here is: if the region selection is empty, break out of the loop
932                            here. if the region selection is not empty, then restart the loop because we know that
933                            we must have removed at least the region(view) we've just been working on as well as any
934                            that we processed on previous iterations.
935
936                            EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
937                            we can just iterate.
938                         */
939
940                         if (_views.empty()) {
941                                 break;
942                         } else {
943                                 i = _views.begin();
944                         }
945
946                 } else {
947                         ++i;
948                 }
949
950                 if (_copy) {
951                         copies.push_back (rv);
952                 }
953         }
954         /*
955            if we've created new regions either by copying or moving 
956            to a new track, we want to replace the old selection with the new ones 
957         */
958         if (new_views.size() > 0) {
959                 _editor->selection->set (new_views);
960         }
961
962         for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
963                 (*p)->thaw();
964         }
965
966   out:
967         for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
968                 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
969         }
970
971         _editor->commit_reversible_command ();
972
973         for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
974                 delete *x;
975         }
976 }
977
978
979 bool
980 RegionMotionDrag::x_move_allowed () const
981 {
982         if (Config->get_edit_mode() == Lock) {
983                 /* in locked edit mode, reverse the usual meaning of _x_constrained */
984                 return _x_constrained;
985         }
986
987         return !_x_constrained;
988 }
989
990 void
991 RegionMotionDrag::copy_regions (GdkEvent* event)
992 {
993         /* duplicate the regionview(s) and region(s) */
994
995         list<RegionView*> new_regionviews;
996
997         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
998
999                 RegionView* rv = (*i);
1000                 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1001                 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1002
1003                 const boost::shared_ptr<const Region> original = rv->region();
1004                 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1005
1006                 RegionView* nrv;
1007                 if (arv) {
1008                         boost::shared_ptr<AudioRegion> audioregion_copy
1009                                 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1010                         nrv = new AudioRegionView (*arv, audioregion_copy);
1011                 } else if (mrv) {
1012                         boost::shared_ptr<MidiRegion> midiregion_copy
1013                                 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1014                         nrv = new MidiRegionView (*mrv, midiregion_copy);
1015                 } else {
1016                         continue;
1017                 }
1018
1019                 nrv->get_canvas_group()->show ();
1020                 new_regionviews.push_back (nrv);
1021
1022                 /* swap _primary to the copy */
1023
1024                 if (rv == _primary) {
1025                         _primary = nrv;
1026                 }
1027
1028                 /* ..and deselect the one we copied */
1029
1030                 rv->set_selected (false);
1031         }
1032
1033         if (new_regionviews.empty()) {
1034                 return;
1035         }
1036
1037         /* reflect the fact that we are dragging the copies */
1038
1039         _views = new_regionviews;
1040
1041         swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1042
1043         /*
1044            sync the canvas to what we think is its current state
1045            without it, the canvas seems to
1046            "forget" to update properly after the upcoming reparent()
1047            ..only if the mouse is in rapid motion at the time of the grab.
1048            something to do with regionview creation raking so long?
1049         */
1050         _editor->update_canvas_now();
1051 }
1052
1053 bool
1054 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1055 {
1056         /* Which trackview is this ? */
1057
1058         pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (current_pointer_y ());
1059         (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1060         (*layer) = tvp.second;
1061
1062         if (*tv && (*tv)->layer_display() == Overlaid) {
1063                 *layer = 0;
1064         }
1065
1066         /* The region motion is only processed if the pointer is over
1067            an audio track.
1068         */
1069
1070         if (!(*tv) || !(*tv)->is_track()) {
1071                 /* To make sure we hide the verbose canvas cursor when the mouse is
1072                    not held over and audiotrack.
1073                 */
1074                 _editor->hide_verbose_canvas_cursor ();
1075                 return false;
1076         }
1077
1078         return true;
1079 }
1080
1081 /** @param new_order New track order.
1082  *  @param old_order Old track order.
1083  *  @param visible_y_low Lowest visible order.
1084  *  @return true if y movement should not happen, otherwise false.
1085  */
1086 bool
1087 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1088 {
1089         if (new_order != old_order) {
1090
1091                 /* this isn't the pointer track */
1092
1093                 if (y_span > 0) {
1094
1095                         /* moving up the canvas */
1096                         if ( (new_order - y_span) >= tavs.visible_y_low) {
1097
1098                                 int32_t n = 0;
1099
1100                                 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1101                                 int32_t visible_tracks = 0;
1102                                 while (visible_tracks < y_span ) {
1103                                         visible_tracks++;
1104                                         while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1105                                                 /* passing through a hidden track */
1106                                                 n--;
1107                                         }
1108                                 }
1109
1110                                 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1111                                         /* moving to a non-track; disallow */
1112                                         return true;
1113                                 }
1114
1115
1116                         } else {
1117                                 /* moving beyond the lowest visible track; disallow */
1118                                 return true;
1119                         }
1120
1121                 } else if (y_span < 0) {
1122
1123                         /* moving down the canvas */
1124                         if ((new_order - y_span) <= tavs.visible_y_high) {
1125
1126                                 int32_t visible_tracks = 0;
1127                                 int32_t n = 0;
1128                                 while (visible_tracks > y_span ) {
1129                                         visible_tracks--;
1130
1131                                         while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1132                                                 /* passing through a hidden track */
1133                                                 n++;
1134                                         }
1135                                 }
1136
1137                                 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1138                                         /* moving to a non-track; disallow */
1139                                         return true;
1140                                 }
1141
1142
1143                         } else {
1144
1145                                 /* moving beyond the highest visible track; disallow */
1146                                 return true;
1147                         }
1148                 }
1149
1150         } else {
1151
1152                 /* this is the pointer's track */
1153
1154                 if ((new_order - y_span) > tavs.visible_y_high) {
1155                         /* we will overflow */
1156                         return true;
1157                 } else if ((new_order - y_span) < tavs.visible_y_low) {
1158                         /* we will overflow */
1159                         return true;
1160                 }
1161         }
1162
1163         return false;
1164 }
1165
1166
1167 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1168         : RegionMotionDrag (e, i, p, v, b),
1169           _copy (c)
1170 {
1171         TimeAxisView* const tv = &_primary->get_time_axis_view ();
1172
1173         _dest_trackview = tv;
1174         if (tv->layer_display() == Overlaid) {
1175                 _dest_layer = 0;
1176         } else {
1177                 _dest_layer = _primary->region()->layer ();
1178         }
1179
1180         double speed = 1;
1181         RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1182         if (rtv && rtv->is_track()) {
1183                 speed = rtv->get_diskstream()->speed ();
1184         }
1185
1186         _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1187 }
1188
1189 void
1190 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1191 {
1192         RegionMotionDrag::start_grab (event, c);
1193
1194         _pointer_frame_offset = grab_frame() - _last_frame_position;
1195 }
1196
1197 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1198         : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1199 {
1200         assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1201                 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1202
1203         _primary = v->view()->create_region_view (r, false, false);
1204
1205         _primary->get_canvas_group()->show ();
1206         _primary->set_position (pos, 0);
1207         _views.push_back (_primary);
1208
1209         _last_frame_position = pos;
1210
1211         _item = _primary->get_canvas_group ();
1212         _dest_trackview = v;
1213         _dest_layer = _primary->region()->layer ();
1214 }
1215
1216 map<RegionView*, pair<RouteTimeAxisView*, int> >
1217 RegionMotionDrag::find_time_axis_views_and_layers ()
1218 {
1219         map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1220
1221         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1222
1223                 double ix1, ix2, iy1, iy2;
1224                 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1225                 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1226                 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1227
1228                 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1229                 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1230         }
1231
1232         return tav;
1233 }
1234
1235
1236 void
1237 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1238 {
1239         _editor->update_canvas_now ();
1240
1241         map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1242
1243         RouteTimeAxisView* dest_rtv = final[_primary].first;
1244
1245         _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1246         _primary->get_canvas_group()->property_y() = 0;
1247
1248         boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1249
1250         _editor->begin_reversible_command (_("insert region"));
1251         XMLNode& before = playlist->get_state ();
1252         playlist->add_region (_primary->region (), _last_frame_position);
1253         _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1254         _editor->commit_reversible_command ();
1255
1256         delete _primary;
1257         _primary = 0;
1258         _views.clear ();
1259 }
1260
1261 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1262         : RegionMoveDrag (e, i, p, v, false, false)
1263 {
1264
1265 }
1266
1267 struct RegionSelectionByPosition {
1268     bool operator() (RegionView*a, RegionView* b) {
1269             return a->region()->position () < b->region()->position();
1270     }
1271 };
1272
1273 void
1274 RegionSpliceDrag::motion (GdkEvent* event, bool)
1275 {
1276         RouteTimeAxisView* tv;
1277         layer_t layer;
1278
1279         if (!check_possible (&tv, &layer)) {
1280                 return;
1281         }
1282
1283         int dir;
1284
1285         if ((current_pointer_x() - last_pointer_x()) > 0) {
1286                 dir = 1;
1287         } else {
1288                 dir = -1;
1289         }
1290
1291         RegionSelection copy (_editor->selection->regions);
1292
1293         RegionSelectionByPosition cmp;
1294         copy.sort (cmp);
1295
1296         nframes64_t const pf = adjusted_current_frame (event);
1297
1298         for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1299
1300                 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1301
1302                 if (!atv) {
1303                         continue;
1304                 }
1305
1306                 boost::shared_ptr<Playlist> playlist;
1307
1308                 if ((playlist = atv->playlist()) == 0) {
1309                         continue;
1310                 }
1311
1312                 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1313                         continue;
1314                 }
1315
1316                 if (dir > 0) {
1317                         if (pf < (*i)->region()->last_frame() + 1) {
1318                                 continue;
1319                         }
1320                 } else {
1321                         if (pf > (*i)->region()->first_frame()) {
1322                                 continue;
1323                         }
1324                 }
1325
1326
1327                 playlist->shuffle ((*i)->region(), dir);
1328         }
1329 }
1330
1331 void
1332 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1333 {
1334
1335 }
1336
1337
1338 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1339         : Drag (e, i),
1340           _view (v)
1341 {
1342
1343 }
1344
1345 void
1346 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1347 {
1348         _dest_trackview = _view;
1349
1350         Drag::start_grab (event);
1351 }
1352
1353
1354 void
1355 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1356 {
1357         if (first_move) {
1358                 // TODO: create region-create-drag region view here
1359         }
1360
1361         // TODO: resize region-create-drag region view here
1362 }
1363
1364 void
1365 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1366 {
1367         MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1368
1369         if (!mtv) {
1370                 return;
1371         }
1372
1373         if (!movement_occurred) {
1374                 mtv->add_region (grab_frame ());
1375         } else {
1376                 motion (event, false);
1377                 // TODO: create region-create-drag region here
1378         }
1379 }
1380
1381 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1382         : Drag (e, i)
1383         , region (0)
1384 {
1385
1386 }
1387
1388 void
1389 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1390 {
1391         Gdk::Cursor     cursor;
1392         ArdourCanvas::CanvasNote*     cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1393
1394         Drag::start_grab (event);
1395
1396         region = &cnote->region_view();
1397
1398         double region_start = region->get_position_pixels();
1399         double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1400
1401         if (grab_x() <= middle_point) {
1402                 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1403                 at_front = true;
1404         } else {
1405                 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1406                 at_front = false;
1407         }
1408
1409         _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1410
1411         if (event->motion.state & Keyboard::PrimaryModifier) {
1412                 relative = false;
1413         } else {
1414                 relative = true;
1415         }
1416
1417         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1418
1419         if (ms.size() > 1) {
1420                 /* has to be relative, may make no sense otherwise */
1421                 relative = true;
1422         }
1423
1424         region->note_selected (cnote, true);
1425
1426         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1427                 MidiRegionSelection::iterator next;
1428                 next = r;
1429                 ++next;
1430                 (*r)->begin_resizing (at_front);
1431                 r = next;
1432         }
1433 }
1434
1435 void
1436 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1437 {
1438         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1439         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1440                 (*r)->update_resizing (at_front, current_pointer_x() - grab_x(), relative);
1441         }
1442 }
1443
1444 void
1445 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1446 {
1447         MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1448         for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1449                 (*r)->commit_resizing (at_front, current_pointer_x() - grab_x(), relative);
1450         }
1451 }
1452
1453 void
1454 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1455 {
1456
1457 }
1458
1459 void
1460 RegionGainDrag::finished (GdkEvent *, bool)
1461 {
1462
1463 }
1464
1465 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1466         : RegionDrag (e, i, p, v)
1467 {
1468
1469 }
1470
1471 void
1472 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1473 {
1474         double speed = 1.0;
1475         TimeAxisView* tvp = &_primary->get_time_axis_view ();
1476         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1477
1478         if (tv && tv->is_track()) {
1479                 speed = tv->get_diskstream()->speed();
1480         }
1481
1482         nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1483         nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1484         nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1485
1486         Drag::start_grab (event, _editor->trimmer_cursor);
1487
1488         nframes64_t const pf = adjusted_current_frame (event);
1489
1490         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1491                 _operation = ContentsTrim;
1492         } else {
1493                 /* These will get overridden for a point trim.*/
1494                 if (pf < (region_start + region_length/2)) {
1495                         /* closer to start */
1496                         _operation = StartTrim;
1497                 } else if (pf > (region_end - region_length/2)) {
1498                         /* closer to end */
1499                         _operation = EndTrim;
1500                 }
1501         }
1502
1503         switch (_operation) {
1504         case StartTrim:
1505                 _editor->show_verbose_time_cursor (region_start, 10);
1506                 break;
1507         case EndTrim:
1508                 _editor->show_verbose_time_cursor (region_end, 10);
1509                 break;
1510         case ContentsTrim:
1511                 _editor->show_verbose_time_cursor (pf, 10);
1512                 break;
1513         }
1514 }
1515
1516 void
1517 TrimDrag::motion (GdkEvent* event, bool first_move)
1518 {
1519         RegionView* rv = _primary;
1520         nframes64_t frame_delta = 0;
1521
1522         bool left_direction;
1523         bool obey_snap = !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier());
1524
1525         /* snap modifier works differently here..
1526            its current state has to be passed to the
1527            various trim functions in order to work properly
1528         */
1529
1530         double speed = 1.0;
1531         TimeAxisView* tvp = &_primary->get_time_axis_view ();
1532         RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1533         pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1534
1535         if (tv && tv->is_track()) {
1536                 speed = tv->get_diskstream()->speed();
1537         }
1538
1539         nframes64_t const pf = adjusted_current_frame (event);
1540
1541         if (last_pointer_frame() > pf) {
1542                 left_direction = true;
1543         } else {
1544                 left_direction = false;
1545         }
1546
1547         if (first_move) {
1548
1549                 string trim_type;
1550
1551                 switch (_operation) {
1552                 case StartTrim:
1553                         trim_type = "Region start trim";
1554                         break;
1555                 case EndTrim:
1556                         trim_type = "Region end trim";
1557                         break;
1558                 case ContentsTrim:
1559                         trim_type = "Region content trim";
1560                         break;
1561                 }
1562
1563                 _editor->begin_reversible_command (trim_type);
1564                 _have_transaction = true;
1565
1566                 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1567                         (*i)->fake_set_opaque(false);
1568                         (*i)->region()->freeze ();
1569
1570                         AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1571
1572                         if (arv){
1573                                 arv->temporarily_hide_envelope ();
1574                         }
1575
1576                         boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1577                         insert_result = _editor->motion_frozen_playlists.insert (pl);
1578
1579                         if (insert_result.second) {
1580                                 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1581                                 pl->freeze();
1582                         }
1583                 }
1584         }
1585
1586         if (pf == last_pointer_frame()) {
1587                 return;
1588         }
1589
1590         /* XXX i hope to god that we can really conclude this ... */
1591         _have_transaction = true;
1592
1593         if (left_direction) {
1594                 frame_delta = (last_pointer_frame() - pf);
1595         } else {
1596                 frame_delta = (pf - last_pointer_frame());
1597         }
1598
1599         bool non_overlap_trim = false;
1600
1601         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1602                 non_overlap_trim = true;
1603         }
1604
1605         switch (_operation) {
1606         case StartTrim:
1607                 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1608                         break;
1609                 } else {
1610
1611                         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1612                                 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1613                         }
1614                         break;
1615                 }
1616
1617         case EndTrim:
1618                 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1619                         break;
1620                 } else {
1621
1622                         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1623                                 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1624                         }
1625                         break;
1626                 }
1627
1628         case ContentsTrim:
1629                 {
1630                         bool swap_direction = false;
1631
1632                         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1633                                 swap_direction = true;
1634                         }
1635
1636                         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1637                                 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1638                         }
1639                 }
1640                 break;
1641         }
1642
1643         switch (_operation) {
1644         case StartTrim:
1645                 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1646                 break;
1647         case EndTrim:
1648                 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1649                 break;
1650         case ContentsTrim:
1651                 _editor->show_verbose_time_cursor (pf, 10);
1652                 break;
1653         }
1654 }
1655
1656
1657 void
1658 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1659 {
1660         if (movement_occurred) {
1661                 motion (event, false);
1662
1663                 if (!_editor->selection->selected (_primary)) {
1664                         _editor->thaw_region_after_trim (*_primary);
1665                 } else {
1666
1667                         for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1668                                 _editor->thaw_region_after_trim (**i);
1669                                 (*i)->fake_set_opaque (true);
1670                         }
1671                 }
1672                 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1673                         (*p)->thaw ();
1674                         if (_have_transaction) {
1675                                 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1676                         }
1677                 }
1678
1679                 _editor->motion_frozen_playlists.clear ();
1680
1681                 if (_have_transaction) {
1682                         _editor->commit_reversible_command();
1683                 }
1684
1685         } else {
1686                 /* no mouse movement */
1687                 _editor->point_trim (event);
1688         }
1689 }
1690
1691 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1692         : Drag (e, i),
1693           _copy (c)
1694 {
1695         _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1696         assert (_marker);
1697 }
1698
1699 void
1700 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1701 {
1702         if (_copy) {
1703                 // create a dummy marker for visual representation of moving the copy.
1704                 // The actual copying is not done before we reach the finish callback.
1705                 char name[64];
1706                 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1707                 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1708                                                           *new MeterSection (_marker->meter()));
1709
1710                 _item = &new_marker->the_item ();
1711                 _marker = new_marker;
1712
1713         } else {
1714
1715                 MetricSection& section (_marker->meter());
1716
1717                 if (!section.movable()) {
1718                         return;
1719                 }
1720
1721         }
1722
1723         Drag::start_grab (event, cursor);
1724
1725         _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1726
1727         _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1728 }
1729
1730 void
1731 MeterMarkerDrag::motion (GdkEvent* event, bool)
1732 {
1733         nframes64_t const pf = adjusted_current_frame (event);
1734
1735         if (pf == last_pointer_frame()) {
1736                 return;
1737         }
1738
1739         _marker->set_position (pf);
1740         
1741         _editor->show_verbose_time_cursor (pf, 10);
1742 }
1743
1744 void
1745 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1746 {
1747         if (!movement_occurred) {
1748                 return;
1749         }
1750
1751         motion (event, false);
1752
1753         BBT_Time when;
1754
1755         TempoMap& map (_editor->session()->tempo_map());
1756         map.bbt_time (last_pointer_frame(), when);
1757
1758         if (_copy == true) {
1759                 _editor->begin_reversible_command (_("copy meter mark"));
1760                 XMLNode &before = map.get_state();
1761                 map.add_meter (_marker->meter(), when);
1762                 XMLNode &after = map.get_state();
1763                 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1764                 _editor->commit_reversible_command ();
1765
1766                 // delete the dummy marker we used for visual representation of copying.
1767                 // a new visual marker will show up automatically.
1768                 delete _marker;
1769         } else {
1770                 _editor->begin_reversible_command (_("move meter mark"));
1771                 XMLNode &before = map.get_state();
1772                 map.move_meter (_marker->meter(), when);
1773                 XMLNode &after = map.get_state();
1774                 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1775                 _editor->commit_reversible_command ();
1776         }
1777 }
1778
1779 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1780         : Drag (e, i),
1781           _copy (c)
1782 {
1783         _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1784         assert (_marker);
1785 }
1786
1787 void
1788 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1789 {
1790
1791         if (_copy) {
1792
1793                 // create a dummy marker for visual representation of moving the copy.
1794                 // The actual copying is not done before we reach the finish callback.
1795                 char name[64];
1796                 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
1797                 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
1798                                                           *new TempoSection (_marker->tempo()));
1799
1800                 _item = &new_marker->the_item ();
1801                 _marker = new_marker;
1802
1803         } else {
1804
1805                 MetricSection& section (_marker->tempo());
1806
1807                 if (!section.movable()) {
1808                         return;
1809                 }
1810         }
1811
1812         Drag::start_grab (event, cursor);
1813
1814         _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
1815         _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
1816 }
1817
1818 void
1819 TempoMarkerDrag::motion (GdkEvent* event, bool)
1820 {
1821         nframes64_t const pf = adjusted_current_frame (event);
1822
1823         if (pf == last_pointer_frame()) {
1824                 return;
1825         }
1826
1827         /* OK, we've moved far enough to make it worth actually move the thing. */
1828
1829         _marker->set_position (pf);
1830
1831         _editor->show_verbose_time_cursor (pf, 10);
1832 }
1833
1834 void
1835 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1836 {
1837         if (!movement_occurred) {
1838                 return;
1839         }
1840
1841         motion (event, false);
1842
1843         BBT_Time when;
1844
1845         TempoMap& map (_editor->session()->tempo_map());
1846         map.bbt_time (last_pointer_frame(), when);
1847
1848         if (_copy == true) {
1849                 _editor->begin_reversible_command (_("copy tempo mark"));
1850                 XMLNode &before = map.get_state();
1851                 map.add_tempo (_marker->tempo(), when);
1852                 XMLNode &after = map.get_state();
1853                 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1854                 _editor->commit_reversible_command ();
1855
1856                 // delete the dummy marker we used for visual representation of copying.
1857                 // a new visual marker will show up automatically.
1858                 delete _marker;
1859         } else {
1860                 _editor->begin_reversible_command (_("move tempo mark"));
1861                 XMLNode &before = map.get_state();
1862                 map.move_tempo (_marker->tempo(), when);
1863                 XMLNode &after = map.get_state();
1864                 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
1865                 _editor->commit_reversible_command ();
1866         }
1867 }
1868
1869
1870 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
1871         : Drag (e, i),
1872           _stop (s)
1873 {
1874         _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
1875         assert (_cursor);
1876 }
1877
1878 void
1879 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1880 {
1881         Drag::start_grab (event, c);
1882
1883         if (!_stop) {
1884
1885                 nframes64_t where = _editor->event_frame (event, 0, 0);
1886
1887                 _editor->snap_to_with_modifier (where, event);
1888                 _editor->playhead_cursor->set_position (where);
1889
1890         }
1891
1892         if (_cursor == _editor->playhead_cursor) {
1893                 _editor->_dragging_playhead = true;
1894
1895                 if (_editor->session() && _was_rolling && _stop) {
1896                         _editor->session()->request_stop ();
1897                 }
1898
1899                 if (_editor->session() && _editor->session()->is_auditioning()) {
1900                         _editor->session()->cancel_audition ();
1901                 }
1902         }
1903
1904         _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1905 }
1906
1907 void
1908 CursorDrag::motion (GdkEvent* event, bool)
1909 {
1910         nframes64_t const adjusted_frame = adjusted_current_frame (event);
1911
1912         if (adjusted_frame == last_pointer_frame()) {
1913                 return;
1914         }
1915
1916         _cursor->set_position (adjusted_frame);
1917
1918         _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
1919
1920 #ifdef GTKOSX
1921         _editor->update_canvas_now ();
1922 #endif
1923         _editor->UpdateAllTransportClocks (_cursor->current_frame);
1924 }
1925
1926 void
1927 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
1928 {
1929         _editor->_dragging_playhead = false;
1930
1931         if (!movement_occurred && _stop) {
1932                 return;
1933         }
1934
1935         motion (event, false);
1936
1937         if (_item == &_editor->playhead_cursor->canvas_item) {
1938                 if (_editor->session()) {
1939                         _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
1940                         _editor->_pending_locate_request = true;
1941                 }
1942         }
1943 }
1944
1945 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1946         : RegionDrag (e, i, p, v)
1947 {
1948
1949 }
1950
1951 void
1952 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1953 {
1954         Drag::start_grab (event, cursor);
1955
1956         AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
1957         boost::shared_ptr<AudioRegion> const r = a->audio_region ();
1958
1959         _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
1960         _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
1961 }
1962
1963 void
1964 FadeInDrag::motion (GdkEvent* event, bool)
1965 {
1966         nframes64_t fade_length;
1967
1968         nframes64_t const pos = adjusted_current_frame (event);
1969
1970         boost::shared_ptr<Region> region = _primary->region ();
1971
1972         if (pos < (region->position() + 64)) {
1973                 fade_length = 64; // this should be a minimum defined somewhere
1974         } else if (pos > region->last_frame()) {
1975                 fade_length = region->length();
1976         } else {
1977                 fade_length = pos - region->position();
1978         }
1979
1980         for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
1981
1982                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
1983
1984                 if (!tmp) {
1985                         continue;
1986                 }
1987
1988                 tmp->reset_fade_in_shape_width (fade_length);
1989         }
1990
1991         _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
1992 }
1993
1994 void
1995 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
1996 {
1997         if (!movement_occurred) {
1998                 return;
1999         }
2000
2001         nframes64_t fade_length;
2002
2003         nframes64_t const pos = adjusted_current_frame (event);
2004
2005         boost::shared_ptr<Region> region = _primary->region ();
2006
2007         if (pos < (region->position() + 64)) {
2008                 fade_length = 64; // this should be a minimum defined somewhere
2009         } else if (pos > region->last_frame()) {
2010                 fade_length = region->length();
2011         } else {
2012                 fade_length = pos - region->position();
2013         }
2014
2015         _editor->begin_reversible_command (_("change fade in length"));
2016
2017         for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2018
2019                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2020
2021                 if (!tmp) {
2022                         continue;
2023                 }
2024
2025                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2026                 XMLNode &before = alist->get_state();
2027
2028                 tmp->audio_region()->set_fade_in_length (fade_length);
2029                 tmp->audio_region()->set_fade_in_active (true);
2030
2031                 XMLNode &after = alist->get_state();
2032                 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2033         }
2034
2035         _editor->commit_reversible_command ();
2036 }
2037
2038 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2039         : RegionDrag (e, i, p, v)
2040 {
2041
2042 }
2043
2044 void
2045 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2046 {
2047         Drag::start_grab (event, cursor);
2048
2049         AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2050         boost::shared_ptr<AudioRegion> r = a->audio_region ();
2051
2052         _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2053         _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2054 }
2055
2056 void
2057 FadeOutDrag::motion (GdkEvent* event, bool)
2058 {
2059         nframes64_t fade_length;
2060
2061         nframes64_t const pos = adjusted_current_frame (event);
2062
2063         boost::shared_ptr<Region> region = _primary->region ();
2064
2065         if (pos > (region->last_frame() - 64)) {
2066                 fade_length = 64; // this should really be a minimum fade defined somewhere
2067         }
2068         else if (pos < region->position()) {
2069                 fade_length = region->length();
2070         }
2071         else {
2072                 fade_length = region->last_frame() - pos;
2073         }
2074
2075         for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2076
2077                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2078
2079                 if (!tmp) {
2080                         continue;
2081                 }
2082
2083                 tmp->reset_fade_out_shape_width (fade_length);
2084         }
2085
2086         _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2087 }
2088
2089 void
2090 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2091 {
2092         if (!movement_occurred) {
2093                 return;
2094         }
2095
2096         nframes64_t fade_length;
2097
2098         nframes64_t const pos = adjusted_current_frame (event);
2099
2100         boost::shared_ptr<Region> region = _primary->region ();
2101
2102         if (pos > (region->last_frame() - 64)) {
2103                 fade_length = 64; // this should really be a minimum fade defined somewhere
2104         }
2105         else if (pos < region->position()) {
2106                 fade_length = region->length();
2107         }
2108         else {
2109                 fade_length = region->last_frame() - pos;
2110         }
2111
2112         _editor->begin_reversible_command (_("change fade out length"));
2113
2114         for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2115
2116                 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2117
2118                 if (!tmp) {
2119                         continue;
2120                 }
2121
2122                 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2123                 XMLNode &before = alist->get_state();
2124
2125                 tmp->audio_region()->set_fade_out_length (fade_length);
2126                 tmp->audio_region()->set_fade_out_active (true);
2127
2128                 XMLNode &after = alist->get_state();
2129                 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2130         }
2131
2132         _editor->commit_reversible_command ();
2133 }
2134
2135 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2136         : Drag (e, i)
2137 {
2138         _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2139         assert (_marker);
2140
2141         _points.push_back (Gnome::Art::Point (0, 0));
2142         _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2143
2144         _line = new ArdourCanvas::Line (*_editor->timebar_group);
2145         _line->property_width_pixels() = 1;
2146         _line->property_points () = _points;
2147         _line->hide ();
2148
2149         _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2150 }
2151
2152 MarkerDrag::~MarkerDrag ()
2153 {
2154         for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2155                 delete *i;
2156         }
2157 }
2158
2159 void
2160 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2161 {
2162         Drag::start_grab (event, cursor);
2163
2164         bool is_start;
2165
2166         Location *location = _editor->find_location_from_marker (_marker, is_start);
2167         _editor->_dragging_edit_point = true;
2168
2169         _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2170
2171         update_item (location);
2172
2173         // _drag_line->show();
2174         // _line->raise_to_top();
2175
2176         if (is_start) {
2177                 _editor->show_verbose_time_cursor (location->start(), 10);
2178         } else {
2179                 _editor->show_verbose_time_cursor (location->end(), 10);
2180         }
2181
2182         Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2183
2184         switch (op) {
2185         case Selection::Toggle:
2186                 _editor->selection->toggle (_marker);
2187                 break;
2188         case Selection::Set:
2189                 if (!_editor->selection->selected (_marker)) {
2190                         _editor->selection->set (_marker);
2191                 }
2192                 break;
2193         case Selection::Extend:
2194         {
2195                 Locations::LocationList ll;
2196                 list<Marker*> to_add;
2197                 nframes64_t s, e;
2198                 _editor->selection->markers.range (s, e);
2199                 s = min (_marker->position(), s);
2200                 e = max (_marker->position(), e);
2201                 s = min (s, e);
2202                 e = max (s, e);
2203                 if (e < max_frames) {
2204                         ++e;
2205                 }
2206                 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2207                 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2208                         Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2209                         if (lm) {
2210                                 if (lm->start) {
2211                                         to_add.push_back (lm->start);
2212                                 }
2213                                 if (lm->end) {
2214                                         to_add.push_back (lm->end);
2215                                 }
2216                         }
2217                 }
2218                 if (!to_add.empty()) {
2219                         _editor->selection->add (to_add);
2220                 }
2221                 break;
2222         }
2223         case Selection::Add:
2224                 _editor->selection->add (_marker);
2225                 break;
2226         }
2227
2228         /* set up copies for us to manipulate during the drag */
2229
2230         for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2231                 Location *l = _editor->find_location_from_marker (*i, is_start);
2232                 _copied_locations.push_back (new Location (*l));
2233         }
2234 }
2235
2236 void
2237 MarkerDrag::motion (GdkEvent* event, bool)
2238 {
2239         nframes64_t f_delta = 0;
2240         bool is_start;
2241         bool move_both = false;
2242         Marker* marker;
2243         Location  *real_location;
2244         Location *copy_location = 0;
2245
2246         nframes64_t const newframe = adjusted_current_frame (event);
2247
2248         nframes64_t next = newframe;
2249
2250         if (newframe == last_pointer_frame()) {
2251                 return;
2252         }
2253
2254         if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2255                 move_both = true;
2256         }
2257
2258         MarkerSelection::iterator i;
2259         list<Location*>::iterator x;
2260
2261         /* find the marker we're dragging, and compute the delta */
2262
2263         for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2264              x != _copied_locations.end() && i != _editor->selection->markers.end();
2265              ++i, ++x) {
2266
2267                 copy_location = *x;
2268                 marker = *i;
2269
2270                 if (marker == _marker) {
2271
2272                         if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2273                                 /* que pasa ?? */
2274                                 return;
2275                         }
2276
2277                         if (real_location->is_mark()) {
2278                                 f_delta = newframe - copy_location->start();
2279                         } else {
2280
2281
2282                                 switch (marker->type()) {
2283                                 case Marker::Start:
2284                                 case Marker::LoopStart:
2285                                 case Marker::PunchIn:
2286                                         f_delta = newframe - copy_location->start();
2287                                         break;
2288
2289                                 case Marker::End:
2290                                 case Marker::LoopEnd:
2291                                 case Marker::PunchOut:
2292                                         f_delta = newframe - copy_location->end();
2293                                         break;
2294                                 default:
2295                                         /* what kind of marker is this ? */
2296                                         return;
2297                                 }
2298                         }
2299                         break;
2300                 }
2301         }
2302
2303         if (i == _editor->selection->markers.end()) {
2304                 /* hmm, impossible - we didn't find the dragged marker */
2305                 return;
2306         }
2307
2308         /* now move them all */
2309
2310         for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2311              x != _copied_locations.end() && i != _editor->selection->markers.end();
2312              ++i, ++x) {
2313
2314                 copy_location = *x;
2315                 marker = *i;
2316
2317                 /* call this to find out if its the start or end */
2318
2319                 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2320                         continue;
2321                 }
2322
2323                 if (real_location->locked()) {
2324                         continue;
2325                 }
2326
2327                 if (copy_location->is_mark()) {
2328
2329                         /* just move it */
2330
2331                         copy_location->set_start (copy_location->start() + f_delta);
2332
2333                 } else {
2334
2335                         nframes64_t new_start = copy_location->start() + f_delta;
2336                         nframes64_t new_end = copy_location->end() + f_delta;
2337
2338                         if (is_start) { // start-of-range marker
2339
2340                                 if (move_both) {
2341                                         copy_location->set_start (new_start);
2342                                         copy_location->set_end (new_end);
2343                                 } else  if (new_start < copy_location->end()) {
2344                                         copy_location->set_start (new_start);
2345                                 } else {
2346                                         _editor->snap_to (next, 1, true);
2347                                         copy_location->set_end (next);
2348                                         copy_location->set_start (newframe);
2349                                 }
2350
2351                         } else { // end marker
2352
2353                                 if (move_both) {
2354                                         copy_location->set_end (new_end);
2355                                         copy_location->set_start (new_start);
2356                                 } else if (new_end > copy_location->start()) {
2357                                         copy_location->set_end (new_end);
2358                                 } else if (newframe > 0) {
2359                                         _editor->snap_to (next, -1, true);
2360                                         copy_location->set_start (next);
2361                                         copy_location->set_end (newframe);
2362                                 }
2363                         }
2364                 }
2365
2366                 update_item (copy_location);
2367
2368                 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2369
2370                 if (lm) {
2371                         lm->set_position (copy_location->start(), copy_location->end());
2372                 }
2373         }
2374
2375         assert (!_copied_locations.empty());
2376
2377         _editor->show_verbose_time_cursor (newframe, 10);
2378
2379 #ifdef GTKOSX
2380         _editor->update_canvas_now ();
2381 #endif
2382 }
2383
2384 void
2385 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2386 {
2387         if (!movement_occurred) {
2388
2389                 /* just a click, do nothing but finish
2390                    off the selection process
2391                 */
2392
2393                 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2394
2395                 switch (op) {
2396                 case Selection::Set:
2397                         if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2398                                 _editor->selection->set (_marker);
2399                         }
2400                         break;
2401
2402                 case Selection::Toggle:
2403                 case Selection::Extend:
2404                 case Selection::Add:
2405                         break;
2406                 }
2407
2408                 return;
2409         }
2410
2411         _editor->_dragging_edit_point = false;
2412
2413         _editor->begin_reversible_command ( _("move marker") );
2414         XMLNode &before = _editor->session()->locations()->get_state();
2415
2416         MarkerSelection::iterator i;
2417         list<Location*>::iterator x;
2418         bool is_start;
2419
2420         for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2421              x != _copied_locations.end() && i != _editor->selection->markers.end();
2422              ++i, ++x) {
2423
2424                 Location * location = _editor->find_location_from_marker (*i, is_start);
2425
2426                 if (location) {
2427
2428                         if (location->locked()) {
2429                                 return;
2430                         }
2431
2432                         if (location->is_mark()) {
2433                                 location->set_start ((*x)->start());
2434                         } else {
2435                                 location->set ((*x)->start(), (*x)->end());
2436                         }
2437                 }
2438         }
2439
2440         XMLNode &after = _editor->session()->locations()->get_state();
2441         _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2442         _editor->commit_reversible_command ();
2443
2444         _line->hide();
2445 }
2446
2447 void
2448 MarkerDrag::update_item (Location* location)
2449 {
2450         double const x1 = _editor->frame_to_pixel (location->start());
2451
2452         _points.front().set_x(x1);
2453         _points.back().set_x(x1);
2454         _line->property_points() = _points;
2455 }
2456
2457 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2458         : Drag (e, i),
2459           _cumulative_x_drag (0),
2460           _cumulative_y_drag (0)
2461 {
2462         _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2463         assert (_point);
2464 }
2465
2466
2467 void
2468 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2469 {
2470         Drag::start_grab (event, _editor->fader_cursor);
2471
2472         // start the grab at the center of the control point so
2473         // the point doesn't 'jump' to the mouse after the first drag
2474         _time_axis_view_grab_x = _point->get_x();
2475         _time_axis_view_grab_y = _point->get_y();
2476         nframes64_t grab_frame = _editor->pixel_to_frame (_time_axis_view_grab_x);
2477
2478         float const fraction = 1 - (_point->get_y() / _point->line().height());
2479
2480         _point->line().start_drag_single (_point, grab_frame, fraction);
2481
2482         _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2483                                             event->button.x + 10, event->button.y + 10);
2484
2485         _editor->show_verbose_canvas_cursor ();
2486 }
2487
2488 void
2489 ControlPointDrag::motion (GdkEvent* event, bool)
2490 {
2491         double dx = current_pointer_x() - last_pointer_x();
2492         double dy = current_pointer_y() - last_pointer_y();
2493
2494         if (event->button.state & Keyboard::SecondaryModifier) {
2495                 dx *= 0.1;
2496                 dy *= 0.1;
2497         }
2498
2499         /* coordinate in TimeAxisView's space */
2500         double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2501         double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2502
2503         // calculate zero crossing point. back off by .01 to stay on the
2504         // positive side of zero
2505         double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2506
2507         // make sure we hit zero when passing through
2508         if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2509                 cy = zero_gain_y;
2510         }
2511
2512         if (_x_constrained) {
2513                 cx = _time_axis_view_grab_x;
2514         }
2515         if (_y_constrained) {
2516                 cy = _time_axis_view_grab_y;
2517         }
2518
2519         _cumulative_x_drag = cx - _time_axis_view_grab_x;
2520         _cumulative_y_drag = cy - _time_axis_view_grab_y;
2521
2522         cx = max (0.0, cx);
2523         cy = max (0.0, cy);
2524         cy = min ((double) _point->line().height(), cy);
2525
2526         nframes64_t cx_frames = _editor->unit_to_frame (cx);
2527
2528         if (!_x_constrained) {
2529                 _editor->snap_to_with_modifier (cx_frames, event);
2530         }
2531
2532         float const fraction = 1.0 - (cy / _point->line().height());
2533
2534         bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2535
2536         _point->line().drag_motion (cx_frames, fraction, push);
2537
2538         _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2539 }
2540
2541 void
2542 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2543 {
2544         if (!movement_occurred) {
2545
2546                 /* just a click */
2547
2548                 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2549                         _editor->reset_point_selection ();
2550                 }
2551
2552         } else {
2553                 motion (event, false);
2554         }
2555         _point->line().end_drag ();
2556 }
2557
2558 bool
2559 ControlPointDrag::active (Editing::MouseMode m)
2560 {
2561         if (m == Editing::MouseGain) {
2562                 /* always active in mouse gain */
2563                 return true;
2564         }
2565
2566         /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2567         return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2568 }
2569
2570 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2571         : Drag (e, i),
2572           _line (0),
2573           _cumulative_y_drag (0)
2574 {
2575
2576 }
2577 void
2578 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2579 {
2580         _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2581         assert (_line);
2582
2583         _item = &_line->grab_item ();
2584
2585         /* need to get x coordinate in terms of parent (TimeAxisItemView)
2586            origin, and ditto for y.
2587         */
2588
2589         double cx = event->button.x;
2590         double cy = event->button.y;
2591
2592         _line->parent_group().w2i (cx, cy);
2593
2594         nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2595
2596         uint32_t before;
2597         uint32_t after;
2598         
2599         if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2600                 /* no adjacent points */
2601                 return;
2602         }
2603
2604         Drag::start_grab (event, _editor->fader_cursor);
2605
2606         /* store grab start in parent frame */
2607
2608         _time_axis_view_grab_x = cx;
2609         _time_axis_view_grab_y = cy;
2610
2611         double fraction = 1.0 - (cy / _line->height());
2612
2613         _line->start_drag_line (before, after, fraction);
2614
2615         _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2616                                             event->button.x + 10, event->button.y + 10);
2617
2618         _editor->show_verbose_canvas_cursor ();
2619 }
2620
2621 void
2622 LineDrag::motion (GdkEvent* event, bool)
2623 {
2624         double dy = current_pointer_y() - last_pointer_y();
2625
2626         if (event->button.state & Keyboard::SecondaryModifier) {
2627                 dy *= 0.1;
2628         }
2629
2630         double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2631
2632         _cumulative_y_drag = cy - _time_axis_view_grab_y;
2633
2634         cy = max (0.0, cy);
2635         cy = min ((double) _line->height(), cy);
2636
2637         double const fraction = 1.0 - (cy / _line->height());
2638
2639         bool push;
2640
2641         if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2642                 push = false;
2643         } else {
2644                 push = true;
2645         }
2646
2647         /* we are ignoring x position for this drag, so we can just pass in 0 */
2648         _line->drag_motion (0, fraction, push);
2649
2650         _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2651 }
2652
2653 void
2654 LineDrag::finished (GdkEvent* event, bool)
2655 {
2656         motion (event, false);
2657         _line->end_drag ();
2658 }
2659
2660 void
2661 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2662 {
2663         Drag::start_grab (event);
2664         _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2665 }
2666
2667 void
2668 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2669 {
2670         nframes64_t start;
2671         nframes64_t end;
2672         double y1;
2673         double y2;
2674
2675         /* use a bigger drag threshold than the default */
2676
2677         nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2678
2679         if (abs ((int) (pf - grab_frame())) < 8) {
2680                 return;
2681         }
2682
2683         nframes64_t grab = grab_frame ();
2684         if (Config->get_rubberbanding_snaps_to_grid ()) {
2685                 _editor->snap_to_with_modifier (grab, event);
2686         }
2687
2688         /* base start and end on initial click position */
2689
2690         if (pf < grab) {
2691                 start = pf;
2692                 end = grab;
2693         } else {
2694                 end = pf;
2695                 start = grab;
2696         }
2697
2698         if (current_pointer_y() < grab_y()) {
2699                 y1 = current_pointer_y();
2700                 y2 = grab_y();
2701         } else {
2702                 y2 = current_pointer_y();
2703                 y1 = grab_y();
2704         }
2705
2706
2707         if (start != end || y1 != y2) {
2708
2709                 double x1 = _editor->frame_to_pixel (start);
2710                 double x2 = _editor->frame_to_pixel (end);
2711
2712                 _editor->rubberband_rect->property_x1() = x1;
2713                 _editor->rubberband_rect->property_y1() = y1;
2714                 _editor->rubberband_rect->property_x2() = x2;
2715                 _editor->rubberband_rect->property_y2() = y2;
2716
2717                 _editor->rubberband_rect->show();
2718                 _editor->rubberband_rect->raise_to_top();
2719
2720                 _editor->show_verbose_time_cursor (pf, 10);
2721         }
2722 }
2723
2724 void
2725 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2726 {
2727         if (movement_occurred) {
2728
2729                 motion (event, false);
2730
2731                 double y1,y2;
2732                 if (current_pointer_y() < grab_y()) {
2733                         y1 = current_pointer_y();
2734                         y2 = grab_y();
2735                 } else {
2736                         y2 = current_pointer_y();
2737                         y1 = grab_y();
2738                 }
2739
2740
2741                 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2742                 bool committed;
2743
2744                 _editor->begin_reversible_command (_("rubberband selection"));
2745
2746                 if (grab_frame() < last_pointer_frame()) {
2747                         committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
2748                 } else {
2749                         committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
2750                 }
2751
2752                 if (!committed) {
2753                         _editor->commit_reversible_command ();
2754                 }
2755
2756         } else {
2757                 if (!getenv("ARDOUR_SAE")) {
2758                         _editor->selection->clear_tracks();
2759                 }
2760                 _editor->selection->clear_regions();
2761                 _editor->selection->clear_points ();
2762                 _editor->selection->clear_lines ();
2763         }
2764
2765         _editor->rubberband_rect->hide();
2766 }
2767
2768 void
2769 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2770 {
2771         Drag::start_grab (event);
2772
2773         _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2774 }
2775
2776 void
2777 TimeFXDrag::motion (GdkEvent* event, bool)
2778 {
2779         RegionView* rv = _primary;
2780
2781         nframes64_t const pf = adjusted_current_frame (event);
2782
2783         if (pf == last_pointer_frame()) {
2784                 return;
2785         }
2786
2787         if (pf > rv->region()->position()) {
2788                 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
2789         }
2790
2791         _editor->show_verbose_time_cursor (pf, 10);
2792 }
2793
2794 void
2795 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2796 {
2797         _primary->get_time_axis_view().hide_timestretch ();
2798
2799         if (!movement_occurred) {
2800                 return;
2801         }
2802
2803         if (last_pointer_frame() < _primary->region()->position()) {
2804                 /* backwards drag of the left edge - not usable */
2805                 return;
2806         }
2807
2808         nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
2809
2810         float percentage = (double) newlen / (double) _primary->region()->length();
2811
2812 #ifndef USE_RUBBERBAND
2813         // Soundtouch uses percentage / 100 instead of normal (/ 1)
2814         if (_primary->region()->data_type() == DataType::AUDIO) {
2815                 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
2816         }
2817 #endif
2818
2819         _editor->begin_reversible_command (_("timestretch"));
2820
2821         // XXX how do timeFX on multiple regions ?
2822
2823         RegionSelection rs;
2824         rs.add (_primary);
2825
2826         if (!_editor->time_stretch (rs, percentage) == 0) {
2827                 error << _("An error occurred while executing time stretch operation") << endmsg;
2828         }
2829 }
2830
2831 void
2832 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2833 {
2834         Drag::start_grab (event);
2835 }
2836
2837 void
2838 ScrubDrag::motion (GdkEvent* /*event*/, bool)
2839 {
2840         _editor->scrub ();
2841 }
2842
2843 void
2844 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
2845 {
2846         if (movement_occurred && _editor->session()) {
2847                 /* make sure we stop */
2848                 _editor->session()->request_transport_speed (0.0);
2849         }
2850 }
2851
2852 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
2853         : Drag (e, i)
2854         , _operation (o)
2855         , _copy (false)
2856         , _original_pointer_time_axis (-1)
2857         , _last_pointer_time_axis (-1)
2858 {
2859
2860 }
2861
2862 void
2863 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
2864 {
2865         nframes64_t start = 0;
2866         nframes64_t end = 0;
2867
2868         if (_editor->session() == 0) {
2869                 return;
2870         }
2871
2872         Gdk::Cursor* cursor = 0;
2873
2874         switch (_operation) {
2875         case CreateSelection:
2876                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2877                         _copy = true;
2878                 } else {
2879                         _copy = false;
2880                 }
2881                 cursor = _editor->selector_cursor;
2882                 Drag::start_grab (event, cursor);
2883                 break;
2884
2885         case SelectionStartTrim:
2886                 if (_editor->clicked_axisview) {
2887                         _editor->clicked_axisview->order_selection_trims (_item, true);
2888                 }
2889                 Drag::start_grab (event, _editor->trimmer_cursor);
2890                 start = _editor->selection->time[_editor->clicked_selection].start;
2891                 _pointer_frame_offset = grab_frame() - start;
2892                 break;
2893
2894         case SelectionEndTrim:
2895                 if (_editor->clicked_axisview) {
2896                         _editor->clicked_axisview->order_selection_trims (_item, false);
2897                 }
2898                 Drag::start_grab (event, _editor->trimmer_cursor);
2899                 end = _editor->selection->time[_editor->clicked_selection].end;
2900                 _pointer_frame_offset = grab_frame() - end;
2901                 break;
2902
2903         case SelectionMove:
2904                 start = _editor->selection->time[_editor->clicked_selection].start;
2905                 Drag::start_grab (event, cursor);
2906                 _pointer_frame_offset = grab_frame() - start;
2907                 break;
2908         }
2909
2910         if (_operation == SelectionMove) {
2911                 _editor->show_verbose_time_cursor (start, 10);
2912         } else {
2913                 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2914         }
2915
2916         _original_pointer_time_axis = _editor->trackview_by_y_position (current_pointer_y ()).first->order ();
2917 }
2918
2919 void
2920 SelectionDrag::motion (GdkEvent* event, bool first_move)
2921 {
2922         nframes64_t start = 0;
2923         nframes64_t end = 0;
2924         nframes64_t length;
2925
2926         pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (current_pointer_y ());
2927         if (pending_time_axis.first == 0) {
2928                 return;
2929         }
2930         
2931         nframes64_t const pending_position = adjusted_current_frame (event);
2932
2933         /* only alter selection if things have changed */
2934
2935         if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
2936                 return;
2937         }
2938
2939         switch (_operation) {
2940         case CreateSelection:
2941         {
2942                 nframes64_t grab = grab_frame ();
2943
2944                 if (first_move) {
2945                         _editor->snap_to (grab);
2946                 }
2947
2948                 if (pending_position < grab_frame()) {
2949                         start = pending_position;
2950                         end = grab;
2951                 } else {
2952                         end = pending_position;
2953                         start = grab;
2954                 }
2955
2956                 /* first drag: Either add to the selection
2957                    or create a new selection
2958                 */
2959
2960                 if (first_move) {
2961
2962                         _editor->begin_reversible_command (_("range selection"));
2963                         _have_transaction = true;
2964
2965                         if (_copy) {
2966                                 /* adding to the selection */
2967                                 _editor->selection->add (_editor->clicked_axisview);
2968                                 _editor->clicked_selection = _editor->selection->add (start, end);
2969                                 _copy = false;
2970                         } else {
2971                                 /* new selection */
2972
2973                                 if (!_editor->selection->selected (_editor->clicked_axisview)) {
2974                                         _editor->selection->set (_editor->clicked_axisview);
2975                                 }
2976                                 
2977                                 _editor->clicked_selection = _editor->selection->set (start, end);
2978                         }
2979                 }
2980
2981                 /* select the track that we're in */
2982                 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
2983                         _editor->selection->add (pending_time_axis.first);
2984                         _added_time_axes.push_back (pending_time_axis.first);
2985                 }
2986
2987                 /* deselect any tracks that this drag no longer includes, being careful to only deselect
2988                    tracks that we selected in the first place.
2989                 */
2990                 
2991                 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
2992                 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
2993
2994                 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
2995                 while (i != _added_time_axes.end()) {
2996
2997                         list<TimeAxisView*>::iterator tmp = i;
2998                         ++tmp;
2999                         
3000                         if ((*i)->order() < min_order || (*i)->order() > max_order) {
3001                                 _editor->selection->remove (*i);
3002                                 _added_time_axes.remove (*i);
3003                         }
3004
3005                         i = tmp;
3006                 }
3007
3008         }
3009         break;
3010
3011         case SelectionStartTrim:
3012
3013                 if (first_move) {
3014                         _editor->begin_reversible_command (_("trim selection start"));
3015                         _have_transaction = true;
3016                 }
3017                 
3018                 start = _editor->selection->time[_editor->clicked_selection].start;
3019                 end = _editor->selection->time[_editor->clicked_selection].end;
3020
3021                 if (pending_position > end) {
3022                         start = end;
3023                 } else {
3024                         start = pending_position;
3025                 }
3026                 break;
3027
3028         case SelectionEndTrim:
3029
3030                 if (first_move) {
3031                         _editor->begin_reversible_command (_("trim selection end"));
3032                         _have_transaction = true;
3033                 }
3034
3035                 start = _editor->selection->time[_editor->clicked_selection].start;
3036                 end = _editor->selection->time[_editor->clicked_selection].end;
3037
3038                 if (pending_position < start) {
3039                         end = start;
3040                 } else {
3041                         end = pending_position;
3042                 }
3043
3044                 break;
3045
3046         case SelectionMove:
3047
3048                 if (first_move) {
3049                         _editor->begin_reversible_command (_("move selection"));
3050                         _have_transaction = true;
3051                 }
3052
3053                 start = _editor->selection->time[_editor->clicked_selection].start;
3054                 end = _editor->selection->time[_editor->clicked_selection].end;
3055
3056                 length = end - start;
3057
3058                 start = pending_position;
3059                 _editor->snap_to (start);
3060
3061                 end = start + length;
3062
3063                 break;
3064         }
3065
3066         if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3067                 _editor->start_canvas_autoscroll (1, 0);
3068         }
3069
3070         if (start != end) {
3071                 _editor->selection->replace (_editor->clicked_selection, start, end);
3072         }
3073
3074         if (_operation == SelectionMove) {
3075                 _editor->show_verbose_time_cursor(start, 10);
3076         } else {
3077                 _editor->show_verbose_time_cursor(pending_position, 10);
3078         }
3079 }
3080
3081 void
3082 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3083 {
3084         Session* s = _editor->session();
3085
3086         if (movement_occurred) {
3087                 motion (event, false);
3088                 /* XXX this is not object-oriented programming at all. ick */
3089                 if (_editor->selection->time.consolidate()) {
3090                         _editor->selection->TimeChanged ();
3091                 }
3092
3093                 if (_have_transaction) {
3094                         _editor->commit_reversible_command ();
3095                 }
3096
3097                 /* XXX what if its a music time selection? */
3098                 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3099                         s->request_play_range (&_editor->selection->time, true);
3100                 }
3101
3102
3103         } else {
3104                 /* just a click, no pointer movement.*/
3105
3106                 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3107                         _editor->selection->clear_time();
3108                 }
3109
3110                 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3111                         _editor->selection->set (_editor->clicked_axisview);
3112                 }
3113                 
3114                 if (s && s->get_play_range () && s->transport_rolling()) {
3115                         s->request_stop (false, false);
3116                 }
3117
3118         }
3119
3120         _editor->stop_canvas_autoscroll ();
3121 }
3122
3123 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3124         : Drag (e, i),
3125           _operation (o),
3126           _copy (false)
3127 {
3128         _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3129         _drag_rect->hide ();
3130
3131         _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3132         _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3133 }
3134
3135 void
3136 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3137 {
3138         if (_editor->session() == 0) {
3139                 return;
3140         }
3141
3142         Gdk::Cursor* cursor = 0;
3143
3144         if (!_editor->temp_location) {
3145                 _editor->temp_location = new Location;
3146         }
3147
3148         switch (_operation) {
3149         case CreateRangeMarker:
3150         case CreateTransportMarker:
3151         case CreateCDMarker:
3152
3153                 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3154                         _copy = true;
3155                 } else {
3156                         _copy = false;
3157                 }
3158                 cursor = _editor->selector_cursor;
3159                 break;
3160         }
3161
3162         Drag::start_grab (event, cursor);
3163
3164         _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3165 }
3166
3167 void
3168 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3169 {
3170         nframes64_t start = 0;
3171         nframes64_t end = 0;
3172         ArdourCanvas::SimpleRect *crect;
3173
3174         switch (_operation) {
3175         case CreateRangeMarker:
3176                 crect = _editor->range_bar_drag_rect;
3177                 break;
3178         case CreateTransportMarker:
3179                 crect = _editor->transport_bar_drag_rect;
3180                 break;
3181         case CreateCDMarker:
3182                 crect = _editor->cd_marker_bar_drag_rect;
3183                 break;
3184         default:
3185                 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3186                 return;
3187                 break;
3188         }
3189
3190         nframes64_t const pf = adjusted_current_frame (event);
3191
3192         /* only alter selection if the current frame is
3193            different from the last frame position.
3194          */
3195
3196         if (pf == last_pointer_frame()) {
3197                 return;
3198         }
3199
3200         if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3201                 nframes64_t grab = grab_frame ();
3202                 _editor->snap_to (grab);
3203                 
3204                 if (pf < grab_frame()) {
3205                         start = pf;
3206                         end = grab;
3207                 } else {
3208                         end = pf;
3209                         start = grab;
3210                 }
3211
3212                 /* first drag: Either add to the selection
3213                    or create a new selection.
3214                 */
3215
3216                 if (first_move) {
3217
3218                         _editor->temp_location->set (start, end);
3219
3220                         crect->show ();
3221
3222                         update_item (_editor->temp_location);
3223                         _drag_rect->show();
3224                         //_drag_rect->raise_to_top();
3225
3226                 }
3227         }
3228
3229         if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3230                 _editor->start_canvas_autoscroll (1, 0);
3231         }
3232
3233         if (start != end) {
3234                 _editor->temp_location->set (start, end);
3235
3236                 double x1 = _editor->frame_to_pixel (start);
3237                 double x2 = _editor->frame_to_pixel (end);
3238                 crect->property_x1() = x1;
3239                 crect->property_x2() = x2;
3240
3241                 update_item (_editor->temp_location);
3242         }
3243
3244         _editor->show_verbose_time_cursor (pf, 10);
3245
3246 }
3247
3248 void
3249 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3250 {
3251         Location * newloc = 0;
3252         string rangename;
3253         int flags;
3254
3255         if (movement_occurred) {
3256                 motion (event, false);
3257                 _drag_rect->hide();
3258
3259                 switch (_operation) {
3260                 case CreateRangeMarker:
3261                 case CreateCDMarker:
3262                     {
3263                         _editor->begin_reversible_command (_("new range marker"));
3264                         XMLNode &before = _editor->session()->locations()->get_state();
3265                         _editor->session()->locations()->next_available_name(rangename,"unnamed");
3266                         if (_operation == CreateCDMarker) {
3267                                 flags = Location::IsRangeMarker | Location::IsCDMarker;
3268                                 _editor->cd_marker_bar_drag_rect->hide();
3269                         }
3270                         else {
3271                                 flags = Location::IsRangeMarker;
3272                                 _editor->range_bar_drag_rect->hide();
3273                         }
3274                         newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3275                         _editor->session()->locations()->add (newloc, true);
3276                         XMLNode &after = _editor->session()->locations()->get_state();
3277                         _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3278                         _editor->commit_reversible_command ();
3279                         break;
3280                     }
3281
3282                 case CreateTransportMarker:
3283                         // popup menu to pick loop or punch
3284                         _editor->new_transport_marker_context_menu (&event->button, _item);
3285                         break;
3286                 }
3287         } else {
3288                 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3289
3290                 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3291
3292                         nframes64_t start;
3293                         nframes64_t end;
3294
3295                         _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3296
3297                         if (end == max_frames) {
3298                                 end = _editor->session()->current_end_frame ();
3299                         }
3300
3301                         if (start == max_frames) {
3302                                 start = _editor->session()->current_start_frame ();
3303                         }
3304
3305                         switch (_editor->mouse_mode) {
3306                         case MouseObject:
3307                                 /* find the two markers on either side and then make the selection from it */
3308                                 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3309                                 break;
3310
3311                         case MouseRange:
3312                                 /* find the two markers on either side of the click and make the range out of it */
3313                                 _editor->selection->set (start, end);
3314                                 break;
3315
3316                         default:
3317                                 break;
3318                         }
3319                 }
3320         }
3321
3322         _editor->stop_canvas_autoscroll ();
3323 }
3324
3325
3326
3327 void
3328 RangeMarkerBarDrag::update_item (Location* location)
3329 {
3330         double const x1 = _editor->frame_to_pixel (location->start());
3331         double const x2 = _editor->frame_to_pixel (location->end());
3332
3333         _drag_rect->property_x1() = x1;
3334         _drag_rect->property_x2() = x2;
3335 }
3336
3337 void
3338 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3339 {
3340         Drag::start_grab (event, _editor->zoom_cursor);
3341         _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3342 }
3343
3344 void
3345 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3346 {
3347         nframes64_t start;
3348         nframes64_t end;
3349
3350         nframes64_t const pf = adjusted_current_frame (event);
3351
3352         if (pf == last_pointer_frame()) {
3353                 return;
3354         }
3355
3356         nframes64_t grab = grab_frame ();
3357         _editor->snap_to_with_modifier (grab, event);
3358
3359         /* base start and end on initial click position */
3360         if (pf < grab) {
3361                 start = pf;
3362                 end = grab;
3363         } else {
3364                 end = pf;
3365                 start = grab;
3366         }
3367
3368         if (start != end) {
3369
3370                 if (first_move) {
3371                         _editor->zoom_rect->show();
3372                         _editor->zoom_rect->raise_to_top();
3373                 }
3374
3375                 _editor->reposition_zoom_rect(start, end);
3376
3377                 _editor->show_verbose_time_cursor (pf, 10);
3378         }
3379 }
3380
3381 void
3382 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3383 {
3384         if (movement_occurred) {
3385                 motion (event, false);
3386
3387                 if (grab_frame() < last_pointer_frame()) {
3388                         _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3389                 } else {
3390                         _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3391                 }
3392         } else {
3393                 _editor->temporal_zoom_to_frame (false, grab_frame());
3394                 /*
3395                 temporal_zoom_step (false);
3396                 center_screen (grab_frame());
3397                 */
3398         }
3399
3400         _editor->zoom_rect->hide();
3401 }
3402
3403 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3404         : Drag (e, i)
3405 {
3406         CanvasNoteEvent*     cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3407         region = &cnote->region_view();
3408 }
3409
3410 void
3411 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3412 {
3413         Drag::start_grab (event);
3414
3415         drag_delta_x = 0;
3416         drag_delta_note = 0;
3417
3418         double event_x;
3419         double event_y;
3420
3421         event_x = current_pointer_x();
3422         event_y = current_pointer_y();
3423
3424         _item->property_parent().get_value()->w2i(event_x, event_y);
3425
3426         last_x = region->snap_to_pixel(event_x);
3427         last_y = event_y;
3428
3429         CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3430
3431         if (!(was_selected = cnote->selected())) {
3432
3433                 /* tertiary-click means extend selection - we'll do that on button release,
3434                    so don't add it here, because otherwise we make it hard to figure
3435                    out the "extend-to" range.
3436                 */
3437
3438                 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3439
3440                 if (!extend) {
3441                         bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3442
3443                         if (add) {
3444                                 region->note_selected (cnote, true);
3445                         } else {
3446                                 region->unique_select (cnote);
3447                         }
3448                 }
3449         }
3450 }
3451
3452 void
3453 NoteDrag::motion (GdkEvent*, bool)
3454 {
3455         MidiStreamView* streamview = region->midi_stream_view();
3456         double event_x;
3457         double event_y;
3458
3459         event_x = current_pointer_x();
3460         event_y = current_pointer_y();
3461
3462         _item->property_parent().get_value()->w2i(event_x, event_y);
3463
3464         event_x = region->snap_to_pixel(event_x);
3465
3466         double dx     = event_x - last_x;
3467         double dy     = event_y - last_y;
3468         last_x = event_x;
3469
3470         drag_delta_x += dx;
3471
3472         // Snap to note rows
3473
3474         if (abs (dy) < streamview->note_height()) {
3475                 dy = 0.0;
3476         } else {
3477                 int8_t this_delta_note;
3478                 if (dy > 0) {
3479                         this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3480                 } else {
3481                         this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3482                 }
3483                 drag_delta_note -= this_delta_note;
3484                 dy = streamview->note_height() * this_delta_note;
3485                 last_y = last_y + dy;
3486         }
3487
3488         if (dx || dy) {
3489                 region->move_selection (dx, dy);
3490
3491                 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3492                 char buf[4];
3493                 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3494                 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3495                 _editor->show_verbose_canvas_cursor_with (buf);
3496         }
3497 }
3498
3499 void
3500 NoteDrag::finished (GdkEvent* ev, bool moved)
3501 {
3502         ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3503
3504         if (!moved) {
3505                 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3506
3507                         if (was_selected) {
3508                                 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3509                                 if (add) {
3510                                         region->note_deselected (cnote);
3511                                 }
3512                         } else {
3513                                 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3514                                 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3515
3516                                 if (!extend && !add && region->selection_size() > 1) {
3517                                         region->unique_select(cnote);
3518                                 } else if (extend) {
3519                                         region->note_selected (cnote, true, true);
3520                                 } else {
3521                                         /* it was added during button press */
3522                                 }
3523                         }
3524                 }
3525         } else {
3526                 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3527         }
3528 }
3529
3530 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3531         : Drag (e, i)
3532         , _ranges (r)
3533         , _nothing_to_drag (false)
3534 {
3535         _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3536         assert (_atav);
3537
3538         _line = _atav->line ();
3539 }
3540
3541 void
3542 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3543 {
3544         Drag::start_grab (event, cursor);
3545
3546         list<ControlPoint*> points;
3547
3548         XMLNode* state = &_line->get_state ();
3549         
3550         if (_ranges.empty()) {
3551                 
3552                 uint32_t const N = _line->npoints ();
3553                 for (uint32_t i = 0; i < N; ++i) {
3554                         points.push_back (_line->nth (i));
3555                 }
3556                 
3557         } else {
3558
3559                 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3560                 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3561
3562                         /* fade into and out of the region that we're dragging;
3563                            64 samples length plucked out of thin air.
3564                         */
3565                         nframes64_t const h = (j->start + j->end) / 2;
3566                         nframes64_t a = j->start + 64;
3567                         if (a > h) {
3568                                 a = h;
3569                         }
3570                         nframes64_t b = j->end - 64;
3571                         if (b < h) {
3572                                 b = h;
3573                         }
3574                         
3575                         the_list->add (j->start, the_list->eval (j->start));
3576                         _line->add_always_in_view (j->start);
3577                         the_list->add (a, the_list->eval (a));
3578                         _line->add_always_in_view (a);
3579                         the_list->add (b, the_list->eval (b));
3580                         _line->add_always_in_view (b);
3581                         the_list->add (j->end, the_list->eval (j->end));
3582                         _line->add_always_in_view (j->end);
3583                 }
3584
3585                 uint32_t const N = _line->npoints ();
3586                 for (uint32_t i = 0; i < N; ++i) {
3587
3588                         ControlPoint* p = _line->nth (i);
3589
3590                         list<AudioRange>::const_iterator j = _ranges.begin ();
3591                         while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3592                                 ++j;
3593                         }
3594
3595                         if (j != _ranges.end()) {
3596                                 points.push_back (p);
3597                         }
3598                 }
3599         }
3600
3601         if (points.empty()) {
3602                 _nothing_to_drag = true;
3603                 return;
3604         }
3605
3606         _line->start_drag_multiple (points, 1 - (current_pointer_y() / _line->height ()), state);
3607 }
3608
3609 void
3610 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3611 {
3612         if (_nothing_to_drag) {
3613                 return;
3614         }
3615         
3616         float const f = 1 - (current_pointer_y() / _line->height());
3617
3618         /* we are ignoring x position for this drag, so we can just pass in 0 */
3619         _line->drag_motion (0, f, false);
3620 }
3621
3622 void
3623 AutomationRangeDrag::finished (GdkEvent* event, bool)
3624 {
3625         if (_nothing_to_drag) {
3626                 return;
3627         }
3628         
3629         motion (event, false);
3630         _line->end_drag ();
3631         _line->clear_always_in_view ();
3632 }