From 148a6b4f9f632be521bd47a91fb186a3b72b38d9 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Wed, 20 Oct 2021 20:53:58 -0500 Subject: [PATCH] Now understands the concept of "focus". Textbox widget started. --- client/client.pro | 2 + client/src/gui/button.c | 8 +- client/src/gui/checkbox.c | 2 +- client/src/gui/gui.c | 84 ++++++++++++++----- client/src/gui/gui.h | 20 +++-- client/src/gui/textbox.c | 171 ++++++++++++++++++++++++++++++++++++++ client/src/gui/textbox.h | 50 +++++++++++ client/src/gui/widget.c | 1 + client/src/gui/widget.h | 2 + client/src/gui/window.c | 2 +- client/src/main.c | 7 ++ 11 files changed, 318 insertions(+), 31 deletions(-) create mode 100644 client/src/gui/textbox.c create mode 100644 client/src/gui/textbox.h diff --git a/client/client.pro b/client/client.pro index 5990656..d0debfc 100644 --- a/client/client.pro +++ b/client/client.pro @@ -52,6 +52,7 @@ HEADERS = \ src/gui/picture.h \ src/gui/radio.h \ src/gui/task.h \ + src/gui/textbox.h \ src/thirdparty/stb_ds.h \ src/thirdparty/stb_leakcheck.h \ src/thirdparty/stb_image.h \ @@ -81,6 +82,7 @@ SOURCES = \ src/gui/picture.c \ src/gui/radio.c \ src/gui/task.c \ + src/gui/textbox.c \ src/gui/widget.c \ src/gui/window.c \ src/gui/image.c \ diff --git a/client/src/gui/button.c b/client/src/gui/button.c index 794bfce..9201616 100644 --- a/client/src/gui/button.c +++ b/client/src/gui/button.c @@ -49,7 +49,7 @@ WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widget buttonSetTitle(b, title); // Width is set in buttonSetTitle - b->base.h = fontHeightGet(_guiFont) + (_guiMetric[METRIC_BUTTON_VERTICAL_MARGIN] * 2) + (_guiMetric[METRIC_BUTTON_BEZEL_SIZE] * 2); + b->base.h = fontHeightGet(_guiFont) + (_guiMetric[METRIC_BUTTON_VERTICAL_PADDING] * 2) + (_guiMetric[METRIC_BUTTON_BEZEL_SIZE] * 2); return button; } @@ -116,10 +116,10 @@ static void buttonPaint(WidgetT *widget) { } // Draw background (depends on x from above). - guiDrawFilledRectangle(b->base.x + i, b->base.y + i, b->base.x + b->base.w - i, b->base.y + b->base.h - i, _guiColor[COLOR_BUTTON_BACKGROUND]); + guiDrawRectangleFilled(b->base.x + i, b->base.y + i, b->base.x + b->base.w - i, b->base.y + b->base.h - i, _guiColor[COLOR_BUTTON_BACKGROUND]); // Draw title (depends on x from above). - fontRender(_guiFont, b->title, _guiColor[COLOR_BUTTON_TEXT], _guiColor[COLOR_BUTTON_BACKGROUND], b->base.x + i + _guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN] + active, b->base.y + i + _guiMetric[METRIC_BUTTON_VERTICAL_MARGIN] + active); + fontRender(_guiFont, b->title, _guiColor[COLOR_BUTTON_TEXT], _guiColor[COLOR_BUTTON_BACKGROUND], b->base.x + i + _guiMetric[METRIC_BUTTON_HORIZONTAL_PADDING] + active, b->base.y + i + _guiMetric[METRIC_BUTTON_VERTICAL_PADDING] + active); GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); } @@ -134,6 +134,6 @@ void buttonSetClickHandler(ButtonT *button, widgetCallback callback) { void buttonSetTitle(ButtonT *button, char *title) { if (button->title) free(button->title); button->title = strdup(title); - button->base.w = (strlen(title) * fontWidthGet(_guiFont)) + (_guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN] * 2) + (_guiMetric[METRIC_BUTTON_BEZEL_SIZE] * 2); + button->base.w = (strlen(title) * fontWidthGet(_guiFont)) + (_guiMetric[METRIC_BUTTON_HORIZONTAL_PADDING] * 2) + (_guiMetric[METRIC_BUTTON_BEZEL_SIZE] * 2); GUI_SET_FLAG((WidgetT *)button, WIDGET_FLAG_DIRTY); } diff --git a/client/src/gui/checkbox.c b/client/src/gui/checkbox.c index 7344eca..a259d71 100644 --- a/client/src/gui/checkbox.c +++ b/client/src/gui/checkbox.c @@ -112,7 +112,7 @@ static void checkboxPaint(WidgetT *widget) { guiDrawHighlightFrame(c->base.x, c->base.y + o, c->base.x + 10, c->base.y + 10 + o, highlight, shadow); // Draw background. - guiDrawFilledRectangle(c->base.x + 1, c->base.y + o + 1, c->base.x + 9, c->base.y + + o + 9, fill); + guiDrawRectangleFilled(c->base.x + 1, c->base.y + o + 1, c->base.x + 9, c->base.y + + o + 9, fill); // Draw title. fontRender(_guiFont, c->title, _guiColor[COLOR_CHECKBOX_TEXT], _guiColor[COLOR_WINDOW_BACKGROUND], c->base.x + 10 + _guiMetric[METRIC_CHECKBOX_PADDING], c->base.y); diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c index 0b2d1a5..9f3848c 100644 --- a/client/src/gui/gui.c +++ b/client/src/gui/gui.c @@ -39,6 +39,8 @@ WindowT *_guiActiveWindow = NULL; static DesktopT *_guiDesktop = NULL; static WidgetT *_guiLastWidgetLeft = NULL; static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE; +static WidgetT *_guiFocused = NULL; + static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse); @@ -202,13 +204,43 @@ void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) { } -void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT pixel) { +void guiDrawRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) { + guiDrawLine(x1, y1, x2, y1, color); + guiDrawLine(x2, y1, x2, y2, color); + guiDrawLine(x1, y2, x2, y2, color); + guiDrawLine(x1, y1, x1, y2, color); +} + + +void guiDrawRectangleFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color) { uint16_t x; uint16_t y; for (y=y1; y<=y2; y++) { for (x=x1; x<=x2; x++) { - vbePutPixel(x, y, pixel); + vbePutPixel(x, y, color); + } + } +} + + +WidgetT *guiFocusGet(void) { + return _guiFocused; +} + + +void guiFocusSet(WidgetT *widget) { + // Did the focus change? + if (widget != _guiFocused) { + // Remove focus from current control. + if (_guiFocused) { + if (_guiFocused->focusMethod) _guiFocused->focusMethod(widget, 0); + } + // Change focus. + _guiFocused = widget; + // Tell new control it has focus. + if (_guiFocused) { + if (_guiFocused->focusMethod) _guiFocused->focusMethod(widget, 1); } } } @@ -225,10 +257,9 @@ void guiPaint(WidgetT *widget) { size_t len = arrlenu(widget->children); size_t x; - // Paint us, if needed. - if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY) && widget->paintMethod) { + // Paint us. Widget handles dirty flag so they can animate if needed. + if (widget->paintMethod) { widget->paintMethod(widget); - GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); } // Paint all children. @@ -246,13 +277,14 @@ void guiProcessMouse(MouseT *mouse) { static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) { - size_t len; - int16_t x; - uint16_t mx; - uint16_t my; - uint16_t sx; - uint16_t sy; - uint8_t event = MOUSE_EVENT_NONE; + size_t len; + int16_t x; + uint16_t mx; + uint16_t my; + uint16_t sx; + uint16_t sy; + uint8_t event = MOUSE_EVENT_NONE; + static WidgetT *focusDown = NULL; // Search children backwards for active widget before checking this widget. len = arrlenu(widget->children); @@ -278,6 +310,7 @@ static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) { // Is this the same widget we were over before? if (_guiLastWidgetLeft != widget) { + // Tell previous widget we're moving out. if (_guiLastWidgetLeft->mouseEventMethod) _guiLastWidgetLeft->mouseEventMethod(_guiLastWidgetLeft, mouse, mx, my, MOUSE_EVENT_OUT); @@ -297,6 +330,10 @@ static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) { } + // If this is a left click, change focus to this new widget. + if (event == MOUSE_EVENT_LEFT_DOWN) focusDown = widget; + if (event == MOUSE_EVENT_LEFT_UP && widget == focusDown) guiFocusSet(widget); + _guiLastWidgetLeft = widget; _guiLastWidgetLeftEvent = event; @@ -344,14 +381,17 @@ void guiSetWidgetAndChildrenDirty(WidgetT *widget) { DesktopT *guiStartup(void) { - _guiMetric[METRIC_BUTTON_BEZEL_SIZE] = 2; - _guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN] = 8; - _guiMetric[METRIC_BUTTON_VERTICAL_MARGIN] = 2; - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] = 4; // Does not include highlight or shadow lines. - _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] = 17; // Does not include highlight or shadow lines. - _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT] = _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 5; // Border, highlights, titlebar. - _guiMetric[METRIC_CHECKBOX_PADDING] = 6; // Makes the 10 wide checkbox fill two character cells by padding it out to 16. - _guiMetric[METRIC_RADIOBUTTON_PADDING] = 6; // Makes the 10 wide radio button fill two character cells by padding it out to 16. + _guiMetric[METRIC_BUTTON_BEZEL_SIZE] = 2; + _guiMetric[METRIC_BUTTON_HORIZONTAL_PADDING] = 8; + _guiMetric[METRIC_BUTTON_VERTICAL_PADDING] = 2; + _guiMetric[METRIC_WINDOW_BORDER_WIDTH] = 4; // Does not include highlight or shadow lines. + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] = 17; // Does not include highlight or shadow lines. + _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT] = _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 5; // Border, highlights, titlebar. + _guiMetric[METRIC_CHECKBOX_PADDING] = 6; // Makes the 10 wide checkbox fill two character cells by padding it out to 16. + _guiMetric[METRIC_RADIOBUTTON_PADDING] = 6; // Makes the 10 wide radio button fill two character cells by padding it out to 16. + _guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING] = 2; + _guiMetric[METRIC_TEXTBOX_VERTICAL_PADDING] = 2; + _guiMetric[METRIC_TEXTBOX_PADDING] = 6; // Matches other label / widget padding. _guiColor[COLOR_BUTTON_BACKGROUND] = vbeMakeColor(168, 168, 168); _guiColor[COLOR_BUTTON_HIGHLIGHT] = vbeMakeColor(248, 252, 248); @@ -380,6 +420,10 @@ DesktopT *guiStartup(void) { _guiColor[COLOR_FRAME_HIGHLIGHT] = vbeMakeColor(248, 252, 248); _guiColor[COLOR_FRAME_SHADOW] = vbeMakeColor( 0, 0, 0); _guiColor[COLOR_FRAME_TEXT] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_TEXTBOX_HIGHLIGHT] = vbeMakeColor(248, 252, 248); + _guiColor[COLOR_TEXTBOX_SHADOW] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_TEXTBOX_TEXT] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_TEXTBOX_BACKGROUND] = vbeMakeColor(248, 252, 248); _guiFont = fontLoad("vga8x14.dat"); diff --git a/client/src/gui/gui.h b/client/src/gui/gui.h index 074a3cd..127cc09 100644 --- a/client/src/gui/gui.h +++ b/client/src/gui/gui.h @@ -47,7 +47,7 @@ enum MagicE { MAGIC_RADIOBUTTON, MAGIC_PICTURE, MAGIC_FRAME, - //MAGIC_TEXTBOX, + MAGIC_TEXTBOX, //MAGIC_UPDOWN, //MAGIC_LISTBOX, MAGIC_COUNT @@ -56,13 +56,16 @@ enum MagicE { // Widget Metrics enum MetricE { METRIC_BUTTON_BEZEL_SIZE = 0, - METRIC_BUTTON_HORIZONTAL_MARGIN, - METRIC_BUTTON_VERTICAL_MARGIN, + METRIC_BUTTON_HORIZONTAL_PADDING, + METRIC_BUTTON_VERTICAL_PADDING, METRIC_WINDOW_BORDER_WIDTH, METRIC_WINDOW_TITLE_HEIGHT, METRIC_WINDOW_TITLE_GRAB_HEIGHT, METRIC_CHECKBOX_PADDING, METRIC_RADIOBUTTON_PADDING, + METRIC_TEXTBOX_HORIZONTAL_PADDING, + METRIC_TEXTBOX_VERTICAL_PADDING, + METRIC_TEXTBOX_PADDING, METRIC_COUNT }; @@ -95,6 +98,10 @@ enum ColorE { COLOR_FRAME_HIGHLIGHT, COLOR_FRAME_SHADOW, COLOR_FRAME_TEXT, + COLOR_TEXTBOX_HIGHLIGHT, + COLOR_TEXTBOX_SHADOW, + COLOR_TEXTBOX_TEXT, + COLOR_TEXTBOX_BACKGROUND, COLOR_COUNT }; @@ -127,8 +134,11 @@ void guiAttach(WidgetT *parent, WidgetT *child); void guiComposite(void); void guiDelete(WidgetT **widget); void guiDrawHighlightFrame(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, ColorT upperLeft, ColorT lowerRight); -void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT pixel); -void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT pixel); +void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color); +void guiDrawRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color); +void guiDrawRectangleFilled(int16_t x1, int16_t y1, int16_t x2, int16_t y2, ColorT color); +WidgetT *guiFocusGet(void); +void guiFocusSet(WidgetT *widget); void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *x, uint16_t *y); void guiPaint(WidgetT *widget); void guiProcessMouse(MouseT *mouse); diff --git a/client/src/gui/textbox.c b/client/src/gui/textbox.c new file mode 100644 index 0000000..087d0c0 --- /dev/null +++ b/client/src/gui/textbox.c @@ -0,0 +1,171 @@ +/* + * Kangaroo Punch MultiPlayer Game Server Mark II + * Copyright (C) 2020-2021 Scott Duensing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#include "textbox.h" + + +static void textboxFocusEvent(WidgetT *widget, uint8_t focused); +static void textboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); +static void textboxPaint(WidgetT *widget); + + +void textboxDel(WidgetT **widget) { + TextboxT *t = (TextboxT *)*widget; + + if (t->title) free(t->title); + if (t->value) free(t->value); + free(t); + t = NULL; +} + + +static void textboxFocusEvent(WidgetT *widget, uint8_t focused) { + +} + + +char *textboxGetValue(TextboxT *textbox) { + return textbox->value; +} + + +WidgetT *textboxInit(WidgetT *widget, uint16_t x, uint16_t y, uint16_t w, char *title) { + TextboxT *t = (TextboxT *)widget; + + t->base.magic = MAGIC_TEXTBOX; + t->base.x = x; + t->base.y = y; + t->base.w = w; + t->base.h = fontHeightGet(_guiFont) + 4 + (_guiMetric[METRIC_TEXTBOX_VERTICAL_PADDING] * 2); + t->base.delMethod = textboxDel; + t->base.focusMethod = textboxFocusEvent; + t->base.paintMethod = textboxPaint; + t->base.mouseEventMethod = textboxMouseEvent; + t->title = NULL; + t->maxLength = 256; + t->value = (char *)malloc(t->maxLength); + t->caret = 0; + + if (!t->value) return NULL; + t->value[0] = 0; + + // Visible is set in textboxSetTitle + textboxSetTitle(t, title); + + return widget; +} + + +static void textboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { + TextboxT *t = (TextboxT *)widget; + + (void)x; + (void)y; + (void)mouse; + + //***TODO*** Allow dragging text cursor with mouse. +} + + +TextboxT *textboxNew(uint16_t x, uint16_t y, uint16_t w, char *title) { + TextboxT *textbox = (TextboxT *)malloc(sizeof(TextboxT)); + WidgetT *widget = NULL; + + if (!textbox) return NULL; + + widget = widgetInit((WidgetT *)textbox); + if (!widget) { + free(textbox); + return NULL; + } + + + if (!textbox) return NULL; + + widget = widgetInit((WidgetT *)textbox); + if (!widget) { + free(textbox); + return NULL; + } + + textbox = (TextboxT *)textboxInit((WidgetT *)textbox, x, y, w, title); + + return textbox; +} + + +static void textboxPaint(WidgetT *widget) { + TextboxT *t = (TextboxT *)widget; + uint16_t labelWidth = (strlen(t->title) * fontWidthGet(_guiFont)) + _guiMetric[METRIC_TEXTBOX_PADDING]; + uint16_t valueWidth = (t->visible * fontWidthGet(_guiFont)) + (_guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING] * 2); + char *draw = NULL; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(t->base.surface); + + // Draw title. + fontRender(_guiFont, t->title, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_WINDOW_BACKGROUND], t->base.x, t->base.y + 1 + _guiMetric[METRIC_TEXTBOX_VERTICAL_PADDING]); + + // Draw outline of textbox. + guiDrawHighlightFrame( t->base.x + labelWidth, t->base.y, t->base.x + labelWidth + valueWidth + 2, t->base.y + t->base.h, _guiColor[COLOR_TEXTBOX_SHADOW], _guiColor[COLOR_TEXTBOX_HIGHLIGHT]); + guiDrawRectangle( t->base.x + labelWidth + 1, t->base.y + 1, t->base.x + labelWidth + valueWidth + 1, t->base.y + t->base.h - 1, _guiColor[COLOR_WINDOW_BACKGROUND]); + + // Draw background. + guiDrawRectangleFilled(t->base.x + labelWidth + 2, t->base.y + 2, t->base.x + labelWidth + valueWidth, t->base.y + t->base.h - 2, _guiColor[COLOR_TEXTBOX_BACKGROUND]); + + // Draw value. ***TODO*** This needs much more! + draw = strdup(t->value); + if (strlen(t->value) > t->visible) draw[t->visible] = 0; + fontRender(_guiFont, draw, _guiColor[COLOR_TEXTBOX_TEXT], _guiColor[COLOR_TEXTBOX_BACKGROUND], t->base.x + labelWidth + 2 + _guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING], t->base.y + 2 + _guiMetric[METRIC_TEXTBOX_VERTICAL_PADDING]); + free(draw); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void textboxSetValue(TextboxT *textbox, char *value) { + // Copy it & truncate if needed. + strncpy(textbox->value, value, textbox->maxLength - 1); + + GUI_SET_FLAG((WidgetT *)textbox, WIDGET_FLAG_DIRTY); +} + + +void textboxSetMaxLength(TextboxT *textbox, uint16_t length) { + char *temp = strdup(textbox->value); + + free(textbox->value); + textbox->maxLength = length + 1; + textbox->value = (char *)malloc(textbox->maxLength); + textboxSetValue(textbox, temp); + free(temp); +} + + +void textboxSetTitle(TextboxT *textbox, char *title) { + if (textbox->title) free(textbox->title); + textbox->title = strdup(title); + + // Figure out how many characters we have room to display. + textbox->visible = (textbox->base.w - ((strlen(title) * fontWidthGet(_guiFont)) + _guiMetric[METRIC_TEXTBOX_PADDING] + 4 + (_guiMetric[METRIC_TEXTBOX_HORIZONTAL_PADDING] * 2))) / fontWidthGet(_guiFont); + + GUI_SET_FLAG((WidgetT *)textbox, WIDGET_FLAG_DIRTY); +} diff --git a/client/src/gui/textbox.h b/client/src/gui/textbox.h new file mode 100644 index 0000000..85e9475 --- /dev/null +++ b/client/src/gui/textbox.h @@ -0,0 +1,50 @@ +/* + * Kangaroo Punch MultiPlayer Game Server Mark II + * Copyright (C) 2020-2021 Scott Duensing + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + */ + + +#ifndef TEXTBOX_H +#define TEXTBOX_H + + +#include "gui.h" +#include "widget.h" + + +typedef struct TextboxS { + WidgetT base; // Must be first in every widget + char *title; + char *value; + uint16_t maxLength; // Maximum length of value + 1 + uint16_t caret; // Cursor position in control (caret + offset = cursor positition in value) + uint16_t offset; // First character position to display in control + uint8_t visible; // How many characters are visible in control + uint8_t blink; +} TextboxT; + + +void textboxDel(WidgetT **widget); +char *textboxGetValue(TextboxT *textbox); +WidgetT *textboxInit(WidgetT *widget, uint16_t x, uint16_t y, uint16_t w, char *title); +TextboxT *textboxNew(uint16_t x, uint16_t y, uint16_t w, char *title); +void textboxSetValue(TextboxT *textbox, char *value); +void textboxSetMaxLength(TextboxT *textbox, uint16_t length); +void textboxSetTitle(TextboxT *textbox, char *title); + + +#endif // TEXTBOX_H diff --git a/client/src/gui/widget.c b/client/src/gui/widget.c index ad78266..2c2bfcd 100644 --- a/client/src/gui/widget.c +++ b/client/src/gui/widget.c @@ -44,6 +44,7 @@ WidgetT *widgetInit(WidgetT *widget) { widget->children = NULL; widget->parent = NULL; widget->delMethod = NULL; + widget->focusMethod = NULL; widget->paintMethod = NULL; widget->mouseEventMethod = NULL; widget->userData = NULL; diff --git a/client/src/gui/widget.h b/client/src/gui/widget.h index edfb619..d5bc3b7 100644 --- a/client/src/gui/widget.h +++ b/client/src/gui/widget.h @@ -38,6 +38,7 @@ typedef struct WindowS WindowT; typedef void (*widgetCallback)(struct WidgetS *widget); typedef void (*widgetDelMethod)(struct WidgetS **widget); +typedef void (*widgetFocusMethod)(struct WidgetS *widget, uint8_t focused); typedef void (*widgetPaintMethod)(struct WidgetS *widget); typedef void (*widgetMouseEventMethod)(struct WidgetS *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); @@ -56,6 +57,7 @@ typedef struct WidgetS { WidgetT **children; // List of children WidgetT *parent; // Parent of this widget widgetDelMethod delMethod; // Delete method + widgetFocusMethod focusMethod; // Focus changed method widgetPaintMethod paintMethod; // Paint method widgetMouseEventMethod mouseEventMethod; // Mouse event handler void *userData; // Anything the user wants to store diff --git a/client/src/gui/window.c b/client/src/gui/window.c index 9061453..5fb93ef 100644 --- a/client/src/gui/window.c +++ b/client/src/gui/window.c @@ -165,7 +165,7 @@ static void windowPaint(WidgetT *widget) { // Title bar - METRIC_WINDOW_TITLE_HEIGHT pixels high. Be sure shadow and highlight are not included in the width. guiDrawHighlightFrame(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 3, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 3, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 4, _guiColor[COLOR_WINDOW_HIGHLIGHT], _guiColor[COLOR_WINDOW_SHADOW]); - guiDrawFilledRectangle(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 2, background); + guiDrawRectangleFilled(_guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 4, x2 - _guiMetric[METRIC_WINDOW_BORDER_WIDTH] - 4, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + _guiMetric[METRIC_WINDOW_TITLE_HEIGHT] + 2, background); fontRender(_guiFont, w->title, text, background, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 16, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 5); diff --git a/client/src/main.c b/client/src/main.c index 65e512d..09d6e9d 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -24,6 +24,8 @@ * - Fix function naming to be classItemVerb (checkboxValueGet instead of checkboxGetValue) * - Replace any direct data manipulation from outside a class with methods to handle it * - More widget states: Ghosted, hidden + * - Move setup math for paint events inside the dirty check + * - Methods that can change the width of a widget (such as setTitle) need to repaint the parent window as well * */ @@ -46,6 +48,7 @@ #include "radio.h" #include "picture.h" #include "frame.h" +#include "textbox.h" void buttonClick(WidgetT *widget) { @@ -72,6 +75,7 @@ void test(void *data) { RadioT *r3b = NULL; PictureT *p1 = NULL; FrameT *f1 = NULL; + TextboxT *t1 = NULL; int8_t key = 0; (void)data; @@ -106,6 +110,9 @@ void test(void *data) { guiAttach(W(w2), W(r3b)); radioSetSelected(r1a); radioSetSelected(r2b); + t1 = textboxNew(10, 60, 265, "Test Textbox"); + textboxSetValue(t1, "Text to edit!"); + guiAttach(W(w2), W(t1)); // Window 3 f1 = frameNew(10, 5, 175, 125, "Test Frame");