Skip to content

Commit

Permalink
add mouse_enter() and mouse_exit() for Pd vanilla
Browse files Browse the repository at this point in the history
with proxy function for canvas messages
  • Loading branch information
ben-wes committed Jan 17, 2025
1 parent 84e2362 commit c53ce6e
Show file tree
Hide file tree
Showing 4 changed files with 147 additions and 9 deletions.
6 changes: 6 additions & 0 deletions pd.lua
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,12 @@ pd._mouseevent = function (object, x, y, event_type)
if event_type == 3 and type(obj.mouse_drag) == "function" then
obj:mouse_drag(x, y)
end
if event_type == 4 and type(obj.mouse_enter) == "function" then
obj:mouse_enter(x, y)
end
if event_type == 5 and type(obj.mouse_exit) == "function" then
obj:mouse_exit(x, y)
end
end
end

Expand Down
125 changes: 119 additions & 6 deletions pdlua.c
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,14 @@ typedef struct pdlua_proxyclock
struct pdlua *owner; /**< Object to forward messages to. */
t_clock *clock; /** Pd clock to use. */
} t_pdlua_proxyclock;

/** Proxy canvas object data. */
typedef struct pdlua_proxycanvas
{
t_pd pd; /**< Minimal Pd object. */
t_symbol *p_sym; /**< The name of the canvas. */
struct pdlua *p_parent; /**< The parent object. */
} t_pdlua_proxycanvas;
/* prototypes*/

static const char *pdlua_reader (lua_State *L, void *rr, size_t *size);
Expand All @@ -263,6 +271,12 @@ static t_pdlua_proxyclock *pdlua_proxyclock_new (struct pdlua *owner);
static void pdlua_proxyclock_setup (void);
/** Dump an array of atoms into a Lua table. */
static void pdlua_pushatomtable (int argc, t_atom *argv);
/** Proxy canvas 'anything' method. */
static void pdlua_proxycanvas_anything(t_pdlua_proxycanvas *p, t_symbol *s, int argc, t_atom *argv);
/** Proxy canvas allocation and initialization. */
static t_pdlua_proxycanvas *pdlua_proxycanvas_new(struct pdlua *owner, t_symbol *name);
/** Register the proxy canvas class with Pd. */
static void pdlua_proxycanvas_setup(void);
/** Pd object constructor. */
static t_pdlua *pdlua_new (t_symbol *s, int argc, t_atom *argv);
/** Pd object destructor. */
Expand Down Expand Up @@ -346,12 +360,15 @@ void pdlua_setup (void);
struct pdlua_proxyinlet;
struct pdlua_proxyreceive;
struct pdlua_proxyclock;
struct pdlua_proxycanvas;
/** Proxy inlet class pointer. */
static t_class *pdlua_proxyinlet_class;
/** Proxy receive class pointer. */
static t_class *pdlua_proxyreceive_class;
/** Proxy clock class pointer. */
static t_class *pdlua_proxyclock_class;
/** Proxy canvas class pointer. */
static t_class *pdlua_proxycanvas_class;

/** Lua file reader callback. */
static const char *pdlua_reader
Expand All @@ -378,6 +395,64 @@ static const char *pdlua_reader
}
}

static void pdlua_proxycanvas_anything(t_pdlua_proxycanvas *p, t_symbol *s, int argc, t_atom *argv) {
#if !PLUGDATA
// Early returns for invalid conditions
if (!p->p_parent) return;
if (s != gensym("motion")) return;
if (argc != 3) return;

t_pdlua *x = p->p_parent;
if (!x->has_gui || x->gfx.mouse_down) return;

float new_x = atom_getfloat(argv);
float new_y = atom_getfloat(argv + 1);

int zoom = glist_getzoom(x->canvas);
int obj_x = text_xpix(&x->pd, x->canvas);
int obj_y = text_ypix(&x->pd, x->canvas);

int xpos = (new_x - obj_x) / zoom;
int ypos = (new_y - obj_y) / zoom;

int inside = (xpos >= 0 && xpos < x->gfx.width &&
ypos >= 0 && ypos < x->gfx.height);

// Handle state changes first
if (!inside && x->gfx.mouse_inside) {
pdlua_gfx_mouse_exit(x, xpos, ypos);
x->gfx.mouse_inside = 0;
} else if (inside && !x->gfx.mouse_inside) {
pdlua_gfx_mouse_enter(x, xpos, ypos);
x->gfx.mouse_inside = 1;
}

// Only then send move event if we're inside
if (inside) {
pdlua_gfx_mouse_move(x, xpos, ypos);
}

x->gfx.mouse_x = new_x;
x->gfx.mouse_y = new_y;
#endif
}

static t_pdlua_proxycanvas *pdlua_proxycanvas_new(t_pdlua *x, t_symbol *s) {
t_pdlua_proxycanvas *p = (t_pdlua_proxycanvas *)pd_new(pdlua_proxycanvas_class);
p->pd = pdlua_proxycanvas_class;
p->p_sym = s;
p->p_parent = x;
pd_bind(&p->pd, p->p_sym);
return p;
}

static void pdlua_proxycanvas_free(t_pdlua_proxycanvas *p) {
if (!p) return;
if (p->p_sym) {
pd_unbind(&p->pd, p->p_sym);
}
}

/** Proxy inlet 'anything' method. */
static void pdlua_proxyinlet_anything
(
Expand Down Expand Up @@ -494,6 +569,18 @@ static void pdlua_proxyclock_setup(void)
pdlua_proxyclock_class = class_new(gensym("pdlua proxy clock"), 0, 0, sizeof(t_pdlua_proxyclock), 0, 0);
}

/** Setup the proxy class for canvas events. */
static void pdlua_proxycanvas_setup(void)
{
pdlua_proxycanvas_class = class_new(
gensym("pdlua proxy canvas"), 0,
(t_method)pdlua_proxycanvas_free,
sizeof(t_pdlua_proxycanvas), 0, 0);
if (pdlua_proxycanvas_class)
class_addanything(pdlua_proxycanvas_class, (t_method)pdlua_proxycanvas_anything);
PDLUA_DEBUG("pdlua proxy canvas setup done", 0);
}

/** Dump an array of atoms into a Lua table. */
static void pdlua_pushatomtable
(
Expand Down Expand Up @@ -714,9 +801,24 @@ static t_pdlua *pdlua_new
if (lua_islightuserdata(__L(), -1))
{
object = lua_touserdata(__L(), -1);

// Create canvas proxy if we have GUI
if (object->has_gui) {
t_canvas *parent_canvas = glist_getcanvas(object->canvas);
char buf[MAXPDSTRING];
snprintf(buf, MAXPDSTRING-1, ".x%lx", (unsigned long)parent_canvas);
object->gfx.proxycanvas = pdlua_proxycanvas_new(object, gensym(buf));
if (!object->gfx.proxycanvas) {
pd_error(NULL, "pdlua: failed to create canvas proxy");
pd_free((t_pd *)object);
lua_pop(__L(), 2);
return NULL;
}
}

lua_pop(__L(), 2);/* pop the userdata and the global "pd" */
PDLUA_DEBUG2("pdlua_new: before returning object %p stack top %d", object, lua_gettop(__L()));
return object;
return object;
}
else
{
Expand Down Expand Up @@ -800,6 +902,14 @@ static void pdlua_motion(t_gobj *z, t_floatarg dx, t_floatarg dy,
int ypos = (x->gfx.mouse_y - text_ypix(&x->pd, x->canvas)) / zoom;
pdlua_gfx_mouse_up(x, xpos, ypos);
x->gfx.mouse_down = 0;

// After mouse up, check if we need to send exit
int inside = (xpos >= 0 && xpos < x->gfx.width &&
ypos >= 0 && ypos < x->gfx.height);
if (!inside && x->gfx.mouse_inside) {
pdlua_gfx_mouse_exit(x, xpos, ypos);
x->gfx.mouse_inside = 0;
}
return;
}
#endif
Expand Down Expand Up @@ -835,11 +945,11 @@ static int pdlua_click(t_gobj *z, t_glist *gl, int xpos, int ypos, int shift, in
{
pdlua_gfx_mouse_up(x, xpix, ypix);
x->gfx.mouse_down = 0;
} else {
x->gfx.mouse_x = xpos;
x->gfx.mouse_y = ypos;
pdlua_gfx_mouse_move(x, xpix, ypix);
}
// no move events generated here
// Let the proxy handle all move events
x->gfx.mouse_x = xpos;
x->gfx.mouse_y = ypos;
}
return 1;
} else
Expand Down Expand Up @@ -3072,7 +3182,10 @@ void pdlua_setup(void)
PDLUA_DEBUG("pdlua pdlua_proxyreceive_setup done", 0);
pdlua_proxyclock_setup();
PDLUA_DEBUG("pdlua pdlua_proxyclock_setup done", 0);
if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class)
pdlua_proxycanvas_setup();
PDLUA_DEBUG("pdlua pdlua_proxycanvas_setup done", 0);

if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class || ! pdlua_proxycanvas_class)
{
pd_error(NULL, "lua: error creating proxy classes");
pd_error(NULL, "lua: loader will not be registered!");
Expand Down
5 changes: 3 additions & 2 deletions pdlua.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/**
/**
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
Expand Down Expand Up @@ -43,8 +43,9 @@ typedef struct _pdlua_gfx
char current_color[10]; // Keep track of current color

// Variables to keep track of mouse button state and drag position
int mouse_x, mouse_y, mouse_down;
int mouse_x, mouse_y, mouse_down, mouse_inside;
int first_draw;
struct t_pdlua_proxycanvas *proxycanvas;
#else
int current_layer;
void(*plugdata_draw_callback)(void*, int, t_symbol*, int, t_atom*); // Callback to perform drawing in plugdata
Expand Down
20 changes: 19 additions & 1 deletion pdlua_gfx.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,15 @@ static int free_path(lua_State* L);

static void pdlua_gfx_clear(t_pdlua *obj, int layer, int removed); // only for pd-vanilla, to delete all tcl/tk items

// GUI event handling
void pdlua_gfx_mouse_enter(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_exit(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_move(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_down(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_up(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_drag(t_pdlua *x, int xpos, int ypos);
void pdlua_gfx_mouse_event(t_pdlua *x, int xpos, int ypos, int type);

void pdlua_gfx_free(t_pdlua_gfx *gfx) {
#if !PLUGDATA
for(int i = 0; i < gfx->num_layers; i++)
Expand Down Expand Up @@ -149,6 +158,14 @@ void pdlua_gfx_mouse_drag(t_pdlua *o, int x, int y) {
pdlua_gfx_mouse_event(o, x, y, 3);
}

void pdlua_gfx_mouse_enter(t_pdlua *x, int xpos, int ypos) {
pdlua_gfx_mouse_event(x, xpos, ypos, 4);
}

void pdlua_gfx_mouse_exit(t_pdlua *x, int xpos, int ypos) {
pdlua_gfx_mouse_event(x, xpos, ypos, 5);
}

// Represents a path object, created with path.new(x, y)
// for pd-vanilla, this contains all the points that the path contains. bezier curves are flattened out to points before being added
// for plugdata, it only contains a unique ID to the juce::Path that this is mapped to
Expand Down Expand Up @@ -793,7 +810,8 @@ static int gfx_initialize(t_pdlua *obj)
gfx->num_transforms = 0;
gfx->num_layers = 0;
gfx->layer_tags = NULL;

gfx->mouse_inside = 0;

pdlua_gfx_repaint(obj, 0);
return 0;
}
Expand Down

0 comments on commit c53ce6e

Please sign in to comment.