Functional note moving.

Better vertical note snap, don't let the mouse drift away from the note on fast drags.


git-svn-id: svn://localhost/ardour2/trunk@2218 d708f5d6-7413-0410-9779-e7cbd77b26cf
This commit is contained in:
David Robillard
2007-08-02 04:43:43 +00:00
parent c96b558320
commit 3c22c8f2d5
3 changed files with 58 additions and 19 deletions

View File

@@ -43,6 +43,8 @@ CanvasMidiEvent::CanvasMidiEvent(MidiRegionView& region, Item* item, const ARDOU
bool
CanvasMidiEvent::on_event(GdkEvent* ev)
{
static uint8_t drag_delta_note = 0;
static double drag_delta_x = 0;
static double last_x, last_y;
double event_x, event_y, dx, dy;
@@ -85,14 +87,17 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
_item->property_parent().get_value()->w2i(event_x, event_y);
switch (_state) {
case Pressed:
case Pressed: // Drag begin
_item->grab(GDK_POINTER_MOTION_MASK | GDK_BUTTON_RELEASE_MASK,
Gdk::Cursor(Gdk::FLEUR), ev->motion.time);
_state = Dragging;
last_x = event_x;
last_y = event_y;
drag_delta_x = 0;
drag_delta_note = 0;
return true;
case Dragging:
case Dragging: // Drag motion
if (ev->motion.is_hint) {
int t_x;
int t_y;
@@ -107,12 +112,20 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
last_x = event_x;
drag_delta_x += dx;
// Snap to note rows
if (abs(dy) < _region.note_height()) {
dy = 0.0;
} else {
dy = _region.note_height() * ((dy > 0) ? 1 : -1);
last_y = event_y;
int8_t this_delta_note;
if (dy > 0)
this_delta_note = (int8_t)ceil(dy / _region.note_height());
else
this_delta_note = (int8_t)floor(dy / _region.note_height());
drag_delta_note -= this_delta_note;
dy = _region.note_height() * this_delta_note;
last_y = last_y + dy;
}
_item->move(dx, dy);
@@ -124,6 +137,10 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
break;
case GDK_BUTTON_RELEASE:
event_x = ev->button.x;
event_y = ev->button.y;
_item->property_parent().get_value()->w2i(event_x, event_y);
switch (_state) {
case Pressed: // Clicked
_state = None;
@@ -132,15 +149,21 @@ CanvasMidiEvent::on_event(GdkEvent* ev)
_item->ungrab(ev->button.time);
_state = None;
if (_note) {
cerr << "Move and stuff." << endl;
// This would be nicer with a MoveCommand that doesn't need to copy...
/*_region.start_delta_command();
_region.start_delta_command();
_region.command_remove_note(this);
Note copy_of_me(*this);
copy_of_me.time = trackview.editor.pixel_to_frame(property_x1());
copy_of_me.note = stuff;
MidiModel::Note copy(*_note);
double delta_t = _region.midi_view()->editor.pixel_to_frame(
abs(drag_delta_x));
if (drag_delta_x < 0)
delta_t *= -1;
copy.set_time(_note->time() + delta_t);
copy.set_note(_note->note() + drag_delta_note);
_region.command_add_note(copy);
_region.apply_command();
*/
}
return true;
default:

View File

@@ -231,13 +231,11 @@ MidiRegionView::create_note_at(double x, double y)
MidiTimeAxisView* const mtv = dynamic_cast<MidiTimeAxisView*>(&trackview);
MidiStreamView* const view = mtv->midi_view();
const uint8_t note_range = view->highest_note() - view->lowest_note() + 1;
const double footer_height = name_highlight->property_y2() - name_highlight->property_y1();
const double roll_height = trackview.height - footer_height;
get_canvas_group()->w2i(x, y);
double note = floor((roll_height - y) / roll_height * (double)note_range) + view->lowest_note();
double note = floor((contents_height() - y) / contents_height() * (double)contents_note_range())
+ view->lowest_note();
assert(note >= 0.0);
assert(note <= 127.0);
@@ -418,7 +416,7 @@ MidiRegionView::add_event (const MidiEvent& ev)
if (midi_view()->note_mode() == Sustained) {
if ((ev.buffer()[0] & 0xF0) == MIDI_CMD_NOTE_ON) {
const Byte& note = ev.buffer()[1];
const double y1 = note_y(note);
const double y1 = note_to_y(note);
CanvasNote* ev_rect = new CanvasNote(*this, *group);
ev_rect->property_x1() = trackview.editor.frame_to_pixel (
@@ -451,7 +449,7 @@ MidiRegionView::add_event (const MidiEvent& ev)
const Byte& note = ev.buffer()[1];
const double diamond_size = std::min(note_height(), 5.0);
const double x = trackview.editor.frame_to_pixel((nframes_t)ev.time());
const double y = note_y(note) + (diamond_size / 2.0);
const double y = note_to_y(note) + (diamond_size / 2.0);
CanvasHit* ev_diamond = new CanvasHit(*this, *group, diamond_size);
ev_diamond->move(x, y);

View File

@@ -79,11 +79,15 @@ class MidiRegionView : public RegionView
inline double note_height() const
{ return contents_height() / (double)contents_note_range(); }
inline double note_y(uint8_t note) const
inline double note_to_y(uint8_t note) const
{ return trackview.height
- (contents_height() * (note - midi_stream_view()->lowest_note() + 1))
- footer_height() - 3.0; }
inline uint8_t y_to_note(double y) const
{ return (uint8_t)floor((contents_height() - y)
/ contents_height() * (double)contents_note_range()); }
void set_y_position_and_height (double, double);
void show_region_editor ();
@@ -101,11 +105,19 @@ class MidiRegionView : public RegionView
void display_model(boost::shared_ptr<ARDOUR::MidiModel> model);
/* This stuff is a bit boilerplatey ATM. Work in progress. */
inline void start_remove_command() {
_command_mode = Remove;
if (!_delta_command)
_delta_command = _model->new_delta_command();
}
inline void start_delta_command() {
_command_mode = Delta;
if (!_delta_command)
_delta_command = _model->new_delta_command();
}
void command_remove_note(ArdourCanvas::CanvasMidiEvent* ev) {
if (_delta_command && ev->note()) {
@@ -113,6 +125,12 @@ class MidiRegionView : public RegionView
ev->selected(true);
}
}
void command_add_note(ARDOUR::MidiModel::Note& note) {
if (_delta_command) {
_delta_command->add(note);
}
}
void note_entered(ArdourCanvas::CanvasMidiEvent* ev) {
if (_command_mode == Remove && _delta_command && ev->note())
@@ -169,7 +187,7 @@ class MidiRegionView : public RegionView
ArdourCanvas::CanvasNote** _active_notes;
ARDOUR::MidiModel::DeltaCommand* _delta_command;
enum CommandMode { None, Remove };
enum CommandMode { None, Remove, Delta };
CommandMode _command_mode;
};