First working Version of TextEdit widget
This commit is contained in:
parent
5163381177
commit
fcaa429729
2 changed files with 129 additions and 21 deletions
|
@ -15,36 +15,103 @@
|
|||
#if GFX_USE_GWIN && GWIN_NEED_TEXTEDIT
|
||||
|
||||
#include "gwin_class.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// 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
|
||||
|
|
|
@ -31,6 +31,10 @@
|
|||
// A TextEdit widget
|
||||
typedef struct GTexteditObject {
|
||||
GWidgetObject w;
|
||||
|
||||
char* textBuffer;
|
||||
size_t bufferSize;
|
||||
uint16_t cursorPos;
|
||||
} GTexteditObject;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -46,13 +50,14 @@ extern "C" {
|
|||
* @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] pInit The initialisation parameters to use.
|
||||
* @param[in] bufSize The maximum number of characters the TextEdit widget can hold.
|
||||
*
|
||||
* @return NULL if there is no resultat drawing area, otherwise the widget handle.
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit);
|
||||
#define gwinTexteditCreate(w, pInit) gwinGTexteditCreate(GDISP, w, pInit)
|
||||
GHandle gwinGTexteditCreate(GDisplay* g, GTexteditObject* widget, GWidgetInit* pInit, size_t bufSize);
|
||||
#define gwinTexteditCreate(w, pInit, bufSize) gwinGTexteditCreate(GDISP, w, pInit, bufSize)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue