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:
@@ -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:
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user