2013-04-06 11:54:19 +00:00
|
|
|
/*
|
2013-05-03 14:36:17 +00:00
|
|
|
* 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:
|
2013-04-06 11:54:19 +00:00
|
|
|
*
|
2013-05-03 14:36:17 +00:00
|
|
|
* http://chibios-gfx.com/license.html
|
2013-04-06 11:54:19 +00:00
|
|
|
*/
|
|
|
|
|
2013-05-06 04:44:47 +00:00
|
|
|
/**
|
|
|
|
* @file src/gwin/slider.c
|
|
|
|
* @brief GWIN sub-system slider code.
|
|
|
|
*
|
|
|
|
* @defgroup Slider Slider
|
|
|
|
* @ingroup GWIN
|
|
|
|
*
|
|
|
|
* @{
|
|
|
|
*/
|
|
|
|
|
2013-04-06 11:54:19 +00:00
|
|
|
#include "gfx.h"
|
|
|
|
|
|
|
|
#if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__)
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
#include "gwin/class_gwin.h"
|
2013-04-06 11:54:19 +00:00
|
|
|
|
|
|
|
#ifndef GWIN_SLIDER_DEAD_BAND
|
|
|
|
#define GWIN_SLIDER_DEAD_BAND 5
|
|
|
|
#endif
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// 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
|
2013-06-07 16:27:59 +00:00
|
|
|
_gwidgetRedraw, // The redraw routine
|
2013-06-06 04:33:32 +00:00
|
|
|
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)
|
|
|
|
};
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
static const GSliderColors GSliderDefaultColors = {
|
|
|
|
HTML2COLOR(0x404040), // color_edge
|
|
|
|
HTML2COLOR(0x000000), // color_thumb
|
|
|
|
HTML2COLOR(0x00E000), // color_active
|
|
|
|
HTML2COLOR(0xE0E0E0), // color_inactive
|
|
|
|
HTML2COLOR(0xFFFFFF), // color_txt
|
2013-04-06 11:54:19 +00:00
|
|
|
};
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// Send the slider event
|
|
|
|
static void SendSliderEvent(GWidgetObject *gw) {
|
|
|
|
GSourceListener * psl;
|
|
|
|
GEvent * pe;
|
|
|
|
#define pse ((GEventGWinSlider *)pe)
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// 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);
|
|
|
|
}
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
#undef pbe
|
|
|
|
}
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// 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);
|
2013-06-07 16:27:59 +00:00
|
|
|
_gwidgetRedraw(gh);
|
2013-04-06 11:54:19 +00:00
|
|
|
return;
|
2013-06-06 04:33:32 +00:00
|
|
|
}
|
2013-04-06 11:54:19 +00:00
|
|
|
#endif
|
2013-04-07 06:02:10 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// Set the new position
|
2013-06-06 06:48:30 +00:00
|
|
|
if (gh->width < gh->height) {
|
|
|
|
if (y > gh->height-GWIN_SLIDER_DEAD_BAND)
|
|
|
|
gsw->pos = gsw->min;
|
|
|
|
else if (y < GWIN_SLIDER_DEAD_BAND)
|
|
|
|
gsw->pos = gsw->max;
|
|
|
|
else
|
|
|
|
gsw->pos = (uint16_t)((int32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
|
|
|
|
} else {
|
|
|
|
if (x > gh->width-GWIN_SLIDER_DEAD_BAND)
|
|
|
|
gsw->pos = gsw->max;
|
|
|
|
else if (x < GWIN_SLIDER_DEAD_BAND)
|
|
|
|
gsw->pos = gsw->min;
|
|
|
|
else
|
|
|
|
gsw->pos = (uint16_t)((int32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min);
|
|
|
|
}
|
2013-04-07 06:02:10 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
ResetDisplayPos(gsw);
|
2013-06-07 16:27:59 +00:00
|
|
|
_gwidgetRedraw(gh);
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// Generate the event
|
|
|
|
SendSliderEvent(gw);
|
|
|
|
#undef gh
|
|
|
|
#undef gsw
|
|
|
|
}
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// 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;
|
2013-04-06 11:54:19 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// Update the display
|
2013-06-07 16:27:59 +00:00
|
|
|
_gwidgetRedraw(&gw->g);
|
2013-04-06 11:54:19 +00:00
|
|
|
#undef gsw
|
2013-06-06 04:33:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
2013-04-06 11:54:19 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
GHandle gwinCreateSlider(GSliderObject *gs, coord_t x, coord_t y, coord_t width, coord_t height) {
|
2013-06-06 04:33:32 +00:00
|
|
|
if (!(gs = (GSliderObject *)_gwidgetInit((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT)))
|
2013-04-06 11:54:19 +00:00
|
|
|
return 0;
|
2013-06-06 04:33:32 +00:00
|
|
|
gs->c = GSliderDefaultColors;
|
2013-04-06 11:54:19 +00:00
|
|
|
gs->min = 0;
|
|
|
|
gs->max = 100;
|
|
|
|
gs->pos = 0;
|
2013-06-06 04:33:32 +00:00
|
|
|
ResetDisplayPos(gs);
|
2013-04-06 11:54:19 +00:00
|
|
|
return (GHandle)gs;
|
|
|
|
}
|
|
|
|
|
|
|
|
void gwinSetSliderRange(GHandle gh, int min, int max) {
|
|
|
|
#define gsw ((GSliderObject *)gh)
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
if (gh->vmt != (gwinVMT *)&sliderVMT)
|
2013-04-06 11:54:19 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (min == max) // prevent divide by 0 errors.
|
|
|
|
max++;
|
|
|
|
gsw->min = min;
|
|
|
|
gsw->max = max;
|
|
|
|
gsw->pos = min;
|
2013-06-06 04:33:32 +00:00
|
|
|
ResetDisplayPos(gsw);
|
2013-04-06 11:54:19 +00:00
|
|
|
#undef gsw
|
|
|
|
}
|
|
|
|
|
|
|
|
void gwinSetSliderPosition(GHandle gh, int pos) {
|
|
|
|
#define gsw ((GSliderObject *)gh)
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
if (gh->vmt != (gwinVMT *)&sliderVMT)
|
2013-04-06 11:54:19 +00:00
|
|
|
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;
|
|
|
|
}
|
2013-06-06 04:33:32 +00:00
|
|
|
ResetDisplayPos(gsw);
|
2013-04-06 11:54:19 +00:00
|
|
|
#undef gsw
|
|
|
|
}
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) {
|
|
|
|
if (gh->vmt != (gwinVMT *)&sliderVMT)
|
2013-04-06 11:54:19 +00:00
|
|
|
return;
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
((GSliderObject *)gh)->c = *pColors;
|
2013-04-06 11:54:19 +00:00
|
|
|
}
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
void gwinSliderDraw_Std(GWidgetObject *gw, void *param) {
|
|
|
|
#define gsw ((GSliderObject *)gw)
|
|
|
|
(void) param;
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
if (gw->g.vmt != (gwinVMT *)&sliderVMT)
|
2013-04-06 11:54:19 +00:00
|
|
|
return;
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
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);
|
2013-04-06 11:54:19 +00:00
|
|
|
|
|
|
|
#undef gsw
|
|
|
|
}
|
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
void gwinSliderDraw_Image(GWidgetObject *gw, void *param) {
|
|
|
|
#define gsw ((GSliderObject *)gw)
|
|
|
|
#define gi ((gdispImage *)param)
|
|
|
|
coord_t z, v;
|
2013-05-27 10:53:34 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
if (gw->g.vmt != (gwinVMT *)&sliderVMT)
|
|
|
|
return;
|
2013-05-27 10:53:34 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
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);
|
2013-04-06 11:54:19 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
// Horizontal slider
|
2013-04-06 11:54:19 +00:00
|
|
|
} else {
|
2013-06-06 04:33:32 +00:00
|
|
|
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);
|
2013-04-06 11:54:19 +00:00
|
|
|
}
|
2013-06-06 04:33:32 +00:00
|
|
|
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);
|
2013-04-07 06:02:10 +00:00
|
|
|
|
2013-06-06 04:33:32 +00:00
|
|
|
#undef gsw
|
|
|
|
}
|
2013-04-07 06:02:10 +00:00
|
|
|
|
2013-04-06 11:54:19 +00:00
|
|
|
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
|
|
|
|
/** @} */
|
|
|
|
|