diff options
Diffstat (limited to 'src/gwin/gwin_widget.c')
| -rw-r--r-- | src/gwin/gwin_widget.c | 173 | 
1 files changed, 158 insertions, 15 deletions
| diff --git a/src/gwin/gwin_widget.c b/src/gwin/gwin_widget.c index bfc5a48f..162d41e3 100644 --- a/src/gwin/gwin_widget.c +++ b/src/gwin/gwin_widget.c @@ -18,19 +18,25 @@  #include "gwin_class.h" -/* Our listener for events for widgets */ -static GListener			gl; +// Our listener for events for widgets +static GListener gl; -/* Our default style - a white background theme */ +#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD +	// Our current focus window +	static GHandle				_widgetInFocus; +#endif + +// Our default style - a white background theme  const GWidgetStyle WhiteWidgetStyle = {  	HTML2COLOR(0xFFFFFF),			// window background +	HTML2COLOR(0x2A8FCD),			// focused  	// enabled color set  	{  		HTML2COLOR(0x000000),		// text  		HTML2COLOR(0x404040),		// edge  		HTML2COLOR(0xE0E0E0),		// fill -		HTML2COLOR(0xE0E0E0),		// progress - inactive area +		HTML2COLOR(0xE0E0E0)		// progress - inactive area  	},  	// disabled color set @@ -38,7 +44,7 @@ const GWidgetStyle WhiteWidgetStyle = {  		HTML2COLOR(0xC0C0C0),		// text  		HTML2COLOR(0x808080),		// edge  		HTML2COLOR(0xE0E0E0),		// fill -		HTML2COLOR(0xC0E0C0),		// progress - active area +		HTML2COLOR(0xC0E0C0)		// progress - active area  	},  	// pressed color set @@ -46,20 +52,21 @@ const GWidgetStyle WhiteWidgetStyle = {  		HTML2COLOR(0x404040),		// text  		HTML2COLOR(0x404040),		// edge  		HTML2COLOR(0x808080),		// fill -		HTML2COLOR(0x00E000),		// progress - active area -	}, +		HTML2COLOR(0x00E000)		// progress - active area +	}  };  /* Our black style */  const GWidgetStyle BlackWidgetStyle = {  	HTML2COLOR(0x000000),			// window background +	HTML2COLOR(0x2A8FCD),			// focused  	// enabled color set  	{  		HTML2COLOR(0xC0C0C0),		// text  		HTML2COLOR(0xC0C0C0),		// edge  		HTML2COLOR(0x606060),		// fill -		HTML2COLOR(0x404040),		// progress - inactive area +		HTML2COLOR(0x404040)		// progress - inactive area  	},  	// disabled color set @@ -67,7 +74,7 @@ const GWidgetStyle BlackWidgetStyle = {  		HTML2COLOR(0x808080),		// text  		HTML2COLOR(0x404040),		// edge  		HTML2COLOR(0x404040),		// fill -		HTML2COLOR(0x004000),		// progress - active area +		HTML2COLOR(0x004000)		// progress - active area  	},  	// pressed color set @@ -75,19 +82,20 @@ const GWidgetStyle BlackWidgetStyle = {  		HTML2COLOR(0xFFFFFF),		// text  		HTML2COLOR(0xC0C0C0),		// edge  		HTML2COLOR(0xE0E0E0),		// fill -		HTML2COLOR(0x008000),		// progress - active area -	}, +		HTML2COLOR(0x008000)		// progress - active area +	}  };  static const GWidgetStyle *	defaultStyle = &BlackWidgetStyle; -/* We use these everywhere in this file */ +// We use these everywhere in this file  #define gw		((GWidgetObject *)gh)  #define wvmt	((gwidgetVMT *)gh->vmt) -/* Process an event */ +// Process an event  static void gwidgetEvent(void *param, GEvent *pe) {  	#define pme		((GEventMouse *)pe) +	#define pke		((GEventKeyboard *)pe)  	#define pte		((GEventToggle *)pe)  	#define pde		((GEventDial *)pe) @@ -105,7 +113,7 @@ static void gwidgetEvent(void *param, GEvent *pe) {  	case GEVENT_MOUSE:  	case GEVENT_TOUCH:  		// Cycle through all windows -		for(gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) { +		for (gh = 0, h = gwinGetNextWindow(0); h; h = gwinGetNextWindow(h)) {  			// The window must be on this display and visible to be relevant  			if (h->display != pme->display || !(h->flags & GWIN_FLG_SYSVISIBLE)) @@ -123,6 +131,7 @@ static void gwidgetEvent(void *param, GEvent *pe) {  				// There is only ever one captured mouse. Prevent normal mouse processing if there is a captured mouse  				gh = 0; +			  				break;  			} @@ -135,6 +144,14 @@ static void gwidgetEvent(void *param, GEvent *pe) {  		if (gh && (gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) == (GWIN_FLG_WIDGET|GWIN_FLG_SYSENABLED)) {  			if ((pme->buttons & GMETA_MOUSE_DOWN)) {  				gh->flags |= GWIN_FLG_MOUSECAPTURE; + +				#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD +					// We should try and capture the focus on this window. +					// If we can't no window should have the focus +					if (!gwinSetFocus(gh)) +						gwinSetFocus(0); +				#endif +  				if (wvmt->MouseDown)  					wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y);  			} @@ -142,6 +159,21 @@ static void gwidgetEvent(void *param, GEvent *pe) {  		break;  	#endif +	#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD +	case GEVENT_KEYBOARD: +		// If Tab key pressed then set focus to next widget +		if (pke->bytecount == 1 && pke->c[0] == GKEY_TAB) { +			if (!(pke->keystate & GKEYSTATE_KEYUP)) +				_gwinMoveFocus(); +			break; +		} + +		// Otherwise, send keyboard events only to widget in focus +		if (_widgetInFocus) +			((gwidgetVMT*)_widgetInFocus->vmt)->KeyboardEvent((GWidgetObject*)_widgetInFocus, pke); +		break; +	#endif +  	#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE  	case GEVENT_TOGGLE:  		// Cycle through all windows @@ -191,9 +223,103 @@ static void gwidgetEvent(void *param, GEvent *pe) {  	#undef pme  	#undef pte +	#undef pke  	#undef pde  } +#if GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD +	GHandle gwinGetFocus(void) { +		return _widgetInFocus; +	} + +	bool_t gwinSetFocus(GHandle gh) { +		GHandle	oldFocus; + +		// Do we already have the focus? +		if (gh == _widgetInFocus) +			return TRUE; + +		// The new window must be NULLL or a visible enabled widget with a keyboard handler +		if (!gh || ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) +						&& ((gwidgetVMT*)gh->vmt)->KeyboardEvent)) { +			// Move the current focus +			oldFocus = _widgetInFocus; +			_widgetInFocus = gh; +			if (oldFocus)	_gwinUpdate(oldFocus); +			if (gh)			_gwinUpdate(gh); +			return TRUE; +		} +		return FALSE; +	} + +	void _gwinMoveFocus(void) { +		GHandle	gh; + +		// Find a new focus window (one may or may not exist). +		for(gh = gwinGetNextWindow(_widgetInFocus); gh && gh != _widgetInFocus; gh = gwinGetNextWindow(gh)) { +			if (gwinSetFocus(gh)) +				return; +		} +		gwinSetFocus(0); +	} + +	void _gwinFixFocus(GHandle gh) { +		GHandle	oldFocus; + +		if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) +				&& ((gwidgetVMT*)gh->vmt)->KeyboardEvent) { + +			// We are a candidate to be able to claim the focus + +			// Claim the focus if no-one else has +			if (!_widgetInFocus) +				_widgetInFocus = gh; + +			return; +		} + +		// We have lost any right to the focus + +		// Did we have the focus +		if (gh != _widgetInFocus) +			return; + +		// We did - we need to find a new focus window +		oldFocus = _widgetInFocus; +		for(gh = gwinGetNextWindow(oldFocus); gh && gh != oldFocus; gh = gwinGetNextWindow(gh)) { + +			// Must be a visible enabled widget with a keyboard handler +			if ((gh->flags & (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE)) == (GWIN_FLG_WIDGET|GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED|GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE) +					&& ((gwidgetVMT*)gh->vmt)->KeyboardEvent) { + +				// Grab the focus for the new window +				_widgetInFocus = gh; + +				// This new window still needs to be marked for redraw (but don't actually do it yet). +				gh->flags |= GWIN_FLG_NEEDREDRAW; +				// RedrawPending |= DOREDRAW_VISIBLES;			- FIX LATER +				return; +			} +		} + +		// No-one has the right to the focus +		_widgetInFocus = 0; +	} + +	void _gwidgetDrawFocusRect(GWidgetObject *gx, coord_t x, coord_t y, coord_t cx, coord_t cy) { +		// Don't do anything if we don't have the focus +		if (&gx->g != _widgetInFocus) +			return; + +		// Use the very simplest possible focus rectangle for now +		uint16_t i = 0; +		for (i = 0; i < GWIN_FOCUS_HIGHLIGHT_WIDTH; i++) { +			gdispGDrawBox(gx->g.display, gx->g.x+x+i, gx->g.y+y+i, cx-2*i, cy-2*i, gx->pstyle->focus); +		} +	} + +#endif +  #if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE  	static GHandle FindToggleUser(uint16_t instance) {  		GHandle			gh; @@ -235,6 +361,10 @@ void _gwidgetInit(void)  	geventListenerInit(&gl);  	geventRegisterCallback(&gl, gwidgetEvent, 0);  	geventAttachSource(&gl, ginputGetMouse(GMOUSE_ALL_INSTANCES), GLISTEN_MOUSEMETA|GLISTEN_MOUSEDOWNMOVES); + +	#if GINPUT_NEED_KEYBOARD +		geventAttachSource(&gl, ginputGetKeyboard(GKEYBOARD_ALL_INSTANCES), GLISTEN_KEYUP); +	#endif  }  void _gwidgetDeinit(void) @@ -267,6 +397,10 @@ void _gwidgetDestroy(GHandle gh) {  		uint16_t	role, instance;  	#endif +	// Make the window is invisible so it is not eligible for focus +	gh->flags &= ~GWIN_FLG_VISIBLE; +	_gwinFixFocus(gh); +  	// Deallocate the text (if necessary)  	if ((gh->flags & GWIN_FLG_ALLOCTXT)) {  		gh->flags &= ~GWIN_FLG_ALLOCTXT; @@ -361,7 +495,6 @@ const GWidgetStyle *gwinGetDefaultStyle(void) {  	return defaultStyle;  } -  void gwinSetText(GHandle gh, const char *text, bool_t useAlloc) {  	if (!(gh->flags & GWIN_FLG_WIDGET))  		return; @@ -398,12 +531,22 @@ const char *gwinGetText(GHandle gh) {  	return gw->text;  } +bool_t gwinIsWidget(GHandle gh) { +	if (gh->flags & GWIN_FLG_WIDGET) { +		return TRUE; +	} + +	return FALSE; +} +  void gwinSetStyle(GHandle gh, const GWidgetStyle *pstyle) {  	if (!(gh->flags & GWIN_FLG_WIDGET))  		return; +  	gw->pstyle = pstyle ? pstyle : defaultStyle;  	gh->bgcolor = pstyle->background;  	gh->color = pstyle->enabled.text; +  	_gwinUpdate(gh);  } | 
