From 7baf5c5d448b626d6a062882434b25ca82212d94 Mon Sep 17 00:00:00 2001 From: inmarket Date: Thu, 6 Jun 2013 14:33:32 +1000 Subject: New simplified gwin using a pseudo class structure. --- src/gwin/button.c | 545 ++++++++++++++++++++++------------------------------ src/gwin/checkbox.c | 225 ++++++++++------------ src/gwin/console.c | 55 +++--- src/gwin/graph.c | 72 +++---- src/gwin/gwidget.c | 254 ++++++++++++++++++++++++ src/gwin/gwin.c | 110 ++++------- src/gwin/gwin.mk | 3 +- src/gwin/slider.c | 402 +++++++++++++++++++------------------- 8 files changed, 884 insertions(+), 782 deletions(-) create mode 100644 src/gwin/gwidget.c (limited to 'src/gwin') diff --git a/src/gwin/button.c b/src/gwin/button.c index cf5babc5..1ebc8ee5 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -19,392 +19,313 @@ #if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__) -/* 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 - -#include "gwin/internal.h" - -#define GWIN_BUTTON_DEFAULT_SHAPE GBTN_3D +// Our pressed state +#define GBUTTON_FLG_PRESSED (GWIN_FIRST_CONTROL_FLAG<<0) + +// Prototypes for button VMT functions +static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y); +static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y); +static void ToggleOff(GWidgetObject *gw, uint16_t instance); +static void ToggleOn(GWidgetObject *gw, uint16_t instance); + +// The button VMT table +static const gwidgetVMT buttonVMT = { + { + "Button", // The classname + _gwidgetDestroy, // The destroy routine + 0, // The after-clear routine + }, + gwinButtonDraw_3D, // The default drawing routine + MouseDown, // Process mouse down events + MouseUp, // Process mouse up events + 0, // Process mouse move events (NOT USED) + ToggleOff, // Process toggle off events + ToggleOn, // Process toggle on events + 0, // Process dial move events (NOT USED) + 0, // Process all events (NOT USED) + 0, // AssignToggle (NOT USED) + 0, // AssignDial (NOT USED) +}; -static const GButtonDrawStyle GButtonDefaultStyleUp = { +// Default color scheme +static const GButtonColors GButtonDefaultColorsUp = { HTML2COLOR(0x404040), // color_up_edge; HTML2COLOR(0xE0E0E0), // color_up_fill; HTML2COLOR(0x000000), // color_up_txt; }; - -static const GButtonDrawStyle GButtonDefaultStyleDown = { +static const GButtonColors GButtonDefaultColorsDown = { HTML2COLOR(0x404040), // color_dn_edge; HTML2COLOR(0x808080), // color_dn_fill; HTML2COLOR(0x404040), // color_dn_txt; }; +static const GButtonColors GButtonDefaultColorsDisabled = { + HTML2COLOR(0x808080), // color_dis_edge; + HTML2COLOR(0xE0E0E0), // color_dis_fill; + HTML2COLOR(0xC0C0C0), // color_dis_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; - - 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((GSourceHandle)gw, 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; +// 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; + gwinDraw((GHandle)gw); } -void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) { - #define gbw ((GButtonObject *)gh) - if (gh->type != GW_BUTTON) - return; - - 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 - - #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; - #endif - - case GBTN_CUSTOM: if (gbw->fn) break; /* Fall Through */ - case GBTN_3D: /* Fall through */ - default: gbw->fn = gwinButtonDraw_3D; break; - } - 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; - } - #undef gbw -} +// 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; + gwinDraw((GHandle)gw); -void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) { - #define gbw ((GButtonObject *)gh) - if (gh->type != GW_BUTTON) - return; + #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 - // 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 = ""; - } - } - // 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; - } - - gbw->txt = txt ? txt : ""; - #undef gbw + SendButtonEvent(gw); } -void gwinButtonDraw(GHandle gh) { - #define gbw ((GButtonObject *)gh) - - if (gh->type != GW_BUTTON) - return; +// A toggle off has occurred +static void ToggleOff(GWidgetObject *gw, uint16_t instance) { + (void) instance; + gw->g.flags &= ~GBUTTON_FLG_PRESSED; + gwinDraw((GHandle)gw); +} - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif +// A toggle on has occurred +static void ToggleOn(GWidgetObject *gw, uint16_t instance) { + (void) instance; + gw->g.flags |= GBUTTON_FLG_PRESSED; + gwinDraw((GHandle)gw); + // Trigger the event on button down (different than for mouse/touch) + SendButtonEvent(gw); +} - 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); +GHandle gwinCreateButton(GButtonObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) { + if (!(gw = (GButtonObject *)_gwidgetInit((GWidgetObject *)gw, x, y, width, height, sizeof(GButtonObject), &buttonVMT))) + return 0; - #undef gbw + gw->c_up = GButtonDefaultColorsUp; + gw->c_dn = GButtonDefaultColorsDown; + gw->c_dis = GButtonDefaultColorsDisabled; + return (GHandle)gw; } -void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) { - #define gbw ((GButtonObject *)gh) - - if (gh->type != GW_BUTTON) +void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled) { + if (gh->vmt != (gwinVMT *)&buttonVMT) return; - gbw->fn = fn ? fn : gwinButtonDraw_3D; - gbw->param = param; + if (pUp) ((GButtonObject *)gh)->c_up = *pUp; + if (pDown) ((GButtonObject *)gh)->c_dn = *pDown; + if (pDisabled) ((GButtonObject *)gh)->c_dis = *pDisabled; +} + +bool_t gwinIsButtonPressed(GHandle gh) { + if (gh->vmt != (gwinVMT *)&buttonVMT) + return FALSE; - #undef gbw + return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE; } -void gwinButtonSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_BUTTON) - return; +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ - gh->enabled = enabled; +static GButtonColors *getDrawColors(GWidgetObject *gw) { + if (!(gw->g.flags & GWIN_FLG_ENABLED)) return &((GButtonObject *)gw)->c_dis; + if ((gw->g.flags & GBUTTON_FLG_PRESSED)) return &((GButtonObject *)gw)->c_dn; + return &((GButtonObject *)gw)->c_up; } -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; +void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { + (void) param; + GButtonColors * pcol; - 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); + 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->txt, gw->g.font, pcol->color_txt, pcol->color_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->color_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->color_edge); } -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_Box(GWidgetObject *gw, void *param) { + (void) param; + GButtonColors * pcol; - 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+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_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) { + (void) param; + GButtonColors * pcol; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + 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->color_fill); + gdispDrawStringBox(gw->g.x+1, gw->g.y+RND_CNR_SIZE, gw->g.width-2, gw->g.height-(2*RND_CNR_SIZE), gw->txt, gw->g.font, pcol->color_txt, justifyCenter); + gdispDrawRoundedBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, RND_CNR_SIZE, pcol->color_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->txt, gw->g.font, pcol->color_txt, pcol->color_fill, justifyCenter); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, pcol->color_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) { + (void) param; + GButtonColors * pcol; + + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; + pcol = getDrawColors(gw); + + gdispFillEllipse(gw->g.x+1, gw->g.y+1, gw->g.width/2-1, gw->g.height/2-1, pcol->color_fill); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter); + gdispDrawEllipse(gw->g.x, gw->g.y, gw->g.width/2, gw->g.height/2, pcol->color_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) { + (void) param; + GButtonColors * pcol; + 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; + + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) { + (void) param; + GButtonColors * pcol; + 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; + + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) { + (void) param; + GButtonColors * pcol; + 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; + + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, 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) { + (void) param; + GButtonColors * pcol; + 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; + + gdispFillConvexPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_fill); + gdispDrawPoly(gw->g.x, gw->g.y, arw, 7, pcol->color_edge); + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, pcol->color_txt, justifyCenter); } #endif -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) { - GSourceHandle gsh; +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) + void gwinButtonDraw_Image(GWidgetObject *gw, void *param) { + GButtonColors * pcol; + coord_t sy; - if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance))) - return FALSE; + if (gw->g.vmt != (gwinVMT *)&buttonVMT) return; - return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); - } -#endif - -#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)) { + pcol = &((GButtonObject *)gw)->c_dis; + sy = 2 * gw->g.height; + } else if ((gw->g.flags & GBUTTON_FLG_PRESSED)) { + pcol = &((GButtonObject *)gw)->c_dn; + sy = gw->g.height; + } else { + pcol = &((GButtonObject *)gw)->c_up; + 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->txt, gw->g.font, pcol->color_txt, justifyCenter); } #endif diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 547a30b5..d35f271c 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,137 @@ #if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__) -static const GCheckboxColor defaultColors = { - Grey, // border - Grey, // selected - Black // background +#include "gwin/class_gwin.h" + +// Our checked state +#define GCHECKBOX_FLG_CHECKED (GWIN_FIRST_CONTROL_FLAG<<0) + +// Prototypes for button VMT functions +static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y); +static void ToggleOn(GWidgetObject *gw, uint16_t instance); + +// The button VMT table +static const gwidgetVMT checkboxVMT = { + { + "Checkbox", // The classname + _gwidgetDestroy, // The destroy routine + 0, // The after-clear routine + }, + gwinCheckboxDraw_CheckOnLeft, // The default drawing routine + MouseDown, // Process mouse down events + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + 0, // Process toggle off events (NOT USED) + ToggleOn, // Process toggle on events + 0, // Process dial move events (NOT USED) + 0, // Process all events (NOT USED) + 0, // AssignToggle (NOT USED) + 0, // AssignDial (NOT USED) }; -/* default style drawing routine */ -static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) { - #define gcw ((GCheckboxObject *)gh) - - (void) enabled; - (void) param; - - gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border); - - 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); - - #undef gcw -} - -/* 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) { - - gbw->isChecked = !gbw->isChecked; - - gwinCheckboxDraw((GHandle)param); - break; - } - return; - #endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ +static const GCheckboxColors defaultColors = { + Black, // border + Grey, // selected + White, // background + Black, // text +}; - default: - return; - } +// Send the checkbox event +static void SendCheckboxEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pce ((GEventGWinCheckbox *)pe) - // Trigger a GWIN checkbox event + // Trigger a GWIN Checkbox Event psl = 0; - while ((psl = geventGetSourceListener(gsh, psl))) { + while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) { if (!(pe = geventGetEventBuffer(psl))) continue; - pbe->type = GEVENT_GWIN_CHECKBOX; - pbe->checkbox = gh; - pbe->isChecked = gbw->isChecked; + pce->type = GEVENT_GWIN_CHECKBOX; + pce->checkbox = &gw->g; + pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; geventSendEvent(psl); - } - - #undef gh - #undef pbe - #undef pme - #undef pte - #undef pxe - #undef gsh - #undef gbw -} + } -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)))) - return 0; + #undef pce +} - 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 +// A mouse down has occurred over the checkbox +static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { + (void) x; (void) y; + gw->g.flags ^= GCHECKBOX_FLG_CHECKED; + gwinDraw((GHandle)gw); + SendCheckboxEvent(gw); +} - geventListenerInit(&gb->listener); - geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb); +// A toggle on has occurred +static void ToggleOn(GWidgetObject *gw, uint16_t instance) { + (void) instance; + gw->g.flags ^= GCHECKBOX_FLG_CHECKED; + gwinDraw((GHandle)gw); + SendCheckboxEvent(gw); +} - // checkboxes are enabled by default - gb->gwin.enabled = TRUE; +GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { + if (!(gb = (GCheckboxObject *)_gwidgetInit((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT))) + return 0; + gb->c = defaultColors; // assign the default colors return (GHandle)gb; } -void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) { - #define gcw ((GCheckboxObject *)gh) - - if (gh->type != GW_CHECKBOX) - return; - - gcw->fn = fn; - gcw->param = param; +bool_t gwinIsCheckboxChecked(GHandle gh) { + if (gh->vmt != (gwinVMT *)&checkboxVMT) + return FALSE; - #undef gcw + return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE; } - -void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_CHECKBOX) +void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors) { + if (gh->vmt != (gwinVMT *)&checkboxVMT) return; - gh->enabled = enabled; + ((GCheckboxObject *)gh)->c = *pColors; } -void gwinCheckboxDraw(GHandle gh) { - #define gcw ((GCheckboxObject *)gh) +void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) { + #define gcw ((GCheckboxObject *)gw) + coord_t ld, df; + (void) param; - if (gh->type != GW_CHECKBOX) + if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; - #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, gcw->c.color_bg); + gdispDrawBox(gw->g.x, gw->g.y, ld, ld, gcw->c.color_border); - 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, gcw->c.color_checked); + gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyLeft); #undef gcw } -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE - bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) { - GSourceHandle gsh; - - if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance))) - return FALSE; - - 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) +void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { + #define gcw ((GCheckboxObject *)gw) + coord_t ep, ld, df; + (void) param; - if (gh->type != GW_CHECKBOX) + if (gw->g.vmt != (gwinVMT *)&checkboxVMT) return; - gcw->colors->border = border; - gcw->colors->checked = checked, - gcw->colors->bg = bg; + 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, gcw->c.color_bg); + gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, gcw->c.color_border); + + 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, gcw->c.color_checked); + gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyRight); #undef gcw } diff --git a/src/gwin/console.c b/src/gwin/console.c index 5c068c93..d9bda362 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 -#include "gwin/internal.h" +#include "gwin/class_gwin.h" #define GWIN_CONSOLE_USE_CLEAR_LINES TRUE #define GWIN_CONSOLE_USE_FILLED_CHARS FALSE @@ -58,11 +53,20 @@ }; #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 + 0, // The destroy routine + AfterClear, // The after-clear routine +}; + +GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height) { + if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT))) 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 @@ -73,17 +77,21 @@ GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t widt #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM BaseSequentialStream *gwinGetConsoleStream(GHandle gh) { - if (gh->type != GW_CONSOLE) + 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 +99,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 +129,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 +208,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 +352,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) { } #endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */ -/** @} */ + diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 287deba9..0ae9822b 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,19 @@ static const GGraphStyle GGraphDefaultStyle = { GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS // flags }; +static const gwinVMT graphVMT = { + "Graph", // The classname + 0, // The destroy 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 +74,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 @@ -163,41 +164,26 @@ 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)))) + if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT))) 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); 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 +192,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 +205,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 +263,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 +272,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 +300,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 +330,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..464210b7 --- /dev/null +++ b/src/gwin/gwidget.c @@ -0,0 +1,254 @@ +/* + * This file is subject to the terms of the GFX License, v1.0. 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 + +#include + +#include "gwin/class_gwin.h" + +/* We use these everywhere in this file */ +#define gw ((GWidgetObject *)gh) +#define wvmt ((gwidgetVMT *)gh->vmt) + +static void gwidgetCallback(void *param, GEvent *pe) { + #define gh ((GWindowObject *)param) + #define pme ((GEventMouse *)pe) + #define pte ((GEventToggle *)pe) + #define pde ((GEventDial *)pe) + + // check if widget is disabled + if (!(gw->g.flags & GWIN_FLG_ENABLED)) + return; + + // Process via AllEvents() if it is defined + if (wvmt->AllEvents) + wvmt->AllEvents(gw, pe); + + // Process various events + switch (pe->type) { + + #if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + case GEVENT_MOUSE: + case GEVENT_TOUCH: + // Are we captured? + if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { + if (pme->meta == GMETA_MOUSE_UP) { + gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; + if (wvmt->MouseUp) + wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); + return; + } 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->meta == GMETA_MOUSE_DOWN + && 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: + if (pte->on) { + if (wvmt->ToggleOn) + wvmt->ToggleOn(gw, pte->instance); + } else { + if (wvmt->ToggleOff) + wvmt->ToggleOff(gw, pte->instance); + } + break; + #endif + + #if GFX_USE_GINPUT && GINPUT_NEED_DIAL + case GEVENT_DIAL: + if (wvmt->DialMove) + wvmt->DialMove(gw, pde->instance, pde->value); + break; + #endif + + default: + break; + } + #undef gh + #undef pme + #undef pte + #undef pde +} + +GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) { + if (!(pgw = (GWidgetObject *)_gwinInit((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt))) + return 0; + + pgw->g.flags |= (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED); + pgw->txt = ""; + pgw->fnDraw = vmt->DefaultDraw; + pgw->fnParam = 0; + geventListenerInit(&pgw->listener); + geventRegisterCallback(&pgw->listener, gwidgetCallback, pgw); + + return (GHandle)pgw; +} + +void _gwidgetDestroy(GHandle gh) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + // Deallocate the text (if necessary) + if ((gh->flags & GWIN_FLG_ALLOCTXT)) { + gh->flags &= ~GWIN_FLG_ALLOCTXT; + gfxFree((void *)gw->txt); + } + // Untangle the listeners (both on us and to us). + geventDetachSource(&gw->listener, 0); + geventDetachSourceListeners((GSourceHandle)gh); + gh->flags &= ~GWIN_FLG_WIDGET; +} + +void gwinSetEnabled(GHandle gh, bool_t enabled) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + if (enabled) + gh->flags |= GWIN_FLG_ENABLED; + else + gh->flags &= ~GWIN_FLG_ENABLED; +} + +void gwinDraw(GHandle gh) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + + gw->fnDraw(gw, gw->fnParam); +} + +void gwinSetText(GHandle gh, const char *txt, 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->txt) { + gfxFree((void *)gw->txt); + gw->txt = ""; + } + } + + // Alloc the new text if required + if (txt && !*txt) txt = 0; + if (txt && useAlloc) { + char *str; + + if ((str = (char *)gfxAlloc(strlen(txt)+1))) { + gh->flags |= GWIN_FLG_ALLOCTXT; + strcpy(str, txt); + } + txt = (const char *)str; + } + + gw->txt = txt ? txt : ""; +} + +const char *gwinGetText(GHandle gh) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return 0; + + return gw->txt; +} + +void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return; + + gw->fnDraw = fn ? fn : wvmt->DefaultDraw; + gw->fnParam = param; +} + +bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags) { + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + return geventAttachSource(pl, (GSourceHandle)gh, flags); +} + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE + bool_t gwinAttachMouse(GHandle gh, uint16_t instance) { + GSourceHandle gsh; + unsigned flags; + + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + if (!wvmt->MouseDown && !wvmt->MouseMove && !wvmt->MouseUp) + return FALSE; + + if (!(gsh = ginputGetMouse(instance))) + return FALSE; + + flags = wvmt->MouseMove ? (GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES) : GLISTEN_MOUSEMETA; + return geventAttachSource(&gw->listener, gsh, flags); + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE + bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { + GSourceHandle gsh; + unsigned flags; + + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + flags = 0; + if (wvmt->ToggleOff) flags |= GLISTEN_TOGGLE_OFF; + if (wvmt->ToggleOn) flags |= GLISTEN_TOGGLE_ON; + if (!flags) + return FALSE; + + if (!(gsh = ginputGetToggle(instance))) + return FALSE; + + if (wvmt->AssignToggle && !wvmt->AssignToggle(gw, role, instance)) + return FALSE; + + return geventAttachSource(&gw->listener, gsh, flags); + } +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) { + GSourceHandle gsh; + + if (!(gh->flags & GWIN_FLG_WIDGET)) + return FALSE; + + if (!wvmt->DialMove) + return FALSE; + + if (!(gsh = ginputGetDial(instance))) + return FALSE; + + if (wvmt->AssignDial && !wvmt->AssignDial(gw, role, instance)) + return FALSE; + + return geventAttachSource(&gw->listener, gsh, 0); + } +#endif + +#endif /* GFX_USE_GWIN */ +/** @} */ + diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index c01c8a90..fcbaa397 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -9,11 +9,19 @@ #if GFX_USE_GWIN -#include "gwin/internal.h" +#include "gwin/class_gwin.h" + +static const gwinVMT basegwinVMT = { + "GWIN", // The classname + 0, // The destroy routine + 0, // The after-clear routine +}; + +static font_t defaultFont; // 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) { +GHandle _gwinInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt) { coord_t w, h; // Check the window size against the screen size @@ -26,60 +34,34 @@ GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_ if (y+height > h) height = h - y; // Allocate the structure if necessary - if (!gw) { - if (!(gw = (GWindowObject *)gfxAlloc(size))) + if (!pgw) { + if (!(pgw = (GWindowObject *)gfxAlloc(size))) return 0; - gw->flags = GWIN_FLG_DYNAMIC; + pgw->flags = GWIN_FLG_DYNAMIC; } else - gw->flags = 0; + pgw->flags = 0; - // 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->x = x; + pgw->y = y; + pgw->width = width; + pgw->height = height; + pgw->color = White; + pgw->bgcolor = Black; #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)))) - return 0; - gw->type = GW_WINDOW; - return (GHandle)gw; + return (GHandle)pgw; } -void gwinSetEnabled(GHandle gh, bool_t enabled) { - (void)gh; - (void)enabled; +GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) { + return _gwinInit(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT); } -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; - } +void gwinDestroy(GHandle gh) { + if (gh->vmt->Destroy) + gh->vmt->Destroy(gh); // Clean up the structure if (gh->flags & GWIN_FLG_DYNAMIC) { @@ -88,30 +70,17 @@ void gwinDestroyWindow(GHandle gh) { } } -void gwinDraw(GHandle gh) { - switch(gh->type) { - #if GWIN_NEED_BUTTON - case GW_BUTTON: - gwinButtonDraw(gh); - break; - #endif - #if GWIN_NEED_SLIDER - case GW_SLIDER: - gwinSliderDraw(gh); - break; - #endif - } +const char *gwinGetClassName(GHandle gh) { + return gh->vmt->classname; } #if GDISP_NEED_TEXT + void gwinSetDefaultFont(font_t font) { + defaultFont = font; + } + 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 @@ -120,13 +89,8 @@ void gwinClear(GHandle gh) { 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) { diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk index be6301c6..90a8e9b4 100644 --- a/src/gwin/gwin.mk +++ b/src/gwin/gwin.mk @@ -1,7 +1,8 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ + $(GFXLIB)/src/gwin/gwidget.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 \ diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 1f252d77..f18c665b 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -19,140 +19,168 @@ #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); -#endif +// Prototypes for slider VMT functions +static void MouseUp(GWidgetObject *gw, coord_t x, coord_t y); +static void MouseMove(GWidgetObject *gw, coord_t x, coord_t y); +static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value); + +// The button VMT table +static const gwidgetVMT sliderVMT = { + { + "Slider", // The classname + _gwidgetDestroy, // The destroy routine + 0, // The after-clear routine + }, + gwinSliderDraw_Std, // The default drawing routine + MouseMove, // Process mouse down events (AS MOUSEMOVE) + MouseUp, // Process mouse up events + MouseMove, // Process mouse move events + 0, // Process toggle off events (NOT USED) + 0, // Process toggle on events (NOT USED) + DialMove, // Process dial move events + 0, // Process all events (NOT USED) + 0, // AssignToggle (NOT USED) + 0, // AssignDial (NOT USED) +}; -static const GSliderDrawStyle GSliderDefaultStyle = { - HTML2COLOR(0x404040), // color_edge; - HTML2COLOR(0x000000), // color_thumb; - HTML2COLOR(0x00E000), // color_active; - HTML2COLOR(0xE0E0E0), // color_inactive; +static const GSliderColors GSliderDefaultColors = { + HTML2COLOR(0x404040), // color_edge + HTML2COLOR(0x000000), // color_thumb + HTML2COLOR(0x00E000), // color_active + HTML2COLOR(0xE0E0E0), // color_inactive + HTML2COLOR(0xFFFFFF), // color_txt }; -// 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); - } - return; - } +// Send the slider event +static void SendSliderEvent(GWidgetObject *gw) { + GSourceListener * psl; + GEvent * pe; + #define pse ((GEventGWinSlider *)pe) - // 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; - } + // Trigger a GWIN Button Event + psl = 0; + while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) { + if (!(pe = geventGetEventBuffer(psl))) + continue; + pse->type = GEVENT_GWIN_SLIDER; + pse->slider = (GHandle)gw; + pse->position = ((GSliderObject *)gw)->pos; + geventSendEvent(psl); + } - // If mouse down - track movement - if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) - trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y); + #undef pbe +} +// 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); +} + +// 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); + gwinDraw(gh); 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)); - // Update the display - gwinSliderDraw(gh); + // Set the new position + if (gh->width < gh->height) + gsw->pos = (uint16_t)((uint32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); + else + gsw->pos = (uint16_t)((uint32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); - // Generate the event - break; - #endif + ResetDisplayPos(gsw); + gwinDraw(gh); - default: - return; - } + // Generate the event + SendSliderEvent(gw); + #undef gh + #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); +// 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; } - #undef pse - #undef pme - #undef pxe - #undef gsh + // Update the display + gwinDraw(&gw->g); #undef gsw - #undef gh +} + +// A dial move event +static void DialMove(GWidgetObject *gw, uint16_t instance, uint16_t value) { +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL + #define gsw ((GSliderObject *)gw) + + // Set the new position + gsw->pos = (uint16_t)((uint32_t)value*(gsw->max-gsw->min)/ginputGetDialRange(instance) + gsw->min); + + ResetDisplayPos(gsw); + gwinDraw(&gw->g); + + // Generate the event + SendSliderEvent(gw); + #undef gsw +#else + (void)gw; (void)instance; (void)value; +#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)))) + if (!(gs = (GSliderObject *)_gwidgetInit((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT))) return 0; - gs->gwin.type = GW_SLIDER; - gs->fn = gwinSliderDraw_Std; - gs->param = 0; - gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle); + gs->c = GSliderDefaultColors; gs->min = 0; gs->max = 100; gs->pos = 0; - gs->tracking = FALSE; - geventListenerInit(&gs->listener); - geventRegisterCallback(&gs->listener, gwinSliderCallback, gs); + ResetDisplayPos(gs); return (GHandle)gs; } void gwinSetSliderRange(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 +188,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) { #define gsw ((GSliderObject *)gh) - if (gh->type != GW_SLIDER) + if (gh->vmt != (gwinVMT *)&sliderVMT) return; if (gsw->min <= gsw->max) { @@ -178,125 +207,96 @@ 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) - - #if GDISP_NEED_CLIP - gdispSetClip(gh->x, gh->y, gh->width, gh->height); - #endif - - 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) +void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) { + if (gh->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); - 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 + ((GSliderObject *)gh)->c = *pColors; } -void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) { - #define gsw ((GSliderObject *)gh) +void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { + #define gsw ((GSliderObject *)gw) + (void) param; - if (gh->type != GW_SLIDER) + if (gw->g.vmt != (gwinVMT *)&sliderVMT) return; - gsw->fn = fn ? fn : gwinSliderDraw_Std; - gsw->param = param; + 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, gsw->c.color_active); + if (gsw->dpos != 0) + gdispFillArea(gw->g.x, gw->g.y, gw->g.width, gsw->dpos, gsw->c.color_inactive); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge); + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_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, gsw->c.color_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, gsw->c.color_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, gsw->c.color_inactive); + if (gsw->dpos != 0) + gdispFillArea(gw->g.x, gw->g.y, gsw->dpos, gw->g.height, gsw->c.color_active); + gdispDrawBox(gw->g.x, gw->g.y, gw->g.width, gw->g.height, gsw->c.color_edge); + gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_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, gsw->c.color_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, gsw->c.color_thumb); + } + gdispDrawStringBox(gw->g.x+1, gw->g.y+1, gw->g.width-2, gw->g.height-2, gw->txt, gw->g.font, gsw->c.color_txt, justifyCenter); #undef gsw } -void gwinSliderSetEnabled(GHandle gh, bool_t enabled) { - if (gh->type != GW_SLIDER) - return; +void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { + #define gsw ((GSliderObject *)gw) + #define gi ((gdispImage *)param) + coord_t z, v; - gh->enabled = enabled; -} + if (gw->g.vmt != (gwinVMT *)&sliderVMT) + return; -void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) { - (void) param; + 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, gsw->c.color_inactive); + 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, gsw->c.color_edge); + gdispDrawLine(gw->g.x, gw->g.y+gsw->dpos, gw->g.x+gw->g.width-1, gw->g.y+gsw->dpos, gsw->c.color_thumb); - 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, gsw->c.color_inactive); + 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, gsw->c.color_edge); + gdispDrawLine(gw->g.x+gsw->dpos, gw->g.y, gw->g.x+gsw->dpos, gw->g.y+gw->g.height-1, gsw->c.color_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->txt, gw->g.font, gsw->c.color_txt, 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 */ /** @} */ -- cgit v1.2.3