diff options
author | Carl Hetherington <carl@carlh.net> | 2010-08-19 22:01:10 +0000 |
---|---|---|
committer | Carl Hetherington <carl@carlh.net> | 2010-08-19 22:01:10 +0000 |
commit | 611c33e6807b028a6a521017188d704445ba1d06 (patch) | |
tree | bb150f67b671fbc8905dc9e31f2b42892696329e /gtk2_ardour/editor_drag.cc | |
parent | 7b6b75f38ff6b34de3f70e36045498f227c1727d (diff) |
Snap to note start rather than mouse pointer when dragging MIDI notes. Fixes #3187.
git-svn-id: svn://localhost/ardour2/branches/3.0@7654 d708f5d6-7413-0410-9779-e7cbd77b26cf
Diffstat (limited to 'gtk2_ardour/editor_drag.cc')
-rw-r--r-- | gtk2_ardour/editor_drag.cc | 145 |
1 files changed, 62 insertions, 83 deletions
diff --git a/gtk2_ardour/editor_drag.cc b/gtk2_ardour/editor_drag.cc index ca85ae809e..0d8736b5fb 100644 --- a/gtk2_ardour/editor_drag.cc +++ b/gtk2_ardour/editor_drag.cc @@ -3751,9 +3751,12 @@ MouseZoomDrag::aborted () NoteDrag::NoteDrag (Editor* e, ArdourCanvas::Item* i) : Drag (e, i) + , _cumulative_dx (0) + , _cumulative_dy (0) { - CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item); - region = &cnote->region_view(); + _primary = dynamic_cast<CanvasNoteEvent*> (_item); + _region = &_primary->region_view (); + _note_height = _region->midi_stream_view()->note_height (); } void @@ -3761,23 +3764,7 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) { Drag::start_grab (event); - drag_delta_x = 0; - drag_delta_note = 0; - - double event_x; - double event_y; - - event_x = _drags->current_pointer_x(); - event_y = _drags->current_pointer_y(); - - _item->property_parent().get_value()->w2i(event_x, event_y); - - last_x = region->snap_to_pixel(event_x); - last_y = event_y; - - CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item); - - if (!(was_selected = cnote->selected())) { + if (!(_was_selected = _primary->selected())) { /* tertiary-click means extend selection - we'll do that on button release, so don't add it here, because otherwise we make it hard to figure @@ -3790,79 +3777,73 @@ NoteDrag::start_grab (GdkEvent* event, Gdk::Cursor *) bool add = Keyboard::modifier_state_equals (event->button.state, Keyboard::PrimaryModifier); if (add) { - region->note_selected (cnote, true); + _region->note_selected (_primary, true); } else { - region->unique_select (cnote); + _region->unique_select (_primary); } } } } -void -NoteDrag::motion (GdkEvent*, bool) +/** @return Current total drag x change in frames */ +frameoffset_t +NoteDrag::total_dx () const { - MidiStreamView* streamview = region->midi_stream_view(); - double event_x; - double event_y; - - event_x = _drags->current_pointer_x(); - event_y = _drags->current_pointer_y(); + /* dx in frames */ + frameoffset_t const dx = _editor->unit_to_frame (_drags->current_pointer_x() - grab_x()); - _item->property_parent().get_value()->w2i(event_x, event_y); - - event_x = region->snap_to_pixel(event_x); + /* primary note time */ + frameoffset_t const n = _region->beats_to_frames (_primary->note()->time ()); + + /* new time of the primary note relative to the region position */ + frameoffset_t const st = n + dx; - double dx = event_x - last_x; - double dy = event_y - last_y; - last_x = event_x; + /* snap and return corresponding delta */ + return _region->snap_frame_to_frame (st) - n; +} - drag_delta_x += dx; +/** @return Current total drag y change in notes */ +int8_t +NoteDrag::total_dy () const +{ + /* this is `backwards' to make increasing note number go in the right direction */ + double const dy = _drags->current_pointer_y() - grab_y(); - // Snap to note rows + /* dy in notes */ + int8_t ndy = 0; - if (abs (dy) < streamview->note_height()) { - dy = 0.0; - } else { - int8_t this_delta_note; + if (abs (dy) >= _note_height) { if (dy > 0) { - this_delta_note = (int8_t)ceil(dy / streamview->note_height() / 2.0); + ndy = (int8_t) ceil (dy / _note_height / 2.0); } else { - this_delta_note = (int8_t)floor(dy / streamview->note_height() / 2.0); - } - drag_delta_note -= this_delta_note; - dy = streamview->note_height() * this_delta_note; - last_y = last_y + dy; - } - - if (dx || dy) { - - CanvasNoteEvent* cnote = dynamic_cast<CanvasNoteEvent*>(_item); - Evoral::MusicalTime new_time; - - if (drag_delta_x) { - nframes64_t start_frames = region->beats_to_frames(cnote->note()->time()); - if (drag_delta_x >= 0) { - start_frames += region->snap_frame_to_frame(_editor->pixel_to_frame(drag_delta_x)); - } else { - start_frames -= region->snap_frame_to_frame(_editor->pixel_to_frame(-drag_delta_x)); - } - new_time = region->frames_to_beats(start_frames); - } else { - new_time = cnote->note()->time(); - } - - boost::shared_ptr<Evoral::Note<Evoral::MusicalTime> > check_note ( - new Evoral::Note<Evoral::MusicalTime> (cnote->note()->channel(), - new_time, - cnote->note()->length(), - cnote->note()->note() + drag_delta_note, - cnote->note()->velocity())); + ndy = (int8_t) floor (dy / _note_height / 2.0); + } + } - region->move_selection (dx, dy); + return ndy; +} + + +void +NoteDrag::motion (GdkEvent *, bool) +{ + /* Total change in x and y since the start of the drag */ + frameoffset_t const dx = total_dx (); + int8_t const dy = total_dy (); + + /* Now work out what we have to do to the note canvas items to set this new drag delta */ + double const tdx = _editor->frame_to_unit (dx) - _cumulative_dx; + double const tdy = dy * _note_height - _cumulative_dy; + + if (tdx || tdy) { + _region->move_selection (tdx, tdy); + _cumulative_dx += tdx; + _cumulative_dy += tdy; char buf[12]; - snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (cnote->note()->note() + drag_delta_note).c_str(), - (int) floor ((cnote->note()->note() + drag_delta_note))); + snprintf (buf, sizeof (buf), "%s (%d)", Evoral::midi_note_name (_primary->note()->note() + dy).c_str(), + (int) floor (_primary->note()->note() + dy)); + _editor->show_verbose_canvas_cursor_with (buf); } } @@ -3870,31 +3851,29 @@ NoteDrag::motion (GdkEvent*, bool) void NoteDrag::finished (GdkEvent* ev, bool moved) { - ArdourCanvas::CanvasNote* cnote = dynamic_cast<ArdourCanvas::CanvasNote*>(_item); - if (!moved) { if (_editor->current_mouse_mode() == Editing::MouseObject) { - if (was_selected) { + if (_was_selected) { bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier); if (add) { - region->note_deselected (cnote); + _region->note_deselected (_primary); } } else { bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier); bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier); - if (!extend && !add && region->selection_size() > 1) { - region->unique_select(cnote); + if (!extend && !add && _region->selection_size() > 1) { + _region->unique_select (_primary); } else if (extend) { - region->note_selected (cnote, true, true); + _region->note_selected (_primary, true, true); } else { /* it was added during button press */ } } } } else { - region->note_dropped (cnote, drag_delta_x, drag_delta_note); + _region->note_dropped (_primary, total_dx(), - total_dy()); } } |