diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/gfx.c | 2 | ||||
-rw-r--r-- | src/ginput/dial.c | 2 | ||||
-rw-r--r-- | src/gqueue/gqueue.c | 37 | ||||
-rw-r--r-- | src/gwin/button.c | 558 | ||||
-rw-r--r-- | src/gwin/checkbox.c | 264 | ||||
-rw-r--r-- | src/gwin/console.c | 60 | ||||
-rw-r--r-- | src/gwin/gimage.c | 175 | ||||
-rw-r--r-- | src/gwin/graph.c | 77 | ||||
-rw-r--r-- | src/gwin/gwidget.c | 461 | ||||
-rw-r--r-- | src/gwin/gwin.c | 383 | ||||
-rw-r--r-- | src/gwin/gwin.mk | 9 | ||||
-rw-r--r-- | src/gwin/gwm.c | 201 | ||||
-rw-r--r-- | src/gwin/label.c | 118 | ||||
-rw-r--r-- | src/gwin/radio.c | 229 | ||||
-rw-r--r-- | src/gwin/slider.c | 487 |
15 files changed, 2239 insertions, 824 deletions
@@ -19,7 +19,7 @@ void DEPRECATED("Use gfxInit() instead") gdispInit() { gfxInit(); } /* These init functions are defined by each module but not published */ extern void _gosInit(void); -#if GFX_USE_GDISP && (GDISP_NEED_MULTITHREAD || GDISP_NEED_ASYNC) +#if GFX_USE_GDISP extern void _gdispInit(void); #endif #if GFX_USE_TDISP diff --git a/src/ginput/dial.c b/src/ginput/dial.c index 3afb4796..d978aa65 100644 --- a/src/ginput/dial.c +++ b/src/ginput/dial.c @@ -57,6 +57,7 @@ static void DialCallback(uint16_t instance, uint16_t rawvalue) { pe->type = GEVENT_DIAL; pe->instance = instance; pe->value = pds->lastvalue; + pe->maxvalue = pds->max; geventSendEvent(psl); } } @@ -144,6 +145,7 @@ bool_t ginputGetDialStatus(uint16_t instance, GEventDial *pdial) { pdial->type = GEVENT_DIAL; pdial->instance = instance; pdial->value = DialStatus[instance].lastvalue; + pdial->maxvalue = DialStatus[instance].max; return TRUE; } diff --git a/src/gqueue/gqueue.c b/src/gqueue/gqueue.c index 7cd1c9d9..beb42a2e 100644 --- a/src/gqueue/gqueue.c +++ b/src/gqueue/gqueue.c @@ -9,6 +9,9 @@ * @file src/gqueue/gqueue.c * @brief GQUEUE source file. */ + +#include "gfx.h" + #if GFX_USE_GQUEUE #if GQUEUE_NEED_ASYNC @@ -22,7 +25,8 @@ gfxSystemLock(); if ((pi = pqueue->head)) pqueue->head = pi->next; - gfxSytemUnlock(); + pi->next = 0; + gfxSystemUnlock(); return pi; } void gfxQueueASyncPut(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) { @@ -46,17 +50,21 @@ gfxSystemUnlock(); } void gfxQueueASyncRemove(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) { + gfxQueueASyncItem *pi; + if (!pitem) return; gfxSystemLock(); if (pqueue->head) { if (pqueue->head == pitem) { pqueue->head = pitem->next; + pitem->next = 0; } else { - for(gfxQueueASyncItem *pi = pqueue->head; pi->next; pi = pi->next) { + for(pi = pqueue->head; pi->next; pi = pi->next) { if (pi->next == pitem) { pi->next = pitem->next; if (pqueue->tail == pitem) pqueue->tail = pi; + pitem->next = 0; break; } } @@ -68,8 +76,10 @@ return pqueue->head == NULL; } bool_t gfxQueueASyncIsIn(gfxQueueASync *pqueue, gfxQueueASyncItem *pitem) { + gfxQueueASyncItem *pi; + gfxSystemLock(); - for(gfxQueueASyncItem *pi = pqueue->head; pi; pi = pi->next) { + for(pi = pqueue->head; pi; pi = pi->next) { if (pi == pitem) { gfxSystemUnlock(); return TRUE; @@ -92,6 +102,7 @@ gfxSystemLock(); pi = pqueue->head; pqueue->head = pi->next; + pi->next = 0; gfxSytemUnlock(); return pi; } @@ -120,17 +131,21 @@ gfxSemSignal(&pqueue->sem); } void gfxQueueGSyncRemove(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) { + gfxQueueGSyncItem *pi; + if (!pitem) return; gfxSystemLock(); if (pqueue->head) { if (pqueue->head == pitem) { pqueue->head = pitem->next; + pitem->next = 0; } else { - for(gfxQueueGSyncItem *pi = pqueue->head; pi->next; pi = pi->next) { + for(pi = pqueue->head; pi->next; pi = pi->next) { if (pi->next == pitem) { pi->next = pitem->next; if (pqueue->tail == pitem) pqueue->tail = pi; + pitem->next = 0; break; } } @@ -142,8 +157,10 @@ return pqueue->head == NULL; } bool_t gfxQueueGSyncIsIn(gfxQueueGSync *pqueue, gfxQueueGSyncItem *pitem) { + gfxQueueGSyncItem *pi; + gfxSystemLock(); - for(gfxQueueGSyncItem *pi = pqueue->head; pi; pi = pi->next) { + for(pi = pqueue->head; pi; pi = pi->next) { if (pi == pitem) { gfxSystemUnlock(); return TRUE; @@ -166,6 +183,7 @@ gfxSystemLock(); pi = pqueue->head; pqueue->head = pi->next; + pi->next = 0; gfxSytemUnlock(); gfxSemSignalI(&pi->sem); @@ -202,18 +220,21 @@ return gfxSemWait(&pitem->sem, ms); } void gfxQueueFSyncRemove(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) { + gfxQueueFSyncItem *pi; + if (!pitem) return; gfxSystemLock(); if (pqueue->head) { if (pqueue->head == pitem) { pqueue->head = pitem->next; found: + pitem->next = 0; gfxSystemUnlock(); gfxSemSignal(&pitem->sem); gfxSemDestroy(&pitem->sem); return; } - for(gfxQueueFSyncItem *pi = pqueue->head; pi->next; pi = pi->next) { + for(pi = pqueue->head; pi->next; pi = pi->next) { if (pi->next == pitem) { pi->next = pitem->next; if (pqueue->tail == pitem) @@ -228,8 +249,10 @@ return pqueue->head == NULL; } bool_t gfxQueueFSyncIsIn(gfxQueueFSync *pqueue, gfxQueueFSyncItem *pitem) { + gfxQueueASyncItem *pi; + gfxSystemLock(); - for(gfxQueueFSyncItem *pi = pqueue->head; pi; pi = pi->next) { + for(pi = pqueue->head; pi; pi = pi->next) { if (pi == pitem) { gfxSystemUnlock(); return TRUE; diff --git a/src/gwin/button.c b/src/gwin/button.c index 6b7306b5..e6f628c3 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -17,394 +17,308 @@ #include "gfx.h" -#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__) +#if GFX_USE_GWIN && GWIN_NEED_BUTTON -/* Parameters for various shapes */ +#include "gwin/class_gwin.h" + +// Parameters for various shapes #define RND_CNR_SIZE 5 // Rounded corner size for rounded buttons #define ARROWHEAD_DIVIDER 4 // A quarter of the height for the arrow head #define ARROWBODY_DIVIDER 4 // A quarter of the width for the arrow body -#include <string.h> - -#include "gwin/internal.h" - -#define GWIN_BUTTON_DEFAULT_SHAPE GBTN_3D - -static const GButtonDrawStyle GButtonDefaultStyleUp = { - HTML2COLOR(0x404040), // color_up_edge; - HTML2COLOR(0xE0E0E0), // color_up_fill; - HTML2COLOR(0x000000), // color_up_txt; -}; - -static const GButtonDrawStyle GButtonDefaultStyleDown = { - HTML2COLOR(0x404040), // color_dn_edge; - HTML2COLOR(0x808080), // color_dn_fill; - HTML2COLOR(0x404040), // color_dn_txt; -}; - -// Process an event callback -static void gwinButtonCallback(void *param, GEvent *pe) { - GSourceListener *psl; - #define gh ((GHandle)param) - #define gbw ((GButtonObject *)param) - #define gsh ((GSourceHandle)param) - #define pme ((GEventMouse *)pe) - #define pte ((GEventTouch *)pe) - #define pxe ((GEventToggle *)pe) - #define pbe ((GEventGWinButton *)pe) - - // check if button is disabled - if (!gh->enabled) - return; - - switch (pe->type) { - #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - case GEVENT_MOUSE: - case GEVENT_TOUCH: - // Ignore anything other than the primary mouse button going up or down - if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT)) - return; - - if (gbw->state == GBTN_UP) { - // Our button is UP: Test for button down over the button - if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) - && pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width - && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) { - gbw->state = GBTN_DOWN; - gwinButtonDraw((GHandle)param); - } - return; - } - - // Our button is DOWN - - // Skip more mouse downs - if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - return; - - // This must be a mouse up - set the button as UP - gbw->state = GBTN_UP; - gwinButtonDraw((GHandle)param); - - #if GWIN_BUTTON_LAZY_RELEASE - break; - #else - // If the mouse up was over the button then create the event - if (pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width - && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) - break; +// Our pressed state +#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0) - return; - #endif - #endif - - #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - case GEVENT_TOGGLE: - // State has changed - update the button - gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP; - gwinButtonDraw((GHandle)param); - - // Trigger the event on button down (different than for mouse/touch) - if (gbw->state == GBTN_DOWN) - break; - - return; - #endif - - default: - return; - } +// Send the button event +static void SendButtonEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pbe ((GEventGWinButton *)pe) // Trigger a GWIN Button Event psl = 0; - while ((psl = geventGetSourceListener(gsh, psl))) { + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; pbe->type = GEVENT_GWIN_BUTTON; - pbe->button = gh; + pbe->button = (GHandle)gw; geventSendEvent(psl); } #undef pbe - #undef pme - #undef pte - #undef pxe - #undef gsh - #undef gbw - #undef gh } -GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) { - if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject)))) - return 0; - - gb->gwin.type = GW_BUTTON; - gb->fn = 0; - gb->param = 0; - gwinSetFont(&gb->gwin, font); - gwinSetButtonStyle(&gb->gwin, GWIN_BUTTON_DEFAULT_SHAPE, &GButtonDefaultStyleUp, &GButtonDefaultStyleDown); - gb->type = type; - gb->state = GBTN_UP; - gb->txt = ""; - geventListenerInit(&gb->listener); - geventRegisterCallback(&gb->listener, gwinButtonCallback, gb); - - // buttons are enabled by default - gb->gwin.enabled = TRUE; - - return (GHandle)gb; -} - -void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) { - #define gbw ((GButtonObject *)gh) - if (gh->type != GW_BUTTON) - return; +#if GINPUT_NEED_MOUSE + // A mouse down has occurred over the button + static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + (void) x; (void) y; + gw->g.flags |= GBUTTON_FLG_PRESSED; + _gwidgetRedraw((GHandle)gw); + } - switch(shape) { - case GBTN_SQUARE: gbw->fn = gwinButtonDraw_Square; break; - #if GDISP_NEED_ARC - case GBTN_ROUNDED: gbw->fn = gwinButtonDraw_Rounded; break; - #endif - #if GDISP_NEED_ELLIPSE - case GBTN_ELLIPSE: gbw->fn = gwinButtonDraw_Ellipse; break; - #endif + // 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); - #if GDISP_NEED_CONVEX_POLYGON - case GBTN_ARROW_UP: gbw->fn = gwinButtonDraw_ArrowUp; break; - case GBTN_ARROW_DOWN: gbw->fn = gwinButtonDraw_ArrowDown; break; - case GBTN_ARROW_LEFT: gbw->fn = gwinButtonDraw_ArrowLeft; break; - case GBTN_ARROW_RIGHT: gbw->fn = gwinButtonDraw_ArrowRight; break; + #if !GWIN_BUTTON_LAZY_RELEASE + // If the mouse up was not over the button then cancel the event + if (x < 0 || y < 0 || x >= gw->g.width || y >= gw->g.height) + return; #endif - case GBTN_CUSTOM: if (gbw->fn) break; /* Fall Through */ - case GBTN_3D: /* Fall through */ - default: gbw->fn = gwinButtonDraw_3D; break; + SendButtonEvent(gw); } - if (pUp) { - gbw->up.color_edge = pUp->color_edge; - gbw->up.color_fill = pUp->color_fill; - gbw->up.color_txt = pUp->color_txt; - } - if (pDown) { - gbw->dn.color_edge = pDown->color_edge; - gbw->dn.color_fill = pDown->color_fill; - gbw->dn.color_txt = pDown->color_txt; +#endif + +#if GINPUT_NEED_TOGGLE + // A toggle off has occurred + static void ToggleOff(GWidgetObject *gw, uint16_t role) { + (void) role; + gw->g.flags &= ~GBUTTON_FLG_PRESSED; + _gwidgetRedraw((GHandle)gw); } - #undef gbw -} -void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) { - #define gbw ((GButtonObject *)gh) - if (gh->type != GW_BUTTON) - return; - - // Dispose of the old string - if ((gh->flags & GBTN_FLG_ALLOCTXT)) { - gh->flags &= ~GBTN_FLG_ALLOCTXT; - if (gbw->txt) { - gfxFree((void *)gbw->txt); - gbw->txt = ""; - } + // A toggle on has occurred + static void ToggleOn(GWidgetObject *gw, uint16_t role) { + (void) role; + gw->g.flags |= GBUTTON_FLG_PRESSED; + _gwidgetRedraw((GHandle)gw); + // Trigger the event on button down (different than for mouse/touch) + SendButtonEvent(gw); } - // Alloc the new text if required - if (txt && useAlloc) { - char *str; - - if ((str = (char *)gfxAlloc(strlen(txt)+1))) { - gh->flags |= GBTN_FLG_ALLOCTXT; - strcpy(str, txt); - } - txt = (const char *)str; + + static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GButtonObject *)gw)->toggle = instance; } - - gbw->txt = txt ? txt : ""; - #undef gbw -} -void gwinButtonDraw(GHandle gh) { - #define gbw ((GButtonObject *)gh) - - if (gh->type != GW_BUTTON) - return; + static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GButtonObject *)gw)->toggle; + } +#endif - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); +// The button VMT table +static const gwidgetVMT buttonVMT = { + { + "Button", // The classname + sizeof(GButtonObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinButtonDraw_3D, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + MouseDown, // Process mouse down events + MouseUp, // Process mouse up events + 0, // Process mouse move events (NOT USED) + }, #endif + #if GINPUT_NEED_TOGGLE + { + 1, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + ToggleOff, // Process toggle off events + ToggleOn, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Process dial move events (NOT USED) + }, + #endif +}; - gbw->fn(gh, - gbw->gwin.enabled, - gbw->state == GBTN_DOWN, - gh->font && gbw->txt ? gbw->txt : "", - gbw->state == GBTN_DOWN ? &gbw->dn : &gbw->up, - gbw->param); - - #undef gbw -} - -void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) { - #define gbw ((GButtonObject *)gh) - - if (gh->type != GW_BUTTON) - return; - - gbw->fn = fn ? fn : gwinButtonDraw_3D; - gbw->param = param; +GHandle gwinButtonCreate(GButtonObject *gw, const GWidgetInit *pInit) { + if (!(gw = (GButtonObject *)_gwidgetCreate(&gw->w, pInit, &buttonVMT))) + return 0; - #undef gbw + #if GINPUT_NEED_TOGGLE + gw->toggle = GWIDGET_NO_INSTANCE; + #endif + gwinSetVisible((GHandle)gw, pInit->g.show); + return (GHandle)gw; } -void gwinButtonSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_BUTTON) - return; +bool_t gwinButtonIsPressed(GHandle gh) { + if (gh->vmt != (gwinVMT *)&buttonVMT) + return FALSE; - gh->enabled = enabled; + return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE; } -void gwinButtonDraw_3D(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ - gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); - gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, pstyle->color_edge); - gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, pstyle->color_edge); +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 gwinButtonDraw_Square(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; +void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; - gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); } #if GDISP_NEED_ARC - void gwinButtonDraw_Rounded(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - - if (gh->width >= 2*RND_CNR_SIZE+10) { - gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, pstyle->color_fill); - gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, pstyle->color_txt, justifyCenter); - gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, pstyle->color_edge); + void gwinButtonDraw_Rounded(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + if (gw->g.width >= 2*RND_CNR_SIZE+10) { + gdispFillRoundedBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, RND_CNR_SIZE-1, pcol->fill); + gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->text, gw->g.font, pcol->text, justifyCenter); + gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->edge); } else { - gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); + gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); } } #endif #if GDISP_NEED_ELLIPSE - void gwinButtonDraw_Ellipse(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - - gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, pstyle->color_fill); - gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); - gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, pstyle->color_edge); + void gwinButtonDraw_Ellipse(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->fill); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); + gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->edge); } #endif #if GDISP_NEED_CONVEX_POLYGON - void gwinButtonDraw_ArrowUp(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - point arw[7]; - - arw[0].x = gh->width/2; arw[0].y = 0; - arw[1].x = gh->width-1; arw[1].y = gh->height/ARROWHEAD_DIVIDER; - arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height/ARROWHEAD_DIVIDER; - arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = gh->height-1; - arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = gh->height-1; - arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height/ARROWHEAD_DIVIDER; - arw[6].x = 0; arw[6].y = gh->height/ARROWHEAD_DIVIDER; - - gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); - gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); - gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); + void gwinButtonDraw_ArrowUp(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + point arw[7]; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + arw[0].x = gw->g.width/2; arw[0].y = 0; + arw[1].x = gw->g.width-1; arw[1].y = gw->g.height/ARROWHEAD_DIVIDER; + arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height/ARROWHEAD_DIVIDER; + arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = gw->g.height-1; + arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = gw->g.height-1; + arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height/ARROWHEAD_DIVIDER; + arw[6].x = 0; arw[6].y = gw->g.height/ARROWHEAD_DIVIDER; + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } - void gwinButtonDraw_ArrowDown(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - point arw[7]; - - arw[0].x = gh->width/2; arw[0].y = gh->height-1; - arw[1].x = gh->width-1; arw[1].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; - arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; - arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = 0; - arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = 0; - arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; - arw[6].x = 0; arw[6].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; - - gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); - gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); - gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); + void gwinButtonDraw_ArrowDown(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + point arw[7]; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + arw[0].x = gw->g.width/2; arw[0].y = gw->g.height-1; + arw[1].x = gw->g.width-1; arw[1].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; + arw[2].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[2].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; + arw[3].x = (gw->g.width + gw->g.width/ARROWBODY_DIVIDER)/2; arw[3].y = 0; + arw[4].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[4].y = 0; + arw[5].x = (gw->g.width - gw->g.width/ARROWBODY_DIVIDER)/2; arw[5].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; + arw[6].x = 0; arw[6].y = gw->g.height-1-gw->g.height/ARROWHEAD_DIVIDER; + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } - void gwinButtonDraw_ArrowLeft(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - point arw[7]; - - arw[0].x = 0; arw[0].y = gh->height/2; - arw[1].x = gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; - arw[2].x = gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; - arw[3].x = gh->width-1; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; - arw[4].x = gh->width-1; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; - arw[5].x = gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; - arw[6].x = gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1; - - gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); - gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); - gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); + void gwinButtonDraw_ArrowLeft(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + point arw[7]; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + arw[0].x = 0; arw[0].y = gw->g.height/2; + arw[1].x = gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0; + arw[2].x = gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2; + arw[3].x = gw->g.width-1; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2; + arw[4].x = gw->g.width-1; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; + arw[5].x = gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; + arw[6].x = gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1; + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } - void gwinButtonDraw_ArrowRight(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { - (void) enabled; - (void) isdown; - (void) param; - point arw[7]; - - arw[0].x = gh->width-1; arw[0].y = gh->height/2; - arw[1].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; - arw[2].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; - arw[3].x = 0; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; - arw[4].x = 0; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; - arw[5].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; - arw[6].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1; - - gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); - gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); - gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); + void gwinButtonDraw_ArrowRight(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + point arw[7]; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + arw[0].x = gw->g.width-1; arw[0].y = gw->g.height/2; + arw[1].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[1].y = 0; + arw[2].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[2].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2; + arw[3].x = 0; arw[3].y = (gw->g.height - gw->g.height/ARROWBODY_DIVIDER)/2; + arw[4].x = 0; arw[4].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; + arw[5].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[5].y = (gw->g.height + gw->g.height/ARROWBODY_DIVIDER)/2; + arw[6].x = gw->g.width-1-gw->g.width/ARROWHEAD_DIVIDER; arw[6].y = gw->g.height-1; + + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } #endif -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) { - GSourceHandle gsh; - - if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance))) - return FALSE; +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) + void gwinButtonDraw_Image(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + coord_t sy; - return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); - } -#endif + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); -#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE - bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance) { - GSourceHandle gsh; - - if (gh->type != GW_BUTTON || !(gsh = ginputGetToggle(instance))) - return FALSE; + if (!(gw->g.flags & GWIN_FLG_ENABLED)) { + sy = 2 * gw->g.height; + } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) { + sy = gw->g.height; + } else { + sy = 0; + } - return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON); + gdispImageDraw((gdispImage *)param, gw->g.x, gw->g.y, gw->g.width, gw->g.height, 0, sy); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); } #endif diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index faea0ef9..84eb3b9f 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -7,7 +7,7 @@ /** * @file src/gwin/checkbox.c - * @brief GWIN sub-system checkbox code. + * @brief GWIN sub-system button code. * * @defgroup Checkbox Checkbox * @ingroup GWIN @@ -19,168 +19,178 @@ #if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__) -static const GCheckboxColor defaultColors = { - Grey, // border - Grey, // selected - Black // background -}; - -/* default style drawing routine */ -static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) { - #define gcw ((GCheckboxObject *)gh) +#include "gwin/class_gwin.h" - (void) enabled; - (void) param; +// Our checked state +#define GCHECKBOX_FLG_CHECKED (GWIN_FIRST_CONTROL_FLAG<<0) - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border); +// Send the checkbox event +static void SendCheckboxEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pce ((GEventGWinCheckbox *)pe) - if (isChecked) - gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->checked); - else - gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->bg); + // Trigger a GWIN Checkbox Event + psl = 0; + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { + if (!(pe = geventGetEventBuffer(psl))) + continue; + pce->type = GEVENT_GWIN_CHECKBOX; + pce->checkbox = &gw->g; + pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; + geventSendEvent(psl); + } - #undef gcw + #undef pce } -/* process an event callback */ -static void gwinCheckboxCallback(void *param, GEvent *pe) { - GSourceListener *psl; - #define gh ((GHandle)param) - #define gbw ((GCheckboxObject *)param) - #define gsh ((GSourceHandle)param) - #define pme ((GEventMouse *)pe) - #define pte ((GEventTouch *)pe) - #define pxe ((GEventToggle *)pe) - #define pbe ((GEventGWinCheckbox *)pe) - - /* check if checkbox is disabled */ - if (!gh->enabled) - return; - - switch (pe->type) { - #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - case GEVENT_MOUSE: - case GEVENT_TOUCH: - - // Ignore anything other than the primary mouse button going up or down - if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT)) - return; - - if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) - && pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width - && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) { +#if GINPUT_NEED_MOUSE + static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + (void) x; (void) y; + gw->g.flags ^= GCHECKBOX_FLG_CHECKED; + _gwidgetRedraw((GHandle)gw); + SendCheckboxEvent(gw); + } +#endif - gbw->isChecked = !gbw->isChecked; +#if GINPUT_NEED_TOGGLE + static void ToggleOn(GWidgetObject *gw, uint16_t role) { + (void) role; + gw->g.flags ^= GCHECKBOX_FLG_CHECKED; + _gwidgetRedraw((GHandle)gw); + SendCheckboxEvent(gw); + } - gwinCheckboxDraw((GHandle)param); - break; - } - return; - #endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ + static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GCheckboxObject *)gw)->toggle = instance; + } - default: - return; + static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GCheckboxObject *)gw)->toggle; } +#endif - // Trigger a GWIN checkbox event - psl = 0; - while ((psl = geventGetSourceListener(gsh, psl))) { - if (!(pe = geventGetEventBuffer(psl))) - continue; - pbe->type = GEVENT_GWIN_CHECKBOX; - pbe->checkbox = gh; - pbe->isChecked = gbw->isChecked; - geventSendEvent(psl); - } - - #undef gh - #undef pbe - #undef pme - #undef pte - #undef pxe - #undef gsh - #undef gbw -} +// The checkbox VMT table +static const gwidgetVMT checkboxVMT = { + { + "Checkbox", // The classname + sizeof(GCheckboxObject),// The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinCheckboxDraw_CheckOnLeft, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + MouseDown, // Process mouse down events + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 1, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Process dial move events (NOT USED) + }, + #endif +}; -GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gb = (GCheckboxObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GCheckboxObject)))) +GHandle gwinCheckboxCreate(GCheckboxObject *gb, const GWidgetInit *pInit) { + if (!(gb = (GCheckboxObject *)_gwidgetCreate(&gb->w, pInit, &checkboxVMT))) return 0; - gb->gwin.type = GW_CHECKBOX; // create a window of the type checkbox - gb->fn = gwinCheckboxDrawDefaultStyle; // set the default style drawing routine - gb->colors = &defaultColors; // asign the default colors - gb->param = 0; // some safe value here - gb->isChecked = GCHBX_UNCHECKED; // checkbox is currently unchecked - gb->gwin.enabled = TRUE; // checkboxes are enabled by default - - geventListenerInit(&gb->listener); - geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb); - - // checkboxes are enabled by default - gb->gwin.enabled = TRUE; - + #if GINPUT_NEED_TOGGLE + gb->toggle = GWIDGET_NO_INSTANCE; + #endif + gwinSetVisible((GHandle)gb, pInit->g.show); return (GHandle)gb; } -void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) { - #define gcw ((GCheckboxObject *)gh) - - if (gh->type != GW_CHECKBOX) +void gwinCheckboxCheck(GHandle gh, bool_t isChecked) { + if (gh->vmt != (gwinVMT *)&checkboxVMT) return; - gcw->fn = fn; - gcw->param = param; - - #undef gcw + if (isChecked) { + if ((gh->flags & GCHECKBOX_FLG_CHECKED)) return; + gh->flags |= GCHECKBOX_FLG_CHECKED; + } else { + if (!(gh->flags & GCHECKBOX_FLG_CHECKED)) return; + gh->flags &= ~GCHECKBOX_FLG_CHECKED; + } + _gwidgetRedraw(gh); + SendCheckboxEvent((GWidgetObject *)gh); } +bool_t gwinCheckboxIsChecked(GHandle gh) { + if (gh->vmt != (gwinVMT *)&checkboxVMT) + return FALSE; -void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_CHECKBOX) - return; + return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; +} + +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ - gh->enabled = enabled; +static const GColorSet *getDrawColors(GWidgetObject *gw) { + if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if ((gw->g.flags & GCHECKBOX_FLG_CHECKED)) return &gw->pstyle->pressed; + return &gw->pstyle->enabled; } -void gwinCheckboxDraw(GHandle gh) { - #define gcw ((GCheckboxObject *)gh) +void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) { + #define gcw ((GCheckboxObject *)gw) + coord_t ld, df; + const GColorSet * pcol; + (void) param; - if (gh->type != GW_CHECKBOX) - return; + if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; + pcol = getDrawColors(gw); - #if GDISP_NEED_CLIP - //gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif + ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; + gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge); - gcw->fn(gh, - gcw->gwin.enabled, - gcw->isChecked, - gcw->param); + df = ld < 4 ? 1 : 2; + if (gw->g.flags & GCHECKBOX_FLG_CHECKED) + gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); #undef gcw } -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) { - GSourceHandle gsh; +void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { + #define gcw ((GCheckboxObject *)gw) + coord_t ep, ld, df; + const GColorSet * pcol; + (void) param; - if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance))) - return FALSE; + if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; + pcol = getDrawColors(gw); - return geventAttachSource(&((GCheckboxObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); - } -#endif - -void gwinCheckboxSetColors(GHandle gh, color_t border, color_t checked, color_t bg) { - #define gcw ((GCheckboxObject *)gh) - - if (gh->type != GW_CHECKBOX) - return; + ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; + ep = gw->g.width-ld-1; + gdispFillArea(gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, pcol->edge); - gcw->colors->border = border; - gcw->colors->checked = checked, - gcw->colors->bg = bg; + df = ld < 4 ? 1 : 2; + if (gw->g.flags & GCHECKBOX_FLG_CHECKED) + gdispFillArea(gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyRight); #undef gcw } diff --git a/src/gwin/console.c b/src/gwin/console.c index a4cd428c..06648e9b 100644 --- a/src/gwin/console.c +++ b/src/gwin/console.c @@ -8,20 +8,15 @@ /** * @file src/gwin/console.c * @brief GWIN sub-system console code. - * - * @defgroup Console Console - * @ingroup GWIN - * - * @{ */ #include "gfx.h" -#if (GFX_USE_GWIN && GWIN_NEED_CONSOLE) || defined(__DOXYGEN__) +#if GFX_USE_GWIN && GWIN_NEED_CONSOLE #include <string.h> -#include "gwin/internal.h" +#include "gwin/class_gwin.h" #define GWIN_CONSOLE_USE_CLEAR_LINES TRUE #define GWIN_CONSOLE_USE_FILLED_CHARS FALSE @@ -58,32 +53,48 @@ }; #endif -GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) { - if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject)))) +static void AfterClear(GWindowObject *gh) { + ((GConsoleObject *)gh)->cx = 0; + ((GConsoleObject *)gh)->cy = 0; +} + +static const gwinVMT consoleVMT = { + "Console", // The classname + sizeof(GConsoleObject), // The object size + 0, // The destroy routine + 0, // The redraw routine + AfterClear, // The after-clear routine +}; + +GHandle gwinConsoleCreate(GConsoleObject *gc, const GWindowInit *pInit) { + if (!(gc = (GConsoleObject *)_gwindowCreate(&gc->g, pInit, &consoleVMT, 0))) return 0; - gc->gwin.type = GW_CONSOLE; - gwinSetFont(&gc->gwin, font); #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM gc->stream.vmt = &GWindowConsoleVMT; #endif gc->cx = 0; gc->cy = 0; + gwinSetVisible((GHandle)gc, pInit->show); return (GHandle)gc; } #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM - BaseSequentialStream *gwinGetConsoleStream(GHandle gh) { - if (gh->type != GW_CONSOLE) + BaseSequentialStream *gwinConsoleGetStream(GHandle gh) { + if (gh->vmt != &consoleVMT) return 0; return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream); } #endif void gwinPutChar(GHandle gh, char c) { - uint8_t width; #define gcw ((GConsoleObject *)gh) + uint8_t width, fy, fp; + + if (gh->vmt != &consoleVMT || !gh->font) + return; - if (gh->type != GW_CONSOLE || !gh->font) return; + fy = gdispGetFontMetric(gh->font, fontHeight); + fp = gdispGetFontMetric(gh->font, fontCharPadding); #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); @@ -91,24 +102,24 @@ void gwinPutChar(GHandle gh, char c) { if (c == '\n') { gcw->cx = 0; - gcw->cy += gcw->fy; + gcw->cy += fy; // We use lazy scrolling here and only scroll when the next char arrives } else if (c == '\r') { // gcw->cx = 0; } else { - width = gdispGetCharWidth(c, gh->font) + gcw->fp; + width = gdispGetCharWidth(c, gh->font) + fp; if (gcw->cx + width >= gh->width) { gcw->cx = 0; - gcw->cy += gcw->fy; + gcw->cy += fy; } - if (gcw->cy + gcw->fy > gh->height) { + if (gcw->cy + fy > gh->height) { #if GDISP_NEED_SCROLL /* scroll the console */ - gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, gcw->fy, gh->bgcolor); + gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor); /* reset the cursor to the start of the last line */ gcw->cx = 0; - gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy; + gcw->cy = (((coord_t)(gh->height/fy))-1)*fy; #else /* clear the console */ gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); @@ -121,7 +132,7 @@ void gwinPutChar(GHandle gh, char c) { #if GWIN_CONSOLE_USE_CLEAR_LINES /* clear to the end of the line */ if (gcw->cx == 0) - gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, gcw->fy, gh->bgcolor); + gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor); #endif #if GWIN_CONSOLE_USE_FILLED_CHARS gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor); @@ -200,7 +211,8 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) { char tmpbuf[MAX_FILLER + 1]; #endif - if (gh->type != GW_CONSOLE || !gh->font) return; + if (gh->vmt != &consoleVMT || !gh->font) + return; va_start(ap, fmt); while (TRUE) { @@ -343,5 +355,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) { } #endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */ -/** @} */ + diff --git a/src/gwin/gimage.c b/src/gwin/gimage.c new file mode 100644 index 00000000..2dcba4ba --- /dev/null +++ b/src/gwin/gimage.c @@ -0,0 +1,175 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +/** + * @file src/gwin/image.c + * @brief GWIN sub-system image code. + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_IMAGE + +#include "gwin/class_gwin.h" + +#define widget(gh) ((GImageObject *)gh) + +static void _destroy(GWindowObject *gh) { + if (gdispImageIsOpen(&widget(gh)->image)) + gdispImageClose(&widget(gh)->image); +} + +static void _redraw(GHandle gh) { + coord_t x, y, w, h, dx, dy; + color_t bg; + + // The default display area + x = gh->x; + y = gh->y; + w = gh->width; + h = gh->height; + bg = gwinGetDefaultBgColor(); + + // If the image isn't open just clear the area + if (!gdispImageIsOpen(&widget(gh)->image)) { + gdispFillArea(x, y, w, h, bg); + return; + } + + // Center horizontally if the area is larger than the image + if (widget(gh)->image.width < w) { + w = widget(gh)->image.width; + dx = (gh->width-w)/2; + x += dx; + if (dx) + gdispFillArea(gh->x, y, dx, h, bg); + gdispFillArea(x+w, y, gh->width-dx-w, h, bg); + dx = 0; + } + + // Center image horizontally if the area is smaller than the image + else if (widget(gh)->image.width > w) { + dx = (widget(gh)->image.width - w)/2; + } + + // Center vertically if the area is larger than the image + if (widget(gh)->image.height < h) { + h = widget(gh)->image.height; + dy = (gh->height-h)/2; + y += dy; + if (dy) + gdispFillArea(x, gh->y, w, dy, bg); + gdispFillArea(x, y+h, w, gh->height-dy-h, bg); + dy = 0; + } + + // Center image vertically if the area is smaller than the image + else if (widget(gh)->image.height > h) { + dy = (widget(gh)->image.height - h)/2; + } + + // Reset the background color in case it has changed + gdispImageSetBgColor(&widget(gh)->image, bg); + + // Display the image + gdispImageDraw(&widget(gh)->image, x, y, w, h, dx, dy); +} + + +static const gwinVMT imageVMT = { + "Image", // The class name + sizeof(GImageObject), // The object size + _destroy, // The destroy routine + _redraw, // The redraw routine + 0, // The after-clear routine +}; + +GHandle gwinImageCreate(GImageObject *gobj, GWindowInit *pInit) { + if (!(gobj = (GImageObject *)_gwindowCreate(&gobj->g, pInit, &imageVMT, 0))) + return 0; + + // Ensure the gdispImageIsOpen() gives valid results + gobj->image.type = 0; + + gwinSetVisible((GHandle)gobj, pInit->show); + + return (GHandle)gobj; +} + +bool_t gwinImageOpenMemory(GHandle gh, const void* memory) { + if (gdispImageIsOpen(&widget(gh)->image)) + gdispImageClose(&widget(gh)->image); + + if (!gdispImageSetMemoryReader(&widget(gh)->image, memory)) + return FALSE; + + if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK) + return FALSE; + + if ((gh->flags & GWIN_FLG_VISIBLE)) { + // 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 + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + _redraw(gh); + } + return TRUE; +} + +#if defined(WIN32) || GFX_USE_OS_WIN32 || GFX_USE_OS_POSIX || defined(__DOXYGEN__) +bool_t gwinImageOpenFile(GHandle gh, const char* filename) { + if (gdispImageIsOpen(&widget(gh)->image)) + gdispImageClose(&widget(gh)->image); + + if (!gdispImageSetFileReader(&widget(gh)->image, filename)) + return FALSE; + + if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK) + return FALSE; + + if ((gh->flags & GWIN_FLG_VISIBLE)) { + // 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 + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + _redraw(gh); + } + return TRUE; +} +#endif + +#if GFX_USE_OS_CHIBIOS || defined(__DOXYGEN__) +bool_t gwinImageOpenStream(GHandle gh, void *streamPtr) { + if (gdispImageIsOpen(&widget(gh)->image)) + gdispImageClose(&widget(gh)->image); + + if (!gdispImageSetBaseFileStreamReader(&widget(gh)->image, streamPtr)) + return FALSE; + + if (gdispImageOpen(&widget(gh)->image) != GDISP_IMAGE_ERR_OK) + return FALSE; + + if ((gh->flags & GWIN_FLG_VISIBLE)) { + // 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 + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + _redraw(gh); + } + return TRUE; +} +#endif + +gdispImageError gwinImageCache(GHandle gh) { + return gdispImageCache(&widget(gh)->image); +} + +#endif // GFX_USE_GWIN && GWIN_NEED_IMAGE +/** @} */ diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 72dcce9d..de447f4f 100644 --- a/src/gwin/graph.c +++ b/src/gwin/graph.c @@ -8,18 +8,13 @@ /** * @file src/gwin/graph.c * @brief GWIN sub-system button code. - * - * @defgroup Graph Graph - * @ingroup GWIN - * - * @{ */ #include "gfx.h" -#if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__) +#if GFX_USE_GWIN && GWIN_NEED_GRAPH -#include "gwin/internal.h" +#include "gwin/class_gwin.h" #define GGRAPH_FLG_CONNECTPOINTS (GWIN_FIRST_CONTROL_FLAG<<0) #define GGRAPH_ARROW_SIZE 5 @@ -34,13 +29,21 @@ static const GGraphStyle GGraphDefaultStyle = { GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags }; +static const gwinVMT graphVMT = { + "Graph", // The classname + sizeof(GGraphObject), // The object size + 0, // The destroy routine + 0, // The redraw routine + 0, // The after-clear routine +}; + static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) { if (style->type == GGRAPH_POINT_NONE) return; // Convert to device space. Note the y-axis is inverted. - x += gg->gwin.x + gg->xorigin; - y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y; + x += gg->g.x + gg->xorigin; + y = gg->g.y + gg->g.height - 1 - gg->yorigin - y; if (style->size <= 1) { gdispDrawPixel(x, y, style->color); @@ -73,10 +76,10 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t return; // Convert to device space. Note the y-axis is inverted. - x0 += gg->gwin.x + gg->xorigin; - y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0; - x1 += gg->gwin.x + gg->xorigin; - y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1; + x0 += gg->g.x + gg->xorigin; + y0 = gg->g.y + gg->g.height - 1 - gg->yorigin - y0; + x1 += gg->g.x + gg->xorigin; + y1 = gg->g.y + gg->g.height - 1 - gg->yorigin - y1; if (style->size <= 0) { // Use the driver to draw a solid line @@ -162,42 +165,28 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t } } -GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject)))) +GHandle gwinGraphCreate(GGraphObject *gg, const GWindowInit *pInit) { + if (!(gg = (GGraphObject *)_gwindowCreate(&gg->g, pInit, &graphVMT, 0))) return 0; - gg->gwin.type = GW_GRAPH; gg->xorigin = gg->yorigin = 0; gg->lastx = gg->lasty = 0; - gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle); + gwinGraphSetStyle((GHandle)gg, &GGraphDefaultStyle); + gwinSetVisible((GHandle)gg, pInit->show); return (GHandle)gg; } void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) { #define gg ((GGraphObject *)gh) - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; - gg->style.point.type = pstyle->point.type; - gg->style.point.size = pstyle->point.size; - gg->style.point.color = pstyle->point.color; - gg->style.line.type = pstyle->line.type; - gg->style.line.size = pstyle->line.size; - gg->style.line.color = pstyle->line.color; - gg->style.xaxis.type = pstyle->xaxis.type; - gg->style.xaxis.size = pstyle->xaxis.size; - gg->style.xaxis.color = pstyle->xaxis.color; - gg->style.yaxis.type = pstyle->yaxis.type; - gg->style.yaxis.size = pstyle->yaxis.size; - gg->style.yaxis.color = pstyle->yaxis.color; - gg->style.xgrid.type = pstyle->xgrid.type; - gg->style.xgrid.size = pstyle->xgrid.size; - gg->style.xgrid.color = pstyle->xgrid.color; - gg->style.xgrid.spacing = pstyle->xgrid.spacing; - gg->style.ygrid.type = pstyle->ygrid.type; - gg->style.ygrid.size = pstyle->ygrid.size; - gg->style.ygrid.color = pstyle->ygrid.color; - gg->style.ygrid.spacing = pstyle->ygrid.spacing; + gg->style.point = pstyle->point; + gg->style.line = pstyle->line; + gg->style.xaxis = pstyle->xaxis; + gg->style.yaxis = pstyle->yaxis; + gg->style.xgrid = pstyle->xgrid; + gg->style.ygrid = pstyle->ygrid; gg->style.flags = pstyle->flags; #undef gg @@ -206,7 +195,7 @@ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) { void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) { #define gg ((GGraphObject *)gh) - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; gg->xorigin = x; @@ -219,7 +208,7 @@ void gwinGraphDrawAxis(GHandle gh) { #define gg ((GGraphObject *)gh) coord_t i, xmin, ymin, xmax, ymax; - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; xmin = -gg->xorigin; @@ -277,7 +266,7 @@ void gwinGraphDrawAxis(GHandle gh) { } void gwinGraphStartSet(GHandle gh) { - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS; @@ -286,7 +275,7 @@ void gwinGraphStartSet(GHandle gh) { void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) { #define gg ((GGraphObject *)gh) - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { @@ -314,7 +303,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) { unsigned i; const point *p; - if (gh->type != GW_GRAPH) + if (gh->vmt != &graphVMT) return; // Draw the connecting lines @@ -344,5 +333,3 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) { } #endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */ -/** @} */ - diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c new file mode 100644 index 00000000..8fc6ba77 --- /dev/null +++ b/src/gwin/gwidget.c @@ -0,0 +1,461 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_WIDGET + +#include <string.h> + +#include "gwin/class_gwin.h" + +/* Our listener for events for widgets */ +static GListener gl; + +/* Our default style - a white background theme */ +const GWidgetStyle WhiteWidgetStyle = { + HTML2COLOR(0xFFFFFF), // window background + + // enabled color set + { + HTML2COLOR(0x000000), // text + HTML2COLOR(0x404040), // edge + HTML2COLOR(0xE0E0E0), // fill + HTML2COLOR(0xE0E0E0), // progress - inactive area + }, + + // disabled color set + { + HTML2COLOR(0xC0C0C0), // text + HTML2COLOR(0x808080), // edge + HTML2COLOR(0xE0E0E0), // fill + HTML2COLOR(0xC0E0C0), // progress - active area + }, + + // pressed color set + { + HTML2COLOR(0x404040), // text + HTML2COLOR(0x404040), // edge + HTML2COLOR(0x808080), // fill + HTML2COLOR(0x00E000), // progress - active area + }, +}; + +/* Our black style */ +const GWidgetStyle BlackWidgetStyle = { + HTML2COLOR(0x000000), // window background + + // enabled color set + { + HTML2COLOR(0xC0C0C0), // text + HTML2COLOR(0xC0C0C0), // edge + HTML2COLOR(0x606060), // fill + HTML2COLOR(0x404040), // progress - inactive area + }, + + // disabled color set + { + HTML2COLOR(0x808080), // text + HTML2COLOR(0x404040), // edge + HTML2COLOR(0x404040), // fill + HTML2COLOR(0x004000), // progress - active area + }, + + // pressed color set + { + HTML2COLOR(0xFFFFFF), // text + HTML2COLOR(0xC0C0C0), // edge + HTML2COLOR(0xE0E0E0), // fill + HTML2COLOR(0x008000), // progress - active area + }, +}; + +static const GWidgetStyle * defaultStyle = &BlackWidgetStyle; + +/* We use these everywhere in this file */ +#define gw ((GWidgetObject *)gh) +#define wvmt ((gwidgetVMT *)gh->vmt) + +/* 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; + #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) + uint16_t role; + #endif + (void) param; + + // Process various events + switch (pe->type) { + + #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + case GEVENT_MOUSE: + case GEVENT_TOUCH: + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + continue; + + // Are we captured? + if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { + if ((pme->last_buttons & ~pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) { + gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; + if (wvmt->MouseUp) + wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); + } else if (wvmt->MouseMove) + wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y); + + // We are not captured - look for mouse downs over the widget + } else if ((~pme->last_buttons & pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) + && pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width + && pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) { + gw->g.flags |= GWIN_FLG_MOUSECAPTURE; + if (wvmt->MouseDown) + wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y); + } + } + break; + #endif + + #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + case GEVENT_TOGGLE: + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + continue; + + for(role = 0; role < wvmt->toggleroles; role++) { + if (wvmt->ToggleGet(gw, role) == pte->instance) { + if (pte->on) { + if (wvmt->ToggleOn) + wvmt->ToggleOn(gw, role); + } else { + if (wvmt->ToggleOff) + wvmt->ToggleOff(gw, role); + } + } + } + } + break; + #endif + + #if GFX_USE_GINPUT && GINPUT_NEED_DIAL + case GEVENT_DIAL: + // Cycle through all windows + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + + // check if it a widget that is enabled and visible + if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) != (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_VISIBLE)) + continue; + + for(role = 0; role < wvmt->dialroles; role++) { + if (wvmt->DialGet(gw, role) == pte->instance) { + if (wvmt->DialMove) + wvmt->DialMove(gw, role, pde->value, pde->maxvalue); + } + } + } + break; + #endif + + default: + break; + } + + #undef gh + #undef pme + #undef pte + #undef pde +} + +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + static GHandle FindToggleUser(uint16_t instance) { + #define gh QItem2GWindow(qi) + const gfxQueueASyncItem * qi; + uint16_t role; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget + continue; + + for(role = 0; role < wvmt->toggleroles; role++) { + if (wvmt->ToggleGet(gw, role) == instance) + return gh; + } + } + return 0; + #undef gh + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + static GHandle FindDialUser(uint16_t instance) { + #define gh QItem2GWindow(qi) + const gfxQueueASyncItem * qi; + uint16_t role; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + if (!(gh->flags & GWIN_FLG_WIDGET)) // check if it a widget + continue; + + for(role = 0; role < wvmt->dialroles; role++) { + if (wvmt->DialGet(gw, role) == instance) + return gh; + } + } + return 0; + #undef gh + } +#endif + +void _gwidgetInit(void) { + geventListenerInit(&gl); + geventRegisterCallback(&gl, gwidgetEvent, 0); +} + +GHandle _gwidgetCreate(GWidgetObject *pgw, const GWidgetInit *pInit, const gwidgetVMT *vmt) { + if (!(pgw = (GWidgetObject *)_gwindowCreate(&pgw->g, &pInit->g, &vmt->g, GWIN_FLG_WIDGET|GWIN_FLG_ENABLED))) + return 0; + + pgw->text = pInit->text ? pInit->text : ""; + pgw->fnDraw = pInit->customDraw ? pInit->customDraw : vmt->DefaultDraw; + pgw->fnParam = pInit->customParam; + pgw->pstyle = pInit->customStyle ? pInit->customStyle : defaultStyle; + + return &pgw->g; +} + +void _gwidgetDestroy(GHandle gh) { + #if GFX_USE_GINPUT && (GINPUT_NEED_TOGGLE || GINPUT_NEED_DIAL) + uint16_t role, instance; + #endif + + // Deallocate the text (if necessary) + if ((gh->flags & GWIN_FLG_ALLOCTXT)) { + gh->flags &= ~GWIN_FLG_ALLOCTXT; + gfxFree((void *)gw->text); + } + + #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + // Detach any toggles from this object + for(role = 0; role < wvmt->toggleroles; role++) { + instance = wvmt->ToggleGet(gw, role); + if (instance != GWIDGET_NO_INSTANCE) { + wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE); + if (!FindToggleUser(instance)) + geventDetachSource(&gl, ginputGetToggle(instance)); + } + } + #endif + + #if GFX_USE_GINPUT && GINPUT_NEED_DIAL + // Detach any dials from this object + for(role = 0; role < wvmt->dialroles; role++) { + instance = wvmt->DialGet(gw, role); + if (instance != GWIDGET_NO_INSTANCE) { + wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE); + if (!FindDialUser(instance)) + geventDetachSource(&gl, ginputGetDial(instance)); + } + } + #endif + + // Remove any listeners on this object. + geventDetachSourceListeners((GSourceHandle)gh); +} + +void _gwidgetRedraw(GHandle gh) { + if (!(gh->flags & GWIN_FLG_VISIBLE)) + return; + + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + + gw->fnDraw(gw, gw->fnParam); +} + +void gwinSetDefaultStyle(const GWidgetStyle *pstyle, bool_t updateAll) { + if (!pstyle) + pstyle = &BlackWidgetStyle; + + if (updateAll) { + const gfxQueueASyncItem * qi; + GHandle gh; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + gh = QItem2GWindow(qi); + if ((gh->flags & GWIN_FLG_WIDGET) && ((GWidgetObject *)gh)->pstyle == defaultStyle) + gwinSetStyle(gh, pstyle); + } + } + gwinSetDefaultBgColor(pstyle->background); + defaultStyle = pstyle; +} + +/** + * @brief Get the current default style. + * + * @api + */ +const GWidgetStyle *gwinGetDefaultStyle(void) { + return defaultStyle; +} + + +void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + // Dispose of the old string + if ((gh->flags & GWIN_FLG_ALLOCTXT)) { + gh->flags &= ~GWIN_FLG_ALLOCTXT; + if (gw->text) { + gfxFree((void *)gw->text); + gw->text = ""; + } + } + + // Alloc the new text if required + if (!text || !*text) + gw->text = ""; + else if (useAlloc) { + char *str; + + if ((str = (char *)gfxAlloc(strlen(text)+1))) { + gh->flags |= GWIN_FLG_ALLOCTXT; + strcpy(str, text); + } + gw->text = (const char *)str; + } else + gw->text = text; + _gwidgetRedraw(gh); +} + +const char *gwinGetText(GHandle gh) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return 0; + + return gw->text; +} + +void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + gw->pstyle = pstyle ? pstyle : defaultStyle; + gh->bgcolor = pstyle->background; + gh->color = pstyle->enabled.text; + _gwidgetRedraw(gh); +} + +const GWidgetStyle *gwinGetStyle(GHandle gh) { + return gw->pstyle; +} + +void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + gw->fnDraw = fn ? fn : wvmt->DefaultDraw; + gw->fnParam = param; + _gwidgetRedraw(gh); +} + +bool_t gwinAttachListener(GListener *pl) { + return geventAttachSource(pl, GWIDGET_SOURCE, 0); +} + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + bool_t gwinAttachMouse(uint16_t instance) { + GSourceHandle gsh; + + if (!(gsh = ginputGetMouse(instance))) + return FALSE; + + return geventAttachSource(&gl, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { + GSourceHandle gsh; + uint16_t oi; + + // Is this a widget + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + // Is the role valid + if (role >= wvmt->toggleroles) + return FALSE; + + // Is this a valid device + if (!(gsh = ginputGetToggle(instance))) + return FALSE; + + // Is this already done? + oi = wvmt->ToggleGet(gw, role); + if (instance == oi) + return TRUE; + + // Remove the old instance + if (oi != GWIDGET_NO_INSTANCE) { + wvmt->ToggleAssign(gw, role, GWIDGET_NO_INSTANCE); + if (!FindToggleUser(oi)) + geventDetachSource(&gl, ginputGetToggle(oi)); + } + + // Assign the new + wvmt->ToggleAssign(gw, role, instance); + return geventAttachSource(&gl, gsh, GLISTEN_TOGGLE_ON|GLISTEN_TOGGLE_OFF); + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) { + GSourceHandle gsh; + uint16_t oi; + + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + // Is the role valid + if (role >= wvmt->dialroles) + return FALSE; + + // Is this a valid device + if (!(gsh = ginputGetDial(instance))) + return FALSE; + + // Is this already done? + oi = wvmt->DialGet(gw, role); + if (instance == oi) + return TRUE; + + // Remove the old instance + if (oi != GWIDGET_NO_INSTANCE) { + wvmt->DialAssign(gw, role, GWIDGET_NO_INSTANCE); + if (!FindDialUser(oi)) + geventDetachSource(&gl, ginputGetDial(oi)); + } + + // Assign the new + wvmt->DialAssign(gw, role, instance); + return geventAttachSource(&gl, gsh, 0); + } +#endif + +#endif /* GFX_USE_GWIN && GWIN_NEED_WIDGET */ +/** @} */ diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index 2f9d2dfd..e5997bc8 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -9,127 +9,278 @@ #if GFX_USE_GWIN -#include "gwin/internal.h" +#include "gwin/class_gwin.h" + +// Needed if there is no window manager +#define MIN_WIN_WIDTH 1 +#define MIN_WIN_HEIGHT 1 + +/*----------------------------------------------- + * Data + *-----------------------------------------------*/ + +static const gwinVMT basegwinVMT = { + "GWIN", // The classname + sizeof(GWindowObject), // The object size + 0, // The destroy routine + 0, // The redraw routine + 0, // The after-clear routine +}; + +static color_t defaultFgColor = White; +static color_t defaultBgColor = Black; +#if GDISP_NEED_TEXT + static font_t defaultFont; +#endif + +/*----------------------------------------------- + * Helper Routines + *-----------------------------------------------*/ + +#if !GWIN_NEED_WINDOWMANAGER + static void _gwm_vis(GHandle gh) { + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } else + gwinClear(gh); + } + static void _gwm_redim(GHandle gh, coord_t x, coord_t y, coord_t width, coord_t height) { + gh->x = x; gh->y = y; + 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 + if ((gh->flags & GWIN_FLG_VISIBLE)) { + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } + } + } +#endif + +/*----------------------------------------------- + * Class Routines + *-----------------------------------------------*/ + +void _gwinInit(void) { + #if GWIN_NEED_WIDGET + extern void _gwidgetInit(void); + + _gwidgetInit(); + #endif + #if GWIN_NEED_WINDOWMANAGER + extern void _gwmInit(void); + + _gwmInit(); + #endif +} // Internal routine for use by GWIN components only -// Initialise a window creating it dynamicly if required. -GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size) { - coord_t w, h; - - // Check the window size against the screen size - w = gdispGetWidth(); - h = gdispGetHeight(); - if (x < 0) { width += x; x = 0; } - if (y < 0) { height += y; y = 0; } - if (x >= w || y >= h) return 0; - if (x+width > w) width = w - x; - if (y+height > h) height = h - y; - +// Initialise a window creating it dynamically if required. +GHandle _gwindowCreate(GWindowObject *pgw, const GWindowInit *pInit, const gwinVMT *vmt, uint16_t flags) { // Allocate the structure if necessary - if (!gw) { - if (!(gw = (GWindowObject *)gfxAlloc(size))) + if (!pgw) { + if (!(pgw = (GWindowObject *)gfxAlloc(vmt->size))) return 0; - gw->flags = GWIN_FLG_DYNAMIC; + pgw->flags = flags|GWIN_FLG_DYNAMIC; } else - gw->flags = 0; + pgw->flags = flags; - // Initialise all basic fields (except the type) - gw->x = x; - gw->y = y; - gw->width = width; - gw->height = height; - gw->color = White; - gw->bgcolor = Black; + // Initialise all basic fields + pgw->vmt = vmt; + pgw->color = defaultFgColor; + pgw->bgcolor = defaultBgColor; #if GDISP_NEED_TEXT - gw->font = 0; + pgw->font = defaultFont; #endif - return (GHandle)gw; -} -GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gw = (GWindowObject *)_gwinInit((GWindowObject *)gw, x, y, width, height, sizeof(GWindowObject)))) +#if GWIN_NEED_WINDOWMANAGER + if (!_GWINwm->vmt->Add(pgw, pInit)) { + if ((pgw->flags & GWIN_FLG_DYNAMIC)) + gfxFree(pgw); return 0; - gw->type = GW_WINDOW; - return (GHandle)gw; + } +#else + _gwm_redim(pgw, pInit->x, pInit->y, pInit->width, pInit->height); +#endif + + return (GHandle)pgw; } -void gwinSetEnabled(GHandle gh, bool_t enabled) { - (void)gh; - (void)enabled; +/*----------------------------------------------- + * Routines that affect all windows + *-----------------------------------------------*/ + +void gwinSetDefaultColor(color_t clr) { + defaultFgColor = clr; } -void gwinDestroyWindow(GHandle gh) { - // Clean up any type specific dynamic memory allocations - switch(gh->type) { -#if GWIN_NEED_BUTTON - case GW_BUTTON: - if ((gh->flags & GBTN_FLG_ALLOCTXT)) { - gh->flags &= ~GBTN_FLG_ALLOCTXT; // To be sure, to be sure - gfxFree((void *)((GButtonObject *)gh)->txt); - } - geventDetachSource(&((GButtonObject *)gh)->listener, 0); - geventDetachSourceListeners((GSourceHandle)gh); - break; -#endif -#if GWIN_NEED_SLIDER - case GW_SLIDER: - geventDetachSource(&((GSliderObject *)gh)->listener, 0); - geventDetachSourceListeners((GSourceHandle)gh); - break; -#endif - default: - break; +color_t gwinGetDefaultColor(void) { + return defaultFgColor; +} + +void gwinSetDefaultBgColor(color_t bgclr) { + defaultBgColor = bgclr; +} + +color_t gwinGetDefaultBgColor(void) { + return defaultBgColor; +} + +#if GDISP_NEED_TEXT + void gwinSetDefaultFont(font_t font) { + defaultFont = font; + } + + font_t gwinGetDefaultFont(void) { + return defaultFont; } +#endif + +/*----------------------------------------------- + * The GWindow Routines + *-----------------------------------------------*/ + +GHandle gwinWindowCreate(GWindowObject *pgw, const GWindowInit *pInit) { + if (!(pgw = _gwindowCreate(pgw, pInit, &basegwinVMT, 0))) + return 0; + gwinSetVisible(pgw, pInit->show); + return pgw; +} + +void gwinDestroy(GHandle gh) { + // Remove from the window manager + #if GWIN_NEED_WINDOWMANAGER + _GWINwm->vmt->Delete(gh); + #endif + + // Class destroy routine + if (gh->vmt->Destroy) + gh->vmt->Destroy(gh); // Clean up the structure - if (gh->flags & GWIN_FLG_DYNAMIC) { - gh->flags = 0; // To be sure, to be sure + if (gh->flags & GWIN_FLG_DYNAMIC) gfxFree((void *)gh); + + gh->flags = 0; // To be sure, to be sure +} + +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; + #if GWIN_NEED_WINDOWMANAGER + _GWINwm->vmt->Visible(gh); + #else + _gwm_vis(gh); + #endif + } + } else { + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~GWIN_FLG_VISIBLE; + #if GWIN_NEED_WINDOWMANAGER + _GWINwm->vmt->Visible(gh); + #endif + } + } +} + +bool_t gwinGetVisible(GHandle gh) { + return (gh->flags & GWIN_FLG_VISIBLE) ? TRUE : FALSE; +} + +void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (enabled) { + if (!(gh->flags & GWIN_FLG_ENABLED)) { + gh->flags |= GWIN_FLG_ENABLED; + if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } + } + } else { + if ((gh->flags & GWIN_FLG_ENABLED)) { + gh->flags &= ~GWIN_FLG_ENABLED; + if ((gh->flags & GWIN_FLG_VISIBLE) && gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } + } } } -void gwinDraw(GHandle gh) { - switch(gh->type) { - #if GWIN_NEED_BUTTON - case GW_BUTTON: - gwinButtonDraw(gh); - break; +bool_t gwinGetEnabled(GHandle gh) { + return (gh->flags & GWIN_FLG_ENABLED) ? TRUE : FALSE; +} + +void gwinMove(GHandle gh, coord_t x, coord_t y) { + #if GWIN_NEED_WINDOWMANAGER + _GWINwm->vmt->Redim(gh, x, y, gh->width, gh->height); + #else + _gwm_redim(gh, x, y, gh->width, gh->height); #endif - #if GWIN_NEED_SLIDER - case GW_SLIDER: - gwinSliderDraw(gh); - break; +} + +void gwinResize(GHandle gh, coord_t width, coord_t height) { + #if GWIN_NEED_WINDOWMANAGER + _GWINwm->vmt->Redim(gh, gh->x, gh->y, width, height); + #else + _gwm_redim(gh, gh->x, gh->y, width, height); + #endif +} + +void gwinRedraw(GHandle gh) { + #if GWIN_NEED_WINDOWMANAGER + gwinRaise(gh); + #else + if ((gh->flags & GWIN_FLG_VISIBLE)) + _gwm_vis(gh); #endif - } } #if GDISP_NEED_TEXT void gwinSetFont(GHandle gh, font_t font) { gh->font = font; - #if GWIN_NEED_CONSOLE - if (font && gh->type == GW_CONSOLE) { - ((GConsoleObject *)gh)->fy = gdispGetFontMetric(font, fontHeight); - ((GConsoleObject *)gh)->fp = gdispGetFontMetric(font, fontCharPadding); - } - #endif } #endif void gwinClear(GHandle gh) { + if (!((gh->flags & GWIN_FLG_VISIBLE))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); - - #if GWIN_NEED_CONSOLE - if (gh->type == GW_CONSOLE) { - ((GConsoleObject *)gh)->cx = 0; - ((GConsoleObject *)gh)->cy = 0; - } - #endif + if (gh->vmt->AfterClear) + gh->vmt->AfterClear(gh); } void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { + if (!((gh->flags & GWIN_FLG_VISIBLE))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -137,6 +288,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -144,6 +298,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -151,6 +308,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -158,6 +318,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -166,6 +329,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -173,6 +339,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -182,6 +351,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -189,6 +361,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -198,6 +373,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -205,6 +383,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -214,6 +395,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -223,7 +407,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -231,7 +417,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -239,7 +427,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -247,7 +437,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -255,7 +447,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -263,7 +457,9 @@ 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->font) return; + if (!((gh->flags & GWIN_FLG_VISIBLE)) || !gh->font) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -273,6 +469,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -280,6 +479,9 @@ 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))) + return; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif @@ -288,7 +490,10 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #endif #if GDISP_NEED_IMAGE - gdispImageError gwinImageDraw(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy) { + 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))) + return GDISP_IMAGE_ERR_OK; + #if GDISP_NEED_CLIP gdispSetClip(gh->x, gh->y, gh->width, gh->height); #endif diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk index be6301c6..92b10b7b 100644 --- a/src/gwin/gwin.mk +++ b/src/gwin/gwin.mk @@ -1,7 +1,12 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ + $(GFXLIB)/src/gwin/gwidget.c \ + $(GFXLIB)/src/gwin/gwm.c \ $(GFXLIB)/src/gwin/console.c \ + $(GFXLIB)/src/gwin/graph.c \ $(GFXLIB)/src/gwin/button.c \ $(GFXLIB)/src/gwin/slider.c \ - $(GFXLIB)/src/gwin/graph.c \ $(GFXLIB)/src/gwin/checkbox.c \ - + $(GFXLIB)/src/gwin/gimage.c \ + $(GFXLIB)/src/gwin/label.c \ + $(GFXLIB)/src/gwin/radio.c \ + diff --git a/src/gwin/gwm.c b/src/gwin/gwm.c new file mode 100644 index 00000000..f9f56838 --- /dev/null +++ b/src/gwin/gwm.c @@ -0,0 +1,201 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +#include "gfx.h" + +// Used by the NULL window manager +#define MIN_WIN_WIDTH 3 +#define MIN_WIN_HEIGHT 3 + +/*----------------------------------------------- + * The default window manager (GNullWindowManager) + *-----------------------------------------------*/ + +#if GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER + +#include "gwin/class_gwin.h" + +/*----------------------------------------------- + * Data + *-----------------------------------------------*/ + +static void WM_Init(void); +static void WM_DeInit(void); +static bool_t WM_Add(GHandle gh, const GWindowInit *pInit); +static void WM_Delete(GHandle gh); +static void WM_Visible(GHandle gh); +static void WM_Redim(GHandle gh, coord_t x, coord_t y, coord_t w, coord_t h); +static void WM_Raise(GHandle gh); +static void WM_MinMax(GHandle gh, GWindowMinMax minmax); + +static const gwmVMT GNullWindowManagerVMT = { + WM_Init, + WM_DeInit, + WM_Add, + WM_Delete, + WM_Visible, + WM_Redim, + WM_Raise, + WM_MinMax, +}; + +static const GWindowManager GNullWindowManager = { + &GNullWindowManagerVMT, +}; + +gfxQueueASync _GWINList; +GWindowManager * _GWINwm; + +/*----------------------------------------------- + * Window Routines + *-----------------------------------------------*/ + +void _gwmInit(void) { + gfxQueueASyncInit(&_GWINList); + _GWINwm = (GWindowManager *)&GNullWindowManager; + _GWINwm->vmt->Init(); +} + +void gwinSetWindowManager(struct GWindowManager *gwm) { + if (!gwm) + gwm = (GWindowManager *)&GNullWindowManager; + if (_GWINwm != gwm) { + _GWINwm->vmt->DeInit(); + _GWINwm = gwm; + _GWINwm->vmt->Init(); + } +} + +void gwinSetMinMax(GHandle gh, GWindowMinMax minmax) { + _GWINwm->vmt->MinMax(gh, minmax); +} + +void gwinRaise(GHandle gh) { + _GWINwm->vmt->Raise(gh); +} + +GWindowMinMax gwinGetMinMax(GHandle gh) { + if (gh->flags & GWIN_FLG_MINIMIZED) + return GWIN_MINIMIZE; + if (gh->flags & GWIN_FLG_MAXIMIZED) + return GWIN_MAXIMIZE; + return GWIN_NORMAL; +} + +/*----------------------------------------------- + * Window Manager Routines + *-----------------------------------------------*/ + +static void WM_Init(void) { + // We don't need to do anything here. + // A full window manager would move the windows around, add borders etc + + // clear the screen + // cycle through the windows already defined displaying them + // or cut all the window areas out of the screen and clear the remainder +} + +static void WM_DeInit(void) { + // We don't need to do anything here. + // A full window manager would remove any borders etc +} + +static bool_t WM_Add(GHandle gh, const GWindowInit *pInit) { + // Note the window will not be marked as visible yet + + // Put it on the queue + gfxQueueASyncPut(&_GWINList, &gh->wmq); + + // Make sure the size is valid + WM_Redim(gh, pInit->x, pInit->y, pInit->width, pInit->height); + return TRUE; +} + +static void WM_Delete(GHandle gh) { + // Make the window invisible and clear the area underneath + if ((gh->flags & GWIN_FLG_VISIBLE)) { + gh->flags &= ~GWIN_FLG_VISIBLE; + gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + } + + // Remove it from the queue + gfxQueueASyncRemove(&_GWINList, &gh->wmq); +} + +static void WM_Visible(GHandle gh) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + if ((gh->flags & GWIN_FLG_VISIBLE)) { + if (gh->vmt->Redraw) + gh->vmt->Redraw(gh); + else + gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); + // A real window manager would also redraw the borders here + } else + gdispFillArea(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 > gdispGetWidth()-MIN_WIN_WIDTH) x = gdispGetWidth()-MIN_WIN_WIDTH; + if (y > gdispGetHeight()-MIN_WIN_HEIGHT) y = gdispGetHeight()-MIN_WIN_HEIGHT; + if (w < MIN_WIN_WIDTH) { w = MIN_WIN_WIDTH; } + if (h < MIN_WIN_HEIGHT) { h = MIN_WIN_HEIGHT; } + if (x+w > gdispGetWidth()) w = gdispGetWidth() - x; + if (y+h > gdispGetHeight()) h = gdispGetHeight() - y; + + // If there has been no resize just exit + if (gh->x == x && gh->y == y && gh->width == w && gh->height == h) + return; + + // Clear the old area + if ((gh->flags & GWIN_FLG_VISIBLE)) + gdispFillArea(gh->x, gh->y, gh->width, gh->height, gwinGetDefaultBgColor()); + + // Set the new size + gh->x = x; gh->y = y; + gh->width = w; gh->height = h; + + // Redraw the window (if possible) + if ((gh->flags & GWIN_FLG_VISIBLE)) { + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } + } +} + +static void WM_MinMax(GHandle gh, GWindowMinMax minmax) { + (void)gh; (void) minmax; + // We don't support minimising, maximising or restoring +} + +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); + + // Redraw the window + if ((gh->flags & GWIN_FLG_VISIBLE)) { + if (gh->vmt->Redraw) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + gh->vmt->Redraw(gh); + } + } +} + +#endif /* GFX_USE_GWIN && GWIN_NEED_WINDOWMANAGER */ +/** @} */ diff --git a/src/gwin/label.c b/src/gwin/label.c new file mode 100644 index 00000000..71ed18eb --- /dev/null +++ b/src/gwin/label.c @@ -0,0 +1,118 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +/** + * @file include/gwin/label.h + * @brief GWIN label widget header file. + * + * @defgroup Label Label + * @ingroup GWIN + * + * @{ + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_LABEL + +#include "gwin/class_gwin.h" + +#define GLABEL_FLG_WAUTO (GWIN_FIRST_CONTROL_FLAG<<0) +#define GLABEL_FLG_HAUTO (GWIN_FIRST_CONTROL_FLAG<<1) + +// Simple: single line with no wrapping +static coord_t getwidth(const char *text, font_t font, coord_t maxwidth) { + (void) maxwidth; + return gdispGetStringWidth(text, font)+2; // Allow one pixel of padding on each side +} + +// Simple: single line with no wrapping +static coord_t getheight(const char *text, font_t font, coord_t maxwidth) { + (void) text; + (void) maxwidth; + + return gdispGetFontMetric(font, fontHeight); +} + +static void gwinLabelDefaultDraw(GWidgetObject *gw, void *param) { + coord_t w, h; + (void) param; + + w = (gw->g.flags & GLABEL_FLG_WAUTO) ? getwidth(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.width; + h = (gw->g.flags & GLABEL_FLG_HAUTO) ? getheight(gw->text, gw->g.font, gdispGetWidth() - gw->g.x) : gw->g.height; + + if (gw->g.width != w || gw->g.height != h) { + gwinResize(&gw->g, w, h); + return; + } + + gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, + (gw->g.flags & GWIN_FLG_ENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text, gw->pstyle->background, + justifyLeft); +} + +static const gwidgetVMT labelVMT = { + { + "Label", // The class name + sizeof(GLabelObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinLabelDefaultDraw, // default drawing routine + #if GINPUT_NEED_MOUSE + { + 0, // Process mose down events (NOT USED) + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, // No toggle role + 0, // Assign Toggles (NOT USED) + 0, // Get Toggles (NOT USED) + 0, // Process toggle off event (NOT USED) + 0, // Process toggle on event (NOT USED) + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Procees dial move events (NOT USED) + }, + #endif +}; + +GHandle gwinLabelCreate(GLabelObject *widget, GWidgetInit *pInit) { + uint16_t flags = 0; + + // auto assign width + if (pInit->g.width <= 0) { + flags |= GLABEL_FLG_WAUTO; + pInit->g.width = getwidth(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x); + } + + // auto assign height + if (pInit->g.height <= 0) { + flags |= GLABEL_FLG_HAUTO; + pInit->g.height = getheight(pInit->text, gwinGetDefaultFont(), gdispGetWidth() - pInit->g.x); + } + + if (!(widget = (GLabelObject *)_gwidgetCreate(&widget->w, pInit, &labelVMT))) + return 0; + + widget->w.g.flags |= flags; + + gwinSetVisible(&widget->w.g, pInit->g.show); + return (GHandle)widget; +} + +#endif // GFX_USE_GWIN && GFX_NEED_LABEL + diff --git a/src/gwin/radio.c b/src/gwin/radio.c new file mode 100644 index 00000000..26ff0b83 --- /dev/null +++ b/src/gwin/radio.c @@ -0,0 +1,229 @@ +/* + * 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://chibios-gfx.com/license.html + */ + +/** + * @file src/gwin/radio.c + * @brief GWIN sub-system radio button code. + * + * @defgroup RadioButton RadioButton + * @ingroup GWIN + * + * @{ + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_RADIO + +#include "gwin/class_gwin.h" + +// Our pressed state +#define GRADIO_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0) + +// Send the button event +static void SendRadioEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pbe ((GEventGWinRadio *)pe) + + // Trigger a GWIN Button Event + psl = 0; + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { + if (!(pe = geventGetEventBuffer(psl))) + continue; + pbe->type = GEVENT_GWIN_RADIO; + pbe->radio = (GHandle)gw; + pbe->group = ((GRadioObject *)gw)->group; + geventSendEvent(psl); + } + + #undef pbe +} + +#if GINPUT_NEED_MOUSE + // A mouse down has occurred over the button + static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + (void) x; (void) y; + + gwinRadioPress((GHandle)gw); + } +#endif + +#if GINPUT_NEED_TOGGLE + // A toggle on has occurred + static void ToggleOn(GWidgetObject *gw, uint16_t role) { + (void) role; + + gwinRadioPress((GHandle)gw); + } + + static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GRadioObject *)gw)->toggle = instance; + } + + static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GRadioObject *)gw)->toggle; + } +#endif + +// The radio button VMT table +static const gwidgetVMT radioVMT = { + { + "Radio", // The classname + sizeof(GRadioObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinRadioDraw_Radio, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + MouseDown, // Process mouse down events + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 1, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Process dial move events (NOT USED) + }, + #endif +}; + +GHandle gwinRadioCreate(GRadioObject *gw, const GWidgetInit *pInit, uint16_t group) { + if (!(gw = (GRadioObject *)_gwidgetCreate(&gw->w, pInit, &radioVMT))) + return 0; + + #if GINPUT_NEED_TOGGLE + gw->toggle = GWIDGET_NO_INSTANCE; + #endif + gw->group = group; + gwinSetVisible((GHandle)gw, pInit->g.show); + return (GHandle)gw; +} + +void gwinRadioPress(GHandle gh) { + GHandle gx; + + if (gh->vmt != (gwinVMT *)&radioVMT || (gh->flags & GRADIO_FLG_PRESSED)) + return; + + if ((gx = gwinRadioGetActive(((GRadioObject *)gh)->group))) { + gx->flags &= ~GRADIO_FLG_PRESSED; + _gwidgetRedraw(gx); + } + gh->flags |= GRADIO_FLG_PRESSED; + _gwidgetRedraw(gh); + SendRadioEvent((GWidgetObject *)gh); +} + +bool_t gwinRadioIsPressed(GHandle gh) { + if (gh->vmt != (gwinVMT *)&radioVMT) + return FALSE; + + return (gh->flags & GRADIO_FLG_PRESSED) ? TRUE : FALSE; +} + +GHandle gwinRadioGetActive(uint16_t group) { + const gfxQueueASyncItem * qi; + GHandle gh; + + for(qi = gfxQueueASyncPeek(&_GWINList); qi; qi = gfxQueueASyncNext(qi)) { + gh = QItem2GWindow(qi); + if (gh->vmt == (gwinVMT *)&radioVMT && ((GRadioObject *)gh)->group == group && (gh->flags & GRADIO_FLG_PRESSED)) + return gh; + } + return 0; +} + +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ + +static const GColorSet *getDrawColors(GWidgetObject *gw) { + if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &gw->pstyle->disabled; + if ((gw->g.flags & GRADIO_FLG_PRESSED)) return &gw->pstyle->pressed; + return &gw->pstyle->enabled; +} + +void gwinRadioDraw_Radio(GWidgetObject *gw, void *param) { + #define gcw ((GRadioObject *)gw) + coord_t ld, df; + const GColorSet * pcol; + (void) param; + + if (gw->g.vmt != (gwinVMT *)&radioVMT) return; + pcol = getDrawColors(gw); + + ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; + + #if GDISP_NEED_CIRCLE + df = (ld-1)/2; + gdispFillArea(gw->g.x, gw->g.y, ld, ld, gw->pstyle->background); + gdispDrawCircle(gw->g.x+df, gw->g.y+df, df, pcol->edge); + + if (gw->g.flags & GRADIO_FLG_PRESSED) + gdispFillCircle(gw->g.x+df, gw->g.y+df, df <= 2 ? 1 : (df-2), pcol->fill); + #else + gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gw->pstyle->background); + gdispDrawBox(gw->g.x, gw->g.y, ld, ld, pcol->edge); + + df = ld < 4 ? 1 : 2; + if (gw->g.flags & GRADIO_FLG_PRESSED) + gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, pcol->fill); + #endif + + gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->text, gw->g.font, pcol->text, gw->pstyle->background, justifyLeft); + #undef gcw +} + +void gwinRadioDraw_Button(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + + if (gw->g.vmt != (gwinVMT *)&radioVMT) return; + pcol = getDrawColors(gw); + + gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); +} + +void gwinRadioDraw_Tab(GWidgetObject *gw, void *param) { + const GColorSet * pcol; + (void) param; + + if (gw->g.vmt != (gwinVMT *)&radioVMT) return; + pcol = getDrawColors(gw); + + if ((gw->g.flags & GRADIO_FLG_PRESSED)) { + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); + gdispFillStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + } else { + gdispFillStringBox(gw->g.x, gw->g.y, gw->g.width-1, gw->g.height-1, gw->text, gw->g.font, pcol->text, pcol->fill, justifyCenter); + gdispDrawLine(gw->g.x+gw->g.width-1, gw->g.y, gw->g.x+gw->g.width-1, gw->g.y+gw->g.height-1, pcol->edge); + gdispDrawLine(gw->g.x, gw->g.y+gw->g.height-1, gw->g.x+gw->g.width-2, gw->g.y+gw->g.height-1, pcol->edge); + } +} + +#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ +/** @} */ + diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 01df189d..4d9c3510 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -19,140 +19,232 @@ #if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__) -#include "gwin/internal.h" +#include "gwin/class_gwin.h" #ifndef GWIN_SLIDER_DEAD_BAND #define GWIN_SLIDER_DEAD_BAND 5 #endif -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - static void trackSliderDraw(GHandle gh, coord_t x, coord_t y); +#ifndef GWIN_SLIDER_TOGGLE_INC + #define GWIN_SLIDER_TOGGLE_INC 20 // How many toggles to go from minimum to maximum #endif -static const GSliderDrawStyle GSliderDefaultStyle = { - HTML2COLOR(0x404040), // color_edge; - HTML2COLOR(0x000000), // color_thumb; - HTML2COLOR(0x00E000), // color_active; - HTML2COLOR(0xE0E0E0), // color_inactive; -}; +// Send the slider event +static void SendSliderEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pse ((GEventGWinSlider *)pe) -// Process an event callback -static void gwinSliderCallback(void *param, GEvent *pe) { - GSourceListener *psl; - #define gh ((GHandle)param) - #define gsw ((GSliderObject *)param) - #define gsh ((GSourceHandle)param) - #define pme ((GEventMouse *)pe) - #define pde ((GEventDial *)pe) - #define pse ((GEventGWinSlider *)pe) - - switch (pe->type) { - #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - case GEVENT_MOUSE: - case GEVENT_TOUCH: - // If not tracking we only only interested in a mouse down over the slider - if (!gsw->tracking) { - if ((pme->meta & GMETA_MOUSE_DOWN) - && pme->x >= gh->x && pme->x < gh->x + gh->width - && pme->y >= gh->y && pme->y < gh->y + gh->height) { - gsw->tracking = TRUE; - trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y); - } + // Trigger a GWIN Button Event + psl = 0; + while ((psl = geventGetSourceListener(GWIDGET_SOURCE, psl))) { + if (!(pe = geventGetEventBuffer(psl))) + continue; + pse->type = GEVENT_GWIN_SLIDER; + pse->slider = (GHandle)gw; + pse->position = ((GSliderObject *)gw)->pos; + geventSendEvent(psl); + } + + #undef pse +} + +// Reset the display position back to the value predicted by the saved slider position +static void ResetDisplayPos(GSliderObject *gsw) { + if (gsw->w.g.width < gsw->w.g.height) + gsw->dpos = gsw->w.g.height-1-((gsw->w.g.height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min); + else + gsw->dpos = ((gsw->w.g.width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min); +} + +#if GINPUT_NEED_MOUSE + // A mouse up event + static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y) { + #define gsw ((GSliderObject *)gw) + #define gh ((GHandle)gw) + + #if GWIN_BUTTON_LAZY_RELEASE + // Clip to the slider + if (x < 0) x = 0; + else if (x >= gh->width) x = gh->width-1; + if (y < 0) y = 0; + else if (y >= gh->height) x = gh->height-1; + #else + // Are we over the slider? + if (x < 0 || x >= gh->width || y < 0 || y >= gh->height) { + // No - restore the slider + ResetDisplayPos(gsw); + _gwidgetRedraw(gh); return; } + #endif - // We are tracking the mouse - - // Test for button up - if ((pme->meta & GMETA_MOUSE_UP)) { - gsw->tracking = FALSE; - - #if !GWIN_BUTTON_LAZY_RELEASE - // Are we over the slider? - if (pme->x < gh->x || pme->x >= gh->x + gh->width - || pme->y < gh->y || pme->y >= gh->y + gh->height) { - // No - restore the slider - gwinSliderDraw(gh); - return; - } - #endif - - // Set the new position - if (gh->width < gh->height) - gwinSetSliderPosition(gh, - (uint16_t)((uint32_t)(gh->height-1-pme->y+gh->y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min)); - else - gwinSetSliderPosition(gh, - (uint16_t)((uint32_t)(pme->x-gh->x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min)); - - // Update the display - gwinSliderDraw(gh); - - // Generate the event - break; - } + // Set the new position + if (gh->width < gh->height) { + if (y > gh->height-GWIN_SLIDER_DEAD_BAND) + gsw->pos = gsw->min; + else if (y < GWIN_SLIDER_DEAD_BAND) + gsw->pos = gsw->max; + else + gsw->pos = (uint16_t)((int32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); + } else { + if (x > gh->width-GWIN_SLIDER_DEAD_BAND) + gsw->pos = gsw->max; + else if (x < GWIN_SLIDER_DEAD_BAND) + gsw->pos = gsw->min; + else + gsw->pos = (uint16_t)((int32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); + } + + ResetDisplayPos(gsw); + _gwidgetRedraw(gh); + + // Generate the event + SendSliderEvent(gw); + #undef gh + #undef gsw + } - // If mouse down - track movement - if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y); + // A mouse move (or mouse down) event + static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y) { + #define gsw ((GSliderObject *)gw) + + // Determine the temporary display position (with range checking) + if (gw->g.width < gw->g.height) { + if (y < 0) + gsw->dpos = 0; + else if (y >= gw->g.height) + gsw->dpos = gw->g.height-1; + else + gsw->dpos = y; + } else { + if (x < 0) + gsw->dpos = 0; + else if (x >= gw->g.width) + gsw->dpos = gw->g.width-1; + else + gsw->dpos = x; + } + + // Update the display + _gwidgetRedraw(&gw->g); + #undef gsw + } +#endif - return; - #endif - #if GFX_USE_GINPUT && GINPUT_NEED_DIAL - case GEVENT_DIAL: - // Set the new position - gwinSetSliderPosition(gh, (uint16_t)((uint32_t)pde->value*(gsw->max-gsw->min)/ginputGetDialRange(pde->instance) + gsw->min)); +#if GINPUT_NEED_TOGGLE + // A toggle on has occurred + static void ToggleOn(GWidgetObject *gw, uint16_t role) { + #define gsw ((GSliderObject *)gw) + + if (role) { + gwinSliderSetPosition((GHandle)gw, gsw->pos+(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gw); + } else { + gwinSliderSetPosition((GHandle)gw, gsw->pos-(gsw->max-gsw->min)/GWIN_SLIDER_TOGGLE_INC); + SendSliderEvent(gw); + } + #undef gsw + } - // Update the display - gwinSliderDraw(gh); + static void ToggleAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + if (role) + ((GSliderObject *)gw)->t_up = instance; + else + ((GSliderObject *)gw)->t_dn = instance; + } - // Generate the event - break; - #endif + static uint16_t ToggleGet(GWidgetObject *gw, uint16_t role) { + return role ? ((GSliderObject *)gw)->t_up : ((GSliderObject *)gw)->t_dn; + } +#endif - default: - return; +#if GINPUT_NEED_DIAL + // A dial move event + static void DialMove(GWidgetObject *gw, uint16_t role, uint16_t value, uint16_t max) { + #define gsw ((GSliderObject *)gw) + (void) role; + + // Set the new position + gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/max + gsw->min); + + ResetDisplayPos(gsw); + _gwidgetRedraw((GHandle)gw); + + // Generate the event + SendSliderEvent(gw); + #undef gsw } - // Trigger a GWIN Slider Event - psl = 0; - while ((psl = geventGetSourceListener(gsh, psl))) { - if (!(pe = geventGetEventBuffer(psl))) - continue; - pse->type = GEVENT_GWIN_SLIDER; - pse->slider = gh; - pse->position = gsw->pos; - geventSendEvent(psl); + static void DialAssign(GWidgetObject *gw, uint16_t role, uint16_t instance) { + (void) role; + ((GSliderObject *)gw)->dial = instance; } - #undef pse - #undef pme - #undef pxe - #undef gsh - #undef gsw - #undef gh -} + static uint16_t DialGet(GWidgetObject *gw, uint16_t role) { + (void) role; + return ((GSliderObject *)gw)->dial; + } +#endif + +// The slider VMT table +static const gwidgetVMT sliderVMT = { + { + "Slider", // The classname + sizeof(GSliderObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinSliderDraw_Std, // The default drawing routine + #if GINPUT_NEED_MOUSE + { + 0, // Process mouse down events (NOT USED) + MouseUp, // Process mouse up events + MouseMove, // Process mouse move events + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 2, // 1 toggle role + ToggleAssign, // Assign Toggles + ToggleGet, // Get Toggles + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + }, + #endif + #if GINPUT_NEED_DIAL + { + 1, // 1 dial roles + DialAssign, // Assign Dials + DialGet, // Get Dials + DialMove, // Process dial move events + }, + #endif +}; -GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) { - if (!(gs = (GSliderObject *)_gwinInit((GWindowObject *)gs, x, y, width, height, sizeof(GSliderObject)))) +GHandle gwinSliderCreate(GSliderObject *gs, const GWidgetInit *pInit) { + if (!(gs = (GSliderObject *)_gwidgetCreate(&gs->w, pInit, &sliderVMT))) return 0; - gs->gwin.type = GW_SLIDER; - gs->fn = gwinSliderDraw_Std; - gs->param = 0; - gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle); + #if GINPUT_NEED_TOGGLE + gs->t_dn = GWIDGET_NO_INSTANCE; + gs->t_up = GWIDGET_NO_INSTANCE; + #endif + #if GINPUT_NEED_DIAL + gs->dial = GWIDGET_NO_INSTANCE; + #endif gs->min = 0; gs->max = 100; gs->pos = 0; - gs->tracking = FALSE; - geventListenerInit(&gs->listener); - geventRegisterCallback(&gs->listener, gwinSliderCallback, gs); + ResetDisplayPos(gs); + gwinSetVisible((GHandle)gs, pInit->g.show); return (GHandle)gs; } -void gwinSetSliderRange(GHandle gh, int min, int max) { +void gwinSliderSetRange(GHandle gh, int min, int max) { #define gsw ((GSliderObject *)gh) - if (gh->type != GW_SLIDER) + if (gh->vmt != (gwinVMT *)&sliderVMT) return; if (min == max) // prevent divide by 0 errors. @@ -160,13 +252,14 @@ void gwinSetSliderRange(GHandle gh, int min, int max) { gsw->min = min; gsw->max = max; gsw->pos = min; + ResetDisplayPos(gsw); #undef gsw } -void gwinSetSliderPosition(GHandle gh, int pos) { +void gwinSliderSetPosition(GHandle gh, int pos) { #define gsw ((GSliderObject *)gh) - if (gh->type != GW_SLIDER) + if (gh->vmt != (gwinVMT *)&sliderVMT) return; if (gsw->min <= gsw->max) { @@ -178,125 +271,105 @@ void gwinSetSliderPosition(GHandle gh, int pos) { else if (pos < gsw->max) gsw->pos = gsw->max; else gsw->pos = pos; } + ResetDisplayPos(gsw); #undef gsw } -void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle) { - #define gsw ((GSliderObject *)gh) - - if (gh->type != GW_SLIDER) - return; - - gsw->style.color_edge = pStyle->color_edge; - gsw->style.color_thumb = pStyle->color_thumb; - gsw->style.color_active = pStyle->color_active; - gsw->style.color_inactive = pStyle->color_inactive; - #undef gsw -} - -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - static void trackSliderDraw(GHandle gh, coord_t x, coord_t y) { - #define gsw ((GSliderObject *)gh) +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif +void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { + #define gsw ((GSliderObject *)gw) + const GColorSet * pcol; + (void) param; - if (gh->height <= gh->width) - gsw->fn(gh, FALSE, x, &gsw->style, gsw->param); - else - gsw->fn(gh, TRUE, y, &gsw->style, gsw->param); - - #undef gbw - } -#endif - -void gwinSliderDraw(GHandle gh) { - #define gsw ((GSliderObject *)gh) - - if (gh->type != GW_SLIDER) + if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif - - if (gh->height <= gh->width) - gsw->fn(gh, FALSE, ((gh->width-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param); + if ((gw->g.flags & GWIN_FLG_ENABLED)) + pcol = &gw->pstyle->pressed; else - gsw->fn(gh, TRUE, gh->height-1-((gh->height-1)*(gsw->pos-gsw->min))/(gsw->max-gsw->min), &gsw->style, gsw->param); - - #undef gbw -} - -void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) { - #define gsw ((GSliderObject *)gh) - - if (gh->type != GW_SLIDER) - return; - - gsw->fn = fn ? fn : gwinSliderDraw_Std; - gsw->param = param; + pcol = &gw->pstyle->disabled; + + if (gw->g.width < gw->g.height) { // Vertical slider + if (gsw->dpos != gw->g.height-1) + gdispFillArea(gw->g.x, gw->g.y+gsw->dpos, gw->g.width, gw->g.height - gsw->dpos, pcol->progress); // Active Area + if (gsw->dpos != 0) + gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb + if (gsw->dpos >= 2) + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos-2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos-2, pcol->edge); // Thumb + if (gsw->dpos <= gw->g.height-2) + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos+2, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos+2, pcol->edge); // Thumb + + // Horizontal slider + } else { + if (gsw->dpos != gw->g.width-1) + gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area + if (gsw->dpos != 0) + gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, pcol->progress); // Active Area + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + if (gsw->dpos >= 2) + gdispDrawLine(gw->g.x+gsw->dpos-2, gw->g.y, gw->g.x+gsw->dpos-2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + if (gsw->dpos <= gw->g.width-2) + gdispDrawLine(gw->g.x+gsw->dpos+2, gw->g.y, gw->g.x+gsw->dpos+2, gw->g.y+gw->g.height-1, pcol->edge); // Thumb + } + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); #undef gsw } -void gwinSliderSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_SLIDER) +void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { + #define gsw ((GSliderObject *)gw) + #define gi ((gdispImage *)param) + const GColorSet * pcol; + coord_t z, v; + + if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - gh->enabled = enabled; -} + if ((gw->g.flags & GWIN_FLG_ENABLED)) + pcol = &gw->pstyle->pressed; + else + pcol = &gw->pstyle->disabled; + + if (gw->g.width < gw->g.height) { // Vertical slider + if (gsw->dpos != 0) // The unfilled area + gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gw->pstyle->enabled.progress); // Inactive area + if (gsw->dpos != gw->g.height-1) { // The filled area + for(z=gw->g.height, v=gi->height; z > gsw->dpos;) { + z -= v; + if (z < gsw->dpos) { + v -= gsw->dpos - z; + z = gsw->dpos; + } + gdispImageDraw(gi, gw->g.x, gw->g.y+z, gw->g.width, v, 0, gi->height-v); + } + } + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, pcol->edge); // Thumb -void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) { - (void) param; - - if (isVertical) { - if (thumbpos != gh->height-1) - gdispFillArea(gh->x, gh->y+thumbpos, gh->width, gh->height - thumbpos, pstyle->color_active); - if (thumbpos != 0) - gdispFillArea(gh->x, gh->y, gh->width, thumbpos, pstyle->color_inactive); - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); - gdispDrawLine(gh->x, gh->y+thumbpos, gh->x+gh->width-1, gh->y+thumbpos, pstyle->color_thumb); - if (thumbpos >= 2) - gdispDrawLine(gh->x, gh->y+thumbpos-2, gh->x+gh->width-1, gh->y+thumbpos-2, pstyle->color_thumb); - if (thumbpos <= gh->height-2) - gdispDrawLine(gh->x, gh->y+thumbpos+2, gh->x+gh->width-1, gh->y+thumbpos+2, pstyle->color_thumb); + // Horizontal slider } else { - if (thumbpos != gh->width-1) - gdispFillArea(gh->x+thumbpos, gh->y, gh->width-thumbpos, gh->height, pstyle->color_inactive); - if (thumbpos != 0) - gdispFillArea(gh->x, gh->y, thumbpos, gh->height, pstyle->color_active); - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); - gdispDrawLine(gh->x+thumbpos, gh->y, gh->x+thumbpos, gh->y+gh->height-1, pstyle->color_thumb); - if (thumbpos >= 2) - gdispDrawLine(gh->x+thumbpos-2, gh->y, gh->x+thumbpos-2, gh->y+gh->height-1, pstyle->color_thumb); - if (thumbpos <= gh->width-2) - gdispDrawLine(gh->x+thumbpos+2, gh->y, gh->x+thumbpos+2, gh->y+gh->height-1, pstyle->color_thumb); - } -} - -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance) { - GSourceHandle gsh; - - if (gh->type != GW_SLIDER || !(gsh = ginputGetMouse(instance))) - return FALSE; - - return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); + if (gsw->dpos != gw->g.width-1) // The unfilled area + gdispFillArea(gw->g.x+gsw->dpos, gw->g.y, gw->g.width-gsw->dpos, gw->g.height, gw->pstyle->enabled.progress); // Inactive area + if (gsw->dpos != 0) { // The filled area + for(z=0, v=gi->width; z < gsw->dpos; z += v) { + if (z+v > gsw->dpos) + v -= z+v - gsw->dpos; + gdispImageDraw(gi, gw->g.x+z, gw->g.y, v, gw->g.height, 0, 0); + } + } + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->edge); // Edge + gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, pcol->edge); // Thumb } -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL - bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance) { - GSourceHandle gsh; + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->text, gw->g.font, pcol->text, justifyCenter); - if (gh->type != GW_SLIDER || !(gsh = ginputGetDial(instance))) - return FALSE; - - return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, 0); - } -#endif + #undef gsw +} #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ /** @} */ |