Add option GWIN_BUTTON_LAZY_RELEASE

Add option GWIN_BUTTON_LAZY_RELEASE. When set to true in gfxconf.h it
changes gwin button behaviour to not require the mouse/touch be over the
button when it is released.
ugfx_release_2.6
Andrew Hannam 2013-03-02 22:20:57 +10:00
parent 57435fb4c2
commit dddbb25930
3 changed files with 354 additions and 346 deletions

View File

@ -87,6 +87,7 @@
#define GEVENT_MAX_SOURCE_LISTENERS 32 #define GEVENT_MAX_SOURCE_LISTENERS 32
#define GTIMER_THREAD_WORKAREA_SIZE 512 #define GTIMER_THREAD_WORKAREA_SIZE 512
#define GADC_MAX_LOWSPEED_DEVICES 4 #define GADC_MAX_LOWSPEED_DEVICES 4
#define GWIN_BUTTON_LAZY_RELEASE FALSE
*/ */
/* Optional Low Level Driver Definitions */ /* Optional Low Level Driver Definitions */

View File

@ -1,71 +1,74 @@
/* /*
ChibiOS/GFX - Copyright (C) 2012 ChibiOS/GFX - Copyright (C) 2012
Joel Bodenmann aka Tectu <joel@unormal.org> Joel Bodenmann aka Tectu <joel@unormal.org>
This file is part of ChibiOS/GFX. This file is part of ChibiOS/GFX.
ChibiOS/GFX is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/GFX is distributed in the hope that it will be useful, ChibiOS/GFX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @file include/gwin/options.h * @file include/gwin/options.h
* @brief GWIN sub-system options header file. * @brief GWIN sub-system options header file.
* *
* @addtogroup GWIN * @addtogroup GWIN
* @{ * @{
*/ */
#ifndef _GWIN_OPTIONS_H #ifndef _GWIN_OPTIONS_H
#define _GWIN_OPTIONS_H #define _GWIN_OPTIONS_H
/** /**
* @name GWIN Functionality to be included * @name GWIN Functionality to be included
* @{ * @{
*/ */
/** /**
* @brief Should button functions be included. * @brief Should button functions be included.
* @details Defaults to FALSE * @details Defaults to FALSE
*/ */
#ifndef GWIN_NEED_BUTTON #ifndef GWIN_NEED_BUTTON
#define GWIN_NEED_BUTTON FALSE #define GWIN_NEED_BUTTON FALSE
#endif #endif
/** /**
* @brief Should console functions be included. * @brief Should console functions be included.
* @details Defaults to FALSE * @details Defaults to FALSE
* @note To use chprintf() for printing in a console window you need to * @note To use chprintf() for printing in a console window you need to
* include in your application source file... * include in your application source file...
* \#include "chprintf.h" * \#include "chprintf.h"
* Also in your makefile, as part of your list of C source files, include * Also in your makefile, as part of your list of C source files, include
* ${CHIBIOS}/os/various/chprintf.c * ${CHIBIOS}/os/various/chprintf.c
*/ */
#ifndef GWIN_NEED_CONSOLE #ifndef GWIN_NEED_CONSOLE
#define GWIN_NEED_CONSOLE FALSE #define GWIN_NEED_CONSOLE FALSE
#endif #endif
/** /**
* @brief Should graph functions be included. * @brief Should graph functions be included.
* @details Defaults to FALSE * @details Defaults to FALSE
*/ */
#ifndef GWIN_NEED_GRAPH #ifndef GWIN_NEED_GRAPH
#define GWIN_NEED_GRAPH FALSE #define GWIN_NEED_GRAPH FALSE
#endif #endif
/** /**
* @} * @}
* *
* @name GWIN Optional Sizing Parameters * @name GWIN Optional Parameters
* @{ * @{
*/ */
/** @} */ #ifndef GWIN_BUTTON_LAZY_RELEASE
#define GWIN_BUTTON_LAZY_RELEASE FALSE
#endif /* _GWIN_OPTIONS_H */ #endif
/** @} */ /** @} */
#endif /* _GWIN_OPTIONS_H */
/** @} */

View File

@ -1,275 +1,279 @@
/* /*
ChibiOS/GFX - Copyright (C) 2012 ChibiOS/GFX - Copyright (C) 2012
Joel Bodenmann aka Tectu <joel@unormal.org> Joel Bodenmann aka Tectu <joel@unormal.org>
This file is part of ChibiOS/GFX. This file is part of ChibiOS/GFX.
ChibiOS/GFX is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or the Free Software Foundation; either version 3 of the License, or
(at your option) any later version. (at your option) any later version.
ChibiOS/GFX is distributed in the hope that it will be useful, ChibiOS/GFX is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. along with this program. If not, see <http://www.gnu.org/licenses/>.
*/ */
/** /**
* @file src/gwin/button.c * @file src/gwin/button.c
* @brief GWIN sub-system button code. * @brief GWIN sub-system button code.
* *
* @defgroup Button Button * @defgroup Button Button
* @ingroup GWIN * @ingroup GWIN
* *
* @{ * @{
*/ */
#include "ch.h" #include "ch.h"
#include "hal.h" #include "hal.h"
#include "gfx.h" #include "gfx.h"
#if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__) #if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__)
#include <string.h> #include <string.h>
#include "gwin/internal.h" #include "gwin/internal.h"
static const GButtonStyle GButtonDefaultStyle = { static const GButtonStyle GButtonDefaultStyle = {
GBTN_3D, GBTN_3D,
HTML2COLOR(0x404040), // color_up_edge; HTML2COLOR(0x404040), // color_up_edge;
HTML2COLOR(0xE0E0E0), // color_up_fill; HTML2COLOR(0xE0E0E0), // color_up_fill;
HTML2COLOR(0x000000), // color_up_txt; HTML2COLOR(0x000000), // color_up_txt;
HTML2COLOR(0x404040), // color_dn_edge; HTML2COLOR(0x404040), // color_dn_edge;
HTML2COLOR(0x808080), // color_dn_fill; HTML2COLOR(0x808080), // color_dn_fill;
HTML2COLOR(0x404040), // color_dn_txt; HTML2COLOR(0x404040), // color_dn_txt;
}; };
// Process an event callback // Process an event callback
static void gwinButtonCallback(void *param, GEvent *pe) { static void gwinButtonCallback(void *param, GEvent *pe) {
GSourceListener *psl; GSourceListener *psl;
#define gh ((GHandle)param) #define gh ((GHandle)param)
#define gbw ((GButtonObject *)param) #define gbw ((GButtonObject *)param)
#define gsh ((GSourceHandle)param) #define gsh ((GSourceHandle)param)
#define pme ((GEventMouse *)pe) #define pme ((GEventMouse *)pe)
#define pte ((GEventTouch *)pe) #define pte ((GEventTouch *)pe)
#define pxe ((GEventToggle *)pe) #define pxe ((GEventToggle *)pe)
#define pbe ((GEventGWinButton *)pe) #define pbe ((GEventGWinButton *)pe)
switch (pe->type) { switch (pe->type) {
#if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE #if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE
case GEVENT_MOUSE: case GEVENT_MOUSE:
case GEVENT_TOUCH: case GEVENT_TOUCH:
// Ignore anything other than the primary mouse button going up or down // Ignore anything other than the primary mouse button going up or down
if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT)) if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT))
return; return;
if (gbw->state == GBTN_UP) { if (gbw->state == GBTN_UP) {
// Our button is UP: Test for button down over the button // Our button is UP: Test for button down over the button
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)
&& pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width && pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) { && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) {
gbw->state = GBTN_DOWN; gbw->state = GBTN_DOWN;
gwinButtonDraw((GHandle)param); gwinButtonDraw((GHandle)param);
} }
return; return;
} }
// Our button is DOWN // Our button is DOWN
// Skip more mouse downs // Skip more mouse downs
if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT))
return; return;
// This must be a mouse up - set the button as UP // This must be a mouse up - set the button as UP
gbw->state = GBTN_UP; gbw->state = GBTN_UP;
gwinButtonDraw((GHandle)param); gwinButtonDraw((GHandle)param);
// If the mouse up was over the button then create the event #if GWIN_BUTTON_LAZY_RELEASE
if (pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width break;
&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) #else
break; // If the mouse up was over the button then create the event
if (pme->x >= gbw->gwin.x && pme->x < gbw->gwin.x + gbw->gwin.width
return; && pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height)
#endif break;
#if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE return;
case GEVENT_TOGGLE: #endif
// State has changed - update the button #endif
gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP;
gwinButtonDraw((GHandle)param); #if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE
case GEVENT_TOGGLE:
// Trigger the event on button down (different than for mouse/touch) // State has changed - update the button
if (gbw->state == GBTN_DOWN) gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP;
break; gwinButtonDraw((GHandle)param);
return; // Trigger the event on button down (different than for mouse/touch)
#endif if (gbw->state == GBTN_DOWN)
break;
default:
return; return;
} #endif
// Trigger a GWIN Button Event default:
psl = 0; return;
while ((psl = geventGetSourceListener(gsh, psl))) { }
if (!(pe = geventGetEventBuffer(psl)))
continue; // Trigger a GWIN Button Event
pbe->type = GEVENT_GWIN_BUTTON; psl = 0;
pbe->button = gh; while ((psl = geventGetSourceListener(gsh, psl))) {
geventSendEvent(psl); if (!(pe = geventGetEventBuffer(psl)))
} continue;
pbe->type = GEVENT_GWIN_BUTTON;
#undef pbe pbe->button = gh;
#undef pme geventSendEvent(psl);
#undef pte }
#undef pxe
#undef gsh #undef pbe
#undef gbw #undef pme
#undef gh #undef pte
} #undef pxe
#undef gsh
GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) { #undef gbw
if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject)))) #undef gh
return 0; }
gb->gwin.type = GW_BUTTON;
gwinSetFont(&gb->gwin, font); GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) {
gwinSetButtonStyle(&gb->gwin, &GButtonDefaultStyle); if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject))))
gb->type = type; return 0;
gb->state = GBTN_UP; gb->gwin.type = GW_BUTTON;
gb->txt = ""; gwinSetFont(&gb->gwin, font);
geventListenerInit(&gb->listener); gwinSetButtonStyle(&gb->gwin, &GButtonDefaultStyle);
geventRegisterCallback(&gb->listener, gwinButtonCallback, gb); gb->type = type;
return (GHandle)gb; gb->state = GBTN_UP;
} gb->txt = "";
geventListenerInit(&gb->listener);
void gwinSetButtonStyle(GHandle gh, const GButtonStyle *style) { geventRegisterCallback(&gb->listener, gwinButtonCallback, gb);
#define gbw ((GButtonObject *)gh) return (GHandle)gb;
if (gh->type != GW_BUTTON) }
return;
void gwinSetButtonStyle(GHandle gh, const GButtonStyle *style) {
gbw->style.shape = style->shape; #define gbw ((GButtonObject *)gh)
gbw->style.color_up_edge = style->color_up_edge; if (gh->type != GW_BUTTON)
gbw->style.color_up_fill = style->color_up_fill; return;
gbw->style.color_dn_edge = style->color_dn_edge;
gbw->style.color_dn_fill = style->color_dn_fill; gbw->style.shape = style->shape;
gbw->style.color_up_txt = style->color_up_txt; gbw->style.color_up_edge = style->color_up_edge;
gbw->style.color_dn_txt = style->color_dn_txt; gbw->style.color_up_fill = style->color_up_fill;
#undef gbw gbw->style.color_dn_edge = style->color_dn_edge;
} gbw->style.color_dn_fill = style->color_dn_fill;
gbw->style.color_up_txt = style->color_up_txt;
void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) { gbw->style.color_dn_txt = style->color_dn_txt;
#define gbw ((GButtonObject *)gh) #undef gbw
if (gh->type != GW_BUTTON) }
return;
void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) {
// Dispose of the old string #define gbw ((GButtonObject *)gh)
if ((gh->flags & GBTN_FLG_ALLOCTXT)) { if (gh->type != GW_BUTTON)
gh->flags &= ~GBTN_FLG_ALLOCTXT; return;
if (gbw->txt) {
chHeapFree((void *)gbw->txt); // Dispose of the old string
gbw->txt = ""; if ((gh->flags & GBTN_FLG_ALLOCTXT)) {
} gh->flags &= ~GBTN_FLG_ALLOCTXT;
} if (gbw->txt) {
// Alloc the new text if required chHeapFree((void *)gbw->txt);
if (txt && useAlloc) { gbw->txt = "";
char *str; }
}
if ((str = (char *)chHeapAlloc(NULL, strlen(txt)+1))) { // Alloc the new text if required
gh->flags |= GBTN_FLG_ALLOCTXT; if (txt && useAlloc) {
strcpy(str, txt); char *str;
}
txt = (const char *)str; if ((str = (char *)chHeapAlloc(NULL, strlen(txt)+1))) {
} gh->flags |= GBTN_FLG_ALLOCTXT;
strcpy(str, txt);
gbw->txt = txt ? txt : ""; }
#undef gbw txt = (const char *)str;
} }
void gwinButtonDraw(GHandle gh) { gbw->txt = txt ? txt : "";
color_t cedge; #undef gbw
color_t cfill; }
color_t ctxt;
const char * txt; void gwinButtonDraw(GHandle gh) {
#define gbw ((GButtonObject *)gh) color_t cedge;
#define RND_CNR_SIZE 5 color_t cfill;
color_t ctxt;
if (gh->type != GW_BUTTON) const char * txt;
return; #define gbw ((GButtonObject *)gh)
#define RND_CNR_SIZE 5
#if GDISP_NEED_CLIP
gdispSetClip(gh->x, gh->y, gh->width, gh->height); if (gh->type != GW_BUTTON)
#endif return;
// Get the text (safely) #if GDISP_NEED_CLIP
txt = gh->font && gbw->txt ? gbw->txt : ""; gdispSetClip(gh->x, gh->y, gh->width, gh->height);
#endif
// Determine the colors to use
switch(gbw->state) { // Get the text (safely)
case GBTN_DOWN: txt = gh->font && gbw->txt ? gbw->txt : "";
cedge = gbw->style.color_dn_edge;
cfill = gbw->style.color_dn_fill; // Determine the colors to use
ctxt = gbw->style.color_dn_txt; switch(gbw->state) {
break; case GBTN_DOWN:
case GBTN_UP: default: cedge = gbw->style.color_dn_edge;
cedge = gbw->style.color_up_edge; cfill = gbw->style.color_dn_fill;
cfill = gbw->style.color_up_fill; ctxt = gbw->style.color_dn_txt;
ctxt = gbw->style.color_up_txt; break;
break; case GBTN_UP: default:
} cedge = gbw->style.color_up_edge;
cfill = gbw->style.color_up_fill;
// Draw according to the shape specified. ctxt = gbw->style.color_up_txt;
switch(gbw->style.shape) { break;
#if GDISP_NEED_ARC }
case GBTN_ROUNDED:
if (gh->width >= 2*RND_CNR_SIZE+10) { // Draw according to the shape specified.
gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, cfill); switch(gbw->style.shape) {
gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, ctxt, justifyCenter); #if GDISP_NEED_ARC
gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, cedge); case GBTN_ROUNDED:
break; if (gh->width >= 2*RND_CNR_SIZE+10) {
} gdispFillRoundedBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, RND_CNR_SIZE-1, cfill);
/* Fall Through */ gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, ctxt, justifyCenter);
#endif gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, cedge);
case GBTN_SQUARE: break;
gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, cfill, justifyCenter); }
gdispDrawBox(gh->x, gh->y, gh->width, gh->height, cedge); /* Fall Through */
break; #endif
#if GDISP_NEED_ELLIPSE case GBTN_SQUARE:
case GBTN_ELLIPSE: gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, cfill, justifyCenter);
gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, cfill); gdispDrawBox(gh->x, gh->y, gh->width, gh->height, cedge);
gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, justifyCenter); break;
gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, cedge); #if GDISP_NEED_ELLIPSE
break; case GBTN_ELLIPSE:
#endif gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, cfill);
case GBTN_3D: default: gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, ctxt, justifyCenter);
gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, ctxt, cfill, justifyCenter); gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, cedge);
gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, cedge); break;
gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, cedge); #endif
break; case GBTN_3D: default:
} gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, ctxt, cfill, justifyCenter);
#undef gbw gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, cedge);
} gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, cedge);
break;
#if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE }
bool_t gwinAttachButtonMouseSource(GHandle gh, GSourceHandle gsh) { #undef gbw
if (gh->type != GW_BUTTON) }
return FALSE;
#if defined(GINPUT_NEED_MOUSE) && GINPUT_NEED_MOUSE
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); bool_t gwinAttachButtonMouseSource(GHandle gh, GSourceHandle gsh) {
} if (gh->type != GW_BUTTON)
#endif return FALSE;
#if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA);
bool_t gwinAttachButtonToggleSource(GHandle gh, GSourceHandle gsh) { }
if (gh->type != GW_BUTTON) #endif
return FALSE;
#if defined(GINPUT_NEED_TOGGLE) && GINPUT_NEED_TOGGLE
return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON); bool_t gwinAttachButtonToggleSource(GHandle gh, GSourceHandle gsh) {
} if (gh->type != GW_BUTTON)
#endif return FALSE;
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */ return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON);
/** @} */ }
#endif
#endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */
/** @} */