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