diff --git a/drivers/multiple/Win32/gdisp_lld_Win32.c b/drivers/multiple/Win32/gdisp_lld_Win32.c index 5c30ccff..3643d727 100644 --- a/drivers/multiple/Win32/gdisp_lld_Win32.c +++ b/drivers/multiple/Win32/gdisp_lld_Win32.c @@ -85,7 +85,7 @@ static HANDLE drawMutex; #define WIN32_BUTTON_AREA 0 #endif -#define APP_NAME "uGFX Simulator" +#define APP_NAME "uGFX" typedef struct winPriv { HWND hwnd; diff --git a/gfxconf.example.h b/gfxconf.example.h index d4bf7e96..cf3f1b2b 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -133,6 +133,7 @@ #define GWIN_CONSOLE_USE_BASESTREAM FALSE #define GWIN_CONSOLE_USE_FLOAT FALSE #define GWIN_NEED_GRAPH FALSE + #define GWIN_NEED_WIDGET FALSE #define GWIN_NEED_LABEL FALSE #define GWIN_LABEL_ATTRIBUTE FALSE @@ -148,6 +149,8 @@ #define GWIN_NEED_PROGRESSBAR FALSE #define GWIN_PROGRESSBAR_AUTO FALSE #define GWIN_FLAT_STYLING FALSE +#define GWIN_NEED_CONTAINERS FALSE + #define GWIN_NEED_FRAME FALSE /////////////////////////////////////////////////////////////////////////// diff --git a/src/gwin/button.c b/src/gwin/button.c index f34e4ba3..da68d267 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -55,14 +55,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); } // A mouse up has occurred (it may or may not be over the button) static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags &= ~GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); #if !GWIN_BUTTON_LAZY_RELEASE // If the mouse up was not over the button then cancel the event @@ -79,14 +79,14 @@ static void SendButtonEvent(GWidgetObject *gw) { static void ToggleOff(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags &= ~GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); } // A toggle on has occurred static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags |= GBUTTON_FLG_PRESSED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); // Trigger the event on button down (different than for mouse/touch) SendButtonEvent(gw); } @@ -161,7 +161,7 @@ bool_t gwinButtonIsPressed(GHandle gh) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled; } @@ -336,7 +336,7 @@ static const GColorSet *getDrawColors(GWidgetObject *gw) { if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; pcol = getDrawColors(gw); - if (!(gw->g.flags & GWIN_FLG_ENABLED)) { + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) { sy = 2 * gw->g.height; } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) { sy = gw->g.height; diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 8cdd51d9..11d76cb2 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -48,7 +48,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { (void) x; (void) y; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); SendCheckboxEvent(gw); } #endif @@ -57,7 +57,7 @@ static void SendCheckboxEvent(GWidgetObject *gw) { static void ToggleOn(GWidgetObject *gw, uint16_t role) { (void) role; gw->g.flags ^= GCHECKBOX_FLG_CHECKED; - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); SendCheckboxEvent(gw); } @@ -130,7 +130,7 @@ void gwinCheckboxCheck(GHandle gh, bool_t isChecked) { if (!(gh->flags & GCHECKBOX_FLG_CHECKED)) return; gh->flags &= ~GCHECKBOX_FLG_CHECKED; } - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); SendCheckboxEvent((GWidgetObject *)gh); } @@ -146,7 +146,7 @@ bool_t gwinCheckboxIsChecked(GHandle gh) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GCHECKBOX_FLG_CHECKED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled; } diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h index 50dd480e..e3b5e2e3 100644 --- a/src/gwin/class_gwin.h +++ b/src/gwin/class_gwin.h @@ -27,16 +27,20 @@ * @brief The predefined flags for a Window * @{ */ -#define GWIN_FLG_DYNAMIC 0x0001 // @< The GWIN structure is allocated -#define GWIN_FLG_VISIBLE 0x0002 // @< The window is visible -#define GWIN_FLG_MINIMIZED 0x0004 // @< The window is minimized -#define GWIN_FLG_MAXIMIZED 0x0008 // @< The window is maximized -#define GWIN_FLG_ENABLED 0x0010 // @< The window is enabled -#define GWIN_FLG_WIDGET 0x0020 // @< This is a widget -#define GWIN_FLG_ALLOCTXT 0x0040 // @< The widget text is allocated -#define GWIN_FLG_MOUSECAPTURE 0x0080 // @< The widget has captured the mouse -#define GWIN_FIRST_WM_FLAG 0x0100 // @< 4 bits free for the window manager to use -#define GWIN_FIRST_CONTROL_FLAG 0x1000 // @< 4 bits free for Windows and Widgets to use +#define GWIN_FIRST_CONTROL_FLAG 0x00000001 // @< 8 bits free for the control to use +#define GWIN_FLG_VISIBLE 0x00000100 // @< The window is "visible" +#define GWIN_FLG_SYSVISIBLE 0x00000200 // @< The window is visible after parents are tested +#define GWIN_FLG_ENABLED 0x00000400 // @< The window is "enabled" +#define GWIN_FLG_SYSENABLED 0x00000800 // @< The window is enabled after parents are tested +#define GWIN_FLG_DYNAMIC 0x00001000 // @< The GWIN structure is allocated +#define GWIN_FLG_ALLOCTXT 0x00002000 // @< The text/label is allocated +#define GWIN_FLG_MOUSECAPTURE 0x00004000 // @< The window has captured the mouse +#define GWIN_FLG_SUPERMASK 0x000F0000 // @< The bit mask to leave just the window superclass type +#define GWIN_FLG_WIDGET 0x00010000 // @< This is a widget +#define GWIN_FLG_CONTAINER 0x00020000 // @< This is a container +#define GWIN_FLG_MINIMIZED 0x00100000 // @< The window is minimized +#define GWIN_FLG_MAXIMIZED 0x00200000 // @< The window is maximized +#define GWIN_FIRST_WM_FLAG 0x01000000 // @< 8 bits free for the window manager to use /* @} */ /** @@ -104,6 +108,27 @@ typedef struct gwinVMT { /* @} */ #endif +#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + + /** + * @brief The Virtual Method Table for a container + * @note A container must have a destroy function. Either use @p _gcontainerDestroy() or use your own function + * which internally calls @p _gcontainerDestroy(). + * @note A container must have a gwin redraw function. Use @p _containerRedraw(). + * @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 gcontainerVMT { + gwidgetVMT gw; + void (*Pos2Screen) (GHandle gh, coord_t *px, coord_t *py); // @< Translate client coords into absolute coords (mandatory) + void (*Size2Screen) (GHandle gh, coord_t *pwidth, coord_t *pheight); // @< Ensure a window fits in the parent client area (mandatory) + void (*NotifyAdd) (GHandle gh, GHandle ghChild); // @< Notification that a child has been added (optional) + void (*NotifyDelete) (GHandle gh, GHandle ghChild); // @< Notification that a child has been deleted (optional) + } gcontainerVMT; + /* @} */ +#endif + // These flags are needed whether or not we are running a window manager. /** * @brief Flags for redrawing after a visibility change @@ -111,16 +136,11 @@ typedef struct gwinVMT { */ #define GWIN_WMFLG_PRESERVE 0x0001 // @< Preserve whatever existing contents possible if a window can't redraw #define GWIN_WMFLG_NOBGCLEAR 0x0002 // @< Don't clear the area if the window is not visible -#define GWIN_WMFLG_NOZORDER 0x0004 // @< Don't redraw higher z-order windows that overlap +#define GWIN_WMFLG_KEEPCLIP 0x0004 // @< Don't modify the preset clipping area +#define GWIN_WMFLG_NOZORDER 0x0008 // @< Don't redraw higher z-order windows that overlap /* @} */ #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; @@ -136,17 +156,13 @@ typedef struct gwinVMT { bool_t (*Add) (GHandle gh, const GWindowInit *pInit); // @< A window has been added void (*Delete) (GHandle gh); // @< A window has been deleted void (*Redraw) (GHandle gh, int visflags); // @< A window needs to be redraw (or undrawn) - void (*Redim) (GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); // @< A window wants to be moved or resized + void (*Size) (GHandle gh, coord_t w, coord_t h); // @< A window wants to be resized + void (*Move) (GHandle gh, coord_t x, coord_t y); // @< A window wants to be moved void (*Raise) (GHandle gh); // @< A window wants to be on top void (*MinMax) (GHandle gh, GWindowMinMax minmax); // @< A window wants to be minimized/maximised } gwmVMT; /* @} */ - /** - * @brief The list of all windows in the system - */ - extern gfxQueueASync _GWINList; - /** * @brief The current window manager */ @@ -197,13 +213,93 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit void _gwidgetDestroy(GHandle gh); /** - * @brief Redraw the Widget object + * @brief Redraw the Widget object (VMT method only) * * @param[in] gh The widget to redraw * + * @note Do not use this routine to update a widget after a status change. + * Use @p _gwidgetUpdate() instead. The difference is that this routine + * does not set the clip region. This routine should only be used in the + * VMT. + * * @notapi */ void _gwidgetRedraw(GHandle gh); + + /** + * @brief Redraw the Widget object after a widget status change. + * + * @param[in] gh The widget to redraw + * + * @note Use this routine to update a widget after a status change. + * + * @notapi + */ + void _gwidgetUpdate(GHandle gh); +#endif + +#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + /** + * @brief Initialise (and allocate if necessary) the base Container object + * + * @param[in] g The GDisplay to display this window on + * @param[in] pgw The GContainerObject structure. If NULL one is allocated from the heap + * @param[in] pInit The user initialization parameters + * @param[in] vmt The virtual method table for the Container object + * + * @return The GHandle of the created widget + * + * @notapi + */ + GHandle _gcontainerCreate(GDisplay *g, GContainerObject *pgw, const GWidgetInit *pInit, const gcontainerVMT *vmt); + + /** + * @brief Destroy the Container object + * + * @param[in] gh The container to destroy + * + * @notapi + */ + void _gcontainerDestroy(GHandle gh); + + /** + * @brief Redraw the Container object (VMT method only) + * + * @param[in] gh The container to redraw + * + * @note Do not use this routine to update a container after a status change. + * Use @p _gcontainerUpdate() instead. The difference is that this routine + * does not set the clip region. This routine should only be used in the + * VMT. + * + * @notapi + */ + #define _gcontainerRedraw(gh) _gwidgetRedraw(gh) + + /** + * @brief Redraw the Container object after a container status change. + * + * @param[in] gh The container to redraw + * + * @note Use this routine to update a container after a status change. + * + * @notapi + */ + #define _gcontainerUpdate(gh) _gwidgetUpdate(gh) + + /** + * @brief Apply the specified action to a window and its children. + * @note The action is applied to the parent first and then its children. + * @note This routine is built to keep stack usage from recursing to a minimum. + * + * @param[in] gh The window to recurse through + * @param[in] fn The function to apply. If it returns TRUE any children it has should also have the function applied + * + * @notapi + */ + void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)); +#else + #define _gwinRecurse(gh, fn) fn(gh) #endif #ifdef __cplusplus diff --git a/src/gwin/frame.c b/src/gwin/frame.c index fbef54dc..9877b95e 100644 --- a/src/gwin/frame.c +++ b/src/gwin/frame.c @@ -190,7 +190,7 @@ static void _callbackBtn(void *param, GEvent *pe) { /////////////////////////////////////////////////////////////////////////////////////////////////// static const GColorSet* _getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; //if ((gw->g.flags & GBUTTON_FLG_PRESSED)) // return &gw->pstyle->pressed; @@ -213,10 +213,6 @@ void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { border = HTML2COLOR(0x2698DE); background = HTML2COLOR(0xEEEEEE); - #if GDISP_NEED_CLIP - gdispGSetClip(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height); - #endif - // Render the actual frame (with border, if any) if (gw->g.flags & GWIN_FRAME_BORDER) { gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, border); diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c new file mode 100644 index 00000000..98281183 --- /dev/null +++ b/src/gwin/gcontainer.c @@ -0,0 +1,71 @@ +/* + * 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 + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_CONTAINERS + +#include "src/gwin/class_gwin.h" + +void _gcontainerInit(void) +{ +} + +void _gcontainerDeinit(void) +{ +} + +GHandle _gcontainerCreate(GDisplay *g, GContainerObject *pgc, const GWidgetInit *pInit, const gcontainerVMT *vmt) { + if (!(pgc = (GContainerObject *)_gwidgetCreate(g, (GWidgetObject *)pgc, pInit, &vmt->gw))) + return 0; + + pgc->g.flags |= GWIN_FLG_CONTAINER; + + return &pgc->g; +} + +void _gcontainerDestroy(GHandle gh) { + GHandle child; + + while((child = gwinGetFirstChild(gh))) + gwinDestroy(child); + _gwidgetDestroy(gh); +} + +void _gwinRecurse(GHandle gh, bool_t (*fn)(GHandle gh)) { + if (fn(gh) && (gh->flags & GWIN_FLG_CONTAINER)) { + // Apply to this windows children + for(gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) { + // Only recurse when we have to. Otherwise apply it directly + if ((gh->flags & GWIN_FLG_CONTAINER)) + _gwinRecurse(gh, fn); + else + fn(gh); + } + } +} + +GHandle gwinGetFirstChild(GHandle gh) { + GHandle child; + + for(child = gwinGetNextWindow(0); child; child = gwinGetNextWindow(child)) + if (child->parent == gh) + return child; + return 0; +} + +GHandle gwinGetSibling(GHandle gh) { + GHandle child; + + for(child = gwinGetNextWindow(gh), gh = gh->parent; child; child = gwinGetNextWindow(child)) + if (child->parent == gh) + return child; + return 0; +} + +#endif /* GFX_USE_GWIN && GWIN_NEED_CONTAINERS */ +/** @} */ diff --git a/src/gwin/gcontainer.h b/src/gwin/gcontainer.h new file mode 100644 index 00000000..61852c7c --- /dev/null +++ b/src/gwin/gcontainer.h @@ -0,0 +1,92 @@ +/* + * 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/gcontainer.h + * @brief GWIN Containers header file. + */ + +#ifndef _GCONTAINER_H +#define _GCONTAINER_H + +/* This file is included within "gwin/gwin.h" */ + +/** + * @defgroup Containers Containers + * @ingroup GWIN + * + * @details A Container is a GWindow that supports child windows. It is also + * a widget in its own right and therefore can accept user input directly. + * + * @pre GFX_USE_GWIN and GWIN_NEED_CONTAINERS must be set to TRUE in your gfxconf.h + * @{ + */ + +// Forward definition +struct GContainerObject; + +/** + * @brief The GWIN Container structure + * @note A container is a GWIN widget that can have children. + * @note Do not access the members directly. Treat it as a black-box and use the method functions. + * + * @{ + */ +typedef GWidgetObject GContainerObject; +/* @} */ + +/** + * A comment/rant on the above structure: + * We would really like the GWidgetObject member to be anonymous. While this is + * allowed under the C11, C99, GNU and various other standards which have been + * around forever - compiler support often requires special flags e.g + * gcc requires the -fms-extensions flag (no wonder the language and compilers have + * not really progressed in 30 years). As portability is a key requirement + * we unfortunately won't use this useful feature in case we get a compiler that + * won't support it even with special flags. + */ + +#ifdef __cplusplus +extern "C" { +#endif + + /** + * @brief Get the first child window + * + * @return The first child or NULL if are no children windows + * + * @param[in] gh The parent container or NULL to get the first top level window + * + * @api + */ + GHandle gwinGetFirstChild(GHandle gh); + + /** + * @brief Get the next child window in the z-order + * + * @return The next window or NULL if no more children + * + * @param[in] gh The window to obtain the next sibling of. + * + * @note This returns the next window under the current parent window. + * Unlike @p gwinGetNextWindow() it will only return windows that + * have the same parent as the supplied window. + * + * @api + */ + GHandle gwinGetSibling(GHandle gh); +#ifdef __cplusplus +} +#endif + +/* Include extra container types */ +#if GWIN_NEED_FRAME || defined(__DOXYGEN__) + #include "src/gwin/frame.h" +#endif + +#endif /* _GCONTAINER_H */ +/** @} */ diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c index 9d6363ba..baf14ad1 100644 --- a/src/gwin/gimage.c +++ b/src/gwin/gimage.c @@ -30,7 +30,7 @@ static void _destroy(GWindowObject *gh) { #define gh ((GHandle)param) // We need to re-test the visibility in case it has been made invisible since the last frame. - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP @@ -160,7 +160,7 @@ bool_t gwinImageOpenGFile(GHandle gh, GFILE *f) { if ((gdispImageOpenGFile(&widget(gh)->image, f) & GDISP_IMAGE_ERR_UNRECOVERABLE)) return FALSE; - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { // Setting the clip here shouldn't be necessary if the redraw doesn't overdraw // but we put it in for safety anyway #if GDISP_NEED_CLIP diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c index c46520ea..de31daa8 100644 --- a/src/gwin/gwidget.c +++ b/src/gwin/gwidget.c @@ -82,16 +82,15 @@ static const GWidgetStyle * defaultStyle = &BlackWidgetStyle; /* 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) - const gfxQueueASyncItem * qi; + GHandle gh; #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) - uint16_t role; + uint16_t role; #endif - (void) param; + (void) param; // Process various events switch (pe->type) { @@ -100,14 +99,14 @@ static void gwidgetEvent(void *param, GEvent *pe) { case GEVENT_MOUSE: case GEVENT_TOUCH: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { // check if the widget matches this display if (gh->display != pme->display) continue; - // 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)) + // check if it is 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; // Are we captured? @@ -134,10 +133,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE case GEVENT_TOGGLE: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + 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_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_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++) { @@ -158,10 +157,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_DIAL case GEVENT_DIAL: // Cycle through all windows - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + 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_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_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++) { @@ -178,7 +177,6 @@ static void gwidgetEvent(void *param, GEvent *pe) { break; } - #undef gh #undef pme #undef pte #undef pde @@ -186,11 +184,10 @@ static void gwidgetEvent(void *param, GEvent *pe) { #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE static GHandle FindToggleUser(uint16_t instance) { - #define gh QItem2GWindow(qi) - const gfxQueueASyncItem * qi; - uint16_t role; + GHandle gh; + uint16_t role; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget continue; @@ -200,17 +197,15 @@ static void gwidgetEvent(void *param, GEvent *pe) { } } 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; + GHandle gh; + uint16_t role; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget continue; @@ -220,7 +215,6 @@ static void gwidgetEvent(void *param, GEvent *pe) { } } return 0; - #undef gh } #endif @@ -236,9 +230,14 @@ void _gwidgetDeinit(void) } 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))) + 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_COLLECTIONS + // This window can't be system enabled if the parent is not enabled + if (pgw->parent && !(pgw->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; @@ -287,13 +286,19 @@ void _gwidgetDestroy(GHandle gh) { } void _gwidgetRedraw(GHandle gh) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) + return; + + gw->fnDraw(gw, gw->fnParam); +} + +void _gwidgetUpdate(GHandle gh) { + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif - gw->fnDraw(gw, gw->fnParam); } @@ -310,11 +315,9 @@ void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) { pstyle = &BlackWidgetStyle; if (updateAll) { - const gfxQueueASyncItem * qi; GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle) gwinSetStyle(gh, pstyle); } @@ -359,7 +362,7 @@ void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { gw->text = (const char *)str; } else gw->text = text; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } const char *gwinGetText(GHandle gh) { @@ -375,7 +378,7 @@ void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { gw->pstyle = pstyle ? pstyle : defaultStyle; gh->bgcolor = pstyle->background; gh->color = pstyle->enabled.text; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } const GWidgetStyle *gwinGetStyle(GHandle gh) { @@ -391,7 +394,7 @@ void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { gw->fnDraw = fn ? fn : wvmt->DefaultDraw; gw->fnParam = param; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } bool_t gwinAttachListener(GListener *pl) { diff --git a/src/gwin/gwidget.h b/src/gwin/gwidget.h index 8795a95b..8373e2d0 100644 --- a/src/gwin/gwidget.h +++ b/src/gwin/gwidget.h @@ -27,7 +27,7 @@ * @{ */ -/* Forward definition */ +// Forward definition struct GWidgetObject; /** @@ -320,9 +320,5 @@ bool_t gwinAttachListener(GListener *pl); #include "src/gwin/progressbar.h" #endif -#if GWIN_NEED_FRAME || defined(__DOXYGEN__) - #include "gwin/frame.h" -#endif - #endif /* _GWIDGET_H */ /** @} */ diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index b48d8335..563b7abe 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -39,10 +39,11 @@ static color_t defaultBgColor = Black; #if GWIN_NEED_WINDOWMANAGER #define _gwm_redraw(gh, flags) _GWINwm->vmt->Redraw(gh, flags) - #define _gwm_redim(gh,x,y,w,h) _GWINwm->vmt->Redim(gh,x,y,w,h); + #define _gwm_move(gh,x,y) _GWINwm->vmt->Move(gh,x,y); + #define _gwm_resize(gh,w,h) _GWINwm->vmt->Size(gh,w,h); #else static void _gwm_redraw(GHandle gh, int flags) { - if ((gh->flags & GWIN_FLG_VISIBLE)) { + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); @@ -63,19 +64,22 @@ static color_t defaultBgColor = Black; gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, defaultBgColor); } } - static void _gwm_redim(GHandle gh, coord_t x, coord_t y, coord_t width, coord_t height) { - gh->x = x; gh->y = y; + static void _gwm_resize(GHandle gh, coord_t width, coord_t height) { gh->width = width; gh->height = height; - if (gh->x < 0) { gh->width += gh->x; gh->x = 0; } - if (gh->y < 0) { gh->height += gh->y; gh->y = 0; } - if (gh->x > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH; - if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_HEIGHT; if (gh->width < MIN_WIN_WIDTH) { gh->width = MIN_WIN_WIDTH; } if (gh->height < MIN_WIN_HEIGHT) { gh->height = MIN_WIN_HEIGHT; } if (gh->x+gh->width > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; - - // Redraw the window + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + static void _gwm_move(GHandle gh, coord_t x, coord_t y) { + gh->x = x; gh->y = y; + if (gh->x < 0) gh->x = 0; + if (gh->y < 0) gh->y = 0; + if (gh->x > gdispGetWidth()-MIN_WIN_WIDTH) gh->x = gdispGetWidth()-MIN_WIN_WIDTH; + if (gh->y > gdispGetHeight()-MIN_WIN_HEIGHT) gh->y = gdispGetHeight()-MIN_WIN_HEIGHT; + if (gh->x+gh->width > gdispGetWidth()) gh->width = gdispGetWidth() - gh->x; + if (gh->y+gh->height > gdispGetHeight()) gh->height = gdispGetHeight() - gh->y; _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #endif @@ -86,20 +90,30 @@ static color_t defaultBgColor = Black; void _gwinInit(void) { - #if GWIN_NEED_WIDGET - extern void _gwidgetInit(void); - - _gwidgetInit(); - #endif #if GWIN_NEED_WINDOWMANAGER extern void _gwmInit(void); _gwmInit(); #endif + #if GWIN_NEED_WIDGET + extern void _gwidgetInit(void); + + _gwidgetInit(); + #endif + #if GWIN_NEED_CONTAINERS + extern void _gcontainerInit(void); + + _gcontainerInit(); + #endif } void _gwinDeinit(void) { + #if GWIN_NEED_CONTAINERS + extern void _gcontainerDeinit(void); + + _gcontainerDeinit(); + #endif #if GWIN_NEED_WIDGET extern void _gwidgetDeinit(void); @@ -132,6 +146,18 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit pgw->font = defaultFont; #endif + #if GWIN_NEED_CONTAINERS + if (pInit->parent) { + if (!(pInit->parent->flags & GWIN_FLG_CONTAINER) || pgw->display != pgw->parent->display) { + if ((pgw->flags & GWIN_FLG_DYNAMIC)) + gfxFree(pgw); + return 0; + } + pgw->parent = pInit->parent; + } else + pgw->parent = 0; + #endif + #if GWIN_NEED_WINDOWMANAGER if (!_GWINwm->vmt->Add(pgw, pInit)) { if ((pgw->flags & GWIN_FLG_DYNAMIC)) @@ -139,13 +165,15 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit return 0; } #else - _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); + pgw->x = pgw->y = pgw->width = pgw->height = 0; + _gwm_move(pgw, pInit->x, pInit->y); + _gwm_resize(pgw, pInit->width, pInit->height); #endif - #if GWIN_NEED_HIERARCHY - pgw->parent = NULL; - pgw->sibling = NULL; - pgw->child = NULL; + #if GWIN_NEED_CONTAINERS + // Notify the parent it has been added + if (pgw->parent && ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd) + ((gcontainerVMT *)pgw->parent->vmt)->NotifyAdd(pgw->parent, pgw); #endif return (GHandle)pgw; @@ -206,25 +234,15 @@ void gwinDestroy(GHandle gh) { if (!gh) return; - #if GWIN_NEED_HIERARCHY - GHandle tmp; - - // recursively destroy our children first - for(tmp = gh->child; tmp; tmp = tmp->sibling) - gwinDestroy(tmp); - - // remove myself from the hierarchy - gwinRemoveChild(gh); - - // issue a redraw of my parent if any - if (gh->parent) { - gwinRedraw(gh->parent); - } - #endif - // Make the window invisible gwinSetVisible(gh, FALSE); + #if GWIN_NEED_CONTAINERS + // Notify the parent it is about to be deleted + if (gh->parent && ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete) + ((gcontainerVMT *)gh->parent->vmt)->NotifyDelete(gh->parent, gh); + #endif + // Remove from the window manager #if GWIN_NEED_WINDOWMANAGER _GWINwm->vmt->Delete(gh); @@ -246,78 +264,124 @@ const char *gwinGetClassName(GHandle gh) { return gh->vmt->classname; } -void gwinSetVisible(GHandle gh, bool_t visible) { - if (visible) { - if (!(gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags |= GWIN_FLG_VISIBLE; - _gwm_redraw(gh, 0); +#if GWIN_NEED_CONTAINERS + // These two sub-functions set/clear system visibility recursively. + static bool_t setSysVisFlag(GHandle gh) { + // If we are now visible and our parent is visible + if ((gh->flags & GWIN_FLG_VISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { + gh->flags |= GWIN_FLG_SYSVISIBLE; + return TRUE; } - } else { - if ((gh->flags & GWIN_FLG_VISIBLE)) { - gh->flags &= ~GWIN_FLG_VISIBLE; - _gwm_redraw(gh, 0); + return FALSE; + } + static bool_t clrSysVisFlag(GHandle gh) { + // If we are now not visible but our parent is visible + if (!(gh->flags & GWIN_FLG_VISIBLE) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + return TRUE; + } + return FALSE; + } + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= GWIN_FLG_VISIBLE; + _gwinRecurse(gh, setSysVisFlag); + _gwm_redraw(gh, 0); + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~GWIN_FLG_VISIBLE; + _gwinRecurse(gh, clrSysVisFlag); + _gwm_redraw(gh, 0); + } } } -} +#else + void gwinSetVisible(GHandle gh, bool_t visible) { + if (visible) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); + _gwm_redraw(gh, 0); + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE); + _gwm_redraw(gh, 0); + } + } + } +#endif bool_t gwinGetVisible(GHandle gh) { - #if GWIN_NEED_HIERARCHY - // return TRUE if all widgets (itself + parents) are visble, false otherwise - GHandle e = gh; - for (e = gh; e; e = e->parent) { - if (!(e->flags & GWIN_FLG_VISIBLE)) - return FALSE; - } - return TRUE; - #else - return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE; - #endif + return (gh->flags & GWIN_FLG_SYSVISIBLE) ? TRUE : FALSE; } -void gwinSetEnabled(GHandle gh, bool_t enabled) { - if (enabled) { - if (!(gh->flags & GWIN_FLG_ENABLED)) { - gh->flags |= GWIN_FLG_ENABLED; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); +#if GWIN_NEED_CONTAINERS + // These two sub-functions set/clear system enable recursively. + static bool_t setSysEnaFlag(GHandle gh) { + // If we are now enabled and our parent is enabled + if ((gh->flags & GWIN_FLG_ENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { + gh->flags |= GWIN_FLG_SYSENABLED; + return TRUE; } - } else { - if ((gh->flags & GWIN_FLG_ENABLED)) { - gh->flags &= ~GWIN_FLG_ENABLED; - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + return FALSE; + } + static bool_t clrSysEnaFlag(GHandle gh) { + // If we are now not enabled but our parent is enabled + if (!(gh->flags & GWIN_FLG_ENABLED) && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) { + gh->flags &= ~GWIN_FLG_SYSENABLED; + return TRUE; + } + return FALSE; + } + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= GWIN_FLG_ENABLED; + _gwinRecurse(gh, setSysEnaFlag); + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~GWIN_FLG_ENABLED; + _gwinRecurse(gh, clrSysEnaFlag); + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE); + } } } -} +#else + void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED); + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + } + } + } +#endif bool_t gwinGetEnabled(GHandle gh) { - #if GWIN_NEED_HIERARCHY - // return TRUE if all widgets (itself + parents) are enabled, false otherwise - GHandle e = gh; - for (e = gh; e; e = e->parent) { - if (!(e->flags & GWIN_FLG_ENABLED)) - return FALSE; - } - return TRUE; - #else - return (gh->flags & GWIN_FLG_ENABLED) ? TRUE : FALSE; - #endif + return (gh->flags & GWIN_FLG_SYSENABLED) ? TRUE : FALSE; } void gwinMove(GHandle gh, coord_t x, coord_t y) { - _gwm_redim(gh, x, y, gh->width, gh->height); + _gwm_move(gh, x, y); } void gwinResize(GHandle gh, coord_t width, coord_t height) { - _gwm_redim(gh, gh->x, gh->y, width, height); + _gwm_resize(gh, width, height); } void gwinRedraw(GHandle gh) { - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE | GWIN_WMFLG_NOBGCLEAR); - - #if GWIN_NEED_HIERARCHY - GHandle tmp; - for (tmp = gh->child; tmp; tmp = tmp->sibling) - gwinRedraw(tmp); - #endif + _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } #if GDISP_NEED_TEXT @@ -326,84 +390,13 @@ void gwinRedraw(GHandle gh) { } #endif -#if GWIN_NEED_HIERARCHY - void gwinAddChild(GHandle parent, GHandle child, bool_t last) { - child->parent = parent; - child->sibling = NULL; - child->child = NULL; - - if (!parent) - return; - - if (last && parent->child) { - GHandle s = parent->child; - while (s->sibling) - s = s->sibling; - s->sibling = child; - } else { - child->sibling = parent->child; - parent->child = child; - } - - // clear the area of the current child position as it will be moved - gwinClear(child); - - // window coordinates until now are relative, make them absolute now. - child->x += parent->x; - child->y += parent->y; - - // redraw the window - gwinRedraw(parent); - } - - void gwinRemoveChild(GHandle gh) { - if(!gh || !gh->parent) { - // without a parent, removing is impossible - // should log a runtime error here - return; - } - - if (gh->parent->child == gh) { - // we are the first child, update parent - gh->parent->child = gh->sibling; - } else { - // otherwise find our predecessor - GHandle tmp = gh->parent->child; - while (tmp && tmp->sibling != gh) - tmp = tmp->sibling; - - if(!tmp) { - // our parent's children list is corrupted - // should log a runtime error here - return; - } - - tmp->sibling = gh->sibling; - } - } - - void gwinRedrawChildren(GHandle gh) { - GHandle tmp; - for (tmp = gh->child; tmp; tmp = tmp->sibling) - gwinRedraw(tmp); - } - - GHandle gwinGetFirstChild(GHandle gh) { - return gh->child; - } - - GHandle gwinGetNextChild(GHandle gh) { - return gh->sibling; - } -#endif - void gwinClear(GHandle gh) { /* * Don't render anything when the window is not visible but * still call the AfterClear() routine as some widgets will * need this to clear internal buffers or similar */ - if (!((gh->flags & GWIN_FLG_VISIBLE))) { + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->AfterClear) gh->vmt->AfterClear(gh); } else { @@ -417,15 +410,14 @@ void gwinClear(GHandle gh) { gh->vmt->AfterClear(gh); } - #if GWIN_NEED_HIERARCHY - GHandle tmp; - for (tmp = gh->child; tmp; tmp = tmp->sibling) - gwinClear(tmp); + #if GWIN_NEED_CONTAINERS + for (gh = gwinGetFirstChild(gh); gh; gh = gwinGetSibling(gh)) + gwinRedraw(gh); #endif } void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -435,7 +427,7 @@ void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { } void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -445,7 +437,7 @@ void gwinDrawLine(GHandle gh, coord_t x0, coord_t y0, coord_t x1, coord_t y1) { } void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -455,7 +447,7 @@ void gwinDrawBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { } void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -465,7 +457,7 @@ void gwinFillArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy) { } void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t srcx, coord_t srcy, coord_t srccx, const pixel_t *buffer) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -476,7 +468,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_CIRCLE void gwinDrawCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -486,7 +478,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillCircle(GHandle gh, coord_t x, coord_t y, coord_t radius) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -498,7 +490,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_ELLIPSE void gwinDrawEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -508,7 +500,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillEllipse(GHandle gh, coord_t x, coord_t y, coord_t a, coord_t b) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -520,7 +512,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_ARC void gwinDrawArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -530,7 +522,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillArc(GHandle gh, coord_t x, coord_t y, coord_t radius, coord_t startangle, coord_t endangle) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -542,7 +534,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_PIXELREAD color_t gwinGetPixelColor(GHandle gh, coord_t x, coord_t y) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return defaultBgColor; #if GDISP_NEED_CLIP @@ -554,7 +546,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_TEXT void gwinDrawChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -564,7 +556,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillChar(GHandle gh, coord_t x, coord_t y, char c) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -574,7 +566,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinDrawString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -584,7 +576,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillString(GHandle gh, coord_t x, coord_t y, const char *str) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -594,7 +586,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinDrawStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -604,7 +596,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillStringBox(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, const char* str, justify_t justify) { - if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE) || !gh->font) return; #if GDISP_NEED_CLIP @@ -616,7 +608,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_CONVEX_POLYGON void gwinDrawPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -626,7 +618,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor } void gwinFillConvexPoly(GHandle gh, coord_t tx, coord_t ty, const point *pntarray, unsigned cnt) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return; #if GDISP_NEED_CLIP @@ -638,7 +630,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #if GDISP_NEED_IMAGE gdispImageError gwinDrawImage(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { - if (!((gh->flags & GWIN_FLG_VISIBLE))) + if (!(gh->flags & GWIN_FLG_SYSVISIBLE)) return GDISP_IMAGE_ERR_OK; #if GDISP_NEED_CLIP diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index 3140b03f..682dcb2d 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -28,7 +28,8 @@ static void WM_DeInit(void); static bool_t WM_Add(GHandle gh, const GWindowInit *pInit); static void WM_Delete(GHandle gh); static void WM_Redraw(GHandle gh, int flags); -static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); +static void WM_Size(GHandle gh, coord_t w, coord_t h); +static void WM_Move(GHandle gh, coord_t x, coord_t y); static void WM_Raise(GHandle gh); static void WM_MinMax(GHandle gh, GWindowMinMax minmax); @@ -38,7 +39,8 @@ static const gwmVMT GNullWindowManagerVMT = { WM_Add, WM_Delete, WM_Redraw, - WM_Redim, + WM_Size, + WM_Move, WM_Raise, WM_MinMax, }; @@ -47,7 +49,7 @@ static const GWindowManager GNullWindowManager = { &GNullWindowManagerVMT, }; -gfxQueueASync _GWINList; +static gfxQueueASync _GWINList; GWindowManager * _GWINwm; #if GFX_USE_GTIMER static GTimer RedrawTimer; @@ -114,11 +116,9 @@ void gwinRedrawDisplay(GDisplay *g, bool_t preserve) { (void) param; #endif - const gfxQueueASyncItem * qi; GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (!g || gh->display == g) _GWINwm->vmt->Redraw(gh, preserve ? (GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR|GWIN_WMFLG_NOZORDER) @@ -150,8 +150,11 @@ static bool_t WM_Add(GHandle gh, const GWindowInit *pInit) { // Put it on the end of the queue gfxQueueASyncPut(&_GWINList, &gh->wmq); - // Make sure the size is valid - WM_Redim(gh, pInit->x, pInit->y, pInit->width, pInit->height); + // Make sure the size/position is valid - prefer position over size. + gh->width = MIN_WIN_WIDTH; gh->height = MIN_WIN_HEIGHT; + gh->x = gh->y = 0; + WM_Move(gh, pInit->x, pInit->y); + WM_Size(gh, pInit->width, pInit->height); return TRUE; } @@ -161,15 +164,20 @@ static void WM_Delete(GHandle gh) { } static void WM_Redraw(GHandle gh, int flags) { - if ((gh->flags & GWIN_FLG_VISIBLE)) { + #if GWIN_NEED_CONTAINERS + redo_redraw: + #endif + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { if (gh->vmt->Redraw) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gh->vmt->Redraw(gh); } else if (!(flags & GWIN_WMFLG_PRESERVE)) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); if (gh->vmt->AfterClear) @@ -184,42 +192,77 @@ static void WM_Redraw(GHandle gh, int flags) { } else if (!(flags & GWIN_WMFLG_NOBGCLEAR)) { #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + if (!(flags & GWIN_WMFLG_KEEPCLIP)) + gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); + #endif + #if GWIN_NEED_CONTAINERS + if (gh->parent) { + // Get the parent to redraw the area + gh = gh->parent; + flags |= GWIN_WMFLG_KEEPCLIP; + goto redo_redraw; + } #endif gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); } } -static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h) { - // This is the simplest way of doing it - just clip the the screen - // If it won't fit on the screen move it around until it does. - if (x < 0) { w += x; x = 0; } - if (y < 0) { h += y; y = 0; } - if (x > gdispGGetWidth(gh->display)-MIN_WIN_WIDTH) x = gdispGGetWidth(gh->display)-MIN_WIN_WIDTH; - if (y > gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT) y = gdispGGetHeight(gh->display)-MIN_WIN_HEIGHT; - if (w < MIN_WIN_WIDTH) { w = MIN_WIN_WIDTH; } - if (h < MIN_WIN_HEIGHT) { h = MIN_WIN_HEIGHT; } - if (x+w > gdispGGetWidth(gh->display)) w = gdispGGetWidth(gh->display) - x; - if (y+h > gdispGGetHeight(gh->display)) h = gdispGGetHeight(gh->display) - y; +static void WM_Size(GHandle gh, coord_t w, coord_t h) { + #if GWIN_NEED_CONTAINERS + // For a child window - convert to absolute size + if (gh->parent) + ((const gcontainerVMT *)gh->parent->vmt)->Size2Screen(gh, &w, &h); + #endif + + // Clip to the screen and give it a minimum size + if (w < MIN_WIN_WIDTH) w = MIN_WIN_WIDTH; + if (h < MIN_WIN_HEIGHT) h = MIN_WIN_HEIGHT; + if (gh->x+w > gdispGGetWidth(gh->display)) w = gdispGGetWidth(gh->display) - gh->x; + if (gh->y+h > gdispGGetHeight(gh->display)) h = gdispGGetHeight(gh->display) - gh->y; // If there has been no resize just exit - if (gh->x == x && gh->y == y && gh->width == w && gh->height == h) + if (gh->width == w && gh->height == h) return; - // Clear the old area - if ((gh->flags & GWIN_FLG_VISIBLE)) { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif - gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + // Clear the old area and then redraw + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + gh->width = w; gh->height = h; + gh->flags |= GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + } else { + gh->width = w; gh->height = h; } +} - // Set the new size - gh->x = x; gh->y = y; - gh->width = w; gh->height = h; +static void WM_Move(GHandle gh, coord_t x, coord_t y) { + #if GWIN_NEED_CONTAINERS + // For a child window - convert to absolute position + if (gh->parent) + ((const gcontainerVMT *)gh->parent->vmt)->Pos2Screen(gh, &x, &y); + #endif - // Redraw the window (if possible) - WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + // Clip to the screen + if (x < 0) x = 0; + if (y < 0) y = 0; + if (x > gdispGGetWidth(gh->display)-gh->width) x = gdispGGetWidth(gh->display)-gh->width; + if (y > gdispGGetHeight(gh->display)-gh->height) y = gdispGGetHeight(gh->display)-gh->height; + + // If there has been no move just exit + if (gh->x == x && gh->y == y) + return; + + // Clear the old area and then redraw + if ((gh->flags & GWIN_FLG_SYSVISIBLE)) { + gh->flags &= ~GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + gh->x = x; gh->y = y; + gh->flags |= GWIN_FLG_SYSVISIBLE; + WM_Redraw(gh, 0); + } else { + gh->x = x; gh->y = y; + } } static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { @@ -230,6 +273,7 @@ static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { static void WM_Raise(GHandle gh) { // Take it off the list and then put it back on top // The order of the list then reflects the z-order. + gfxQueueASyncRemove(&_GWINList, &gh->wmq); gfxQueueASyncPut(&_GWINList, &gh->wmq); @@ -237,5 +281,9 @@ static void WM_Raise(GHandle gh) { WM_Redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); } +GHandle gwinGetNextWindow(GHandle gh) { + return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList); +} + #endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */ /** @} */ diff --git a/src/gwin/label.c b/src/gwin/label.c index 2aa0c860..ffb9fa3d 100644 --- a/src/gwin/label.c +++ b/src/gwin/label.c @@ -147,7 +147,7 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.width; h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGGetWidth(gw->g.display) - gw->g.x) : gw->g.height; - c = (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + c = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; if (gw->g.width != w || gw->g.height != h) { gwinResize(&gw->g, w, h); @@ -167,7 +167,7 @@ static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { // render the border (if any) if (gw->g.flags & GLABEL_FLG_BORDER) - gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, w, h, (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, w, h, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); } #endif // GFX_USE_GWIN && GFX_NEED_LABEL diff --git a/src/gwin/list.c b/src/gwin/list.c index 788e8828..2ff18777 100644 --- a/src/gwin/list.c +++ b/src/gwin/list.c @@ -107,7 +107,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); } } - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); sendListEvent(gw, item); } @@ -136,14 +136,14 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= iheight; if (gw2obj->top < 0) gw2obj->top = 0; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else if (y >= gw->g.height - 2*ARROW) { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { gw2obj->top += iheight; if (gw2obj->top > gw2obj->cnt * iheight - pgsz) gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else if (y < gw->g.height/2) { if (gw2obj->top > 0) { @@ -151,7 +151,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top -= pgsz; else gw2obj->top = 0; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } else { if (gw2obj->top < gw2obj->cnt * iheight - pgsz) { @@ -159,7 +159,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top += pgsz; else gw2obj->top = gw2obj->cnt * iheight - pgsz; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } return; @@ -197,7 +197,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); gw2obj->top = 0; gw2obj->last_mouse_y = y; if (oldtop != gw2obj->top) - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } } #endif @@ -218,7 +218,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } break; } @@ -235,7 +235,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param); if (qix) { qi2li->flags &=~ GLIST_FLG_SELECTED; qix2li->flags |= GLIST_FLG_SELECTED; - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); } break; } @@ -388,7 +388,7 @@ int gwinListAddItem(GHandle gh, const char* item_name, bool_t useAlloc) { // increment the total amount of entries in the list widget gh2obj->cnt++; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); // return the position in the list (-1 because we start with index 0) return gh2obj->cnt-1; @@ -486,7 +486,7 @@ void gwinListDeleteAll(GHandle gh) { gh->flags &= ~GLIST_FLG_HASIMAGES; gh2obj->cnt = 0; gh2obj->top = 0; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); } void gwinListItemDelete(GHandle gh, int item) { @@ -507,7 +507,7 @@ void gwinListItemDelete(GHandle gh, int item) { gfxFree((void *)qi); if (gh2obj->top >= item && gh2obj->top) gh2obj->top--; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); break; } } @@ -620,7 +620,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { if (!(gw->g.flags & GLIST_FLG_ENABLERENDER)) return; - ps = (gw->g.flags & GWIN_FLG_ENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; + ps = (gw->g.flags & GWIN_FLG_SYSENABLED) ? &gw->pstyle->enabled : &gw->pstyle->disabled; iheight = gdispGetFontMetric(gw->g.font, fontHeight) + VERTICAL_PADDING; x = 1; @@ -677,7 +677,7 @@ static void gwinListDefaultDraw(GWidgetObject* gw, void* param) { if (qi2li->pimg && gdispImageIsOpen(qi2li->pimg)) { // Calculate which image sy = (qi2li->flags & GLIST_FLG_SELECTED) ? 0 : (iheight-VERTICAL_PADDING); - if (!(gw->g.flags & GWIN_FLG_ENABLED)) + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) sy += 2*(iheight-VERTICAL_PADDING); while (sy > qi2li->pimg->height) sy -= iheight-VERTICAL_PADDING; diff --git a/src/gwin/progressbar.c b/src/gwin/progressbar.c index 524a5346..ca267f0c 100644 --- a/src/gwin/progressbar.c +++ b/src/gwin/progressbar.c @@ -128,7 +128,7 @@ void gwinProgressbarSetPosition(GHandle gh, int pos) { } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -159,7 +159,7 @@ void gwinProgressbarIncrement(GHandle gh) { gsw->pos = gsw->max; ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -178,7 +178,7 @@ void gwinProgressbarDecrement(GHandle gh) { gsw->pos -= gsw->res; ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -239,7 +239,7 @@ void gwinProgressbarDraw_Std(GWidgetObject *gw, void *param) { return; // get the colors right - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; @@ -277,7 +277,7 @@ void gwinProgressbarDraw_Image(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&progressbarVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; diff --git a/src/gwin/radio.c b/src/gwin/radio.c index 0ae5546a..da6aa5ea 100644 --- a/src/gwin/radio.c +++ b/src/gwin/radio.c @@ -133,10 +133,10 @@ void gwinRadioPress(GHandle gh) { if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) { gx->flags &= ~GRADIO_FLG_PRESSED; - _gwidgetRedraw(gx); + _gwidgetUpdate(gx); } gh->flags |= GRADIO_FLG_PRESSED; - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); SendRadioEvent((GWidgetObject *)gh); } @@ -148,11 +148,9 @@ bool_t gwinRadioIsPressed(GHandle gh) { } GHandle gwinRadioGetActive(uint16_t group) { - const gfxQueueASyncItem * qi; - GHandle gh; + GHandle gh; - for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { - gh = QItem2GWindow(qi); + for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) { if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED)) return gh; } @@ -164,7 +162,7 @@ GHandle gwinRadioGetActive(uint16_t group) { *----------------------------------------------------------*/ static const GColorSet *getDrawColors(GWidgetObject *gw) { - if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if (!(gw->g.flags & GWIN_FLG_SYSENABLED)) return &gw->pstyle->disabled; if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &gw->pstyle->pressed; return &gw->pstyle->enabled; } diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 4c91ede6..3266e20a 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -74,7 +74,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) { // No - restore the slider ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); return; } #endif @@ -97,7 +97,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); // Generate the event SendSliderEvent(gw); @@ -127,7 +127,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { } // Update the display - _gwidgetRedraw(&gw->g); + _gwidgetUpdate(&gw->g); #undef gsw } #endif @@ -169,7 +169,7 @@ static void ResetDisplayPos(GSliderObject *gsw) { gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); ResetDisplayPos(gsw); - _gwidgetRedraw((GHandle)gw); + _gwidgetUpdate((GHandle)gw); // Generate the event SendSliderEvent(gw); @@ -272,7 +272,7 @@ void gwinSliderSetPosition(GHandle gh, int pos) { else gsw->pos = pos; } ResetDisplayPos(gsw); - _gwidgetRedraw(gh); + _gwidgetUpdate(gh); #undef gsw } @@ -289,7 +289,7 @@ void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; @@ -334,7 +334,7 @@ void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - if ((gw->g.flags & GWIN_FLG_ENABLED)) + if ((gw->g.flags & GWIN_FLG_SYSENABLED)) pcol = &gw->pstyle->pressed; else pcol = &gw->pstyle->disabled; diff --git a/src/gwin/sys_defs.h b/src/gwin/sys_defs.h index 431de67c..91831cba 100644 --- a/src/gwin/sys_defs.h +++ b/src/gwin/sys_defs.h @@ -42,17 +42,15 @@ typedef struct GWindowObject { #endif const struct gwinVMT *vmt; // @< The VMT for this GWIN GDisplay * display; // @< The display this window is on. - coord_t x, y; // @< Position relative to parent + coord_t x, y; // @< Screen relative position coord_t width, height; // @< Dimensions of this window color_t color, bgcolor; // @< The current drawing colors uint32_t flags; // @< Window flags (the meaning is private to the GWIN class) #if GDISP_NEED_TEXT font_t font; // @< The current font #endif - #if GWIN_NEED_HIERARCHY - GHandle parent; // @< The parent widget - GHandle sibling; // @< The widget to its left (add right later as well) - GHandle child; // @< The child widget + #if GWIN_NEED_CONTAINERS + GHandle parent; // @< The parent window #endif } GWindowObject, * GHandle; /* @} */ @@ -70,9 +68,12 @@ typedef struct GWindowObject { * @{ */ typedef struct GWindowInit { - coord_t x, y; // @< The initial screen position + coord_t x, y; // @< The initial position relative to its parent coord_t width, height; // @< The initial dimension bool_t show; // @< Should the window be visible initially + #if GWIN_NEED_CONTAINERS + GHandle parent; // @< The parent - must be a container or NULL + #endif } GWindowInit; /* @} */ @@ -332,6 +333,9 @@ extern "C" { * as not visible, nothing is done to remove the window from the screen. * When there is a window manager, it is up to the window manager to * handle what happens. + * @note Even when you mark a window as visible, it may still not be displayed + * if it's parent is invisible. When the parent becomes visible this child + * will automatically be shown because it is already marked as visible. * * @api */ @@ -341,6 +345,9 @@ extern "C" { * @brief Gets the visibility of a window * @return TRUE if visible * + * @note It is possible for a child to be marked as visible by @p gwinSetVisible() + * but for this call to return FALSE if one of its parents are not visible. + * * @param[in] gh The window * * @api @@ -353,8 +360,10 @@ extern "C" { * @param[in] gh The window handle * @param[in] enabled Enable or disable the window * - * @note The window is automatically redrawn if it - * supports self-redrawing. + * @note The window is automatically redrawn if it supports self-redrawing. + * @note Even when you mark a window as enabled, it may still remain disabled + * if it's parent is disabled. When the parent becomes enabled this child + * will automatically be enabled because it is already marked as enabled. * * @api */ @@ -382,6 +391,9 @@ extern "C" { * @brief Gets the enabled state of a window * @return TRUE if enabled * + * @note It is possible for a child to be marked as enabled by @p gwinSetEnabled() + * but for this call to return FALSE if one of its parents are not enabled. + * * @param[in] gh The window * * @api @@ -437,65 +449,6 @@ extern "C" { */ void gwinRedraw(GHandle gh); - #if GWIN_NEED_HIERARCHY - /** - * @brief Add a child widget to a parent one - * - * @param[in] parent The parent window (does not need to be parent yet) - * @param[in] child The child window - * @param[in] last Should the child window be added to the front or the back of the list? - * - * @api - */ - void gwinAddChild(GHandle parent, GHandle child, bool_t last); - - /** - * @brief Remove a child from a parent - * - * @note Other children of the same parent stay - * @note Children of the child are lost, they have to be reassigned manually if necessary. - * - * @param[in] child The child window - * - * @api - */ - void gwinRemoveChild(GHandle child); - - /** - * @brief Redraw only the children of a parent but not the parent itself - * - * @details This routine does exactly the same as @p gwinRedraw() but does not - * issue a redraw of the passed widget but only of it's children. - * - * @param[in] gh The widget - * - * @api - */ - void gwinRedrawChildren(GHandle gh); - - /** - * @brief Get first child of a widget - * - * @return The first child or NULL if the widget has no children - * - * @param[in] gh The parent widget - * - * @api - */ - GHandle gwinGetFirstChild(GHandle gh); - - /** - * @brief Get the next child of a widget - * - * @return The next child or NULL if no more childs - * - * @param[in] gh The parent widget - * - * @api - */ - GHandle gwinGetNextChild(GHandle gh); - #endif - #if GWIN_NEED_WINDOWMANAGER || defined (__DOXYGEN__) /** * @brief Redraw a window @@ -558,6 +511,24 @@ extern "C" { * @api */ void gwinRaise(GHandle gh); + + /** + * @brief Get the next window in the z-order + * @return The next window or NULL if no more windows + * + * @param[in] gh The previous window or NULL to get the first window + * + * @note This returns the next window in the system from top to bottom. + * @note Where there are parent child relationships, this ignores them + * and will list all windows in the system. There is no defined + * order between children of siblings and they can in fact be mixed + * in order. The only relationship honored is that parents will be + * listed before their children. + * + * @api + */ + GHandle gwinGetNextWindow(GHandle gh); + #endif #if GDISP_NEED_TEXT || defined(__DOXYGEN__) @@ -947,7 +918,12 @@ extern "C" { #include "src/gwin/gwidget.h" #endif - /* Include extra window types */ + /* Include containers */ + #if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__) + #include "src/gwin/gcontainer.h" + #endif + + /* Include vanilla window objects */ #if GWIN_NEED_CONSOLE || defined(__DOXYGEN__) #include "src/gwin/console.h" #endif diff --git a/src/gwin/sys_make.mk b/src/gwin/sys_make.mk index dbca7fd8..95a2ba84 100644 --- a/src/gwin/sys_make.mk +++ b/src/gwin/sys_make.mk @@ -11,5 +11,6 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ $(GFXLIB)/src/gwin/radio.c \ $(GFXLIB)/src/gwin/list.c \ $(GFXLIB)/src/gwin/progressbar.c \ + $(GFXLIB)/src/gwin/gcontainer.c \ $(GFXLIB)/src/gwin/frame.c \ diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h index 69507b94..0f3f3f4b 100644 --- a/src/gwin/sys_options.h +++ b/src/gwin/sys_options.h @@ -33,8 +33,8 @@ * @brief Should the widget hierarchy be included. This provides parent-child features. * @details Defaults to FALSE */ - #ifndef GWIN_NEED_HIERARCHY - #define GWIN_NEED_HIERARCHY FALSE + #ifndef GWIN_NEED_CONTAINERS + #define GWIN_NEED_CONTAINERS FALSE #endif /** * @brief Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc) diff --git a/src/gwin/sys_rules.h b/src/gwin/sys_rules.h index fda55fe7..eeba2286 100644 --- a/src/gwin/sys_rules.h +++ b/src/gwin/sys_rules.h @@ -28,22 +28,13 @@ #endif // Objects require their super-class - #if GWIN_NEED_HIERARCHY - #if !GQUEUE_NEED_ASYNC - #if GFX_DISPLAY_RULE_WARNINGS - #warning "GWIN: GQUEUE_NEED_ASYNC is required when GWIN_NEED_HIERARCHY is enabled. It has been turned on for you." - #endif - #undef GQUEUE_NEED_ASYNC - #define GQUEUE_NEED_ASYNC TRUE - #endif - #endif #if GWIN_NEED_FRAME - #if !GWIN_NEED_HIERARCHY + #if !GWIN_NEED_CONTAINERS #if GFX_DISPLAY_RULE_WARNINGS - #warning "GWIN: GWIN_NEED_HIERARCHY is required when GIWN_NEED_FRAME is enabled. It has been turned on for you." + #warning "GWIN: GWIN_NEED_CONTAINERS is required when GIWN_NEED_FRAME is enabled. It has been turned on for you." #endif - #undef GWIN_NEED_HIERARCHY - #define GWIN_NEED_HIERARCHY TRUE + #undef GWIN_NEED_CONTAINERS + #define GWIN_NEED_CONTAINERS TRUE #endif #endif #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO || GWIN_NEED_LIST || \ @@ -58,6 +49,15 @@ #endif // Rules for the super-classes + #if GWIN_NEED_CONTAINERS + #if !GWIN_NEED_WIDGET + #if GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GWIN_NEED_WIDGET is required when GWIN_NEED_CONTAINERS is enabled. It has been turned on for you." + #endif + #undef GWIN_NEED_WIDGET + #define GWIN_NEED_WIDGET TRUE + #endif + #endif #if GWIN_NEED_WIDGET #if !GDISP_NEED_TEXT #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_WIDGET is TRUE." @@ -116,12 +116,7 @@ #error "GWIN: GDISP_NEED_TEXT is required if GWIN_NEED_CONSOLE is TRUE." #endif #endif - #if GWIN_NEED_PROGRESSBAR - #if GWIN_PROGRESSBAR_AUTO - #if !GFX_USE_GTIMER - #error "GWIN: GFX_USE_GTIMER is required if GWIN_PROGRESSBAR_AUTO is TRUE." - #endif - #endif + #if GWIN_NEED_GRAPH #endif #endif