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) {
if (dirty) {
widget->flags |= WIDGET_DIRTY;
// Also set parent, if any.
if (widget->parent) widgetDirtySet(widget->parent, 1);
} else {
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) {
if (raw) {
widget->flags |= WIDGET_RAW_INPUT;

View file

@ -50,6 +50,8 @@ struct WindowS;
typedef void (*GuiCallbackT)(void *data, ...);
typedef void (*WidgetEventT)(struct WidgetS *widget, ...);
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 {
int16_t x;
@ -76,6 +78,7 @@ typedef struct RegisterS {
WidgetEventT destroy; // Destroy routine.
WidgetEventT paint; // Paint routine.
GuiCallbackT unregister; // Unregister routine.
WidgetFindT findWidget; // Returns widget located under cursor.
} RegisterT;
typedef struct WidgetS {
@ -144,18 +147,19 @@ void guiShutdown(void);
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth);
void guiStop(void);
void widgetAdd(WidgetT *target, int16_t x, int16_t y, WidgetT *widget);
void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h);
uint8_t widgetChildrenDirty(WidgetT *widget);
uint8_t widgetChildrenPaint(WidgetT *widget);
void widgetDestroy(WidgetT *widget);
uint8_t widgetDirtyGet(WidgetT *widget);
void widgetDirtySet(WidgetT *widget, uint8_t dirty);
void widgetInputSetRaw(WidgetT *widget, uint8_t raw);
uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent);
void widgetMove(WidgetT *widget, int16_t x, int16_t y);
void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y);
void widgetRemove(WidgetT *target, WidgetT *widget);
void widgetAdd(WidgetT *target, int16_t x, int16_t y, WidgetT *widget);
void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h);
uint8_t widgetChildrenDirty(WidgetT *widget);
uint8_t widgetChildrenPaint(WidgetT *widget);
void widgetDestroy(WidgetT *widget);
uint8_t widgetDirtyGet(WidgetT *widget);
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);
uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent);
void widgetMove(WidgetT *widget, int16_t x, int16_t y);
void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y);
void widgetRemove(WidgetT *target, WidgetT *widget);
#endif // GUI_H

View file

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

View file

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

View file

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

View file

@ -141,10 +141,11 @@ static void labelPaint(struct WidgetS *widget, ...) {
RegisterT *labelRegister(uint8_t magic) {
static RegisterT reg = {
"Label",
NULL, // No default on-click handler.
NULL, // No default on-click handler.
labelDestroy,
labelPaint,
NULL // No unregister handler.
NULL, // No unregister handler.
widgetFinder
};
// One-time widget startup code.

View file

@ -79,10 +79,11 @@ static void picturePaint(struct WidgetS *widget, ...) {
RegisterT *pictureRegister(uint8_t magic) {
static RegisterT reg = {
"Picture",
NULL, // No default on-click handler.
NULL, // No default on-click handler.
pictureDestroy,
picturePaint,
NULL // No unregister handler.
NULL, // No unregister handler.
widgetFinder
};
// One-time widget startup code.

View file

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

View file

@ -32,10 +32,11 @@
uint8_t __MAGIC_SCROLLABLE = 0;
static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
static void scrollableDestroy(struct WidgetS *widget, ...);
static void scrollableFixupSizes(ScrollableT *s);
static void scrollablePaint(struct WidgetS *widget, ...);
static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
static void scrollableDestroy(struct WidgetS *widget, ...);
static void scrollableFixupSizes(ScrollableT *s);
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) {
@ -203,7 +204,8 @@ RegisterT *scrollableRegister(uint8_t magic) {
NULL, // No default on-click handler.
scrollableDestroy,
scrollablePaint,
NULL // No unregister handler.
NULL, // No unregister handler.
scrollableWidgetFinder
};
// One-time widget startup code.
@ -214,7 +216,10 @@ RegisterT *scrollableRegister(uint8_t magic) {
int32_t scrollableValueHGet(ScrollableT *scroll) {
return hscrollValueGet(scroll->scrollh);
if (scroll->scrollh) {
return hscrollValueGet(scroll->scrollh);
}
return 0;
}
@ -226,7 +231,10 @@ void scrollableValueHSet(ScrollableT *scroll, int32_t value) {
int32_t scrollableValueVGet(ScrollableT *scroll) {
return vscrollValueGet(scroll->scrollv);
if (scroll->scrollh) {
return vscrollValueGet(scroll->scrollv);
}
return 0;
}
@ -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) {
int32_t in = 0;
if (scroll->scrollh) in = hscrollValueGet(scroll->scrollh);

View file

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

View file

@ -36,11 +36,10 @@ static WindowT *_windowTop = NULL;
static int16_t _iconCount = 0;
static void windowCache(WindowT *w, uint8_t redrawWindow);
static void windowDestroy(struct WidgetS *widget, ...);
static void windowPaint(struct WidgetS *widget, ...);
static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *localX, int16_t *localY);
static void windowCache(WindowT *w, uint8_t redrawWindow);
static void windowDestroy(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 void windowCache(WindowT *w, uint8_t redrawWindow) {
@ -562,7 +561,8 @@ RegisterT *windowRegister(uint8_t magic) {
NULL, // Click event is special for windows.
windowDestroy, // Destroy.
windowPaint, // Paint.
NULL // Unregister.
NULL, // Unregister.
windowWidgetFinder
};
// 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;
// Too big? Horizontal.
// Get the current view offset.
x = scrollableValueHGet(win->scroll);
// Width of content area of window.
content = win->bounds.x2 - win->bounds.x + 1;
// 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;
// Too big? Vertical.
// Get the current view offset.
y = scrollableValueVGet(win->scroll);
// Height of content area of window.
content = win->bounds.y2 - win->bounds.y + 1;
// 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) {
uint16_t i;
@ -636,8 +664,7 @@ void wmStartup(void) {
void wmUpdate(EventT *event) {
int16_t i;
int16_t windowLocalX;
int16_t windowLocalY;
PointT widgetLocal;
int16_t x2;
int16_t y2;
uint8_t onResize = 0;
@ -682,7 +709,7 @@ void wmUpdate(EventT *event) {
x2 = win->base.r.x + win->base.r.w - 1;
y2 = win->base.r.y + win->base.r.h - 1;
// Are we over a widget?
widgetOver = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
widgetOver = windowWidgetFinder(W(win), event->x, event->y, &widgetLocal.x, &widgetLocal.y);
} else {
x2 = 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->reg->click) {
rawEvent.event = event;
rawEvent.data = widget->data;
//logWrite("Firing raw click for %s\n", widgetOver->reg->widgetName);
widgetOver->reg->click(widgetOver, windowLocalX - widgetOver->r.x, windowLocalY - widgetOver->r.y, CLICK_RAW_INPUT, &rawEvent);
rawEvent.data = widgetOver->data;
widgetOver->reg->click(widgetOver, widgetLocal.x, widgetLocal.y, CLICK_RAW_INPUT, &rawEvent);
}
return;
}
@ -765,10 +791,9 @@ void wmUpdate(EventT *event) {
}
// Are we over a widget?
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
if (widget) {
if (widget->reg->click) widget->reg->click(widget, windowLocalX - widget->r.x, windowLocalY - widget->r.y, CLICK_LEFT_DOWN, widget->data);
widgetDown = widget;
if (widgetOver) {
if (widgetOver->reg->click) widgetOver->reg->click(widgetOver, widgetLocal.x, widgetLocal.y, CLICK_LEFT_DOWN, widgetOver->data);
widgetDown = widgetOver;
}
// 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?
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?
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
// Send to widget for processing or send cancel. Convert mouse to widget-local coordinates.
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);
widget = windowWidgetFinder(W(win), event->x, event->y, &widgetLocal.x, &widgetLocal.y);
// Send to widget for processing or send cancel.
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
@ -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) {
return _windowTop;
}