Basic click handling for widgets implemented.

This commit is contained in:
Scott Duensing 2022-06-26 18:37:00 -05:00
parent 018ccedd46
commit 34dd7d7fbe
7 changed files with 124 additions and 18 deletions

View file

@ -101,6 +101,7 @@ void fontRender(char *string, uint16_t x, uint16_t y) {
for (c=0; c<strlen(string); c++) {
character = string[c];
// Don't forget to update fontWidthCharactersGet.
if (_allowMods) {
// Change _foreground to GUI Color Index.
if (character == 1) {
@ -197,6 +198,38 @@ void fontUnload(FontT **font) {
}
uint16_t fontWidthCharactersGet(char *string) {
uint8_t character;
uint8_t c;
uint16_t count = 0;
// This duplicates a lot of code from fontRender but it keeps the render loop from being ugly.
for (c=0; c<strlen(string); c++) {
character = string[c];
if (_allowMods) {
// Change _foreground to GUI Color Index.
if (character == 1) {
character = string[++c];
if (character == 16) character = 0; // Because we can't pass NULL in a string, 16 is used for black.
continue;
}
// Change _background to GUI Color Index.
if (character == 2) {
character = string[++c];
if (character == 16) character = 0; // Because we can't pass NULL in a string, 16 is used for black.
continue;
}
}
count++;
}
return count;
}
uint16_t fontWidthGet(FontT *font) {
return font->width;
}

View file

@ -25,6 +25,7 @@ void fontModsEnabledSet(uint8_t enabled);
void fontRender(char *string, uint16_t x, uint16_t y);
void fontSet(FontT *font);
void fontUnload(FontT **font);
uint16_t fontWidthCharactersGet(char *string);
uint16_t fontWidthGet(FontT *font);

View file

@ -11,6 +11,7 @@ struct WidgetS;
typedef void (*GuiCallbackT)(void *data, ...);
typedef void (*WidgetEventT)(struct WidgetS *widget, ...);
typedef void (*ClickHandlerT)(struct WidgetS *widget, uint16_t x, uint16_t y, void *data);
typedef struct PointS {
int16_t x;
@ -31,16 +32,16 @@ typedef struct RectS {
} RectT;
typedef struct RegisterS {
char *widgetName; // Text name of widget.
WidgetEventT click; // Click handler.
WidgetEventT destroy; // Destroy routine.
WidgetEventT paint; // Paint routine.
GuiCallbackT unregister; // Unregister routine.
char *widgetName; // Text name of widget.
ClickHandlerT click; // Click handler.
WidgetEventT destroy; // Destroy routine.
WidgetEventT paint; // Paint routine.
GuiCallbackT unregister; // Unregister routine.
} RegisterT;
typedef struct WidgetS {
uint8_t magic; // Magic ID of widget.
RectT r; // Outer bounds, except for windows.
RectT r; // Outer bounds of widget. NOTE: USES WIDTH/HEIGHT, NOT X2/Y2!
RegisterT *reg; // Registration information.
void *data; // Pointer to arbitrary data for user.
uint8_t dirty; // Is the widget dirty?

View file

@ -8,7 +8,7 @@ static void labelDestroy(struct WidgetS *widget, ...);
static void labelPaint(struct WidgetS *widget, ...);
void labelClickSet(LabelT *label, WidgetEventT handler, void *data) {
void labelClickSet(LabelT *label, ClickHandlerT handler, void *data) {
label->base.reg->click = handler;
label->base.data = data;
}
@ -21,19 +21,39 @@ void labelColorSet(LabelT *label, ColorT foreground, ColorT background) {
}
LabelT *labelCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, FontT *font, char *contents, ...) {
LabelT *l = NULL;
// ***TODO*** Auto-calculate width/height.
LabelT *labelCreate(uint16_t x, uint16_t y, uint8_t alignment, FontT *font, char *contents, ...) {
LabelT *l = NULL;
uint16_t width;
uint16_t height;
NEW(LabelT, l);
memset(l, 0, sizeof(LabelT));
guiWidgetBaseSet((WidgetT *)l, __MAGIC_LABEL, x, y, w, h);
l->font = font;
l->text = strdup(contents);
l->foreground = GUI_BLACK;
l->background = GUI_LIGHTGRAY;
l->modsEnabled = 0;
l->alignment = alignment;
l->pos.x = x;
l->pos.y = y;
width = fontWidthCharactersGet(contents) * fontWidthGet(font);
height = fontHeightGet(font);
switch (alignment) {
case LABEL_ALIGN_LEFT:
// Passed in values are fine.
break;
case LABEL_ALIGN_CENTER:
x -= width * 0.5;
break;
case LABEL_ALIGN_RIGHT:
x -= width;
break;
}
guiWidgetBaseSet((WidgetT *)l, __MAGIC_LABEL, x, y, width, height);
return l;
}
@ -55,7 +75,7 @@ static void labelPaint(struct WidgetS *widget, ...) {
fontSet(l->font);
fontColorSet(l->foreground, l->background);
fontModsEnabledSet(l->modsEnabled);
// ***TODO*** Alignment, clipping, etc.
// ***TODO*** Clipping.
fontRender(l->text, l->base.r.x, l->base.r.y);
}
}

View file

@ -5,9 +5,16 @@
#include "../gui.h"
#define LABEL_ALIGN_LEFT 0
#define LABEL_ALIGN_RIGHT 1
#define LABEL_ALIGN_CENTER 2
typedef struct LabelS {
WidgetT base; // Required by all widgets.
char *text; // Contents of label.
PointT pos; // Anchor position (before alignment).
uint8_t alignment; // Alignment from specified location.
FontT *font; // Font to use.
uint8_t modsEnabled; // Escape codes enabled?
ColorT foreground; // Foreground color.
@ -18,9 +25,9 @@ typedef struct LabelS {
extern uint8_t __MAGIC_LABEL; // Magic ID assigned to us from the GUI.
void labelClickSet(LabelT *label, WidgetEventT handler, void *data);
void labelClickSet(LabelT *label, ClickHandlerT handler, void *data);
void labelColorSet(LabelT *label, ColorT foreground, ColorT background);
LabelT *labelCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, FontT *font, char *contents, ...);
LabelT *labelCreate(uint16_t x, uint16_t y, uint8_t alignment, FontT *font, char *contents, ...);
RegisterT *labelRegister(uint8_t magic);

View file

@ -870,6 +870,8 @@ void wmStartup(void) {
void wmUpdate(EventT *event) {
int16_t i;
int16_t x;
int16_t y;
int16_t x2;
int16_t y2;
uint8_t onResize = 0;
@ -879,6 +881,7 @@ void wmUpdate(EventT *event) {
static PointT resizeOffset = { 0 };
static uint8_t dragging = 0;
static PointT dragOffset = { 0 };
static WidgetT *widgetDown = NULL;
// Do we have windows?
if (arrlen(_windowList) > 0) {
@ -968,9 +971,19 @@ void wmUpdate(EventT *event) {
break;
}
// Are we inside the window content? Most likely, check first.
// Are we inside the window content? Most likely, check this first.
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
//***TODO*** Send to window for processing.
// Are we over a widget?
x = event->x - win->bounds.x + win->offset.x;
y = event->y - win->bounds.y + win->offset.y;
for (i=0; i<arrlen(win->children); i++) {
widget = win->children[i];
if (x >= widget->r.x && x < widget->r.x + widget->r.x2 && y >= widget->r.y && y < widget->r.y + widget->r.y2) {
// Remember this widget for when left-up occurs.
widgetDown = widget;
break;
}
}
}
// Are we inside the close button? Does not include button frame on purpose.
@ -1093,6 +1106,30 @@ void wmUpdate(EventT *event) {
// Can no longer be resizing.
resizing = 0;
// Did the left button just come up?
if (event->flags & EVENT_FLAG_LEFT_UP) {
// Did this click begin over a widget?
if (widgetDown) {
// Are we still inside the window content?
if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) {
// Are we stll over the same widget?
x = event->x - win->bounds.x + win->offset.x;
y = event->y - win->bounds.y + win->offset.y;
for (i=0; i<arrlen(win->children); i++) {
widget = win->children[i];
if (widget == widgetDown && x >= widget->r.x && x < widget->r.x + widget->r.x2 && y >= widget->r.y && y < widget->r.y + widget->r.y2) {
// Send to widget for processing.
if (widget->reg->click) widget->reg->click(widget, x - widget->r.x, y - widget->r.y, widget->data);
break;
}
}
}
widgetDown = NULL;
} // widgetDown
}
}
break;

View file

@ -3,6 +3,12 @@
#include "gui/widgets/label.h"
void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, void *data) {
(void)widget;
logWrite("%dx%d %s\n", x, y, data);
}
int main(int argc, char *argv[]) {
char title[256];
uint16_t i;
@ -19,8 +25,9 @@ int main(int argc, char *argv[]) {
sprintf(title, "Testing %d", i);
w = windowCreate(i * 50, i * 50, 300, 200, title, WIN_STANDARD, 640, 480);
l = labelCreate(10, 10, 0, 0, __guiFontVGA8x16, "Label Test");
l = labelCreate(150, 10, LABEL_ALIGN_LEFT, __guiFontVGA8x16, "Label Test");
labelColorSet(l, __guiBaseColors[i], GUI_BLACK);
labelClickSet(l, clickHandler, title);
windowWidgetAdd(w, W(l));
}
guiRun();