the basics of lollipop dragging

This commit is contained in:
Paul Davis 2023-06-20 11:28:59 -06:00
parent 2977205f3a
commit cf7ba80fc1
12 changed files with 140 additions and 26 deletions

View File

@ -674,7 +674,7 @@ Editor::canvas_control_point_event (GdkEvent *event, ArdourCanvas::Item* item, C
bool
Editor::canvas_velocity_event (GdkEvent *event, ArdourCanvas::Item* item)
{
std::cerr << "Velocity event: " << Gtkmm2ext::event_type_string (event->type) << std::endl;
// std::cerr << "Velocity event: " << Gtkmm2ext::event_type_string (event->type) << std::endl;
return typed_event (item, event, VelocityItem);
}

View File

@ -52,6 +52,7 @@
#include "ardour/session_playlists.h"
#include "canvas/canvas.h"
#include "canvas/lollipop.h"
#include "canvas/scroll_group.h"
#include "ardour_ui.h"
@ -77,6 +78,7 @@
#include "region_gain_line.h"
#include "selection.h"
#include "ui_config.h"
#include "velocity_ghost_region.h"
#include "verbose_cursor.h"
#include "video_timeline.h"
@ -7178,9 +7180,11 @@ RegionMarkerDrag::setup_pointer_sample_offset ()
_pointer_offset = model_abs_pos.distance (raw_grab_time ());
}
LollipopDrag::LollipopDrag (Editor* ed, MidiRegionView* r, ArdourCanvas::Item* i)
: Drag (ed, i, r->region ()->position ().time_domain ())
LollipopDrag::LollipopDrag (Editor* ed, ArdourCanvas::Item* l)
: Drag (ed, l, Temporal::BeatTime)
, _primary (dynamic_cast<ArdourCanvas::Lollipop*> (l))
{
_region = reinterpret_cast<VelocityGhostRegion*> (_item->get_data ("ghostregionview"));
}
LollipopDrag::~LollipopDrag ()
@ -7191,25 +7195,48 @@ void
LollipopDrag::start_grab (GdkEvent *ev, Gdk::Cursor* c)
{
Drag::start_grab (ev, c);
NoteBase* note = static_cast<NoteBase*> (_primary->get_data (X_("note")));
MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (&_region->parent_rv);
assert (mrv);
bool add = Keyboard::modifier_state_equals (ev->button.state, Keyboard::PrimaryModifier);
bool extend = Keyboard::modifier_state_equals (ev->button.state, Keyboard::TertiaryModifier);
mrv->note_selected (note, add, extend);
}
void
LollipopDrag::motion (GdkEvent *ev, bool first_move)
{
_region->drag_lolli (_primary, &ev->motion);
}
void
LollipopDrag::finished (GdkEvent *ev, bool did_move)
{
if (!did_move) {
return;
}
int velocity = _region->y_position_to_velocity (_primary->y0());
NoteBase* note = static_cast<NoteBase*> (_primary->get_data (X_("note")));
MidiRegionView* mrv = dynamic_cast<MidiRegionView*> (&_region->parent_rv);
assert (mrv);
mrv->set_velocity (note, velocity);
}
void
LollipopDrag::aborted (bool)
{
/* XXX get ghost velocity view etc. to redraw with original values */
}
void
LollipopDrag::setup_pointer_sample_offset ()
{
NoteBase* note = static_cast<NoteBase*> (_primary->get_data (X_("note")));
_pointer_offset = _region->parent_rv.region()->source_beats_to_absolute_time (note->note()->time ()).distance (raw_grab_time ());
}

View File

@ -56,6 +56,7 @@ namespace ArdourCanvas {
class Item;
class Line;
class Rectangle;
class Lollipop;
}
namespace PBD {
@ -81,6 +82,7 @@ class ControlPoint;
class AudioRegionView;
class AutomationLine;
class AutomationTimeAxisView;
class VelocityGhostRegion;
/** Class to manage current drags */
class DragManager
@ -1550,7 +1552,7 @@ class RegionMarkerDrag : public Drag
class LollipopDrag : public Drag
{
public:
LollipopDrag (Editor*, MidiRegionView*, ArdourCanvas::Item*);
LollipopDrag (Editor*, ArdourCanvas::Item*);
~LollipopDrag ();
void start_grab (GdkEvent *, Gdk::Cursor* c = 0);
@ -1573,8 +1575,8 @@ class LollipopDrag : public Drag
void setup_pointer_sample_offset ();
private:
MidiRegionView* _region;
NoteBase* _primary;
VelocityGhostRegion* _region;
ArdourCanvas::Lollipop* _primary;
};
#endif /* __gtk2_ardour_editor_drag_h_ */

View File

@ -897,6 +897,11 @@ Editor::button_press_handler_1 (ArdourCanvas::Item* item, GdkEvent* event, ItemT
return true;
break;
case VelocityItem:
_drags->set (new LollipopDrag (this, item), event);
return true;
break;
default:
break;
}

View File

@ -221,8 +221,7 @@ MidiGhostRegion::GhostEvent::GhostEvent (NoteBase* e, ArdourCanvas::Container* g
: event (e)
{
if (dynamic_cast<Note*>(e)) {
item = new ArdourCanvas::Rectangle(
g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1()));
item = new ArdourCanvas::Rectangle (g, ArdourCanvas::Rect(e->x0(), e->y0(), e->x1(), e->y1()));
is_hit = false;
} else {
Hit* hit = dynamic_cast<Hit*>(e);

View File

@ -28,7 +28,7 @@ using namespace ARDOUR;
using ArdourCanvas::Coord;
using ArdourCanvas::Duple;
Lollipop::Lollipop (
NoteVelocityLollipop (
MidiRegionView& region, ArdourCanvas::Item* parent, const std::shared_ptr<NoteType> note, bool with_events)
: NoteBase (region, with_events, note)
, _lollipop (new ArdourCanvas::Lollipop (parent))
@ -37,73 +37,74 @@ Lollipop::Lollipop (
set_item (_lollipop);
}
Lollipop::~Lollipop ()
NoteVelocity~Lollipop ()
{
delete _lollipop;
}
void
Lollipop::move_event (double dx, double dy)
NoteVelocitymove_event (double dx, double dy)
{
std::cerr << "move lolli to: " << (Duple (_lollipop->x(), _lollipop->y0()).translate (Duple (dx, dy)), _lollipop->length(), _lollipop->radius()) << std::endl;
_lollipop->set (Duple (_lollipop->x(), _lollipop->y0()).translate (Duple (dx, dy)), _lollipop->length(), _lollipop->radius());
}
void
Lollipop::set_outline_color (uint32_t color)
NoteVelocityset_outline_color (uint32_t color)
{
_lollipop->set_outline_color (color);
}
void
Lollipop::set_fill_color (uint32_t color)
NoteVelocityset_fill_color (uint32_t color)
{
_lollipop->set_fill_color (color);
}
void
Lollipop::show ()
NoteVelocityshow ()
{
_lollipop->show ();
}
void
Lollipop::hide ()
NoteVelocityhide ()
{
_lollipop->hide ();
}
void
Lollipop::set (ArdourCanvas::Duple const & d, ArdourCanvas::Coord len, ArdourCanvas::Coord radius)
NoteVelocityset (ArdourCanvas::Duple const & d, ArdourCanvas::Coord len, ArdourCanvas::Coord radius)
{
_lollipop->set (d, len, radius);
}
void
Lollipop::set_x (Coord x)
NoteVelocityset_x (Coord x)
{
_lollipop->set_x (x);
}
void
Lollipop::set_len (Coord l)
NoteVelocityset_len (Coord l)
{
_lollipop->set_length (l);
}
void
Lollipop::set_outline_what (ArdourCanvas::Rectangle::What what)
NoteVelocityset_outline_what (ArdourCanvas::Rectangle::What what)
{
// _lollipop->set_outline_what (what);
}
void
Lollipop::set_outline_all ()
NoteVelocityset_outline_all ()
{
// _lollipop->set_outline_all ();
}
void
Lollipop::set_ignore_events (bool ignore)
NoteVelocityset_ignore_events (bool ignore)
{
_lollipop->set_ignore_events (ignore);
}

View File

@ -31,17 +31,17 @@ namespace ArdourCanvas {
class Lollipop;
}
class Lollipop : public NoteBase
class NoteVelocity : public NoteBase
{
public:
typedef Evoral::Note<Temporal::Beats> NoteType;
Lollipop (MidiRegionView& region,
NoteVelocity (MidiRegionView& region,
ArdourCanvas::Item* parent,
const std::shared_ptr<NoteType> note = std::shared_ptr<NoteType>(),
bool with_events = true);
~Lollipop ();
~NoteVelocity ();
void set (ArdourCanvas::Duple const &, ArdourCanvas::Coord, ArdourCanvas::Coord);
void set_x (ArdourCanvas::Coord);
@ -58,6 +58,8 @@ public:
void set_ignore_events (bool);
ArdourCanvas::Lollipop& lolli() { return *_lollipop; }
void move_event (double dx, double dy);
private:

View File

@ -3369,6 +3369,31 @@ MidiRegionView::change_note_length (NoteBase* event, Temporal::Beats t)
note_diff_add_change (event, MidiModel::NoteDiffCommand::Length, t);
}
void
MidiRegionView::set_velocity (NoteBase* note, int velocity)
{
if (_selection.empty()) {
return;
}
int delta = velocity - note->note()->velocity();
std::cerr << "vel delta = " << delta << std::endl;
start_note_diff_command (_("set velocities"));
for (Selection::iterator i = _selection.begin(); i != _selection.end();) {
Selection::iterator next = i;
++next;
change_note_velocity (*i, delta, true);
i = next;
}
apply_note_diff();
}
void
MidiRegionView::change_velocities (bool up, bool fine, bool allow_smush, bool all_together)
{

View File

@ -54,10 +54,10 @@ namespace MIDI {
};
class SysEx;
class NoteBase;
class Note;
class Hit;
class MidiTimeAxisView;
class NoteBase;
class GhostRegion;
class AutomationTimeAxisView;
class AutomationRegionView;
@ -67,6 +67,7 @@ class EditNoteDialog;
class PatchChange;
class ItemCounts;
class CursorContext;
class VelocityGhostRegion;
class MidiRegionView : public RegionView
{
@ -286,6 +287,7 @@ public:
void goto_next_note (bool add_to_selection);
void change_note_lengths (bool, bool, Temporal::Beats beats, bool start, bool end);
void change_velocities (bool up, bool fine, bool allow_smush, bool all_together);
void set_velocity (NoteBase* primary, int velocity);
void transpose (bool up, bool fine, bool allow_smush);
void nudge_notes (bool forward, bool fine);
void channel_edit ();
@ -502,6 +504,7 @@ public:
std::shared_ptr<PatchChange> find_canvas_patch_change (ARDOUR::MidiModel::PatchChangePtr p);
std::shared_ptr<SysEx> find_canvas_sys_ex (ARDOUR::MidiModel::SysExPtr s);
friend class VelocityGhostRegion;
void update_note (NoteBase*, bool update_ghost_regions = true);
void update_sustained (Note *, bool update_ghost_regions = true);
void update_hit (Hit *, bool update_ghost_regions = true);

View File

@ -79,6 +79,8 @@ VelocityGhostRegion::add_note (NoteBase* nb)
events.insert (std::make_pair (nb->note(), event));
l->Event.connect (sigc::bind (sigc::mem_fun (*this, &VelocityGhostRegion::lollevent), event));
l->raise_to_top ();
l->set_data (X_("ghostregionview"), this);
l->set_data (X_("note"), nb);
event->item->set_fill_color (UIConfiguration::instance().color_mod(nb->base_color(), "ghost track midi fill"));
event->item->set_outline_color (_outline);
@ -125,3 +127,45 @@ VelocityGhostRegion::set_colors ()
{
base_rect->set_fill_color (Gtkmm2ext::Color (0xff000085));
}
void
VelocityGhostRegion::drag_lolli (ArdourCanvas::Lollipop* l, GdkEventMotion* ev)
{
ArdourCanvas::Rect r (base_rect->item_to_window (base_rect->get()));
/* translate event y-coord so that zero matches the top of base_rect */
ev->y -= r.y0;
/* clamp y to be within the range defined by the base_rect height minus
* the lollipop radius at top and bottom
*/
const double effective_y = std::max (lollipop_radius, std::min (r.height() - (2.0 * lollipop_radius), ev->y));
std::cerr << "new y " << effective_y << std::endl;
l->set (ArdourCanvas::Duple (l->x(), effective_y), r.height() - effective_y - lollipop_radius, lollipop_radius);
}
int
VelocityGhostRegion::y_position_to_velocity (double y) const
{
const ArdourCanvas::Rect r (base_rect->get());
int velocity;
std::cerr << "y = " << y << " h = " << r.height() << std::endl;
if (y >= r.height() - (2.0 * lollipop_radius)) {
velocity = 0;
} else if (y <= lollipop_radius) {
velocity = 127;
} else {
velocity = floor (127. * ((r.height() - y) / r.height()));
}
std::cerr << " y = " << y << " vel = " << velocity << std::endl;
return velocity;
}

View File

@ -23,6 +23,10 @@
#include "ghostregion.h"
namespace ArdourCanvas {
class Lollipop;
}
class VelocityGhostRegion : public MidiGhostRegion
{
public:
@ -36,6 +40,9 @@ public:
void remove_note (NoteBase*);
void set_colors ();
void drag_lolli (ArdourCanvas::Lollipop* l, GdkEventMotion* ev);
int y_position_to_velocity (double y) const;
private:
bool lollevent (GdkEvent*, MidiGhostRegion::GhostEvent*);

View File

@ -152,7 +152,6 @@ gtk2_ardour_sources = [
'level_meter.cc',
'library_download_dialog.cc',
'location_ui.cc',
'lollipop.cc',
'loudness_dialog.cc',
'loudness_settings.cc',
'lua_script_manager.cc',