aboutsummaryrefslogtreecommitdiffstats
path: root/src/gwin/gwin_widget.c
diff options
context:
space:
mode:
authorinmarket <andrewh@inmarket.com.au>2015-10-13 01:00:10 +1000
committerinmarket <andrewh@inmarket.com.au>2015-10-13 01:00:10 +1000
commit10c7471149453cea6686aa6f61ec6dac0525c47b (patch)
tree11c872b10ad42872de3d44d7fec3aa5388ee90e4 /src/gwin/gwin_widget.c
parentddf79cd411e2cbdb58c485851b16be496109ab3b (diff)
parent5cf81b6fbe76cd5decab8e532fd607202abbc6c6 (diff)
downloaduGFX-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.c177
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);
}