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