diff --git a/demos/modules/gwin/slider/gfxconf.h b/demos/modules/gwin/slider/gfxconf.h new file mode 100644 index 00000000..477d7d29 --- /dev/null +++ b/demos/modules/gwin/slider/gfxconf.h @@ -0,0 +1,57 @@ +/** + * This file has a different license to the rest of the GFX system. + * You can copy, modify and distribute this file as you see fit. + * You do not need to publish your source modifications to this file. + * The only thing you are not permitted to do is to relicense it + * under a different license. + */ + +#ifndef _GFXCONF_H +#define _GFXCONF_H + +/* GFX sub-systems to turn on */ +#define GFX_USE_GDISP TRUE +#define GFX_USE_GWIN TRUE +#define GFX_USE_GEVENT TRUE +#define GFX_USE_GTIMER TRUE +#define GFX_USE_GINPUT TRUE + +/* Features for the GDISP sub-system. */ +#define GDISP_NEED_VALIDATION TRUE +#define GDISP_NEED_CLIP TRUE +#define GDISP_NEED_TEXT TRUE +#define GDISP_NEED_CIRCLE FALSE +#define GDISP_NEED_ELLIPSE FALSE +#define GDISP_NEED_ARC FALSE +#define GDISP_NEED_CONVEX_POLYGON FALSE +#define GDISP_NEED_SCROLL FALSE +#define GDISP_NEED_PIXELREAD FALSE +#define GDISP_NEED_CONTROL FALSE +#define GDISP_NEED_IMAGE FALSE +#define GDISP_NEED_MULTITHREAD TRUE +#define GDISP_NEED_ASYNC FALSE +#define GDISP_NEED_MSGAPI FALSE + +/* Builtin Fonts */ +#define GDISP_INCLUDE_FONT_SMALL FALSE +#define GDISP_INCLUDE_FONT_LARGER FALSE +#define GDISP_INCLUDE_FONT_UI1 FALSE +#define GDISP_INCLUDE_FONT_UI2 TRUE +#define GDISP_INCLUDE_FONT_LARGENUMBERS FALSE + +/* GDISP image decoders */ +#define GDISP_NEED_IMAGE_NATIVE FALSE +#define GDISP_NEED_IMAGE_GIF FALSE +#define GDISP_NEED_IMAGE_BMP FALSE +#define GDISP_NEED_IMAGE_JPG FALSE +#define GDISP_NEED_IMAGE_PNG FALSE + +/* Features for the GWIN sub-system. */ +#define GWIN_NEED_BUTTON FALSE +#define GWIN_NEED_CONSOLE TRUE +#define GWIN_NEED_SLIDER TRUE + +/* Features for the GINPUT sub-system. */ +#define GINPUT_NEED_MOUSE TRUE + +#endif /* _GFXCONF_H */ diff --git a/demos/modules/gwin/slider/main.c b/demos/modules/gwin/slider/main.c new file mode 100644 index 00000000..9a318943 --- /dev/null +++ b/demos/modules/gwin/slider/main.c @@ -0,0 +1,89 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" +#include "chprintf.h" + +static GListener gl; + +#define SLIDER_WIDTH 20 + +int main(void) { + coord_t swidth, sheight; + GHandle ghSliderH, ghSliderV, ghConsole; + font_t fui2; + GSourceHandle gsMouse; + GEventGWinSlider * pSliderEvent; + BaseSequentialStream *consout; + + halInit(); // Initialize the Hardware + chSysInit(); // Initialize the OS + gdispInit(); // Initialize the display + + gdispClear(Black); + + // Get the display dimensions + swidth = gdispGetWidth(); + sheight = gdispGetHeight(); + + // Get the font + fui2 = gdispOpenFont("UI2"); + + // Create out gwin windows/widgets + ghSliderH = gwinCreateSlider(NULL, 5, 5, swidth-10, SLIDER_WIDTH); + ghSliderV = gwinCreateSlider(NULL, 5, 10+SLIDER_WIDTH, SLIDER_WIDTH, sheight-15+SLIDER_WIDTH); + ghConsole = gwinCreateConsole(NULL, 10+SLIDER_WIDTH, 10+SLIDER_WIDTH, swidth-15-SLIDER_WIDTH, sheight-15-SLIDER_WIDTH, fui2); + consout = gwinGetConsoleStream(ghConsole); + + // Color up the console window + gwinSetColor(ghConsole, White); + gwinSetBgColor(ghConsole, Blue); + + // Assign the mouse to the sliders. + gsMouse = ginputGetMouse(0); + gwinAttachSliderMouseSource(ghSliderH, gsMouse); + gwinAttachSliderMouseSource(ghSliderV, gsMouse); + + // We want to listen for slider events + geventListenerInit(&gl); + geventAttachSource(&gl, gwinGetSliderSource(ghSliderH), 0); + geventAttachSource(&gl, gwinGetSliderSource(ghSliderV), 0); + + // Draw everything on the screen + gwinClear(ghConsole); + gwinSliderDraw(ghSliderH); + gwinSliderDraw(ghSliderV); + + while(1) { + // Get an Event + // - we can assume it is a slider event as that is all we are listening for + pSliderEvent = (GEventGWinSlider *)geventEventWait(&gl, TIME_INFINITE); + + // Double check that assumption + if (pSliderEvent->type != GEVENT_GWIN_SLIDER) + continue; + + chprintf(consout, "%c=%d\n", pSliderEvent->slider == ghSliderH ? 'H' : 'V', pSliderEvent->position); + } + + return 0; +} diff --git a/demos/modules/gwin/slider/result_647x490.png b/demos/modules/gwin/slider/result_647x490.png new file mode 100644 index 00000000..c7b12a93 Binary files /dev/null and b/demos/modules/gwin/slider/result_647x490.png differ diff --git a/gfxconf.example.h b/gfxconf.example.h index c9a91f2d..5d29600f 100644 --- a/gfxconf.example.h +++ b/gfxconf.example.h @@ -76,6 +76,7 @@ #define GWIN_NEED_BUTTON FALSE #define GWIN_NEED_CONSOLE FALSE #define GWIN_NEED_GRAPH FALSE +#define GWIN_NEED_SLIDER FALSE /* Features for the GEVENT subsystem. */ #define GEVENT_ASSERT_NO_RESOURCE FALSE diff --git a/include/gwin/gwin.h b/include/gwin/gwin.h index e6b42b31..47c2e38d 100644 --- a/include/gwin/gwin.h +++ b/include/gwin/gwin.h @@ -488,6 +488,29 @@ 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); #endif +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) + /** + * @brief Draw the image + * @return GDISP_IMAGE_ERR_OK (0) on success or an error code. + * + * @param[in] gh The window handle + * @param[in] img The image structure + * @param[in] x,y The window location to draw the image + * @param[in] cx,cy The area on the screen to draw + * @param[in] sx,sy The image position to start drawing at + * + * @pre gdispImageOpen() must have returned successfully. + * + * @note If sx,sy + cx,cy is outside the image boundaries the area outside the image + * is simply not drawn. + * @note If @p gdispImageCache() has been called first for this frame, this routine will draw using a + * fast blit from the cached frame. If not, it reads the input and decodes it as it + * is drawing. This may be significantly slower than if the image has been cached (but + * uses a lot less RAM) + */ + gdispImageError gwinImageDraw(GHandle gh, gdispImage *img, coord_t x, coord_t y, coord_t cx, coord_t cy, coord_t sx, coord_t sy); +#endif + #ifdef __cplusplus } #endif @@ -496,6 +519,7 @@ void gwinBlitArea(GHandle gh, coord_t x, coord_t y, coord_t cx, coord_t cy, coor #include "gwin/console.h" #include "gwin/button.h" #include "gwin/graph.h" +#include "gwin/slider.h" #endif /* GFX_USE_GWIN */ diff --git a/include/gwin/options.h b/include/gwin/options.h index 4ec9ba5d..e8d527e0 100644 --- a/include/gwin/options.h +++ b/include/gwin/options.h @@ -59,6 +59,13 @@ #ifndef GWIN_NEED_GRAPH #define GWIN_NEED_GRAPH FALSE #endif + /** + * @brief Should slider functions be included. + * @details Defaults to FALSE + */ + #ifndef GWIN_NEED_SLIDER + #define GWIN_NEED_SLIDER FALSE + #endif /** * @} * diff --git a/include/gwin/slider.h b/include/gwin/slider.h new file mode 100644 index 00000000..c7599b33 --- /dev/null +++ b/include/gwin/slider.h @@ -0,0 +1,233 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * @file include/gwin/slider.h + * @brief GWIN Graphic window subsystem header file. + * + * @defgroup Slider Slider + * @ingroup GWIN + * + * @details Create sliders with different styles + * + * @pre GFX_USE_GWIN must be set to TRUE in your gfxconf.h + * @pre GWIN_NEED_SLIDER must be set to TRUE in your gfxconf.h + * @{ + */ + +#ifndef _GWIN_SLIDER_H +#define _GWIN_SLIDER_H + +#if GWIN_NEED_SLIDER || defined(__DOXYGEN__) + +/*===========================================================================*/ +/* Driver constants. */ +/*===========================================================================*/ + +#define GW_SLIDER 0x0004 +#define GEVENT_GWIN_SLIDER (GEVENT_GWIN_FIRST+1) + +/*===========================================================================*/ +/* Type definitions */ +/*===========================================================================*/ + +typedef struct GEventGWinSlider_t { + GEventType type; // The type of this event (GEVENT_GWIN_BUTTON) + GHandle slider; // The slider that is returning results + int position; +} GEventGWinSlider; + +// There are currently no GEventGWinSlider listening flags - use 0 + +typedef struct GSliderDrawStyle_t { + color_t color_edge; + color_t color_thumb; + color_t color_active; + color_t color_inactive; +} GSliderDrawStyle; + +typedef void (*GSliderDrawFunction)(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param); + +// A button window +typedef struct GSliderObject_t { + GWindowObject gwin; + + GSliderDrawStyle style; + bool_t tracking; + int min; + int max; + int pos; + GSliderDrawFunction fn; + void *param; + GListener listener; +} GSliderObject; + +/*===========================================================================*/ +/* External declarations. */ +/*===========================================================================*/ + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @brief Create a slider window. + * @return NULL if there is no resultant drawing area, otherwise a window handle. + * + * @param[in] gb The GSliderObject structure to initialise. If this is NULL the structure is dynamically allocated. + * @param[in] x,y The screen co-ordinates for the bottom left corner of the window + * @param[in] width The width of the window + * @param[in] height The height of the window + * @note The drawing color gets set to White and the background drawing color to Black. + * @note The dimensions and position may be changed to fit on the real screen. + * @note The slider is not automatically drawn. Call gwinSliderDraw() after changing the slider style. + * @note Sets the slider range from 0 to 100 with an initial position of 0 + * + * @api + */ +GHandle gwinCreateSlider(GSliderObject *gb, coord_t x, coord_t y, coord_t width, coord_t height); + +/** + * @brief Set the slider range. + * + * @param[in] gh The window handle (must be a slider window) + * @param[in] min The minimum value + * @param[in] max The maximum value + * @note Sets the position to the minimum value. + * @note The slider is not automatically drawn. Call gwinSliderDraw() after changing the range. + * + * @api + */ +void gwinSetSliderRange(GHandle gh, int min, int max); + +/** + * @brief Set the slider position. + * + * @param[in] gh The window handle (must be a slider window) + * @param[in] pos The new position + * @note If the new position is outside the slider range then the position + * is set to the closest end of the range. + * @note The slider is not automatically drawn. Call gwinSliderDraw() after changing the position. + * + * @api + */ +void gwinSetSliderPosition(GHandle gh, int pos); + +/** + * @brief Set the style of a slider. + * @details The slider style is defined by its colours. + * + * @param[in] gh The window handle (must be a slider window) + * @param[in] pStyle The styling for the slider. + * + * @note The slider is not automatically redrawn. Call gwinSliderDraw() after changing the slider style + * @note The slider style is copied into the internal slider structure - there is no need to + * maintain a static style structure. + * + * @api + */ +void gwinSetSliderStyle(GHandle gh, const GSliderDrawStyle *pStyle); + +/** + * @brief Redraw the slider. + * + * @param[in] gh The window handle (must be a slider window) + * + * @api + */ +void gwinSliderDraw(GHandle gh); + +/** + * @brief Set the callback routine to perform a custom button drawing. + * + * @param[in] gh The window handle (must be a button window) + * @param[in] fn The function to use to draw the button + * @param[in] param A parameter to pass to the button drawing function + * + * @api + */ +void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param); + +/** + * @brief Get the current slider position. + * @return The slider position + * + * @param[in] gh The window handle (must be a button window) + * + * @note The use of a listener to get the slider position is recommended if you + * want continuous updates on the slider position. + * + * @api + */ +#define gwinGetSliderPosition(gh) (((GSliderObject *)(gh))->pos) + +/** + * @brief Get the source handle of a slider + * @details Get the source handle of a slider so the application can listen for events + * + * @param[in] gh The window handle + * + * @api + */ +#define gwinGetSliderSource(gh) ((GSourceHandle)(gh)) + +#if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE + /** + * @brief Attach a mouse source + * @details Attach a mouse source to a slider + * + * @param[in] gh The button handle + * @param[in] gsh The source handle + * + * @api + */ + bool_t gwinAttachSliderMouseSource(GHandle gh, GSourceHandle gsh); +#endif + +/** + * @brief Standard slider drawing routines + * @details This routine is called to draw the standard slider. + * + * @param[in] gh The button handle + * @param[in] isVertical The slider is vertically oriented instead of horizontal + * @param[in] thumbpos The position of the slider (0..cx-1 or cy-1..0) + * @param[in] pstyle The current drawing style + * @param[in] param A parameter passed in from the user + * + * @note In your custom slider drawing function you may optionally call this + * standard functions and then draw your extra details on top. + * @note The standard functions below ignore the param parameter. It is there + * only to ensure the functions match the GSliderDrawFunction type. + * @note When called by a slider the framework ensure that it is + * a slider object and sets up clipping to the slider object window. These + * drawing routines then don't have to worry about explicitly doing that. + * + * @api + */ +void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param); + +#ifdef __cplusplus +} +#endif + +#endif /* GWIN_NEED_SLIDER */ + +#endif /* _GWIN_SLIDER_H */ +/** @} */ + diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index a2b702e2..58d75694 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -89,6 +89,12 @@ void gwinDestroyWindow(GHandle gh) { 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; @@ -285,6 +291,15 @@ 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) { + #if GDISP_NEED_CLIP + gdispSetClip(gh->x, gh->y, gh->width, gh->height); + #endif + return gdispImageDraw(img, gh->x+x, gh->y+y, cx, cy, sx, sy); + } +#endif + #endif /* GFX_USE_GWIN */ /** @} */ diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk index 34a57c91..804d5ac9 100644 --- a/src/gwin/gwin.mk +++ b/src/gwin/gwin.mk @@ -1,5 +1,6 @@ GFXSRC += $(GFXLIB)/src/gwin/gwin.c \ $(GFXLIB)/src/gwin/console.c \ $(GFXLIB)/src/gwin/button.c \ + $(GFXLIB)/src/gwin/slider.c \ $(GFXLIB)/src/gwin/graph.c diff --git a/src/gwin/slider.c b/src/gwin/slider.c new file mode 100644 index 00000000..034ba6b2 --- /dev/null +++ b/src/gwin/slider.c @@ -0,0 +1,281 @@ +/* + ChibiOS/GFX - Copyright (C) 2012, 2013 + Joel Bodenmann aka Tectu + + This file is part of ChibiOS/GFX. + + ChibiOS/GFX is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + ChibiOS/GFX is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ +/** + * @file src/gwin/slider.c + * @brief GWIN sub-system slider code. + * + * @defgroup Slider Slider + * @ingroup GWIN + * + * @{ + */ + +#include "ch.h" +#include "hal.h" +#include "gfx.h" + +#if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__) + +#include "gwin/internal.h" + +#ifndef GWIN_SLIDER_DEAD_BAND + #define GWIN_SLIDER_DEAD_BAND 5 +#endif + +static void trackSliderDraw(GHandle gh, coord_t x, coord_t y); + +static const GSliderDrawStyle GSliderDefaultStyle = { + HTML2COLOR(0x404040), // color_edge; + HTML2COLOR(0x000000), // color_thumb; + HTML2COLOR(0x00E000), // color_active; + HTML2COLOR(0xE0E0E0), // color_inactive; +}; + +// 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 pse ((GEventGWinSlider *)pe) + + switch (pe->type) { + #if defined(GINPUT_NEED_MOUSE) && 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; + } + + // 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, + (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, + (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; + } + + // If mouse down - track movement + if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) + trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y); + + return; + #endif + + default: + return; + } + + // 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); + } + + #undef pse + #undef pme + #undef pxe + #undef gsh + #undef gsw + #undef gh +} + +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)))) + return 0; + gs->gwin.type = GW_SLIDER; + gs->fn = gwinSliderDraw_Std; + gs->param = 0; + gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle); + gs->min = 0; + gs->max = 100; + gs->pos = 0; + gs->tracking = FALSE; + geventListenerInit(&gs->listener); + geventRegisterCallback(&gs->listener, gwinSliderCallback, gs); + return (GHandle)gs; +} + +void gwinSetSliderRange(GHandle gh, int min, int max) { + #define gsw ((GSliderObject *)gh) + + if (gh->type != GW_SLIDER) + return; + + if (min == max) // prevent divide by 0 errors. + max++; + gsw->min = min; + gsw->max = max; + gsw->pos = min; + #undef gsw +} + +void gwinSetSliderPosition(GHandle gh, int pos) { + #define gsw ((GSliderObject *)gh) + + if (gh->type != GW_SLIDER) + return; + + if (gsw->min <= gsw->max) { + if (pos < gsw->min) gsw->pos = gsw->min; + else if (pos > gsw->max) gsw->pos = gsw->max; + else gsw->pos = pos; + } else { + if (pos > gsw->min) gsw->pos = gsw->min; + else if (pos < gsw->max) gsw->pos = gsw->max; + else gsw->pos = pos; + } + #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 +} + +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 +} + +void gwinSliderDraw(GHandle gh) { + #define gsw ((GSliderObject *)gh) + + if (gh->type != GW_SLIDER) + 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 +} + +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; + + #undef gsw +} + +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); + } 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 defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE + bool_t gwinAttachSliderMouseSource(GHandle gh, GSourceHandle gsh) { + if (gh->type != GW_SLIDER) + return FALSE; + + return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); + } +#endif + +#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ +/** @} */ +