pianoroll: dragging start handle before zero shifts MIDI later in time
This commit is contained in:
@@ -7564,13 +7564,34 @@ ClipStartDrag::motion (GdkEvent* event, bool first_move)
|
||||
{
|
||||
ArdourCanvas::Rect r (original_rect);
|
||||
|
||||
timepos_t pos (adjusted_current_time (event));
|
||||
editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true);
|
||||
double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos));
|
||||
double x, y;
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
|
||||
if (x >= editing_context.timeline_origin()) {
|
||||
|
||||
/* Compute snapped position and adjust rect item if appropriate */
|
||||
|
||||
timepos_t pos = adjusted_current_time (event);
|
||||
editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true);
|
||||
double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos));
|
||||
|
||||
if (pix >= editing_context.timeline_origin()) {
|
||||
r.x1 = dragging_rect->parent()->canvas_to_item (Duple (pix, 0.0)).x;
|
||||
}
|
||||
|
||||
if (pix > editing_context.timeline_origin()) {
|
||||
r.x1 = dragging_rect->parent()->canvas_to_item (Duple (pix, 0.0)).x;
|
||||
} else {
|
||||
|
||||
/* We need to do our own math here because the normal drag
|
||||
* coordinates are clamped to zero (no negative values).
|
||||
*/
|
||||
|
||||
x -= editing_context.timeline_origin();
|
||||
timepos_t tp (mce.pixel_to_sample (x));
|
||||
Beats b (tp.beats() * -1);
|
||||
mce.shift_midi (timepos_t (b), false);
|
||||
|
||||
/* ensure the line is in the right place */
|
||||
|
||||
r.x1 = r.x0 + 1.;
|
||||
}
|
||||
|
||||
@@ -7585,22 +7606,50 @@ ClipStartDrag::finished (GdkEvent* event, bool movement_occured)
|
||||
return;
|
||||
}
|
||||
|
||||
timepos_t pos = adjusted_current_time (event);
|
||||
double x, y;
|
||||
gdk_event_get_coords (event, &x, &y);
|
||||
|
||||
assert (mce.midi_view());
|
||||
if (x >= editing_context.timeline_origin()) {
|
||||
|
||||
timepos_t pos = adjusted_current_time (event);
|
||||
editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true);
|
||||
double pix = editing_context.timeline_to_canvas (editing_context.time_to_pixel (pos));
|
||||
|
||||
if (pix >= editing_context.timeline_origin()) {
|
||||
|
||||
assert (mce.midi_view());
|
||||
|
||||
if (mce.midi_view()->show_source()) {
|
||||
pos = mce.midi_view()->source_beats_to_timeline (pos.beats());
|
||||
}
|
||||
|
||||
editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true);
|
||||
mce.set_trigger_start (pos);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
/* We need to do our own math here because the normal drag
|
||||
* coordinates are clamped to zero (no negative values).
|
||||
*/
|
||||
|
||||
x -= editing_context.timeline_origin();
|
||||
timepos_t tp (mce.pixel_to_sample (x));
|
||||
Beats b (tp.beats() * -1);
|
||||
mce.shift_midi (timepos_t (b), true);
|
||||
|
||||
if (mce.midi_view()->show_source()) {
|
||||
pos = mce.midi_view()->source_beats_to_timeline (pos.beats());
|
||||
}
|
||||
|
||||
editing_context.snap_to_with_modifier (pos, event, Temporal::RoundNearest, ARDOUR::SnapToGrid_Scaled, true);
|
||||
mce.set_trigger_start (pos);
|
||||
}
|
||||
|
||||
void
|
||||
ClipStartDrag::aborted (bool)
|
||||
ClipStartDrag::aborted (bool movement_occured)
|
||||
{
|
||||
dragging_rect->set (original_rect);
|
||||
|
||||
if (movement_occured) {
|
||||
/* redraw to get notes back to the right places */
|
||||
mce.shift_midi (timepos_t (Temporal::Beats()), false);
|
||||
}
|
||||
}
|
||||
|
||||
ClipEndDrag::ClipEndDrag (EditingContext& ec, ArdourCanvas::Rectangle& r, Pianoroll& m)
|
||||
|
||||
@@ -1260,6 +1260,9 @@ MidiView::model_changed()
|
||||
_marked_for_selection.clear ();
|
||||
_marked_for_velocity.clear ();
|
||||
_pending_note_selection.clear ();
|
||||
|
||||
size_start_rect ();
|
||||
size_end_rect ();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -5270,6 +5273,81 @@ MidiView::add_split_notes ()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MidiView::shift_midi (timepos_t const & t, bool model)
|
||||
{
|
||||
/* INTENDED FOR USE IN PIANOROLL CONTEXT ONLY */
|
||||
|
||||
assert (_show_source);
|
||||
|
||||
Beats beats (t.beats());
|
||||
|
||||
if (model) {
|
||||
|
||||
/* Change the model */
|
||||
|
||||
std::string cmd = string_compose (_("Shift MIDI by %1"), beats.str());
|
||||
XMLNode& before (_midi_region->get_state());
|
||||
_editing_context.begin_reversible_command (cmd);
|
||||
_model->insert_silence_at_start (beats, _editing_context.history());
|
||||
XMLNode& after (_midi_region->get_state());
|
||||
_editing_context.add_command (new MementoCommand<MidiRegion> (*(_midi_region.get()), &before, &after));
|
||||
_editing_context.commit_reversible_command ();
|
||||
|
||||
} else {
|
||||
|
||||
/* Only change the view */
|
||||
|
||||
for (auto & [ note, gui ] : _events) {
|
||||
Temporal::Beats note_time_qn;
|
||||
double dx = 0.0;
|
||||
|
||||
if (_show_source) {
|
||||
note_time_qn = note->time ();
|
||||
} else {
|
||||
note_time_qn = _midi_region->source_beats_to_absolute_beats (note->time());
|
||||
}
|
||||
|
||||
if (_midi_context.note_mode() == Sustained) {
|
||||
dx = _editing_context.time_to_pixel_unrounded (timepos_t (note_time_qn + beats));
|
||||
|
||||
/*: ::item_to_canvas() converts to a global canvas
|
||||
* coordinate, but ::time_to_pixel() gives us a
|
||||
* timeline-relative coordinate.
|
||||
*
|
||||
* So we need to adjust ...
|
||||
*/
|
||||
|
||||
dx -= _editing_context.canvas_to_timeline (gui->item()->item_to_canvas (ArdourCanvas::Duple (gui->x0(), 0)).x);
|
||||
} else {
|
||||
/* Hit::x0() is offset by _position.x, unlike Note::x0() */
|
||||
Hit* hit = dynamic_cast<Hit*>(gui);
|
||||
if (hit) {
|
||||
dx = _editing_context.time_to_pixel_unrounded (timepos_t (note_time_qn + beats));
|
||||
dx -= _editing_context.canvas_to_timeline (gui->item()->item_to_canvas (ArdourCanvas::Duple (((hit->x0() + hit->x1()) / 2.0) - hit->position().x, 0)).x);
|
||||
}
|
||||
}
|
||||
|
||||
gui->move_event (dx, 0.0);
|
||||
|
||||
/* update length, which may have changed in pixels at the new location */
|
||||
if (_midi_context.note_mode() == Sustained) {
|
||||
Note* sus = dynamic_cast<Note*> (gui);
|
||||
double len_dx = _editing_context.time_to_pixel_unrounded (timepos_t (note_time_qn) + t + timecnt_t (note->length()));
|
||||
|
||||
/* at this point, len_dx is a timeline-relative pixel
|
||||
* duration. To convert it back to an item-centric
|
||||
* coordinate, we need to first convert it to a global
|
||||
* canvas position.
|
||||
*/
|
||||
|
||||
len_dx = _editing_context.timeline_to_canvas (len_dx);
|
||||
sus->set_x1 (gui->item()->canvas_to_item (ArdourCanvas::Duple (len_dx, 0)).x);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
double
|
||||
MidiView::height() const
|
||||
{
|
||||
|
||||
@@ -358,6 +358,8 @@ class MidiView : public virtual sigc::trackable, public LineMerger
|
||||
void note_deleted (NoteBase*);
|
||||
void clear_note_selection ();
|
||||
|
||||
void shift_midi (Temporal::timepos_t const &, bool model);
|
||||
|
||||
void show_verbose_cursor_for_new_note_value(std::shared_ptr<NoteType> current_note, uint8_t new_note) const;
|
||||
|
||||
std::shared_ptr<ARDOUR::MidiTrack> midi_track() const { return _midi_track; }
|
||||
|
||||
@@ -2822,3 +2822,12 @@ Pianoroll::allow_trim_cursors () const
|
||||
return mouse_mode == Editing::MouseContent || mouse_mode == Editing::MouseTimeFX;
|
||||
}
|
||||
|
||||
void
|
||||
Pianoroll::shift_midi (timepos_t const & t, bool model)
|
||||
{
|
||||
if (!view) {
|
||||
return;
|
||||
}
|
||||
|
||||
view->shift_midi (t, model);
|
||||
}
|
||||
|
||||
@@ -142,6 +142,8 @@ class Pianoroll : public CueEditor
|
||||
void set_session (ARDOUR::Session*);
|
||||
bool allow_trim_cursors () const;
|
||||
|
||||
void shift_midi (Temporal::timepos_t const &, bool model);
|
||||
|
||||
protected:
|
||||
void load_bindings ();
|
||||
void register_actions ();
|
||||
|
||||
Reference in New Issue
Block a user