diff options
Diffstat (limited to 'src/gwin/slider.c')
-rw-r--r-- | src/gwin/slider.c | 402 |
1 files changed, 201 insertions, 201 deletions
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 */ /** @} */ |