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