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/picture.h \
|
||||||
src/gui/radio.h \
|
src/gui/radio.h \
|
||||||
src/gui/task.h \
|
src/gui/task.h \
|
||||||
|
src/gui/textbox.h \
|
||||||
src/thirdparty/stb_ds.h \
|
src/thirdparty/stb_ds.h \
|
||||||
src/thirdparty/stb_leakcheck.h \
|
src/thirdparty/stb_leakcheck.h \
|
||||||
src/thirdparty/stb_image.h \
|
src/thirdparty/stb_image.h \
|
||||||
|
@ -81,6 +82,7 @@ SOURCES = \
|
||||||
src/gui/picture.c \
|
src/gui/picture.c \
|
||||||
src/gui/radio.c \
|
src/gui/radio.c \
|
||||||
src/gui/task.c \
|
src/gui/task.c \
|
||||||
|
src/gui/textbox.c \
|
||||||
src/gui/widget.c \
|
src/gui/widget.c \
|
||||||
src/gui/window.c \
|
src/gui/window.c \
|
||||||
src/gui/image.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);
|
buttonSetTitle(b, title);
|
||||||
|
|
||||||
// Width is set in buttonSetTitle
|
// 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;
|
return button;
|
||||||
}
|
}
|
||||||
|
@ -116,10 +116,10 @@ static void buttonPaint(WidgetT *widget) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw background (depends on x from above).
|
// 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).
|
// 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);
|
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||||
}
|
}
|
||||||
|
@ -134,6 +134,6 @@ void buttonSetClickHandler(ButtonT *button, widgetCallback callback) {
|
||||||
void buttonSetTitle(ButtonT *button, char *title) {
|
void buttonSetTitle(ButtonT *button, char *title) {
|
||||||
if (button->title) free(button->title);
|
if (button->title) free(button->title);
|
||||||
button->title = strdup(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);
|
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);
|
guiDrawHighlightFrame(c->base.x, c->base.y + o, c->base.x + 10, c->base.y + 10 + o, highlight, shadow);
|
||||||
|
|
||||||
// Draw background.
|
// 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.
|
// 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);
|
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 DesktopT *_guiDesktop = NULL;
|
||||||
static WidgetT *_guiLastWidgetLeft = NULL;
|
static WidgetT *_guiLastWidgetLeft = NULL;
|
||||||
static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
|
static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
|
||||||
|
static WidgetT *_guiFocused = NULL;
|
||||||
|
|
||||||
|
|
||||||
static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse);
|
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 x;
|
||||||
uint16_t y;
|
uint16_t y;
|
||||||
|
|
||||||
for (y=y1; y<=y2; y++) {
|
for (y=y1; y<=y2; y++) {
|
||||||
for (x=x1; x<=x2; x++) {
|
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 len = arrlenu(widget->children);
|
||||||
size_t x;
|
size_t x;
|
||||||
|
|
||||||
// Paint us, if needed.
|
// Paint us. Widget handles dirty flag so they can animate if needed.
|
||||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY) && widget->paintMethod) {
|
if (widget->paintMethod) {
|
||||||
widget->paintMethod(widget);
|
widget->paintMethod(widget);
|
||||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Paint all children.
|
// Paint all children.
|
||||||
|
@ -246,13 +277,14 @@ void guiProcessMouse(MouseT *mouse) {
|
||||||
|
|
||||||
|
|
||||||
static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) {
|
static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) {
|
||||||
size_t len;
|
size_t len;
|
||||||
int16_t x;
|
int16_t x;
|
||||||
uint16_t mx;
|
uint16_t mx;
|
||||||
uint16_t my;
|
uint16_t my;
|
||||||
uint16_t sx;
|
uint16_t sx;
|
||||||
uint16_t sy;
|
uint16_t sy;
|
||||||
uint8_t event = MOUSE_EVENT_NONE;
|
uint8_t event = MOUSE_EVENT_NONE;
|
||||||
|
static WidgetT *focusDown = NULL;
|
||||||
|
|
||||||
// Search children backwards for active widget before checking this widget.
|
// Search children backwards for active widget before checking this widget.
|
||||||
len = arrlenu(widget->children);
|
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?
|
// Is this the same widget we were over before?
|
||||||
if (_guiLastWidgetLeft != widget) {
|
if (_guiLastWidgetLeft != widget) {
|
||||||
|
|
||||||
// Tell previous widget we're moving out.
|
// Tell previous widget we're moving out.
|
||||||
if (_guiLastWidgetLeft->mouseEventMethod) _guiLastWidgetLeft->mouseEventMethod(_guiLastWidgetLeft, mouse, mx, my, MOUSE_EVENT_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;
|
_guiLastWidgetLeft = widget;
|
||||||
_guiLastWidgetLeftEvent = event;
|
_guiLastWidgetLeftEvent = event;
|
||||||
|
|
||||||
|
@ -344,14 +381,17 @@ void guiSetWidgetAndChildrenDirty(WidgetT *widget) {
|
||||||
|
|
||||||
DesktopT *guiStartup(void) {
|
DesktopT *guiStartup(void) {
|
||||||
|
|
||||||
_guiMetric[METRIC_BUTTON_BEZEL_SIZE] = 2;
|
_guiMetric[METRIC_BUTTON_BEZEL_SIZE] = 2;
|
||||||
_guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN] = 8;
|
_guiMetric[METRIC_BUTTON_HORIZONTAL_PADDING] = 8;
|
||||||
_guiMetric[METRIC_BUTTON_VERTICAL_MARGIN] = 2;
|
_guiMetric[METRIC_BUTTON_VERTICAL_PADDING] = 2;
|
||||||
_guiMetric[METRIC_WINDOW_BORDER_WIDTH] = 4; // Does not include highlight or shadow lines.
|
_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_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_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_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_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_BACKGROUND] = vbeMakeColor(168, 168, 168);
|
||||||
_guiColor[COLOR_BUTTON_HIGHLIGHT] = vbeMakeColor(248, 252, 248);
|
_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_HIGHLIGHT] = vbeMakeColor(248, 252, 248);
|
||||||
_guiColor[COLOR_FRAME_SHADOW] = vbeMakeColor( 0, 0, 0);
|
_guiColor[COLOR_FRAME_SHADOW] = vbeMakeColor( 0, 0, 0);
|
||||||
_guiColor[COLOR_FRAME_TEXT] = 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");
|
_guiFont = fontLoad("vga8x14.dat");
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ enum MagicE {
|
||||||
MAGIC_RADIOBUTTON,
|
MAGIC_RADIOBUTTON,
|
||||||
MAGIC_PICTURE,
|
MAGIC_PICTURE,
|
||||||
MAGIC_FRAME,
|
MAGIC_FRAME,
|
||||||
//MAGIC_TEXTBOX,
|
MAGIC_TEXTBOX,
|
||||||
//MAGIC_UPDOWN,
|
//MAGIC_UPDOWN,
|
||||||
//MAGIC_LISTBOX,
|
//MAGIC_LISTBOX,
|
||||||
MAGIC_COUNT
|
MAGIC_COUNT
|
||||||
|
@ -56,13 +56,16 @@ enum MagicE {
|
||||||
// Widget Metrics
|
// Widget Metrics
|
||||||
enum MetricE {
|
enum MetricE {
|
||||||
METRIC_BUTTON_BEZEL_SIZE = 0,
|
METRIC_BUTTON_BEZEL_SIZE = 0,
|
||||||
METRIC_BUTTON_HORIZONTAL_MARGIN,
|
METRIC_BUTTON_HORIZONTAL_PADDING,
|
||||||
METRIC_BUTTON_VERTICAL_MARGIN,
|
METRIC_BUTTON_VERTICAL_PADDING,
|
||||||
METRIC_WINDOW_BORDER_WIDTH,
|
METRIC_WINDOW_BORDER_WIDTH,
|
||||||
METRIC_WINDOW_TITLE_HEIGHT,
|
METRIC_WINDOW_TITLE_HEIGHT,
|
||||||
METRIC_WINDOW_TITLE_GRAB_HEIGHT,
|
METRIC_WINDOW_TITLE_GRAB_HEIGHT,
|
||||||
METRIC_CHECKBOX_PADDING,
|
METRIC_CHECKBOX_PADDING,
|
||||||
METRIC_RADIOBUTTON_PADDING,
|
METRIC_RADIOBUTTON_PADDING,
|
||||||
|
METRIC_TEXTBOX_HORIZONTAL_PADDING,
|
||||||
|
METRIC_TEXTBOX_VERTICAL_PADDING,
|
||||||
|
METRIC_TEXTBOX_PADDING,
|
||||||
METRIC_COUNT
|
METRIC_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -95,6 +98,10 @@ enum ColorE {
|
||||||
COLOR_FRAME_HIGHLIGHT,
|
COLOR_FRAME_HIGHLIGHT,
|
||||||
COLOR_FRAME_SHADOW,
|
COLOR_FRAME_SHADOW,
|
||||||
COLOR_FRAME_TEXT,
|
COLOR_FRAME_TEXT,
|
||||||
|
COLOR_TEXTBOX_HIGHLIGHT,
|
||||||
|
COLOR_TEXTBOX_SHADOW,
|
||||||
|
COLOR_TEXTBOX_TEXT,
|
||||||
|
COLOR_TEXTBOX_BACKGROUND,
|
||||||
COLOR_COUNT
|
COLOR_COUNT
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -127,8 +134,11 @@ void guiAttach(WidgetT *parent, WidgetT *child);
|
||||||
void guiComposite(void);
|
void guiComposite(void);
|
||||||
void guiDelete(WidgetT **widget);
|
void guiDelete(WidgetT **widget);
|
||||||
void guiDrawHighlightFrame(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, ColorT upperLeft, ColorT lowerRight);
|
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 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);
|
||||||
|
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 guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *x, uint16_t *y);
|
||||||
void guiPaint(WidgetT *widget);
|
void guiPaint(WidgetT *widget);
|
||||||
void guiProcessMouse(MouseT *mouse);
|
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->children = NULL;
|
||||||
widget->parent = NULL;
|
widget->parent = NULL;
|
||||||
widget->delMethod = NULL;
|
widget->delMethod = NULL;
|
||||||
|
widget->focusMethod = NULL;
|
||||||
widget->paintMethod = NULL;
|
widget->paintMethod = NULL;
|
||||||
widget->mouseEventMethod = NULL;
|
widget->mouseEventMethod = NULL;
|
||||||
widget->userData = NULL;
|
widget->userData = NULL;
|
||||||
|
|
|
@ -38,6 +38,7 @@ typedef struct WindowS WindowT;
|
||||||
|
|
||||||
typedef void (*widgetCallback)(struct WidgetS *widget);
|
typedef void (*widgetCallback)(struct WidgetS *widget);
|
||||||
typedef void (*widgetDelMethod)(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 (*widgetPaintMethod)(struct WidgetS *widget);
|
||||||
typedef void (*widgetMouseEventMethod)(struct WidgetS *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
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 **children; // List of children
|
||||||
WidgetT *parent; // Parent of this widget
|
WidgetT *parent; // Parent of this widget
|
||||||
widgetDelMethod delMethod; // Delete method
|
widgetDelMethod delMethod; // Delete method
|
||||||
|
widgetFocusMethod focusMethod; // Focus changed method
|
||||||
widgetPaintMethod paintMethod; // Paint method
|
widgetPaintMethod paintMethod; // Paint method
|
||||||
widgetMouseEventMethod mouseEventMethod; // Mouse event handler
|
widgetMouseEventMethod mouseEventMethod; // Mouse event handler
|
||||||
void *userData; // Anything the user wants to store
|
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.
|
// 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]);
|
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);
|
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)
|
* - Fix function naming to be classItemVerb (checkboxValueGet instead of checkboxGetValue)
|
||||||
* - Replace any direct data manipulation from outside a class with methods to handle it
|
* - Replace any direct data manipulation from outside a class with methods to handle it
|
||||||
* - More widget states: Ghosted, hidden
|
* - 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 "radio.h"
|
||||||
#include "picture.h"
|
#include "picture.h"
|
||||||
#include "frame.h"
|
#include "frame.h"
|
||||||
|
#include "textbox.h"
|
||||||
|
|
||||||
|
|
||||||
void buttonClick(WidgetT *widget) {
|
void buttonClick(WidgetT *widget) {
|
||||||
|
@ -72,6 +75,7 @@ void test(void *data) {
|
||||||
RadioT *r3b = NULL;
|
RadioT *r3b = NULL;
|
||||||
PictureT *p1 = NULL;
|
PictureT *p1 = NULL;
|
||||||
FrameT *f1 = NULL;
|
FrameT *f1 = NULL;
|
||||||
|
TextboxT *t1 = NULL;
|
||||||
int8_t key = 0;
|
int8_t key = 0;
|
||||||
|
|
||||||
(void)data;
|
(void)data;
|
||||||
|
@ -106,6 +110,9 @@ void test(void *data) {
|
||||||
guiAttach(W(w2), W(r3b));
|
guiAttach(W(w2), W(r3b));
|
||||||
radioSetSelected(r1a);
|
radioSetSelected(r1a);
|
||||||
radioSetSelected(r2b);
|
radioSetSelected(r2b);
|
||||||
|
t1 = textboxNew(10, 60, 265, "Test Textbox");
|
||||||
|
textboxSetValue(t1, "Text to edit!");
|
||||||
|
guiAttach(W(w2), W(t1));
|
||||||
|
|
||||||
// Window 3
|
// Window 3
|
||||||
f1 = frameNew(10, 5, 175, 125, "Test Frame");
|
f1 = frameNew(10, 5, 175, 125, "Test Frame");
|
||||||
|
|
Loading…
Add table
Reference in a new issue