Basic click handling for widgets implemented.
This commit is contained in:
parent
018ccedd46
commit
34dd7d7fbe
7 changed files with 124 additions and 18 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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?
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Add table
Reference in a new issue