diff --git a/src/gwin/class_gwin.h b/src/gwin/class_gwin.h index b38b6bb8..2c9b6a68 100644 --- a/src/gwin/class_gwin.h +++ b/src/gwin/class_gwin.h @@ -121,10 +121,12 @@ typedef struct gwinVMT { */ typedef struct gcontainerVMT { gwidgetVMT gw; - void (*AdjustPosition) (GHandle gh, coord_t *px, coord_t *py); // @< The container can adjust the relative position of a child (optional) - void (*AdjustSize) (GHandle gh, coord_t *pwidth, coord_t *pheight); // @< The container can adjust the size of a child (optional) - 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) + coord_t (*LeftBorder) (GHandle gh); // @< The size of the left border (mandatory) + coord_t (*TopBorder) (GHandle gh); // @< The size of the top border (mandatory) + coord_t (*RightBorder) (GHandle gh); // @< The size of the right border (mandatory) + coord_t (*BottomBorder) (GHandle gh); // @< The size of the bottom border (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 diff --git a/src/gwin/frame.c b/src/gwin/frame.c index 16e16987..dad807ca 100644 --- a/src/gwin/frame.c +++ b/src/gwin/frame.c @@ -19,6 +19,12 @@ #if GFX_USE_GWIN && GWIN_NEED_FRAME +#include "src/gwin/class_gwin.h" + +#if GWIN_FRAME_BORDER != GWIN_FIRST_CONTROL_FLAG + #error "GWIN Frame: - Flag definitions don't match" +#endif + /* Some values for the default render */ #define BORDER_X 5 #define BORDER_Y 30 @@ -29,9 +35,12 @@ #define gh2obj ((GFrameObject *)gh) /* Forware declarations */ -void gwinFrameDraw_Std(GWidgetObject *gw, void *param); +static void gwinFrameDraw_Std(GWidgetObject *gw, void *param); static void _callbackBtn(void *param, GEvent *pe); +static coord_t BorderSizeLRB(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) ? BORDER_X : 0; } +static coord_t BorderSizeT(GHandle gh) { return (gh->flags & GWIN_FRAME_BORDER) ? BORDER_Y : 0; } + static void _frameDestroy(GHandle gh) { /* Deregister the button callback */ geventRegisterCallback(&gh2obj->gl, NULL, NULL); @@ -90,8 +99,10 @@ static const gcontainerVMT frameVMT = { }, #endif }, - 0, // Adjust the relative position of a child (optional) - 0, // Adjust the size of a child (optional) + BorderSizeLRB, // The size of the left border (mandatory) + BorderSizeT, // The size of the top border (mandatory) + BorderSizeLRB, // The size of the right border (mandatory) + BorderSizeLRB, // The size of the bottom border (mandatory) 0, // A child has been added (optional) 0, // A child has been deleted (optional) }; @@ -108,9 +119,6 @@ GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) flags |= GWIN_FRAME_BORDER; - /* apply flags */ - fo->gc.g.flags |= flags; - /* create and initialize the listener if any button is present. */ if ((flags & (GWIN_FRAME_CLOSE_BTN|GWIN_FRAME_MINMAX_BTN))) { geventListenerInit(&fo->gl); @@ -157,6 +165,9 @@ GHandle gwinGFrameCreate(GDisplay *g, GFrameObject *fo, GWidgetInit *pInit, uint fo->btnMax = gwinGButtonCreate(g, 0, &wi); } + /* Apply flags. We apply these here so the controls above are outside the child area */ + fo->gc.g.flags |= flags; + gwinSetVisible(&fo->gc.g, pInit->g.show); return &fo->gc.g; @@ -196,10 +207,8 @@ static const GColorSet* _getDrawColors(GWidgetObject *gw) { return &gw->pstyle->enabled; } -void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { +static void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { const GColorSet *pcol; - color_t border; - color_t background; (void)param; if (gw->g.vmt != (gwinVMT *)&frameVMT) @@ -207,26 +216,15 @@ void gwinFrameDraw_Std(GWidgetObject *gw, void *param) { pcol = _getDrawColors(gw); - // do some magic to make the background lighter than the widgets. Fix this somewhen. - border = HTML2COLOR(0x2698DE); - background = HTML2COLOR(0xEEEEEE); - // 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.height - BORDER_Y - BORDER_X, background); + gdispGFillArea(gw->g.display, gw->g.x + BORDER_X, gw->g.y + BORDER_Y, gw->g.width - 2*BORDER_X, gw->g.height - BORDER_Y - BORDER_X, gw->pstyle->background); + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, BORDER_Y, gw->text, gw->g.font, gdispContrastColor(pcol->edge), pcol->edge, justifyCenter); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+BORDER_Y, BORDER_X, gw->g.height-(BORDER_Y+BORDER_X), pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x+gw->g.width-BORDER_X, gw->g.y+BORDER_Y, BORDER_X, gw->g.height-(BORDER_Y+BORDER_X), pcol->edge); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y+gw->g.height-BORDER_X, gw->g.width, BORDER_X, pcol->edge); } 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); + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); } } diff --git a/src/gwin/frame.h b/src/gwin/frame.h index 1b20b931..8116b1de 100644 --- a/src/gwin/frame.h +++ b/src/gwin/frame.h @@ -23,12 +23,14 @@ #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) +/** + * @brief Flags for gwinFrameCreate() + * @{ + */ +#define GWIN_FRAME_BORDER 0x00000001 +#define GWIN_FRAME_CLOSE_BTN 0x00000002 +#define GWIN_FRAME_MINMAX_BTN 0x00000004 +/* @} */ typedef struct GFrameObject { GContainerObject gc; diff --git a/src/gwin/gcontainer.c b/src/gwin/gcontainer.c index 704c26c0..3f6bfb56 100644 --- a/src/gwin/gcontainer.c +++ b/src/gwin/gcontainer.c @@ -104,6 +104,18 @@ GHandle gwinGetSibling(GHandle gh) { return 0; } +coord_t gwinGetInnerWidth(GHandle gh) { + if (!(gh->flags & GWIN_FLG_CONTAINER)) + return 0; + return gh->width - ((const gcontainerVMT *)gh->vmt)->LeftBorder(gh) - ((const gcontainerVMT *)gh->vmt)->RightBorder(gh); +} + +coord_t gwinGetInnerHeight(GHandle gh) { + if (!(gh->flags & GWIN_FLG_CONTAINER)) + return 0; + return gh->height - ((const gcontainerVMT *)gh->vmt)->TopBorder(gh) - ((const gcontainerVMT *)gh->vmt)->BottomBorder(gh); +} + #endif /* GFX_USE_GWIN && GWIN_NEED_CONTAINERS */ /** @} */ @@ -119,9 +131,17 @@ GHandle gwinGetSibling(GHandle gh) { #if GFX_USE_GWIN && GWIN_NEED_CONTAINER +#if GWIN_CONTAINER_BORDER != GWIN_FIRST_CONTROL_FLAG + #error "GWIN Container: - Flag definitions don't match" +#endif + +static coord_t BorderSize(GHandle gh) { return (gh->flags & GWIN_CONTAINER_BORDER) ? 2 : 0; } + static void DrawSimpleContainer(GWidgetObject *gw, void *param) { (void) param; gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background); + if ((gw->g.flags & GWIN_CONTAINER_BORDER)) + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge); } // The container VMT table @@ -151,18 +171,22 @@ static const gcontainerVMT containerVMT = { }, #endif }, - 0, // Adjust the relative position of a child (optional) - 0, // Adjust the size of a child (optional) + BorderSize, // The size of the left border (mandatory) + BorderSize, // The size of the top border (mandatory) + BorderSize, // The size of the right border (mandatory) + BorderSize, // The size of the bottom border (mandatory) 0, // A child has been added (optional) 0, // A child has been deleted (optional) }; -GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gw, const GWidgetInit *pInit) { - if (!(gw = (GContainerObject *)_gcontainerCreate(g, gw, pInit, &containerVMT))) +GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gc, const GWidgetInit *pInit, uint32_t flags) { + if (!(gc = (GContainerObject *)_gcontainerCreate(g, gc, pInit, &containerVMT))) return 0; - gwinSetVisible((GHandle)gw, pInit->g.show); - return (GHandle)gw; + gc->g.flags |= flags; + + gwinSetVisible((GHandle)gc, pInit->g.show); + return (GHandle)gc; } #endif diff --git a/src/gwin/gcontainer.h b/src/gwin/gcontainer.h index 8159797c..4a7b5632 100644 --- a/src/gwin/gcontainer.h +++ b/src/gwin/gcontainer.h @@ -80,6 +80,36 @@ extern "C" { */ GHandle gwinGetSibling(GHandle gh); + /** + * @brief Get the inner width of a container window + * + * @return The inner width of a container window or zero if this is not a container + * + * @param[in] gh The window + * + * @api + */ + coord_t gwinGetInnerWidth(GHandle gh); + + /** + * @brief Get the inner height of a container window + * + * @return The inner height of a container window or zero if this is not a container + * + * @param[in] gh The window + * + * @api + */ + coord_t gwinGetInnerHeight(GHandle gh); + + + /** + * @brief Flags for gwinContainerCreate() + * @{ + */ + #define GWIN_CONTAINER_BORDER 0x00000001 + /* @} */ + /** * @brief Create a simple container. * @return NULL if there is no resultant drawing area, otherwise a window handle. @@ -90,8 +120,8 @@ extern "C" { * * @api */ - GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gw, const GWidgetInit *pInit); - #define gwinContainerCreate(gc, pInit) gwinGContainerCreate(GDISP, gc, pInit) + GHandle gwinGContainerCreate(GDisplay *g, GContainerObject *gw, const GWidgetInit *pInit, uint32_t flags); + #define gwinContainerCreate(gc, pInit, flags) gwinGContainerCreate(GDISP, gc, pInit, flags) #ifdef __cplusplus } diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c index 7611bc9d..1c96d1c9 100644 --- a/src/gwin/gwm.c +++ b/src/gwin/gwm.c @@ -208,23 +208,27 @@ static void WM_Redraw(GHandle gh, int flags) { } static void WM_Size(GHandle gh, coord_t w, coord_t h) { - // Give it a minimum size - if (w < MIN_WIN_WIDTH) w = MIN_WIN_WIDTH; - if (h < MIN_WIN_HEIGHT) h = MIN_WIN_HEIGHT; + coord_t v; #if GWIN_NEED_CONTAINERS if (gh->parent) { // Clip to the container - if (gh->x+w > gh->parent->x+gh->parent->width) w = gh->parent->x + gh->parent->width - gh->x; - if (gh->y+h > gh->parent->y+gh->parent->height) h = gh->parent->y + gh->parent->height - gh->y; - if (((const gcontainerVMT *)gh->parent->vmt)->AdjustSize) - ((const gcontainerVMT *)gh->parent->vmt)->AdjustSize(gh, &w, &h); + v = gh->parent->x + gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); + if (gh->x+w > v) w = v - gh->x; + v = gh->parent->y + gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); + if (gh->y+h > v) h = v - gh->y; } #endif // Clip to the screen - 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; + v = gdispGGetWidth(gh->display); + if (gh->x+w > v) w = v - gh->x; + v = gdispGGetHeight(gh->display); + if (gh->y+h > v) h = v - gh->y; + + // Give it a minimum size + if (w < MIN_WIN_WIDTH) w = MIN_WIN_WIDTH; + if (h < MIN_WIN_HEIGHT) h = MIN_WIN_HEIGHT; // If there has been no resize just exit if (gh->width == w && gh->height == h) @@ -243,29 +247,31 @@ static void WM_Size(GHandle gh, coord_t w, coord_t h) { } static void WM_Move(GHandle gh, coord_t x, coord_t y) { + coord_t v; + #if GWIN_NEED_CONTAINERS if (gh->parent) { - // Clip to the parent + // Clip to the parent size + v = gh->parent->width - ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->RightBorder(gh->parent); + if (x+gh->width > v) x = v-gh->width; + v = gh->parent->height - ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent) - ((const gcontainerVMT *)gh->parent->vmt)->BottomBorder(gh->parent); + if (y+gh->height > v) y = v-gh->height; if (x < 0) x = 0; if (y < 0) y = 0; - if (x > gh->parent->width-gh->width) x = gh->parent->width-gh->width; - if (y > gh->parent->height-gh->height) y = gh->parent->height-gh->height; - - // Allow the parent to adjust it - if (((const gcontainerVMT *)gh->parent->vmt)->AdjustPosition) - ((const gcontainerVMT *)gh->parent->vmt)->AdjustPosition(gh, &x, &y); // Convert to absolute position - x += gh->parent->x; - y += gh->parent->y; + x += gh->parent->x + ((const gcontainerVMT *)gh->parent->vmt)->LeftBorder(gh->parent); + y += gh->parent->y + ((const gcontainerVMT *)gh->parent->vmt)->TopBorder(gh->parent); } #endif // Clip to the screen + v = gdispGGetWidth(gh->display); + if (x+gh->width > v) x = v-gh->width; + v = gdispGGetHeight(gh->display); + if (y+gh->height > v) y = v-gh->height; 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)