diff options
author | inmarket <andrewh@inmarket.com.au> | 2015-10-13 01:00:10 +1000 |
---|---|---|
committer | inmarket <andrewh@inmarket.com.au> | 2015-10-13 01:00:10 +1000 |
commit | 10c7471149453cea6686aa6f61ec6dac0525c47b (patch) | |
tree | 11c872b10ad42872de3d44d7fec3aa5388ee90e4 /src/gwin/gwin_widget.c | |
parent | ddf79cd411e2cbdb58c485851b16be496109ab3b (diff) | |
parent | 5cf81b6fbe76cd5decab8e532fd607202abbc6c6 (diff) | |
download | uGFX-10c7471149453cea6686aa6f61ec6dac0525c47b.tar.gz uGFX-10c7471149453cea6686aa6f61ec6dac0525c47b.tar.bz2 uGFX-10c7471149453cea6686aa6f61ec6dac0525c47b.zip |
Merge branch 'TextEdit'
Diffstat (limited to 'src/gwin/gwin_widget.c')
-rw-r--r-- | src/gwin/gwin_widget.c | 177 |
1 files changed, 162 insertions, 15 deletions
diff --git a/src/gwin/gwin_widget.c b/src/gwin/gwin_widget.c index bfc5a48f..1bf91b11 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,13 @@ 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) || GWIN_NEED_KEYBOARD + // We should try and capture the focus on this window. + // If we can't then we don't change the focus + gwinSetFocus(gh); + #endif + if (wvmt->MouseDown) wvmt->MouseDown(gw, pme->x - gh->x, pme->y - gh->y); } @@ -142,6 +158,21 @@ static void gwidgetEvent(void *param, GEvent *pe) { break; #endif + #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_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 +222,108 @@ static void gwidgetEvent(void *param, GEvent *pe) { #undef pme #undef pte + #undef pke #undef pde } +#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_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; + bool_t looponce; + + // Find a new focus window (one may or may not exist). + looponce = FALSE; + for(gh = gwinGetNextWindow(_widgetInFocus); ; gh = gwinGetNextWindow(gh)) { + if (!gh && !looponce) { + looponce = TRUE; + gh = gwinGetNextWindow(0); + } + if (gwinSetFocus(gh)) + break; + } + } + + 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 +365,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 +401,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 +499,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 +535,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); } |