Now understands the concept of "focus". Textbox widget started.
This commit is contained in:
parent
7c531861a4
commit
148a6b4f9f
11 changed files with 318 additions and 31 deletions
|
@ -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 \
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
171
client/src/gui/textbox.c
Normal file
171
client/src/gui/textbox.c
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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);
|
||||
}
|
50
client/src/gui/textbox.h
Normal file
50
client/src/gui/textbox.h
Normal file
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#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
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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");
|
||||
|
|
Loading…
Add table
Reference in a new issue