Skip to content

Commit c53ce6e

Browse files
committed
add mouse_enter() and mouse_exit() for Pd vanilla
with proxy function for canvas messages
1 parent 84e2362 commit c53ce6e

File tree

4 files changed

+147
-9
lines changed

4 files changed

+147
-9
lines changed

pd.lua

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,12 @@ pd._mouseevent = function (object, x, y, event_type)
115115
if event_type == 3 and type(obj.mouse_drag) == "function" then
116116
obj:mouse_drag(x, y)
117117
end
118+
if event_type == 4 and type(obj.mouse_enter) == "function" then
119+
obj:mouse_enter(x, y)
120+
end
121+
if event_type == 5 and type(obj.mouse_exit) == "function" then
122+
obj:mouse_exit(x, y)
123+
end
118124
end
119125
end
120126

pdlua.c

Lines changed: 119 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,14 @@ typedef struct pdlua_proxyclock
238238
struct pdlua *owner; /**< Object to forward messages to. */
239239
t_clock *clock; /** Pd clock to use. */
240240
} t_pdlua_proxyclock;
241+
242+
/** Proxy canvas object data. */
243+
typedef struct pdlua_proxycanvas
244+
{
245+
t_pd pd; /**< Minimal Pd object. */
246+
t_symbol *p_sym; /**< The name of the canvas. */
247+
struct pdlua *p_parent; /**< The parent object. */
248+
} t_pdlua_proxycanvas;
241249
/* prototypes*/
242250

243251
static const char *pdlua_reader (lua_State *L, void *rr, size_t *size);
@@ -263,6 +271,12 @@ static t_pdlua_proxyclock *pdlua_proxyclock_new (struct pdlua *owner);
263271
static void pdlua_proxyclock_setup (void);
264272
/** Dump an array of atoms into a Lua table. */
265273
static void pdlua_pushatomtable (int argc, t_atom *argv);
274+
/** Proxy canvas 'anything' method. */
275+
static void pdlua_proxycanvas_anything(t_pdlua_proxycanvas *p, t_symbol *s, int argc, t_atom *argv);
276+
/** Proxy canvas allocation and initialization. */
277+
static t_pdlua_proxycanvas *pdlua_proxycanvas_new(struct pdlua *owner, t_symbol *name);
278+
/** Register the proxy canvas class with Pd. */
279+
static void pdlua_proxycanvas_setup(void);
266280
/** Pd object constructor. */
267281
static t_pdlua *pdlua_new (t_symbol *s, int argc, t_atom *argv);
268282
/** Pd object destructor. */
@@ -346,12 +360,15 @@ void pdlua_setup (void);
346360
struct pdlua_proxyinlet;
347361
struct pdlua_proxyreceive;
348362
struct pdlua_proxyclock;
363+
struct pdlua_proxycanvas;
349364
/** Proxy inlet class pointer. */
350365
static t_class *pdlua_proxyinlet_class;
351366
/** Proxy receive class pointer. */
352367
static t_class *pdlua_proxyreceive_class;
353368
/** Proxy clock class pointer. */
354369
static t_class *pdlua_proxyclock_class;
370+
/** Proxy canvas class pointer. */
371+
static t_class *pdlua_proxycanvas_class;
355372

356373
/** Lua file reader callback. */
357374
static const char *pdlua_reader
@@ -378,6 +395,64 @@ static const char *pdlua_reader
378395
}
379396
}
380397

398+
static void pdlua_proxycanvas_anything(t_pdlua_proxycanvas *p, t_symbol *s, int argc, t_atom *argv) {
399+
#if !PLUGDATA
400+
// Early returns for invalid conditions
401+
if (!p->p_parent) return;
402+
if (s != gensym("motion")) return;
403+
if (argc != 3) return;
404+
405+
t_pdlua *x = p->p_parent;
406+
if (!x->has_gui || x->gfx.mouse_down) return;
407+
408+
float new_x = atom_getfloat(argv);
409+
float new_y = atom_getfloat(argv + 1);
410+
411+
int zoom = glist_getzoom(x->canvas);
412+
int obj_x = text_xpix(&x->pd, x->canvas);
413+
int obj_y = text_ypix(&x->pd, x->canvas);
414+
415+
int xpos = (new_x - obj_x) / zoom;
416+
int ypos = (new_y - obj_y) / zoom;
417+
418+
int inside = (xpos >= 0 && xpos < x->gfx.width &&
419+
ypos >= 0 && ypos < x->gfx.height);
420+
421+
// Handle state changes first
422+
if (!inside && x->gfx.mouse_inside) {
423+
pdlua_gfx_mouse_exit(x, xpos, ypos);
424+
x->gfx.mouse_inside = 0;
425+
} else if (inside && !x->gfx.mouse_inside) {
426+
pdlua_gfx_mouse_enter(x, xpos, ypos);
427+
x->gfx.mouse_inside = 1;
428+
}
429+
430+
// Only then send move event if we're inside
431+
if (inside) {
432+
pdlua_gfx_mouse_move(x, xpos, ypos);
433+
}
434+
435+
x->gfx.mouse_x = new_x;
436+
x->gfx.mouse_y = new_y;
437+
#endif
438+
}
439+
440+
static t_pdlua_proxycanvas *pdlua_proxycanvas_new(t_pdlua *x, t_symbol *s) {
441+
t_pdlua_proxycanvas *p = (t_pdlua_proxycanvas *)pd_new(pdlua_proxycanvas_class);
442+
p->pd = pdlua_proxycanvas_class;
443+
p->p_sym = s;
444+
p->p_parent = x;
445+
pd_bind(&p->pd, p->p_sym);
446+
return p;
447+
}
448+
449+
static void pdlua_proxycanvas_free(t_pdlua_proxycanvas *p) {
450+
if (!p) return;
451+
if (p->p_sym) {
452+
pd_unbind(&p->pd, p->p_sym);
453+
}
454+
}
455+
381456
/** Proxy inlet 'anything' method. */
382457
static void pdlua_proxyinlet_anything
383458
(
@@ -494,6 +569,18 @@ static void pdlua_proxyclock_setup(void)
494569
pdlua_proxyclock_class = class_new(gensym("pdlua proxy clock"), 0, 0, sizeof(t_pdlua_proxyclock), 0, 0);
495570
}
496571

572+
/** Setup the proxy class for canvas events. */
573+
static void pdlua_proxycanvas_setup(void)
574+
{
575+
pdlua_proxycanvas_class = class_new(
576+
gensym("pdlua proxy canvas"), 0,
577+
(t_method)pdlua_proxycanvas_free,
578+
sizeof(t_pdlua_proxycanvas), 0, 0);
579+
if (pdlua_proxycanvas_class)
580+
class_addanything(pdlua_proxycanvas_class, (t_method)pdlua_proxycanvas_anything);
581+
PDLUA_DEBUG("pdlua proxy canvas setup done", 0);
582+
}
583+
497584
/** Dump an array of atoms into a Lua table. */
498585
static void pdlua_pushatomtable
499586
(
@@ -714,9 +801,24 @@ static t_pdlua *pdlua_new
714801
if (lua_islightuserdata(__L(), -1))
715802
{
716803
object = lua_touserdata(__L(), -1);
804+
805+
// Create canvas proxy if we have GUI
806+
if (object->has_gui) {
807+
t_canvas *parent_canvas = glist_getcanvas(object->canvas);
808+
char buf[MAXPDSTRING];
809+
snprintf(buf, MAXPDSTRING-1, ".x%lx", (unsigned long)parent_canvas);
810+
object->gfx.proxycanvas = pdlua_proxycanvas_new(object, gensym(buf));
811+
if (!object->gfx.proxycanvas) {
812+
pd_error(NULL, "pdlua: failed to create canvas proxy");
813+
pd_free((t_pd *)object);
814+
lua_pop(__L(), 2);
815+
return NULL;
816+
}
817+
}
818+
717819
lua_pop(__L(), 2);/* pop the userdata and the global "pd" */
718820
PDLUA_DEBUG2("pdlua_new: before returning object %p stack top %d", object, lua_gettop(__L()));
719-
return object;
821+
return object;
720822
}
721823
else
722824
{
@@ -800,6 +902,14 @@ static void pdlua_motion(t_gobj *z, t_floatarg dx, t_floatarg dy,
800902
int ypos = (x->gfx.mouse_y - text_ypix(&x->pd, x->canvas)) / zoom;
801903
pdlua_gfx_mouse_up(x, xpos, ypos);
802904
x->gfx.mouse_down = 0;
905+
906+
// After mouse up, check if we need to send exit
907+
int inside = (xpos >= 0 && xpos < x->gfx.width &&
908+
ypos >= 0 && ypos < x->gfx.height);
909+
if (!inside && x->gfx.mouse_inside) {
910+
pdlua_gfx_mouse_exit(x, xpos, ypos);
911+
x->gfx.mouse_inside = 0;
912+
}
803913
return;
804914
}
805915
#endif
@@ -835,11 +945,11 @@ static int pdlua_click(t_gobj *z, t_glist *gl, int xpos, int ypos, int shift, in
835945
{
836946
pdlua_gfx_mouse_up(x, xpix, ypix);
837947
x->gfx.mouse_down = 0;
838-
} else {
839-
x->gfx.mouse_x = xpos;
840-
x->gfx.mouse_y = ypos;
841-
pdlua_gfx_mouse_move(x, xpix, ypix);
842948
}
949+
// no move events generated here
950+
// Let the proxy handle all move events
951+
x->gfx.mouse_x = xpos;
952+
x->gfx.mouse_y = ypos;
843953
}
844954
return 1;
845955
} else
@@ -3072,7 +3182,10 @@ void pdlua_setup(void)
30723182
PDLUA_DEBUG("pdlua pdlua_proxyreceive_setup done", 0);
30733183
pdlua_proxyclock_setup();
30743184
PDLUA_DEBUG("pdlua pdlua_proxyclock_setup done", 0);
3075-
if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class)
3185+
pdlua_proxycanvas_setup();
3186+
PDLUA_DEBUG("pdlua pdlua_proxycanvas_setup done", 0);
3187+
3188+
if (! pdlua_proxyinlet_class || ! pdlua_proxyreceive_class || ! pdlua_proxyclock_class || ! pdlua_proxycanvas_class)
30763189
{
30773190
pd_error(NULL, "lua: error creating proxy classes");
30783191
pd_error(NULL, "lua: loader will not be registered!");

pdlua.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/**
1+
/**
22
* This program is free software; you can redistribute it and/or
33
* modify it under the terms of the GNU General Public License
44
* as published by the Free Software Foundation; either version 2
@@ -43,8 +43,9 @@ typedef struct _pdlua_gfx
4343
char current_color[10]; // Keep track of current color
4444

4545
// Variables to keep track of mouse button state and drag position
46-
int mouse_x, mouse_y, mouse_down;
46+
int mouse_x, mouse_y, mouse_down, mouse_inside;
4747
int first_draw;
48+
struct t_pdlua_proxycanvas *proxycanvas;
4849
#else
4950
int current_layer;
5051
void(*plugdata_draw_callback)(void*, int, t_symbol*, int, t_atom*); // Callback to perform drawing in plugdata

pdlua_gfx.h

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,15 @@ static int free_path(lua_State* L);
8383

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

86+
// GUI event handling
87+
void pdlua_gfx_mouse_enter(t_pdlua *x, int xpos, int ypos);
88+
void pdlua_gfx_mouse_exit(t_pdlua *x, int xpos, int ypos);
89+
void pdlua_gfx_mouse_move(t_pdlua *x, int xpos, int ypos);
90+
void pdlua_gfx_mouse_down(t_pdlua *x, int xpos, int ypos);
91+
void pdlua_gfx_mouse_up(t_pdlua *x, int xpos, int ypos);
92+
void pdlua_gfx_mouse_drag(t_pdlua *x, int xpos, int ypos);
93+
void pdlua_gfx_mouse_event(t_pdlua *x, int xpos, int ypos, int type);
94+
8695
void pdlua_gfx_free(t_pdlua_gfx *gfx) {
8796
#if !PLUGDATA
8897
for(int i = 0; i < gfx->num_layers; i++)
@@ -149,6 +158,14 @@ void pdlua_gfx_mouse_drag(t_pdlua *o, int x, int y) {
149158
pdlua_gfx_mouse_event(o, x, y, 3);
150159
}
151160

161+
void pdlua_gfx_mouse_enter(t_pdlua *x, int xpos, int ypos) {
162+
pdlua_gfx_mouse_event(x, xpos, ypos, 4);
163+
}
164+
165+
void pdlua_gfx_mouse_exit(t_pdlua *x, int xpos, int ypos) {
166+
pdlua_gfx_mouse_event(x, xpos, ypos, 5);
167+
}
168+
152169
// Represents a path object, created with path.new(x, y)
153170
// for pd-vanilla, this contains all the points that the path contains. bezier curves are flattened out to points before being added
154171
// for plugdata, it only contains a unique ID to the juce::Path that this is mapped to
@@ -793,7 +810,8 @@ static int gfx_initialize(t_pdlua *obj)
793810
gfx->num_transforms = 0;
794811
gfx->num_layers = 0;
795812
gfx->layer_tags = NULL;
796-
813+
gfx->mouse_inside = 0;
814+
797815
pdlua_gfx_repaint(obj, 0);
798816
return 0;
799817
}

0 commit comments

Comments
 (0)