From 46ba0420c342eaed1e4365c7e4cb65c0263bc7eb Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 12 Aug 2015 19:36:14 +0200 Subject: Adding TextEdit dummy widget (not implemented yet) --- src/gwin/gwin_textedit.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 113 insertions(+) create mode 100644 src/gwin/gwin_textedit.c (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c new file mode 100644 index 00000000..4aa41d61 --- /dev/null +++ b/src/gwin/gwin_textedit.c @@ -0,0 +1,113 @@ +/* + * This file is subject to the terms of the GFX License. If a copy of + * the license was not distributed with this file, you can obtain one at: + * + * http://ugfx.org/license.html + */ + +/** + * @file src/gwin/gwin_textedit.c + * @brief GWIN TextEdit widget header file + */ + +#include "gfx.h" + +#if GFX_USE_GWIN && GWIN_NEED_TEXTEDIT + +#include "gwin_class.h" + +// Text padding (between edge and text) in pixels +const int TEXT_PADDING = 3; + +// macros to assist in data type conversions +#define gh2obj ((GTexteditObject *)gh) +#define gw2obj ((GTexteditObject *)gw) + +#if GINPUT_NEED_KEYBOARD + static void _keyboardEvent(GWidgetObject* gw, GEventKeyboard* pke) + { + if (pke->bytecount = 1) { + //gw->text = pke->c[0]; + gwinSetText((GHandle)gw, &(pke->c[0]), TRUE); + } + + _gwinUpdate(&gw); + } +#endif + +static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param); + +static const gwidgetVMT texteditVMT = { + { + "TextEdit", // The class name + sizeof(GTexteditObject), // The object size + _gwidgetDestroy, // The destroy routine + _gwidgetRedraw, // The redraw routine + 0, // The after-clear routine + }, + gwinTexteditDefaultDraw, // default drawing routine + #if GINPUT_NEED_MOUSE + { + 0, // Process mose down events (NOT USED) + 0, // Process mouse up events (NOT USED) + 0, // Process mouse move events (NOT USED) + }, + #endif + #if GINPUT_NEED_KEYBOARD + { + _keyboardEvent, // Process keyboard key down events + }, + #endif + #if GINPUT_NEED_TOGGLE + { + 0, // No toggle role + 0, // Assign Toggles (NOT USED) + 0, // Get Toggles (NOT USED) + 0, // Process toggle off event (NOT USED) + 0, // Process toggle on event (NOT USED) + }, + #endif + #if GINPUT_NEED_DIAL + { + 0, // No dial roles + 0, // Assign Dials (NOT USED) + 0, // Get Dials (NOT USED) + 0, // Procees dial move events (NOT USED) + }, + #endif +}; + +GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit) +{ + uint16_t flags = 0; + + if (!(widget = (GTexteditObject*)_gwidgetCreate(g, &widget->w, pInit, &texteditVMT))) { + return 0; + } + + widget->w.g.flags |= flags; + gwinSetVisible(&widget->w.g, pInit->g.show); + + return (GHandle)widget; +} + +static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) +{ + color_t textColor; + (void) param; + + // Is it a valid handle? + if (gw->g.vmt != (gwinVMT*)&texteditVMT) { + return; + } + + textColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + + + gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft); +} + +#undef gh2obj +#undef gw2obj + +#endif // GFX_USE_GWIN && GWIN_NEED_TEXTEDIT -- cgit v1.2.3 From f1ede211fb341ebd9bf0d31ff3ca4cf7aba43b19 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Wed, 12 Aug 2015 20:22:34 +0200 Subject: First (simple) implementation of textbox behavior --- src/gwin/gwin_textedit.c | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 4aa41d61..fe15f441 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -26,9 +26,25 @@ const int TEXT_PADDING = 3; #if GINPUT_NEED_KEYBOARD static void _keyboardEvent(GWidgetObject* gw, GEventKeyboard* pke) { - if (pke->bytecount = 1) { - //gw->text = pke->c[0]; - gwinSetText((GHandle)gw, &(pke->c[0]), TRUE); + // Create a temporary buffer containing the current size + unsigned bufSize = strlen(gwinGetText((GHandle)gw))+1; + char buf[bufSize]; + strncpy(buf, gwinGetText((GHandle)gw), bufSize); + + // Parse the key press + if (pke->bytecount == 1) { + // Check backspace + if (pke->c[0] == GKEY_BACKSPACE) { + buf[strlen(buf)-1] = '\0'; + } + + // Append new character + else { + strncat(buf, &(pke->c[0]), 1); + } + + // Set the new text + gwinSetText((GHandle)gw, buf, TRUE); } _gwinUpdate(&gw); @@ -103,7 +119,6 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) textColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; - gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft); } -- cgit v1.2.3 From 37a088efb73e119a6675241394926cdb47c11ab2 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Thu, 13 Aug 2015 01:12:34 +0200 Subject: Compiler warning --- src/gwin/gwin_textedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index fe15f441..6e90b3ac 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -47,7 +47,7 @@ const int TEXT_PADDING = 3; gwinSetText((GHandle)gw, buf, TRUE); } - _gwinUpdate(&gw); + _gwinUpdate((GHandle)gw); } #endif -- cgit v1.2.3 From fcaa42972964e002474e6f79364f3af1a616d25c Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 18:33:16 +0200 Subject: First working Version of TextEdit widget --- src/gwin/gwin_textedit.c | 141 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 122 insertions(+), 19 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 6e90b3ac..9c7990eb 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -15,36 +15,103 @@ #if GFX_USE_GWIN && GWIN_NEED_TEXTEDIT #include "gwin_class.h" +#include +#include -// Text padding (between edge and text) in pixels -const int TEXT_PADDING = 3; +// Some settings + const int CURSOR_EXTRA_HEIGHT = 1; + +// Macros to assist in data type conversions +#define gh2obj ((GTexteditObject *)gh) +#define gw2obj ((GTexteditObject *)gw) + +// cursorPos is the position of the next character +// textBuffer[cursorPos++] = readKey(); + +// ToDo: Optimize by using strncpy() instead +static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) +{ + // Find the end of the string + size_t indexTerminator = index; + while (buffer[indexTerminator] != '\0' && indexTerminator < bufferSize-1) { + indexTerminator++; + } + + // Shift + size_t i = 0; + for (i = index; i < indexTerminator+1; i++) { + buffer[i-1] = buffer[i]; + } + buffer[indexTerminator] = '\0'; +} + +// ToDo: Optimize by using strncpy() instead +static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char fillChar) +{ + // Find the end of the string + size_t indexTerminator = index; + while (buffer[indexTerminator] != '\0' && indexTerminator < bufferSize-1) { + indexTerminator++; + } + + // Shift + size_t i = 0; + for (i = indexTerminator+1; i > index; i--) { + if (i > bufferSize-1) { + break; + } + + buffer[i] = buffer[i-1]; + } + + // Fill the gap + buffer[index] = fillChar; +} -// macros to assist in data type conversions -#define gh2obj ((GTexteditObject *)gh) -#define gw2obj ((GTexteditObject *)gw) #if GINPUT_NEED_KEYBOARD static void _keyboardEvent(GWidgetObject* gw, GEventKeyboard* pke) { - // Create a temporary buffer containing the current size - unsigned bufSize = strlen(gwinGetText((GHandle)gw))+1; - char buf[bufSize]; - strncpy(buf, gwinGetText((GHandle)gw), bufSize); + // 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 > 0) { + gw2obj->cursorPos--; + } + break; + + case GKEY_RIGHT: + if (gw2obj->cursorPos < strlen(gw2obj->textBuffer)) { + gw2obj->cursorPos++; + } + break; + + + default: + break; + } + } // Parse the key press - if (pke->bytecount == 1) { + else if (pke->bytecount >= 1) { // Check backspace if (pke->c[0] == GKEY_BACKSPACE) { - buf[strlen(buf)-1] = '\0'; + if (gw2obj->cursorPos == 0) { + return; + } + _shiftTextLeft(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos--); } - // Append new character + // Add a new character else { - strncat(buf, &(pke->c[0]), 1); + // 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]); } // Set the new text - gwinSetText((GHandle)gw, buf, TRUE); + gwinSetText((GHandle)gw, gw2obj->textBuffer, FALSE); } _gwinUpdate((GHandle)gw); @@ -93,15 +160,30 @@ static const gwidgetVMT texteditVMT = { #endif }; -GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit) +GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit, size_t bufSize) { uint16_t flags = 0; + // Create the underlying widget if (!(widget = (GTexteditObject*)_gwidgetCreate(g, &widget->w, pInit, &texteditVMT))) { return 0; } - widget->w.g.flags |= flags; + // Allocate the text buffer + widget->bufferSize = bufSize; + widget->textBuffer = gfxAlloc(widget->bufferSize); + if (widget->textBuffer == 0) { + return 0; + } + + // Initialize the text buffer + size_t i = 0; + for (i = 0; i < bufSize; i++) { + widget->textBuffer[i] = '\0'; + } + + widget->cursorPos = 0; + widget->w.g.flags |= flags; gwinSetVisible(&widget->w.g, pInit->g.show); return (GHandle)widget; @@ -109,17 +191,38 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* p static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) { - color_t textColor; - (void) param; + (void)param; // Is it a valid handle? if (gw->g.vmt != (gwinVMT*)&texteditVMT) { return; } - textColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + // Retrieve colors + color_t textColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + color_t cursorColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge; + // Render background and string gdispGFillStringBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft); + + // Render cursor (if focused) + if (gwinGetFocus() == (GHandle)gw || TRUE) { + // Calculate cursor stuff + char textBeforeCursor[gw2obj->bufferSize]; + strncpy(textBeforeCursor, gw->text, gw2obj->cursorPos+1); + textBeforeCursor[gw2obj->cursorPos] = '\0'; + coord_t textWidth = gdispGetStringWidth(textBeforeCursor, gw->g.font); + coord_t cursorHeight = gdispGetFontMetric(gw->g.font, fontHeight); + coord_t cursorSpacingTop = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; + coord_t cursorSpacingBottom = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; + + // Draw cursor + coord_t lineX0 = gw->g.x + textWidth - 2; + coord_t lineX1 = gw->g.x + textWidth - 2; + coord_t lineY0 = gw->g.y + cursorSpacingTop; + coord_t lineY1 = gw->g.y + gw->g.height - cursorSpacingBottom; + gdispGDrawLine(gw->g.display, lineX0, lineY0, lineX1, lineY1, cursorColor); + } } #undef gh2obj -- cgit v1.2.3 From b828bf567bd6989cddb3259a65871f7460011f5d Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 18:47:55 +0200 Subject: Optimizing string shift operations by using memcpy() --- src/gwin/gwin_textedit.c | 22 ++++++---------------- 1 file changed, 6 insertions(+), 16 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 9c7990eb..999a91dd 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -16,7 +16,6 @@ #include "gwin_class.h" #include -#include // Some settings const int CURSOR_EXTRA_HEIGHT = 1; @@ -28,7 +27,7 @@ // cursorPos is the position of the next character // textBuffer[cursorPos++] = readKey(); -// ToDo: Optimize by using strncpy() instead +// ToDo: Optimize by using memncpy() instead static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) { // Find the end of the string @@ -38,14 +37,12 @@ static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) } // Shift - size_t i = 0; - for (i = index; i < indexTerminator+1; i++) { - buffer[i-1] = buffer[i]; - } - buffer[indexTerminator] = '\0'; + memcpy(&buffer[index-1], &buffer[index], indexTerminator-index); + + // Terminate the string + buffer[indexTerminator-1] = '\0'; } -// ToDo: Optimize by using strncpy() instead static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char fillChar) { // Find the end of the string @@ -55,14 +52,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char } // Shift - size_t i = 0; - for (i = indexTerminator+1; i > index; i--) { - if (i > bufferSize-1) { - break; - } - - buffer[i] = buffer[i-1]; - } + memcpy(&buffer[index+1], &buffer[index], indexTerminator-index); // Fill the gap buffer[index] = fillChar; -- cgit v1.2.3 From 2c99e8c6869c8786e7c2ce95f2af82acf0831141 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 18:53:05 +0200 Subject: Adding handler for the DELETE button to the TextEdit widget --- src/gwin/gwin_textedit.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 999a91dd..8f5cb8dd 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -86,7 +86,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char // Parse the key press else if (pke->bytecount >= 1) { - // Check backspace + // Is it backspace? if (pke->c[0] == GKEY_BACKSPACE) { if (gw2obj->cursorPos == 0) { return; @@ -94,6 +94,15 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char _shiftTextLeft(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos--); } + // Is it delete? + else if (pke->c[0] == GKEY_DEL) { + // Check whether there is a character on the right side of the cursor + if (gw2obj->textBuffer[gw2obj->cursorPos] == '\0') { + return; + } + _shiftTextLeft(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos+1); + } + // Add a new character else { // Shift everything right from the cursor by one character. This includes the '\0'. Then inser the new character. -- cgit v1.2.3 From 03bc3f25a7425af6255d023fc837cc8be1453e8d Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 18:53:43 +0200 Subject: CleanUp --- src/gwin/gwin_textedit.c | 1 - 1 file changed, 1 deletion(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 8f5cb8dd..4d1f93a6 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -27,7 +27,6 @@ // cursorPos is the position of the next character // textBuffer[cursorPos++] = readKey(); -// ToDo: Optimize by using memncpy() instead static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) { // Find the end of the string -- cgit v1.2.3 From 668257c87262f044ff3858224ba0646f690cd706 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 18:55:36 +0200 Subject: Prevent buffer overflow --- src/gwin/gwin_textedit.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 4d1f93a6..f90666ff 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -104,6 +104,11 @@ 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) { + 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]); } -- cgit v1.2.3 From f7075e25ed9bcd701395745161f9ee086c025e21 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 20:48:41 +0200 Subject: More work on the TextEdit --- src/gwin/gwin_textedit.c | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index f90666ff..bb25c102 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -18,7 +18,9 @@ #include // Some settings - const int CURSOR_EXTRA_HEIGHT = 1; +const int TEXT_PADDING_LEFT = 4; +const int CURSOR_PADDING_LEFT = 0; +const int CURSOR_EXTRA_HEIGHT = 1; // Macros to assist in data type conversions #define gh2obj ((GTexteditObject *)gh) @@ -185,7 +187,10 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* p widget->textBuffer[i] = '\0'; } - widget->cursorPos = 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); + widget->w.g.flags |= flags; gwinSetVisible(&widget->w.g, pInit->g.show); @@ -206,22 +211,20 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) color_t cursorColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge; // Render background and string + //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, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft); // Render cursor (if focused) - if (gwinGetFocus() == (GHandle)gw || TRUE) { + if (gwinGetFocus() == (GHandle)gw) { // Calculate cursor stuff - char textBeforeCursor[gw2obj->bufferSize]; - strncpy(textBeforeCursor, gw->text, gw2obj->cursorPos+1); - textBeforeCursor[gw2obj->cursorPos] = '\0'; - coord_t textWidth = gdispGetStringWidth(textBeforeCursor, gw->g.font); + coord_t textWidth = gdispGetStringWidthCount(gw2obj->textBuffer, gw->g.font, gw2obj->cursorPos); coord_t cursorHeight = gdispGetFontMetric(gw->g.font, fontHeight); coord_t cursorSpacingTop = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; coord_t cursorSpacingBottom = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; // Draw cursor - coord_t lineX0 = gw->g.x + textWidth - 2; - coord_t lineX1 = gw->g.x + textWidth - 2; + coord_t lineX0 = gw->g.x + textWidth + CURSOR_PADDING_LEFT + gdispGetFontMetric(gw->g.font, fontBaselineX)/2; + coord_t lineX1 = lineX0; coord_t lineY0 = gw->g.y + cursorSpacingTop; coord_t lineY1 = gw->g.y + gw->g.height - cursorSpacingBottom; gdispGDrawLine(gw->g.display, lineX0, lineY0, lineX1, lineY1, cursorColor); -- cgit v1.2.3 From 7f70789bc3423b915195bc09dfcbff5121cd2f70 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 21:12:56 +0200 Subject: Adding border option to TextEdit widget --- src/gwin/gwin_textedit.c | 31 +++++++++++++++++++++++++++---- 1 file changed, 27 insertions(+), 4 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index bb25c102..eb6340a3 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -22,6 +22,9 @@ const int TEXT_PADDING_LEFT = 4; 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) @@ -191,14 +194,29 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* p strncpy(widget->textBuffer, gwinGetText((GHandle)widget), widget->bufferSize); // FixMe: pInit->text leads to a segfault widget->cursorPos = strlen(widget->textBuffer); - widget->w.g.flags |= flags; + widget->w.g.flags |= flags | GTEXTEDIT_FLG_BORDER;; gwinSetVisible(&widget->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; + } +} + static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) { + (void)param; // Is it a valid handle? @@ -211,8 +229,13 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) color_t cursorColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge; // Render background and string - //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, gw->g.y, gw->g.width, gw->g.height, gw->text, gw->g.font, textColor, gw->pstyle->background, justifyLeft); + 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 cursor (if focused) if (gwinGetFocus() == (GHandle)gw) { @@ -223,7 +246,7 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) coord_t cursorSpacingBottom = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; // Draw cursor - coord_t lineX0 = gw->g.x + textWidth + CURSOR_PADDING_LEFT + gdispGetFontMetric(gw->g.font, fontBaselineX)/2; + coord_t lineX0 = gw->g.x + textWidth + CURSOR_PADDING_LEFT + TEXT_PADDING_LEFT + gdispGetFontMetric(gw->g.font, fontBaselineX)/2; coord_t lineX1 = lineX0; coord_t lineY0 = gw->g.y + cursorSpacingTop; coord_t lineY1 = gw->g.y + gw->g.height - cursorSpacingBottom; -- cgit v1.2.3 From 668b161f0eead1b9687305281eb59be0e0713bbe Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Fri, 14 Aug 2015 23:51:28 +0200 Subject: Adding color to widget style for focused widgets --- src/gwin/gwin_textedit.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index eb6340a3..21415b9c 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -18,9 +18,10 @@ #include // Some settings -const int TEXT_PADDING_LEFT = 4; -const int CURSOR_PADDING_LEFT = 0; -const int CURSOR_EXTRA_HEIGHT = 1; +const int TEXT_PADDING_LEFT = 4; +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) @@ -237,6 +238,14 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) 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); + } + } + // Render cursor (if focused) if (gwinGetFocus() == (GHandle)gw) { // Calculate cursor stuff -- cgit v1.2.3 From bd353d37e3db2aea609600342d8657c67ea8e44d Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 16 Aug 2015 01:24:18 +0200 Subject: Typo --- src/gwin/gwin_textedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 21415b9c..8d242ec7 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -147,7 +147,7 @@ static const gwidgetVMT texteditVMT = { #endif #if GINPUT_NEED_KEYBOARD { - _keyboardEvent, // Process keyboard key down events + _keyboardEvent // Process keyboard key down events }, #endif #if GINPUT_NEED_TOGGLE -- cgit v1.2.3 From 63c5e4949f63470bd20d2bc35a9fcc0b50795910 Mon Sep 17 00:00:00 2001 From: Joel Bodenmann Date: Sun, 16 Aug 2015 01:35:46 +0200 Subject: Adding KEYUP events --- src/gwin/gwin_textedit.c | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 8d242ec7..99708a0a 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -67,6 +67,11 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char #if GINPUT_NEED_KEYBOARD static void _keyboardEvent(GWidgetObject* gw, GEventKeyboard* pke) { + // Only react on KEYDOWN events. Ignore KEYUP events. + if (pke->keystate & GKEYSTATE_KEYUP) { + return; + } + // Is it a special key? if (pke->keystate & GKEYSTATE_SPECIAL) { // Arrow keys to move the cursor -- cgit v1.2.3 From 15e7342fd7b21b76a565561a3caafee394e70c88 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 16 Aug 2015 21:53:47 +1000 Subject: Updates to focus. --- src/gwin/gwin_textedit.c | 60 +++++++++++++----------------------------------- 1 file changed, 16 insertions(+), 44 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 99708a0a..5ea8936a 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -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); - - return (GHandle)widget; -} - -void gwinTexteditSetBorder(GHandle gh, bool_t border) -{ - // Is it a valid handle? - if (gh->vmt != (gwinVMT*)&texteditVMT) { - return; - } + gwinSetVisible(&wt->w.g, pInit->g.show); - 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) { -- cgit v1.2.3 From af76c04767f3e5d1cc6f39ba907a7d4afdb43200 Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 16 Aug 2015 22:05:32 +1000 Subject: Compile fixes --- src/gwin/gwin_textedit.c | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 5ea8936a..70a5f8f0 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -30,11 +30,11 @@ const int CURSOR_EXTRA_HEIGHT = 1; // cursorPos is the position of the next character // textBuffer[cursorPos++] = readKey(); -static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) +static void _shiftTextLeft(char* buffer, size_t maxSize, size_t index) { // Find the end of the string size_t indexTerminator = index; - while (buffer[indexTerminator] != '\0' && indexTerminator < bufferSize-1) { + while (buffer[indexTerminator] != '\0' && indexTerminator < maxSize-1) { indexTerminator++; } @@ -45,11 +45,11 @@ static void _shiftTextLeft(char* buffer, size_t bufferSize, size_t index) buffer[indexTerminator-1] = '\0'; } -static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char fillChar) +static void _shiftTextRight(char* buffer, size_t maxSize, size_t index, char fillChar) { // Find the end of the string size_t indexTerminator = index; - while (buffer[indexTerminator] != '\0' && indexTerminator < bufferSize-1) { + while (buffer[indexTerminator] != '\0' && indexTerminator < maxSize-1) { indexTerminator++; } @@ -98,7 +98,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char if (gw2obj->cursorPos == 0) { return; } - _shiftTextLeft(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos--); + _shiftTextLeft(gw2obj->textBuffer, gw2obj->maxSize, gw2obj->cursorPos--); } // Is it delete? @@ -107,7 +107,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char if (gw2obj->textBuffer[gw2obj->cursorPos] == '\0') { return; } - _shiftTextLeft(gw2obj->textBuffer, gw2obj->bufferSize, gw2obj->cursorPos+1); + _shiftTextLeft(gw2obj->textBuffer, gw2obj->maxSize, gw2obj->cursorPos+1); } // Add a new character @@ -117,7 +117,7 @@ static void _shiftTextRight(char* buffer, size_t bufferSize, size_t index, char 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]); + _shiftTextRight(gw2obj->textBuffer, gw2obj->maxSize, gw2obj->cursorPos++, pke->c[0]); } // Set the new text @@ -172,21 +172,19 @@ static const gwidgetVMT texteditVMT = { GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize) { - uint16_t flags = 0; - // Create the underlying widget if (!(wt = (GTexteditObject*)_gwidgetCreate(g, &wt->w, pInit, &texteditVMT))) return 0; // Allocate the text buffer wt->maxSize = maxSize; - wt->textBuffer = gfxAlloc(widget->maxSize); + wt->textBuffer = gfxAlloc(wt->maxSize); if (wt->textBuffer == 0) return 0; // Initialize the text buffer size_t i = 0; - for (i = 0; i < bufSize; i++) { + for (i = 0; i < wt->maxSize; i++) { wt->textBuffer[i] = '\0'; } -- cgit v1.2.3 From a569bbfc1eaf2ac67e151c27ee674107a589f93d Mon Sep 17 00:00:00 2001 From: inmarket Date: Sun, 16 Aug 2015 22:20:53 +1000 Subject: Border fix --- src/gwin/gwin_textedit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 70a5f8f0..1395ab71 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -219,7 +219,7 @@ static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) 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 - _gwidgetDrawFocusRect(gw, 0, 0, gw->g.width-1, gw->g.height-1); + _gwidgetDrawFocusRect(gw, 1, 1, gw->g.width-2, gw->g.height-2); // Render cursor (if focused) if (gwinGetFocus() == (GHandle)gw) { -- cgit v1.2.3 From 3fea02324831eba1773f45b1dc6d0bf2a0c8326d Mon Sep 17 00:00:00 2001 From: inmarket Date: Mon, 17 Aug 2015 00:18:54 +1000 Subject: Add some keyboard widget support --- src/gwin/gwin_textedit.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index 1395ab71..c1373897 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -61,7 +61,7 @@ static void _shiftTextRight(char* buffer, size_t maxSize, size_t index, char fil } -#if GINPUT_NEED_KEYBOARD +#if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD static void TextEditKeyboard(GWidgetObject* gw, GEventKeyboard* pke) { // Only react on KEYDOWN events. Ignore KEYUP events. @@ -146,7 +146,7 @@ static const gwidgetVMT texteditVMT = { 0, // Process mouse move events (NOT USED) }, #endif - #if GINPUT_NEED_KEYBOARD + #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD { TextEditKeyboard // Process keyboard key down events }, -- cgit v1.2.3 From 5e8e0b7744a59c5bbf918a5133b55c3d1beef12f Mon Sep 17 00:00:00 2001 From: inmarket Date: Tue, 13 Oct 2015 00:58:31 +1000 Subject: Working TextEdit with on-screen keyboard (and real keyboard) --- src/gwin/gwin_textedit.c | 229 ++++++++++++++++++++++++----------------------- 1 file changed, 119 insertions(+), 110 deletions(-) (limited to 'src/gwin/gwin_textedit.c') diff --git a/src/gwin/gwin_textedit.c b/src/gwin/gwin_textedit.c index c1373897..ee147c84 100644 --- a/src/gwin/gwin_textedit.c +++ b/src/gwin/gwin_textedit.c @@ -18,110 +18,109 @@ #include // Some settings -const int TEXT_PADDING_LEFT = 4; -const int FOCUS_BORDER_THICKNESS = 3; -const int CURSOR_PADDING_LEFT = 0; -const int CURSOR_EXTRA_HEIGHT = 1; +#define TEXT_PADDING_LEFT 4 +#define CURSOR_PADDING_LEFT 0 +#define CURSOR_EXTRA_HEIGHT 1 // Macros to assist in data type conversions #define gh2obj ((GTexteditObject *)gh) #define gw2obj ((GTexteditObject *)gw) -// cursorPos is the position of the next character -// textBuffer[cursorPos++] = readKey(); - -static void _shiftTextLeft(char* buffer, size_t maxSize, size_t index) -{ - // Find the end of the string - size_t indexTerminator = index; - while (buffer[indexTerminator] != '\0' && indexTerminator < maxSize-1) { - indexTerminator++; - } - - // Shift - memcpy(&buffer[index-1], &buffer[index], indexTerminator-index); - - // Terminate the string - buffer[indexTerminator-1] = '\0'; -} - -static void _shiftTextRight(char* buffer, size_t maxSize, size_t index, char fillChar) -{ - // Find the end of the string - size_t indexTerminator = index; - while (buffer[indexTerminator] != '\0' && indexTerminator < maxSize-1) { - indexTerminator++; +static bool_t resizeText(GWidgetObject* gw, size_t pos, int32_t diff) { + char *p, *q; + size_t sz; + + p = (char *)gw->text; + sz = strlen(p)+1; + if (diff < 0) + memcpy(p+pos, p+pos-diff, sz-pos+diff); + if (!(p = gfxRealloc(p, sz, sz+diff))) + return FALSE; + gw->text = p; + if (diff > 0) { + q = p + sz; + p += pos; + while(--q >= p) + q[diff] = q[0]; } - - // Shift - memcpy(&buffer[index+1], &buffer[index], indexTerminator-index); - - // Fill the gap - buffer[index] = fillChar; + return TRUE; } - -#if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD - static void TextEditKeyboard(GWidgetObject* gw, GEventKeyboard* pke) - { +#if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD + static void TextEditKeyboard(GWidgetObject* gw, GEventKeyboard* pke) { // Only react on KEYDOWN events. Ignore KEYUP events. - if (pke->keystate & GKEYSTATE_KEYUP) { + if ((pke->keystate & GKEYSTATE_KEYUP) || !pke->bytecount) return; - } // 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 > 0) { - gw2obj->cursorPos--; - } + if (!gw2obj->cursorPos) + return; + gw2obj->cursorPos--; break; - case GKEY_RIGHT: - if (gw2obj->cursorPos < strlen(gw2obj->textBuffer)) { - gw2obj->cursorPos++; - } + if (!gw->text[gw2obj->cursorPos]) + return; + gw2obj->cursorPos++; break; - - - default: + case GKEY_HOME: + if (!gw2obj->cursorPos) + return; + gw2obj->cursorPos = 0; break; - } - } - - // Parse the key press - else if (pke->bytecount >= 1) { - // Is it backspace? - if (pke->c[0] == GKEY_BACKSPACE) { - if (gw2obj->cursorPos == 0) { + case GKEY_END: + if (!gw->text[gw2obj->cursorPos]) return; - } - _shiftTextLeft(gw2obj->textBuffer, gw2obj->maxSize, gw2obj->cursorPos--); + gw2obj->cursorPos = strlen(gw->text); + break; + default: + return; } - // Is it delete? - else if (pke->c[0] == GKEY_DEL) { - // Check whether there is a character on the right side of the cursor - if (gw2obj->textBuffer[gw2obj->cursorPos] == '\0') { + } else { + + // Normal key press + switch((uint8_t)pke->c[0]) { + case GKEY_BACKSPACE: + // Backspace + if (!gw2obj->cursorPos) + return; + gw2obj->cursorPos--; + resizeText(gw, gw2obj->cursorPos, -1); + 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; + resizeText(gw, gw2obj->cursorPos, -1); + break; + default: + // Ignore any other control characters + if ((uint8_t)pke->c[0] < GKEY_SPACE) return; - } - _shiftTextLeft(gw2obj->textBuffer, gw2obj->maxSize, gw2obj->cursorPos+1); - } - // Add a new character - else { - // Prevent buffer overflow - if (gw2obj->cursorPos >= gw2obj->maxSize) + // Keep the edit length to less than the maximum + if (gw2obj->maxSize && gw2obj->cursorPos+pke->bytecount > 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->maxSize, gw2obj->cursorPos++, pke->c[0]); - } + // Make space + resizeText(gw, gw2obj->cursorPos, pke->bytecount); - // Set the new text - gwinSetText((GHandle)gw, gw2obj->textBuffer, FALSE); + // Insert the character + memcpy((char *)gw->text+gw2obj->cursorPos, pke->c, pke->bytecount); + gw2obj->cursorPos += pke->bytecount; + break; + } } _gwinUpdate((GHandle)gw); @@ -141,12 +140,12 @@ static const gwidgetVMT texteditVMT = { gwinTexteditDefaultDraw, // default drawing routine #if GINPUT_NEED_MOUSE { - 0, // Process mose down events (NOT USED) + 0, // Process mouse down events (NOT USED) 0, // Process mouse up events (NOT USED) 0, // Process mouse move events (NOT USED) }, #endif - #if GINPUT_NEED_KEYBOARD || GWIN_NEED_KEYBOARD + #if (GFX_USE_GINPUT && GINPUT_NEED_KEYBOARD) || GWIN_NEED_KEYBOARD { TextEditKeyboard // Process keyboard key down events }, @@ -172,25 +171,25 @@ static const gwidgetVMT texteditVMT = { GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit, size_t maxSize) { + char *p; + // Create the underlying widget if (!(wt = (GTexteditObject*)_gwidgetCreate(g, &wt->w, pInit, &texteditVMT))) return 0; - // Allocate the text buffer wt->maxSize = maxSize; - wt->textBuffer = gfxAlloc(wt->maxSize); - if (wt->textBuffer == 0) - return 0; - // Initialize the text buffer - size_t i = 0; - for (i = 0; i < wt->maxSize; i++) { - wt->textBuffer[i] = '\0'; + // Reallocate the text (if necessary) + if (!(wt->w.g.flags & GWIN_FLG_ALLOCTXT)) { + if (!(p = gfxAlloc(wt->maxSize+1))) + return 0; + strncpy(p, wt->w.text, wt->maxSize); + wt->w.text = p; + wt->w.g.flags |= GWIN_FLG_ALLOCTXT; } // Set text and cursor position - strncpy(wt->textBuffer, gwinGetText((GHandle)wt), wt->maxSize); // FixMe: pInit->text leads to a segfault - wt->cursorPos = strlen(wt->textBuffer); + wt->cursorPos = strlen(wt->w.text); gwinSetVisible(&wt->w.g, pInit->g.show); @@ -199,43 +198,53 @@ GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* wt, GWidgetInit* pInit static void gwinTexteditDefaultDraw(GWidgetObject* gw, void* param) { - + const char *p; + coord_t cpos, tpos; + color_t ccol, tcol; (void)param; // Is it a valid handle? - if (gw->g.vmt != (gwinVMT*)&texteditVMT) { + if (gw->g.vmt != (gwinVMT*)&texteditVMT) return; - } // Retrieve colors - color_t textColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; - color_t cursorColor = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge; + tcol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.text : gw->pstyle->disabled.text; + ccol = (gw->g.flags & GWIN_FLG_SYSENABLED) ? gw->pstyle->enabled.edge : gw->pstyle->disabled.edge; + + // Adjust the text position so the cursor fits in the window + p = gw->text; + if (!gw2obj->cursorPos) + tpos = 0; + else { + for(cpos = gw2obj->cursorPos; ; p++, cpos--) { + tpos = gdispGetStringWidthCount(p, gw->g.font, cpos); + if (tpos < gw->g.width-(TEXT_PADDING_LEFT+CURSOR_PADDING_LEFT)) + break; + } + } // Render background and string - 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 (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 - _gwidgetDrawFocusRect(gw, 1, 1, gw->g.width-2, gw->g.height-2); + #if TEXT_PADDING_LEFT + gdispGFillArea(gw->g.display, gw->g.x, gw->g.y, TEXT_PADDING_LEFT, gw->g.height, gw->pstyle->background); + #endif + gdispGFillStringBox(gw->g.display, gw->g.x + TEXT_PADDING_LEFT, gw->g.y, gw->g.width-TEXT_PADDING_LEFT, gw->g.height, p, gw->g.font, tcol, gw->pstyle->background, justifyLeft); // Render cursor (if focused) if (gwinGetFocus() == (GHandle)gw) { // Calculate cursor stuff - coord_t textWidth = gdispGetStringWidthCount(gw2obj->textBuffer, gw->g.font, gw2obj->cursorPos); - coord_t cursorHeight = gdispGetFontMetric(gw->g.font, fontHeight); - coord_t cursorSpacingTop = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; - coord_t cursorSpacingBottom = (gw->g.height - cursorHeight)/2 - CURSOR_EXTRA_HEIGHT; // Draw cursor - coord_t lineX0 = gw->g.x + textWidth + CURSOR_PADDING_LEFT + TEXT_PADDING_LEFT + gdispGetFontMetric(gw->g.font, fontBaselineX)/2; - coord_t lineX1 = lineX0; - coord_t lineY0 = gw->g.y + cursorSpacingTop; - coord_t lineY1 = gw->g.y + gw->g.height - cursorSpacingBottom; - gdispGDrawLine(gw->g.display, lineX0, lineY0, lineX1, lineY1, cursorColor); + tpos += gw->g.x + CURSOR_PADDING_LEFT + TEXT_PADDING_LEFT + gdispGetFontMetric(gw->g.font, fontBaselineX)/2; + cpos = (gw->g.height - gdispGetFontMetric(gw->g.font, fontHeight))/2 - CURSOR_EXTRA_HEIGHT; + gdispGDrawLine(gw->g.display, tpos, gw->g.y + cpos, tpos, gw->g.y + gw->g.height - cpos, ccol); } + + // Render border + gdispGDrawBox(gw->g.display, gw->g.x, gw->g.y, gw->g.width, gw->g.height, ccol); + + // Render highlighted border of focused + _gwidgetDrawFocusRect(gw, 1, 1, gw->g.width-2, gw->g.height-2); + } #undef gh2obj -- cgit v1.2.3