From b9f53aa7936686134f19c480346816a3d234f7f7 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 25 Jan 2015 17:40:34 +1000 Subject: [PATCH] Add the ability to flash a gwin window/widget. Only the button draws for checkbox's and radio's currently do anything about it. Widget demo updated to show this on Checkbox 3 (the toggle button). --- demos/modules/gwin/widgets/gfxconf.h | 1 + demos/modules/gwin/widgets/main.c | 14 ++++++ gfxconf.example.h | 2 + src/gwin/gwin.h | 34 +++++++++++++ src/gwin/gwin_checkbox.c | 10 ++++ src/gwin/gwin_class.h | 19 ++++++- src/gwin/gwin_options.h | 15 ++++++ src/gwin/gwin_radio.c | 12 ++++- src/gwin/gwin_wm.c | 75 ++++++++++++++++++++++++++++ 9 files changed, 180 insertions(+), 2 deletions(-) diff --git a/demos/modules/gwin/widgets/gfxconf.h b/demos/modules/gwin/widgets/gfxconf.h index e7e2714e..4ba2c21d 100644 --- a/demos/modules/gwin/widgets/gfxconf.h +++ b/demos/modules/gwin/widgets/gfxconf.h @@ -51,6 +51,7 @@ #define GFX_USE_GWIN TRUE #define GWIN_NEED_WINDOWMANAGER TRUE + #define GWIN_NEED_FLASHING TRUE #define GWIN_NEED_CONSOLE TRUE #define GWIN_CONSOLE_USE_HISTORY TRUE diff --git a/demos/modules/gwin/widgets/main.c b/demos/modules/gwin/widgets/main.c index 80cd6c02..d5bfb6d2 100644 --- a/demos/modules/gwin/widgets/main.c +++ b/demos/modules/gwin/widgets/main.c @@ -79,6 +79,8 @@ static const GWidgetStyle YellowWidgetStyle = { static font_t font; static GListener gl; static GHandle ghConsole; +static GTimer FlashTimer; + #if GWIN_NEED_TABSET static GHandle ghTabset; #else @@ -485,6 +487,12 @@ static void setEnabled(bool_t ena) { //gwinSetEnabled(ghCheckDisableAll, TRUE); } +static void FlashOffFn(void *param) { + (void) param; + + gwinNoFlash(ghCheckbox3); +} + int main(void) { GEvent * pe; @@ -517,6 +525,7 @@ int main(void) { // We want to listen for widget events geventListenerInit(&gl); gwinAttachListener(&gl); + gtimerInit(&FlashTimer); #if !GWIN_NEED_TABSET // Press the Tab we want visible @@ -543,6 +552,11 @@ int main(void) { if (((GEventGWinCheckbox *)pe)->gwin == ghCheckDisableAll) { gwinPrintf(ghConsole, "%s All\n", ((GEventGWinCheckbox *)pe)->isChecked ? "Disable" : "Enable"); setEnabled(!((GEventGWinCheckbox *)pe)->isChecked); + + // If it is the toggle button checkbox start the flash. + } else if (((GEventGWinCheckbox *)pe)->gwin == ghCheckbox3) { + gwinFlash(ghCheckbox3); + gtimerStart(&FlashTimer, FlashOffFn, 0, FALSE, 3000); } break; diff --git a/gfxconf.example.h b/gfxconf.example.h index 3a91d21a..4c94bb18 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -148,6 +148,8 @@ //#define GWIN_NEED_WINDOWMANAGER FALSE // #define GWIN_REDRAW_IMMEDIATE FALSE // #define GWIN_REDRAW_SINGLEOP FALSE +// #define GWIN_NEED_FLASHING FALSE +// #define GWIN_FLASHING_PERIOD 250 //#define GWIN_NEED_CONSOLE FALSE // #define GWIN_CONSOLE_USE_HISTORY FALSE diff --git a/src/gwin/gwin.h b/src/gwin/gwin.h index 81bf38e5..9b2d18b7 100644 --- a/src/gwin/gwin.h +++ b/src/gwin/gwin.h @@ -547,6 +547,40 @@ extern "C" { */ GHandle gwinGetNextWindow(GHandle gh); + /** + * @brief Set a window or widget to flash + * + * @param[in] gh The window handle + * @param[in] flash Enable or disable the flashing of the window + * + * @note The window is automatically redrawn if it supports self-redrawing. + * @note When a window is set to flash, its appearance changes in some + * way every flash period (GWIN_FLASHING_PERIOD). How its appearance + * changes depends on the draw for each window/widget. + * + * @pre Requires GWIN_NEED_FLASHING to be TRUE + * + * @api + */ + void gwinSetFlashing(GHandle gh, bool_t flash); + + /** + * @brief Enables flashing of a window or widget + * + * @param[in] gh The window handle + * + * @api + */ + #define gwinFlash(gh) gwinSetFlashing(gh, TRUE) + + /** + * @brief Disables a widget + * + * @param[in] gh The window handle + * + * @api + */ + #define gwinNoFlash(gh) gwinSetFlashing(gh, FALSE) #endif #if GDISP_NEED_TEXT || defined(__DOXYGEN__) diff --git a/src/gwin/gwin_checkbox.c b/src/gwin/gwin_checkbox.c index ff0507d9..3f1d46bf 100644 --- a/src/gwin/gwin_checkbox.c +++ b/src/gwin/gwin_checkbox.c @@ -216,6 +216,11 @@ void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; pcol = getDrawColors(gw); + #if GWIN_NEED_FLASHING + // Flash the on and off state. + pcol = _gwinGetFlashedColor(gw, pcol, TRUE); + #endif + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); @@ -232,6 +237,11 @@ void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; pcol = getDrawColors(gw); + #if GWIN_NEED_FLASHING + // Flash the on and off state. + pcol = _gwinGetFlashedColor(gw, pcol, TRUE); + #endif + /* Fill the box blended from variants of the fill color */ tcol = gdispBlendColor(White, pcol->fill, TOP_FADE); bcol = gdispBlendColor(Black, pcol->fill, BOTTOM_FADE); diff --git a/src/gwin/gwin_class.h b/src/gwin/gwin_class.h index 8cb17ac8..01b6e596 100644 --- a/src/gwin/gwin_class.h +++ b/src/gwin/gwin_class.h @@ -47,6 +47,7 @@ #define GWIN_FLG_MINIMIZED 0x00100000 // @< The window is minimized #define GWIN_FLG_MAXIMIZED 0x00200000 // @< The window is maximized #define GWIN_FLG_MOUSECAPTURE 0x00400000 // @< The window has captured the mouse +#define GWIN_FLG_FLASHING 0x00800000 // @< The window is flashing - see the _gwinFlashState boolean #define GWIN_FIRST_WM_FLAG 0x01000000 // @< 8 bits free for the window manager to use #define GWIN_LAST_WM_FLAG 0x80000000 // @< 8 bits free for the window manager to use /** @} */ @@ -165,7 +166,9 @@ typedef struct gwinVMT { /** * @brief The current window manager */ - extern GWindowManager * _GWINwm; + extern GWindowManager * _GWINwm; + extern bool_t _gwinFlashState; + #endif #ifdef __cplusplus @@ -313,6 +316,20 @@ bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit); * @notapi */ void _gwinSendEvent(GHandle gh, GEventType type); + + + #if GWIN_NEED_FLASHING || defined(__DOXYGEN__) + /** + * @brief Convert a chosen style color set pressed/enabled etc if flashing + * @return The colorset - after flashing is taken into account + * + * @param[in] gw The widget + * @param[in] pcol The style color set that has been chosen to reflect the state of the widget + * @param[in] flashOffState Whether the off-state should be flashed as well. If false, only the + * pressed color set is flashed. + */ + const GColorSet *_gwinGetFlashedColor(GWidgetObject *gw, const GColorSet *pcol, bool_t flashOffState); + #endif #endif #if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) diff --git a/src/gwin/gwin_options.h b/src/gwin/gwin_options.h index 9252e67a..106c5e06 100644 --- a/src/gwin/gwin_options.h +++ b/src/gwin/gwin_options.h @@ -328,6 +328,21 @@ #ifndef GWIN_TABSET_TABHEIGHT #define GWIN_TABSET_TABHEIGHT 18 #endif + /** + * @brief Should flashing of widgets be supported + * @details Defaults to FALSE + * @pre Requires GWIN_NEED_WINDOWMANAGER to be TRUE + */ + #ifndef GWIN_NEED_FLASHING + #define GWIN_NEED_FLASHING FALSE + #endif + /** + * @brief What is the period for the flashing timer + * @details Defaults to 250 milliseconds + */ + #ifndef GWIN_FLASHING_PERIOD + #define GWIN_FLASHING_PERIOD 250 + #endif /** @} */ #endif /* _GWIN_OPTIONS_H */ diff --git a/src/gwin/gwin_radio.c b/src/gwin/gwin_radio.c index 0bafa7cc..b9076109 100644 --- a/src/gwin/gwin_radio.c +++ b/src/gwin/gwin_radio.c @@ -203,7 +203,12 @@ void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&radioVMT) return; pcol = getDrawColors(gw); - + + #if GWIN_NEED_FLASHING + // Flash only the on state. + pcol = _gwinGetFlashedColor(gw, pcol, FALSE); + #endif + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); gdispGDrawLine(gw->g.display, gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); gdispGDrawLine(gw->g.display, gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); @@ -215,6 +220,11 @@ void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&radioVMT) return; pcol = getDrawColors(gw); + #if GWIN_NEED_FLASHING + // Flash only the on state. + pcol = _gwinGetFlashedColor(gw, pcol, FALSE); + #endif + if ((gw->g.flags & GRADIO_FLG_PRESSED)) { gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); gdispGFillStringBox(gw->g.display, gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); diff --git a/src/gwin/gwin_wm.c b/src/gwin/gwin_wm.c index 6d860f23..00365c36 100644 --- a/src/gwin/gwin_wm.c +++ b/src/gwin/gwin_wm.c @@ -161,9 +161,13 @@ // The default window manager extern const GWindowManager GNullWindowManager; GWindowManager * _GWINwm; +bool_t _gwinFlashState; static gfxSem gwinsem; static gfxQueueASync _GWINList; +#if GWIN_NEED_FLASHING + static GTimer FlashTimer; +#endif #if !GWIN_REDRAW_IMMEDIATE static GTimer RedrawTimer; static void RedrawTimerFn(void *param); @@ -171,6 +175,7 @@ static gfxQueueASync _GWINList; static volatile uint8_t RedrawPending; #define DOREDRAW_INVISIBLES 0x01 #define DOREDRAW_VISIBLES 0x02 + #define DOREDRAW_FLASHRUNNING 0x04 /*----------------------------------------------- @@ -181,6 +186,9 @@ void _gwmInit(void) { gfxSemInit(&gwinsem, 1, 1); gfxQueueASyncInit(&_GWINList); + #if GWIN_NEED_FLASHING + gtimerInit(&FlashTimer); + #endif #if !GWIN_REDRAW_IMMEDIATE gtimerInit(&RedrawTimer); gtimerStart(&RedrawTimer, RedrawTimerFn, 0, TRUE, TIME_INFINITE); @@ -563,6 +571,73 @@ GHandle gwinGetNextWindow(GHandle gh) { return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList); } +#if GWIN_NEED_FLASHING + static void FlashTimerFn(void *param) { + GHandle gh; + (void) param; + + // Assume we will be stopping + RedrawPending &= ~DOREDRAW_FLASHRUNNING; + + // Swap the flash state + _gwinFlashState = !_gwinFlashState; + + // Redraw all flashing windows + for(gh = (GHandle)gfxQueueASyncPeek(&_GWINList); gh; gh = (GHandle)gfxQueueASyncNext(&gh->wmq)) { + if ((gh->flags & GWIN_FLG_FLASHING)) { + RedrawPending |= DOREDRAW_FLASHRUNNING; + _gwinUpdate(gh); + } + } + + // Do we have no flashers left? + if (!(RedrawPending & DOREDRAW_FLASHRUNNING)) + gtimerStop(&FlashTimer); + } + + void gwinSetFlashing(GHandle gh, bool_t flash) { + + // Start flashing? + if (flash) { + gh->flags |= GWIN_FLG_FLASHING; // A redraw will occur on the next flash period. + + // Start the flash timer if needed + if (!(RedrawPending & DOREDRAW_FLASHRUNNING)) { + RedrawPending |= DOREDRAW_FLASHRUNNING; + + // Ensure we start the timer with flash bit on + _gwinFlashState = FALSE; + FlashTimerFn(0); // First flash + gtimerStart(&FlashTimer, FlashTimerFn, 0, TRUE, GWIN_FLASHING_PERIOD); // Subsequent flashes + } + + // Stop flashing? + } else if ((gh->flags & GWIN_FLG_FLASHING)) { + gh->flags &= ~GWIN_FLG_FLASHING; + // We need to manually redraw as the timer is now turned off for this window + _gwinUpdate(gh); + } + } + + #if GWIN_NEED_WIDGET + const GColorSet *_gwinGetFlashedColor(GWidgetObject *gw, const GColorSet *pcol, bool_t flashOffState) { + // Does the flashing state affect the current colors? + if ((gw->g.flags & GWIN_FLG_FLASHING) && _gwinFlashState) { + + // For a pressed state show an unpressed state + if (pcol == &gw->pstyle->pressed) + pcol = &gw->pstyle->enabled; + + // For a non-pressed state (if allowed) show a pressed state + else if (flashOffState && pcol == &gw->pstyle->enabled) + pcol = &gw->pstyle->pressed; + } + return pcol; + } + #endif +#endif + + /*----------------------------------------------- * "Null" Window Manager Routines *-----------------------------------------------*/