Widget clicking now working properly with containers.

This commit is contained in:
Scott Duensing 2022-09-03 18:52:37 -05:00
parent 7bd4d41582
commit 9b0eb302a8
11 changed files with 132 additions and 86 deletions

View file

@ -287,12 +287,23 @@ uint8_t widgetDirtyGet(WidgetT *widget) {
void widgetDirtySet(WidgetT *widget, uint8_t dirty) { void widgetDirtySet(WidgetT *widget, uint8_t dirty) {
if (dirty) { if (dirty) {
widget->flags |= WIDGET_DIRTY; widget->flags |= WIDGET_DIRTY;
// Also set parent, if any.
if (widget->parent) widgetDirtySet(widget->parent, 1);
} else { } else {
widget->flags &= ~WIDGET_DIRTY; widget->flags &= ~WIDGET_DIRTY;
} }
} }
WidgetT *widgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY) {
// Find mouse position in widget-local space.
*localX = x - widget->r.x;
*localY = y - widget->r.y;
// By default, widgets just return themselves. Widgets such as scrollarea, window, frame, etc. that contain other widgets will need to override this.
return widget;
}
void widgetInputSetRaw(WidgetT *widget, uint8_t raw) { void widgetInputSetRaw(WidgetT *widget, uint8_t raw) {
if (raw) { if (raw) {
widget->flags |= WIDGET_RAW_INPUT; widget->flags |= WIDGET_RAW_INPUT;

View file

@ -50,6 +50,8 @@ struct WindowS;
typedef void (*GuiCallbackT)(void *data, ...); typedef void (*GuiCallbackT)(void *data, ...);
typedef void (*WidgetEventT)(struct WidgetS *widget, ...); typedef void (*WidgetEventT)(struct WidgetS *widget, ...);
typedef void (*ClickHandlerT)(struct WidgetS *widget, uint16_t x, uint16_t y, uint8_t event, void *data); typedef void (*ClickHandlerT)(struct WidgetS *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
typedef struct WidgetS *(*WidgetFindT)(struct WidgetS *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY);
typedef struct PointS { typedef struct PointS {
int16_t x; int16_t x;
@ -76,6 +78,7 @@ typedef struct RegisterS {
WidgetEventT destroy; // Destroy routine. WidgetEventT destroy; // Destroy routine.
WidgetEventT paint; // Paint routine. WidgetEventT paint; // Paint routine.
GuiCallbackT unregister; // Unregister routine. GuiCallbackT unregister; // Unregister routine.
WidgetFindT findWidget; // Returns widget located under cursor.
} RegisterT; } RegisterT;
typedef struct WidgetS { typedef struct WidgetS {
@ -151,6 +154,7 @@ uint8_t widgetChildrenPaint(WidgetT *widget);
void widgetDestroy(WidgetT *widget); void widgetDestroy(WidgetT *widget);
uint8_t widgetDirtyGet(WidgetT *widget); uint8_t widgetDirtyGet(WidgetT *widget);
void widgetDirtySet(WidgetT *widget, uint8_t dirty); void widgetDirtySet(WidgetT *widget, uint8_t dirty);
WidgetT *widgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY);
void widgetInputSetRaw(WidgetT *widget, uint8_t raw); void widgetInputSetRaw(WidgetT *widget, uint8_t raw);
uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent); uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent);
void widgetMove(WidgetT *widget, int16_t x, int16_t y); void widgetMove(WidgetT *widget, int16_t x, int16_t y);

View file

@ -124,7 +124,8 @@ RegisterT *buttonRegister(uint8_t magic) {
buttonClick, buttonClick,
buttonDestroy, buttonDestroy,
buttonPaint, buttonPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -120,7 +120,8 @@ RegisterT *checkboxRegister(uint8_t magic) {
checkboxClick, checkboxClick,
checkboxDestroy, checkboxDestroy,
checkboxPaint, checkboxPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -233,7 +233,8 @@ RegisterT *hscrollRegister(uint8_t magic) {
hscrollClick, hscrollClick,
hscrollDestroy, hscrollDestroy,
hscrollPaint, hscrollPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -144,7 +144,8 @@ RegisterT *labelRegister(uint8_t magic) {
NULL, // No default on-click handler. NULL, // No default on-click handler.
labelDestroy, labelDestroy,
labelPaint, labelPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -82,7 +82,8 @@ RegisterT *pictureRegister(uint8_t magic) {
NULL, // No default on-click handler. NULL, // No default on-click handler.
pictureDestroy, pictureDestroy,
picturePaint, picturePaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -157,7 +157,8 @@ RegisterT *radioRegister(uint8_t magic) {
radioClick, radioClick,
radioDestroy, radioDestroy,
radioPaint, radioPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -36,6 +36,7 @@ static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint
static void scrollableDestroy(struct WidgetS *widget, ...); static void scrollableDestroy(struct WidgetS *widget, ...);
static void scrollableFixupSizes(ScrollableT *s); static void scrollableFixupSizes(ScrollableT *s);
static void scrollablePaint(struct WidgetS *widget, ...); static void scrollablePaint(struct WidgetS *widget, ...);
static WidgetT *scrollableWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY);
static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) { static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
@ -203,7 +204,8 @@ RegisterT *scrollableRegister(uint8_t magic) {
NULL, // No default on-click handler. NULL, // No default on-click handler.
scrollableDestroy, scrollableDestroy,
scrollablePaint, scrollablePaint,
NULL // No unregister handler. NULL, // No unregister handler.
scrollableWidgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.
@ -214,8 +216,11 @@ RegisterT *scrollableRegister(uint8_t magic) {
int32_t scrollableValueHGet(ScrollableT *scroll) { int32_t scrollableValueHGet(ScrollableT *scroll) {
if (scroll->scrollh) {
return hscrollValueGet(scroll->scrollh); return hscrollValueGet(scroll->scrollh);
} }
return 0;
}
void scrollableValueHSet(ScrollableT *scroll, int32_t value) { void scrollableValueHSet(ScrollableT *scroll, int32_t value) {
@ -226,8 +231,11 @@ void scrollableValueHSet(ScrollableT *scroll, int32_t value) {
int32_t scrollableValueVGet(ScrollableT *scroll) { int32_t scrollableValueVGet(ScrollableT *scroll) {
if (scroll->scrollh) {
return vscrollValueGet(scroll->scrollv); return vscrollValueGet(scroll->scrollv);
} }
return 0;
}
void scrollableValueVSet(ScrollableT *scroll, int32_t value) { void scrollableValueVSet(ScrollableT *scroll, int32_t value) {
@ -237,6 +245,32 @@ void scrollableValueVSet(ScrollableT *scroll, int32_t value) {
} }
static WidgetT *scrollableWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY) {
int16_t i;
ScrollableT *scroll = (ScrollableT *)widget;
WidgetT *w;
PointT p;
// Widget local mouse position.
*localX = x - widget->r.x + scroll->offset.x;
*localY = y - widget->r.y + scroll->offset.y;
// Find widget under mouse.
for (i=0; i<arrlen(widget->children); i++) {
w = widget->children[i];
if (*localX >= w->r.x && *localX < w->r.x + w->r.w && *localY >= w->r.y && *localY < w->r.y + w->r.h) {
// Ask this widget who we're pointing at.
p.x = *localX;
p.y = *localY;
return w->reg->findWidget(w, p.x, p.y, localX, localY);
}
}
// Didn't find a widget.
return NULL;
}
void scrollableWidthSet(ScrollableT *scroll, int16_t w) { void scrollableWidthSet(ScrollableT *scroll, int16_t w) {
int32_t in = 0; int32_t in = 0;
if (scroll->scrollh) in = hscrollValueGet(scroll->scrollh); if (scroll->scrollh) in = hscrollValueGet(scroll->scrollh);

View file

@ -243,7 +243,8 @@ RegisterT *vscrollRegister(uint8_t magic) {
vscrollClick, vscrollClick,
vscrollDestroy, vscrollDestroy,
vscrollPaint, vscrollPaint,
NULL // No unregister handler. NULL, // No unregister handler.
widgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.

View file

@ -39,8 +39,7 @@ static int16_t _iconCount = 0;
static void windowCache(WindowT *w, uint8_t redrawWindow); static void windowCache(WindowT *w, uint8_t redrawWindow);
static void windowDestroy(struct WidgetS *widget, ...); static void windowDestroy(struct WidgetS *widget, ...);
static void windowPaint(struct WidgetS *widget, ...); static void windowPaint(struct WidgetS *widget, ...);
static WidgetT *windowWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY);
static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *localX, int16_t *localY);
static void windowCache(WindowT *w, uint8_t redrawWindow) { static void windowCache(WindowT *w, uint8_t redrawWindow) {
@ -562,7 +561,8 @@ RegisterT *windowRegister(uint8_t magic) {
NULL, // Click event is special for windows. NULL, // Click event is special for windows.
windowDestroy, // Destroy. windowDestroy, // Destroy.
windowPaint, // Paint. windowPaint, // Paint.
NULL // Unregister. NULL, // Unregister.
windowWidgetFinder
}; };
// One-time widget startup code. // One-time widget startup code.
@ -588,8 +588,6 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) {
if (height < (GADGET_SIZE * 4) + chrome.y) height = (GADGET_SIZE * 4) + chrome.y; if (height < (GADGET_SIZE * 4) + chrome.y) height = (GADGET_SIZE * 4) + chrome.y;
// Too big? Horizontal. // Too big? Horizontal.
// Get the current view offset.
x = scrollableValueHGet(win->scroll);
// Width of content area of window. // Width of content area of window.
content = win->bounds.x2 - win->bounds.x + 1; content = win->bounds.x2 - win->bounds.x + 1;
// Do we need to take the height of the vertical scroll bar into account? // Do we need to take the height of the vertical scroll bar into account?
@ -599,8 +597,6 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) {
if (width > x) width = x; if (width > x) width = x;
// Too big? Vertical. // Too big? Vertical.
// Get the current view offset.
y = scrollableValueVGet(win->scroll);
// Height of content area of window. // Height of content area of window.
content = win->bounds.y2 - win->bounds.y + 1; content = win->bounds.y2 - win->bounds.y + 1;
// Clamp. // Clamp.
@ -620,6 +616,38 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) {
} }
static WidgetT *windowWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY) {
int16_t i;
PointT br;
WidgetT *w;
// Find window bottom/right bounds.
br.x = widget->r.x + widget->r.w - 1;
br.y = widget->r.y + widget->r.h - 1;
// Are we over the provided window?
if (x <= br.x && x >= widget->r.x && y <= br.y && y >= widget->r.y) {
// Widget local mouse position.
*localX = x - widget->r.x;
*localY = y - widget->r.y;
// Find widget under mouse.
for (i=0; i<arrlen(widget->children); i++) {
w = widget->children[i];
if (*localX >= w->r.x && *localX < w->r.x + w->r.w && *localY >= w->r.y && *localY < w->r.y + w->r.h) {
// Ask this widget who we're pointing at. Reuse 'br'.
br.x = *localX;
br.y = *localY;
w = w->reg->findWidget(w, br.x, br.y, localX, localY);
return w;
}
}
}
// Didn't find a widget.
return NULL;
}
void wmShutdown(void) { void wmShutdown(void) {
uint16_t i; uint16_t i;
@ -636,8 +664,7 @@ void wmStartup(void) {
void wmUpdate(EventT *event) { void wmUpdate(EventT *event) {
int16_t i; int16_t i;
int16_t windowLocalX; PointT widgetLocal;
int16_t windowLocalY;
int16_t x2; int16_t x2;
int16_t y2; int16_t y2;
uint8_t onResize = 0; uint8_t onResize = 0;
@ -682,7 +709,7 @@ void wmUpdate(EventT *event) {
x2 = win->base.r.x + win->base.r.w - 1; x2 = win->base.r.x + win->base.r.w - 1;
y2 = win->base.r.y + win->base.r.h - 1; y2 = win->base.r.y + win->base.r.h - 1;
// Are we over a widget? // Are we over a widget?
widgetOver = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY); widgetOver = windowWidgetFinder(W(win), event->x, event->y, &widgetLocal.x, &widgetLocal.y);
} else { } else {
x2 = 0; x2 = 0;
y2 = 0; y2 = 0;
@ -693,9 +720,8 @@ void wmUpdate(EventT *event) {
if (widgetOver && !widgetDown && !dragging && !resizing && (widgetOver->flags & WIDGET_RAW_INPUT) && (event->buttons != 0)) { if (widgetOver && !widgetDown && !dragging && !resizing && (widgetOver->flags & WIDGET_RAW_INPUT) && (event->buttons != 0)) {
if (widgetOver->reg->click) { if (widgetOver->reg->click) {
rawEvent.event = event; rawEvent.event = event;
rawEvent.data = widget->data; rawEvent.data = widgetOver->data;
//logWrite("Firing raw click for %s\n", widgetOver->reg->widgetName); widgetOver->reg->click(widgetOver, widgetLocal.x, widgetLocal.y, CLICK_RAW_INPUT, &rawEvent);
widgetOver->reg->click(widgetOver, windowLocalX - widgetOver->r.x, windowLocalY - widgetOver->r.y, CLICK_RAW_INPUT, &rawEvent);
} }
return; return;
} }
@ -765,10 +791,9 @@ void wmUpdate(EventT *event) {
} }
// Are we over a widget? // Are we over a widget?
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY); if (widgetOver) {
if (widget) { if (widgetOver->reg->click) widgetOver->reg->click(widgetOver, widgetLocal.x, widgetLocal.y, CLICK_LEFT_DOWN, widgetOver->data);
if (widget->reg->click) widget->reg->click(widget, windowLocalX - widget->r.x, windowLocalY - widget->r.y, CLICK_LEFT_DOWN, widget->data); widgetDown = widgetOver;
widgetDown = widget;
} }
// Are we inside the close button? Does not include button frame on purpose. // Are we inside the close button? Does not include button frame on purpose.
@ -878,9 +903,9 @@ void wmUpdate(EventT *event) {
// Are we still inside the window content? // Are we still inside the window content?
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
// Are we stll over the same widget? // Are we stll over the same widget?
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY); widget = windowWidgetFinder(W(win), event->x, event->y, &widgetLocal.x, &widgetLocal.y);
// Send to widget for processing or send cancel. Convert mouse to widget-local coordinates. // Send to widget for processing or send cancel.
if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, windowLocalX - widgetDown->r.x, windowLocalY - widgetDown->r.y, (widget == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data); if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, widgetLocal.x, widgetLocal.y, (widget == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data);
} }
widgetDown = NULL; widgetDown = NULL;
} // widgetDown } // widgetDown
@ -895,41 +920,6 @@ void wmUpdate(EventT *event) {
} }
static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *localX, int16_t *localY) {
int16_t i;
int16_t x2;
int16_t y2;
PointT offset;
WidgetT *widget;
// If we have scrollbars, get the offset for the view.
if (win->scroll->scrollh) offset.x = hscrollValueGet(win->scroll->scrollh);
if (win->scroll->scrollv) offset.y = vscrollValueGet(win->scroll->scrollv);
// Find window bounds.
x2 = win->base.r.x + win->base.r.w - 1;
y2 = win->base.r.y + win->base.r.h - 1;
// Are we over the provided window?
if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) {
// Find window-local mouse coordinates.
*localX = event->x - win->base.r.x;// + offset.x;
*localY = event->y - win->base.r.y;// + offset.y;
// Find widget under mouse.
for (i=0; i<arrlen(win->base.children); i++) {
widget = win->base.children[i];
if (*localX >= widget->r.x && *localX < widget->r.x + widget->r.w && *localY >= widget->r.y && *localY < widget->r.y + widget->r.h) {
//logWrite("Over %s\n", widget->reg->widgetName);
// Return this widget.
return widget;
}
}
}
return NULL;
}
WindowT *wmWindowOnTopGet(void) { WindowT *wmWindowOnTopGet(void) {
return _windowTop; return _windowTop;
} }