From 7c531861a412c0d428451dd4179c358f79b031c7 Mon Sep 17 00:00:00 2001 From: Scott Duensing Date: Tue, 19 Oct 2021 19:24:52 -0500 Subject: [PATCH] Fixes, new widgets: Checkbox, Frame, Label, Picture, Radio Button. --- client/client.pro | 10 ++ client/data/kanga.png | 3 + client/src/gui/button.c | 16 ++- client/src/gui/button.h | 1 + client/src/gui/checkbox.c | 151 +++++++++++++++++++++++++++ client/src/gui/checkbox.h | 45 +++++++++ client/src/gui/frame.c | 101 +++++++++++++++++++ client/src/gui/frame.h | 41 ++++++++ client/src/gui/gui.c | 19 +++- client/src/gui/gui.h | 31 +++++- client/src/gui/image.c | 24 ++++- client/src/gui/image.h | 16 +-- client/src/gui/label.c | 148 +++++++++++++++++++++++++++ client/src/gui/label.h | 49 +++++++++ client/src/gui/picture.c | 114 +++++++++++++++++++++ client/src/gui/picture.h | 44 ++++++++ client/src/gui/radio.c | 207 ++++++++++++++++++++++++++++++++++++++ client/src/gui/radio.h | 46 +++++++++ client/src/gui/widget.c | 10 ++ client/src/gui/widget.h | 6 +- client/src/gui/window.c | 4 +- client/src/main.c | 81 ++++++++++++--- 22 files changed, 1130 insertions(+), 37 deletions(-) create mode 100644 client/data/kanga.png create mode 100644 client/src/gui/checkbox.c create mode 100644 client/src/gui/checkbox.h create mode 100644 client/src/gui/frame.c create mode 100644 client/src/gui/frame.h create mode 100644 client/src/gui/label.c create mode 100644 client/src/gui/label.h create mode 100644 client/src/gui/picture.c create mode 100644 client/src/gui/picture.h create mode 100644 client/src/gui/radio.c create mode 100644 client/src/gui/radio.h diff --git a/client/client.pro b/client/client.pro index e93b5c4..5990656 100644 --- a/client/client.pro +++ b/client/client.pro @@ -45,7 +45,12 @@ INCLUDEPATH += \ HEADERS = \ $$LINUX_HEADERS \ src/gui/button.h \ + src/gui/checkbox.h \ + src/gui/frame.h \ src/gui/keyboard.h \ + src/gui/label.h \ + src/gui/picture.h \ + src/gui/radio.h \ src/gui/task.h \ src/thirdparty/stb_ds.h \ src/thirdparty/stb_leakcheck.h \ @@ -67,9 +72,14 @@ SOURCES = \ $$LINUX_SOURCES \ src/gui/array.c \ src/gui/button.c \ + src/gui/checkbox.c \ src/gui/font.c \ src/gui/desktop.c \ + src/gui/frame.c \ src/gui/gui.c \ + src/gui/label.c \ + src/gui/picture.c \ + src/gui/radio.c \ src/gui/task.c \ src/gui/widget.c \ src/gui/window.c \ diff --git a/client/data/kanga.png b/client/data/kanga.png new file mode 100644 index 0000000..65bf33d --- /dev/null +++ b/client/data/kanga.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9fdc5a05e7c468e98ebda1ab929e25677045690cebbd630217e617981be42386 +size 24155 diff --git a/client/src/gui/button.c b/client/src/gui/button.c index a37f312..794bfce 100644 --- a/client/src/gui/button.c +++ b/client/src/gui/button.c @@ -20,6 +20,7 @@ #include "button.h" + static void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); static void buttonPaint(WidgetT *widget); @@ -43,8 +44,8 @@ WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widget b->base.paintMethod = buttonPaint; b->base.mouseEventMethod = buttonMouseEvent; b->title = NULL; - b->clicked = callback; + buttonSetClickHandler(b, callback); buttonSetTitle(b, title); // Width is set in buttonSetTitle @@ -102,8 +103,9 @@ ButtonT *buttonNew(uint16_t x, uint16_t y, char *title, widgetCallback callback) static void buttonPaint(WidgetT *widget) { ButtonT *b = (ButtonT *)widget; int16_t i; - ColorT highlight = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_BUTTON_SHADOW] : _guiColor[COLOR_BUTTON_HIGHLIGHT]; - ColorT shadow = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_BUTTON_HIGHLIGHT] : _guiColor[COLOR_BUTTON_SHADOW] ; + int8_t active = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE); + ColorT highlight = active ? _guiColor[COLOR_BUTTON_SHADOW] : _guiColor[COLOR_BUTTON_HIGHLIGHT]; + ColorT shadow = active ? _guiColor[COLOR_BUTTON_HIGHLIGHT] : _guiColor[COLOR_BUTTON_SHADOW] ; if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { vbeSurfaceSet(b->base.surface); @@ -117,15 +119,21 @@ static void buttonPaint(WidgetT *widget) { 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]); // 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], b->base.y + i + _guiMetric[METRIC_BUTTON_VERTICAL_MARGIN]); + 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); GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); } } +void buttonSetClickHandler(ButtonT *button, widgetCallback callback) { + button->clicked = 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); + GUI_SET_FLAG((WidgetT *)button, WIDGET_FLAG_DIRTY); } diff --git a/client/src/gui/button.h b/client/src/gui/button.h index 0d2d1cc..37d7a1a 100644 --- a/client/src/gui/button.h +++ b/client/src/gui/button.h @@ -36,6 +36,7 @@ typedef struct ButtonS { void buttonDel(WidgetT **widget); WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widgetCallback callback); ButtonT *buttonNew(uint16_t x, uint16_t y, char *title, widgetCallback callback); +void buttonSetClickHandler(ButtonT *button, widgetCallback callback); void buttonSetTitle(ButtonT *button, char *title); diff --git a/client/src/gui/checkbox.c b/client/src/gui/checkbox.c new file mode 100644 index 0000000..7344eca --- /dev/null +++ b/client/src/gui/checkbox.c @@ -0,0 +1,151 @@ +/* + * 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 "checkbox.h" + + +static void checkboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); +static void checkboxPaint(WidgetT *widget); + + +void checkboxDel(WidgetT **widget) { + CheckboxT *c = (CheckboxT *)*widget; + + if (c->title) free(c->title); + free(c); + c = NULL; +} + + +uint8_t checkboxGetValue(CheckboxT *checkbox) { + return GUI_GET_FLAG((WidgetT *)checkbox, WIDGET_FLAG_ACTIVE); +} + + +WidgetT *checkboxInit(WidgetT *widget, uint16_t x, uint16_t y, char *title) { + CheckboxT *c = (CheckboxT *)widget; + + c->base.magic = MAGIC_CHECKBOX; + c->base.x = x; + c->base.y = y; + c->base.delMethod = checkboxDel; + c->base.paintMethod = checkboxPaint; + c->base.mouseEventMethod = checkboxMouseEvent; + c->title = NULL; + c->clicked = NULL; + + checkboxSetTitle(c, title); + + // Width is set in checkboxSetTitle + c->base.h = fontHeightGet(_guiFont); + + return widget; +} + + +static void checkboxMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { + CheckboxT *c = (CheckboxT *)widget; + + (void)x; + (void)y; + (void)mouse; + + if (event == MOUSE_EVENT_LEFT_UP) { + // Toggle value. + checkboxSetValue(c, !checkboxGetValue(c)); + // Fire callback on mouse up. + if (c->clicked) c->clicked(widget); + } +} + + +CheckboxT *checkboxNew(uint16_t x, uint16_t y, char *title) { + CheckboxT *checkbox = (CheckboxT *)malloc(sizeof(CheckboxT)); + WidgetT *widget = NULL; + + if (!checkbox) return NULL; + + widget = widgetInit((WidgetT *)checkbox); + if (!widget) { + free(checkbox); + return NULL; + } + + checkbox = (CheckboxT *)checkboxInit((WidgetT *)checkbox, x, y, title); + + return checkbox; +} + + +static void checkboxPaint(WidgetT *widget) { + CheckboxT *c = (CheckboxT *)widget; + int16_t o; + int8_t active = checkboxGetValue(c); + ColorT highlight = active ? _guiColor[COLOR_CHECKBOX_SHADOW] : _guiColor[COLOR_CHECKBOX_HIGHLIGHT]; + ColorT shadow = active ? _guiColor[COLOR_CHECKBOX_HIGHLIGHT] : _guiColor[COLOR_CHECKBOX_SHADOW]; + ColorT fill = active ? _guiColor[COLOR_CHECKBOX_ACTIVE] : _guiColor[COLOR_CHECKBOX_INACTIVE]; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(c->base.surface); + + // Checkbox is 10x10 pixels. Find offset based on font height. + o = (_guiFont->height - 10) * 0.5; + + // Draw outline of checkbox. + 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); + + // 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); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void checkboxSetClickHandler(CheckboxT *checkbox, widgetCallback callback) { + checkbox->clicked = callback; +} + + +void checkboxSetTitle(CheckboxT *checkbox, char *title) { + if (checkbox->title) free(checkbox->title); + checkbox->title = strdup(title); + checkbox->base.w = (strlen(title) * fontWidthGet(_guiFont)) + 10 + _guiMetric[METRIC_CHECKBOX_PADDING]; + GUI_SET_FLAG((WidgetT *)checkbox, WIDGET_FLAG_DIRTY); +} + + +void checkboxSetValue(CheckboxT *checkbox, uint8_t selected) { + if (selected) { + if (!checkboxGetValue(checkbox)) { + GUI_SET_FLAG((WidgetT *)checkbox, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG((WidgetT *)checkbox, WIDGET_FLAG_DIRTY); + } + } else { + if (checkboxGetValue(checkbox)) { + GUI_CLEAR_FLAG((WidgetT *)checkbox, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG((WidgetT *)checkbox, WIDGET_FLAG_DIRTY); + } + } +} + diff --git a/client/src/gui/checkbox.h b/client/src/gui/checkbox.h new file mode 100644 index 0000000..8838820 --- /dev/null +++ b/client/src/gui/checkbox.h @@ -0,0 +1,45 @@ +/* + * 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 CHECKBOX_H +#define CHECKBOX_H + + +#include "gui.h" +#include "widget.h" + + +typedef struct CheckboxS { + WidgetT base; // Must be first in every widget + char *title; + widgetCallback clicked; +} CheckboxT; + + +void checkboxDel(WidgetT **widget); +uint8_t checkboxGetValue(CheckboxT *checkbox); +WidgetT *checkboxInit(WidgetT *widget, uint16_t x, uint16_t y, char *title); +CheckboxT *checkboxNew(uint16_t x, uint16_t y, char *title); +void checkboxSetClickHandler(CheckboxT *checkbox, widgetCallback callback); +void checkboxSetTitle(CheckboxT *checkbox, char *title); +void checkboxSetValue(CheckboxT *checkbox, uint8_t selected); + + +#endif // CHECKBOX_H diff --git a/client/src/gui/frame.c b/client/src/gui/frame.c new file mode 100644 index 0000000..07a38d8 --- /dev/null +++ b/client/src/gui/frame.c @@ -0,0 +1,101 @@ +/* + * 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 "frame.h" + + +static void framePaint(WidgetT *widget); + + +void frameDel(WidgetT **widget) { + FrameT *f = (FrameT *)*widget; + + if (f->title) free(f->title); + free(f); + f = NULL; +} + + +WidgetT *frameInit(WidgetT *widget, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) { + FrameT *f = (FrameT *)widget; + + f->base.magic = MAGIC_FRAME; + f->base.x = x; + f->base.y = y; + f->base.w = w; + f->base.h = h; + f->base.delMethod = frameDel; + f->base.paintMethod = framePaint; + f->title = NULL; + + f->base.marginX += 3; + f->base.marginY += 9; + + frameSetTitle(f, title); + + return widget; +} + + +FrameT *frameNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) { + FrameT *frame = (FrameT *)malloc(sizeof(FrameT)); + WidgetT *widget = NULL; + + if (!frame) return NULL; + + widget = widgetInit((WidgetT *)frame); + if (!widget) { + free(frame); + return NULL; + } + + frame = (FrameT *)frameInit((WidgetT *)frame, x, y, w, h, title); + + return frame; +} + + +static void framePaint(WidgetT *widget) { + FrameT *f = (FrameT *)widget; + uint16_t o = _guiFont->height * 0.5; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(f->base.surface); + + // Draw frame. + guiDrawHighlightFrame(f->base.x, f->base.y + o, f->base.x + f->base.w, f->base.y + f->base.h - o, _guiColor[COLOR_FRAME_SHADOW], _guiColor[COLOR_FRAME_HIGHLIGHT]); + + // Draw title. + fontRender(_guiFont, f->title, _guiColor[COLOR_FRAME_TEXT], _guiColor[COLOR_WINDOW_BACKGROUND], f->base.x + 10, f->base.y); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void frameSetTitle(FrameT *frame, char *title) { + if (frame->title) free(frame->title); + frame->title = (char *)malloc(strlen(title) + 3); + frame->title[0] = ' '; + frame->title[1] = 0; + strcat(frame->title, title); + strcat(frame->title, " "); + GUI_SET_FLAG((WidgetT *)frame, WIDGET_FLAG_DIRTY); +} diff --git a/client/src/gui/frame.h b/client/src/gui/frame.h new file mode 100644 index 0000000..687caa1 --- /dev/null +++ b/client/src/gui/frame.h @@ -0,0 +1,41 @@ +/* + * 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 FRAME_H +#define FRAME_H + + +#include "gui.h" +#include "widget.h" + + +typedef struct FrameS { + WidgetT base; // Must be first in every widget + char *title; +} FrameT; + + +void frameDel(WidgetT **widget); +WidgetT *frameInit(WidgetT *widget, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title); +FrameT *frameNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title); +void frameSetTitle(FrameT *frame, char *title); + + +#endif // FRAME_H diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c index 0f328d3..0b2d1a5 100644 --- a/client/src/gui/gui.c +++ b/client/src/gui/gui.c @@ -349,7 +349,9 @@ DesktopT *guiStartup(void) { _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] + 4; // 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_RADIOBUTTON_PADDING] = 6; // Makes the 10 wide radio button fill two character cells by padding it out to 16. _guiColor[COLOR_BUTTON_BACKGROUND] = vbeMakeColor(168, 168, 168); _guiColor[COLOR_BUTTON_HIGHLIGHT] = vbeMakeColor(248, 252, 248); @@ -363,6 +365,21 @@ DesktopT *guiStartup(void) { _guiColor[COLOR_WINDOW_TITLE_INACTIVE] = vbeMakeColor(168, 168, 168); _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] = vbeMakeColor(248, 252, 248); _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_LABEL_TEXT_INACTIVE] = vbeMakeColor(248, 252, 248); + _guiColor[COLOR_LABEL_TEXT_INACTIVE] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_CHECKBOX_HIGHLIGHT] = vbeMakeColor(248, 252, 248); + _guiColor[COLOR_CHECKBOX_SHADOW] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_CHECKBOX_ACTIVE] = vbeMakeColor( 80, 84, 80); + _guiColor[COLOR_CHECKBOX_INACTIVE] = vbeMakeColor(168, 168, 168); + _guiColor[COLOR_CHECKBOX_TEXT] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_RADIOBUTTON_HIGHLIGHT] = vbeMakeColor(248, 252, 248); + _guiColor[COLOR_RADIOBUTTON_SHADOW] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_RADIOBUTTON_ACTIVE] = vbeMakeColor( 80, 84, 80); + _guiColor[COLOR_RADIOBUTTON_INACTIVE] = vbeMakeColor(168, 168, 168); + _guiColor[COLOR_RADIOBUTTON_TEXT] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_FRAME_HIGHLIGHT] = vbeMakeColor(248, 252, 248); + _guiColor[COLOR_FRAME_SHADOW] = vbeMakeColor( 0, 0, 0); + _guiColor[COLOR_FRAME_TEXT] = vbeMakeColor( 0, 0, 0); _guiFont = fontLoad("vga8x14.dat"); diff --git a/client/src/gui/gui.h b/client/src/gui/gui.h index 593b439..074a3cd 100644 --- a/client/src/gui/gui.h +++ b/client/src/gui/gui.h @@ -29,9 +29,9 @@ #include "font.h" -#define GUI_GET_FLAG(w,f) ((w)->flags & (1 << (f))) -#define GUI_SET_FLAG(w,f) (w)->flags |= (1 << (f)) -#define GUI_CLEAR_FLAG(w,f) (w)->flags &= (~(1 << (f))) +#define GUI_GET_FLAG(w,f) (((w)->flags & (1 << (f))) != 0) +#define GUI_SET_FLAG(w,f) ((w)->flags |= (1 << (f))) +#define GUI_CLEAR_FLAG(w,f) ((w)->flags &= (~(1 << (f)))) #define W(w) ((WidgetT *)w) @@ -42,6 +42,14 @@ enum MagicE { MAGIC_DESKTOP, MAGIC_WINDOW, MAGIC_BUTTON, + MAGIC_LABEL, + MAGIC_CHECKBOX, + MAGIC_RADIOBUTTON, + MAGIC_PICTURE, + MAGIC_FRAME, + //MAGIC_TEXTBOX, + //MAGIC_UPDOWN, + //MAGIC_LISTBOX, MAGIC_COUNT }; @@ -53,6 +61,8 @@ enum MetricE { METRIC_WINDOW_BORDER_WIDTH, METRIC_WINDOW_TITLE_HEIGHT, METRIC_WINDOW_TITLE_GRAB_HEIGHT, + METRIC_CHECKBOX_PADDING, + METRIC_RADIOBUTTON_PADDING, METRIC_COUNT }; @@ -70,6 +80,21 @@ enum ColorE { COLOR_WINDOW_TITLE_INACTIVE, COLOR_WINDOW_TITLE_TEXT_ACTIVE, COLOR_WINDOW_TITLE_TEXT_INACTIVE, + COLOR_LABEL_TEXT_ACTIVE, + COLOR_LABEL_TEXT_INACTIVE, + COLOR_CHECKBOX_HIGHLIGHT, + COLOR_CHECKBOX_SHADOW, + COLOR_CHECKBOX_ACTIVE, + COLOR_CHECKBOX_INACTIVE, + COLOR_CHECKBOX_TEXT, + COLOR_RADIOBUTTON_HIGHLIGHT, + COLOR_RADIOBUTTON_SHADOW, + COLOR_RADIOBUTTON_ACTIVE, + COLOR_RADIOBUTTON_INACTIVE, + COLOR_RADIOBUTTON_TEXT, + COLOR_FRAME_HIGHLIGHT, + COLOR_FRAME_SHADOW, + COLOR_FRAME_TEXT, COLOR_COUNT }; diff --git a/client/src/gui/image.c b/client/src/gui/image.c index 0725b96..c318b73 100644 --- a/client/src/gui/image.c +++ b/client/src/gui/image.c @@ -74,6 +74,11 @@ ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color) { } +uint16_t imageHeightGet(ImageT *image) { + return image->height; +} + + ImageT *imageLoad(char *filename) { uint16_t x; uint16_t y; @@ -116,9 +121,15 @@ ColorT imagePixelGet(ImageT *image, uint16_t x, uint16_t y) { void imageRender(ImageT *image, uint16_t x, uint16_t y) { uint16_t x1; uint16_t y1; + uint16_t x2 = image->width; + uint16_t y2 = image->height; - for (y1=0; y1height; y1++) { - for (x1=0; x1width; x1++) { + // Clip on right and bottom + if (x + x2 > vbeSurfaceWidthGet()) x2 -= x + x2 - vbeSurfaceWidthGet(); + if (y + y2 > vbeSurfaceHeightGet()) y2 -= y + y2 - vbeSurfaceHeightGet(); + + for (y1=0; y1pixels[x1][y1]); } } @@ -132,8 +143,8 @@ void imageRenderWithAlpha(ImageT *image, uint16_t x, uint16_t y, ColorT alpha) { uint16_t y2 = image->height; // Clip on right and bottom - if (x + x2 > vbeDisplayWidthGet()) x2 -= x + x2 - vbeDisplayWidthGet(); - if (y + y2 > vbeDisplayHeightGet()) y2 -= y + y2 - vbeDisplayHeightGet(); + if (x + x2 > vbeSurfaceWidthGet()) x2 -= x + x2 - vbeSurfaceWidthGet(); + if (y + y2 > vbeSurfaceHeightGet()) y2 -= y + y2 - vbeSurfaceHeightGet(); for (y1=0; y1width; +} diff --git a/client/src/gui/image.h b/client/src/gui/image.h index bbaa043..f052d69 100644 --- a/client/src/gui/image.h +++ b/client/src/gui/image.h @@ -35,13 +35,15 @@ typedef struct ImageS { } ImageT; -ImageT *imageAllocate(uint16_t w, uint16_t h); -ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color); -ImageT *imageLoad(char *filename); -ColorT imagePixelGet(ImageT *image, uint16_t x, uint16_t y); -void imageRender(ImageT *image, uint16_t x, uint16_t y); -void imageRenderWithAlpha(ImageT *image, uint16_t x, uint16_t y, ColorT alpha); -void imageUnload(ImageT **image); +ImageT *imageAllocate(uint16_t w, uint16_t h); +ImageT *imageCreate(uint16_t w, uint16_t h, ColorT color); +uint16_t imageHeightGet(ImageT *image); +ImageT *imageLoad(char *filename); +ColorT imagePixelGet(ImageT *image, uint16_t x, uint16_t y); +void imageRender(ImageT *image, uint16_t x, uint16_t y); +void imageRenderWithAlpha(ImageT *image, uint16_t x, uint16_t y, ColorT alpha); +void imageUnload(ImageT **image); +uint16_t imageWidthGet(ImageT *image); #endif // IMAGE_H diff --git a/client/src/gui/label.c b/client/src/gui/label.c new file mode 100644 index 0000000..4c89435 --- /dev/null +++ b/client/src/gui/label.c @@ -0,0 +1,148 @@ +/* + * 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 "label.h" + + +static void labelMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); +static void labelPaint(WidgetT *widget); + + +void labelDel(WidgetT **widget) { + LabelT *l = (LabelT *)*widget; + + if (l->title) free(l->title); + free(l); + l = NULL; +} + + +WidgetT *labelInit(WidgetT *widget, uint16_t x, uint16_t y, char *title) { + LabelT *l = (LabelT *)widget; + + l->base.magic = MAGIC_LABEL; + l->base.x = x; + l->base.y = y; + l->base.delMethod = labelDel; + l->base.paintMethod = labelPaint; + l->base.mouseEventMethod = labelMouseEvent; + l->title = NULL; + l->background = _guiColor[COLOR_WINDOW_BACKGROUND]; + l->foreground = _guiColor[COLOR_LABEL_TEXT_INACTIVE]; + l->clicked = NULL; + + labelSetTitle(l, title); + + // Width is set in labelSetTitle + l->base.h = fontHeightGet(_guiFont); + + return widget; +} + + +static void labelMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { + LabelT *l = (LabelT *)widget; + + (void)x; + (void)y; + (void)mouse; + + // Label pressed? + if (event == MOUSE_EVENT_LEFT_HOLD) { + if (!GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { + GUI_SET_FLAG(widget, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY); + } + } else { + if (GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY); + } + } + + // Fire callback on mouse up. + if (event == MOUSE_EVENT_LEFT_UP) { + if (l->clicked) l->clicked(widget); + } +} + + +LabelT *labelNew(uint16_t x, uint16_t y, char *title) { + LabelT *label = (LabelT *)malloc(sizeof(LabelT)); + WidgetT *widget = NULL; + + if (!label) return NULL; + + widget = widgetInit((WidgetT *)label); + if (!widget) { + free(label); + return NULL; + } + + label = (LabelT *)labelInit((WidgetT *)label, x, y, title); + + return label; +} + + +static void labelPaint(WidgetT *widget) { + LabelT *l = (LabelT *)widget; + ColorT text = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? l->active : l->foreground; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(l->base.surface); + + // Draw title. + fontRender(_guiFont, l->title, text, l->background, l->base.x, l->base.y); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void labelSetActiveColor(LabelT *label, ColorT color) { + label->active = color; + GUI_SET_FLAG((WidgetT *)label, WIDGET_FLAG_DIRTY); +} + + +void labelSetBackgroundColor(LabelT *label, ColorT color) { + label->background = color; + GUI_SET_FLAG((WidgetT *)label, WIDGET_FLAG_DIRTY); +} + + +void labelSetClickHandler(LabelT *label, widgetCallback callback) { + label->clicked = callback; +} + + +void labelSetForegroundColor(LabelT *label, ColorT color) { + label->foreground = color; + GUI_SET_FLAG((WidgetT *)label, WIDGET_FLAG_DIRTY); +} + + +void labelSetTitle(LabelT *label, char *title) { + if (label->title) free(label->title); + label->title = strdup(title); + label->base.w = (strlen(title) * fontWidthGet(_guiFont)); + GUI_SET_FLAG((WidgetT *)label, WIDGET_FLAG_DIRTY); +} diff --git a/client/src/gui/label.h b/client/src/gui/label.h new file mode 100644 index 0000000..47cedb2 --- /dev/null +++ b/client/src/gui/label.h @@ -0,0 +1,49 @@ +/* + * 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 LABEL_H +#define LABEL_H + + +#include "gui.h" +#include "widget.h" + + +typedef struct LabelS { + WidgetT base; // Must be first in every widget + char *title; + widgetCallback clicked; + ColorT active; + ColorT foreground; + ColorT background; +} LabelT; + + +void labelDel(WidgetT **widget); +WidgetT *labelInit(WidgetT *widget, uint16_t x, uint16_t y, char *title); +LabelT *labelNew(uint16_t x, uint16_t y, char *title); +void labelSetActiveColor(LabelT *label, ColorT color); +void labelSetBackgroundColor(LabelT *label, ColorT color); +void labelSetClickHandler(LabelT *label, widgetCallback callback); +void labelSetForegroundColor(LabelT *label, ColorT color); +void labelSetTitle(LabelT *label, char *title); + + +#endif // LABEL_H diff --git a/client/src/gui/picture.c b/client/src/gui/picture.c new file mode 100644 index 0000000..6092972 --- /dev/null +++ b/client/src/gui/picture.c @@ -0,0 +1,114 @@ +/* + * 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 "picture.h" + + +static void pictureMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); +static void picturePaint(WidgetT *widget); + + +void pictureDel(WidgetT **widget) { + PictureT *p = (PictureT *)*widget; + + if (p->image) imageUnload(&p->image); + if (p->filename) free(p->filename); + free(p); + p = NULL; +} + + +WidgetT *pictureInit(WidgetT *widget, uint16_t x, uint16_t y, char *filename) { + PictureT *l = (PictureT *)widget; + + l->base.magic = MAGIC_PICTURE; + l->base.x = x; + l->base.y = y; + l->base.delMethod = pictureDel; + l->base.paintMethod = picturePaint; + l->base.mouseEventMethod = pictureMouseEvent; + l->filename = strdup(filename); + l->clicked = NULL; + + l->image = imageLoad(l->filename); + if (!l->image) { + free(l->filename); + return NULL; + } + + l->base.w = imageWidthGet(l->image); + l->base.h = imageHeightGet(l->image); + + return widget; +} + + +static void pictureMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { + PictureT *p = (PictureT *)widget; + + (void)x; + (void)y; + (void)mouse; + + // Fire callback on mouse up. + if (event == MOUSE_EVENT_LEFT_UP) { + if (p->clicked) p->clicked(widget); + } +} + + +PictureT *pictureNew(uint16_t x, uint16_t y, char *filename) { + PictureT *picture = (PictureT *)malloc(sizeof(PictureT)); + WidgetT *widget = NULL; + + if (!picture) return NULL; + + widget = widgetInit((WidgetT *)picture); + if (!widget) { + free(picture); + return NULL; + } + + picture = (PictureT *)pictureInit((WidgetT *)picture, x, y, filename); + if (!picture) { + free(picture); + return NULL; + } + + return picture; +} + + +static void picturePaint(WidgetT *widget) { + PictureT *p = (PictureT *)widget; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(p->base.surface); + + imageRender(p->image, p->base.x, p->base.y); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void pictureSetClickHandler(PictureT *picture, widgetCallback callback) { + picture->clicked = callback; +} diff --git a/client/src/gui/picture.h b/client/src/gui/picture.h new file mode 100644 index 0000000..735d42c --- /dev/null +++ b/client/src/gui/picture.h @@ -0,0 +1,44 @@ +/* + * 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 PICTURE_H +#define PICTURE_H + + +#include "gui.h" +#include "widget.h" +#include "image.h" + + +typedef struct PictureS { + WidgetT base; // Must be first in every widget + char *filename; + widgetCallback clicked; + ImageT *image; +} PictureT; + + +void pictureDel(WidgetT **widget); +WidgetT *pictureInit(WidgetT *widget, uint16_t x, uint16_t y, char *filename); +PictureT *pictureNew(uint16_t x, uint16_t y, char *filename); +void pictureSetClickHandler(PictureT *picture, widgetCallback callback); + + +#endif // PICTURE_H diff --git a/client/src/gui/radio.c b/client/src/gui/radio.c new file mode 100644 index 0000000..d8ebd60 --- /dev/null +++ b/client/src/gui/radio.c @@ -0,0 +1,207 @@ +/* + * 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 "radio.h" + + +static void radioClearSelectedInGroup(WidgetT *widget, uint32_t group); +static RadioT *radioFindSelectedInGroup(WidgetT *widget, uint32_t group); +static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event); +static void radioPaint(WidgetT *widget); + + +static void radioClearSelectedInGroup(WidgetT *widget, uint32_t group) { + size_t len = arrlenu(widget->children); + size_t x; + + // Is this a Radio Button? + if (widget->magic == MAGIC_RADIOBUTTON) { + // Is this in our group and active? + if (((RadioT *)widget)->group == group && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { + // Deactivate it, mark it dirty, and stop searching. + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY); + return; + } + } + + // Process any children. + if (len > 0) { + for (x=0; xchildren[x], group); + } + } +} + + +void radioDel(WidgetT **widget) { + RadioT *r = (RadioT *)*widget; + + if (r->title) free(r->title); + free(r); + r = NULL; +} + + +static RadioT *radioFindSelectedInGroup(WidgetT *widget, uint32_t group) { + size_t len = arrlenu(widget->children); + size_t x; + RadioT *result = NULL; + + // Is this a Radio Button? + if (widget->magic == MAGIC_RADIOBUTTON) { + // Is this in our group and active? + if (((RadioT *)widget)->group == group && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) { + // Found! Stop searching. + return (RadioT *)widget; + } + } + + // Process any children. + if (len > 0) { + for (x=0; xchildren[x], group); + if (result) break; + } + } + + return result; +} + + +RadioT *radioGetSelected(RadioT *radio) { + return radioFindSelectedInGroup(guiRootGet(), radio->group); +} + + +WidgetT *radioInit(WidgetT *widget, uint16_t x, uint16_t y, char *title, uint16_t group) { + RadioT *r = (RadioT *)widget; + + r->base.magic = MAGIC_RADIOBUTTON; + r->base.x = x; + r->base.y = y; + r->base.delMethod = radioDel; + r->base.paintMethod = radioPaint; + r->base.mouseEventMethod = radioMouseEvent; + r->title = NULL; + r->clicked = NULL; + r->group = group; + + radioSetTitle(r, title); + + // Width is set in radioSetTitle + r->base.h = fontHeightGet(_guiFont); + + return widget; +} + + +static void radioMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) { + RadioT *r = (RadioT *)widget; + + (void)x; + (void)y; + (void)mouse; + + if (event == MOUSE_EVENT_LEFT_UP) { + // Select us. + radioSetSelected(r); + // Fire callback on mouse up. + if (r->clicked) r->clicked(widget); + } +} + + +RadioT *radioNew(uint16_t x, uint16_t y, char *title, uint16_t group) { + RadioT *radio = (RadioT *)malloc(sizeof(RadioT)); + WidgetT *widget = NULL; + + if (!radio) return NULL; + + widget = widgetInit((WidgetT *)radio); + if (!widget) { + free(radio); + return NULL; + } + + radio = (RadioT *)radioInit((WidgetT *)radio, x, y, title, group); + + return radio; +} + + +static void radioPaint(WidgetT *widget) { + RadioT *r = (RadioT *)widget; + int16_t i; + int16_t o; + uint8_t active = (radioGetSelected(r) == r); + ColorT highlight = active ? _guiColor[COLOR_RADIOBUTTON_SHADOW] : _guiColor[COLOR_RADIOBUTTON_HIGHLIGHT]; + ColorT shadow = active ? _guiColor[COLOR_RADIOBUTTON_HIGHLIGHT] : _guiColor[COLOR_RADIOBUTTON_SHADOW]; + ColorT fill = active ? _guiColor[COLOR_RADIOBUTTON_ACTIVE] : _guiColor[COLOR_RADIOBUTTON_INACTIVE]; + + if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) { + vbeSurfaceSet(r->base.surface); + + // Radio button is 10x10 pixels. Find offset based on font height. + o = (_guiFont->height - 10) * 0.5; + + // Draw outline of radio button. + guiDrawLine(r->base.x, r->base.y + o + 5, r->base.x + 5, r->base.y + o, highlight); + guiDrawLine(r->base.x + 5, r->base.y + o, r->base.x + 10, r->base.y + o + 5, highlight); + guiDrawLine(r->base.x, r->base.y + o + 5, r->base.x + 5, r->base.y + o + 10, shadow); + guiDrawLine(r->base.x + 5, r->base.y + o + 10, r->base.x + 10, r->base.y + o + 5, shadow); + + // Fill radio button. + for (i=0; i<4; i++) { + guiDrawLine(r->base.x + 5 - i, r->base.y + o + i + 1, r->base.x + 5 + i, r->base.y + o + i + 1, fill); + guiDrawLine(r->base.x + 5 - i, r->base.y + o - i + 8, r->base.x + 5 + i, r->base.y + o - i + 8, fill); + } + + // Draw title. + fontRender(_guiFont, r->title, _guiColor[COLOR_RADIOBUTTON_TEXT], _guiColor[COLOR_WINDOW_BACKGROUND], r->base.x + 10 + _guiMetric[METRIC_RADIOBUTTON_PADDING], r->base.y); + + GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY); + } +} + + +void radioSetClickHandler(RadioT *radio, widgetCallback callback) { + radio->clicked = callback; +} + + +void radioSetSelected(RadioT *radio) { + // Are we already selected? + if (!GUI_GET_FLAG((WidgetT *)radio, WIDGET_FLAG_ACTIVE)) { + // Clear whoever is selected. + radioClearSelectedInGroup(guiRootGet(), radio->group); + // Select us. + GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_ACTIVE); + GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_DIRTY); + } +} + + +void radioSetTitle(RadioT *radio, char *title) { + if (radio->title) free(radio->title); + radio->title = strdup(title); + radio->base.w = (strlen(title) * fontWidthGet(_guiFont)) + 10 + _guiMetric[METRIC_RADIOBUTTON_PADDING]; + GUI_SET_FLAG((WidgetT *)radio, WIDGET_FLAG_DIRTY); +} diff --git a/client/src/gui/radio.h b/client/src/gui/radio.h new file mode 100644 index 0000000..c56f58c --- /dev/null +++ b/client/src/gui/radio.h @@ -0,0 +1,46 @@ +/* + * 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 RADIO_H +#define RADIO_H + + +#include "gui.h" +#include "widget.h" + + +typedef struct RadioS { + WidgetT base; // Must be first in every widget + char *title; + uint16_t group; + widgetCallback clicked; +} RadioT; + + +void radioDel(WidgetT **widget); +RadioT *radioGetSelected(RadioT *radio); +WidgetT *radioInit(WidgetT *widget, uint16_t x, uint16_t y, char *title, uint16_t group); +RadioT *radioNew(uint16_t x, uint16_t y, char *title, uint16_t group); +void radioSetClickHandler(RadioT *radio, widgetCallback callback); +void radioSetSelected(RadioT *radio); +void radioSetTitle(RadioT *radio, char *title); + + +#endif // RADIO_H diff --git a/client/src/gui/widget.c b/client/src/gui/widget.c index b19f500..ad78266 100644 --- a/client/src/gui/widget.c +++ b/client/src/gui/widget.c @@ -21,6 +21,16 @@ #include "widget.h" +uint16_t widgetGetHeight(WidgetT *widget) { + return widget->h; +} + + +uint16_t widgetGetWidth(WidgetT *widget) { + return widget->w; +} + + WidgetT *widgetInit(WidgetT *widget) { widget->magic = MAGIC_UNKNOWN; widget->flags = 0; diff --git a/client/src/gui/widget.h b/client/src/gui/widget.h index 9ac6267..edfb619 100644 --- a/client/src/gui/widget.h +++ b/client/src/gui/widget.h @@ -62,8 +62,10 @@ typedef struct WidgetS { } WidgetT; -WidgetT *widgetInit(WidgetT *widget); -WidgetT *widgetNew(void); +uint16_t widgetGetHeight(WidgetT *widget); +uint16_t widgetGetWidth(WidgetT *widget); +WidgetT *widgetInit(WidgetT *widget); +WidgetT *widgetNew(void); #endif // WIDGET_H diff --git a/client/src/gui/window.c b/client/src/gui/window.c index 8acc383..9061453 100644 --- a/client/src/gui/window.c +++ b/client/src/gui/window.c @@ -70,8 +70,8 @@ WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_ win->flags = 0; win->title = NULL; - win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2; - win->base.marginY += _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]; + win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 6; + win->base.marginY += _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT] + 1; windowSetTitle(win, title); diff --git a/client/src/main.c b/client/src/main.c index 3d92e67..65e512d 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -18,6 +18,16 @@ */ +/* + * To Do: + * + * - 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 + * + */ + + #include "os.h" #include "vesa.h" #include "mouse.h" @@ -25,11 +35,17 @@ #include "task.h" #include "image.h" #include "font.h" + #include "gui.h" #include "widget.h" #include "desktop.h" #include "window.h" #include "button.h" +#include "label.h" +#include "checkbox.h" +#include "radio.h" +#include "picture.h" +#include "frame.h" void buttonClick(WidgetT *widget) { @@ -38,36 +54,73 @@ void buttonClick(WidgetT *widget) { void test(void *data) { - MouseT *mouse = NULL; - ImageT *pointer = NULL; - ColorT alpha; - DesktopT *desktop = (DesktopT *)guiRootGet(); - WindowT *w1 = NULL; - WindowT *w2 = NULL; - WindowT *w3 = NULL; - ButtonT *b1 = NULL; - int8_t key = 0; + MouseT *mouse = NULL; + ImageT *pointer = NULL; + ColorT alpha; + DesktopT *desktop = (DesktopT *)guiRootGet(); + WindowT *w1 = NULL; + WindowT *w2 = NULL; + WindowT *w3 = NULL; + ButtonT *b1 = NULL; + LabelT *l1 = NULL; + CheckboxT *c1 = NULL; + RadioT *r1a = NULL; + RadioT *r2a = NULL; + RadioT *r3a = NULL; + RadioT *r1b = NULL; + RadioT *r2b = NULL; + RadioT *r3b = NULL; + PictureT *p1 = NULL; + FrameT *f1 = NULL; + int8_t key = 0; (void)data; pointer = imageLoad("mouse.png"); alpha = imagePixelGet(pointer, 5, 0); + // Windows w1 = windowNew(25, 25, 300, 200, "Window 1"); - w2 = windowNew(150, 150, 300, 200, "Window 2"); - w3 = windowNew(300, 300, 300, 200, "Window 3"); guiAttach(W(desktop), W(w1)); + w2 = windowNew(150, 150, 300, 200, "Window 2"); guiAttach(W(desktop), W(w2)); + w3 = windowNew(300, 300, 300, 200, "Window 3"); guiAttach(W(desktop), W(w3)); - b1 = buttonNew(25, 25, "Test Button", buttonClick); - guiAttach(W(w3), W(b1)); + // Window 1 + p1 = pictureNew(0, 0, "kanga.png"); + guiAttach(W(w1), W(p1)); + + // Window 2 + r1a = radioNew(10, 10, "Radio 1a", 1); + guiAttach(W(w2), W(r1a)); + r2a = radioNew(20 + widgetGetWidth(W(r1a)), 10, "Radio 2a", 1); + guiAttach(W(w2), W(r2a)); + r3a = radioNew(30 + widgetGetWidth(W(r1a)) + widgetGetWidth(W(r2a)), 10, "Radio 3a", 1); + guiAttach(W(w2), W(r3a)); + r1b = radioNew(10, 35, "Radio 1b", 2); + guiAttach(W(w2), W(r1b)); + r2b = radioNew(20 + widgetGetWidth(W(r1b)), 35, "Radio 2b", 2); + guiAttach(W(w2), W(r2b)); + r3b = radioNew(30 + widgetGetWidth(W(r1b)) + widgetGetWidth(W(r2b)), 35, "Radio 3b", 2); + guiAttach(W(w2), W(r3b)); + radioSetSelected(r1a); + radioSetSelected(r2b); + + // Window 3 + f1 = frameNew(10, 5, 175, 125, "Test Frame"); + guiAttach(W(w3), W(f1)); + b1 = buttonNew(10, 10, "Test Button", buttonClick); + guiAttach(W(f1), W(b1)); + l1 = labelNew(10, 40, "Test Label"); + guiAttach(W(f1), W(l1)); + c1 = checkboxNew(10, 65, "Test Checkbox"); + guiAttach(W(f1), W(c1)); do { mouse = mouseRead(); if (keyHit()) { key = keyASCII(); - logWrite("Key %d Scan %d Alt %d\n", key, keyScanCode(), keyAlt()); } else { key = 0; }