Updates to focus.
parent
377fe644d1
commit
15e7342fd7
|
@ -48,13 +48,15 @@
|
|||
#define GDISP_NEED_CLIP TRUE
|
||||
#define GDISP_NEED_TEXT TRUE
|
||||
#define GDISP_NEED_TEXT_KERNING TRUE
|
||||
#define GDISP_NEED_STARTUP_LOGO TRUE
|
||||
#define GDISP_NEED_MULTITHREAD TRUE
|
||||
|
||||
/* GDISP fonts to include */
|
||||
#define GDISP_INCLUDE_FONT_UI2 TRUE
|
||||
#define GDISP_INCLUDE_FONT_DEJAVUSANS16 TRUE
|
||||
|
||||
/* Features for the GWIN subsystem. */
|
||||
#define GWIN_NEED_WINDOWMANAGER TRUE
|
||||
#define GWIN_NEED_WIDGET TRUE
|
||||
#define GWIN_NEED_CONSOLE TRUE
|
||||
#define GWIN_NEED_TEXTEDIT TRUE
|
||||
#define GWIN_NEED_BUTTON TRUE
|
||||
|
@ -63,5 +65,9 @@
|
|||
#define GINPUT_NEED_MOUSE TRUE
|
||||
#define GINPUT_NEED_KEYBOARD TRUE
|
||||
|
||||
/* Features for the GQUEUE subsystem. */
|
||||
#define GFX_USE_GQUEUE TRUE
|
||||
#define GQUEUE_NEED_ASYNC TRUE
|
||||
|
||||
#endif /* _GFXCONF_H */
|
||||
|
||||
|
|
|
@ -49,13 +49,14 @@
|
|||
/* Our custom yellow style */
|
||||
static const GWidgetStyle YellowWidgetStyle = {
|
||||
Yellow, // window background
|
||||
HTML2COLOR(0x800000), // focus
|
||||
|
||||
// enabled color set
|
||||
{
|
||||
HTML2COLOR(0x0000FF), // text
|
||||
HTML2COLOR(0x404040), // edge
|
||||
HTML2COLOR(0xE0E0E0), // fill
|
||||
HTML2COLOR(0xE0E0E0), // progress - inactive area
|
||||
HTML2COLOR(0xE0E0E0) // progress - inactive area
|
||||
},
|
||||
|
||||
// disabled color set
|
||||
|
@ -63,7 +64,7 @@ static const GWidgetStyle YellowWidgetStyle = {
|
|||
HTML2COLOR(0xC0C0C0), // text
|
||||
HTML2COLOR(0x808080), // edge
|
||||
HTML2COLOR(0xE0E0E0), // fill
|
||||
HTML2COLOR(0xC0E0C0), // progress - active area
|
||||
HTML2COLOR(0xC0E0C0) // progress - active area
|
||||
},
|
||||
|
||||
// pressed color set
|
||||
|
@ -72,7 +73,7 @@ static const GWidgetStyle YellowWidgetStyle = {
|
|||
HTML2COLOR(0x404040), // edge
|
||||
HTML2COLOR(0x808080), // fill
|
||||
HTML2COLOR(0x00E000), // progress - active area
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
/* The variables we need */
|
||||
|
|
|
@ -552,31 +552,6 @@ extern "C" {
|
|||
*/
|
||||
GHandle gwinGetNextWindow(GHandle gh);
|
||||
|
||||
/**
|
||||
* @brief Set the focus to a specific widget
|
||||
*
|
||||
* @details The widget that is currently in focus is the widget that
|
||||
* receives mouse and keyboard events.
|
||||
* Passing NULL will remove the focus from any widget.
|
||||
*
|
||||
* @param[in] gh The widget handle. Non-widget handles will be ignored.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gwinSetFocus(GHandle gh);
|
||||
|
||||
/**
|
||||
* @brief Get the widget that is currently in focus
|
||||
*
|
||||
* @details The widget that is currently in focus is the widget that
|
||||
* receives mouse and keyboard events.
|
||||
*
|
||||
* @return The handle of the widget that is currently in focus. May be NULL.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GHandle gwinGetFocus(void);
|
||||
|
||||
/**
|
||||
* @brief Set a window or widget to flash
|
||||
*
|
||||
|
|
|
@ -256,9 +256,8 @@ void _gwinDrawEnd(GHandle gh);
|
|||
* @param[in] gh The window
|
||||
* @param[in] how Do we wait for the lock?
|
||||
*
|
||||
* @note This call will delete the window. If called without the
|
||||
* drawing lock 'how' must be REDRAW_WAIT. If called with the drawing
|
||||
* lock 'how' must be REDRAW_INSESSION.
|
||||
* @note If called without the drawing lock 'how' must be REDRAW_WAIT.
|
||||
* If called with the drawing lock 'how' must be REDRAW_INSESSION.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
|
@ -322,6 +321,50 @@ bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit);
|
|||
*/
|
||||
void _gwinSendEvent(GHandle gh, GEventType type);
|
||||
|
||||
#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Move the focus off the current focus window.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gwinMoveFocus(void);
|
||||
|
||||
/**
|
||||
* @brief Do focus fixup's after a change of state for a window.
|
||||
* @details If a focus window has become invisible or disabled then
|
||||
* the focus must be taken away from it. If there is no focus
|
||||
* window and this window is eligible then this window becomes
|
||||
* the focus.
|
||||
*
|
||||
* @param[in] gh The window
|
||||
*
|
||||
* @note This routine does not actually do a redraw. It assumes that surrounding code
|
||||
* will because of the change of state that lead to this being called.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gwinFixFocus(GHandle gh);
|
||||
|
||||
/**
|
||||
* @brief Draw a simple focus rectangle in the default style.
|
||||
*
|
||||
* @param[in] gw The widget
|
||||
* @param[in] x, y The start x, y position (relative to the window)
|
||||
* @param[in] cx, cy The width & height of the rectangle
|
||||
*
|
||||
* @note Assumes the widget is in a state where it can draw.
|
||||
* @note Nothing is drawn if the window doesn't have focus.
|
||||
* @note The focus rectangle may be more than one pixel thick and may
|
||||
* not be a continuous line.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
void _gwidgetDrawFocusRect(GWidgetObject *gw, coord_t x, coord_t y, coord_t cx, coord_t cy);
|
||||
|
||||
#else
|
||||
#define _gwinFixFocus(gh)
|
||||
#define _gwidgetDrawFocusRect(gh,x,y,cx,cy)
|
||||
#endif
|
||||
|
||||
#if GWIN_NEED_FLASHING || defined(__DOXYGEN__)
|
||||
/**
|
||||
|
@ -335,6 +378,8 @@ bool_t _gwinWMAdd(GHandle gh, const GWindowInit *pInit);
|
|||
*/
|
||||
const GColorSet *_gwinGetFlashedColor(GWidgetObject *gw, const GColorSet *pcol, bool_t flashOffState);
|
||||
#endif
|
||||
#else
|
||||
#define _gwinFixFocus(gh)
|
||||
#endif
|
||||
|
||||
#if GWIN_NEED_CONTAINERS || defined(__DOXYGEN__)
|
||||
|
|
|
@ -23,9 +23,6 @@ const int FOCUS_BORDER_THICKNESS = 3;
|
|||
const int CURSOR_PADDING_LEFT = 0;
|
||||
const int CURSOR_EXTRA_HEIGHT = 1;
|
||||
|
||||
// Some flags
|
||||
#define GTEXTEDIT_FLG_BORDER (GWIN_FIRST_CONTROL_FLAG << 0)
|
||||
|
||||
// Macros to assist in data type conversions
|
||||
#define gh2obj ((GTexteditObject *)gh)
|
||||
#define gw2obj ((GTexteditObject *)gw)
|
||||
|
@ -65,7 +62,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char
|
|||
|
||||
|
||||
#if GINPUT_NEED_KEYBOARD
|
||||
static void _keyboardEvent(GWidgetObject* gw, GEventKeyboard* pke)
|
||||
static void TextEditKeyboard(GWidgetObject* gw, GEventKeyboard* pke)
|
||||
{
|
||||
// Only react on KEYDOWN events. Ignore KEYUP events.
|
||||
if (pke->keystate & GKEYSTATE_KEYUP) {
|
||||
|
@ -116,9 +113,8 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char
|
|||
// Add a new character
|
||||
else {
|
||||
// Prevent buffer overflow
|
||||
if (gw2obj->cursorPos >= gw2obj->bufferSize) {
|
||||
if (gw2obj->cursorPos >= gw2obj->maxSize)
|
||||
return;
|
||||
}
|
||||
|
||||
// Shift everything right from the cursor by one character. This includes the '\0'. Then inser the new character.
|
||||
_shiftTextRight(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos++, pke->c[0]);
|
||||
|
@ -152,7 +148,7 @@ static const gwidgetVMT texteditVMT = {
|
|||
#endif
|
||||
#if GINPUT_NEED_KEYBOARD
|
||||
{
|
||||
_keyboardEvent // Process keyboard key down events
|
||||
TextEditKeyboard // Process keyboard key down events
|
||||
},
|
||||
#endif
|
||||
#if GINPUT_NEED_TOGGLE
|
||||
|
@ -174,50 +170,33 @@ static const gwidgetVMT texteditVMT = {
|
|||
#endif
|
||||
};
|
||||
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit, size_t bufSize)
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize)
|
||||
{
|
||||
uint16_t flags = 0;
|
||||
|
||||
// Create the underlying widget
|
||||
if (!(widget = (GTexteditObject*)_gwidgetCreate(g, &widget->w, pInit, &texteditVMT))) {
|
||||
if (!(wt = (GTexteditObject*)_gwidgetCreate(g, &wt->w, pInit, &texteditVMT)))
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Allocate the text buffer
|
||||
widget->bufferSize = bufSize;
|
||||
widget->textBuffer = gfxAlloc(widget->bufferSize);
|
||||
if (widget->textBuffer == 0) {
|
||||
wt->maxSize = maxSize;
|
||||
wt->textBuffer = gfxAlloc(widget->maxSize);
|
||||
if (wt->textBuffer == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Initialize the text buffer
|
||||
size_t i = 0;
|
||||
for (i = 0; i < bufSize; i++) {
|
||||
widget->textBuffer[i] = '\0';
|
||||
wt->textBuffer[i] = '\0';
|
||||
}
|
||||
|
||||
// Set text and cursor position
|
||||
strncpy(widget->textBuffer, gwinGetText((GHandle)widget), widget->bufferSize); // FixMe: pInit->text leads to a segfault
|
||||
widget->cursorPos = strlen(widget->textBuffer);
|
||||
strncpy(wt->textBuffer, gwinGetText((GHandle)wt), wt->maxSize); // FixMe: pInit->text leads to a segfault
|
||||
wt->cursorPos = strlen(wt->textBuffer);
|
||||
|
||||
widget->w.g.flags |= flags | GTEXTEDIT_FLG_BORDER;;
|
||||
gwinSetVisible(&widget->w.g, pInit->g.show);
|
||||
gwinSetVisible(&wt->w.g, pInit->g.show);
|
||||
|
||||
return (GHandle)widget;
|
||||
}
|
||||
|
||||
void gwinTexteditSetBorder(GHandle gh, bool_t border)
|
||||
{
|
||||
// Is it a valid handle?
|
||||
if (gh->vmt != (gwinVMT*)&texteditVMT) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (border) {
|
||||
gh2obj->w.g.flags |= GTEXTEDIT_FLG_BORDER;
|
||||
} else {
|
||||
gh2obj->w.g.flags &=~ GTEXTEDIT_FLG_BORDER;
|
||||
}
|
||||
return (GHandle)wt;
|
||||
}
|
||||
|
||||
static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param)
|
||||
|
@ -238,18 +217,11 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param)
|
|||
gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->pstyle->background);
|
||||
gdispGFillStringBox(gw->g.display, gw->g.x + TEXT_PADDING_LEFT, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft);
|
||||
|
||||
// Render border (if supposed to)
|
||||
if (gw2obj->w.g.flags & GTEXTEDIT_FLG_BORDER) {
|
||||
gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge);
|
||||
}
|
||||
// Render border (always)
|
||||
gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge);
|
||||
|
||||
// Render highlighted border of focused
|
||||
if (gwinGetFocus() == (GHandle)gw) {
|
||||
int i = 0;
|
||||
for (i = 0; i < FOCUS_BORDER_THICKNESS; i++) {
|
||||
gdispGDrawBox(gw->g.display, gw->g.x+i, gw->g.y+i, gw->g.width-2*i, gw->g.height-2*i, gw->pstyle->focus);
|
||||
}
|
||||
}
|
||||
_gwidgetDrawFocusRect(gw, 0, 0, gw->g.width-1, gw->g.height-1);
|
||||
|
||||
// Render cursor (if focused)
|
||||
if (gwinGetFocus() == (GHandle)gw) {
|
||||
|
|
|
@ -33,7 +33,7 @@ typedef struct GTexteditObject {
|
|||
GWidgetObject w;
|
||||
|
||||
char* textBuffer;
|
||||
size_t bufferSize;
|
||||
size_t maxSize;
|
||||
uint16_t cursorPos;
|
||||
} GTexteditObject;
|
||||
|
||||
|
@ -48,28 +48,17 @@ extern "C" {
|
|||
* is abstracted through the GINPUT module.
|
||||
*
|
||||
* @param[in] g The GDisplay on which the textedit should be displayed
|
||||
* @param[in] widget The TextEdit structure to initialise. If this is NULL, the structure is dynamically allocated.
|
||||
* @param[in] wt The TextEdit structure to initialise. If this is NULL, the structure is dynamically allocated.
|
||||
* @param[in] pInit The initialisation parameters to use.
|
||||
* @param[in] bufSize The maximum number of characters the TextEdit widget can hold.
|
||||
* @param[in] maxSize The maximum number of characters the TextEdit widget can hold.
|
||||
*
|
||||
* @return NULL if there is no resultat drawing area, otherwise the widget handle.
|
||||
* @return NULL if there is no resultant drawing area, otherwise the widget handle.
|
||||
*
|
||||
* @note If the initial text set is larger than maxSize then the text is truncated at maxSize characters.
|
||||
* @api
|
||||
*/
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit, size_t bufSize);
|
||||
#define gwinTexteditCreate(w, pInit, bufSize) gwinGTexteditCreate(GDISP, w, pInit, bufSize)
|
||||
|
||||
/**
|
||||
* @brief Border settings for the default rendering routine
|
||||
*
|
||||
* @note Border is enabled by default.
|
||||
*
|
||||
* @param[in] gh The widget handle (must be a TextEdit handle)
|
||||
* @param[in] border Shall a border be rendered?
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
void gwinTexteditSetBorder(GHandle gh, bool_t border);
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize);
|
||||
#define gwinTexteditCreate(wt, pInit, maxSize) gwinGTexteditCreate(GDISP, wt, pInit, maxSize)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -21,6 +21,11 @@
|
|||
// Our listener for events for widgets
|
||||
static GListener gl;
|
||||
|
||||
#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
|
||||
|
@ -139,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);
|
||||
}
|
||||
|
@ -150,79 +163,14 @@ static void gwidgetEvent(void *param, GEvent *pe) {
|
|||
case GEVENT_KEYBOARD:
|
||||
// If Tab key pressed then set focus to next widget
|
||||
if (pke->bytecount == 1 && pke->c[0] == GKEY_TAB) {
|
||||
|
||||
// Only react on KEYDOWN events. Ignore KEYUP events.
|
||||
if (pke->keystate & GKEYSTATE_KEYUP)
|
||||
break;
|
||||
|
||||
// Get the next widget
|
||||
bool_t foundWidget = FALSE;
|
||||
bool_t endOfListDetected = FALSE;
|
||||
GHandle nextWidget = gwinGetFocus();
|
||||
GHandle prevWidget = gwinGetFocus();
|
||||
do {
|
||||
nextWidget = gwinGetNextWindow(nextWidget);
|
||||
foundWidget = TRUE;
|
||||
|
||||
// Begin with the first one if this is the last one
|
||||
if (nextWidget == 0) {
|
||||
foundWidget = FALSE;
|
||||
// We go through the list twice - just to be sure
|
||||
if (endOfListDetected)
|
||||
break;
|
||||
endOfListDetected = TRUE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Check whether this is a window or a widget
|
||||
if (!gwinIsWidget(nextWidget)) {
|
||||
foundWidget = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only focus on a widget that is visible and enabled
|
||||
if (!(nextWidget->flags & GWIN_FLG_SYSVISIBLE) || !(nextWidget->flags & GWIN_FLG_ENABLED)) {
|
||||
foundWidget = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
// When using the TAB key we only focus on widgets that process keyboard events
|
||||
if (((gwidgetVMT*)nextWidget->vmt)->KeyboardEvent == 0) {
|
||||
foundWidget = FALSE;
|
||||
continue;
|
||||
}
|
||||
|
||||
} while (foundWidget == FALSE);
|
||||
gwinSetFocus(nextWidget);
|
||||
|
||||
// Redraw the new and the previous focused widget because they usually render differently when
|
||||
// they are not focused anymore (eg. no blinking cursor)
|
||||
if (prevWidget != 0)
|
||||
gwinRedraw(prevWidget);
|
||||
if (nextWidget != 0)
|
||||
gwinRedraw(nextWidget);
|
||||
|
||||
if (!(pke->keystate & GKEYSTATE_KEYUP))
|
||||
_gwinMoveFocus();
|
||||
break;
|
||||
}
|
||||
|
||||
// Otherise, send keyboard events only to widget in focus
|
||||
GHandle widgetInFocus = gwinGetFocus();
|
||||
if (widgetInFocus != 0) {
|
||||
// Make sure that it is a widget
|
||||
if (!gwinIsWidget(widgetInFocus))
|
||||
break;
|
||||
|
||||
// Make sure that the widget is enabled and visible
|
||||
if (!(widgetInFocus->flags & GWIN_FLG_SYSVISIBLE) || !(widgetInFocus->flags & GWIN_FLG_ENABLED))
|
||||
break;
|
||||
|
||||
// Check whether this widget provides a method for handling keyboard events
|
||||
if (((gwidgetVMT*)widgetInFocus->vmt)->KeyboardEvent == 0)
|
||||
break;
|
||||
|
||||
// If we got this far we can finally pass the event
|
||||
((gwidgetVMT*)widgetInFocus->vmt)->KeyboardEvent((GWidgetObject*)widgetInFocus, pke);
|
||||
}
|
||||
// Otherwise, send keyboard events only to widget in focus
|
||||
if (_widgetInFocus)
|
||||
((gwidgetVMT*)_widgetInFocus->vmt)->KeyboardEvent((GWidgetObject*)_widgetInFocus, pke);
|
||||
break;
|
||||
#endif
|
||||
|
||||
|
@ -278,6 +226,96 @@ static void gwidgetEvent(void *param, GEvent *pe) {
|
|||
#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;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No-one has the right to the focus
|
||||
_widgetInFocus = 0;
|
||||
}
|
||||
|
||||
void _gwidgetDrawFocusRect(GWidgetObject *gw, coord_t x, coord_t y, coord_t cx, coord_t cy) {
|
||||
// Don't do anything if we don't have the focus
|
||||
if (&gw->g != _widgetInFocus)
|
||||
return;
|
||||
|
||||
// Use the very simplest possible focus rectangle for now.
|
||||
gdispGDrawBox(gw->g.display, gw->g.x+x, gw->g.y+y, cx, cy, gw->pstyle.focus);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if GFX_USE_GINPUT && GINPUT_NEED_TOGGLE
|
||||
static GHandle FindToggleUser(uint16_t instance) {
|
||||
GHandle gh;
|
||||
|
@ -355,6 +393,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;
|
||||
|
|
|
@ -356,6 +356,36 @@ bool_t gwinAttachListener(GListener *pl);
|
|||
bool_t gwinAttachDial(GHandle gh, uint16_t role, uint16_t instance);
|
||||
#endif
|
||||
|
||||
#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || defined(__DOXYGEN__)
|
||||
/**
|
||||
* @brief Set the keyboard focus to a specific window
|
||||
* @return Returns TRUE if the focus could be set to that window
|
||||
*
|
||||
* @param[in] gh The window
|
||||
*
|
||||
* @note Passing NULL will remove the focus from any window.
|
||||
* @note Only visible enabled widgets are capable of getting the focus.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
bool_t gwinSetFocus(GHandle gh);
|
||||
|
||||
/**
|
||||
* @brief Get the widget that is currently in focus
|
||||
*
|
||||
* @details The widget that is currently in focus is the widget that
|
||||
* receives mouse and keyboard events.
|
||||
*
|
||||
* @return The handle of the widget that is currently in focus. May be NULL.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GHandle gwinGetFocus(void);
|
||||
#else
|
||||
#define gwinGetFocus() (0)
|
||||
#define gwinSetFocus(gh) (FALSE)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -162,7 +162,6 @@
|
|||
extern const GWindowManager GNullWindowManager;
|
||||
GWindowManager * _GWINwm;
|
||||
bool_t _gwinFlashState;
|
||||
static GHandle _widgetInFocus;
|
||||
static gfxSem gwinsem;
|
||||
static gfxQueueASync _GWINList;
|
||||
#if GWIN_NEED_FLASHING
|
||||
|
@ -333,14 +332,23 @@ void _gwinUpdate(GHandle gh) {
|
|||
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE)) {
|
||||
// We have been made visible
|
||||
gh->flags |= (GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
|
||||
|
||||
// Do we want to grab the focus
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
RedrawPending |= DOREDRAW_VISIBLES;
|
||||
}
|
||||
break;
|
||||
case (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE):
|
||||
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE))
|
||||
break;
|
||||
|
||||
// Parent has been made invisible
|
||||
gh->flags &= ~GWIN_FLG_SYSVISIBLE;
|
||||
|
||||
// No focus for us anymore
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
break;
|
||||
case GWIN_FLG_SYSVISIBLE:
|
||||
// We have been made invisible
|
||||
|
@ -348,6 +356,10 @@ void _gwinUpdate(GHandle gh) {
|
|||
if (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSVISIBLE)) {
|
||||
// The parent is visible so we must clear the area we took
|
||||
gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
|
||||
|
||||
// No focus for us anymore
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
RedrawPending |= DOREDRAW_INVISIBLES;
|
||||
}
|
||||
break;
|
||||
|
@ -457,6 +469,10 @@ void gwinRedraw(GHandle gh) {
|
|||
if (visible) {
|
||||
if (!(gh->flags & GWIN_FLG_VISIBLE)) {
|
||||
gh->flags |= (GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE|GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
|
||||
|
||||
// Do we want to grab the focus
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
RedrawPending |= DOREDRAW_VISIBLES;
|
||||
TriggerRedraw();
|
||||
}
|
||||
|
@ -464,6 +480,10 @@ void gwinRedraw(GHandle gh) {
|
|||
if ((gh->flags & GWIN_FLG_VISIBLE)) {
|
||||
gh->flags &= ~(GWIN_FLG_VISIBLE|GWIN_FLG_SYSVISIBLE);
|
||||
gh->flags |= (GWIN_FLG_NEEDREDRAW|GWIN_FLG_BGREDRAW);
|
||||
|
||||
// No focus for us anymore
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
RedrawPending |= DOREDRAW_INVISIBLES;
|
||||
TriggerRedraw();
|
||||
}
|
||||
|
@ -484,6 +504,10 @@ void gwinRedraw(GHandle gh) {
|
|||
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
|
||||
if ((gh->flags & (GWIN_FLG_SYSENABLED|GWIN_FLG_ENABLED)) == GWIN_FLG_ENABLED && (!gh->parent || (gh->parent->flags & GWIN_FLG_SYSENABLED))) {
|
||||
gh->flags |= GWIN_FLG_SYSENABLED; // Fix it
|
||||
|
||||
// Do we want to grab the focus
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
_gwinUpdate(gh);
|
||||
}
|
||||
}
|
||||
|
@ -497,6 +521,10 @@ void gwinRedraw(GHandle gh) {
|
|||
for(gh = gwinGetNextWindow(0); gh; gh = gwinGetNextWindow(gh)) {
|
||||
if ((gh->flags & GWIN_FLG_SYSENABLED) && (!(gh->flags & GWIN_FLG_ENABLED) || (gh->parent && !(gh->parent->flags & GWIN_FLG_SYSENABLED)))) {
|
||||
gh->flags &= ~GWIN_FLG_SYSENABLED; // Fix it
|
||||
|
||||
// No focus for us anymore
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
_gwinUpdate(gh);
|
||||
}
|
||||
}
|
||||
|
@ -508,11 +536,19 @@ void gwinRedraw(GHandle gh) {
|
|||
if (enabled) {
|
||||
if (!(gh->flags & GWIN_FLG_ENABLED)) {
|
||||
gh->flags |= (GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED);
|
||||
|
||||
// Do we want to grab the focus
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
_gwinUpdate(gh);
|
||||
}
|
||||
} else {
|
||||
if ((gh->flags & GWIN_FLG_ENABLED)) {
|
||||
gh->flags &= ~(GWIN_FLG_ENABLED|GWIN_FLG_SYSENABLED);
|
||||
|
||||
// No focus for us anymore
|
||||
_gwinFixFocus(gh);
|
||||
|
||||
_gwinUpdate(gh);
|
||||
}
|
||||
}
|
||||
|
@ -573,25 +609,6 @@ GHandle gwinGetNextWindow(GHandle gh) {
|
|||
return gh ? (GHandle)gfxQueueASyncNext(&gh->wmq) : (GHandle)gfxQueueASyncPeek(&_GWINList);
|
||||
}
|
||||
|
||||
void gwinSetFocus(GHandle gh) {
|
||||
// Passing NULL removes the focus from any widget
|
||||
if (gh == 0) {
|
||||
_widgetInFocus = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
// Only accept widgets
|
||||
if (!gwinIsWidget(gh)) {
|
||||
return;
|
||||
}
|
||||
|
||||
_widgetInFocus = gh;
|
||||
}
|
||||
|
||||
GHandle gwinGetFocus(void) {
|
||||
return _widgetInFocus;
|
||||
}
|
||||
|
||||
#if GWIN_NEED_FLASHING
|
||||
static void FlashTimerFn(void *param) {
|
||||
GHandle gh;
|
||||
|
|
Loading…
Reference in New Issue