From 0388755df1e3d65aa6d17f90965bcf5037c204ab Mon Sep 17 00:00:00 2001 From: inmarket Date: Sat, 26 Aug 2017 11:15:56 +1000 Subject: [PATCH] Add gwinTextEditSendKey() and gwinTextEditSendSpecialKey() --- changelog.txt | 1 + src/gwin/gwin_textedit.c | 190 +++++++++++++++++++++------------------ src/gwin/gwin_textedit.h | 26 ++++++ 3 files changed, 132 insertions(+), 85 deletions(-) diff --git a/changelog.txt b/changelog.txt index b44253db..22a6ea73 100644 --- a/changelog.txt +++ b/changelog.txt @@ -47,6 +47,7 @@ REMOVED: Removed long deprecated functions gfxSemCounter() and gfxSemCounterI() FIX: gwinDetachToggle() is now a visible part of the API CHANGE: Update OSX makefiles (allows for 64bit building) FIX: Fixed resetting a timer on gwinImage objects when using animated GIFs +FEATURE: Added gwinTextEditSendKey() and gwinTextEditSendSpecialKey() *** Release 2.7 *** diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 8e639300..61c28c66 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -26,54 +26,54 @@ #define gh2obj ((GTexteditObject *)gh) #define gw2obj ((GTexteditObject *)gw) -static void TextEditRemoveChar(GWidgetObject* gw) { +static void TextEditRemoveChar(GHandle gh) { char *p; const char *q; unsigned sz; unsigned pos; - sz = strlen(gw->text); - pos = gw2obj->cursorPos; - q = gw->text+pos; + sz = strlen(gh2obj->w.text); + pos = gh2obj->cursorPos; + q = gh2obj->w.text+pos; - if (!(gw->g.flags & GWIN_FLG_ALLOCTXT)) { + if (!(gh->flags & GWIN_FLG_ALLOCTXT)) { // Allocate and then copy if (!(p = gfxAlloc(sz))) return; if (pos) - memcpy(p, gw->text, pos); + memcpy(p, gh2obj->w.text, pos); memcpy(p+pos, q+1, sz-pos); - gw->g.flags |= GWIN_FLG_ALLOCTXT; + gh->flags |= GWIN_FLG_ALLOCTXT; } else { // Copy and then reallocate memcpy((char *)q, q+1, sz-pos); - if (!(p = gfxRealloc((char *)gw->text, sz+1, sz))) // This should never fail as we are making it smaller + if (!(p = gfxRealloc((char *)gh2obj->w.text, sz+1, sz))) // This should never fail as we are making it smaller return; } - gw->text = p; + gh2obj->w.text = p; } -static bool_t TextEditAddChars(GWidgetObject* gw, unsigned cnt) { +static bool_t TextEditAddChars(GHandle gh, unsigned cnt) { char *p; const char *q; unsigned sz; unsigned pos; // Get the size of the text buffer - sz = strlen(gw->text)+1; - pos = gw2obj->cursorPos; + sz = strlen(gh2obj->w.text)+1; + pos = gh2obj->cursorPos; - if (!(gw->g.flags & GWIN_FLG_ALLOCTXT)) { + if (!(gh->flags & GWIN_FLG_ALLOCTXT)) { if (!(p = gfxAlloc(sz+cnt))) return FALSE; - memcpy(p, gw->text, pos); - memcpy(p+pos+cnt, gw->text+pos, sz-pos); - gw->g.flags |= GWIN_FLG_ALLOCTXT; - gw->text = p; + memcpy(p, gh2obj->w.text, pos); + memcpy(p+pos+cnt, gh2obj->w.text+pos, sz-pos); + gh->flags |= GWIN_FLG_ALLOCTXT; + gh2obj->w.text = p; } else { - if (!(p = gfxRealloc((char *)gw->text, sz, sz+cnt))) + if (!(p = gfxRealloc((char *)gh2obj->w.text, sz, sz+cnt))) return FALSE; - gw->text = p; + gh2obj->w.text = p; q = p+pos; p += sz; while(--p >= q) @@ -117,76 +117,13 @@ static void TextEditMouseDown(GWidgetObject* gw, coord_t x, coord_t y) { // Is it a special key? if (pke->keystate & GKEYSTATE_SPECIAL) { - // Arrow keys to move the cursor - switch ((uint8_t)pke->c[0]) { - case GKEY_LEFT: - if (!gw2obj->cursorPos) - return; - gw2obj->cursorPos--; - break; - case GKEY_RIGHT: - if (!gw->text[gw2obj->cursorPos]) - return; - gw2obj->cursorPos++; - break; - case GKEY_HOME: - if (!gw2obj->cursorPos) - return; - gw2obj->cursorPos = 0; - break; - case GKEY_END: - if (!gw->text[gw2obj->cursorPos]) - return; - gw2obj->cursorPos = strlen(gw->text); - break; - default: - return; - } + gwinTextEditSendSpecialKey(&gw->g, (uint8_t)pke->c[0]); + return; - } else { - - // Normal key press - switch((uint8_t)pke->c[0]) { - case GKEY_BACKSPACE: - // Backspace - if (!gw2obj->cursorPos) - return; - gw2obj->cursorPos--; - TextEditRemoveChar(gw); - break; - case GKEY_TAB: - case GKEY_LF: - case GKEY_CR: - // Move to the next field - _gwinMoveFocus(); - return; - case GKEY_DEL: - // Delete - if (!gw->text[gw2obj->cursorPos]) - return; - TextEditRemoveChar(gw); - break; - default: - // Ignore any other control characters - if ((uint8_t)pke->c[0] < GKEY_SPACE) - return; - - // Keep the edit length to less than the maximum - if (gw2obj->maxSize && strlen(gw->text)+pke->bytecount > gw2obj->maxSize) - return; - - // Make space - if (TextEditAddChars(gw, pke->bytecount)) { - // Insert the characters - memcpy((char *)gw->text+gw2obj->cursorPos, pke->c, pke->bytecount); - gw2obj->cursorPos += pke->bytecount; - } - break; - } } - _gwinUpdate((GHandle)gw); + gwinTextEditSendKey(&gw->g, pke->c, pke->bytecount); } #endif @@ -246,6 +183,89 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit return (GHandle)wt; } +#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD + void gwinTextEditSendSpecialKey(GHandle gh, uint8_t key) { + // Is it a valid handle? + if (gh->vmt != (gwinVMT*)&texteditVMT) + return; + + // Arrow keys to move the cursor + switch (key) { + case GKEY_LEFT: + if (!gh2obj->cursorPos) + return; + gh2obj->cursorPos--; + break; + case GKEY_RIGHT: + if (!gh2obj->w.text[gh2obj->cursorPos]) + return; + gh2obj->cursorPos++; + break; + case GKEY_HOME: + if (!gh2obj->cursorPos) + return; + gh2obj->cursorPos = 0; + break; + case GKEY_END: + if (!gh2obj->w.text[gh2obj->cursorPos]) + return; + gh2obj->cursorPos = strlen(gh2obj->w.text); + break; + default: + return; + } + + _gwinUpdate(gh); + } + + void gwinTextEditSendKey(GHandle gh, char *key, unsigned len) { + // Is it a valid handle? + if (gh->vmt != (gwinVMT*)&texteditVMT || !key || !len) + return; + + // Normal key press + switch((uint8_t)key[0]) { + case GKEY_BACKSPACE: + // Backspace + if (!gh2obj->cursorPos) + return; + gh2obj->cursorPos--; + TextEditRemoveChar(gh); + break; + case GKEY_TAB: + case GKEY_LF: + case GKEY_CR: + // Move to the next field + _gwinMoveFocus(); + return; + case GKEY_DEL: + // Delete + if (!gh2obj->w.text[gh2obj->cursorPos]) + return; + TextEditRemoveChar(gh); + break; + default: + // Ignore any other control characters + if ((uint8_t)key[0] < GKEY_SPACE) + return; + + // Keep the edit length to less than the maximum + if (gh2obj->maxSize && strlen(gh2obj->w.text)+len > gh2obj->maxSize) + return; + + // Make space + if (TextEditAddChars(gh, len)) { + // Insert the characters + memcpy((char *)gh2obj->w.text+gh2obj->cursorPos, key, len); + gh2obj->cursorPos += len; + } + break; + } + + _gwinUpdate(gh); + } +#endif + void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) { const char* p; diff --git a/src/gwin/gwin_textedit.h b/src/gwin/gwin_textedit.h index ed2f634d..8cf6c03e 100644 --- a/src/gwin/gwin_textedit.h +++ b/src/gwin/gwin_textedit.h @@ -63,6 +63,32 @@ extern "C" { GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize); #define gwinTexteditCreate(wt, pInit, maxSize) gwinGTexteditCreate(GDISP, wt, pInit, maxSize) +/** + * @brief Send a special key to the textedit such as GKEY_LEFT, GKEY_RIGHT, GKEY_HOME, GKEY_END + * + * @param[in] gh The window handle (must be a textedit window) + * @param[in] key The special key to send. + * @pre Requires GINPUT_NEED_KEYBOARD or GWIN_NEED_KEYBOARD to be on + * @api + */ +void gwinTextEditSendSpecialKey(GHandle gh, uint8_t key); + +/** + * @brief Send a normal utf8 character to the textedit + * + * @param[in] gh The window handle (must be a textedit window) + * @param[in] pkey The pointer to the utf8 character to send. + * @param[in] len The length of the utf8 character in bytes. + * @note This must ONLY be called with a single utf8 character at a time. Don't attempt to + * send a string of characters in the one call. + * @note Characters are interpreted as if they came directly from a keyboard ie a backspace + * character will perform the backspace operation, a tab will send the focus to the next + * control etc. + * @pre Requires GINPUT_NEED_KEYBOARD or GWIN_NEED_KEYBOARD to be on + * @api + */ +void gwinTextEditSendKey(GHandle gh, char *pkey, unsigned len); + /** * @defgroup Renderings_Textedit Renderings *