2 Copyright (C) 2009 Paul Davis
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.
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.
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.
20 #include "pbd/memento_command.h"
21 #include "pbd/basename.h"
22 #include "ardour/diskstream.h"
23 #include "ardour/session.h"
24 #include "ardour/dB.h"
25 #include "ardour/region_factory.h"
26 #include "ardour/midi_diskstream.h"
30 #include "audio_region_view.h"
31 #include "midi_region_view.h"
32 #include "ardour_ui.h"
33 #include "gui_thread.h"
34 #include "control_point.h"
36 #include "region_gain_line.h"
37 #include "editor_drag.h"
38 #include "audio_time_axis.h"
39 #include "midi_time_axis.h"
40 #include "canvas-note.h"
41 #include "selection.h"
42 #include "midi_selection.h"
43 #include "automation_time_axis.h"
46 using namespace ARDOUR;
49 using namespace Editing;
50 using namespace ArdourCanvas;
52 using Gtkmm2ext::Keyboard;
54 double const ControlPointDrag::_zero_gain_fraction = gain_to_slider_position (dB_to_coefficient (0.0));
56 DragManager::DragManager (Editor* e)
59 , _current_pointer_frame (0)
64 DragManager::~DragManager ()
72 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
81 DragManager::break_drag ()
85 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
96 DragManager::add (Drag* d)
98 d->set_manager (this);
103 DragManager::set (Drag* d, GdkEvent* e, Gdk::Cursor* c)
105 assert (_drags.empty ());
106 d->set_manager (this);
107 _drags.push_back (d);
112 DragManager::start_grab (GdkEvent* e)
114 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
116 for (list<Drag*>::const_iterator i = _drags.begin(); i != _drags.end(); ++i) {
117 (*i)->start_grab (e);
122 DragManager::end_grab (GdkEvent* e)
127 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
128 bool const t = (*i)->end_grab (e);
143 DragManager::motion_handler (GdkEvent* e, bool from_autoscroll)
147 _current_pointer_frame = _editor->event_frame (e, &_current_pointer_x, &_current_pointer_y);
149 for (list<Drag*>::iterator i = _drags.begin(); i != _drags.end(); ++i) {
150 bool const t = (*i)->motion_handler (e, from_autoscroll);
161 DragManager::have_item (ArdourCanvas::Item* i) const
163 list<Drag*>::const_iterator j = _drags.begin ();
164 while (j != _drags.end() && (*j)->item () != i) {
168 return j != _drags.end ();
171 pair<nframes64_t, nframes64_t>
172 DragManager::extent () const
174 if (_drags.empty()) {
175 return make_pair (0, 0);
178 list<Drag*>::const_iterator i = _drags.begin ();
179 pair<nframes64_t, nframes64_t> e = (*i)->extent ();
182 while (i != _drags.end()) {
183 pair<nframes64_t, nframes64_t> const t = (*i)->extent ();
184 e.first = min (e.first, t.first);
185 e.second = max (e.second, t.second);
192 Drag::Drag (Editor* e, ArdourCanvas::Item* i)
195 , _pointer_frame_offset (0)
196 , _move_threshold_passed (false)
198 , _last_pointer_frame (0)
204 Drag::swap_grab (ArdourCanvas::Item* new_item, Gdk::Cursor* cursor, uint32_t time)
210 cursor = _editor->which_grabber_cursor ();
213 _item->grab (Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK, *cursor, time);
217 Drag::start_grab (GdkEvent* event, Gdk::Cursor *cursor)
220 cursor = _editor->which_grabber_cursor ();
223 // if dragging with button2, the motion is x constrained, with Alt-button2 it is y constrained
225 if (Keyboard::is_button2_event (&event->button)) {
226 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::SecondaryModifier)) {
227 _y_constrained = true;
228 _x_constrained = false;
230 _y_constrained = false;
231 _x_constrained = true;
234 _x_constrained = false;
235 _y_constrained = false;
238 _grab_frame = _editor->event_frame (event, &_grab_x, &_grab_y);
239 _grab_frame = adjusted_frame (_grab_frame, event);
240 _last_pointer_frame = _grab_frame;
241 _last_pointer_x = _grab_x;
242 _last_pointer_y = _grab_y;
244 _item->grab (Gdk::POINTER_MOTION_MASK|Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK,
248 if (_editor->session() && _editor->session()->transport_rolling()) {
251 _was_rolling = false;
254 switch (_editor->snap_type()) {
255 case SnapToRegionStart:
256 case SnapToRegionEnd:
257 case SnapToRegionSync:
258 case SnapToRegionBoundary:
259 _editor->build_region_boundary_cache ();
266 /** @param event GDK event, or 0.
267 * @return true if some movement occurred, otherwise false.
270 Drag::end_grab (GdkEvent* event)
272 _editor->stop_canvas_autoscroll ();
274 _item->ungrab (event ? event->button.time : 0);
276 finished (event, _move_threshold_passed);
278 _editor->hide_verbose_canvas_cursor();
280 return _move_threshold_passed;
284 Drag::adjusted_frame (nframes64_t f, GdkEvent const * event, bool snap) const
288 if (f > _pointer_frame_offset) {
289 pos = f - _pointer_frame_offset;
293 _editor->snap_to_with_modifier (pos, event);
300 Drag::adjusted_current_frame (GdkEvent const * event, bool snap) const
302 return adjusted_frame (_drags->current_pointer_frame (), event, snap);
306 Drag::motion_handler (GdkEvent* event, bool from_autoscroll)
308 /* check to see if we have moved in any way that matters since the last motion event */
309 if ( (!x_movement_matters() || _last_pointer_frame == adjusted_current_frame (event)) &&
310 (!y_movement_matters() || _last_pointer_y == _drags->current_pointer_y ()) ) {
314 pair<nframes64_t, int> const threshold = move_threshold ();
316 bool const old_move_threshold_passed = _move_threshold_passed;
318 if (!from_autoscroll && !_move_threshold_passed) {
320 bool const xp = (::llabs (adjusted_current_frame (event) - _grab_frame) >= threshold.first);
321 bool const yp = (::fabs ((_drags->current_pointer_y () - _grab_y)) >= threshold.second);
323 _move_threshold_passed = ((xp && x_movement_matters()) || (yp && y_movement_matters()));
326 if (active (_editor->mouse_mode) && _move_threshold_passed) {
328 if (event->motion.state & Gdk::BUTTON1_MASK || event->motion.state & Gdk::BUTTON2_MASK) {
329 if (!from_autoscroll) {
330 _editor->maybe_autoscroll (&event->motion, allow_vertical_autoscroll ());
333 motion (event, _move_threshold_passed != old_move_threshold_passed);
335 _last_pointer_x = _drags->current_pointer_x ();
336 _last_pointer_y = _drags->current_pointer_y ();
337 _last_pointer_frame = adjusted_current_frame (event);
355 _editor->stop_canvas_autoscroll ();
356 _editor->hide_verbose_canvas_cursor ();
359 pair<nframes64_t, nframes64_t>
360 Drag::extent () const
362 nframes64_t const f = adjusted_current_frame (0);
363 return make_pair (f, f);
366 RegionDrag::RegionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
371 RegionView::RegionViewGoingAway.connect (death_connection, ui_bind (&RegionDrag::region_going_away, this, _1), gui_context());
375 RegionDrag::region_going_away (RegionView* v)
377 if (!_drags->ending ()) {
382 pair<nframes64_t, nframes64_t>
383 RegionDrag::extent () const
385 nframes64_t const f = adjusted_current_frame (0);
386 return make_pair (f, f + _primary->region()->length ());
390 RegionMotionDrag::RegionMotionDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b)
391 : RegionDrag (e, i, p, v),
402 RegionMotionDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
404 Drag::start_grab (event);
406 _editor->show_verbose_time_cursor (_last_frame_position, 10);
409 RegionMotionDrag::TimeAxisViewSummary
410 RegionMotionDrag::get_time_axis_view_summary ()
412 int32_t children = 0;
413 TimeAxisViewSummary sum;
415 _editor->visible_order_range (&sum.visible_y_low, &sum.visible_y_high);
417 /* get a bitmask representing the visible tracks */
419 for (TrackViewList::iterator i = _editor->track_views.begin(); i != _editor->track_views.end(); ++i) {
420 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (*i);
421 TimeAxisView::Children children_list;
423 /* zeroes are audio/MIDI tracks. ones are other types. */
425 if (!rtv->hidden()) {
427 if (!rtv->is_track()) {
428 /* not an audio nor MIDI track */
429 sum.tracks = sum.tracks |= (0x01 << rtv->order());
432 sum.height_list[rtv->order()] = (*i)->current_height();
435 if ((children_list = rtv->get_child_list()).size() > 0) {
436 for (TimeAxisView::Children::iterator j = children_list.begin(); j != children_list.end(); ++j) {
437 sum.tracks = sum.tracks |= (0x01 << (rtv->order() + children));
438 sum.height_list[rtv->order() + children] = (*j)->current_height();
449 RegionMotionDrag::compute_y_delta (
450 TimeAxisView const * last_pointer_view, TimeAxisView* current_pointer_view,
451 int32_t last_pointer_layer, int32_t current_pointer_layer,
452 TimeAxisViewSummary const & tavs,
453 int32_t* pointer_order_span, int32_t* pointer_layer_span,
454 int32_t* canvas_pointer_order_span
458 *pointer_order_span = 0;
459 *pointer_layer_span = 0;
463 bool clamp_y_axis = false;
465 /* the change in track order between this callback and the last */
466 *pointer_order_span = last_pointer_view->order() - current_pointer_view->order();
467 /* the change in layer between this callback and the last;
468 only meaningful if pointer_order_span == 0 (ie we've not moved tracks) */
469 *pointer_layer_span = last_pointer_layer - current_pointer_layer;
471 if (*pointer_order_span != 0) {
473 /* find the actual pointer span, in terms of the number of visible tracks;
474 to do this, we reduce |pointer_order_span| by the number of hidden tracks
477 *canvas_pointer_order_span = *pointer_order_span;
478 if (last_pointer_view->order() >= current_pointer_view->order()) {
479 for (int32_t y = current_pointer_view->order(); y < last_pointer_view->order(); y++) {
480 if (tavs.height_list[y] == 0) {
481 *canvas_pointer_order_span--;
485 for (int32_t y = last_pointer_view->order(); y <= current_pointer_view->order(); y++) {
486 if (tavs.height_list[y] == 0) {
487 *canvas_pointer_order_span++;
492 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
494 RegionView* rv = (*i);
496 if (rv->region()->locked()) {
500 double ix1, ix2, iy1, iy2;
501 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
502 rv->get_canvas_frame()->i2w (ix1, iy1);
503 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
505 /* get the new trackview for this particular region */
506 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (iy1);
508 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tvp.first);
510 /* XXX: not sure that we should be passing canvas_pointer_order_span in here,
511 as surely this is a per-region thing... */
513 clamp_y_axis = y_movement_disallowed (
514 rtv->order(), last_pointer_view->order(), *canvas_pointer_order_span, tavs
522 } else if (_dest_trackview == current_pointer_view) {
524 if (current_pointer_layer == last_pointer_layer) {
525 /* No movement; clamp */
531 _dest_trackview = current_pointer_view;
532 _dest_layer = current_pointer_layer;
540 RegionMotionDrag::compute_x_delta (GdkEvent const * event, nframes64_t* pending_region_position)
542 /* compute the amount of pointer motion in frames, and where
543 the region would be if we moved it by that much.
545 *pending_region_position = adjusted_current_frame (event);
547 nframes64_t sync_frame;
548 nframes64_t sync_offset;
551 sync_offset = _primary->region()->sync_offset (sync_dir);
553 /* we don't handle a sync point that lies before zero.
555 if (sync_dir >= 0 || (sync_dir < 0 && *pending_region_position >= sync_offset)) {
557 sync_frame = *pending_region_position + (sync_dir*sync_offset);
559 _editor->snap_to_with_modifier (sync_frame, event);
561 *pending_region_position = _primary->region()->adjust_to_sync (sync_frame);
564 *pending_region_position = _last_frame_position;
567 if (*pending_region_position > max_frames - _primary->region()->length()) {
568 *pending_region_position = _last_frame_position;
573 if ((*pending_region_position != _last_frame_position) && x_move_allowed ()) {
575 /* now compute the canvas unit distance we need to move the regionview
576 to make it appear at the new location.
579 x_delta = (static_cast<double> (*pending_region_position) - _last_frame_position) / _editor->frames_per_unit;
581 if (*pending_region_position <= _last_frame_position) {
583 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
585 RegionView* rv = (*i);
587 // If any regionview is at zero, we need to know so we can stop further leftward motion.
589 double ix1, ix2, iy1, iy2;
590 rv->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
591 rv->get_canvas_frame()->i2w (ix1, iy1);
593 if (-x_delta > ix1 + _editor->horizontal_adjustment.get_value()) {
595 *pending_region_position = _last_frame_position;
602 _last_frame_position = *pending_region_position;
609 RegionMotionDrag::motion (GdkEvent* event, bool first_move)
613 TimeAxisViewSummary tavs = get_time_axis_view_summary ();
615 vector<int32_t>::iterator j;
617 /* *pointer* variables reflect things about the pointer; as we may be moving
618 multiple regions, much detail must be computed per-region */
620 /* current_pointer_view will become the TimeAxisView that we're currently pointing at, and
621 current_pointer_layer the current layer on that TimeAxisView; in this code layer numbers
622 are with respect to how the view's layers are displayed; if we are in Overlaid mode, layer
623 is always 0 regardless of what the region's "real" layer is */
624 RouteTimeAxisView* current_pointer_view;
625 layer_t current_pointer_layer;
626 if (!check_possible (¤t_pointer_view, ¤t_pointer_layer)) {
630 /* TimeAxisView that we were pointing at last time we entered this method */
631 TimeAxisView const * const last_pointer_view = _dest_trackview;
632 /* the order of the track that we were pointing at last time we entered this method */
633 int32_t const last_pointer_order = last_pointer_view->order ();
634 /* the layer that we were pointing at last time we entered this method */
635 layer_t const last_pointer_layer = _dest_layer;
637 int32_t pointer_order_span;
638 int32_t pointer_layer_span;
639 int32_t canvas_pointer_order_span;
641 bool const clamp_y_axis = compute_y_delta (
642 last_pointer_view, current_pointer_view,
643 last_pointer_layer, current_pointer_layer, tavs,
644 &pointer_order_span, &pointer_layer_span,
645 &canvas_pointer_order_span
648 nframes64_t pending_region_position;
649 double const x_delta = compute_x_delta (event, &pending_region_position);
651 /*************************************************************
653 ************************************************************/
655 if (x_delta == 0 && pointer_order_span == 0 && pointer_layer_span == 0 && !first_move) {
656 /* haven't reached next snap point, and we're not switching
657 trackviews nor layers. nothing to do.
662 /*************************************************************
664 ************************************************************/
666 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
668 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
670 RegionView* rv = (*i);
672 if (rv->region()->locked()) {
676 /* here we are calculating the y distance from the
677 top of the first track view to the top of the region
678 area of the track view that we're working on */
680 /* this x value is just a dummy value so that we have something
685 /* distance from the top of this track view to the region area
686 of our track view is always 1 */
690 /* convert to world coordinates, ie distance from the top of
693 rv->get_canvas_frame()->i2w (ix1, iy1);
695 /* compensate for the ruler section and the vertical scrollbar position */
696 iy1 += _editor->get_trackview_group_vertical_offset ();
700 // hide any dependent views
702 rv->get_time_axis_view().hide_dependent_views (*rv);
705 reparent to a non scrolling group so that we can keep the
706 region selection above all time axis views.
707 reparenting means we have to move the rv as the two
708 parent groups have different coordinates.
711 rv->get_canvas_group()->property_y() = iy1 - 1;
712 rv->get_canvas_group()->reparent(*(_editor->_region_motion_group));
714 rv->fake_set_opaque (true);
717 /* current view for this particular region */
718 pair<TimeAxisView*, int> pos = _editor->trackview_by_y_position (iy1);
719 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
721 if (pointer_order_span != 0 && !clamp_y_axis) {
723 /* INTER-TRACK MOVEMENT */
725 /* move through the height list to the track that the region is currently on */
726 vector<int32_t>::iterator j = tavs.height_list.begin ();
728 while (j != tavs.height_list.end () && x != rtv->order ()) {
734 int32_t temp_pointer_order_span = canvas_pointer_order_span;
736 if (j != tavs.height_list.end ()) {
738 /* Account for layers in the original and
739 destination tracks. If we're moving around in layers we assume
740 that only one track is involved, so it's ok to use *pointer*
743 StreamView* lv = last_pointer_view->view ();
746 /* move to the top of the last trackview */
747 if (lv->layer_display () == Stacked) {
748 y_delta -= (lv->layers() - last_pointer_layer - 1) * lv->child_height ();
751 StreamView* cv = current_pointer_view->view ();
754 /* move to the right layer on the current trackview */
755 if (cv->layer_display () == Stacked) {
756 y_delta += (cv->layers() - current_pointer_layer - 1) * cv->child_height ();
759 /* And for being on a non-topmost layer on the new
762 while (temp_pointer_order_span > 0) {
763 /* we're moving up canvas-wise,
764 so we need to find the next track height
766 if (j != tavs.height_list.begin()) {
770 if (x != last_pointer_order) {
772 ++temp_pointer_order_span;
777 temp_pointer_order_span--;
780 while (temp_pointer_order_span < 0) {
784 if (x != last_pointer_order) {
786 --temp_pointer_order_span;
790 if (j != tavs.height_list.end()) {
794 temp_pointer_order_span++;
798 /* find out where we'll be when we move and set height accordingly */
800 pair<TimeAxisView*, int> const pos = _editor->trackview_by_y_position (iy1 + y_delta);
801 RouteTimeAxisView const * temp_rtv = dynamic_cast<RouteTimeAxisView*> (pos.first);
802 rv->set_height (temp_rtv->view()->child_height());
804 /* if you un-comment the following, the region colours will follow
805 the track colours whilst dragging; personally
806 i think this can confuse things, but never mind.
809 //const GdkColor& col (temp_rtv->view->get_region_color());
810 //rv->set_color (const_cast<GdkColor&>(col));
814 if (pointer_order_span == 0 && pointer_layer_span != 0 && !clamp_y_axis) {
816 /* INTER-LAYER MOVEMENT in the same track */
817 y_delta = rtv->view()->child_height () * pointer_layer_span;
822 _editor->mouse_brush_insert_region (rv, pending_region_position);
824 rv->move (x_delta, y_delta);
827 } /* foreach region */
829 _total_x_delta += x_delta;
832 _editor->cursor_group->raise_to_top();
835 if (x_delta != 0 && !_brushing) {
836 _editor->show_verbose_time_cursor (_last_frame_position, 10);
841 RegionMoveDrag::motion (GdkEvent* event, bool first_move)
843 if (_copy && first_move) {
844 copy_regions (event);
847 RegionMotionDrag::motion (event, first_move);
851 RegionMoveDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
853 vector<RegionView*> copies;
854 boost::shared_ptr<Diskstream> ds;
855 boost::shared_ptr<Playlist> from_playlist;
856 RegionSelection new_views;
857 typedef set<boost::shared_ptr<Playlist> > PlaylistSet;
858 PlaylistSet modified_playlists;
859 PlaylistSet frozen_playlists;
860 list <sigc::connection> modified_playlist_connections;
861 pair<PlaylistSet::iterator,bool> insert_result, frozen_insert_result;
862 nframes64_t drag_delta;
863 bool changed_tracks, changed_position;
864 map<RegionView*, pair<RouteTimeAxisView*, int> > final;
865 RouteTimeAxisView* source_tv;
867 if (!movement_occurred) {
873 /* all changes were made during motion event handlers */
876 for (list<RegionView*>::iterator i = _views.begin(); i != _views.end(); ++i) {
877 copies.push_back (*i);
884 /* reverse this here so that we have the correct logic to finalize
888 if (Config->get_edit_mode() == Lock) {
889 _x_constrained = !_x_constrained;
893 if (_x_constrained) {
894 _editor->begin_reversible_command (_("fixed time region copy"));
896 _editor->begin_reversible_command (_("region copy"));
899 if (_x_constrained) {
900 _editor->begin_reversible_command (_("fixed time region drag"));
902 _editor->begin_reversible_command (_("region drag"));
906 changed_position = (_last_frame_position != (nframes64_t) (_primary->region()->position()));
907 changed_tracks = (_dest_trackview != &_primary->get_time_axis_view());
909 drag_delta = _primary->region()->position() - _last_frame_position;
911 _editor->update_canvas_now ();
913 /* make a list of where each region ended up */
914 final = find_time_axis_views_and_layers ();
916 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ) {
918 RegionView* rv = (*i);
919 RouteTimeAxisView* dest_rtv = final[*i].first;
920 layer_t dest_layer = final[*i].second;
924 if (rv->region()->locked()) {
929 if (changed_position && !_x_constrained) {
930 where = rv->region()->position() - drag_delta;
932 where = rv->region()->position();
935 boost::shared_ptr<Region> new_region;
938 /* we already made a copy */
939 new_region = rv->region();
941 /* undo the previous hide_dependent_views so that xfades don't
942 disappear on copying regions
945 //rv->get_time_axis_view().reveal_dependent_views (*rv);
947 } else if (changed_tracks && dest_rtv->playlist()) {
948 new_region = RegionFactory::create (rv->region());
951 if (changed_tracks || _copy) {
953 boost::shared_ptr<Playlist> to_playlist = dest_rtv->playlist();
960 _editor->latest_regionviews.clear ();
962 sigc::connection c = dest_rtv->view()->RegionViewAdded.connect (sigc::mem_fun(*_editor, &Editor::collect_new_region_view));
964 insert_result = modified_playlists.insert (to_playlist);
966 if (insert_result.second) {
967 _editor->session()->add_command (new MementoCommand<Playlist>(*to_playlist, &to_playlist->get_state(), 0));
970 to_playlist->add_region (new_region, where);
971 if (dest_rtv->view()->layer_display() == Stacked) {
972 new_region->set_layer (dest_layer);
973 new_region->set_pending_explicit_relayer (true);
978 if (!_editor->latest_regionviews.empty()) {
979 // XXX why just the first one ? we only expect one
980 // commented out in nick_m's canvas reworking. is that intended?
981 //dest_atv->reveal_dependent_views (*latest_regionviews.front());
982 new_views.push_back (_editor->latest_regionviews.front());
987 motion on the same track. plonk the previously reparented region
988 back to its original canvas group (its streamview).
989 No need to do anything for copies as they are fake regions which will be deleted.
992 rv->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
993 rv->get_canvas_group()->property_y() = 0;
994 rv->get_time_axis_view().reveal_dependent_views (*rv);
996 /* just change the model */
998 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1000 if (dest_rtv->view()->layer_display() == Stacked) {
1001 rv->region()->set_layer (dest_layer);
1002 rv->region()->set_pending_explicit_relayer (true);
1005 insert_result = modified_playlists.insert (playlist);
1007 if (insert_result.second) {
1008 _editor->session()->add_command (new MementoCommand<Playlist>(*playlist, &playlist->get_state(), 0));
1010 /* freeze to avoid lots of relayering in the case of a multi-region drag */
1011 frozen_insert_result = frozen_playlists.insert(playlist);
1013 if (frozen_insert_result.second) {
1017 rv->region()->set_position (where, (void*) this);
1020 if (changed_tracks && !_copy) {
1022 /* get the playlist where this drag started. we can't use rv->region()->playlist()
1023 because we may have copied the region and it has not been attached to a playlist.
1026 source_tv = dynamic_cast<RouteTimeAxisView*> (&rv->get_time_axis_view());
1027 ds = source_tv->get_diskstream();
1028 from_playlist = ds->playlist();
1032 assert (from_playlist);
1034 /* moved to a different audio track, without copying */
1036 /* the region that used to be in the old playlist is not
1037 moved to the new one - we use a copy of it. as a result,
1038 any existing editor for the region should no longer be
1042 rv->hide_region_editor();
1043 rv->fake_set_opaque (false);
1045 /* remove the region from the old playlist */
1047 insert_result = modified_playlists.insert (from_playlist);
1049 if (insert_result.second) {
1050 _editor->session()->add_command (new MementoCommand<Playlist>(*from_playlist, &from_playlist->get_state(), 0));
1053 from_playlist->remove_region (rv->region());
1055 /* OK, this is where it gets tricky. If the playlist was being used by >1 tracks, and the region
1056 was selected in all of them, then removing it from a playlist will have removed all
1057 trace of it from the selection (i.e. there were N regions selected, we removed 1,
1058 but since its the same playlist for N tracks, all N tracks updated themselves, removed the
1059 corresponding regionview, and the selection is now empty).
1061 this could have invalidated any and all iterators into the region selection.
1063 the heuristic we use here is: if the region selection is empty, break out of the loop
1064 here. if the region selection is not empty, then restart the loop because we know that
1065 we must have removed at least the region(view) we've just been working on as well as any
1066 that we processed on previous iterations.
1068 EXCEPT .... if we are doing a copy drag, then the selection hasn't been modified and
1069 we can just iterate.
1072 if (_views.empty()) {
1083 copies.push_back (rv);
1087 if we've created new regions either by copying or moving
1088 to a new track, we want to replace the old selection with the new ones
1090 if (new_views.size() > 0) {
1091 _editor->selection->set (new_views);
1094 for (set<boost::shared_ptr<Playlist> >::iterator p = frozen_playlists.begin(); p != frozen_playlists.end(); ++p) {
1099 for (set<boost::shared_ptr<Playlist> >::iterator p = modified_playlists.begin(); p != modified_playlists.end(); ++p) {
1100 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p), 0, &(*p)->get_state()));
1103 _editor->commit_reversible_command ();
1105 for (vector<RegionView*>::iterator x = copies.begin(); x != copies.end(); ++x) {
1111 RegionMoveDrag::aborted ()
1115 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1122 RegionMotionDrag::aborted ();
1127 RegionMotionDrag::aborted ()
1129 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1130 TimeAxisView* tv = &(*i)->get_time_axis_view ();
1131 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1133 (*i)->get_canvas_group()->reparent (*rtv->view()->canvas_item());
1134 (*i)->get_canvas_group()->property_y() = 0;
1135 (*i)->get_time_axis_view().reveal_dependent_views (**i);
1136 (*i)->fake_set_opaque (false);
1137 (*i)->move (-_total_x_delta, 0);
1138 (*i)->set_height (rtv->view()->child_height ());
1141 _editor->update_canvas_now ();
1146 RegionMotionDrag::x_move_allowed () const
1148 if (Config->get_edit_mode() == Lock) {
1149 /* in locked edit mode, reverse the usual meaning of _x_constrained */
1150 return _x_constrained;
1153 return !_x_constrained;
1157 RegionMotionDrag::copy_regions (GdkEvent* event)
1159 /* duplicate the regionview(s) and region(s) */
1161 list<RegionView*> new_regionviews;
1163 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1165 RegionView* rv = (*i);
1166 AudioRegionView* arv = dynamic_cast<AudioRegionView*>(rv);
1167 MidiRegionView* mrv = dynamic_cast<MidiRegionView*>(rv);
1169 const boost::shared_ptr<const Region> original = rv->region();
1170 boost::shared_ptr<Region> region_copy = RegionFactory::create (original);
1174 boost::shared_ptr<AudioRegion> audioregion_copy
1175 = boost::dynamic_pointer_cast<AudioRegion>(region_copy);
1176 nrv = new AudioRegionView (*arv, audioregion_copy);
1178 boost::shared_ptr<MidiRegion> midiregion_copy
1179 = boost::dynamic_pointer_cast<MidiRegion>(region_copy);
1180 nrv = new MidiRegionView (*mrv, midiregion_copy);
1185 nrv->get_canvas_group()->show ();
1186 new_regionviews.push_back (nrv);
1188 /* swap _primary to the copy */
1190 if (rv == _primary) {
1194 /* ..and deselect the one we copied */
1196 rv->set_selected (false);
1199 if (new_regionviews.empty()) {
1203 /* reflect the fact that we are dragging the copies */
1205 _views = new_regionviews;
1207 swap_grab (new_regionviews.front()->get_canvas_group (), 0, event ? event->motion.time : 0);
1210 sync the canvas to what we think is its current state
1211 without it, the canvas seems to
1212 "forget" to update properly after the upcoming reparent()
1213 ..only if the mouse is in rapid motion at the time of the grab.
1214 something to do with regionview creation taking so long?
1216 _editor->update_canvas_now();
1220 RegionMotionDrag::check_possible (RouteTimeAxisView** tv, layer_t* layer)
1222 /* Which trackview is this ? */
1224 pair<TimeAxisView*, int> const tvp = _editor->trackview_by_y_position (_drags->current_pointer_y ());
1225 (*tv) = dynamic_cast<RouteTimeAxisView*> (tvp.first);
1226 (*layer) = tvp.second;
1228 if (*tv && (*tv)->layer_display() == Overlaid) {
1232 /* The region motion is only processed if the pointer is over
1236 if (!(*tv) || !(*tv)->is_track()) {
1237 /* To make sure we hide the verbose canvas cursor when the mouse is
1238 not held over and audiotrack.
1240 _editor->hide_verbose_canvas_cursor ();
1247 /** @param new_order New track order.
1248 * @param old_order Old track order.
1249 * @param visible_y_low Lowest visible order.
1250 * @return true if y movement should not happen, otherwise false.
1253 RegionMotionDrag::y_movement_disallowed (int new_order, int old_order, int y_span, TimeAxisViewSummary const & tavs) const
1255 if (new_order != old_order) {
1257 /* this isn't the pointer track */
1261 /* moving up the canvas */
1262 if ( (new_order - y_span) >= tavs.visible_y_low) {
1266 /* work out where we'll end up with this y span, taking hidden TimeAxisViews into account */
1267 int32_t visible_tracks = 0;
1268 while (visible_tracks < y_span ) {
1270 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1271 /* passing through a hidden track */
1276 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1277 /* moving to a non-track; disallow */
1283 /* moving beyond the lowest visible track; disallow */
1287 } else if (y_span < 0) {
1289 /* moving down the canvas */
1290 if ((new_order - y_span) <= tavs.visible_y_high) {
1292 int32_t visible_tracks = 0;
1294 while (visible_tracks > y_span ) {
1297 while (tavs.height_list[new_order - (visible_tracks - n)] == 0) {
1298 /* passing through a hidden track */
1303 if (tavs.tracks[new_order - (y_span - n)] != 0x00) {
1304 /* moving to a non-track; disallow */
1311 /* moving beyond the highest visible track; disallow */
1318 /* this is the pointer's track */
1320 if ((new_order - y_span) > tavs.visible_y_high) {
1321 /* we will overflow */
1323 } else if ((new_order - y_span) < tavs.visible_y_low) {
1324 /* we will overflow */
1333 RegionMoveDrag::RegionMoveDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v, bool b, bool c)
1334 : RegionMotionDrag (e, i, p, v, b),
1337 TimeAxisView* const tv = &_primary->get_time_axis_view ();
1339 _dest_trackview = tv;
1340 if (tv->layer_display() == Overlaid) {
1343 _dest_layer = _primary->region()->layer ();
1347 RouteTimeAxisView* rtv = dynamic_cast<RouteTimeAxisView*> (tv);
1348 if (rtv && rtv->is_track()) {
1349 speed = rtv->get_diskstream()->speed ();
1352 _last_frame_position = static_cast<nframes64_t> (_primary->region()->position() / speed);
1356 RegionMoveDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
1358 RegionMotionDrag::start_grab (event, c);
1360 _pointer_frame_offset = grab_frame() - _last_frame_position;
1363 RegionInsertDrag::RegionInsertDrag (Editor* e, boost::shared_ptr<Region> r, RouteTimeAxisView* v, nframes64_t pos)
1364 : RegionMotionDrag (e, 0, 0, list<RegionView*> (), false)
1366 assert ((boost::dynamic_pointer_cast<AudioRegion> (r) && dynamic_cast<AudioTimeAxisView*> (v)) ||
1367 (boost::dynamic_pointer_cast<MidiRegion> (r) && dynamic_cast<MidiTimeAxisView*> (v)));
1369 _primary = v->view()->create_region_view (r, false, false);
1371 _primary->get_canvas_group()->show ();
1372 _primary->set_position (pos, 0);
1373 _views.push_back (_primary);
1375 _last_frame_position = pos;
1377 _item = _primary->get_canvas_group ();
1378 _dest_trackview = v;
1379 _dest_layer = _primary->region()->layer ();
1382 map<RegionView*, pair<RouteTimeAxisView*, int> >
1383 RegionMotionDrag::find_time_axis_views_and_layers ()
1385 map<RegionView*, pair<RouteTimeAxisView*, int> > tav;
1387 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1389 double ix1, ix2, iy1, iy2;
1390 (*i)->get_canvas_frame()->get_bounds (ix1, iy1, ix2, iy2);
1391 (*i)->get_canvas_frame()->i2w (ix1, iy1);
1392 iy1 += _editor->vertical_adjustment.get_value() - _editor->canvas_timebars_vsize;
1394 pair<TimeAxisView*, int> tv = _editor->trackview_by_y_position (iy1);
1395 tav[*i] = make_pair (dynamic_cast<RouteTimeAxisView*> (tv.first), tv.second);
1403 RegionInsertDrag::finished (GdkEvent* /*event*/, bool /*movement_occurred*/)
1405 _editor->update_canvas_now ();
1407 map<RegionView*, pair<RouteTimeAxisView*, int> > final = find_time_axis_views_and_layers ();
1409 RouteTimeAxisView* dest_rtv = final[_primary].first;
1411 _primary->get_canvas_group()->reparent (*dest_rtv->view()->canvas_item());
1412 _primary->get_canvas_group()->property_y() = 0;
1414 boost::shared_ptr<Playlist> playlist = dest_rtv->playlist();
1416 _editor->begin_reversible_command (_("insert region"));
1417 XMLNode& before = playlist->get_state ();
1418 playlist->add_region (_primary->region (), _last_frame_position);
1419 _editor->session()->add_command (new MementoCommand<Playlist> (*playlist, &before, &playlist->get_state()));
1420 _editor->commit_reversible_command ();
1428 RegionInsertDrag::aborted ()
1433 RegionSpliceDrag::RegionSpliceDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1434 : RegionMoveDrag (e, i, p, v, false, false)
1439 struct RegionSelectionByPosition {
1440 bool operator() (RegionView*a, RegionView* b) {
1441 return a->region()->position () < b->region()->position();
1446 RegionSpliceDrag::motion (GdkEvent* event, bool)
1448 RouteTimeAxisView* tv;
1451 if (!check_possible (&tv, &layer)) {
1457 if ((_drags->current_pointer_x() - last_pointer_x()) > 0) {
1463 RegionSelection copy (_editor->selection->regions);
1465 RegionSelectionByPosition cmp;
1468 nframes64_t const pf = adjusted_current_frame (event);
1470 for (RegionSelection::iterator i = copy.begin(); i != copy.end(); ++i) {
1472 RouteTimeAxisView* atv = dynamic_cast<RouteTimeAxisView*> (&(*i)->get_time_axis_view());
1478 boost::shared_ptr<Playlist> playlist;
1480 if ((playlist = atv->playlist()) == 0) {
1484 if (!playlist->region_is_shuffle_constrained ((*i)->region())) {
1489 if (pf < (*i)->region()->last_frame() + 1) {
1493 if (pf > (*i)->region()->first_frame()) {
1499 playlist->shuffle ((*i)->region(), dir);
1504 RegionSpliceDrag::finished (GdkEvent* /*event*/, bool)
1510 RegionSpliceDrag::aborted ()
1515 RegionCreateDrag::RegionCreateDrag (Editor* e, ArdourCanvas::Item* i, TimeAxisView* v)
1523 RegionCreateDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1525 _dest_trackview = _view;
1527 Drag::start_grab (event);
1532 RegionCreateDrag::motion (GdkEvent* /*event*/, bool first_move)
1535 // TODO: create region-create-drag region view here
1538 // TODO: resize region-create-drag region view here
1542 RegionCreateDrag::finished (GdkEvent* event, bool movement_occurred)
1544 MidiTimeAxisView* mtv = dynamic_cast<MidiTimeAxisView*> (_dest_trackview);
1550 if (!movement_occurred) {
1551 mtv->add_region (grab_frame ());
1553 motion (event, false);
1554 // TODO: create region-create-drag region here
1559 RegionCreateDrag::aborted ()
1564 NoteResizeDrag::NoteResizeDrag (Editor* e, ArdourCanvas::Item* i)
1572 NoteResizeDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1575 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
1577 Drag::start_grab (event);
1579 region = &cnote->region_view();
1581 double region_start = region->get_position_pixels();
1582 double middle_point = region_start + cnote->x1() + (cnote->x2() - cnote->x1()) / 2.0L;
1584 if (grab_x() <= middle_point) {
1585 cursor = Gdk::Cursor(Gdk::LEFT_SIDE);
1588 cursor = Gdk::Cursor(Gdk::RIGHT_SIDE);
1592 _item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK, cursor, event->motion.time);
1594 if (event->motion.state & Keyboard::PrimaryModifier) {
1600 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1602 if (ms.size() > 1) {
1603 /* has to be relative, may make no sense otherwise */
1607 region->note_selected (cnote, true);
1609 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ) {
1610 MidiRegionSelection::iterator next;
1613 (*r)->begin_resizing (at_front);
1619 NoteResizeDrag::motion (GdkEvent* /*event*/, bool /*first_move*/)
1621 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1622 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1623 (*r)->update_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1628 NoteResizeDrag::finished (GdkEvent*, bool /*movement_occurred*/)
1630 MidiRegionSelection& ms (_editor->get_selection().midi_regions);
1631 for (MidiRegionSelection::iterator r = ms.begin(); r != ms.end(); ++r) {
1632 (*r)->commit_resizing (at_front, _drags->current_pointer_x() - grab_x(), relative);
1637 NoteResizeDrag::aborted ()
1643 RegionGainDrag::motion (GdkEvent* /*event*/, bool)
1649 RegionGainDrag::finished (GdkEvent *, bool)
1655 RegionGainDrag::aborted ()
1660 TrimDrag::TrimDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
1661 : RegionDrag (e, i, p, v)
1662 , _have_transaction (false)
1668 TrimDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
1671 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1672 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1674 if (tv && tv->is_track()) {
1675 speed = tv->get_diskstream()->speed();
1678 nframes64_t region_start = (nframes64_t) (_primary->region()->position() / speed);
1679 nframes64_t region_end = (nframes64_t) (_primary->region()->last_frame() / speed);
1680 nframes64_t region_length = (nframes64_t) (_primary->region()->length() / speed);
1682 Drag::start_grab (event, _editor->trimmer_cursor);
1684 nframes64_t const pf = adjusted_current_frame (event);
1686 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1687 _operation = ContentsTrim;
1689 /* These will get overridden for a point trim.*/
1690 if (pf < (region_start + region_length/2)) {
1691 /* closer to start */
1692 _operation = StartTrim;
1693 } else if (pf > (region_end - region_length/2)) {
1695 _operation = EndTrim;
1699 switch (_operation) {
1701 _editor->show_verbose_time_cursor (region_start, 10);
1704 _editor->show_verbose_time_cursor (region_end, 10);
1707 _editor->show_verbose_time_cursor (pf, 10);
1713 TrimDrag::motion (GdkEvent* event, bool first_move)
1715 RegionView* rv = _primary;
1716 nframes64_t frame_delta = 0;
1718 bool left_direction;
1719 bool obey_snap = event ? !Keyboard::modifier_state_contains (event->button.state, Keyboard::snap_modifier()) : false;
1721 /* snap modifier works differently here..
1722 its current state has to be passed to the
1723 various trim functions in order to work properly
1727 TimeAxisView* tvp = &_primary->get_time_axis_view ();
1728 RouteTimeAxisView* tv = dynamic_cast<RouteTimeAxisView*>(tvp);
1729 pair<set<boost::shared_ptr<Playlist> >::iterator,bool> insert_result;
1731 if (tv && tv->is_track()) {
1732 speed = tv->get_diskstream()->speed();
1735 nframes64_t const pf = adjusted_current_frame (event);
1737 if (last_pointer_frame() > pf) {
1738 left_direction = true;
1740 left_direction = false;
1747 switch (_operation) {
1749 trim_type = "Region start trim";
1752 trim_type = "Region end trim";
1755 trim_type = "Region content trim";
1759 _editor->begin_reversible_command (trim_type);
1760 _have_transaction = true;
1762 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1763 (*i)->fake_set_opaque(false);
1764 (*i)->region()->freeze ();
1766 AudioRegionView* const arv = dynamic_cast<AudioRegionView*>(*i);
1769 arv->temporarily_hide_envelope ();
1772 boost::shared_ptr<Playlist> pl = (*i)->region()->playlist();
1773 insert_result = _editor->motion_frozen_playlists.insert (pl);
1775 if (insert_result.second) {
1776 _editor->session()->add_command(new MementoCommand<Playlist>(*pl, &pl->get_state(), 0));
1782 if (left_direction) {
1783 frame_delta = (last_pointer_frame() - pf);
1785 frame_delta = (pf - last_pointer_frame());
1788 bool non_overlap_trim = false;
1790 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
1791 non_overlap_trim = true;
1794 switch (_operation) {
1796 if ((left_direction == false) && (pf <= rv->region()->first_frame()/speed)) {
1800 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1801 _editor->single_start_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1807 if ((left_direction == true) && (pf > (nframes64_t) (rv->region()->last_frame()/speed))) {
1811 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1812 _editor->single_end_trim (**i, frame_delta, left_direction, obey_snap, non_overlap_trim);
1819 bool swap_direction = false;
1821 if (event && Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
1822 swap_direction = true;
1825 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1826 _editor->single_contents_trim (**i, frame_delta, left_direction, swap_direction, obey_snap);
1832 switch (_operation) {
1834 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->position()/speed), 10);
1837 _editor->show_verbose_time_cursor((nframes64_t) (rv->region()->last_frame()/speed), 10);
1840 _editor->show_verbose_time_cursor (pf, 10);
1847 TrimDrag::finished (GdkEvent* event, bool movement_occurred)
1849 if (movement_occurred) {
1850 motion (event, false);
1852 if (!_editor->selection->selected (_primary)) {
1853 _editor->thaw_region_after_trim (*_primary);
1856 for (list<RegionView*>::const_iterator i = _views.begin(); i != _views.end(); ++i) {
1857 _editor->thaw_region_after_trim (**i);
1858 (*i)->fake_set_opaque (true);
1861 for (set<boost::shared_ptr<Playlist> >::iterator p = _editor->motion_frozen_playlists.begin(); p != _editor->motion_frozen_playlists.end(); ++p) {
1863 if (_have_transaction) {
1864 _editor->session()->add_command (new MementoCommand<Playlist>(*(*p).get(), 0, &(*p)->get_state()));
1868 _editor->motion_frozen_playlists.clear ();
1870 if (_have_transaction) {
1871 _editor->commit_reversible_command();
1875 /* no mouse movement */
1876 _editor->point_trim (event, adjusted_current_frame (event));
1881 TrimDrag::aborted ()
1883 /* Our motion method is changing model state, so use the Undo system
1884 to cancel. Perhaps not ideal, as this will leave an Undo point
1885 behind which may be slightly odd from the user's point of view.
1890 if (_have_transaction) {
1895 MeterMarkerDrag::MeterMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1899 _marker = reinterpret_cast<MeterMarker*> (_item->get_data ("marker"));
1904 MeterMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1907 // create a dummy marker for visual representation of moving the copy.
1908 // The actual copying is not done before we reach the finish callback.
1910 snprintf (name, sizeof(name), "%g/%g", _marker->meter().beats_per_bar(), _marker->meter().note_divisor ());
1911 MeterMarker* new_marker = new MeterMarker(*_editor, *_editor->meter_group, ARDOUR_UI::config()->canvasvar_MeterMarker.get(), name,
1912 *new MeterSection (_marker->meter()));
1914 _item = &new_marker->the_item ();
1915 _marker = new_marker;
1919 MetricSection& section (_marker->meter());
1921 if (!section.movable()) {
1927 Drag::start_grab (event, cursor);
1929 _pointer_frame_offset = grab_frame() - _marker->meter().frame();
1931 _editor->show_verbose_time_cursor (adjusted_current_frame(event), 10);
1935 MeterMarkerDrag::motion (GdkEvent* event, bool)
1937 nframes64_t const pf = adjusted_current_frame (event);
1939 _marker->set_position (pf);
1941 _editor->show_verbose_time_cursor (pf, 10);
1945 MeterMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
1947 if (!movement_occurred) {
1951 motion (event, false);
1955 TempoMap& map (_editor->session()->tempo_map());
1956 map.bbt_time (last_pointer_frame(), when);
1958 if (_copy == true) {
1959 _editor->begin_reversible_command (_("copy meter mark"));
1960 XMLNode &before = map.get_state();
1961 map.add_meter (_marker->meter(), when);
1962 XMLNode &after = map.get_state();
1963 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1964 _editor->commit_reversible_command ();
1966 // delete the dummy marker we used for visual representation of copying.
1967 // a new visual marker will show up automatically.
1970 _editor->begin_reversible_command (_("move meter mark"));
1971 XMLNode &before = map.get_state();
1972 map.move_meter (_marker->meter(), when);
1973 XMLNode &after = map.get_state();
1974 _editor->session()->add_command(new MementoCommand<TempoMap>(map, &before, &after));
1975 _editor->commit_reversible_command ();
1980 MeterMarkerDrag::aborted ()
1982 _marker->set_position (_marker->meter().frame ());
1985 TempoMarkerDrag::TempoMarkerDrag (Editor* e, ArdourCanvas::Item* i, bool c)
1989 _marker = reinterpret_cast<TempoMarker*> (_item->get_data ("marker"));
1994 TempoMarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
1999 // create a dummy marker for visual representation of moving the copy.
2000 // The actual copying is not done before we reach the finish callback.
2002 snprintf (name, sizeof (name), "%.2f", _marker->tempo().beats_per_minute());
2003 TempoMarker* new_marker = new TempoMarker(*_editor, *_editor->tempo_group, ARDOUR_UI::config()->canvasvar_TempoMarker.get(), name,
2004 *new TempoSection (_marker->tempo()));
2006 _item = &new_marker->the_item ();
2007 _marker = new_marker;
2011 MetricSection& section (_marker->tempo());
2013 if (!section.movable()) {
2018 Drag::start_grab (event, cursor);
2020 _pointer_frame_offset = grab_frame() - _marker->tempo().frame();
2021 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2025 TempoMarkerDrag::motion (GdkEvent* event, bool)
2027 nframes64_t const pf = adjusted_current_frame (event);
2028 _marker->set_position (pf);
2029 _editor->show_verbose_time_cursor (pf, 10);
2033 TempoMarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2035 if (!movement_occurred) {
2039 motion (event, false);
2043 TempoMap& map (_editor->session()->tempo_map());
2044 map.bbt_time (last_pointer_frame(), when);
2046 if (_copy == true) {
2047 _editor->begin_reversible_command (_("copy tempo mark"));
2048 XMLNode &before = map.get_state();
2049 map.add_tempo (_marker->tempo(), when);
2050 XMLNode &after = map.get_state();
2051 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2052 _editor->commit_reversible_command ();
2054 // delete the dummy marker we used for visual representation of copying.
2055 // a new visual marker will show up automatically.
2058 _editor->begin_reversible_command (_("move tempo mark"));
2059 XMLNode &before = map.get_state();
2060 map.move_tempo (_marker->tempo(), when);
2061 XMLNode &after = map.get_state();
2062 _editor->session()->add_command (new MementoCommand<TempoMap>(map, &before, &after));
2063 _editor->commit_reversible_command ();
2068 TempoMarkerDrag::aborted ()
2070 _marker->set_position (_marker->tempo().frame());
2073 CursorDrag::CursorDrag (Editor* e, ArdourCanvas::Item* i, bool s)
2077 _cursor = reinterpret_cast<EditorCursor*> (_item->get_data ("cursor"));
2082 CursorDrag::start_grab (GdkEvent* event, Gdk::Cursor* c)
2084 Drag::start_grab (event, c);
2088 nframes64_t where = _editor->event_frame (event, 0, 0);
2090 _editor->snap_to_with_modifier (where, event);
2091 _editor->playhead_cursor->set_position (where);
2095 if (_cursor == _editor->playhead_cursor) {
2096 _editor->_dragging_playhead = true;
2098 if (_editor->session() && _was_rolling && _stop) {
2099 _editor->session()->request_stop ();
2102 if (_editor->session() && _editor->session()->is_auditioning()) {
2103 _editor->session()->cancel_audition ();
2107 _pointer_frame_offset = grab_frame() - _cursor->current_frame;
2109 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2113 CursorDrag::motion (GdkEvent* event, bool)
2115 nframes64_t const adjusted_frame = adjusted_current_frame (event);
2117 if (adjusted_frame == last_pointer_frame()) {
2121 _cursor->set_position (adjusted_frame);
2123 _editor->show_verbose_time_cursor (_cursor->current_frame, 10);
2126 _editor->update_canvas_now ();
2128 _editor->UpdateAllTransportClocks (_cursor->current_frame);
2132 CursorDrag::finished (GdkEvent* event, bool movement_occurred)
2134 _editor->_dragging_playhead = false;
2136 if (!movement_occurred && _stop) {
2140 motion (event, false);
2142 if (_item == &_editor->playhead_cursor->canvas_item) {
2143 if (_editor->session()) {
2144 _editor->session()->request_locate (_editor->playhead_cursor->current_frame, _was_rolling);
2145 _editor->_pending_locate_request = true;
2151 CursorDrag::aborted ()
2153 _editor->_dragging_playhead = false;
2154 _cursor->set_position (adjusted_frame (grab_frame (), 0, false));
2157 FadeInDrag::FadeInDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2158 : RegionDrag (e, i, p, v)
2164 FadeInDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2166 Drag::start_grab (event, cursor);
2168 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2169 boost::shared_ptr<AudioRegion> const r = a->audio_region ();
2171 _pointer_frame_offset = grab_frame() - ((nframes64_t) r->fade_in()->back()->when + r->position());
2172 _editor->show_verbose_duration_cursor (r->position(), r->position() + r->fade_in()->back()->when, 10);
2176 FadeInDrag::motion (GdkEvent* event, bool)
2178 nframes64_t fade_length;
2180 nframes64_t const pos = adjusted_current_frame (event);
2182 boost::shared_ptr<Region> region = _primary->region ();
2184 if (pos < (region->position() + 64)) {
2185 fade_length = 64; // this should be a minimum defined somewhere
2186 } else if (pos > region->last_frame()) {
2187 fade_length = region->length();
2189 fade_length = pos - region->position();
2192 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2194 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2200 tmp->reset_fade_in_shape_width (fade_length);
2203 _editor->show_verbose_duration_cursor (region->position(), region->position() + fade_length, 10);
2207 FadeInDrag::finished (GdkEvent* event, bool movement_occurred)
2209 if (!movement_occurred) {
2213 nframes64_t fade_length;
2215 nframes64_t const pos = adjusted_current_frame (event);
2217 boost::shared_ptr<Region> region = _primary->region ();
2219 if (pos < (region->position() + 64)) {
2220 fade_length = 64; // this should be a minimum defined somewhere
2221 } else if (pos > region->last_frame()) {
2222 fade_length = region->length();
2224 fade_length = pos - region->position();
2227 _editor->begin_reversible_command (_("change fade in length"));
2229 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2231 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2237 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_in();
2238 XMLNode &before = alist->get_state();
2240 tmp->audio_region()->set_fade_in_length (fade_length);
2241 tmp->audio_region()->set_fade_in_active (true);
2243 XMLNode &after = alist->get_state();
2244 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2247 _editor->commit_reversible_command ();
2251 FadeInDrag::aborted ()
2253 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2254 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2260 tmp->reset_fade_in_shape_width (tmp->audio_region()->fade_in()->back()->when);
2264 FadeOutDrag::FadeOutDrag (Editor* e, ArdourCanvas::Item* i, RegionView* p, list<RegionView*> const & v)
2265 : RegionDrag (e, i, p, v)
2271 FadeOutDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2273 Drag::start_grab (event, cursor);
2275 AudioRegionView* a = dynamic_cast<AudioRegionView*> (_primary);
2276 boost::shared_ptr<AudioRegion> r = a->audio_region ();
2278 _pointer_frame_offset = grab_frame() - (r->length() - (nframes64_t) r->fade_out()->back()->when + r->position());
2279 _editor->show_verbose_duration_cursor (r->last_frame() - r->fade_out()->back()->when, r->last_frame(), 10);
2283 FadeOutDrag::motion (GdkEvent* event, bool)
2285 nframes64_t fade_length;
2287 nframes64_t const pos = adjusted_current_frame (event);
2289 boost::shared_ptr<Region> region = _primary->region ();
2291 if (pos > (region->last_frame() - 64)) {
2292 fade_length = 64; // this should really be a minimum fade defined somewhere
2294 else if (pos < region->position()) {
2295 fade_length = region->length();
2298 fade_length = region->last_frame() - pos;
2301 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2303 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2309 tmp->reset_fade_out_shape_width (fade_length);
2312 _editor->show_verbose_duration_cursor (region->last_frame() - fade_length, region->last_frame(), 10);
2316 FadeOutDrag::finished (GdkEvent* event, bool movement_occurred)
2318 if (!movement_occurred) {
2322 nframes64_t fade_length;
2324 nframes64_t const pos = adjusted_current_frame (event);
2326 boost::shared_ptr<Region> region = _primary->region ();
2328 if (pos > (region->last_frame() - 64)) {
2329 fade_length = 64; // this should really be a minimum fade defined somewhere
2331 else if (pos < region->position()) {
2332 fade_length = region->length();
2335 fade_length = region->last_frame() - pos;
2338 _editor->begin_reversible_command (_("change fade out length"));
2340 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2342 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2348 boost::shared_ptr<AutomationList> alist = tmp->audio_region()->fade_out();
2349 XMLNode &before = alist->get_state();
2351 tmp->audio_region()->set_fade_out_length (fade_length);
2352 tmp->audio_region()->set_fade_out_active (true);
2354 XMLNode &after = alist->get_state();
2355 _editor->session()->add_command(new MementoCommand<AutomationList>(*alist.get(), &before, &after));
2358 _editor->commit_reversible_command ();
2362 FadeOutDrag::aborted ()
2364 for (RegionSelection::iterator i = _views.begin(); i != _views.end(); ++i) {
2365 AudioRegionView* tmp = dynamic_cast<AudioRegionView*> (*i);
2371 tmp->reset_fade_out_shape_width (tmp->audio_region()->fade_out()->back()->when);
2375 MarkerDrag::MarkerDrag (Editor* e, ArdourCanvas::Item* i)
2378 _marker = reinterpret_cast<Marker*> (_item->get_data ("marker"));
2381 _points.push_back (Gnome::Art::Point (0, 0));
2382 _points.push_back (Gnome::Art::Point (0, _editor->physical_screen_height));
2384 _line = new ArdourCanvas::Line (*_editor->timebar_group);
2385 _line->property_width_pixels() = 1;
2386 _line->property_points () = _points;
2389 _line->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_MarkerDragLine.get();
2392 MarkerDrag::~MarkerDrag ()
2394 for (list<Location*>::iterator i = _copied_locations.begin(); i != _copied_locations.end(); ++i) {
2400 MarkerDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
2402 Drag::start_grab (event, cursor);
2406 Location *location = _editor->find_location_from_marker (_marker, is_start);
2407 _editor->_dragging_edit_point = true;
2409 _pointer_frame_offset = grab_frame() - (is_start ? location->start() : location->end());
2411 update_item (location);
2413 // _drag_line->show();
2414 // _line->raise_to_top();
2417 _editor->show_verbose_time_cursor (location->start(), 10);
2419 _editor->show_verbose_time_cursor (location->end(), 10);
2422 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2425 case Selection::Toggle:
2426 _editor->selection->toggle (_marker);
2428 case Selection::Set:
2429 if (!_editor->selection->selected (_marker)) {
2430 _editor->selection->set (_marker);
2433 case Selection::Extend:
2435 Locations::LocationList ll;
2436 list<Marker*> to_add;
2438 _editor->selection->markers.range (s, e);
2439 s = min (_marker->position(), s);
2440 e = max (_marker->position(), e);
2443 if (e < max_frames) {
2446 _editor->session()->locations()->find_all_between (s, e, ll, Location::Flags (0));
2447 for (Locations::LocationList::iterator i = ll.begin(); i != ll.end(); ++i) {
2448 Editor::LocationMarkers* lm = _editor->find_location_markers (*i);
2451 to_add.push_back (lm->start);
2454 to_add.push_back (lm->end);
2458 if (!to_add.empty()) {
2459 _editor->selection->add (to_add);
2463 case Selection::Add:
2464 _editor->selection->add (_marker);
2468 /* set up copies for us to manipulate during the drag */
2470 for (MarkerSelection::iterator i = _editor->selection->markers.begin(); i != _editor->selection->markers.end(); ++i) {
2471 Location *l = _editor->find_location_from_marker (*i, is_start);
2472 _copied_locations.push_back (new Location (*l));
2477 MarkerDrag::motion (GdkEvent* event, bool)
2479 nframes64_t f_delta = 0;
2481 bool move_both = false;
2483 Location *real_location;
2484 Location *copy_location = 0;
2486 nframes64_t const newframe = adjusted_current_frame (event);
2488 nframes64_t next = newframe;
2490 if (newframe == last_pointer_frame()) {
2494 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier)) {
2498 MarkerSelection::iterator i;
2499 list<Location*>::iterator x;
2501 /* find the marker we're dragging, and compute the delta */
2503 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2504 x != _copied_locations.end() && i != _editor->selection->markers.end();
2510 if (marker == _marker) {
2512 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2517 if (real_location->is_mark()) {
2518 f_delta = newframe - copy_location->start();
2522 switch (marker->type()) {
2524 case Marker::LoopStart:
2525 case Marker::PunchIn:
2526 f_delta = newframe - copy_location->start();
2530 case Marker::LoopEnd:
2531 case Marker::PunchOut:
2532 f_delta = newframe - copy_location->end();
2535 /* what kind of marker is this ? */
2543 if (i == _editor->selection->markers.end()) {
2544 /* hmm, impossible - we didn't find the dragged marker */
2548 /* now move them all */
2550 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2551 x != _copied_locations.end() && i != _editor->selection->markers.end();
2557 /* call this to find out if its the start or end */
2559 if ((real_location = _editor->find_location_from_marker (marker, is_start)) == 0) {
2563 if (real_location->locked()) {
2567 if (copy_location->is_mark()) {
2571 copy_location->set_start (copy_location->start() + f_delta);
2575 nframes64_t new_start = copy_location->start() + f_delta;
2576 nframes64_t new_end = copy_location->end() + f_delta;
2578 if (is_start) { // start-of-range marker
2581 copy_location->set_start (new_start);
2582 copy_location->set_end (new_end);
2583 } else if (new_start < copy_location->end()) {
2584 copy_location->set_start (new_start);
2586 _editor->snap_to (next, 1, true);
2587 copy_location->set_end (next);
2588 copy_location->set_start (newframe);
2591 } else { // end marker
2594 copy_location->set_end (new_end);
2595 copy_location->set_start (new_start);
2596 } else if (new_end > copy_location->start()) {
2597 copy_location->set_end (new_end);
2598 } else if (newframe > 0) {
2599 _editor->snap_to (next, -1, true);
2600 copy_location->set_start (next);
2601 copy_location->set_end (newframe);
2606 update_item (copy_location);
2608 Editor::LocationMarkers* lm = _editor->find_location_markers (real_location);
2611 lm->set_position (copy_location->start(), copy_location->end());
2615 assert (!_copied_locations.empty());
2617 _editor->show_verbose_time_cursor (newframe, 10);
2620 _editor->update_canvas_now ();
2625 MarkerDrag::finished (GdkEvent* event, bool movement_occurred)
2627 if (!movement_occurred) {
2629 /* just a click, do nothing but finish
2630 off the selection process
2633 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2636 case Selection::Set:
2637 if (_editor->selection->selected (_marker) && _editor->selection->markers.size() > 1) {
2638 _editor->selection->set (_marker);
2642 case Selection::Toggle:
2643 case Selection::Extend:
2644 case Selection::Add:
2651 _editor->_dragging_edit_point = false;
2653 _editor->begin_reversible_command ( _("move marker") );
2654 XMLNode &before = _editor->session()->locations()->get_state();
2656 MarkerSelection::iterator i;
2657 list<Location*>::iterator x;
2660 for (i = _editor->selection->markers.begin(), x = _copied_locations.begin();
2661 x != _copied_locations.end() && i != _editor->selection->markers.end();
2664 Location * location = _editor->find_location_from_marker (*i, is_start);
2668 if (location->locked()) {
2672 if (location->is_mark()) {
2673 location->set_start ((*x)->start());
2675 location->set ((*x)->start(), (*x)->end());
2680 XMLNode &after = _editor->session()->locations()->get_state();
2681 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
2682 _editor->commit_reversible_command ();
2688 MarkerDrag::aborted ()
2694 MarkerDrag::update_item (Location* location)
2696 double const x1 = _editor->frame_to_pixel (location->start());
2698 _points.front().set_x(x1);
2699 _points.back().set_x(x1);
2700 _line->property_points() = _points;
2703 ControlPointDrag::ControlPointDrag (Editor* e, ArdourCanvas::Item* i)
2705 _cumulative_x_drag (0),
2706 _cumulative_y_drag (0)
2708 _point = reinterpret_cast<ControlPoint*> (_item->get_data ("control_point"));
2714 ControlPointDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2716 Drag::start_grab (event, _editor->fader_cursor);
2718 // start the grab at the center of the control point so
2719 // the point doesn't 'jump' to the mouse after the first drag
2720 _time_axis_view_grab_x = _point->get_x();
2721 _time_axis_view_grab_y = _point->get_y();
2723 float const fraction = 1 - (_point->get_y() / _point->line().height());
2725 _point->line().start_drag_single (_point, _time_axis_view_grab_x, fraction);
2727 _editor->set_verbose_canvas_cursor (_point->line().get_verbose_cursor_string (fraction),
2728 event->button.x + 10, event->button.y + 10);
2730 _editor->show_verbose_canvas_cursor ();
2734 ControlPointDrag::motion (GdkEvent* event, bool)
2736 double dx = _drags->current_pointer_x() - last_pointer_x();
2737 double dy = _drags->current_pointer_y() - last_pointer_y();
2739 if (event->button.state & Keyboard::SecondaryModifier) {
2744 /* coordinate in TimeAxisView's space */
2745 double cx = _time_axis_view_grab_x + _cumulative_x_drag + dx;
2746 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2748 // calculate zero crossing point. back off by .01 to stay on the
2749 // positive side of zero
2750 double const zero_gain_y = (1.0 - _zero_gain_fraction) * _point->line().height() - .01;
2752 // make sure we hit zero when passing through
2753 if ((cy < zero_gain_y && (cy - dy) > zero_gain_y) || (cy > zero_gain_y && (cy - dy) < zero_gain_y)) {
2757 if (_x_constrained) {
2758 cx = _time_axis_view_grab_x;
2760 if (_y_constrained) {
2761 cy = _time_axis_view_grab_y;
2764 _cumulative_x_drag = cx - _time_axis_view_grab_x;
2765 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2769 cy = min ((double) _point->line().height(), cy);
2771 nframes64_t cx_frames = _editor->unit_to_frame (cx);
2773 if (!_x_constrained) {
2774 _editor->snap_to_with_modifier (cx_frames, event);
2777 float const fraction = 1.0 - (cy / _point->line().height());
2779 bool const push = Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier);
2781 _point->line().drag_motion (_editor->frame_to_unit (cx_frames), fraction, false, push);
2783 _editor->set_verbose_canvas_cursor_text (_point->line().get_verbose_cursor_string (fraction));
2787 ControlPointDrag::finished (GdkEvent* event, bool movement_occurred)
2789 if (!movement_occurred) {
2793 if ((event->type == GDK_BUTTON_RELEASE) && (event->button.button == 1) && Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
2794 _editor->reset_point_selection ();
2798 motion (event, false);
2800 _point->line().end_drag ();
2804 ControlPointDrag::aborted ()
2806 _point->line().reset ();
2810 ControlPointDrag::active (Editing::MouseMode m)
2812 if (m == Editing::MouseGain) {
2813 /* always active in mouse gain */
2817 /* otherwise active if the point is on an automation line (ie not if its on a region gain line) */
2818 return dynamic_cast<AutomationLine*> (&(_point->line())) != 0;
2821 LineDrag::LineDrag (Editor* e, ArdourCanvas::Item* i)
2824 _cumulative_y_drag (0)
2829 LineDrag::start_grab (GdkEvent* event, Gdk::Cursor* /*cursor*/)
2831 _line = reinterpret_cast<AutomationLine*> (_item->get_data ("line"));
2834 _item = &_line->grab_item ();
2836 /* need to get x coordinate in terms of parent (TimeAxisItemView)
2837 origin, and ditto for y.
2840 double cx = event->button.x;
2841 double cy = event->button.y;
2843 _line->parent_group().w2i (cx, cy);
2845 nframes64_t const frame_within_region = (nframes64_t) floor (cx * _editor->frames_per_unit);
2850 if (!_line->control_points_adjacent (frame_within_region, before, after)) {
2851 /* no adjacent points */
2855 Drag::start_grab (event, _editor->fader_cursor);
2857 /* store grab start in parent frame */
2859 _time_axis_view_grab_x = cx;
2860 _time_axis_view_grab_y = cy;
2862 double fraction = 1.0 - (cy / _line->height());
2864 _line->start_drag_line (before, after, fraction);
2866 _editor->set_verbose_canvas_cursor (_line->get_verbose_cursor_string (fraction),
2867 event->button.x + 10, event->button.y + 10);
2869 _editor->show_verbose_canvas_cursor ();
2873 LineDrag::motion (GdkEvent* event, bool)
2875 double dy = _drags->current_pointer_y() - last_pointer_y();
2877 if (event->button.state & Keyboard::SecondaryModifier) {
2881 double cy = _time_axis_view_grab_y + _cumulative_y_drag + dy;
2883 _cumulative_y_drag = cy - _time_axis_view_grab_y;
2886 cy = min ((double) _line->height(), cy);
2888 double const fraction = 1.0 - (cy / _line->height());
2892 if (Keyboard::modifier_state_contains (event->button.state, Keyboard::PrimaryModifier)) {
2898 /* we are ignoring x position for this drag, so we can just pass in anything */
2899 _line->drag_motion (0, fraction, true, push);
2901 _editor->set_verbose_canvas_cursor_text (_line->get_verbose_cursor_string (fraction));
2905 LineDrag::finished (GdkEvent* event, bool)
2907 motion (event, false);
2912 LineDrag::aborted ()
2918 RubberbandSelectDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
2920 Drag::start_grab (event);
2921 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
2925 RubberbandSelectDrag::motion (GdkEvent* event, bool)
2932 nframes64_t const pf = adjusted_current_frame (event, Config->get_rubberbanding_snaps_to_grid ());
2934 nframes64_t grab = grab_frame ();
2935 if (Config->get_rubberbanding_snaps_to_grid ()) {
2936 _editor->snap_to_with_modifier (grab, event);
2939 /* base start and end on initial click position */
2949 if (_drags->current_pointer_y() < grab_y()) {
2950 y1 = _drags->current_pointer_y();
2953 y2 = _drags->current_pointer_y();
2958 if (start != end || y1 != y2) {
2960 double x1 = _editor->frame_to_pixel (start);
2961 double x2 = _editor->frame_to_pixel (end);
2963 _editor->rubberband_rect->property_x1() = x1;
2964 _editor->rubberband_rect->property_y1() = y1;
2965 _editor->rubberband_rect->property_x2() = x2;
2966 _editor->rubberband_rect->property_y2() = y2;
2968 _editor->rubberband_rect->show();
2969 _editor->rubberband_rect->raise_to_top();
2971 _editor->show_verbose_time_cursor (pf, 10);
2976 RubberbandSelectDrag::finished (GdkEvent* event, bool movement_occurred)
2978 if (movement_occurred) {
2980 motion (event, false);
2983 if (_drags->current_pointer_y() < grab_y()) {
2984 y1 = _drags->current_pointer_y();
2987 y2 = _drags->current_pointer_y();
2992 Selection::Operation op = ArdourKeyboard::selection_type (event->button.state);
2995 _editor->begin_reversible_command (_("rubberband selection"));
2997 if (grab_frame() < last_pointer_frame()) {
2998 committed = _editor->select_all_within (grab_frame(), last_pointer_frame() - 1, y1, y2, _editor->track_views, op);
3000 committed = _editor->select_all_within (last_pointer_frame(), grab_frame() - 1, y1, y2, _editor->track_views, op);
3004 _editor->commit_reversible_command ();
3008 if (!getenv("ARDOUR_SAE")) {
3009 _editor->selection->clear_tracks();
3011 _editor->selection->clear_regions();
3012 _editor->selection->clear_points ();
3013 _editor->selection->clear_lines ();
3016 _editor->rubberband_rect->hide();
3020 RubberbandSelectDrag::aborted ()
3022 _editor->rubberband_rect->hide ();
3026 TimeFXDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3028 Drag::start_grab (event);
3030 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3034 TimeFXDrag::motion (GdkEvent* event, bool)
3036 RegionView* rv = _primary;
3038 nframes64_t const pf = adjusted_current_frame (event);
3040 if (pf > rv->region()->position()) {
3041 rv->get_time_axis_view().show_timestretch (rv->region()->position(), pf);
3044 _editor->show_verbose_time_cursor (pf, 10);
3048 TimeFXDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3050 _primary->get_time_axis_view().hide_timestretch ();
3052 if (!movement_occurred) {
3056 if (last_pointer_frame() < _primary->region()->position()) {
3057 /* backwards drag of the left edge - not usable */
3061 nframes64_t newlen = last_pointer_frame() - _primary->region()->position();
3063 float percentage = (double) newlen / (double) _primary->region()->length();
3065 #ifndef USE_RUBBERBAND
3066 // Soundtouch uses percentage / 100 instead of normal (/ 1)
3067 if (_primary->region()->data_type() == DataType::AUDIO) {
3068 percentage = (float) ((double) newlen - (double) _primary->region()->length()) / ((double) newlen) * 100.0f;
3072 _editor->begin_reversible_command (_("timestretch"));
3074 // XXX how do timeFX on multiple regions ?
3079 if (!_editor->time_stretch (rs, percentage) == 0) {
3080 error << _("An error occurred while executing time stretch operation") << endmsg;
3085 TimeFXDrag::aborted ()
3087 _primary->get_time_axis_view().hide_timestretch ();
3092 ScrubDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3094 Drag::start_grab (event);
3098 ScrubDrag::motion (GdkEvent* /*event*/, bool)
3100 _editor->scrub (adjusted_current_frame (0, false), _drags->current_pointer_x ());
3104 ScrubDrag::finished (GdkEvent* /*event*/, bool movement_occurred)
3106 if (movement_occurred && _editor->session()) {
3107 /* make sure we stop */
3108 _editor->session()->request_transport_speed (0.0);
3113 ScrubDrag::aborted ()
3118 SelectionDrag::SelectionDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3122 , _original_pointer_time_axis (-1)
3123 , _last_pointer_time_axis (-1)
3129 SelectionDrag::start_grab (GdkEvent* event, Gdk::Cursor*)
3131 nframes64_t start = 0;
3132 nframes64_t end = 0;
3134 if (_editor->session() == 0) {
3138 Gdk::Cursor* cursor = 0;
3140 switch (_operation) {
3141 case CreateSelection:
3142 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3147 cursor = _editor->selector_cursor;
3148 Drag::start_grab (event, cursor);
3151 case SelectionStartTrim:
3152 if (_editor->clicked_axisview) {
3153 _editor->clicked_axisview->order_selection_trims (_item, true);
3155 Drag::start_grab (event, _editor->trimmer_cursor);
3156 start = _editor->selection->time[_editor->clicked_selection].start;
3157 _pointer_frame_offset = grab_frame() - start;
3160 case SelectionEndTrim:
3161 if (_editor->clicked_axisview) {
3162 _editor->clicked_axisview->order_selection_trims (_item, false);
3164 Drag::start_grab (event, _editor->trimmer_cursor);
3165 end = _editor->selection->time[_editor->clicked_selection].end;
3166 _pointer_frame_offset = grab_frame() - end;
3170 start = _editor->selection->time[_editor->clicked_selection].start;
3171 Drag::start_grab (event, cursor);
3172 _pointer_frame_offset = grab_frame() - start;
3176 if (_operation == SelectionMove) {
3177 _editor->show_verbose_time_cursor (start, 10);
3179 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3182 _original_pointer_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ()).first->order ();
3186 SelectionDrag::motion (GdkEvent* event, bool first_move)
3188 nframes64_t start = 0;
3189 nframes64_t end = 0;
3192 pair<TimeAxisView*, int> const pending_time_axis = _editor->trackview_by_y_position (_drags->current_pointer_y ());
3193 if (pending_time_axis.first == 0) {
3197 nframes64_t const pending_position = adjusted_current_frame (event);
3199 /* only alter selection if things have changed */
3201 if (pending_time_axis.first->order() == _last_pointer_time_axis && pending_position == last_pointer_frame()) {
3205 switch (_operation) {
3206 case CreateSelection:
3208 nframes64_t grab = grab_frame ();
3211 _editor->snap_to (grab);
3214 if (pending_position < grab_frame()) {
3215 start = pending_position;
3218 end = pending_position;
3222 /* first drag: Either add to the selection
3223 or create a new selection
3229 /* adding to the selection */
3230 _editor->selection->add (_editor->clicked_axisview);
3231 _editor->clicked_selection = _editor->selection->add (start, end);
3236 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3237 _editor->selection->set (_editor->clicked_axisview);
3240 _editor->clicked_selection = _editor->selection->set (start, end);
3244 /* select the track that we're in */
3245 if (find (_added_time_axes.begin(), _added_time_axes.end(), pending_time_axis.first) == _added_time_axes.end()) {
3246 _editor->selection->add (pending_time_axis.first);
3247 _added_time_axes.push_back (pending_time_axis.first);
3250 /* deselect any tracks that this drag no longer includes, being careful to only deselect
3251 tracks that we selected in the first place.
3254 int min_order = min (_original_pointer_time_axis, pending_time_axis.first->order());
3255 int max_order = max (_original_pointer_time_axis, pending_time_axis.first->order());
3257 list<TimeAxisView*>::iterator i = _added_time_axes.begin();
3258 while (i != _added_time_axes.end()) {
3260 list<TimeAxisView*>::iterator tmp = i;
3263 if ((*i)->order() < min_order || (*i)->order() > max_order) {
3264 _editor->selection->remove (*i);
3265 _added_time_axes.remove (*i);
3274 case SelectionStartTrim:
3276 start = _editor->selection->time[_editor->clicked_selection].start;
3277 end = _editor->selection->time[_editor->clicked_selection].end;
3279 if (pending_position > end) {
3282 start = pending_position;
3286 case SelectionEndTrim:
3288 start = _editor->selection->time[_editor->clicked_selection].start;
3289 end = _editor->selection->time[_editor->clicked_selection].end;
3291 if (pending_position < start) {
3294 end = pending_position;
3301 start = _editor->selection->time[_editor->clicked_selection].start;
3302 end = _editor->selection->time[_editor->clicked_selection].end;
3304 length = end - start;
3306 start = pending_position;
3307 _editor->snap_to (start);
3309 end = start + length;
3314 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3315 _editor->start_canvas_autoscroll (1, 0);
3319 _editor->selection->replace (_editor->clicked_selection, start, end);
3322 if (_operation == SelectionMove) {
3323 _editor->show_verbose_time_cursor(start, 10);
3325 _editor->show_verbose_time_cursor(pending_position, 10);
3330 SelectionDrag::finished (GdkEvent* event, bool movement_occurred)
3332 Session* s = _editor->session();
3334 if (movement_occurred) {
3335 motion (event, false);
3336 /* XXX this is not object-oriented programming at all. ick */
3337 if (_editor->selection->time.consolidate()) {
3338 _editor->selection->TimeChanged ();
3341 /* XXX what if its a music time selection? */
3342 if (s && (s->config.get_auto_play() || (s->get_play_range() && s->transport_rolling()))) {
3343 s->request_play_range (&_editor->selection->time, true);
3348 /* just a click, no pointer movement.*/
3350 if (Keyboard::no_modifier_keys_pressed (&event->button)) {
3351 _editor->selection->clear_time();
3354 if (!_editor->selection->selected (_editor->clicked_axisview)) {
3355 _editor->selection->set (_editor->clicked_axisview);
3358 if (s && s->get_play_range () && s->transport_rolling()) {
3359 s->request_stop (false, false);
3364 _editor->stop_canvas_autoscroll ();
3368 SelectionDrag::aborted ()
3373 RangeMarkerBarDrag::RangeMarkerBarDrag (Editor* e, ArdourCanvas::Item* i, Operation o)
3378 _drag_rect = new ArdourCanvas::SimpleRect (*_editor->time_line_group, 0.0, 0.0, 0.0, _editor->physical_screen_height);
3379 _drag_rect->hide ();
3381 _drag_rect->property_fill_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3382 _drag_rect->property_outline_color_rgba() = ARDOUR_UI::config()->canvasvar_RangeDragRect.get();
3386 RangeMarkerBarDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3388 if (_editor->session() == 0) {
3392 Gdk::Cursor* cursor = 0;
3394 if (!_editor->temp_location) {
3395 _editor->temp_location = new Location;
3398 switch (_operation) {
3399 case CreateRangeMarker:
3400 case CreateTransportMarker:
3401 case CreateCDMarker:
3403 if (Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier)) {
3408 cursor = _editor->selector_cursor;
3412 Drag::start_grab (event, cursor);
3414 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3418 RangeMarkerBarDrag::motion (GdkEvent* event, bool first_move)
3420 nframes64_t start = 0;
3421 nframes64_t end = 0;
3422 ArdourCanvas::SimpleRect *crect;
3424 switch (_operation) {
3425 case CreateRangeMarker:
3426 crect = _editor->range_bar_drag_rect;
3428 case CreateTransportMarker:
3429 crect = _editor->transport_bar_drag_rect;
3431 case CreateCDMarker:
3432 crect = _editor->cd_marker_bar_drag_rect;
3435 cerr << "Error: unknown range marker op passed to Editor::drag_range_markerbar_op ()" << endl;
3440 nframes64_t const pf = adjusted_current_frame (event);
3442 if (_operation == CreateRangeMarker || _operation == CreateTransportMarker || _operation == CreateCDMarker) {
3443 nframes64_t grab = grab_frame ();
3444 _editor->snap_to (grab);
3446 if (pf < grab_frame()) {
3454 /* first drag: Either add to the selection
3455 or create a new selection.
3460 _editor->temp_location->set (start, end);
3464 update_item (_editor->temp_location);
3466 //_drag_rect->raise_to_top();
3471 if (event->button.x >= _editor->horizontal_adjustment.get_value() + _editor->_canvas_width) {
3472 _editor->start_canvas_autoscroll (1, 0);
3476 _editor->temp_location->set (start, end);
3478 double x1 = _editor->frame_to_pixel (start);
3479 double x2 = _editor->frame_to_pixel (end);
3480 crect->property_x1() = x1;
3481 crect->property_x2() = x2;
3483 update_item (_editor->temp_location);
3486 _editor->show_verbose_time_cursor (pf, 10);
3491 RangeMarkerBarDrag::finished (GdkEvent* event, bool movement_occurred)
3493 Location * newloc = 0;
3497 if (movement_occurred) {
3498 motion (event, false);
3501 switch (_operation) {
3502 case CreateRangeMarker:
3503 case CreateCDMarker:
3505 _editor->begin_reversible_command (_("new range marker"));
3506 XMLNode &before = _editor->session()->locations()->get_state();
3507 _editor->session()->locations()->next_available_name(rangename,"unnamed");
3508 if (_operation == CreateCDMarker) {
3509 flags = Location::IsRangeMarker | Location::IsCDMarker;
3510 _editor->cd_marker_bar_drag_rect->hide();
3513 flags = Location::IsRangeMarker;
3514 _editor->range_bar_drag_rect->hide();
3516 newloc = new Location(_editor->temp_location->start(), _editor->temp_location->end(), rangename, (Location::Flags) flags);
3517 _editor->session()->locations()->add (newloc, true);
3518 XMLNode &after = _editor->session()->locations()->get_state();
3519 _editor->session()->add_command(new MementoCommand<Locations>(*(_editor->session()->locations()), &before, &after));
3520 _editor->commit_reversible_command ();
3524 case CreateTransportMarker:
3525 // popup menu to pick loop or punch
3526 _editor->new_transport_marker_context_menu (&event->button, _item);
3530 /* just a click, no pointer movement. remember that context menu stuff was handled elsewhere */
3532 if (Keyboard::no_modifier_keys_pressed (&event->button) && _operation != CreateCDMarker) {
3537 _editor->session()->locations()->marks_either_side (grab_frame(), start, end);
3539 if (end == max_frames) {
3540 end = _editor->session()->current_end_frame ();
3543 if (start == max_frames) {
3544 start = _editor->session()->current_start_frame ();
3547 switch (_editor->mouse_mode) {
3549 /* find the two markers on either side and then make the selection from it */
3550 _editor->select_all_within (start, end, 0.0f, FLT_MAX, _editor->track_views, Selection::Set);
3554 /* find the two markers on either side of the click and make the range out of it */
3555 _editor->selection->set (start, end);
3564 _editor->stop_canvas_autoscroll ();
3568 RangeMarkerBarDrag::aborted ()
3574 RangeMarkerBarDrag::update_item (Location* location)
3576 double const x1 = _editor->frame_to_pixel (location->start());
3577 double const x2 = _editor->frame_to_pixel (location->end());
3579 _drag_rect->property_x1() = x1;
3580 _drag_rect->property_x2() = x2;
3584 MouseZoomDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3586 Drag::start_grab (event, _editor->zoom_cursor);
3587 _editor->show_verbose_time_cursor (adjusted_current_frame (event), 10);
3591 MouseZoomDrag::motion (GdkEvent* event, bool first_move)
3596 nframes64_t const pf = adjusted_current_frame (event);
3598 nframes64_t grab = grab_frame ();
3599 _editor->snap_to_with_modifier (grab, event);
3601 /* base start and end on initial click position */
3613 _editor->zoom_rect->show();
3614 _editor->zoom_rect->raise_to_top();
3617 _editor->reposition_zoom_rect(start, end);
3619 _editor->show_verbose_time_cursor (pf, 10);
3624 MouseZoomDrag::finished (GdkEvent* event, bool movement_occurred)
3626 if (movement_occurred) {
3627 motion (event, false);
3629 if (grab_frame() < last_pointer_frame()) {
3630 _editor->temporal_zoom_by_frame (grab_frame(), last_pointer_frame(), "mouse zoom");
3632 _editor->temporal_zoom_by_frame (last_pointer_frame(), grab_frame(), "mouse zoom");
3635 _editor->temporal_zoom_to_frame (false, grab_frame());
3637 temporal_zoom_step (false);
3638 center_screen (grab_frame());
3642 _editor->zoom_rect->hide();
3646 MouseZoomDrag::aborted ()
3648 _editor->zoom_rect->hide ();
3651 NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i)
3654 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3655 region = &cnote->region_view();
3659 NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *)
3661 Drag::start_grab (event);
3664 drag_delta_note = 0;
3669 event_x = _drags->current_pointer_x();
3670 event_y = _drags->current_pointer_y();
3672 _item->property_parent().get_value()->w2i(event_x, event_y);
3674 last_x = region->snap_to_pixel(event_x);
3677 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3679 if (!(was_selected = cnote->selected())) {
3681 /* tertiary-click means extend selection - we'll do that on button release,
3682 so don't add it here, because otherwise we make it hard to figure
3683 out the "extend-to" range.
3686 bool extend = Keyboard::modifier_state_equals (event->button.state, Keyboard::TertiaryModifier);
3689 bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier);
3692 region->note_selected (cnote, true);
3694 region->unique_select (cnote);
3701 NoteDrag::motion (GdkEvent*, bool)
3703 MidiStreamView* streamview = region->midi_stream_view();
3707 event_x = _drags->current_pointer_x();
3708 event_y = _drags->current_pointer_y();
3710 _item->property_parent().get_value()->w2i(event_x, event_y);
3712 event_x = region->snap_to_pixel(event_x);
3714 double dx = event_x - last_x;
3715 double dy = event_y - last_y;
3720 // Snap to note rows
3722 if (abs (dy) < streamview->note_height()) {
3725 int8_t this_delta_note;
3727 this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0);
3729 this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0);
3731 drag_delta_note -= this_delta_note;
3732 dy = streamview->note_height() * this_delta_note;
3733 last_y = last_y + dy;
3737 region->move_selection (dx, dy);
3739 CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item);
3741 snprintf (buf, sizeof (buf), "%g", (int) cnote->note()->note() + drag_delta_note);
3742 //editor.show_verbose_canvas_cursor_with (Evoral::midi_note_name (ev->note()->note()));
3743 _editor->show_verbose_canvas_cursor_with (buf);
3748 NoteDrag::finished (GdkEvent* ev, bool moved)
3750 ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item);
3753 if (_editor->current_mouse_mode() == Editing::MouseObject) {
3756 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3758 region->note_deselected (cnote);
3761 bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
3762 bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
3764 if (!extend && !add && region->selection_size() > 1) {
3765 region->unique_select(cnote);
3766 } else if (extend) {
3767 region->note_selected (cnote, true, true);
3769 /* it was added during button press */
3774 region->note_dropped (cnote, drag_delta_x, drag_delta_note);
3779 NoteDrag::aborted ()
3784 AutomationRangeDrag::AutomationRangeDrag (Editor* e, ArdourCanvas::Item* i, list<AudioRange> const & r)
3787 , _nothing_to_drag (false)
3789 _atav = reinterpret_cast<AutomationTimeAxisView*> (_item->get_data ("trackview"));
3792 _line = _atav->line ();
3796 AutomationRangeDrag::start_grab (GdkEvent* event, Gdk::Cursor* cursor)
3798 Drag::start_grab (event, cursor);
3800 list<ControlPoint*> points;
3802 XMLNode* state = &_line->get_state ();
3804 if (_ranges.empty()) {
3806 uint32_t const N = _line->npoints ();
3807 for (uint32_t i = 0; i < N; ++i) {
3808 points.push_back (_line->nth (i));
3813 boost::shared_ptr<AutomationList> the_list = _line->the_list ();
3814 for (list<AudioRange>::const_iterator j = _ranges.begin(); j != _ranges.end(); ++j) {
3816 /* fade into and out of the region that we're dragging;
3817 64 samples length plucked out of thin air.
3819 nframes64_t const h = (j->start + j->end) / 2;
3820 nframes64_t a = j->start + 64;
3824 nframes64_t b = j->end - 64;
3829 the_list->add (j->start, the_list->eval (j->start));
3830 _line->add_always_in_view (j->start);
3831 the_list->add (a, the_list->eval (a));
3832 _line->add_always_in_view (a);
3833 the_list->add (b, the_list->eval (b));
3834 _line->add_always_in_view (b);
3835 the_list->add (j->end, the_list->eval (j->end));
3836 _line->add_always_in_view (j->end);
3839 uint32_t const N = _line->npoints ();
3840 for (uint32_t i = 0; i < N; ++i) {
3842 ControlPoint* p = _line->nth (i);
3844 list<AudioRange>::const_iterator j = _ranges.begin ();
3845 while (j != _ranges.end() && (j->start >= (*p->model())->when || j->end <= (*p->model())->when)) {
3849 if (j != _ranges.end()) {
3850 points.push_back (p);
3855 if (points.empty()) {
3856 _nothing_to_drag = true;
3860 _line->start_drag_multiple (points, 1 - (_drags->current_pointer_y() / _line->height ()), state);
3864 AutomationRangeDrag::motion (GdkEvent* event, bool first_move)
3866 if (_nothing_to_drag) {
3870 float const f = 1 - (_drags->current_pointer_y() / _line->height());
3872 /* we are ignoring x position for this drag, so we can just pass in anything */
3873 _line->drag_motion (0, f, true, false);
3877 AutomationRangeDrag::finished (GdkEvent* event, bool)
3879 if (_nothing_to_drag) {
3883 motion (event, false);
3885 _line->clear_always_in_view ();
3889 AutomationRangeDrag::aborted ()
3891 _line->clear_always_in_view ();