ugfx/src/gwin/button.c

336 lines
12 KiB
C
Raw Normal View History

/*
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-05-03 14:36:17 +00:00
* http://chibios-gfx.com/license.html
*/
/**
* @file src/gwin/button.c
* @brief GWIN sub-system button code.
*
* @defgroup Button Button
* @ingroup GWIN
*
* @{
*/
#include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__)
#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
// 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
_gwidgetRedraw, // The redraw 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)
};
// Default color scheme
static const GButtonColors GButtonDefaultColorsUp = {
HTML2COLOR(0x404040), // color_up_edge;
HTML2COLOR(0xE0E0E0), // color_up_fill;
HTML2COLOR(0x000000), // color_up_txt;
2013-03-30 23:52:33 +00:00
};
static const GButtonColors GButtonDefaultColorsDown = {
HTML2COLOR(0x404040), // color_dn_edge;
HTML2COLOR(0x808080), // color_dn_fill;
HTML2COLOR(0x404040), // color_dn_txt;
2013-03-30 23:52:33 +00:00
};
static const GButtonColors GButtonDefaultColorsDisabled = {
HTML2COLOR(0x808080), // color_dis_edge;
HTML2COLOR(0xE0E0E0), // color_dis_fill;
HTML2COLOR(0xC0C0C0), // color_dis_txt;
};
// 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((GSourceHandle)gw, psl))) {
if (!(pe = geventGetEventBuffer(psl)))
continue;
pbe->type = GEVENT_GWIN_BUTTON;
pbe->button = (GHandle)gw;
geventSendEvent(psl);
}
#undef pbe
}
// 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;
_gwidgetRedraw((GHandle)gw);
}
// 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;
_gwidgetRedraw((GHandle)gw);
#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
SendButtonEvent(gw);
}
// A toggle off has occurred
static void ToggleOff(GWidgetObject *gw, uint16_t instance) {
(void) instance;
gw->g.flags &= ~GBUTTON_FLG_PRESSED;
_gwidgetRedraw((GHandle)gw);
}
// A toggle on has occurred
static void ToggleOn(GWidgetObject *gw, uint16_t instance) {
(void) instance;
gw->g.flags |= GBUTTON_FLG_PRESSED;
_gwidgetRedraw((GHandle)gw);
// Trigger the event on button down (different than for mouse/touch)
SendButtonEvent(gw);
}
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;
gw->c_up = GButtonDefaultColorsUp;
gw->c_dn = GButtonDefaultColorsDown;
gw->c_dis = GButtonDefaultColorsDisabled;
return (GHandle)gw;
}
void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled) {
if (gh->vmt != (gwinVMT *)&buttonVMT)
return;
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;
return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE;
}
/*----------------------------------------------------------
* Custom Draw Routines
*----------------------------------------------------------*/
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(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
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_Box(GWidgetObject *gw, void *param) {
(void) param;
GButtonColors * pcol;
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(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(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(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(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(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(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(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 GDISP_NEED_IMAGE || defined(__DOXYGEN__)
void gwinButtonDraw_Image(GWidgetObject *gw, void *param) {
GButtonColors * pcol;
coord_t sy;
if (gw->g.vmt != (gwinVMT *)&buttonVMT) return;
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;
}
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
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */