From ee19104dbb51b98a8753414854cc6c5cdee42a55 Mon Sep 17 00:00:00 2001 From: Andrew Hannam Date: Sat, 6 Apr 2013 21:54:19 +1000 Subject: [PATCH] GWIN slider + image support --- demos/modules/gwin/slider/gfxconf.h | 57 ++++ demos/modules/gwin/slider/main.c | 89 ++++++ demos/modules/gwin/slider/result_647x490.png | Bin 0 -> 24141 bytes gfxconf.example.h | 1 + include/gwin/gwin.h | 24 ++ include/gwin/options.h | 7 + include/gwin/slider.h | 233 +++++++++++++++ src/gwin/gwin.c | 15 + src/gwin/gwin.mk | 1 + src/gwin/slider.c | 281 +++++++++++++++++++ 10 files changed, 708 insertions(+) create mode 100644 demos/modules/gwin/slider/gfxconf.h create mode 100644 demos/modules/gwin/slider/main.c create mode 100644 demos/modules/gwin/slider/result_647x490.png create mode 100644 include/gwin/slider.h create mode 100644 src/gwin/slider.c 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 0000000000000000000000000000000000000000..c7b12a93d71ab2999d901e11ec465f8fee424023 GIT binary patch literal 24141 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

t1Xie$&AcMsDaI1TbiJ=M*?4m?QUen9`wm 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 + + 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 */ +/** @} */ +