diff --git a/roo-e/src/gui/gui.c b/roo-e/src/gui/gui.c index 16c3f4e..591b444 100644 --- a/roo-e/src/gui/gui.c +++ b/roo-e/src/gui/gui.c @@ -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; diff --git a/roo-e/src/gui/gui.h b/roo-e/src/gui/gui.h index 89d40fa..b506178 100644 --- a/roo-e/src/gui/gui.h +++ b/roo-e/src/gui/gui.h @@ -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 diff --git a/roo-e/src/gui/widgets/button.c b/roo-e/src/gui/widgets/button.c index b9f4508..92d548b 100644 --- a/roo-e/src/gui/widgets/button.c +++ b/roo-e/src/gui/widgets/button.c @@ -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. diff --git a/roo-e/src/gui/widgets/checkbox.c b/roo-e/src/gui/widgets/checkbox.c index aedd846..3fd4af8 100644 --- a/roo-e/src/gui/widgets/checkbox.c +++ b/roo-e/src/gui/widgets/checkbox.c @@ -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. diff --git a/roo-e/src/gui/widgets/hscroll.c b/roo-e/src/gui/widgets/hscroll.c index 4cf36a3..acb1dee 100644 --- a/roo-e/src/gui/widgets/hscroll.c +++ b/roo-e/src/gui/widgets/hscroll.c @@ -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. diff --git a/roo-e/src/gui/widgets/label.c b/roo-e/src/gui/widgets/label.c index f15c716..a43eb86 100644 --- a/roo-e/src/gui/widgets/label.c +++ b/roo-e/src/gui/widgets/label.c @@ -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. diff --git a/roo-e/src/gui/widgets/picture.c b/roo-e/src/gui/widgets/picture.c index 642ca80..b223dce 100644 --- a/roo-e/src/gui/widgets/picture.c +++ b/roo-e/src/gui/widgets/picture.c @@ -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. diff --git a/roo-e/src/gui/widgets/radio.c b/roo-e/src/gui/widgets/radio.c index 27c277b..4d88bea 100644 --- a/roo-e/src/gui/widgets/radio.c +++ b/roo-e/src/gui/widgets/radio.c @@ -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. diff --git a/roo-e/src/gui/widgets/scroll.c b/roo-e/src/gui/widgets/scroll.c index 9b742b8..75ed7c1 100644 --- a/roo-e/src/gui/widgets/scroll.c +++ b/roo-e/src/gui/widgets/scroll.c @@ -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; ichildren); 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); diff --git a/roo-e/src/gui/widgets/vscroll.c b/roo-e/src/gui/widgets/vscroll.c index 583a1c3..245d2df 100644 --- a/roo-e/src/gui/widgets/vscroll.c +++ b/roo-e/src/gui/widgets/vscroll.c @@ -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. diff --git a/roo-e/src/gui/wmwindow.c b/roo-e/src/gui/wmwindow.c index 220369c..4c81f68 100644 --- a/roo-e/src/gui/wmwindow.c +++ b/roo-e/src/gui/wmwindow.c @@ -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; ichildren); 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; ibase.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; }