diff options
-rw-r--r-- | gfxconf.example.h | 3 | ||||
-rw-r--r-- | src/gwin/frame.c | 247 | ||||
-rw-r--r-- | src/gwin/frame.h | 68 | ||||
-rw-r--r-- | src/gwin/gwidget.h | 6 | ||||
-rw-r--r-- | src/gwin/gwin.c | 150 | ||||
-rw-r--r-- | src/gwin/sys_defs.h | 69 | ||||
-rw-r--r-- | src/gwin/sys_make.mk | 1 | ||||
-rw-r--r-- | src/gwin/sys_options.h | 14 | ||||
-rw-r--r-- | src/gwin/sys_rules.h | 18 |
9 files changed, 563 insertions, 13 deletions
diff --git a/gfxconf.example.h b/gfxconf.example.h index 824c2a23..8b179c61 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -133,8 +133,8 @@ #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_HIERARCHY FALSE #define GWIN_NEED_LABEL FALSE #define GWIN_NEED_BUTTON FALSE #define GWIN_BUTTON_LAZY_RELEASE FALSE @@ -146,6 +146,7 @@ #define GWIN_NEED_LIST FALSE #define GWIN_NEED_LIST_IMAGES FALSE #define GWIN_NEED_PROGRESSBAR FALSE + #define GWIN_NEED_FRAME FALSE /////////////////////////////////////////////////////////////////////////// diff --git a/src/gwin/frame.c b/src/gwin/frame.c new file mode 100644 index 00000000..fbef54dc --- /dev/null +++ b/src/gwin/frame.c @@ -0,0 +1,247 @@ +/* + * 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/frame.c + * @brief GWIN sub-system frame code. + * + * @defgroup Frame Frame + * @ingroup GWIN + * + * @{ + */ + +#include "gfx.h" + +#if (GFX_USE_GWIN && GWIN_NEED_FRAME) || defined(__DOXYGEN__) + +/* Some values for the default render */ +#define BORDER_X 5 +#define BORDER_Y 30 +#define BUTTON_X 20 +#define BUTTON_Y 20 + +/* Some useful macros for data type conversions */ +#define gh2obj ((GFrameObject *)gh) + +/* Forware declarations */ +void gwinFrameDraw_Std(GWidgetObject *gw, void *param); +static void _callbackBtn(void *param, GEvent *pe); + +static void _frameDestroy(GHandle gh) { + /* Deregister the button callback */ + geventRegisterCallback(&gh2obj->gl, NULL, NULL); + geventDetachSource(&gh2obj->gl, NULL); + + /* call the gwidget standard destroy routine */ + _gwidgetDestroy(gh); +} + +#if GINPUT_NEED_MOUSE + static void _mouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + + } + + static void _mouseUp(GWidgetObject *gw, coord_t x, coord_t y) { + + } + + static void _mouseMove(GWidgetObject *gw, coord_t x, coord_t y) { + + } +#endif + +static const gwidgetVMT frameVMT = { + { + "Frame", // The classname + sizeof(GFrameObject), // The object size + _frameDestroy, // The destroy routie + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinFrameDraw_Std, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + _mouseDown, // Process mouse down event + _mouseUp, // Process mouse up events + _mouseMove, // Process mouse move events + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, // 1 toggle role + 0, // Assign Toggles + 0, // Get Toggles + 0, // Process toggle off events + 0, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // 1 dial roles + 0, // Assign Dials + 0, // Get Dials + 0, // Process dial move events + }, + #endif +}; + +GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint16_t flags) { + uint16_t tmp; + + if (!(fo = (GFrameObject *)_gwidgetCreate(g, &fo->w, pInit, &frameVMT))) + return 0; + + fo->btnClose = NULL; + fo->btnMin = NULL; + fo->btnMax = NULL; + + /* Buttons require a border */ + tmp = flags; + if ((tmp & GWIN_FRAME_CLOSE_BTN || tmp & GWIN_FRAME_MINMAX_BTN) && !(tmp & GWIN_FRAME_BORDER)) { + tmp |= GWIN_FRAME_BORDER; + } + + /* apply flags */ + fo->w.g.flags |= tmp; + + /* create and initialize the listener if any button is present. */ + if ((fo->w.g.flags & GWIN_FRAME_CLOSE_BTN) || (fo->w.g.flags & GWIN_FRAME_MINMAX_BTN)) { + geventListenerInit(&fo->gl); + gwinAttachListener(&fo->gl); + geventRegisterCallback(&fo->gl, _callbackBtn, (GHandle)fo); + } + + /* create close button if necessary */ + if (fo->w.g.flags & GWIN_FRAME_CLOSE_BTN) { + GWidgetInit wi; + + wi.customDraw = 0; + wi.customParam = 0; + wi.customStyle = 0; + wi.g.show = TRUE; + + wi.g.x = fo->w.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "X"; + fo->btnClose = gwinButtonCreate(NULL, &wi); + gwinAddChild((GHandle)fo, fo->btnClose, FALSE); + } + + /* create minimize and maximize buttons if necessary */ + if (fo->w.g.flags & GWIN_FRAME_MINMAX_BTN) { + GWidgetInit wi; + + wi.customDraw = 0; + wi.customParam = 0; + wi.customStyle = 0; + wi.g.show = TRUE; + + wi.g.x = (fo->w.g.flags & GWIN_FRAME_CLOSE_BTN) ? fo->w.g.width - 2*BORDER_X - 2*BUTTON_X : fo->w.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "O"; + fo->btnMin = gwinButtonCreate(NULL, &wi); + gwinAddChild((GHandle)fo, fo->btnMin, FALSE); + + wi.g.x = (fo->w.g.flags & GWIN_FRAME_CLOSE_BTN) ? fo->w.g.width - 3*BORDER_X - 3*BUTTON_X : fo->w.g.width - BORDER_X - BUTTON_X; + wi.g.y = (BORDER_Y - BUTTON_Y) / 2; + wi.g.width = BUTTON_X; + wi.g.height = BUTTON_Y; + wi.text = "_"; + fo->btnMax = gwinButtonCreate(NULL, &wi); + gwinAddChild((GHandle)fo, fo->btnMax, FALSE); + } + + gwinSetVisible(&fo->w.g, pInit->g.show); + + return (GHandle)fo; +} + +/* Process a button event */ +static void _callbackBtn(void *param, GEvent *pe) { + switch (pe->type) { + case GEVENT_GWIN_BUTTON: + if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnClose) + gwinDestroy((GHandle)param); + + else if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnMin) + ;/* ToDo */ + + else if (((GEventGWinButton *)pe)->button == ((GFrameObject*)(GHandle)param)->btnMax) + ;/* ToDo */ + + break; + + default: + break; + } +} + +/////////////////////////////////////////////////////////////////////////////////////////////////// +// Default render routines // +/////////////////////////////////////////////////////////////////////////////////////////////////// + +static const GColorSet* _getDrawColors(GWidgetObject *gw) { + if (!(gw->g.flags & GWIN_FLG_ENABLED)) + return &gw->pstyle->disabled; + //if ((gw->g.flags & GBUTTON_FLG_PRESSED)) + // return &gw->pstyle->pressed; + + return &gw->pstyle->enabled; +} + +void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { + GColorSet *pcol; + color_t border; + color_t background; + (void)param; + + if (gw->g.vmt != (gwinVMT *)&frameVMT) + return; + + pcol = _getDrawColors(gw); + + // do some magic to make the background lighter than the widgets. Fix this somewhen. + 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); + gdispGFillArea(gw->g.display, gw->g.x + BORDER_X, gw->g.y + BORDER_Y, gw->g.width - 2*BORDER_X, gw->g.width - BORDER_Y - BORDER_X, background); + } else { + // This ensure that the actual frame content (it's children) render at the same spot, no mather whether the frame has a border or not + gdispGFillArea(gw->g.display, gw->g.x + BORDER_X, gw->g.y + BORDER_Y, gw->g.width, gw->g.height, background); + } + + // Render frame title - if any + if (gw->text != NULL) { + coord_t text_y; + + text_y = ((BORDER_Y - gdispGetFontMetric(gw->g.font, fontHeight))/2); + + gdispGDrawString(gw->g.display, gw->g.x + BORDER_X, gw->g.y + text_y, gw->text, gw->g.font, pcol->text); + } + + #if GDISP_NEED_CLIP + gdispGUnsetClip(gw->g.display); + #endif + + gwinRedrawChildren((GHandle)gw); +} + +#endif /* (GFX_USE_GWIN && GWIN_NEED_FRAME) || defined(__DOXYGEN__) */ +/** @} */ + diff --git a/src/gwin/frame.h b/src/gwin/frame.h new file mode 100644 index 00000000..9d1d63fb --- /dev/null +++ b/src/gwin/frame.h @@ -0,0 +1,68 @@ +/* + * 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/frame.h + * @brief GWIN Graphic window subsystem header file. + * + * @defgroup Frame Frame + * @ingroup GWIN + * + * @details A frame is a rectangular window that can have optional border as well as buttons to + * close, maximize and minimize it. The main purpose of this widget is to contain children. + * + * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h + * @pre GWIN_NEED_FRAME must be set to TRUE in your gfxconf.h + * @{ + */ + +#ifndef _GWIN_FRAME_H +#define _GWIN_FRAME_H + +#include "src/gwin/class_gwin.h" + +// Flags for gwinFrameCreate() +#define GWIN_FRAME_BORDER (GWIN_FIRST_CONTROL_FLAG << 0) +#define GWIN_FRAME_CLOSE_BTN (GWIN_FIRST_CONTROL_FLAG << 1) +#define GWIN_FRAME_MINMAX_BTN (GWIN_FIRST_CONTROL_FLAG << 2) + +typedef struct GFrameObject { + GWidgetObject w; + + GListener gl; // internal listener for the buttons + // These could probably be removed... I have to think harder later + GHandle btnClose; + GHandle btnMin; + GHandle btnMax; +} GFrameObject; + +/** + * @brief Create a frame widget + * + * @details This widget provides a window like we know it from desktop systems. You usually use this together with + * gwinAddChild(). + * + * @param[in] g The GDisplay to display this window on + * @param[in] fo The GFrameObject structure to initialize. If this is NULL the structure is dynamically allocated. + * @param[in] pInit The initialization parameters + * @param[in] flags Some flags, see notes. + * + * @note Possible flags are: GWIN_FRAME_BORDER, GWIN_FRAME_CLOSE_BTN, GWIN_FRAME_MINMAX_BTN. + * Whether the close or the minimize maximize buttons are used, the boarder is automatically invoked. + * @note These frame buttons are processed internally. The close button will invoke a gwinDestroy() which will + * destroy the window itself and EVERY child it contains (also children of children). + * + * @return NULL if there is no resulting widget. A valid GHandle otherwise. + * + * @api + */ +GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint16_t flags); +#define gwinFrameCreate(fo, pInit, flags) gwinGFrameCreate(GDISP, fo, pInit, flags); + +#endif /* _GWIN_FRAME_H */ +/** @} */ + diff --git a/src/gwin/gwidget.h b/src/gwin/gwidget.h index 96832fe3..6568859d 100644 --- a/src/gwin/gwidget.h +++ b/src/gwin/gwidget.h @@ -27,7 +27,7 @@ * @{ */ -// Forward definition +/* Forward definition */ struct GWidgetObject; /** @@ -304,5 +304,9 @@ 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 54f42077..b9a488d3 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -142,6 +142,12 @@ GHandle _gwindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pInit _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); #endif + #if GWIN_NEED_HIERARCHY + pgw->parent = NULL; + pgw->sibling = NULL; + pgw->child = NULL; + #endif + return (GHandle)pgw; } @@ -189,6 +195,27 @@ GHandle gwinGWindowCreate(GDisplay *g, GWindowObject *pgw, const GWindowInit *pI } void gwinDestroy(GHandle gh) { + if (!gh) { + // should log a runtime error here + 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); @@ -228,7 +255,17 @@ void gwinSetVisible(GHandle gh, bool_t visible) { } bool_t gwinGetVisible(GHandle gh) { - return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE; + #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 } void gwinSetEnabled(GHandle gh, bool_t enabled) { @@ -246,7 +283,17 @@ void gwinSetEnabled(GHandle gh, bool_t enabled) { } bool_t gwinGetEnabled(GHandle gh) { - return (gh->flags & GWIN_FLG_ENABLED) ? TRUE : FALSE; + #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 } void gwinMove(GHandle gh, coord_t x, coord_t y) { @@ -258,7 +305,13 @@ void gwinResize(GHandle gh, coord_t width, coord_t height) { } void gwinRedraw(GHandle gh) { - _gwm_redraw(gh, GWIN_WMFLG_PRESERVE|GWIN_WMFLG_NOBGCLEAR); + _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 } #if GDISP_NEED_TEXT @@ -267,10 +320,81 @@ 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 + * still call tthe AfterClear() routine as some widgets will * need this to clear internal buffers or similar */ if (!((gh->flags & GWIN_FLG_VISIBLE))) { @@ -278,14 +402,20 @@ void gwinClear(GHandle gh) { gh->vmt->AfterClear(gh); } else { - #if GDISP_NEED_CLIP - gdispGSetClip(gh->display, gh->x, gh->y, gh->width, gh->height); - #endif + #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, gh->bgcolor); - if (gh->vmt->AfterClear) - gh->vmt->AfterClear(gh); + gdispGFillArea(gh->display, gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); } + + #if GWIN_NEED_HIERARCHY + GHandle tmp; + for (tmp = gh->child; tmp; tmp = tmp->sibling) + gwinClear(tmp); + #endif } void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { diff --git a/src/gwin/sys_defs.h b/src/gwin/sys_defs.h index ac2c98c7..6302f28f 100644 --- a/src/gwin/sys_defs.h +++ b/src/gwin/sys_defs.h @@ -27,6 +27,9 @@ #if GFX_USE_GWIN || defined(__DOXYGEN__) +/* Forward declaration */ +typedef struct GWindowObject *GHandle; + /** * @brief A window object structure * @note Do not access the members directly. Treat it as a black-box and use the method functions. @@ -39,13 +42,18 @@ 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; // @< Screen relative position + coord_t x, y; // @< Position relative to parent 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 + #endif } GWindowObject, * GHandle; /* @} */ @@ -395,6 +403,65 @@ 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 diff --git a/src/gwin/sys_make.mk b/src/gwin/sys_make.mk index 4c670ea2..dbca7fd8 100644 --- a/src/gwin/sys_make.mk +++ b/src/gwin/sys_make.mk @@ -11,4 +11,5 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ $(GFXLIB)/src/gwin/radio.c \ $(GFXLIB)/src/gwin/list.c \ $(GFXLIB)/src/gwin/progressbar.c \ + $(GFXLIB)/src/gwin/frame.c \ diff --git a/src/gwin/sys_options.h b/src/gwin/sys_options.h index 656e0e3f..5fe2d93e 100644 --- a/src/gwin/sys_options.h +++ b/src/gwin/sys_options.h @@ -30,6 +30,13 @@ #define GWIN_NEED_WIDGET FALSE #endif /** + * @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 + #endif + /** * @brief Should widget functions be included. Needed for any widget (eg Buttons, Sliders etc) * @details Defaults to FALSE */ @@ -37,6 +44,13 @@ #define GWIN_NEED_WIDGET FALSE #endif /** + * @brief Should the frame widget be included. + * @details Defaults to FALSE + */ + #ifndef GWIN_NEED_FRAME + #define GWIN_NEED_FRAME FALSE + #endif + /** * @brief Should console functions be included. * @details Defaults to FALSE */ diff --git a/src/gwin/sys_rules.h b/src/gwin/sys_rules.h index 77f029f0..3178def8 100644 --- a/src/gwin/sys_rules.h +++ b/src/gwin/sys_rules.h @@ -37,6 +37,24 @@ #endif #endif #endif + #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 GFX_DISPLAY_RULE_WARNINGS + #warning "GWIN: GWIN_NEED_HIERARCHY 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 + #endif + #endif #if GWIN_NEED_BUTTON || GWIN_NEED_SLIDER || GWIN_NEED_CHECKBOX || GWIN_NEED_LABEL || GWIN_NEED_RADIO || GWIN_NEED_LIST || \ GWIN_NEED_IMAGE || GWIN_NEED_CHECKBOX || GWIN_NEED_PROGRESSBAR #if !GWIN_NEED_WIDGET |