diff options
| author | inmarket <andrewh@inmarket.com.au> | 2013-06-06 14:33:32 +1000 | 
|---|---|---|
| committer | inmarket <andrewh@inmarket.com.au> | 2013-06-06 14:33:32 +1000 | 
| commit | 7baf5c5d448b626d6a062882434b25ca82212d94 (patch) | |
| tree | 590bea0f81bd4b9e2ebe54c944877ea501e00fa3 /src | |
| parent | eebecad9f7995dacf3f7c053e3d6b42617ec7294 (diff) | |
| download | uGFX-7baf5c5d448b626d6a062882434b25ca82212d94.tar.gz uGFX-7baf5c5d448b626d6a062882434b25ca82212d94.tar.bz2 uGFX-7baf5c5d448b626d6a062882434b25ca82212d94.zip | |
New simplified gwin using a pseudo class structure.
Diffstat (limited to 'src')
| -rw-r--r-- | src/gwin/button.c | 545 | ||||
| -rw-r--r-- | src/gwin/checkbox.c | 225 | ||||
| -rw-r--r-- | src/gwin/console.c | 55 | ||||
| -rw-r--r-- | src/gwin/graph.c | 72 | ||||
| -rw-r--r-- | src/gwin/gwidget.c | 254 | ||||
| -rw-r--r-- | src/gwin/gwin.c | 110 | ||||
| -rw-r--r-- | src/gwin/gwin.mk | 3 | ||||
| -rw-r--r-- | src/gwin/slider.c | 402 | 
8 files changed, 884 insertions, 782 deletions
| diff --git a/src/gwin/button.c b/src/gwin/button.c index cf5babc5..1ebc8ee5 100644 --- a/src/gwin/button.c +++ b/src/gwin/button.c @@ -19,392 +19,313 @@  #if (GFX_USE_GWIN && GWIN_NEED_BUTTON) || defined(__DOXYGEN__) -/* Parameters for various shapes */ +#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 -#include <string.h> - -#include "gwin/internal.h" - -#define GWIN_BUTTON_DEFAULT_SHAPE		GBTN_3D +// 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 +		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) +}; -static const GButtonDrawStyle GButtonDefaultStyleUp = { +// Default color scheme +static const GButtonColors GButtonDefaultColorsUp = {  	HTML2COLOR(0x404040),		// color_up_edge;  	HTML2COLOR(0xE0E0E0),		// color_up_fill;  	HTML2COLOR(0x000000),		// color_up_txt;  }; - -static const GButtonDrawStyle GButtonDefaultStyleDown = { +static const GButtonColors GButtonDefaultColorsDown = {  	HTML2COLOR(0x404040),		// color_dn_edge;  	HTML2COLOR(0x808080),		// color_dn_fill;  	HTML2COLOR(0x404040),		// color_dn_txt;  }; +static const GButtonColors GButtonDefaultColorsDisabled = { +	HTML2COLOR(0x808080),		// color_dis_edge; +	HTML2COLOR(0xE0E0E0),		// color_dis_fill; +	HTML2COLOR(0xC0C0C0),		// color_dis_txt; +}; -// Process an event callback -static void gwinButtonCallback(void *param, GEvent *pe) { -	GSourceListener	*psl; -	#define gh		((GHandle)param) -	#define gbw		((GButtonObject *)param) -	#define gsh		((GSourceHandle)param) -	#define pme		((GEventMouse *)pe) -	#define pte		((GEventTouch *)pe) -	#define pxe		((GEventToggle *)pe) -	#define pbe		((GEventGWinButton *)pe) - -	// check if button is disabled -	if (!gh->enabled) -		return; - -	switch (pe->type) { -	#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -		case GEVENT_MOUSE: -		case GEVENT_TOUCH: -			// Ignore anything other than the primary mouse button going up or down -			if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT)) -				return; - -			if (gbw->state == GBTN_UP) { -				// Our button is UP: Test for button down over the button -				if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) -						&& 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) { -					gbw->state = GBTN_DOWN; -					gwinButtonDraw((GHandle)param); -				} -				return; -			} - -			// Our button is DOWN - -			// Skip more mouse downs -			if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) -				return; - -			// This must be a mouse up - set the button as UP -			gbw->state = GBTN_UP; -			gwinButtonDraw((GHandle)param); - -			#if GWIN_BUTTON_LAZY_RELEASE -				break; -			#else -				// 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 -						&& pme->y >= gbw->gwin.y && pme->y < gbw->gwin.y + gbw->gwin.height) -					break; - -				return; -			#endif -	#endif - -	#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE -		case GEVENT_TOGGLE: -			// State has changed - update the button -			gbw->state = pxe->on ? GBTN_DOWN : GBTN_UP; -			gwinButtonDraw((GHandle)param); - -			// Trigger the event on button down (different than for mouse/touch) -			if (gbw->state == GBTN_DOWN) -				break; - -			return; -	#endif - -	default: -		return; -	} +// 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(gsh, psl))) { +	while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {  		if (!(pe = geventGetEventBuffer(psl)))  			continue;  		pbe->type = GEVENT_GWIN_BUTTON; -		pbe->button = gh; +		pbe->button = (GHandle)gw;  		geventSendEvent(psl);  	}  	#undef pbe -	#undef pme -	#undef pte -	#undef pxe -	#undef gsh -	#undef gbw -	#undef gh  } -GHandle gwinCreateButton(GButtonObject *gb, coord_t x, coord_t y, coord_t width, coord_t height, font_t font, GButtonType type) { -	if (!(gb = (GButtonObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GButtonObject)))) -		return 0; - -	gb->gwin.type = GW_BUTTON; -	gb->fn = 0; -	gb->param = 0; -	gwinSetFont(&gb->gwin, font); -	gwinSetButtonStyle(&gb->gwin, GWIN_BUTTON_DEFAULT_SHAPE, &GButtonDefaultStyleUp, &GButtonDefaultStyleDown); -	gb->type = type; -	gb->state = GBTN_UP; -	gb->txt = ""; -	geventListenerInit(&gb->listener); -	geventRegisterCallback(&gb->listener, gwinButtonCallback, gb); - -	// buttons are enabled by default -	gb->gwin.enabled = TRUE; - -	return (GHandle)gb; +// 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; +	gwinDraw((GHandle)gw);  } -void gwinSetButtonStyle(GHandle gh, GButtonShape shape, const GButtonDrawStyle *pUp, const GButtonDrawStyle *pDown) { -	#define gbw		((GButtonObject *)gh) -	if (gh->type != GW_BUTTON) -		return; - -	switch(shape) { -		case GBTN_SQUARE:		gbw->fn = gwinButtonDraw_Square;		break; -		#if GDISP_NEED_ARC -			case GBTN_ROUNDED:	gbw->fn = gwinButtonDraw_Rounded;		break; -		#endif -		#if GDISP_NEED_ELLIPSE -			case GBTN_ELLIPSE:	gbw->fn = gwinButtonDraw_Ellipse;		break; -		#endif - -		#if GDISP_NEED_CONVEX_POLYGON -			case GBTN_ARROW_UP:		gbw->fn = gwinButtonDraw_ArrowUp;		break; -			case GBTN_ARROW_DOWN:	gbw->fn = gwinButtonDraw_ArrowDown;		break; -			case GBTN_ARROW_LEFT:	gbw->fn = gwinButtonDraw_ArrowLeft;		break; -			case GBTN_ARROW_RIGHT:	gbw->fn = gwinButtonDraw_ArrowRight;	break; -		#endif - -		case GBTN_CUSTOM:		if (gbw->fn)	break;		/* Fall Through */ -		case GBTN_3D:			/* Fall through */ -		default:				gbw->fn = gwinButtonDraw_3D;			break; -	} -	if (pUp) { -		gbw->up.color_edge = pUp->color_edge; -		gbw->up.color_fill = pUp->color_fill; -		gbw->up.color_txt = pUp->color_txt; -	} -	if (pDown) { -		gbw->dn.color_edge = pDown->color_edge; -		gbw->dn.color_fill = pDown->color_fill; -		gbw->dn.color_txt = pDown->color_txt; -	} -	#undef gbw -} +// 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; +	gwinDraw((GHandle)gw); -void gwinSetButtonText(GHandle gh, const char *txt, bool_t useAlloc) { -	#define gbw		((GButtonObject *)gh) -	if (gh->type != GW_BUTTON) -		return; +	#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 -	// Dispose of the old string -	if ((gh->flags & GBTN_FLG_ALLOCTXT)) { -		gh->flags &= ~GBTN_FLG_ALLOCTXT; -		if (gbw->txt) { -			gfxFree((void *)gbw->txt); -			gbw->txt = ""; -		} -	} -	// Alloc the new text if required -	if (txt && useAlloc) { -		char *str; -		 -		if ((str = (char *)gfxAlloc(strlen(txt)+1))) { -			gh->flags |= GBTN_FLG_ALLOCTXT; -			strcpy(str, txt); -		} -		txt = (const char *)str; -	} -	 -	gbw->txt = txt ? txt : ""; -	#undef gbw +	SendButtonEvent(gw);  } -void gwinButtonDraw(GHandle gh) { -	#define gbw		((GButtonObject *)gh) -	 -	if (gh->type != GW_BUTTON) -		return; +// A toggle off has occurred +static void ToggleOff(GWidgetObject *gw, uint16_t instance) { +	(void) instance; +	gw->g.flags &= ~GBUTTON_FLG_PRESSED; +	gwinDraw((GHandle)gw); +} -	#if GDISP_NEED_CLIP -		gdispSetClip(gh->x, gh->y, gh->width, gh->height); -	#endif +// A toggle on has occurred +static void ToggleOn(GWidgetObject *gw, uint16_t instance) { +	(void) instance; +	gw->g.flags |= GBUTTON_FLG_PRESSED; +	gwinDraw((GHandle)gw); +	// Trigger the event on button down (different than for mouse/touch) +	SendButtonEvent(gw); +} -	gbw->fn(gh, -			gbw->gwin.enabled, -			gbw->state == GBTN_DOWN, -			gh->font && gbw->txt ? gbw->txt : "", -			gbw->state == GBTN_DOWN ? &gbw->dn : &gbw->up, -			gbw->param); +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; -	#undef gbw +	gw->c_up = GButtonDefaultColorsUp; +	gw->c_dn = GButtonDefaultColorsDown; +	gw->c_dis = GButtonDefaultColorsDisabled; +	return (GHandle)gw;  } -void gwinSetButtonCustom(GHandle gh, GButtonDrawFunction fn, void *param) { -	#define gbw		((GButtonObject *)gh) - -	if (gh->type != GW_BUTTON) +void gwinSetButtonColors(GHandle gh, const GButtonColors *pUp, const GButtonColors *pDown, const GButtonColors *pDisabled) { +	if (gh->vmt != (gwinVMT *)&buttonVMT)  		return; -	gbw->fn = fn ? fn : gwinButtonDraw_3D; -	gbw->param = param; +	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; -	#undef gbw +	return (gh->flags & GBUTTON_FLG_PRESSED) ? TRUE : FALSE;  } -void gwinButtonSetEnabled(GHandle gh, bool_t enabled) { -	if (gh->type != GW_BUTTON) -		return; +/*---------------------------------------------------------- + * Custom Draw Routines + *----------------------------------------------------------*/ -	gh->enabled = enabled; +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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -	(void) enabled; -	(void) isdown; -	(void) param; +void gwinButtonDraw_3D(GWidgetObject *gw, void *param) { +	(void)			param; +	GButtonColors *	pcol; -	gdispFillStringBox(gh->x, gh->y, gh->width-1, gh->height-1, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); -	gdispDrawLine(gh->x+gh->width-1, gh->y, gh->x+gh->width-1, gh->y+gh->height-1, pstyle->color_edge); -	gdispDrawLine(gh->x, gh->y+gh->height-1, gh->x+gh->width-2, gh->y+gh->height-1, pstyle->color_edge); +	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_Square(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -	(void) enabled; -	(void) isdown; -	(void) param; +void gwinButtonDraw_Box(GWidgetObject *gw, void *param) { +	(void)			param; +	GButtonColors *	pcol; -	gdispFillStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); -	gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); +	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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; - -		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, pstyle->color_fill); -			gdispDrawStringBox(gh->x+1, gh->y+RND_CNR_SIZE, gh->width-2, gh->height-(2*RND_CNR_SIZE), txt, gh->font, pstyle->color_txt, justifyCenter); -			gdispDrawRoundedBox(gh->x, gh->y, gh->width, gh->height, RND_CNR_SIZE, pstyle->color_edge); +	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(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, pstyle->color_fill, justifyCenter); -			gdispDrawBox(gh->x, gh->y, gh->width, gh->height, pstyle->color_edge); +			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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; - -		gdispFillEllipse(gh->x+1, gh->y+1, gh->width/2-1, gh->height/2-1, pstyle->color_fill); -		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); -		gdispDrawEllipse(gh->x, gh->y, gh->width/2, gh->height/2, pstyle->color_edge); +	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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; -		point	arw[7]; - -		arw[0].x = gh->width/2; arw[0].y = 0; -		arw[1].x = gh->width-1; arw[1].y = gh->height/ARROWHEAD_DIVIDER; -		arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height/ARROWHEAD_DIVIDER; -		arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = gh->height-1; -		arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = gh->height-1; -		arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height/ARROWHEAD_DIVIDER; -		arw[6].x = 0; arw[6].y = gh->height/ARROWHEAD_DIVIDER; - -		gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); -		gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); -		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->color_txt, justifyCenter); +	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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; -		point	arw[7]; - -		arw[0].x = gh->width/2; arw[0].y = gh->height-1; -		arw[1].x = gh->width-1; arw[1].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; -		arw[2].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[2].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; -		arw[3].x = (gh->width + gh->width/ARROWBODY_DIVIDER)/2; arw[3].y = 0; -		arw[4].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[4].y = 0; -		arw[5].x = (gh->width - gh->width/ARROWBODY_DIVIDER)/2; arw[5].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; -		arw[6].x = 0; arw[6].y = gh->height-1-gh->height/ARROWHEAD_DIVIDER; - -		gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); -		gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); -		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; -		point	arw[7]; - -		arw[0].x = 0; arw[0].y = gh->height/2; -		arw[1].x = gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; -		arw[2].x = gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; -		arw[3].x = gh->width-1; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; -		arw[4].x = gh->width-1; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; -		arw[5].x = gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; -		arw[6].x = gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1; - -		gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); -		gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); -		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->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(GHandle gh, bool_t enabled, bool_t isdown, const char *txt, const GButtonDrawStyle *pstyle, void *param) { -		(void) enabled; -		(void) isdown; -		(void) param; -		point	arw[7]; - -		arw[0].x = gh->width-1; arw[0].y = gh->height/2; -		arw[1].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[1].y = 0; -		arw[2].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[2].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; -		arw[3].x = 0; arw[3].y = (gh->height - gh->height/ARROWBODY_DIVIDER)/2; -		arw[4].x = 0; arw[4].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; -		arw[5].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[5].y = (gh->height + gh->height/ARROWBODY_DIVIDER)/2; -		arw[6].x = gh->width-1-gh->width/ARROWHEAD_DIVIDER; arw[6].y = gh->height-1; - -		gdispFillConvexPoly(gh->x, gh->y, arw, 7, pstyle->color_fill); -		gdispDrawPoly(gh->x, gh->y, arw, 7, pstyle->color_edge); -		gdispDrawStringBox(gh->x+1, gh->y+1, gh->width-2, gh->height-2, txt, gh->font, pstyle->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 GFX_USE_GINPUT && GINPUT_NEED_MOUSE -	bool_t gwinAttachButtonMouse(GHandle gh, uint16_t instance) { -		GSourceHandle gsh; +#if GDISP_NEED_IMAGE || defined(__DOXYGEN__) +	void gwinButtonDraw_Image(GWidgetObject *gw, void *param) { +		GButtonColors *	pcol; +		coord_t			sy; -		if (gh->type != GW_BUTTON || !(gsh = ginputGetMouse(instance))) -			return FALSE; +		if (gw->g.vmt != (gwinVMT *)&buttonVMT)	return; -		return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); -	} -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE -	bool_t gwinAttachButtonToggle(GHandle gh, uint16_t instance) { -		GSourceHandle gsh; - -		if (gh->type != GW_BUTTON || !(gsh = ginputGetToggle(instance))) -			return FALSE; +		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; +		} -		return geventAttachSource(&((GButtonObject *)gh)->listener, gsh, GLISTEN_TOGGLE_OFF|GLISTEN_TOGGLE_ON); +		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 diff --git a/src/gwin/checkbox.c b/src/gwin/checkbox.c index 547a30b5..d35f271c 100644 --- a/src/gwin/checkbox.c +++ b/src/gwin/checkbox.c @@ -7,7 +7,7 @@  /**   * @file    src/gwin/checkbox.c - * @brief   GWIN sub-system checkbox code. + * @brief   GWIN sub-system button code.   *   * @defgroup Checkbox Checkbox   * @ingroup GWIN @@ -19,168 +19,137 @@  #if (GFX_USE_GWIN && GWIN_NEED_CHECKBOX) || defined(__DOXYGEN__) -static const GCheckboxColor defaultColors = { -	Grey,	// border -	Grey,	// selected -	Black	// background +#include "gwin/class_gwin.h" + +// Our checked state +#define GCHECKBOX_FLG_CHECKED		(GWIN_FIRST_CONTROL_FLAG<<0) + +// Prototypes for button VMT functions +static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y); +static void ToggleOn(GWidgetObject *gw, uint16_t instance); + +// The button VMT table +static const gwidgetVMT checkboxVMT = { +	{ +		"Checkbox",				// The classname +		_gwidgetDestroy,		// The destroy routine +		0,						// The after-clear routine +	}, +	gwinCheckboxDraw_CheckOnLeft,	// The default drawing routine +	MouseDown,				// Process mouse down events +	0,						// Process mouse up events (NOT USED) +	0,						// Process mouse move events (NOT USED) +	0,						// Process toggle off events (NOT USED) +	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 style drawing routine */ -static void gwinCheckboxDrawDefaultStyle(GHandle gh, bool_t enabled, bool_t isChecked, void* param) { -	#define gcw		((GCheckboxObject *)gh) - -	(void) enabled; -	(void) param; - -	gdispDrawBox(gh->x, gh->y, gh->width, gh->height, gcw->colors->border); - -	if (isChecked) -		gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->checked); -	else -		gdispFillArea(gh->x+2, gh->y+2, gh->width-4, gh->height-4, gcw->colors->bg); - -	#undef gcw -} - -/* process an event callback */ -static void gwinCheckboxCallback(void *param, GEvent *pe) { -	GSourceListener *psl; -	#define gh		((GHandle)param) -	#define gbw		((GCheckboxObject *)param) -	#define gsh		((GSourceHandle)param) -	#define pme		((GEventMouse *)pe) -	#define pte		((GEventTouch *)pe) -	#define pxe		((GEventToggle *)pe) -	#define pbe		((GEventGWinCheckbox *)pe) - -	/* check if checkbox is disabled */ -	if (!gh->enabled) -		return; - -	switch (pe->type) { -	#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -		case GEVENT_MOUSE: -		case GEVENT_TOUCH: - -			// Ignore anything other than the primary mouse button going up or down -			if (!((pme->current_buttons ^ pme->last_buttons) & GINPUT_MOUSE_BTN_LEFT)) -				return; - -			if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT) -					&& 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) { - -				gbw->isChecked = !gbw->isChecked; - -				gwinCheckboxDraw((GHandle)param); -				break; -			} -			return; -	#endif /* GFX_USE_GINPUT && GINPUT_NEED_MOUSE */ +static const GCheckboxColors defaultColors = { +	Black,	// border +	Grey,	// selected +	White,	// background +	Black,	// text +}; -		default: -			return; -	} +// Send the checkbox event +static void SendCheckboxEvent(GWidgetObject *gw) { +	GSourceListener	*	psl; +	GEvent *			pe; +	#define pce			((GEventGWinCheckbox *)pe) -	// Trigger a GWIN checkbox event +	// Trigger a GWIN Checkbox Event  	psl = 0; -	while ((psl = geventGetSourceListener(gsh, psl))) { +	while ((psl = geventGetSourceListener((GSourceHandle)gw, psl))) {  		if (!(pe = geventGetEventBuffer(psl)))  			continue; -		pbe->type = GEVENT_GWIN_CHECKBOX; -		pbe->checkbox = gh; -		pbe->isChecked = gbw->isChecked; +		pce->type = GEVENT_GWIN_CHECKBOX; +		pce->checkbox = &gw->g; +		pce->isChecked = (gw->g.flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;  		geventSendEvent(psl); -	}	 - -	#undef gh -	#undef pbe -	#undef pme -	#undef pte -	#undef pxe -	#undef gsh -	#undef gbw -} +	} -GHandle gwinCheckboxCreate(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { -	if (!(gb = (GCheckboxObject *)_gwinInit((GWindowObject *)gb, x, y, width, height, sizeof(GCheckboxObject)))) -		return 0; +	#undef pce +} -	gb->gwin.type = GW_CHECKBOX;			// create a window of the type checkbox -	gb->fn = gwinCheckboxDrawDefaultStyle;	// set the default style drawing routine  -	gb->colors = &defaultColors;			// asign the default colors -	gb->param = 0;							// some safe value here -	gb->isChecked = GCHBX_UNCHECKED;		// checkbox is currently unchecked -	gb->gwin.enabled = TRUE;				// checkboxes are enabled by default +// A mouse down has occurred over the checkbox +static void MouseDown(GWidgetObject *gw, coord_t x, coord_t y) { +	(void) x; (void) y; +	gw->g.flags ^= GCHECKBOX_FLG_CHECKED; +	gwinDraw((GHandle)gw); +	SendCheckboxEvent(gw); +} -	geventListenerInit(&gb->listener); -	geventRegisterCallback(&gb->listener, gwinCheckboxCallback, gb); +// A toggle on has occurred +static void ToggleOn(GWidgetObject *gw, uint16_t instance) { +	(void) instance; +	gw->g.flags ^= GCHECKBOX_FLG_CHECKED; +	gwinDraw((GHandle)gw); +	SendCheckboxEvent(gw); +} -	// checkboxes are enabled by default -	gb->gwin.enabled = TRUE; +GHandle gwinCreateCheckbox(GCheckboxObject *gb, coord_t x, coord_t y, coord_t width, coord_t height) { +	if (!(gb = (GCheckboxObject *)_gwidgetInit((GWidgetObject *)gb, x, y, width, height, sizeof(GCheckboxObject), &checkboxVMT))) +		return 0; +	gb->c = defaultColors;			// assign the default colors  	return (GHandle)gb;  } -void gwinCheckboxSetCustom(GHandle gh, GCheckboxDrawFunction fn, void *param) { -	#define gcw		((GCheckboxObject *)gh) - -	if (gh->type != GW_CHECKBOX) -		return; - -	gcw->fn = fn; -	gcw->param = param; +bool_t gwinIsCheckboxChecked(GHandle gh) { +	if (gh->vmt != (gwinVMT *)&checkboxVMT) +		return FALSE; -	#undef gcw	 +	return (gh->flags & GCHECKBOX_FLG_CHECKED) ? TRUE : FALSE;  } - -void gwinCheckboxSetEnabled(GHandle gh, bool_t enabled) { -	if (gh->type != GW_CHECKBOX) +void gwinCheckboxSetColors(GHandle gh, GCheckboxColors *pColors) { +	if (gh->vmt != (gwinVMT *)&checkboxVMT)  		return; -	gh->enabled = enabled; +	((GCheckboxObject *)gh)->c = *pColors;  } -void gwinCheckboxDraw(GHandle gh) { -	#define gcw		((GCheckboxObject *)gh) +void gwinCheckboxDraw_CheckOnLeft(GWidgetObject *gw, void *param) { +	#define gcw		((GCheckboxObject *)gw) +	coord_t	ld, df; +	(void) param; -	if (gh->type != GW_CHECKBOX) +	if (gw->g.vmt != (gwinVMT *)&checkboxVMT)  		return; -	#if GDISP_NEED_CLIP -		//gdispSetClip(gh->x, gh->y, gh->width, gh->height); -	#endif +	ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; +	gdispFillArea(gw->g.x+1, gw->g.y+1, ld, ld-2, gcw->c.color_bg); +	gdispDrawBox(gw->g.x, gw->g.y, ld, ld, gcw->c.color_border); -	gcw->fn(gh, -            gcw->gwin.enabled, -            gcw->isChecked, -            gcw->param); +	df = ld < 4 ? 1 : 2; +	if (gw->g.flags & GCHECKBOX_FLG_CHECKED) +		gdispFillArea(gw->g.x+df, gw->g.y+df, ld-2*df, ld-2*df, gcw->c.color_checked); +	gdispFillStringBox(gw->g.x+ld+1, gw->g.y, gw->g.width-ld-1, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyLeft);  	#undef gcw  } -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -	bool_t gwinCheckboxAttachMouse(GHandle gh, uint16_t instance) { -		GSourceHandle gsh; - -		if (gh->type != GW_CHECKBOX || !(gsh = ginputGetMouse(instance))) -			return FALSE; - -		return geventAttachSource(&((GCheckboxObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA); -	} -#endif - -void gwinCheckboxSetColors(GHandle gh, color_t border, color_t checked, color_t bg) { -	#define gcw		((GCheckboxObject *)gh) +void gwinCheckboxDraw_CheckOnRight(GWidgetObject *gw, void *param) { +	#define gcw		((GCheckboxObject *)gw) +	coord_t	ep, ld, df; +	(void) param; -	if (gh->type != GW_CHECKBOX) +	if (gw->g.vmt != (gwinVMT *)&checkboxVMT)  		return; -	gcw->colors->border = border; -	gcw->colors->checked = checked, -	gcw->colors->bg = bg; +	ld = gw->g.width < gw->g.height ? gw->g.width : gw->g.height; +	ep = gw->g.width-ld-1; +	gdispFillArea(gw->g.x+ep-1, gw->g.y+1, ld, ld-2, gcw->c.color_bg); +	gdispDrawBox(gw->g.x+ep, gw->g.y, ld, ld, gcw->c.color_border); + +	df = ld < 4 ? 1 : 2; +	if (gw->g.flags & GCHECKBOX_FLG_CHECKED) +		gdispFillArea(gw->g.x+ep+df, gw->g.y+df, ld-2*df, ld-2*df, gcw->c.color_checked); +	gdispFillStringBox(gw->g.x, gw->g.y, ep, gw->g.height, gw->txt, gw->g.font, gcw->c.color_txt, gcw->c.color_bg, justifyRight);  	#undef gcw  } diff --git a/src/gwin/console.c b/src/gwin/console.c index 5c068c93..d9bda362 100644 --- a/src/gwin/console.c +++ b/src/gwin/console.c @@ -8,20 +8,15 @@  /**   * @file    src/gwin/console.c   * @brief   GWIN sub-system console code. - * - * @defgroup Console Console - * @ingroup GWIN - * - * @{   */  #include "gfx.h" -#if (GFX_USE_GWIN && GWIN_NEED_CONSOLE) || defined(__DOXYGEN__) +#if GFX_USE_GWIN && GWIN_NEED_CONSOLE  #include <string.h> -#include "gwin/internal.h" +#include "gwin/class_gwin.h"  #define GWIN_CONSOLE_USE_CLEAR_LINES			TRUE  #define GWIN_CONSOLE_USE_FILLED_CHARS			FALSE @@ -58,11 +53,20 @@  	};  #endif -GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height, font_t font) { -	if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject)))) +static void AfterClear(GWindowObject *gh) { +	((GConsoleObject *)gh)->cx = 0; +	((GConsoleObject *)gh)->cy = 0; +} + +static const gwinVMT consoleVMT = { +		"Console",				// The classname +		0,						// The destroy routine +		AfterClear,				// The after-clear routine +}; + +GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t width, coord_t height) { +	if (!(gc = (GConsoleObject *)_gwinInit((GWindowObject *)gc, x, y, width, height, sizeof(GConsoleObject), &consoleVMT)))  		return 0; -	gc->gwin.type = GW_CONSOLE; -	gwinSetFont(&gc->gwin, font);  	#if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM  		gc->stream.vmt = &GWindowConsoleVMT;  	#endif @@ -73,17 +77,21 @@ GHandle gwinCreateConsole(GConsoleObject *gc, coord_t x, coord_t y, coord_t widt  #if GFX_USE_OS_CHIBIOS && GWIN_CONSOLE_USE_BASESTREAM  	BaseSequentialStream *gwinGetConsoleStream(GHandle gh) { -		if (gh->type != GW_CONSOLE) +		if (gh->vmt != &consoleVMT)  			return 0;  		return (BaseSequentialStream *)&(((GConsoleObject *)(gh))->stream);  	}  #endif  void gwinPutChar(GHandle gh, char c) { -	uint8_t			width;  	#define gcw		((GConsoleObject *)gh) +	uint8_t			width, fy, fp; + +	if (gh->vmt != &consoleVMT || !gh->font) +		return; -	if (gh->type != GW_CONSOLE || !gh->font) return; +	fy = gdispGetFontMetric(gh->font, fontHeight); +	fp = gdispGetFontMetric(gh->font, fontCharPadding);  	#if GDISP_NEED_CLIP  		gdispSetClip(gh->x, gh->y, gh->width, gh->height); @@ -91,24 +99,24 @@ void gwinPutChar(GHandle gh, char c) {  	if (c == '\n') {  		gcw->cx = 0; -		gcw->cy += gcw->fy; +		gcw->cy += fy;  		// We use lazy scrolling here and only scroll when the next char arrives  	} else if (c == '\r') {  		// gcw->cx = 0;  	} else { -		width = gdispGetCharWidth(c, gh->font) + gcw->fp; +		width = gdispGetCharWidth(c, gh->font) + fp;  		if (gcw->cx + width >= gh->width) {  			gcw->cx = 0; -			gcw->cy += gcw->fy; +			gcw->cy += fy;  		} -		if (gcw->cy + gcw->fy > gh->height) { +		if (gcw->cy + fy > gh->height) {  #if GDISP_NEED_SCROLL  			/* scroll the console */ -			gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, gcw->fy, gh->bgcolor); +			gdispVerticalScroll(gh->x, gh->y, gh->width, gh->height, fy, gh->bgcolor);  			/* reset the cursor to the start of the last line */  			gcw->cx = 0; -			gcw->cy = (((coord_t)(gh->height/gcw->fy))-1)*gcw->fy; +			gcw->cy = (((coord_t)(gh->height/fy))-1)*fy;  #else  			/* clear the console */  			gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); @@ -121,7 +129,7 @@ void gwinPutChar(GHandle gh, char c) {  #if GWIN_CONSOLE_USE_CLEAR_LINES  		/* clear to the end of the line */  		if (gcw->cx == 0) -			gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, gcw->fy, gh->bgcolor); +			gdispFillArea(gh->x, gh->y + gcw->cy, gh->width, fy, gh->bgcolor);  #endif  #if GWIN_CONSOLE_USE_FILLED_CHARS  		gdispFillChar(gh->x + gcw->cx, gh->y + gcw->cy, c, gh->font, gh->color, gh->bgcolor); @@ -200,7 +208,8 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {  		char tmpbuf[MAX_FILLER + 1];  	#endif -	if (gh->type != GW_CONSOLE || !gh->font) return; +	if (gh->vmt != &consoleVMT || !gh->font) +		return;  	va_start(ap, fmt);  	while (TRUE) { @@ -343,5 +352,5 @@ void gwinPrintf(GHandle gh, const char *fmt, ...) {  }  #endif /* GFX_USE_GWIN && GWIN_NEED_CONSOLE */ -/** @} */ + diff --git a/src/gwin/graph.c b/src/gwin/graph.c index 287deba9..0ae9822b 100644 --- a/src/gwin/graph.c +++ b/src/gwin/graph.c @@ -8,18 +8,13 @@  /**   * @file    src/gwin/graph.c   * @brief   GWIN sub-system button code. - * - * @defgroup Graph Graph - * @ingroup GWIN - * - * @{   */  #include "gfx.h" -#if (GFX_USE_GWIN && GWIN_NEED_GRAPH) || defined(__DOXYGEN__) +#if GFX_USE_GWIN && GWIN_NEED_GRAPH -#include "gwin/internal.h" +#include "gwin/class_gwin.h"  #define GGRAPH_FLG_CONNECTPOINTS			(GWIN_FIRST_CONTROL_FLAG<<0)  #define GGRAPH_ARROW_SIZE					5 @@ -34,13 +29,19 @@ static const GGraphStyle GGraphDefaultStyle = {  	GWIN_GRAPH_STYLE_XAXIS_ARROWS|GWIN_GRAPH_STYLE_YAXIS_ARROWS		// flags  }; +static const gwinVMT graphVMT = { +		"Graph",				// The classname +		0,						// The destroy routine +		0,						// The after-clear routine +}; +  static void pointto(GGraphObject *gg, coord_t x, coord_t y, const GGraphPointStyle *style) {  	if (style->type == GGRAPH_POINT_NONE)  		return;  	// Convert to device space. Note the y-axis is inverted. -	x += gg->gwin.x + gg->xorigin; -	y = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y; +	x += gg->g.x + gg->xorigin; +	y = gg->g.y + gg->g.height - 1 - gg->yorigin - y;  	if (style->size <= 1) {  		gdispDrawPixel(x, y, style->color); @@ -73,10 +74,10 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t  		return;  	// Convert to device space. Note the y-axis is inverted. -	x0 += gg->gwin.x + gg->xorigin; -	y0 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y0; -	x1 += gg->gwin.x + gg->xorigin; -	y1 = gg->gwin.y + gg->gwin.height - 1 - gg->yorigin - y1; +	x0 += gg->g.x + gg->xorigin; +	y0 = gg->g.y + gg->g.height - 1 - gg->yorigin - y0; +	x1 += gg->g.x + gg->xorigin; +	y1 = gg->g.y + gg->g.height - 1 - gg->yorigin - y1;  	if (style->size <= 0) {  		// Use the driver to draw a solid line @@ -163,41 +164,26 @@ static void lineto(GGraphObject *gg, coord_t x0, coord_t y0, coord_t x1, coord_t  }  GHandle gwinCreateGraph(GGraphObject *gg, coord_t x, coord_t y, coord_t width, coord_t height) { -	if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject)))) +	if (!(gg = (GGraphObject *)_gwinInit((GWindowObject *)gg, x, y, width, height, sizeof(GGraphObject), &graphVMT)))  		return 0; -	gg->gwin.type = GW_GRAPH;  	gg->xorigin = gg->yorigin = 0;  	gg->lastx = gg->lasty = 0; -	gwinGraphSetStyle(&gg->gwin, &GGraphDefaultStyle); +	gwinGraphSetStyle((GHandle)gg, &GGraphDefaultStyle);  	return (GHandle)gg;  }  void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {  	#define gg	((GGraphObject *)gh) -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return; -	gg->style.point.type = pstyle->point.type; -	gg->style.point.size = pstyle->point.size; -	gg->style.point.color = pstyle->point.color; -	gg->style.line.type = pstyle->line.type; -	gg->style.line.size = pstyle->line.size; -	gg->style.line.color = pstyle->line.color; -	gg->style.xaxis.type = pstyle->xaxis.type; -	gg->style.xaxis.size = pstyle->xaxis.size; -	gg->style.xaxis.color = pstyle->xaxis.color; -	gg->style.yaxis.type = pstyle->yaxis.type; -	gg->style.yaxis.size = pstyle->yaxis.size; -	gg->style.yaxis.color = pstyle->yaxis.color; -	gg->style.xgrid.type = pstyle->xgrid.type; -	gg->style.xgrid.size = pstyle->xgrid.size; -	gg->style.xgrid.color = pstyle->xgrid.color; -	gg->style.xgrid.spacing = pstyle->xgrid.spacing; -	gg->style.ygrid.type = pstyle->ygrid.type; -	gg->style.ygrid.size = pstyle->ygrid.size; -	gg->style.ygrid.color = pstyle->ygrid.color; -	gg->style.ygrid.spacing = pstyle->ygrid.spacing; +	gg->style.point = pstyle->point; +	gg->style.line = pstyle->line; +	gg->style.xaxis = pstyle->xaxis; +	gg->style.yaxis = pstyle->yaxis; +	gg->style.xgrid = pstyle->xgrid; +	gg->style.ygrid = pstyle->ygrid;  	gg->style.flags = pstyle->flags;  	#undef gg @@ -206,7 +192,7 @@ void gwinGraphSetStyle(GHandle gh, const GGraphStyle *pstyle) {  void gwinGraphSetOrigin(GHandle gh, coord_t x, coord_t y) {  	#define gg	((GGraphObject *)gh) -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return;  	gg->xorigin = x; @@ -219,7 +205,7 @@ void gwinGraphDrawAxis(GHandle gh) {  	#define gg	((GGraphObject *)gh)  	coord_t		i, xmin, ymin, xmax, ymax; -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return;  	xmin = -gg->xorigin; @@ -277,7 +263,7 @@ void gwinGraphDrawAxis(GHandle gh) {  }  void gwinGraphStartSet(GHandle gh) { -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return;  	gh->flags &= ~GGRAPH_FLG_CONNECTPOINTS; @@ -286,7 +272,7 @@ void gwinGraphStartSet(GHandle gh) {  void gwinGraphDrawPoint(GHandle gh, coord_t x, coord_t y) {  	#define gg	((GGraphObject *)gh) -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return;  	if ((gh->flags & GGRAPH_FLG_CONNECTPOINTS)) { @@ -314,7 +300,7 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {  	unsigned		i;  	const point		*p; -	if (gh->type != GW_GRAPH) +	if (gh->vmt != &graphVMT)  		return;  	// Draw the connecting lines @@ -344,5 +330,3 @@ void gwinGraphDrawPoints(GHandle gh, const point *points, unsigned count) {  }  #endif /* GFX_USE_GWIN && GWIN_NEED_GRAPH */ -/** @} */ - diff --git a/src/gwin/gwidget.c b/src/gwin/gwidget.c new file mode 100644 index 00000000..464210b7 --- /dev/null +++ b/src/gwin/gwidget.c @@ -0,0 +1,254 @@ +/* + * 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: + * + *              http://chibios-gfx.com/license.html + */ + +#include "gfx.h" + +#if GFX_USE_GWIN + +#include <string.h> + +#include "gwin/class_gwin.h" + +/* We use these everywhere in this file */ +#define gw		((GWidgetObject *)gh) +#define wvmt	((gwidgetVMT *)gh->vmt) + +static void gwidgetCallback(void *param, GEvent *pe) { +	#define gh		((GWindowObject *)param) +	#define pme		((GEventMouse *)pe) +	#define pte		((GEventToggle *)pe) +	#define pde		((GEventDial *)pe) + +	// check if widget is disabled +	if (!(gw->g.flags & GWIN_FLG_ENABLED)) +		return; + +	// Process via AllEvents() if it is defined +	if (wvmt->AllEvents) +		wvmt->AllEvents(gw, pe); + +	// Process various events +	switch (pe->type) { + +	#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE +	case GEVENT_MOUSE: +	case GEVENT_TOUCH: +		// Are we captured? +		if ((gw->g.flags & GWIN_FLG_MOUSECAPTURE)) { +			if (pme->meta == GMETA_MOUSE_UP) { +				gw->g.flags &= ~GWIN_FLG_MOUSECAPTURE; +				if (wvmt->MouseUp) +					wvmt->MouseUp(gw, pme->x - gw->g.x, pme->y - gw->g.y); +				return; +			} else if (wvmt->MouseMove) +				wvmt->MouseMove(gw, pme->x - gw->g.x, pme->y - gw->g.y); + +		// We are not captured - look for mouse downs over the widget +		} else if (pme->meta == GMETA_MOUSE_DOWN +				&& pme->x >= gw->g.x && pme->x < gw->g.x + gw->g.width +				&& pme->y >= gw->g.y && pme->y < gw->g.y + gw->g.height) { +			gw->g.flags |= GWIN_FLG_MOUSECAPTURE; +			if (wvmt->MouseDown) +				wvmt->MouseDown(gw, pme->x - gw->g.x, pme->y - gw->g.y); +		} +		break; +	#endif + +	#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE +	case GEVENT_TOGGLE: +		if (pte->on) { +			if (wvmt->ToggleOn) +				wvmt->ToggleOn(gw, pte->instance); +		} else { +			if (wvmt->ToggleOff) +				wvmt->ToggleOff(gw, pte->instance); +		} +		break; +	#endif + +	#if GFX_USE_GINPUT && GINPUT_NEED_DIAL +	case GEVENT_DIAL: +		if (wvmt->DialMove) +			wvmt->DialMove(gw, pde->instance, pde->value); +		break; +	#endif + +	default: +		break; +	} +	#undef gh +	#undef pme +	#undef pte +	#undef pde +} + +GHandle _gwidgetInit(GWidgetObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwidgetVMT *vmt) { +	if (!(pgw = (GWidgetObject *)_gwinInit((GWindowObject *)pgw, x, y, width, height, size, (const gwinVMT *)vmt))) +		return 0; + +	pgw->g.flags |= (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED); +	pgw->txt = ""; +	pgw->fnDraw = vmt->DefaultDraw; +	pgw->fnParam = 0; +	geventListenerInit(&pgw->listener); +	geventRegisterCallback(&pgw->listener, gwidgetCallback, pgw); + +	return (GHandle)pgw; +} + +void _gwidgetDestroy(GHandle gh) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return; + +	// Deallocate the text (if necessary) +	if ((gh->flags & GWIN_FLG_ALLOCTXT)) { +		gh->flags &= ~GWIN_FLG_ALLOCTXT; +		gfxFree((void *)gw->txt); +	} +	// Untangle the listeners (both on us and to us). +	geventDetachSource(&gw->listener, 0); +	geventDetachSourceListeners((GSourceHandle)gh); +	gh->flags &= ~GWIN_FLG_WIDGET; +} + +void gwinSetEnabled(GHandle gh, bool_t enabled) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return; + +	if (enabled) +		gh->flags |= GWIN_FLG_ENABLED; +	else +		gh->flags &= ~GWIN_FLG_ENABLED; +} + +void gwinDraw(GHandle gh) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return; + +	#if GDISP_NEED_CLIP +		gdispSetClip(gh->x, gh->y, gh->width, gh->height); +	#endif + +	gw->fnDraw(gw, gw->fnParam); +} + +void gwinSetText(GHandle gh, const char *txt, bool_t useAlloc) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return; + +	// Dispose of the old string +	if ((gh->flags & GWIN_FLG_ALLOCTXT)) { +		gh->flags &= ~GWIN_FLG_ALLOCTXT; +		if (gw->txt) { +			gfxFree((void *)gw->txt); +			gw->txt = ""; +		} +	} + +	// Alloc the new text if required +	if (txt && !*txt) txt = 0; +	if (txt && useAlloc) { +		char *str; + +		if ((str = (char *)gfxAlloc(strlen(txt)+1))) { +			gh->flags |= GWIN_FLG_ALLOCTXT; +			strcpy(str, txt); +		} +		txt = (const char *)str; +	} + +	gw->txt = txt ? txt : ""; +} + +const char *gwinGetText(GHandle gh) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return 0; + +	return gw->txt; +} + +void gwinSetCustomDraw(GHandle gh, CustomWidgetDrawFunction fn, void *param) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return; + +	gw->fnDraw = fn ? fn : wvmt->DefaultDraw; +	gw->fnParam = param; +} + +bool_t gwinAttachListener(GHandle gh, GListener *pl, unsigned flags) { +	if (!(gh->flags & GWIN_FLG_WIDGET)) +		return FALSE; + +	return geventAttachSource(pl, (GSourceHandle)gh, flags); +} + +#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE +	bool_t gwinAttachMouse(GHandle gh, uint16_t instance) { +		GSourceHandle	gsh; +		unsigned		flags; + +		if (!(gh->flags & GWIN_FLG_WIDGET)) +			return FALSE; + +		if (!wvmt->MouseDown && !wvmt->MouseMove && !wvmt->MouseUp) +			return FALSE; + +		if (!(gsh = ginputGetMouse(instance))) +			return FALSE; + +		flags = wvmt->MouseMove ? (GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES) : GLISTEN_MOUSEMETA; +		return geventAttachSource(&gw->listener, gsh, flags); +	} +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE +	bool_t gwinAttachToggle(GHandle gh, uint16_t role, uint16_t instance) { +		GSourceHandle	gsh; +		unsigned		flags; + +		if (!(gh->flags & GWIN_FLG_WIDGET)) +			return FALSE; + +		flags = 0; +		if (wvmt->ToggleOff)	flags |= GLISTEN_TOGGLE_OFF; +		if (wvmt->ToggleOn)		flags |= GLISTEN_TOGGLE_ON; +		if (!flags) +			return FALSE; + +		if (!(gsh = ginputGetToggle(instance))) +			return FALSE; + +		if (wvmt->AssignToggle && !wvmt->AssignToggle(gw, role, instance)) +			return FALSE; + +		return geventAttachSource(&gw->listener, gsh, flags); +	} +#endif + +#if GFX_USE_GINPUT && GINPUT_NEED_DIAL +	bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance) { +		GSourceHandle	gsh; + +		if (!(gh->flags & GWIN_FLG_WIDGET)) +			return FALSE; + +		if (!wvmt->DialMove) +			return FALSE; + +		if (!(gsh = ginputGetDial(instance))) +			return FALSE; + +		if (wvmt->AssignDial && !wvmt->AssignDial(gw, role, instance)) +			return FALSE; + +		return geventAttachSource(&gw->listener, gsh, 0); +	} +#endif + +#endif /* GFX_USE_GWIN */ +/** @} */ + diff --git a/src/gwin/gwin.c b/src/gwin/gwin.c index c01c8a90..fcbaa397 100644 --- a/src/gwin/gwin.c +++ b/src/gwin/gwin.c @@ -9,11 +9,19 @@  #if GFX_USE_GWIN -#include "gwin/internal.h" +#include "gwin/class_gwin.h" + +static const gwinVMT basegwinVMT = { +		"GWIN",					// The classname +		0,						// The destroy routine +		0,						// The after-clear routine +}; + +static font_t	defaultFont;  // Internal routine for use by GWIN components only  // Initialise a window creating it dynamicly if required. -GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size) { +GHandle _gwinInit(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height, size_t size, const gwinVMT *vmt) {  	coord_t	w, h;  	// Check the window size against the screen size @@ -26,60 +34,34 @@ GHandle _gwinInit(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_  	if (y+height > h) height = h - y;  	// Allocate the structure if necessary -	if (!gw) { -		if (!(gw = (GWindowObject *)gfxAlloc(size))) +	if (!pgw) { +		if (!(pgw = (GWindowObject *)gfxAlloc(size)))  			return 0; -		gw->flags = GWIN_FLG_DYNAMIC; +		pgw->flags = GWIN_FLG_DYNAMIC;  	} else -		gw->flags = 0; +		pgw->flags = 0; -	// Initialise all basic fields (except the type) -	gw->x = x; -	gw->y = y; -	gw->width = width; -	gw->height = height; -	gw->color = White; -	gw->bgcolor = Black; +	// Initialise all basic fields +	pgw->vmt = vmt; +	pgw->x = x; +	pgw->y = y; +	pgw->width = width; +	pgw->height = height; +	pgw->color = White; +	pgw->bgcolor = Black;  	#if GDISP_NEED_TEXT -		gw->font = 0; +		pgw->font = defaultFont;  	#endif -	return (GHandle)gw; -} - -GHandle gwinCreateWindow(GWindowObject *gw, coord_t x, coord_t y, coord_t width, coord_t height) { -	if (!(gw = (GWindowObject *)_gwinInit((GWindowObject *)gw, x, y, width, height, sizeof(GWindowObject)))) -		return 0; -	gw->type = GW_WINDOW; -	return (GHandle)gw; +	return (GHandle)pgw;  } -void gwinSetEnabled(GHandle gh, bool_t enabled) { -	(void)gh; -	(void)enabled; +GHandle gwinCreateWindow(GWindowObject *pgw, coord_t x, coord_t y, coord_t width, coord_t height) { +	return _gwinInit(pgw, x, y, width, height, sizeof(GWindowObject), &basegwinVMT);  } -void gwinDestroyWindow(GHandle gh) { -	// Clean up any type specific dynamic memory allocations -	switch(gh->type) { -#if GWIN_NEED_BUTTON -	case GW_BUTTON: -		if ((gh->flags & GBTN_FLG_ALLOCTXT)) { -			gh->flags &= ~GBTN_FLG_ALLOCTXT;		// To be sure, to be sure -			gfxFree((void *)((GButtonObject *)gh)->txt); -		} -		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; -	} +void gwinDestroy(GHandle gh) { +	if (gh->vmt->Destroy) +		gh->vmt->Destroy(gh);  	// Clean up the structure  	if (gh->flags & GWIN_FLG_DYNAMIC) { @@ -88,30 +70,17 @@ void gwinDestroyWindow(GHandle gh) {  	}  } -void gwinDraw(GHandle gh) { -	switch(gh->type) { -	#if GWIN_NEED_BUTTON -		case GW_BUTTON: -			gwinButtonDraw(gh); -			break; -	#endif -	#if GWIN_NEED_SLIDER -		case GW_SLIDER: -			gwinSliderDraw(gh); -			break; -	#endif -	} +const char *gwinGetClassName(GHandle gh) { +	return gh->vmt->classname;  }  #if GDISP_NEED_TEXT +	void gwinSetDefaultFont(font_t font) { +		defaultFont = font; +	} +  	void gwinSetFont(GHandle gh, font_t font) {  		gh->font = font; -	#if GWIN_NEED_CONSOLE -		if (font && gh->type == GW_CONSOLE) { -			((GConsoleObject *)gh)->fy = gdispGetFontMetric(font, fontHeight); -			((GConsoleObject *)gh)->fp = gdispGetFontMetric(font, fontCharPadding); -		} -	#endif  	}  #endif @@ -120,13 +89,8 @@ void gwinClear(GHandle gh) {  		gdispSetClip(gh->x, gh->y, gh->width, gh->height);  	#endif  	gdispFillArea(gh->x, gh->y, gh->width, gh->height, gh->bgcolor); - -	#if GWIN_NEED_CONSOLE -		if (gh->type == GW_CONSOLE) { -			((GConsoleObject *)gh)->cx = 0; -			((GConsoleObject *)gh)->cy = 0; -		} -	#endif +	if (gh->vmt->AfterClear) +		gh->vmt->AfterClear(gh);  }  void gwinDrawPixel(GHandle gh, coord_t x, coord_t y) { diff --git a/src/gwin/gwin.mk b/src/gwin/gwin.mk index be6301c6..90a8e9b4 100644 --- a/src/gwin/gwin.mk +++ b/src/gwin/gwin.mk @@ -1,7 +1,8 @@  GFXSRC +=   $(GFXLIB)/src/gwin/gwin.c \ +			$(GFXLIB)/src/gwin/gwidget.c \  			$(GFXLIB)/src/gwin/console.c \ +			$(GFXLIB)/src/gwin/graph.c \  			$(GFXLIB)/src/gwin/button.c \  			$(GFXLIB)/src/gwin/slider.c \ -			$(GFXLIB)/src/gwin/graph.c \  			$(GFXLIB)/src/gwin/checkbox.c \ diff --git a/src/gwin/slider.c b/src/gwin/slider.c index 1f252d77..f18c665b 100644 --- a/src/gwin/slider.c +++ b/src/gwin/slider.c @@ -19,140 +19,168 @@  #if (GFX_USE_GWIN && GWIN_NEED_SLIDER) || defined(__DOXYGEN__) -#include "gwin/internal.h" +#include "gwin/class_gwin.h"  #ifndef GWIN_SLIDER_DEAD_BAND  	#define GWIN_SLIDER_DEAD_BAND	5  #endif -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -	static void trackSliderDraw(GHandle gh, coord_t x, coord_t y); -#endif +// 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 +		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) +}; -static const GSliderDrawStyle GSliderDefaultStyle = { -	HTML2COLOR(0x404040),		// color_edge; -	HTML2COLOR(0x000000),		// color_thumb; -	HTML2COLOR(0x00E000),		// color_active; -	HTML2COLOR(0xE0E0E0),		// color_inactive; +static const GSliderColors GSliderDefaultColors = { +	HTML2COLOR(0x404040),		// color_edge +	HTML2COLOR(0x000000),		// color_thumb +	HTML2COLOR(0x00E000),		// color_active +	HTML2COLOR(0xE0E0E0),		// color_inactive +	HTML2COLOR(0xFFFFFF),		// color_txt  }; -// 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 pde		((GEventDial *)pe) -	#define pse		((GEventGWinSlider *)pe) - -	switch (pe->type) { -	#if GFX_USE_GINPUT && 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; -			} +// Send the slider event +static void SendSliderEvent(GWidgetObject *gw) { +	GSourceListener	*	psl; +	GEvent *			pe; +	#define pse			((GEventGWinSlider *)pe) -			// 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, -						(uint16_t)((uint32_t)(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, -						(uint16_t)((uint32_t)(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; -			} +	// 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); +	} -			// If mouse down - track movement -			if ((pme->current_buttons & GINPUT_MOUSE_BTN_LEFT)) -				trackSliderDraw(gh, pme->x-gh->x, pme->y-gh->y); +	#undef pbe +} +// 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); +			gwinDraw(gh);  			return; +		}  	#endif -	#if GFX_USE_GINPUT && GINPUT_NEED_DIAL -		case GEVENT_DIAL: -			// Set the new position -			gwinSetSliderPosition(gh, (uint16_t)((uint32_t)pde->value*(gsw->max-gsw->min)/ginputGetDialRange(pde->instance) + gsw->min)); -			// Update the display -			gwinSliderDraw(gh); +	// Set the new position +	if (gh->width < gh->height) +		gsw->pos = (uint16_t)((uint32_t)(gh->height-1-y-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->height-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); +	else +		gsw->pos = (uint16_t)((uint32_t)(x-GWIN_SLIDER_DEAD_BAND)*(gsw->max-gsw->min)/(gh->width-2*GWIN_SLIDER_DEAD_BAND) + gsw->min); -			// Generate the event -			break; -	#endif +	ResetDisplayPos(gsw); +	gwinDraw(gh); -	default: -		return; -	} +	// Generate the event +	SendSliderEvent(gw); +	#undef gh +	#undef gsw +} -	// 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); +// 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;  	} -	#undef pse -	#undef pme -	#undef pxe -	#undef gsh +	// Update the display +	gwinDraw(&gw->g);  	#undef gsw -	#undef gh +} + +// 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  }  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)))) +	if (!(gs = (GSliderObject *)_gwidgetInit((GWidgetObject *)gs, x, y, width, height, sizeof(GSliderObject), &sliderVMT)))  		return 0; -	gs->gwin.type = GW_SLIDER; -	gs->fn = gwinSliderDraw_Std; -	gs->param = 0; -	gwinSetSliderStyle(&gs->gwin, &GSliderDefaultStyle); +	gs->c = GSliderDefaultColors;  	gs->min = 0;  	gs->max = 100;  	gs->pos = 0; -	gs->tracking = FALSE; -	geventListenerInit(&gs->listener); -	geventRegisterCallback(&gs->listener, gwinSliderCallback, gs); +	ResetDisplayPos(gs);  	return (GHandle)gs;  }  void gwinSetSliderRange(GHandle gh, int min, int max) {  	#define gsw		((GSliderObject *)gh) -	if (gh->type != GW_SLIDER) +	if (gh->vmt != (gwinVMT *)&sliderVMT)  		return;  	if (min == max)		// prevent divide by 0 errors. @@ -160,13 +188,14 @@ void gwinSetSliderRange(GHandle gh, int min, int max) {  	gsw->min = min;  	gsw->max = max;  	gsw->pos = min; +	ResetDisplayPos(gsw);  	#undef gsw  }  void gwinSetSliderPosition(GHandle gh, int pos) {  	#define gsw		((GSliderObject *)gh) -	if (gh->type != GW_SLIDER) +	if (gh->vmt != (gwinVMT *)&sliderVMT)  		return;  	if (gsw->min <= gsw->max) { @@ -178,125 +207,96 @@ void gwinSetSliderPosition(GHandle gh, int pos) {  		else if (pos < gsw->max) gsw->pos = gsw->max;  		else gsw->pos = pos;  	} +	ResetDisplayPos(gsw);  	#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 -} - -#if GFX_USE_GINPUT && GINPUT_NEED_MOUSE -	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 -	} -#endif - -void gwinSliderDraw(GHandle gh) { -	#define gsw		((GSliderObject *)gh) -	 -	if (gh->type != GW_SLIDER) +void gwinSetSliderColors(GHandle gh, const GSliderColors *pColors) { +	if (gh->vmt != (gwinVMT *)&sliderVMT)  		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 +	((GSliderObject *)gh)->c = *pColors;  } -void gwinSetSliderCustom(GHandle gh, GSliderDrawFunction fn, void *param) { -	#define gsw		((GSliderObject *)gh) +void gwinSliderDraw_Std(GWidgetObject *gw, void *param) { +	#define gsw		((GSliderObject *)gw) +	(void) param; -	if (gh->type != GW_SLIDER) +	if (gw->g.vmt != (gwinVMT *)&sliderVMT)  		return; -	gsw->fn = fn ? fn : gwinSliderDraw_Std; -	gsw->param = param; +	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);  	#undef gsw  } -void gwinSliderSetEnabled(GHandle gh, bool_t enabled) { -	if (gh->type != GW_SLIDER) -		return; +void gwinSliderDraw_Image(GWidgetObject *gw, void *param) { +	#define gsw		((GSliderObject *)gw) +	#define gi		((gdispImage *)param) +	coord_t			z, v; -	gh->enabled = enabled; -} +	if (gw->g.vmt != (gwinVMT *)&sliderVMT) +		return; -void gwinSliderDraw_Std(GHandle gh, bool_t isVertical, coord_t thumbpos, const GSliderDrawStyle *pstyle, void *param) { -	(void) param; +	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); -	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); +	// Horizontal slider  	} 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 GFX_USE_GINPUT && GINPUT_NEED_MOUSE -	bool_t gwinAttachSliderMouse(GHandle gh, uint16_t instance) { -		GSourceHandle	gsh; - -		if (gh->type != GW_SLIDER || !(gsh = ginputGetMouse(instance))) -			return FALSE; - -		return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); +		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);  	} -#endif - -#if GFX_USE_GINPUT && GINPUT_NEED_DIAL -	bool_t gwinAttachSliderDial(GHandle gh, uint16_t instance) { -		GSourceHandle	gsh; +	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); -		if (gh->type != GW_SLIDER || !(gsh = ginputGetDial(instance))) -			return FALSE; - -		return geventAttachSource(&((GSliderObject *)gh)->listener, gsh, 0); -	} -#endif +	#undef gsw +}  #endif /* GFX_USE_GWIN && GWIN_NEED_BUTTON */  /** @} */ | 
