diff options
Diffstat (limited to 'src/gwin')
-rw-r--r-- | src/gwin/gwin_widget.c | 1469 |
1 files changed, 738 insertions, 731 deletions
diff --git a/src/gwin/gwin_widget.c b/src/gwin/gwin_widget.c index 476ee6ba..34b047eb 100644 --- a/src/gwin/gwin_widget.c +++ b/src/gwin/gwin_widget.c @@ -1,731 +1,738 @@ -/* - * This file is subject to the terms of the GFX License. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://ugfx.org/license.html - */ - -/** - * @file src/gwin/gwin_widget.c - * @brief GWIN sub-system widget code - */ - -#include "../../gfx.h" - -#if GFX_USE_GWIN && GWIN_NEED_WIDGET - -#include <string.h> - -#include "gwin_class.h" - -// Our listener for events for widgets -static GListener gl; - -#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD - // Our current focus window - static GHandle _widgetInFocus; -#endif - -// Our default style - a white background theme -const GWidgetStyle WhiteWidgetStyle = { - HTML2COLOR(0xFFFFFF), // window background - HTML2COLOR(0x2A8FCD), // focused - - // enabled color set - { - HTML2COLOR(0x000000), // text - HTML2COLOR(0x404040), // edge - HTML2COLOR(0xE0E0E0), // fill - HTML2COLOR(0x00E000) // progress - active area - }, - - // disabled color set - { - HTML2COLOR(0xC0C0C0), // text - HTML2COLOR(0x808080), // edge - HTML2COLOR(0xE0E0E0), // fill - HTML2COLOR(0xC0E0C0) // progress - active area - }, - - // pressed color set - { - HTML2COLOR(0x404040), // text - HTML2COLOR(0x404040), // edge - HTML2COLOR(0x808080), // fill - HTML2COLOR(0x00E000) // progress - active area - } -}; - -/* Our black style */ -const GWidgetStyle BlackWidgetStyle = { - HTML2COLOR(0x000000), // window background - HTML2COLOR(0x2A8FCD), // focused - - // enabled color set - { - HTML2COLOR(0xC0C0C0), // text - HTML2COLOR(0xC0C0C0), // edge - HTML2COLOR(0x606060), // fill - HTML2COLOR(0x008000) // progress - active area - }, - - // disabled color set - { - HTML2COLOR(0x808080), // text - HTML2COLOR(0x404040), // edge - HTML2COLOR(0x404040), // fill - HTML2COLOR(0x004000) // progress - active area - }, - - // pressed color set - { - HTML2COLOR(0xFFFFFF), // text - HTML2COLOR(0xC0C0C0), // edge - HTML2COLOR(0xE0E0E0), // fill - HTML2COLOR(0x008000) // progress - active area - } -}; - -static const GWidgetStyle * defaultStyle = &BlackWidgetStyle; - -// We use these everywhere in this file -#define gw ((GWidgetObject *)gh) -#define wvmt ((gwidgetVMT *)gh->vmt) - -// Process an event -static void gwidgetEvent(void *param, GEvent *pe) { - #define pme ((GEventMouse *)pe) - #define pke ((GEventKeyboard *)pe) - #define pte ((GEventToggle *)pe) - #define pde ((GEventDial *)pe) - - GHandle h; - GHandle gh; - #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) - uint16_t role; - #endif - (void) param; - - // Process various events - switch (pe->type) { - - #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - case GEVENT_MOUSE: - case GEVENT_TOUCH: - // Cycle through all windows - for (gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) { - - // The window must be on this display and visible to be relevant - if (h->display != pme->display || !(h->flags & GWIN_FLG_SYSVISIBLE)) - continue; - - // Is the mouse currently captured by this widget? - if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) { - gh = h; - if ((pme->buttons & GMETA_MOUSE_UP)) { - gh->flags &= ~GWIN_FLG_MOUSECAPTURE; - if (wvmt->MouseUp) - wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y); - } else if (wvmt->MouseMove) - wvmt->MouseMove(gw, pme->x - gh->x, pme->y - gh->y); - - // There is only ever one captured mouse. Prevent normal mouse processing if there is a captured mouse - gh = 0; - - break; - } - - // Save the highest z-order window that the mouse is over - if (pme->x >= h->x && pme->x < h->x + h->width && pme->y >= h->y && pme->y < h->y + h->height) - gh = h; - } - - // Process any mouse down over the highest order window if it is an enabled widget - if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) { - if ((pme->buttons & GMETA_MOUSE_DOWN)) { - gh->flags |= GWIN_FLG_MOUSECAPTURE; - - #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD - // We should try and capture the focus on this window. - // If we can't then we don't change the focus - gwinSetFocus(gh); - #endif - - if (wvmt->MouseDown) - wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y); - } - } - break; - #endif - - #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD - case GEVENT_KEYBOARD: - // If Tab key pressed then set focus to next widget - if (pke->bytecount == 1 && pke->c[0] == GKEY_TAB) { - if (!(pke->keystate & GKEYSTATE_KEYUP)) - _gwinMoveFocus(); - break; - } - - // Otherwise, send keyboard events only to widget in focus - if (_widgetInFocus) - ((gwidgetVMT*)_widgetInFocus->vmt)->KeyboardEvent((GWidgetObject*)_widgetInFocus, pke); - break; - #endif - - #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - case GEVENT_TOGGLE: - // Cycle through all windows - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - - // check if it a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) - continue; - - for(role = 0; role < wvmt->toggleroles; role++) { - if (wvmt->ToggleGet(gw, role) == pte->instance) { - if (pte->on) { - if (wvmt->ToggleOn) - wvmt->ToggleOn(gw, role); - } else { - if (wvmt->ToggleOff) - wvmt->ToggleOff(gw, role); - } - } - } - } - break; - #endif - - #if GFX_USE_GINPUT && GINPUT_NEED_DIAL - case GEVENT_DIAL: - // Cycle through all windows - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - - // check if it a widget that is enabled and visible - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) - continue; - - for(role = 0; role < wvmt->dialroles; role++) { - if (wvmt->DialGet(gw, role) == pte->instance) { - if (wvmt->DialMove) - wvmt->DialMove(gw, role, pde->value, pde->maxvalue); - } - } - } - break; - #endif - - default: - break; - } - - #undef pme - #undef pte - #undef pke - #undef pde -} - -#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD - GHandle gwinGetFocus(void) { - return _widgetInFocus; - } - - bool_t gwinSetFocus(GHandle gh) { - GHandle oldFocus; - - // Do we already have the focus? - if (gh == _widgetInFocus) - return TRUE; - - // The new window must be NULLL or a visible enabled widget with a keyboard handler - if (!gh || ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) - && ((gwidgetVMT*)gh->vmt)->KeyboardEvent)) { - // Move the current focus - oldFocus = _widgetInFocus; - _widgetInFocus = gh; - if (oldFocus) _gwinUpdate(oldFocus); - if (gh) _gwinUpdate(gh); - return TRUE; - } - return FALSE; - } - - void _gwinMoveFocus(void) { - GHandle gh; - bool_t looponce; - - // Find a new focus window (one may or may not exist). - looponce = FALSE; - for(gh = gwinGetNextWindow(_widgetInFocus); ; gh = gwinGetNextWindow(gh)) { - if (!gh && !looponce) { - looponce = TRUE; - gh = gwinGetNextWindow(0); - } - if (gwinSetFocus(gh)) - break; - } - } - - void _gwinFixFocus(GHandle gh) { - GHandle oldFocus; - - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) - && ((gwidgetVMT*)gh->vmt)->KeyboardEvent) { - - // We are a candidate to be able to claim the focus - - // Claim the focus if no-one else has - if (!_widgetInFocus) - _widgetInFocus = gh; - - return; - } - - // We have lost any right to the focus - - // Did we have the focus - if (gh != _widgetInFocus) - return; - - // We did - we need to find a new focus window - oldFocus = _widgetInFocus; - for(gh = gwinGetNextWindow(oldFocus); gh && gh != oldFocus; gh = gwinGetNextWindow(gh)) { - - // Must be a visible enabled widget with a keyboard handler - if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) - && ((gwidgetVMT*)gh->vmt)->KeyboardEvent) { - - // Grab the focus for the new window - _widgetInFocus = gh; - - // This new window still needs to be marked for redraw (but don't actually do it yet). - gh->flags |= GWIN_FLG_NEEDREDRAW; - // RedrawPending |= DOREDRAW_VISIBLES; - FIX LATER - return; - } - } - - // No-one has the right to the focus - _widgetInFocus = 0; - } - - void _gwidgetDrawFocusRect(GWidgetObject *gx, coord_t x, coord_t y, coord_t cx, coord_t cy) { - coord_t i; - - // Don't do anything if we don't have the focus - if (&gx->g != _widgetInFocus) - return; - - // Use the very simplest possible focus rectangle for now - for (i = 0; i < GWIN_FOCUS_HIGHLIGHT_WIDTH; i++) { - gdispGDrawBox(gx->g.display, gx->g.x+x+i, gx->g.y+y+i, cx-2*i, cy-2*i, gx->pstyle->focus); - } - } - -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - static GHandle FindToggleUser(uint16_t instance) { - GHandle gh; - uint16_t role; - - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget - continue; - - for(role = 0; role < wvmt->toggleroles; role++) { - if (wvmt->ToggleGet(gw, role) == instance) - return gh; - } - } - return 0; - } -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL - static GHandle FindDialUser(uint16_t instance) { - GHandle gh; - uint16_t role; - - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget - continue; - - for(role = 0; role < wvmt->dialroles; role++) { - if (wvmt->DialGet(gw, role) == instance) - return gh; - } - } - return 0; - } -#endif - -void _gwidgetInit(void) -{ - geventListenerInit(&gl); - geventRegisterCallback(&gl, gwidgetEvent, 0); - #if GINPUT_NEED_MOUSE - geventAttachSource(&gl, ginputGetMouse(GMOUSE_ALL_INSTANCES), GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); - #endif - #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD - geventAttachSource(&gl, ginputGetKeyboard(GKEYBOARD_ALL_INSTANCES), GLISTEN_KEYUP); - #endif -} - -void _gwidgetDeinit(void) -{ - /* ToDo */ -} - -GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) { - if (!(pgw = (GWidgetObject *)_gwindowCreate(g, &pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED))) - return 0; - - #if GWIN_NEED_CONTAINERS - // This window can't be system enabled if the parent is not enabled - if (pgw->g.parent && !(pgw->g.parent->flags & GWIN_FLG_SYSENABLED)) - pgw->g.flags &= ~GWIN_FLG_SYSENABLED; - #endif - pgw->text = pInit->text ? pInit->text : ""; - pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw; - pgw->fnParam = pInit->customParam; - pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle; - #if GWIN_WIDGET_TAGS - pgw->tag = pInit->tag; - #endif - - return &pgw->g; -} - -void _gwidgetDestroy(GHandle gh) { - #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) - uint16_t role, instance; - #endif - - // Make the window is invisible so it is not eligible for focus - gh->flags &= ~GWIN_FLG_VISIBLE; - _gwinFixFocus(gh); - - // Deallocate the text (if necessary) - if ((gh->flags & GWIN_FLG_ALLOCTXT)) { - gh->flags &= ~GWIN_FLG_ALLOCTXT; - gfxFree((void *)gw->text); - } - - #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - // Detach any toggles from this object - for(role = 0; role < wvmt->toggleroles; role++) { - instance = wvmt->ToggleGet(gw, role); - if (instance != GWIDGET_NO_INSTANCE) { - wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE); - if (!FindToggleUser(instance)) - geventDetachSource(&gl, ginputGetToggle(instance)); - } - } - #endif - - #if GFX_USE_GINPUT && GINPUT_NEED_DIAL - // Detach any dials from this object - for(role = 0; role < wvmt->dialroles; role++) { - instance = wvmt->DialGet(gw, role); - if (instance != GWIDGET_NO_INSTANCE) { - wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE); - if (!FindDialUser(instance)) - geventDetachSource(&gl, ginputGetDial(instance)); - } - } - #endif - - // Remove any listeners on this object. - geventDetachSourceListeners((GSourceHandle)gh); -} - -void _gwidgetRedraw(GHandle gh) { - if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) - return; - - gw->fnDraw(gw, gw->fnParam); -} - -void _gwinSendEvent(GHandle gh, GEventType type) { - GSourceListener * psl; - GEventGWin * pge; - - // Trigger a GWIN Event - psl = 0; - while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { - if (!(pge = (GEventGWin *)geventGetEventBuffer(psl))) - continue; - pge->type = type; - pge->gwin = gh; - #if GWIN_WIDGET_TAGS - pge->tag = (gh->flags & GWIN_FLG_WIDGET) ? ((GWidgetObject *)gh)->tag : 0; - #endif - geventSendEvent(psl); - } -} - -void gwinWidgetClearInit(GWidgetInit *pwi) { - char *p; - unsigned len; - - for(p = (char *)pwi, len = sizeof(GWidgetInit); len; len--) - *p++ = 0; -} - -void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) { - if (!pstyle) - pstyle = &BlackWidgetStyle; - - if (updateAll) { - GHandle gh; - - for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { - if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle) - gwinSetStyle(gh, pstyle); - else - gwinRedraw(gh); - } - } - gwinSetDefaultBgColor(pstyle->background); - defaultStyle = pstyle; -} - -/** - * @brief Get the current default style. - * - * @api - */ -const GWidgetStyle *gwinGetDefaultStyle(void) { - return defaultStyle; -} - -void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return; - - // Dispose of the old string - if ((gh->flags & GWIN_FLG_ALLOCTXT)) { - gh->flags &= ~GWIN_FLG_ALLOCTXT; - if (gw->text) { - gfxFree((void *)gw->text); - gw->text = ""; - } - } - - // Alloc the new text if required - if (!text || !*text) - gw->text = ""; - else if (useAlloc) { - char *str; - - if ((str = gfxAlloc(strlen(text)+1))) { - gh->flags |= GWIN_FLG_ALLOCTXT; - strcpy(str, text); - } - gw->text = (const char *)str; - } else - gw->text = text; - _gwinUpdate(gh); -} - -#if GFX_USE_GFILE && GFILE_NEED_PRINTG && GFILE_NEED_STRINGS - #include <stdarg.h> - - void gwinPrintg(GHandle gh, const char * fmt, ...) { - char *str; - va_list va; - int size; - - if (!(gh->flags & GWIN_FLG_WIDGET)) - return; - - // Dispose of the old string - if ((gh->flags & GWIN_FLG_ALLOCTXT)) { - gh->flags &= ~GWIN_FLG_ALLOCTXT; - if (gw->text) { - gfxFree((void *)gw->text); - gw->text = ""; - } - } - - // Alloc the new text - va_start (va, fmt); - - size = vsnprintg(0, 0, fmt, va) + 1; //determine the buffer size required - - if ((str = gfxAlloc(size))) { - gh->flags |= GWIN_FLG_ALLOCTXT; - vsnprintg(str, size, fmt, va); - gw->text = (const char *)str; - } else - gw->text = ""; - - va_end (va); - - _gwinUpdate(gh); - } -#endif - -const char *gwinGetText(GHandle gh) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return 0; - - return gw->text; -} - -bool_t gwinIsWidget(GHandle gh) { - if (gh->flags & GWIN_FLG_WIDGET) { - return TRUE; - } - - return FALSE; -} - -void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return; - - gw->pstyle = pstyle ? pstyle : defaultStyle; - gh->bgcolor = gw->pstyle->background; - gh->color = gw->pstyle->enabled.text; - - _gwinUpdate(gh); -} - -const GWidgetStyle *gwinGetStyle(GHandle gh) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return 0; - - return gw->pstyle; -} - -void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return; - - gw->fnDraw = fn ? fn : wvmt->DefaultDraw; - gw->fnParam = param; - _gwinUpdate(gh); -} - -bool_t gwinAttachListener(GListener *pl) { - return geventAttachSource(pl, GWIDGET_SOURCE, 0); -} - -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance) { - // This is now a NULL event because we automatically attach to all mice in the system. - (void) instance; - return TRUE; - } -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { - GSourceHandle gsh; - uint16_t oi; - - // Is this a widget - if (!(gh->flags & GWIN_FLG_WIDGET)) - return FALSE; - - // Is the role valid - if (role >= wvmt->toggleroles) - return FALSE; - - // Is this a valid device - if (!(gsh = ginputGetToggle(instance))) - return FALSE; - - // Is this already done? - oi = wvmt->ToggleGet(gw, role); - if (instance == oi) - return TRUE; - - // Remove the old instance - if (oi != GWIDGET_NO_INSTANCE) { - wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE); - if (!FindToggleUser(oi)) - geventDetachSource(&gl, ginputGetToggle(oi)); - } - - // Assign the new - wvmt->ToggleAssign(gw, role, instance); - return geventAttachSource(&gl, gsh, GLISTEN_TOGGLE_ON|GLISTEN_TOGGLE_OFF); - } - - bool_t gwinDetachToggle(GHandle gh, uint16_t role) { - uint16_t oi; - - // Is this a widget - if (!(gh->flags & GWIN_FLG_WIDGET)) - return FALSE; - - // Is the role valid - if (role >= ((gwidgetVMT *)gh->vmt)->toggleroles) - return FALSE; - - oi = ((gwidgetVMT *)gh->vmt)->ToggleGet(gw, role); - - // Remove the instance - if (oi != GWIDGET_NO_INSTANCE) { - ((gwidgetVMT *)gh->vmt)->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE); - if (!FindToggleUser(oi)) - geventDetachSource(&gl, ginputGetToggle(oi)); - } - return TRUE; - } - -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL - bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) { - GSourceHandle gsh; - uint16_t oi; - - if (!(gh->flags & GWIN_FLG_WIDGET)) - return FALSE; - - // Is the role valid - if (role >= wvmt->dialroles) - return FALSE; - - // Is this a valid device - if (!(gsh = ginputGetDial(instance))) - return FALSE; - - // Is this already done? - oi = wvmt->DialGet(gw, role); - if (instance == oi) - return TRUE; - - // Remove the old instance - if (oi != GWIDGET_NO_INSTANCE) { - wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE); - if (!FindDialUser(oi)) - geventDetachSource(&gl, ginputGetDial(oi)); - } - - // Assign the new - wvmt->DialAssign(gw, role, instance); - return geventAttachSource(&gl, gsh, 0); - } -#endif - -#if GWIN_WIDGET_TAGS - void gwinSetTag(GHandle gh, WidgetTag tag) { - if ((gh->flags & GWIN_FLG_WIDGET)) - gw->tag = tag; - } - - WidgetTag gwinGetTag(GHandle gh) { - return ((gh->flags & GWIN_FLG_WIDGET)) ? gw->tag : 0; - } -#endif - -#undef gw -#undef wvmt -#endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */ -/** @} */ +/*
+ * This file is subject to the terms of the GFX License. If a copy of
+ * the license was not distributed with this file, you can obtain one at:
+ *
+ * http://ugfx.org/license.html
+ */
+
+/**
+ * @file src/gwin/gwin_widget.c
+ * @brief GWIN sub-system widget code
+ */
+
+#include "../../gfx.h"
+
+#if GFX_USE_GWIN && GWIN_NEED_WIDGET
+
+#include <string.h>
+
+#include "gwin_class.h"
+
+// Our listener for events for widgets
+static GListener gl;
+
+#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD
+ // Our current focus window
+ static GHandle _widgetInFocus;
+#endif
+
+// Our default style - a white background theme
+const GWidgetStyle WhiteWidgetStyle = {
+ HTML2COLOR(0xFFFFFF), // window background
+ HTML2COLOR(0x2A8FCD), // focused
+
+ // enabled color set
+ {
+ HTML2COLOR(0x000000), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0x00E000) // progress - active area
+ },
+
+ // disabled color set
+ {
+ HTML2COLOR(0xC0C0C0), // text
+ HTML2COLOR(0x808080), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0xC0E0C0) // progress - active area
+ },
+
+ // pressed color set
+ {
+ HTML2COLOR(0x404040), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0x808080), // fill
+ HTML2COLOR(0x00E000) // progress - active area
+ }
+};
+
+/* Our black style */
+const GWidgetStyle BlackWidgetStyle = {
+ HTML2COLOR(0x000000), // window background
+ HTML2COLOR(0x2A8FCD), // focused
+
+ // enabled color set
+ {
+ HTML2COLOR(0xC0C0C0), // text
+ HTML2COLOR(0xC0C0C0), // edge
+ HTML2COLOR(0x606060), // fill
+ HTML2COLOR(0x008000) // progress - active area
+ },
+
+ // disabled color set
+ {
+ HTML2COLOR(0x808080), // text
+ HTML2COLOR(0x404040), // edge
+ HTML2COLOR(0x404040), // fill
+ HTML2COLOR(0x004000) // progress - active area
+ },
+
+ // pressed color set
+ {
+ HTML2COLOR(0xFFFFFF), // text
+ HTML2COLOR(0xC0C0C0), // edge
+ HTML2COLOR(0xE0E0E0), // fill
+ HTML2COLOR(0x008000) // progress - active area
+ }
+};
+
+static const GWidgetStyle * defaultStyle = &BlackWidgetStyle;
+
+// We use these everywhere in this file
+#define gw ((GWidgetObject *)gh)
+#define wvmt ((gwidgetVMT *)gh->vmt)
+
+// Process an event
+static void gwidgetEvent(void *param, GEvent *pe) {
+ #define pme ((GEventMouse *)pe)
+ #define pke ((GEventKeyboard *)pe)
+ #define pte ((GEventToggle *)pe)
+ #define pde ((GEventDial *)pe)
+
+ #if GFX_USE_GINPUT
+ #if GINPUT_NEED_MOUSE
+ GHandle h;
+ #endif
+ #if GINPUT_NEED_MOUSE || GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL || GINPUT_NEED_KEYBOARD
+ GHandle gh;
+ #endif
+ #if GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL
+ uint16_t role;
+ #endif
+ #endif
+
+ (void) param;
+
+ // Process various events
+ switch (pe->type) {
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+ case GEVENT_MOUSE:
+ case GEVENT_TOUCH:
+ // Cycle through all windows
+ for (gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) {
+
+ // The window must be on this display and visible to be relevant
+ if (h->display != pme->display || !(h->flags & GWIN_FLG_SYSVISIBLE))
+ continue;
+
+ // Is the mouse currently captured by this widget?
+ if ((h->flags & (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) == (GWIN_FLG_WIDGET|GWIN_FLG_MOUSECAPTURE)) {
+ gh = h;
+ if ((pme->buttons & GMETA_MOUSE_UP)) {
+ gh->flags &= ~GWIN_FLG_MOUSECAPTURE;
+ if (wvmt->MouseUp)
+ wvmt->MouseUp(gw, pme->x - gh->x, pme->y - gh->y);
+ } else if (wvmt->MouseMove)
+ wvmt->MouseMove(gw, pme->x - gh->x, pme->y - gh->y);
+
+ // There is only ever one captured mouse. Prevent normal mouse processing if there is a captured mouse
+ gh = 0;
+
+ break;
+ }
+
+ // Save the highest z-order window that the mouse is over
+ if (pme->x >= h->x && pme->x < h->x + h->width && pme->y >= h->y && pme->y < h->y + h->height)
+ gh = h;
+ }
+
+ // Process any mouse down over the highest order window if it is an enabled widget
+ if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) {
+ if ((pme->buttons & GMETA_MOUSE_DOWN)) {
+ gh->flags |= GWIN_FLG_MOUSECAPTURE;
+
+ #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD
+ // We should try and capture the focus on this window.
+ // If we can't then we don't change the focus
+ gwinSetFocus(gh);
+ #endif
+
+ if (wvmt->MouseDown)
+ wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y);
+ }
+ }
+ break;
+ #endif
+
+ #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD
+ case GEVENT_KEYBOARD:
+ // If Tab key pressed then set focus to next widget
+ if (pke->bytecount == 1 && pke->c[0] == GKEY_TAB) {
+ if (!(pke->keystate & GKEYSTATE_KEYUP))
+ _gwinMoveFocus();
+ break;
+ }
+
+ // Otherwise, send keyboard events only to widget in focus
+ if (_widgetInFocus)
+ ((gwidgetVMT*)_widgetInFocus->vmt)->KeyboardEvent((GWidgetObject*)_widgetInFocus, pke);
+ break;
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ case GEVENT_TOGGLE:
+ // Cycle through all windows
+ for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
+
+ // check if it a widget that is enabled and visible
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE))
+ continue;
+
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ if (wvmt->ToggleGet(gw, role) == pte->instance) {
+ if (pte->on) {
+ if (wvmt->ToggleOn)
+ wvmt->ToggleOn(gw, role);
+ } else {
+ if (wvmt->ToggleOff)
+ wvmt->ToggleOff(gw, role);
+ }
+ }
+ }
+ }
+ break;
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ case GEVENT_DIAL:
+ // Cycle through all windows
+ for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
+
+ // check if it a widget that is enabled and visible
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED|GWIN_FLG_SYSVISIBLE))
+ continue;
+
+ for(role = 0; role < wvmt->dialroles; role++) {
+ if (wvmt->DialGet(gw, role) == pte->instance) {
+ if (wvmt->DialMove)
+ wvmt->DialMove(gw, role, pde->value, pde->maxvalue);
+ }
+ }
+ }
+ break;
+ #endif
+
+ default:
+ break;
+ }
+
+ #undef pme
+ #undef pte
+ #undef pke
+ #undef pde
+}
+
+#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD
+ GHandle gwinGetFocus(void) {
+ return _widgetInFocus;
+ }
+
+ bool_t gwinSetFocus(GHandle gh) {
+ GHandle oldFocus;
+
+ // Do we already have the focus?
+ if (gh == _widgetInFocus)
+ return TRUE;
+
+ // The new window must be NULLL or a visible enabled widget with a keyboard handler
+ if (!gh || ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)
+ && ((gwidgetVMT*)gh->vmt)->KeyboardEvent)) {
+ // Move the current focus
+ oldFocus = _widgetInFocus;
+ _widgetInFocus = gh;
+ if (oldFocus) _gwinUpdate(oldFocus);
+ if (gh) _gwinUpdate(gh);
+ return TRUE;
+ }
+ return FALSE;
+ }
+
+ void _gwinMoveFocus(void) {
+ GHandle gh;
+ bool_t looponce;
+
+ // Find a new focus window (one may or may not exist).
+ looponce = FALSE;
+ for(gh = gwinGetNextWindow(_widgetInFocus); ; gh = gwinGetNextWindow(gh)) {
+ if (!gh && !looponce) {
+ looponce = TRUE;
+ gh = gwinGetNextWindow(0);
+ }
+ if (gwinSetFocus(gh))
+ break;
+ }
+ }
+
+ void _gwinFixFocus(GHandle gh) {
+ GHandle oldFocus;
+
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)
+ && ((gwidgetVMT*)gh->vmt)->KeyboardEvent) {
+
+ // We are a candidate to be able to claim the focus
+
+ // Claim the focus if no-one else has
+ if (!_widgetInFocus)
+ _widgetInFocus = gh;
+
+ return;
+ }
+
+ // We have lost any right to the focus
+
+ // Did we have the focus
+ if (gh != _widgetInFocus)
+ return;
+
+ // We did - we need to find a new focus window
+ oldFocus = _widgetInFocus;
+ for(gh = gwinGetNextWindow(oldFocus); gh && gh != oldFocus; gh = gwinGetNextWindow(gh)) {
+
+ // Must be a visible enabled widget with a keyboard handler
+ if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)
+ && ((gwidgetVMT*)gh->vmt)->KeyboardEvent) {
+
+ // Grab the focus for the new window
+ _widgetInFocus = gh;
+
+ // This new window still needs to be marked for redraw (but don't actually do it yet).
+ gh->flags |= GWIN_FLG_NEEDREDRAW;
+ // RedrawPending |= DOREDRAW_VISIBLES; - FIX LATER
+ return;
+ }
+ }
+
+ // No-one has the right to the focus
+ _widgetInFocus = 0;
+ }
+
+ void _gwidgetDrawFocusRect(GWidgetObject *gx, coord_t x, coord_t y, coord_t cx, coord_t cy) {
+ coord_t i;
+
+ // Don't do anything if we don't have the focus
+ if (&gx->g != _widgetInFocus)
+ return;
+
+ // Use the very simplest possible focus rectangle for now
+ for (i = 0; i < GWIN_FOCUS_HIGHLIGHT_WIDTH; i++) {
+ gdispGDrawBox(gx->g.display, gx->g.x+x+i, gx->g.y+y+i, cx-2*i, cy-2*i, gx->pstyle->focus);
+ }
+ }
+
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ static GHandle FindToggleUser(uint16_t instance) {
+ GHandle gh;
+ uint16_t role;
+
+ for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
+ if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget
+ continue;
+
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ if (wvmt->ToggleGet(gw, role) == instance)
+ return gh;
+ }
+ }
+ return 0;
+ }
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ static GHandle FindDialUser(uint16_t instance) {
+ GHandle gh;
+ uint16_t role;
+
+ for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
+ if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget
+ continue;
+
+ for(role = 0; role < wvmt->dialroles; role++) {
+ if (wvmt->DialGet(gw, role) == instance)
+ return gh;
+ }
+ }
+ return 0;
+ }
+#endif
+
+void _gwidgetInit(void)
+{
+ geventListenerInit(&gl);
+ geventRegisterCallback(&gl, gwidgetEvent, 0);
+ #if GINPUT_NEED_MOUSE
+ geventAttachSource(&gl, ginputGetMouse(GMOUSE_ALL_INSTANCES), GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES);
+ #endif
+ #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD
+ geventAttachSource(&gl, ginputGetKeyboard(GKEYBOARD_ALL_INSTANCES), GLISTEN_KEYUP);
+ #endif
+}
+
+void _gwidgetDeinit(void)
+{
+ /* ToDo */
+}
+
+GHandle _gwidgetCreate(GDisplay *g, GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) {
+ if (!(pgw = (GWidgetObject *)_gwindowCreate(g, &pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED)))
+ return 0;
+
+ #if GWIN_NEED_CONTAINERS
+ // This window can't be system enabled if the parent is not enabled
+ if (pgw->g.parent && !(pgw->g.parent->flags & GWIN_FLG_SYSENABLED))
+ pgw->g.flags &= ~GWIN_FLG_SYSENABLED;
+ #endif
+ pgw->text = pInit->text ? pInit->text : "";
+ pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw;
+ pgw->fnParam = pInit->customParam;
+ pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle;
+ #if GWIN_WIDGET_TAGS
+ pgw->tag = pInit->tag;
+ #endif
+
+ return &pgw->g;
+}
+
+void _gwidgetDestroy(GHandle gh) {
+ #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL)
+ uint16_t role, instance;
+ #endif
+
+ // Make the window is invisible so it is not eligible for focus
+ gh->flags &= ~GWIN_FLG_VISIBLE;
+ _gwinFixFocus(gh);
+
+ // Deallocate the text (if necessary)
+ if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
+ gh->flags &= ~GWIN_FLG_ALLOCTXT;
+ gfxFree((void *)gw->text);
+ }
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ // Detach any toggles from this object
+ for(role = 0; role < wvmt->toggleroles; role++) {
+ instance = wvmt->ToggleGet(gw, role);
+ if (instance != GWIDGET_NO_INSTANCE) {
+ wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindToggleUser(instance))
+ geventDetachSource(&gl, ginputGetToggle(instance));
+ }
+ }
+ #endif
+
+ #if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ // Detach any dials from this object
+ for(role = 0; role < wvmt->dialroles; role++) {
+ instance = wvmt->DialGet(gw, role);
+ if (instance != GWIDGET_NO_INSTANCE) {
+ wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindDialUser(instance))
+ geventDetachSource(&gl, ginputGetDial(instance));
+ }
+ }
+ #endif
+
+ // Remove any listeners on this object.
+ geventDetachSourceListeners((GSourceHandle)gh);
+}
+
+void _gwidgetRedraw(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_SYSVISIBLE))
+ return;
+
+ gw->fnDraw(gw, gw->fnParam);
+}
+
+void _gwinSendEvent(GHandle gh, GEventType type) {
+ GSourceListener * psl;
+ GEventGWin * pge;
+
+ // Trigger a GWIN Event
+ psl = 0;
+ while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) {
+ if (!(pge = (GEventGWin *)geventGetEventBuffer(psl)))
+ continue;
+ pge->type = type;
+ pge->gwin = gh;
+ #if GWIN_WIDGET_TAGS
+ pge->tag = (gh->flags & GWIN_FLG_WIDGET) ? ((GWidgetObject *)gh)->tag : 0;
+ #endif
+ geventSendEvent(psl);
+ }
+}
+
+void gwinWidgetClearInit(GWidgetInit *pwi) {
+ char *p;
+ unsigned len;
+
+ for(p = (char *)pwi, len = sizeof(GWidgetInit); len; len--)
+ *p++ = 0;
+}
+
+void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) {
+ if (!pstyle)
+ pstyle = &BlackWidgetStyle;
+
+ if (updateAll) {
+ GHandle gh;
+
+ for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
+ if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle)
+ gwinSetStyle(gh, pstyle);
+ else
+ gwinRedraw(gh);
+ }
+ }
+ gwinSetDefaultBgColor(pstyle->background);
+ defaultStyle = pstyle;
+}
+
+/**
+ * @brief Get the current default style.
+ *
+ * @api
+ */
+const GWidgetStyle *gwinGetDefaultStyle(void) {
+ return defaultStyle;
+}
+
+void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ // Dispose of the old string
+ if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
+ gh->flags &= ~GWIN_FLG_ALLOCTXT;
+ if (gw->text) {
+ gfxFree((void *)gw->text);
+ gw->text = "";
+ }
+ }
+
+ // Alloc the new text if required
+ if (!text || !*text)
+ gw->text = "";
+ else if (useAlloc) {
+ char *str;
+
+ if ((str = gfxAlloc(strlen(text)+1))) {
+ gh->flags |= GWIN_FLG_ALLOCTXT;
+ strcpy(str, text);
+ }
+ gw->text = (const char *)str;
+ } else
+ gw->text = text;
+ _gwinUpdate(gh);
+}
+
+#if GFX_USE_GFILE && GFILE_NEED_PRINTG && GFILE_NEED_STRINGS
+ #include <stdarg.h>
+
+ void gwinPrintg(GHandle gh, const char * fmt, ...) {
+ char *str;
+ va_list va;
+ int size;
+
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ // Dispose of the old string
+ if ((gh->flags & GWIN_FLG_ALLOCTXT)) {
+ gh->flags &= ~GWIN_FLG_ALLOCTXT;
+ if (gw->text) {
+ gfxFree((void *)gw->text);
+ gw->text = "";
+ }
+ }
+
+ // Alloc the new text
+ va_start (va, fmt);
+
+ size = vsnprintg(0, 0, fmt, va) + 1; //determine the buffer size required
+
+ if ((str = gfxAlloc(size))) {
+ gh->flags |= GWIN_FLG_ALLOCTXT;
+ vsnprintg(str, size, fmt, va);
+ gw->text = (const char *)str;
+ } else
+ gw->text = "";
+
+ va_end (va);
+
+ _gwinUpdate(gh);
+ }
+#endif
+
+const char *gwinGetText(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return 0;
+
+ return gw->text;
+}
+
+bool_t gwinIsWidget(GHandle gh) {
+ if (gh->flags & GWIN_FLG_WIDGET) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ gw->pstyle = pstyle ? pstyle : defaultStyle;
+ gh->bgcolor = gw->pstyle->background;
+ gh->color = gw->pstyle->enabled.text;
+
+ _gwinUpdate(gh);
+}
+
+const GWidgetStyle *gwinGetStyle(GHandle gh) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return 0;
+
+ return gw->pstyle;
+}
+
+void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) {
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return;
+
+ gw->fnDraw = fn ? fn : wvmt->DefaultDraw;
+ gw->fnParam = param;
+ _gwinUpdate(gh);
+}
+
+bool_t gwinAttachListener(GListener *pl) {
+ return geventAttachSource(pl, GWIDGET_SOURCE, 0);
+}
+
+#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE
+ bool_t DEPRECATED("This call can now be removed. Attaching the mouse to GWIN is now automatic.") gwinAttachMouse(uint16_t instance) {
+ // This is now a NULL event because we automatically attach to all mice in the system.
+ (void) instance;
+ return TRUE;
+ }
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
+ bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) {
+ GSourceHandle gsh;
+ uint16_t oi;
+
+ // Is this a widget
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return FALSE;
+
+ // Is the role valid
+ if (role >= wvmt->toggleroles)
+ return FALSE;
+
+ // Is this a valid device
+ if (!(gsh = ginputGetToggle(instance)))
+ return FALSE;
+
+ // Is this already done?
+ oi = wvmt->ToggleGet(gw, role);
+ if (instance == oi)
+ return TRUE;
+
+ // Remove the old instance
+ if (oi != GWIDGET_NO_INSTANCE) {
+ wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindToggleUser(oi))
+ geventDetachSource(&gl, ginputGetToggle(oi));
+ }
+
+ // Assign the new
+ wvmt->ToggleAssign(gw, role, instance);
+ return geventAttachSource(&gl, gsh, GLISTEN_TOGGLE_ON|GLISTEN_TOGGLE_OFF);
+ }
+
+ bool_t gwinDetachToggle(GHandle gh, uint16_t role) {
+ uint16_t oi;
+
+ // Is this a widget
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return FALSE;
+
+ // Is the role valid
+ if (role >= ((gwidgetVMT *)gh->vmt)->toggleroles)
+ return FALSE;
+
+ oi = ((gwidgetVMT *)gh->vmt)->ToggleGet(gw, role);
+
+ // Remove the instance
+ if (oi != GWIDGET_NO_INSTANCE) {
+ ((gwidgetVMT *)gh->vmt)->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindToggleUser(oi))
+ geventDetachSource(&gl, ginputGetToggle(oi));
+ }
+ return TRUE;
+ }
+
+#endif
+
+#if GFX_USE_GINPUT && GINPUT_NEED_DIAL
+ bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) {
+ GSourceHandle gsh;
+ uint16_t oi;
+
+ if (!(gh->flags & GWIN_FLG_WIDGET))
+ return FALSE;
+
+ // Is the role valid
+ if (role >= wvmt->dialroles)
+ return FALSE;
+
+ // Is this a valid device
+ if (!(gsh = ginputGetDial(instance)))
+ return FALSE;
+
+ // Is this already done?
+ oi = wvmt->DialGet(gw, role);
+ if (instance == oi)
+ return TRUE;
+
+ // Remove the old instance
+ if (oi != GWIDGET_NO_INSTANCE) {
+ wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE);
+ if (!FindDialUser(oi))
+ geventDetachSource(&gl, ginputGetDial(oi));
+ }
+
+ // Assign the new
+ wvmt->DialAssign(gw, role, instance);
+ return geventAttachSource(&gl, gsh, 0);
+ }
+#endif
+
+#if GWIN_WIDGET_TAGS
+ void gwinSetTag(GHandle gh, WidgetTag tag) {
+ if ((gh->flags & GWIN_FLG_WIDGET))
+ gw->tag = tag;
+ }
+
+ WidgetTag gwinGetTag(GHandle gh) {
+ return ((gh->flags & GWIN_FLG_WIDGET)) ? gw->tag : 0;
+ }
+#endif
+
+#undef gw
+#undef wvmt
+#endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */
+/** @} */
|