summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCarl Hetherington <carl@carlh.net>2010-08-19 22:01:10 +0000
committerCarl Hetherington <carl@carlh.net>2010-08-19 22:01:10 +0000
commit611c33e6807b028a6a521017188d704445ba1d06 (patch)
treebb150f67b671fbc8905dc9e31f2b42892696329e
parent7b6b75f38ff6b34de3f70e36045498f227c1727d (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
-rw-r--r--gtk2_ardour/editor_drag.cc145
-rw-r--r--gtk2_ardour/editor_drag.h23
-rw-r--r--gtk2_ardour/midi_region_view.cc12
-rw-r--r--gtk2_ardour/midi_region_view.h2
4 files changed, 82 insertions, 100 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());
}
}
diff --git a/gtk2_ardour/editor_drag.h b/gtk2_ardour/editor_drag.h
index 647655e7fb..b194366380 100644
--- a/gtk2_ardour/editor_drag.h
+++ b/gtk2_ardour/editor_drag.h
@@ -35,6 +35,12 @@ namespace ARDOUR {
class Location;
}
+namespace Gnome {
+ namespace Canvas {
+ class CanvasNoteEvent;
+ }
+}
+
class Editor;
class EditorCursor;
class TimeAxisView;
@@ -356,6 +362,7 @@ private:
bool at_front;
};
+/** Drags to move MIDI notes */
class NoteDrag : public Drag
{
public:
@@ -367,12 +374,16 @@ class NoteDrag : public Drag
void aborted ();
private:
- MidiRegionView* region;
- double last_x;
- double last_y;
- double drag_delta_x;
- double drag_delta_note;
- bool was_selected;
+
+ ARDOUR::frameoffset_t total_dx () const;
+ int8_t total_dy () const;
+
+ MidiRegionView* _region;
+ Gnome::Canvas::CanvasNoteEvent* _primary;
+ double _cumulative_dx;
+ double _cumulative_dy;
+ bool _was_selected;
+ double _note_height;
};
/** Drag of region gain */
diff --git a/gtk2_ardour/midi_region_view.cc b/gtk2_ardour/midi_region_view.cc
index a520a22d50..1ca948f860 100644
--- a/gtk2_ardour/midi_region_view.cc
+++ b/gtk2_ardour/midi_region_view.cc
@@ -1956,7 +1956,7 @@ MidiRegionView::move_selection(double dx, double dy)
}
void
-MidiRegionView::note_dropped(CanvasNoteEvent *, double dt, int8_t dnote)
+MidiRegionView::note_dropped(CanvasNoteEvent *, frameoffset_t dt, int8_t dnote)
{
assert (!_selection.empty());
@@ -1991,15 +1991,7 @@ MidiRegionView::note_dropped(CanvasNoteEvent *, double dt, int8_t dnote)
for (Selection::iterator i = _selection.begin(); i != _selection.end() ; ++i) {
- nframes64_t start_frames = beats_to_frames((*i)->note()->time());
-
- if (dt >= 0) {
- start_frames += snap_frame_to_frame(trackview.editor().pixel_to_frame(dt));
- } else {
- start_frames -= snap_frame_to_frame(trackview.editor().pixel_to_frame(-dt));
- }
-
- Evoral::MusicalTime new_time = frames_to_beats(start_frames);
+ Evoral::MusicalTime new_time = frames_to_beats (beats_to_frames ((*i)->note()->time()) + dt);
if (new_time < 0) {
continue;
diff --git a/gtk2_ardour/midi_region_view.h b/gtk2_ardour/midi_region_view.h
index 75ee5f13d8..9523937565 100644
--- a/gtk2_ardour/midi_region_view.h
+++ b/gtk2_ardour/midi_region_view.h
@@ -200,7 +200,7 @@ class MidiRegionView : public RegionView
size_t selection_size() { return _selection.size(); }
void move_selection(double dx, double dy);
- void note_dropped(ArdourCanvas::CanvasNoteEvent* ev, double d_pixels, int8_t d_note);
+ void note_dropped (ArdourCanvas::CanvasNoteEvent* ev, ARDOUR::frameoffset_t, int8_t d_note);
void select_matching_notes (uint8_t notenum, uint16_t channel_mask, bool add, bool extend);
void toggle_matching_notes (uint8_t notenum, uint16_t channel_mask);