diff --git a/demos/modules/gadc/gwinosc.c b/demos/modules/gadc/gwinosc.c index 88e61334..60a08686 100644 --- a/demos/modules/gadc/gwinosc.c +++ b/demos/modules/gadc/gwinosc.c @@ -47,7 +47,7 @@ GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint32_t physdev, uint32_t frequency) { /* Initialise the base class GWIN */ - if (!(gs = (GScopeObject *)_gwindowInit((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) + if (!(gs = (GScopeObject *)_gwindowCreate((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) return 0; /* Initialise the scope object members and allocate memory for buffers */ diff --git a/demos/modules/gaudin/gwinosc.c b/demos/modules/gaudin/gwinosc.c index e90430d3..975c2c06 100644 --- a/demos/modules/gaudin/gwinosc.c +++ b/demos/modules/gaudin/gwinosc.c @@ -54,7 +54,7 @@ GHandle gwinCreateScope(GScopeObject *gs, coord_t x, coord_t y, coord_t cx, coord_t cy, uint16_t channel, uint32_t frequency) { /* Initialise the base class GWIN */ - if (!(gs = (GScopeObject *)_gwindowInit((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) + if (!(gs = (GScopeObject *)_gwindowCreate((GWindowObject *)gs, x, y, cx, cy, sizeof(GScopeObject)))) return 0; /* Initialise the scope object members and allocate memory for buffers */ diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index b4574149..411d829e 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -51,15 +51,17 @@ #define GDISP_NEED_IMAGE_PNG FALSE /* Features for the GWIN sub-system. */ +#define GWIN_NEED_WINDOWMANAGER TRUE #define GWIN_NEED_CONSOLE TRUE #define GWIN_NEED_GRAPH FALSE +#define GWIN_NEED_WIDGET TRUE #define GWIN_NEED_BUTTON TRUE #define GWIN_NEED_SLIDER TRUE #define GWIN_NEED_CHECKBOX TRUE /* Features for the GINPUT sub-system. */ #define GINPUT_NEED_MOUSE TRUE -#define GINPUT_NEED_TOGGLE FALSE +#define GINPUT_NEED_TOGGLE TRUE #define GINPUT_NEED_DIAL FALSE #endif /* _GFXCONF_H */ diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 2102d3a2..1c34b9fa 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -49,11 +49,20 @@ int main(void) { gfxInit(); gdispClear(White); - // Set the font and defalt colors + // Set the widget defaults gwinSetDefaultFont(gdispOpenFont("UI2")); gwinSetDefaultColor(Black); gwinSetDefaultBgColor(White); + // We want to listen for widget events + geventListenerInit(&gl); + gwinAttachListener(&gl); + + // Connect the mouse + #if GINPUT_NEED_MOUSE + gwinAttachMouse(0); + #endif + // Create out gwin windows/widgets ghConsole = gwinCreateConsole(NULL, ScrWidth/2+1, ScrHeight/2+1, ScrWidth/2-1, ScrHeight/2-1); ghButton1 = gwinCreateButton(NULL, 0+0*(BUTTON_WIDTH+1), 0, BUTTON_WIDTH, BUTTON_HEIGHT); @@ -84,49 +93,28 @@ int main(void) { gwinSetText(ghCheckbox1, "C1", FALSE); gwinSetText(ghCheckbox2, "C2", FALSE); - // Assign the mouse and dials to the buttons & sliders etc. -#if GINPUT_NEED_MOUSE - gwinAttachMouse(ghButton1, 0); - gwinAttachMouse(ghButton2, 0); - gwinAttachMouse(ghButton3, 0); - gwinAttachMouse(ghButton4, 0); - gwinAttachMouse(ghSlider1, 0); - gwinAttachMouse(ghSlider2, 0); - gwinAttachMouse(ghSlider3, 0); - gwinAttachMouse(ghSlider4, 0); - gwinAttachMouse(ghCheckbox1, 0); - gwinAttachMouse(ghCheckbox2, 0); -#endif -#if GINPUT_NEED_DIAL - gwinAttachSliderDial(ghSlider1, 0); - gwinAttachSliderDial(ghSlider3, 1); -#endif - - // We want to listen for widget events - geventListenerInit(&gl); - gwinAttachListener(ghButton1, &gl, 0); - gwinAttachListener(ghButton2, &gl, 0); - gwinAttachListener(ghButton3, &gl, 0); - gwinAttachListener(ghButton4, &gl, 0); - gwinAttachListener(ghSlider1, &gl, 0); - gwinAttachListener(ghSlider2, &gl, 0); - gwinAttachListener(ghSlider3, &gl, 0); - gwinAttachListener(ghSlider4, &gl, 0); - gwinAttachListener(ghCheckbox1, &gl, 0); - gwinAttachListener(ghCheckbox2, &gl, 0); + // Assign toggles and dials to the buttons & sliders etc. + #if GINPUT_NEED_TOGGLE + gwinAttachToggle(ghButton1, 0, 0); + gwinAttachToggle(ghButton2, 0, 1); + #endif + #if GINPUT_NEED_DIAL + gwinAttachDial(ghSlider1, 0, 0); + gwinAttachDial(ghSlider3, 0, 1); + #endif // Draw everything on the screen gwinClear(ghConsole); - gwinDraw(ghButton1); - gwinDraw(ghButton2); - gwinDraw(ghButton3); - gwinDraw(ghButton4); - gwinDraw(ghSlider1); - gwinDraw(ghSlider2); - gwinDraw(ghSlider3); - gwinDraw(ghSlider4); - gwinDraw(ghCheckbox1); - gwinDraw(ghCheckbox2); + gwinSetVisible(ghButton1, TRUE); + gwinSetVisible(ghButton2, TRUE); + gwinSetVisible(ghButton3, TRUE); + gwinSetVisible(ghButton4, TRUE); + gwinSetVisible(ghSlider1, TRUE); + gwinSetVisible(ghSlider2, TRUE); + gwinSetVisible(ghSlider3, TRUE); + gwinSetVisible(ghSlider4, TRUE); + gwinSetVisible(ghCheckbox1, TRUE); + gwinSetVisible(ghCheckbox2, TRUE); while(1) { // Get an Event diff --git a/drivers/multiple/Win32/gdisp_lld.c b/drivers/multiple/Win32/gdisp_lld.c index a41954a7..b53b3632 100644 --- a/drivers/multiple/Win32/gdisp_lld.c +++ b/drivers/multiple/Win32/gdisp_lld.c @@ -119,8 +119,8 @@ static LRESULT myWindowProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam) break; case WM_LBUTTONUP: #if GINPUT_NEED_TOGGLE - if ((toggles & 0xF0)) { - toggles &= 0x0F; + if ((toggles & 0x0F)) { + toggles &= ~0x0F; rect.left = 0; rect.right = wWidth; rect.top = wHeight; diff --git a/drivers/multiple/Win32/ginput_lld_toggle_config.h b/drivers/multiple/Win32/ginput_lld_toggle_config.h index e96380d3..d487ca42 100644 --- a/drivers/multiple/Win32/ginput_lld_toggle_config.h +++ b/drivers/multiple/Win32/ginput_lld_toggle_config.h @@ -1,9 +1,9 @@ -/* - * This file is subject to the terms of the GFX License, v1.0. If a copy of - * the license was not distributed with this file, you can obtain one at: - * - * http://chibios-gfx.com/license.html - */ +/* + * This file is subject to the terms of the GFX License, v1.0. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://chibios-gfx.com/license.html + */ /** * @file drivers/multiple/Win32/ginput_lld_toggle_config.h @@ -20,19 +20,19 @@ #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE -#define GINPUT_TOGGLE_POLL_PERIOD TIME_INFINITE // We are interrupt driven (or polled - ether works here) +#define GINPUT_TOGGLE_POLL_PERIOD TIME_INFINITE // We are interrupt driven (or polled - either works here) #define GINPUT_TOGGLE_NUM_PORTS 8 // The total number of toggle inputs #define GINPUT_TOGGLE_CONFIG_ENTRIES 1 // The total number of GToggleConfig entries -#define GINPUT_TOGGLE_SW1 0 // Switch 1 - Toggle -#define GINPUT_TOGGLE_SW2 1 // Switch 2 - Toggle -#define GINPUT_TOGGLE_SW3 2 // Switch 3 - Toggle -#define GINPUT_TOGGLE_SW4 3 // Switch 4 - Toggle +#define GINPUT_TOGGLE_MOMENTARY1 0 // Switch 5 - Momentary +#define GINPUT_TOGGLE_MOMENTARY2 1 // Switch 6 - Momentary +#define GINPUT_TOGGLE_MOMENTARY3 2 // Switch 7 - Momentary +#define GINPUT_TOGGLE_MOMENTARY4 3 // Switch 8 - Momentary -#define GINPUT_TOGGLE_MOMENTARY1 4 // Switch 5 - Momentary -#define GINPUT_TOGGLE_MOMENTARY2 5 // Switch 6 - Momentary -#define GINPUT_TOGGLE_MOMENTARY3 6 // Switch 7 - Momentary -#define GINPUT_TOGGLE_MOMENTARY4 7 // Switch 8 - Momentary +#define GINPUT_TOGGLE_SW1 4 // Switch 1 - Toggle +#define GINPUT_TOGGLE_SW2 5 // Switch 2 - Toggle +#define GINPUT_TOGGLE_SW3 6 // Switch 3 - Toggle +#define GINPUT_TOGGLE_SW4 7 // Switch 4 - Toggle #endif /* GFX_USE_GDISP && GINPUT_NEED_TOGGLE */ diff --git a/include/gfx_rules.h b/include/gfx_rules.h index 7e14ef9d..6c0dc756 100644 --- a/include/gfx_rules.h +++ b/include/gfx_rules.h @@ -46,24 +46,6 @@ #warning "GWIN: Drawing can occur outside the defined windows as GDISP_NEED_CLIP is FALSE" #endif #endif - #if GWIN_NEED_WINDOWMANAGER - #if !GFX_USE_GQUEUE || !GQUEUE_NEED_ASYNC - #if GFX_DISPLAY_RULE_WARNINGS - #warning "GWIN: GFX_USE_GQUEUE and GQUEUE_NEED_ASYNC is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you." - #endif - #undef GFX_USE_GQUEUE - #undef GQUEUE_NEED_ASYNC - #define GFX_USE_GQUEUE TRUE - #define GQUEUE_NEED_ASYNC TRUE - #endif - #endif - #if GWIN_NEED_CONSOLE - #if !GDISP_NEED_TEXT - #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE." - #endif - #endif - #if GWIN_NEED_GRAPH - #endif #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX #if !GWIN_NEED_WIDGET #if GFX_DISPLAY_RULE_WARNINGS @@ -81,6 +63,13 @@ // This test also ensures that GFX_USE_GEVENT is set #error "GWIN: GFX_USE_GINPUT (and one or more input sources) is required if GWIN_NEED_WIDGET is TRUE" #endif + #if !GWIN_NEED_WINDOWMANAGER + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GWIN_NEED_WINDOWMANAGER is required if GWIN_NEED_WIDGET is TRUE. It has been turned on for you." + #endif + #undef GWIN_NEED_WINDOWMANAGER + #define GWIN_NEED_WINDOWMANAGER TRUE + #endif #if !GDISP_NEED_MULTITHREAD && !GDISP_NEED_ASYNC #if GFX_DISPLAY_RULE_WARNINGS #warning "GWIN: Either GDISP_NEED_MULTITHREAD or GDISP_NEED_ASYNC is required if GWIN_NEED_WIDGET is TRUE." @@ -90,6 +79,24 @@ #define GDISP_NEED_MULTITHREAD TRUE #endif #endif + #if GWIN_NEED_WINDOWMANAGER + #if !GFX_USE_GQUEUE || !GQUEUE_NEED_ASYNC + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GFX_USE_GQUEUE and GQUEUE_NEED_ASYNC is required if GWIN_NEED_WINDOWMANAGER is TRUE. It has been turned on for you." + #endif + #undef GFX_USE_GQUEUE + #undef GQUEUE_NEED_ASYNC + #define GFX_USE_GQUEUE TRUE + #define GQUEUE_NEED_ASYNC TRUE + #endif + #endif + #if GWIN_NEED_CONSOLE + #if !GDISP_NEED_TEXT + #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE." + #endif + #endif + #if GWIN_NEED_GRAPH + #endif #endif #if GFX_USE_GINPUT diff --git a/include/ginput/dial.h b/include/ginput/dial.h index af54952a..8b4f9d3c 100644 --- a/include/ginput/dial.h +++ b/include/ginput/dial.h @@ -36,6 +36,7 @@ typedef struct GEventDial_t { GEventType type; // The type of this event (GEVENT_DIAL) uint16_t instance; // The dial instance uint16_t value; // The dial value + uint16_t maxvalue; // The maximum dial value } GEventDial; /*===========================================================================*/ diff --git a/include/gqueue/gqueue.h b/include/gqueue/gqueue.h index 38c1908d..399042d9 100644 --- a/include/gqueue/gqueue.h +++ b/include/gqueue/gqueue.h @@ -103,7 +103,7 @@ void gfxQueueFSyncInit(gfxQueueFSync *pqueue); /* @} */ /** - * @brief Get an item from the head of the queue. + * @brief Get an item from the head of the queue (and remove it from the queue). * @return NULL if the timeout expires before an item is available * * @param[in] pqueue A pointer to the queue @@ -139,7 +139,7 @@ bool_t gfxQueueFSyncPut(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem, delayti /* @} */ /** - * @brief Pop an item from the head of the queue. + * @brief Pop an item from the head of the queue (and remove it from the queue). * @detail This is exactly the same as the Get operation above. * * @api @@ -220,6 +220,46 @@ bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem); bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem); /* @} */ +/** + * @brief Get the first item from the head of the queue but do not remove it from the queue. + * @return NULL if no item is available. + * + * @param[in] pqueue A pointer to the queue + * + * @note This call does not block. + * @note This can be used as the first call to iterate all the elements in the queue. + * @note As that item is still on the queue, it should be treated as read-only. It could + * also be removed from the queue at any time by another thread (thereby altering the + * queue item). + * + * @api + * @{ + */ +#define gfxQueueASyncPeek(pqueue) ((const gfxQueueASyncItem *)((pqueue)->head)) +#define gfxQueueGSyncPeek(pqueue) ((const gfxQueueGSyncItem *)((pqueue)->head)) +#define gfxQueueFSyncPeek(pqueue) ((const gfxQueueFSyncItem *)((pqueue)->head)) +/* @} */ + +/** + * @brief Get the next item in the queue (but do not remove it from the queue). + * @return NULL if no item is available. + * + * @param[in] pitem The previous item in the queue + * + * @note This call does not block. + * @note This can be used as subsequent calls to iterate all the elements in the queue. + * @note As that item is still on the queue, it should be treated as read-only. It could + * also be removed from the queue at any time by another thread (thereby altering the + * queue item). + * + * @api + * @{ + */ +#define gfxQueueASyncNext(pitem) ((const gfxQueueASyncItem *)((pitem)->next)) +#define gfxQueueGSyncNext(pitem) ((const gfxQueueGSyncItem *)((pitem)->next)) +#define gfxQueueFSyncNext(pitem) ((const gfxQueueFSyncItem *)((pitem)->next)) +/* @} */ + #ifdef __cplusplus } #endif diff --git a/include/gwin/button.h b/include/gwin/button.h index 53096ea3..20fd6df7 100644 --- a/include/gwin/button.h +++ b/include/gwin/button.h @@ -55,6 +55,7 @@ typedef struct GButtonColors { */ typedef struct GButtonObject_t { GWidgetObject w; + uint16_t toggle; GButtonColors c_up; GButtonColors c_dn; GButtonColors c_dis; @@ -78,10 +79,13 @@ extern "C" { * @note The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there * is no default font and text drawing operations will no nothing. * @note The dimensions and position may be changed to fit on the real screen. - * @note A button remembers its normal button state. If there is a window manager then it is automatically + * @note A button remembers its normal drawing state. If there is a window manager then it is automatically * redrawn if the window is moved or its visibility state is changed. * @note The button is initially marked as invisible so that more properties can be set before display. * Call @p gwinSetVisible() to display it when ready. + * @note A button supports mouse and a toggle input. + * @note When assigning a toggle, only one toggle is supported. If you try to assign more than one toggle it will + * forget the previous toggle. When assigning a toggle the role parameter must be 0. * * @api */ diff --git a/include/gwin/checkbox.h b/include/gwin/checkbox.h index de49fa01..6f151218 100644 --- a/include/gwin/checkbox.h +++ b/include/gwin/checkbox.h @@ -50,6 +50,7 @@ typedef struct GCheckboxColors { /* A Checkbox window */ typedef struct GCheckboxObject_t { GWidgetObject w; + uint16_t toggle; GCheckboxColors c; } GCheckboxObject; @@ -62,10 +63,18 @@ typedef struct GCheckboxObject_t { * @param[in] width The width of the window * @param[in] height The height of the window * - * @note The drawing color gets set to White and the background drawing color to Black. - * @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont() + * @note The drawing color and the background color get set to the current defaults. If you haven't called + * @p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are White and Black respectively. + * @note The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there + * is no default font and text drawing operations will no nothing. * @note The dimensions and position may be changed to fit on the real screen. - * @note The checkbox is not automatically drawn. Call gwinDraw() to draw it. + * @note A checkbox remembers its normal drawing state. If there is a window manager then it is automatically + * redrawn if the window is moved or its visibility state is changed. + * @note The checkbox is initially marked as invisible so that more properties can be set before display. + * Call @p gwinSetVisible() to display it when ready. + * @note A checkbox supports mouse and a toggle input. + * @note When assigning a toggle, only one toggle is supported. If you try to assign more than one toggle it will + * forget the previous toggle. When assigning a toggle the role parameter must be 0. * * @api */ diff --git a/include/gwin/class_gwin.h b/include/gwin/class_gwin.h index 5e3cb01f..1c640c0c 100644 --- a/include/gwin/class_gwin.h +++ b/include/gwin/class_gwin.h @@ -52,37 +52,58 @@ typedef struct gwinVMT { /* @} */ #if GWIN_NEED_WIDGET || defined(__DOXYGEN__) + + /** + * @brief An toggle/dial instance is not being used + */ + #define GWIDGET_NO_INSTANCE ((uint16_t)-1) + + /** + * @brief The source handle that widgets use when sending events + */ + #define GWIDGET_SOURCE ((GSourceHandle)(void *)_gwidgetCreate) + /** * @brief The Virtual Method Table for a widget * @note A widget must have a destroy function. Either use @p _gwidgetDestroy() or use your own function * which internally calls @p _gwidgetDestroy(). * @note A widget must have a redraw function. Use @p _gwidgetRedraw(). - * @note If no MouseDown(), MouseUp() or MouseMove() function is provided, the widget will not accept being attached to a mouse input source. - * @note If no ToggleOn() or ToggleOff() function is provided, the widget will not accept being attached to a toggle input source. - * @note If no DialMove() function is provided, the widget will not accept being attached to a dial input source. - * @note AssignToggle() and AssignDial() enable a widget to handle more than one toggle/dial device attached to the widget. - * For example, a slider might accept two toggles, one for slider-down and one for slider-up. - * The function enables the widget to record that a particular device instance performs each particular role. - * (eg toggle0 = slider-down, toggle1 = slider-up). + * @note If toggleroles != 0, ToggleAssign(), ToggleGet() and one or both of ToggleOff() and ToggleOn() must be specified. + * @note If dialroles != 0, DialAssign(), DialGet() and DialMove() must be specified. * @{ */ typedef struct gwidgetVMT { - struct gwinVMT g; // @< This is still a GWIN - void (*DefaultDraw) (GWidgetObject *gw, void *param); // @< The default drawing routine (mandatory) - void (*MouseDown) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse down events (optional) - void (*MouseUp) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse up events (optional) - void (*MouseMove) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse move events (optional) - void (*ToggleOff) (GWidgetObject *gw, uint16_t instance); // @< Process toggle off events (optional) - void (*ToggleOn) (GWidgetObject *gw, uint16_t instance); // @< Process toggle on events (optional) - void (*DialMove) (GWidgetObject *gw, uint16_t instance, uint16_t value); // @< Process dial move events (optional) - void (*AllEvents) (GWidgetObject *gw, GEvent *pe); // @< Process all events (optional) - bool_t (*AssignToggle) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Test the role and save the toggle instance handle (optional) - bool_t (*AssignDial) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Test the role and save the dial instance handle (optional) + struct gwinVMT g; // @< This is still a GWIN + void (*DefaultDraw) (GWidgetObject *gw, void *param); // @< The default drawing routine (mandatory) + struct { + void (*MouseDown) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse down events (optional) + void (*MouseUp) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse up events (optional) + void (*MouseMove) (GWidgetObject *gw, coord_t x, coord_t y); // @< Process mouse move events (optional) + }; + struct { + uint16_t toggleroles; // @< The roles supported for toggles (0->toggleroles-1) + void (*ToggleAssign) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Assign a toggle to a role (optional) + uint16_t (*ToggleGet) (GWidgetObject *gw, uint16_t role); // @< Return the instance for a particular role (optional) + void (*ToggleOff) (GWidgetObject *gw, uint16_t role); // @< Process toggle off events (optional) + void (*ToggleOn) (GWidgetObject *gw, uint16_t role); // @< Process toggle on events (optional) + }; + struct { + uint16_t dialroles; // @< The roles supported for dials (0->dialroles-1) + void (*DialAssign) (GWidgetObject *gw, uint16_t role, uint16_t instance); // @< Test the role and save the dial instance handle (optional) + uint16_t (*DialGet) (GWidgetObject *gw, uint16_t role); // @< Return the instance for a particular role (optional) + void (*DialMove) (GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max); // @< Process dial move events (optional) + }; } gwidgetVMT; /* @} */ #endif #if GWIN_NEED_WINDOWMANAGER || defined(__DOXYGEN__) + #if 1 // When we know that wmq is the first element of the GWindowObject structure + #define QItem2GWindow(qi) ((GHandle)qi) + #else + #define QItem2GWindow(qi) ((GHandle)(((char *)(qi)) - (size_t)(&(((GWindowObject *)0)->wmq)))) + #endif + // @note There is only ever one instance of each GWindowManager type typedef struct GWindowManager { const struct gwmVMT *vmt; @@ -126,7 +147,7 @@ extern "C" { * * @notapi */ -GHandle _gwindowInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwinVMT *vmt, uint16_t flags); +GHandle _gwindowCreate(GWindowObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwinVMT *vmt, uint16_t flags); #if GWIN_NEED_WIDGET || defined(__DOXYGEN__) /** @@ -140,7 +161,7 @@ GHandle _gwindowInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t w, coord_ * * @notapi */ - GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwidgetVMT *vmt); + GHandle _gwidgetCreate(GWidgetObject *pgw, coord_t x, coord_t y, coord_t w, coord_t h, size_t size, const gwidgetVMT *vmt); /** * @brief Destroy the Widget object diff --git a/include/gwin/gwidget.h b/include/gwin/gwidget.h index 21cfd4ac..a022ab13 100644 --- a/include/gwin/gwidget.h +++ b/include/gwin/gwidget.h @@ -46,7 +46,6 @@ typedef void (*CustomWidgetDrawFunction)(struct GWidgetObject *gw, void *param); */ typedef struct GWidgetObject { GWindowObject g; // @< This is still a GWIN - GListener listener; // @< The widget listener const char * txt; // @< The widget text CustomWidgetDrawFunction fnDraw; // @< The current draw function void * fnParam; // @< A parameter for the current draw function @@ -120,28 +119,27 @@ const char *gwinGetText(GHandle gh); void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param); /** - * @brief Attach a Listener to this widget + * @brief Attach a Listener to listen for widget events * @return TRUE on success * - * @param[in] gh The widget handle * @param[in] pl The listener - * @param[in] flags Flags to use for listening. For most widgets this should be 0. * * @api */ -bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags); +bool_t gwinAttachListener(GListener *pl); #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE /** - * @brief Attach a mouse to a widget + * @brief Set the mouse to be used to control the widgets * @return TRUE on success * - * @param[in] gh The widget handle * @param[in] instance The mouse instance * + * @note Every widget uses the same mouse. + * * @api */ - bool_t gwinAttachMouse(GHandle gh, uint16_t instance); + bool_t gwinAttachMouse(uint16_t instance); #endif #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE diff --git a/include/gwin/gwin.h b/include/gwin/gwin.h index d915a4f0..96d7be97 100644 --- a/include/gwin/gwin.h +++ b/include/gwin/gwin.h @@ -35,6 +35,7 @@ */ typedef struct GWindowObject { #if GWIN_NEED_WINDOWMANAGER + // This MUST be the first member of the struct gfxQueueASyncItem wmq; // @< The next window (for the window manager) #endif const struct gwinVMT *vmt; // @< The VMT for this GWIN diff --git a/include/gwin/options.h b/include/gwin/options.h index 3619e075..db4ae69b 100644 --- a/include/gwin/options.h +++ b/include/gwin/options.h @@ -21,11 +21,11 @@ * @{ */ /** - * @brief Should a window manager be used. + * @brief Should window manager support be included * @details Defaults to FALSE */ #ifndef GWIN_NEED_WINDOWMANAGER - #define GWIN_NEED_WINDOWMANAGER FALSE + #define GWIN_NEED_WIDGET FALSE #endif /** * @brief Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc) diff --git a/include/gwin/slider.h b/include/gwin/slider.h index 41894305..45618114 100644 --- a/include/gwin/slider.h +++ b/include/gwin/slider.h @@ -45,11 +45,14 @@ typedef struct GSliderColors { // A slider window typedef struct GSliderObject_t { GWidgetObject w; - GSliderColors c; + uint16_t t_dn; + uint16_t t_up; + uint16_t dial; coord_t dpos; int min; int max; int pos; + GSliderColors c; } GSliderObject; #ifdef __cplusplus @@ -65,11 +68,22 @@ extern "C" { * @param[in] width The width of the window * @param[in] height The height of the window * - * @note The drawing color gets set to White and the background drawing color to Black. - * @note Don't forget to set the font using @p gwinSetFont() or @p gwinSetDefaultFont() + * @note The drawing color and the background color get set to the current defaults. If you haven't called + * @p gwinSetDefaultColor() or @p gwinSetDefaultBgColor() then these are White and Black respectively. + * @note The font gets set to the current default font. If you haven't called @p gwinSetDefaultFont() then there + * is no default font and text drawing operations will no nothing. * @note The dimensions and position may be changed to fit on the real screen. - * @note The slider is not automatically drawn. Call gwinDraw() to draw it. - * @note Sets the slider range from 0 to 100 with an initial position of 0 + * @note A slider remembers its normal drawing state. If there is a window manager then it is automatically + * redrawn if the window is moved or its visibility state is changed. + * @note The slider is initially marked as invisible so that more properties can be set before display. + * Call @p gwinSetVisible() to display it when ready. + * @note The initial slider range is from 0 to 100 with an initial position of 0. + * @note A slider supports mouse, toggle and dial input. + * @note When assigning a toggle, only one toggle is supported per role. If you try to assign more than + * one toggle to a role it will forget the previous toggle. Two roles are supported: + * Role 0 = toggle for down, Role 1 = toggle for up. + * @note When assigning a dial, only one dial is supported. If you try to assign more than one dial + * it will forget the previous dial. Only dial role 0 is supported. * * @api */ diff --git a/src/ginput/dial.c b/src/ginput/dial.c index 24836910..2e52c224 100644 --- a/src/ginput/dial.c +++ b/src/ginput/dial.c @@ -57,6 +57,7 @@ static void DialCallback(uint16_t instance, uint16_t rawvalue) { pe->type = GEVENT_DIAL; pe->instance = instance; pe->value = pds->lastvalue; + pe->maxvalue = pds->max; geventSendEvent(psl); } } @@ -144,6 +145,7 @@ bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial) { pdial->type = GEVENT_DIAL; pdial->instance = instance; pdial->value = DialStatus[instance].lastvalue; + pdial->maxvalue = DialStatus[instance].max; return TRUE; } diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c index 11d10c0a..002378b3 100644 --- a/src/gqueue/gqueue.c +++ b/src/gqueue/gqueue.c @@ -37,6 +37,7 @@ gfxSystemLock(); if ((pi = pqueue->head)) pqueue->head = pi->next; + pi->next = 0; gfxSystemUnlock(); return pi; } @@ -68,12 +69,14 @@ if (pqueue->head) { if (pqueue->head == pitem) { pqueue->head = pitem->next; + pitem->next = 0; } else { for(pi = pqueue->head; pi->next; pi = pi->next) { if (pi->next == pitem) { pi->next = pitem->next; if (pqueue->tail == pitem) pqueue->tail = pi; + pitem->next = 0; break; } } @@ -111,6 +114,7 @@ gfxSystemLock(); pi = pqueue->head; pqueue->head = pi->next; + pi->next = 0; gfxSytemUnlock(); return pi; } @@ -146,12 +150,14 @@ if (pqueue->head) { if (pqueue->head == pitem) { pqueue->head = pitem->next; + pitem->next = 0; } else { for(pi = pqueue->head; pi->next; pi = pi->next) { if (pi->next == pitem) { pi->next = pitem->next; if (pqueue->tail == pitem) pqueue->tail = pi; + pitem->next = 0; break; } } @@ -189,6 +195,7 @@ gfxSystemLock(); pi = pqueue->head; pqueue->head = pi->next; + pi->next = 0; gfxSytemUnlock(); gfxSemSignalI(&pi->sem); @@ -233,6 +240,7 @@ if (pqueue->head == pitem) { pqueue->head = pitem->next; found: + pitem->next = 0; gfxSystemUnlock(); gfxSemSignal(&pitem->sem); gfxSemDestroy(&pitem->sem); diff --git a/src/gwin/button.c b/src/gwin/button.c index 83b81b03..285a406c 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -32,8 +32,10 @@ // Prototypes for button VMT functions static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y); static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y); -static void ToggleOff(GWidgetObject *gw, uint16_t instance); -static void ToggleOn(GWidgetObject *gw, uint16_t instance); +static void ToggleOff(GWidgetObject *gw, uint16_t role); +static void ToggleOn(GWidgetObject *gw, uint16_t role); +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance); +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role); // The button VMT table static const gwidgetVMT buttonVMT = { @@ -43,16 +45,25 @@ static const gwidgetVMT buttonVMT = { _gwidgetRedraw, // The redraw routine 0, // The after-clear routine }, - gwinButtonDraw_3D, // The default drawing routine - MouseDown, // Process mouse down events - MouseUp, // Process mouse up events - 0, // Process mouse move events (NOT USED) - ToggleOff, // Process toggle off events - ToggleOn, // Process toggle on events - 0, // Process dial move events (NOT USED) - 0, // Process all events (NOT USED) - 0, // AssignToggle (NOT USED) - 0, // AssignDial (NOT USED) + gwinButtonDraw_3D, // The default drawing routine + { + MouseDown, // Process mouse down events + MouseUp, // Process mouse up events + 0, // Process mouse move events (NOT USED) + }, + { + 1, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + ToggleOff, // Process toggle off events + ToggleOn, // Process toggle on events + }, + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Process dial move events (NOT USED) + } }; // Default color scheme @@ -80,7 +91,7 @@ static void SendButtonEvent(GWidgetObject *gw) { // Trigger a GWIN Button Event psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) { + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pbe->type = GEVENT_GWIN_BUTTON; @@ -114,25 +125,36 @@ static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { } // A toggle off has occurred -static void ToggleOff(GWidgetObject *gw, uint16_t instance) { - (void) instance; +static void ToggleOff(GWidgetObject *gw, uint16_t role) { + (void) role; gw->g.flags &= ~GBUTTON_FLG_PRESSED; _gwidgetRedraw((GHandle)gw); } // A toggle on has occurred -static void ToggleOn(GWidgetObject *gw, uint16_t instance) { - (void) instance; +static void ToggleOn(GWidgetObject *gw, uint16_t role) { + (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; _gwidgetRedraw((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) SendButtonEvent(gw); } +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GButtonObject *)gw)->toggle = instance; +} + +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GButtonObject *)gw)->toggle; +} + GHandle gwinCreateButton(GButtonObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gw = (GButtonObject *)_gwidgetInit((GWidgetObject *)gw, x, y, width, height, sizeof(GButtonObject), &buttonVMT))) + if (!(gw = (GButtonObject *)_gwidgetCreate((GWidgetObject *)gw, x, y, width, height, sizeof(GButtonObject), &buttonVMT))) return 0; + gw->toggle = GWIDGET_NO_INSTANCE; gw->c_up = GButtonDefaultColorsUp; gw->c_dn = GButtonDefaultColorsDown; gw->c_dis = GButtonDefaultColorsDisabled; diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 893dab9c..53e99e42 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -26,7 +26,9 @@ // Prototypes for button VMT functions static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y); -static void ToggleOn(GWidgetObject *gw, uint16_t instance); +static void ToggleOn(GWidgetObject *gw, uint16_t role); +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance); +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role); // The button VMT table static const gwidgetVMT checkboxVMT = { @@ -37,15 +39,24 @@ static const gwidgetVMT checkboxVMT = { 0, // The after-clear routine }, gwinCheckboxDraw_CheckOnLeft, // The default drawing routine - MouseDown, // Process mouse down events - 0, // Process mouse up events (NOT USED) - 0, // Process mouse move events (NOT USED) - 0, // Process toggle off events (NOT USED) - ToggleOn, // Process toggle on events - 0, // Process dial move events (NOT USED) - 0, // Process all events (NOT USED) - 0, // AssignToggle (NOT USED) - 0, // AssignDial (NOT USED) + { + MouseDown, // Process mouse down events + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + }, + { + 1, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + }, + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Process dial move events (NOT USED) + } }; static const GCheckboxColors defaultColors = { @@ -63,7 +74,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { // Trigger a GWIN Checkbox Event psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) { + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pce->type = GEVENT_GWIN_CHECKBOX; @@ -84,17 +95,28 @@ static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { } // A toggle on has occurred -static void ToggleOn(GWidgetObject *gw, uint16_t instance) { - (void) instance; +static void ToggleOn(GWidgetObject *gw, uint16_t role) { + (void) role; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; _gwidgetRedraw((GHandle)gw); SendCheckboxEvent(gw); } +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GCheckboxObject *)gw)->toggle = instance; +} + +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GCheckboxObject *)gw)->toggle; +} + GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gb = (GCheckboxObject *)_gwidgetInit((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT))) + if (!(gb = (GCheckboxObject *)_gwidgetCreate((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT))) return 0; + gb->toggle = (uint16_t) -1; gb->c = defaultColors; // assign the default colors return (GHandle)gb; } diff --git a/src/gwin/console.c b/src/gwin/console.c index c4b2798d..6941295a 100644 --- a/src/gwin/console.c +++ b/src/gwin/console.c @@ -66,7 +66,7 @@ static const gwinVMT consoleVMT = { }; GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gc = (GConsoleObject *)_gwindowInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT, GWIN_FLG_VISIBLE))) + if (!(gc = (GConsoleObject *)_gwindowCreate((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT, GWIN_FLG_VISIBLE))) return 0; #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM gc->stream.vmt = &GWindowConsoleVMT; diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 393297e7..264c0c2c 100644 --- a/src/gwin/graph.c +++ b/src/gwin/graph.c @@ -165,7 +165,7 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t } GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gg = (GGraphObject *)_gwindowInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT, GWIN_FLG_VISIBLE))) + if (!(gg = (GGraphObject *)_gwindowCreate((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT, GWIN_FLG_VISIBLE))) return 0; gg->xorigin = gg->yorigin = 0; gg->lastx = gg->lasty = 0; diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index 773a715d..ee7986d1 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -13,23 +13,25 @@ #include "gwin/class_gwin.h" +/* Our listener for events for widgets */ +static GListener gl; + /* We use these everywhere in this file */ #define gw ((GWidgetObject *)gh) #define wvmt ((gwidgetVMT *)gh->vmt) -static void gwidgetCallback(void *param, GEvent *pe) { - #define gh ((GWindowObject *)param) +/* Process an event */ +static void gwidgetEvent(void *param, GEvent *pe) { + #define gh QItem2GWindow(qi) #define pme ((GEventMouse *)pe) #define pte ((GEventToggle *)pe) #define pde ((GEventDial *)pe) - // check if widget is disabled - if ((gw->g.flags & (GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) - return; - - // Process via AllEvents() if it is defined - if (wvmt->AllEvents) - wvmt->AllEvents(gw, pe); + const gfxQueueASyncItem * qi; + #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) + uint16_t role; + #endif + (void) param; // Process various events switch (pe->type) { @@ -37,76 +39,179 @@ static void gwidgetCallback(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE case GEVENT_MOUSE: case GEVENT_TOUCH: - // Are we captured? - if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { - if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { - gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; - if (wvmt->MouseUp) - wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); - return; - } else if (wvmt->MouseMove) - wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y); + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - // We are not captured - look for mouse downs over the widget - } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) - && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width - && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) { - gw->g.flags |= GWIN_FLG_MOUSECAPTURE; - if (wvmt->MouseDown) - wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y); + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + continue; + + // Are we captured? + if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { + if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { + gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; + if (wvmt->MouseUp) + wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); + } else if (wvmt->MouseMove) + wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y); + + // We are not captured - look for mouse downs over the widget + } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) + && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width + && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) { + gw->g.flags |= GWIN_FLG_MOUSECAPTURE; + if (wvmt->MouseDown) + wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y); + } } break; #endif #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE case GEVENT_TOGGLE: - if (pte->on) { - if (wvmt->ToggleOn) - wvmt->ToggleOn(gw, pte->instance); - } else { - if (wvmt->ToggleOff) - wvmt->ToggleOff(gw, pte->instance); + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + 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: - if (wvmt->DialMove) - wvmt->DialMove(gw, pde->instance, pde->value); + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + 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 gh #undef pme #undef pte #undef pde } -GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) { - if (!(pgw = (GWidgetObject *)_gwindowInit((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + static GHandle FindToggleUser(uint16_t instance) { + #define gh QItem2GWindow(qi) + const gfxQueueASyncItem * qi; + uint16_t role; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + 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; + #undef gh + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + static GHandle FindDialUser(uint16_t instance) { + #define gh QItem2GWindow(qi) + const gfxQueueASyncItem * qi; + uint16_t role; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + 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; + #undef gh + } +#endif + +void _gwidgetInit(void) { + geventListenerInit(&gl); + geventRegisterCallback(&gl, gwidgetEvent, 0); +} + +GHandle _gwidgetCreate(GWidgetObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) { + if (!(pgw = (GWidgetObject *)_gwindowCreate((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) return 0; pgw->txt = ""; pgw->fnDraw = vmt->DefaultDraw; pgw->fnParam = 0; - geventListenerInit(&pgw->listener); - geventRegisterCallback(&pgw->listener, gwidgetCallback, pgw); return (GHandle)pgw; } void _gwidgetDestroy(GHandle gh) { + #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) + uint16_t role, instance; + #endif + // Deallocate the text (if necessary) if ((gh->flags & GWIN_FLG_ALLOCTXT)) { gh->flags &= ~GWIN_FLG_ALLOCTXT; gfxFree((void *)gw->txt); } - // Untangle the listeners (both on us and to us). - geventDetachSource(&gw->listener, 0); + + #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); } @@ -183,76 +288,89 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { _gwidgetRedraw(gh); } -bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags) { - if (!(gh->flags & GWIN_FLG_WIDGET)) - return FALSE; - - return geventAttachSource(pl, (GSourceHandle)gh, flags); +bool_t gwinAttachListener(GListener *pl) { + return geventAttachSource(pl, GWIDGET_SOURCE, 0); } #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinAttachMouse(GHandle gh, uint16_t instance) { + bool_t gwinAttachMouse(uint16_t instance) { GSourceHandle gsh; - unsigned flags; - - if (!(gh->flags & GWIN_FLG_WIDGET)) - return FALSE; - - if (!wvmt->MouseDown && !wvmt->MouseMove && !wvmt->MouseUp) - return FALSE; if (!(gsh = ginputGetMouse(instance))) return FALSE; - flags = wvmt->MouseMove ? (GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES) : GLISTEN_MOUSEMETA; - return geventAttachSource(&gw->listener, gsh, flags); + return geventAttachSource(&gl, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); } #endif #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { GSourceHandle gsh; - unsigned flags; + uint16_t oi; + // Is this a widget if (!(gh->flags & GWIN_FLG_WIDGET)) return FALSE; - flags = 0; - if (wvmt->ToggleOff) flags |= GLISTEN_TOGGLE_OFF; - if (wvmt->ToggleOn) flags |= GLISTEN_TOGGLE_ON; - if (!flags) + // Is the role valid + if (role >= wvmt->toggleroles) return FALSE; + // Is this a valid device if (!(gsh = ginputGetToggle(instance))) return FALSE; - if (wvmt->AssignToggle && !wvmt->AssignToggle(gw, role, instance)) - return FALSE; + // Is this already done? + oi = wvmt->ToggleGet(gw, role); + if (instance == oi) + return TRUE; - return geventAttachSource(&gw->listener, gsh, flags); + // 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); } #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; - if (!wvmt->DialMove) + // Is the role valid + if (role >= wvmt->dialroles) return FALSE; + // Is this a valid device if (!(gsh = ginputGetDial(instance))) return FALSE; - if (wvmt->AssignDial && !wvmt->AssignDial(gw, role, instance)) - return FALSE; + // Is this already done? + oi = wvmt->DialGet(gw, role); + if (instance == oi) + return TRUE; - return geventAttachSource(&gw->listener, gsh, 0); + // 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 #endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */ /** @} */ - diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 3e790d38..98e61c52 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -70,6 +70,11 @@ static color_t defaultBgColor = Black; *-----------------------------------------------*/ void _gwinInit(void) { + #if GWIN_NEED_WIDGET + extern void _gwidgetInit(void); + + _gwidgetInit(); + #endif #if GWIN_NEED_WINDOWMANAGER gfxQueueASyncInit(&_GWINList); cwm = &GNullWindowManager; @@ -79,7 +84,7 @@ void _gwinInit(void) { // Internal routine for use by GWIN components only // Initialise a window creating it dynamically if required. -GHandle _gwindowInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt, uint16_t flags) { +GHandle _gwindowCreate(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt, uint16_t flags) { // Allocate the structure if necessary if (!pgw) { if (!(pgw = (GWindowObject *)gfxAlloc(size))) @@ -146,7 +151,7 @@ void gwinSetDefaultBgColor(color_t bgclr) { *-----------------------------------------------*/ GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) { - return _gwindowInit(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT, GWIN_FLG_VISIBLE); + return _gwindowCreate(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT, GWIN_FLG_VISIBLE); } void gwinDestroy(GHandle gh) { diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 1a1855a9..343973a2 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -25,10 +25,19 @@ #define GWIN_SLIDER_DEAD_BAND 5 #endif +#ifndef GWIN_SLIDER_TOGGLE_INC + #define GWIN_SLIDER_TOGGLE_INC 20 // How many toggles to go from minimum to maximum +#endif + // Prototypes for slider VMT functions static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y); static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y); -static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value); +static void ToggleOn(GWidgetObject *gw, uint16_t role); +static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max); +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance); +static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance); +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role); +static uint16_t DialGet(GWidgetObject *gw, uint16_t role); // The button VMT table static const gwidgetVMT sliderVMT = { @@ -38,16 +47,25 @@ static const gwidgetVMT sliderVMT = { _gwidgetRedraw, // The redraw routine 0, // The after-clear routine }, - gwinSliderDraw_Std, // The default drawing routine - MouseMove, // Process mouse down events (AS MOUSEMOVE) - MouseUp, // Process mouse up events - MouseMove, // Process mouse move events - 0, // Process toggle off events (NOT USED) - 0, // Process toggle on events (NOT USED) - DialMove, // Process dial move events - 0, // Process all events (NOT USED) - 0, // AssignToggle (NOT USED) - 0, // AssignDial (NOT USED) + gwinSliderDraw_Std, // The default drawing routine + { + 0, // Process mouse down events (NOT USED) + MouseUp, // Process mouse up events + MouseMove, // Process mouse move events + }, + { + 2, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + }, + { + 1, // 1 dial roles + DialAssign, // Assign Dials + DialGet, // Get Dials + DialMove, // Process dial move events + } }; static const GSliderColors GSliderDefaultColors = { @@ -66,7 +84,7 @@ static void SendSliderEvent(GWidgetObject *gw) { // Trigger a GWIN Button Event psl = 0; - while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) { + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pse->type = GEVENT_GWIN_SLIDER; @@ -75,7 +93,7 @@ static void SendSliderEvent(GWidgetObject *gw) { geventSendEvent(psl); } - #undef pbe + #undef pse } // Reset the display position back to the value predicted by the saved slider position @@ -159,13 +177,28 @@ static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) { #undef gsw } -// A dial move event -static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value) { -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL +// A toggle on has occurred +static void ToggleOn(GWidgetObject *gw, uint16_t role) { #define gsw ((GSliderObject *)gw) + if (role) { + gwinSetSliderPosition((GHandle)gw, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gw); + } else { + gwinSetSliderPosition((GHandle)gw, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gw); + } + #undef gsw +} + +// A dial move event +static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max) { +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + #define gsw ((GSliderObject *)gw) + (void) role; + // Set the new position - gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/ginputGetDialRange(instance) + gsw->min); + gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); ResetDisplayPos(gsw); gwinDraw(&gw->g); @@ -174,13 +207,37 @@ static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value) { SendSliderEvent(gw); #undef gsw #else - (void)gw; (void)instance; (void)value; + (void)gw; (void)role; (void)value; (void)max; #endif } +static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + if (role) + ((GSliderObject *)gw)->t_up = instance; + else + ((GSliderObject *)gw)->t_dn = instance; +} + +static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + return role ? ((GSliderObject *)gw)->t_up : ((GSliderObject *)gw)->t_dn; +} + +static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GSliderObject *)gw)->dial = instance; +} + +static uint16_t DialGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GSliderObject *)gw)->dial; +} + GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gs = (GSliderObject *)_gwidgetInit((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT))) + if (!(gs = (GSliderObject *)_gwidgetCreate((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT))) return 0; + gs->t_dn = (uint16_t) -1; + gs->t_up = (uint16_t) -1; + gs->dial = (uint16_t) -1; gs->c = GSliderDefaultColors; gs->min = 0; gs->max = 100;