Frame widget added.

This commit is contained in:
Scott Duensing 2022-09-05 17:00:27 -05:00
parent 87a69959c7
commit 353ebfb68e
9 changed files with 349 additions and 38 deletions

View file

@ -55,6 +55,7 @@ HEADERS += \
src/gui/surface.h \
src/gui/widgets/button.h \
src/gui/widgets/checkbox.h \
src/gui/widgets/frame.h \
src/gui/widgets/label.h \
src/gui/widgets/picture.h \
src/gui/widgets/radio.h \
@ -78,6 +79,7 @@ SOURCES += \
src/gui/surface.c \
src/gui/widgets/button.c \
src/gui/widgets/checkbox.c \
src/gui/widgets/frame.c \
src/gui/widgets/label.c \
src/gui/widgets/picture.c \
src/gui/widgets/radio.c \

View file

@ -39,6 +39,7 @@
#include "widgets/vscroll.h"
#include "widgets/hscroll.h"
#include "widgets/scroll.h"
#include "widgets/frame.h"
#endif // GUIALL_H

View file

@ -202,6 +202,7 @@ uint8_t guiStartup(int16_t width, int16_t height, int16_t depth) {
guiRegister(vscrollRegister);
guiRegister(hscrollRegister);
guiRegister(scrollableRegister); // After hscroll and vscroll.
guiRegister(frameRegister);
return SUCCESS;
}

View file

@ -0,0 +1,266 @@
/*
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
* Copyright (C) 2022 Scott Duensing
*
* http://kangaroopunch.com
*
*
* This file is part of Roo/E.
*
* Roo/E is free software: you can redistribute it and/or modify it under the
* terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Roo/E 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 Affero General Public License
* along with Roo/E. If not, see <https://www.gnu.org/licenses/>.
*
*/
#include "frame.h"
#include "array.h"
uint8_t __MAGIC_FRAME = 0;
static void frameDestroy(struct WidgetS *widget, ...);
static void framePaint(struct WidgetS *widget, ...);
static WidgetT *frameWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY);
// Passing "flags" as a default int provides proper alignment for the following va_args list.
FrameT *frameCreate(char *title, int16_t width, int16_t height, int flags, ...) {
FrameT *f = NULL;
SurfaceT *t = surfaceGet();
va_list args;
NEW(FrameT, f);
memset(f, 0, sizeof(FrameT));
widgetBaseSet(W(f), __MAGIC_FRAME, width, height);
// Set up desired frame style.
f->flags = flags;
// Set up title.
if (title && strlen(title) > 0) {
f->title = (char *)malloc(strlen(title) + 3);
if (!f->title) {
DEL(f);
return NULL;
}
sprintf(f->title, " %s ", title);
}
// Get title and optional font.
if (f->flags & FRAME_FONT) {
va_start(args, flags);
f->font = (FontT *)va_arg(args, void *);
va_end(args);
} else {
f->font = __guiFontVGA8x14;
}
// Surface size is requested size less the font area around it (unless style is FRAME_NONE).
if (f->flags & FRAME_NONE) {
f->pixels.x = width;
f->pixels.y = height;
} else {
// With a frame, we need to adjust the height/width to be a multiple of the font size.
f->chars.x = ((float)f->base.r.w / (float)fontWidthGet(f->font));
f->chars.y = ((float)f->base.r.h / (float)fontHeightGet(f->font));
f->base.r.w = f->chars.x * fontWidthGet(f->font);
f->base.r.h = f->chars.y * fontHeightGet(f->font);
f->pixels.x = f->base.r.w - (fontWidthGet(f->font) * 2);
f->pixels.y = f->base.r.h - (fontHeightGet(f->font) * 2);;
}
// Create surface.
f->surface = surfaceCreate(f->pixels.x, f->pixels.y);
if (!f->surface) {
if (f->title) free(f->title);
DEL(f);
return NULL;
}
surfaceSet(f->surface);
surfaceClear(GUI_LIGHTGRAY);
surfaceSet(t);
return f;
}
static void frameDestroy(struct WidgetS *widget, ...) {
FrameT *f = (FrameT *)widget;
uint16_t c;
// Free children.
for (c=0; c<arrlen(f->base.children); c++) widgetDestroy(f->base.children[c]);
arrfree(f->base.children);
if (f->title) free(f->title);
if (f->surface) surfaceDestroy(&f->surface);
DEL(f);
}
static void framePaint(struct WidgetS *widget, ...) {
FrameT *f = (FrameT *)widget;
SurfaceT *t = surfaceGet();
PointT o;
PointT w;
uint16_t x;
uint16_t x2;
uint16_t y;
uint16_t i;
unsigned char ul;
unsigned char ur;
unsigned char ll;
unsigned char lr;
unsigned char h;
unsigned char v;
unsigned char s[2];
if (widgetDirtyGet(widget)) {
widgetDirtySet(widget, 0);
// If we have a frame, draw it.
if (f->flags & FRAME_NONE) {
w.x = 0;
w.y = 0;
} else {
w.x = fontWidthGet(f->font);
w.y = fontHeightGet(f->font);
if (f->flags & FRAME_SINGLE) {
// Single line frame.
ul = 218;
ur = 191;
ll = 192;
lr = 217;
h = 196;
v = 179;
} else {
// Double line frame.
ul = 201;
ur = 187;
ll = 200;
lr = 188;
h = 205;
v = 186;
}
fontColorSet(GUI_BLACK, GUI_LIGHTGRAY);
fontModsEnabledSet(1);
s[1] = 0;
// Top line.
x = f->base.r.x;
y = f->base.r.y;
s[0] = ul;
fontRender((char *)s, x, y);
x += w.x;
s[0] = h;
for (i=0; i<f->chars.x - 2; i++) {
fontRender((char *)s, x, y);
x += w.x;
}
x2 = x;
s[0] = ur;
fontRender((char *)s, x, y);
// Title (this incurs some overdraw).
if (f->title) {
fontRender(f->title, f->base.r.x + (w.x * 2), y);
}
// Middle lines.
x = f->base.r.x;
y += w.y;
s[0] = v;
for (i=0; i<f->chars.y - 2; i++) {
fontRender((char *)s, x, y);
fontRender((char *)s, x2, y);
y += w.y;
}
// Bottom line.
s[0] = ll;
fontRender((char *)s, x, y);
x += w.x;
s[0] = h;
for (i=0; i<f->chars.x - 2; i++) {
fontRender((char *)s, x, y);
x += w.x;
}
s[0] = lr;
fontRender((char *)s, x, y);
}
// Move the contents to 0,0 to draw it into it's own surface.
o.x = f->base.r.x;
o.y = f->base.r.y;
f->base.r.x = 0;
f->base.r.y = 0;
// Draw children onto surface.
surfaceSet(f->surface);
widgetChildrenPaint(widget);
surfaceSet(t);
// Put us back at the proper coodinates.
f->base.r.x = o.x;
f->base.r.y = o.y;
// Blit.
surfaceBlit(f->base.r.x + w.x, f->base.r.y + w.y, 0, 0, 0, 0, f->surface);
}
}
RegisterT *frameRegister(uint8_t magic) {
static RegisterT reg = {
"Frame",
NULL, // No default on-click handler.
frameDestroy,
framePaint,
NULL, // No unregister handler.
frameWidgetFinder
};
// One-time widget startup code.
__MAGIC_FRAME = magic;
return &reg;
}
static WidgetT *frameWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int16_t *localX, int16_t *localY) {
int16_t i;
WidgetT *w;
PointT p;
FrameT *f = (FrameT *)widget;
// Widget local mouse position.
*localX = x - widget->r.x - (f->flags & FRAME_NONE ? 0 : fontWidthGet(f->font));
*localY = y - widget->r.y - (f->flags & FRAME_NONE ? 0 : fontHeightGet(f->font));
// Find widget under mouse.
for (i=0; i<arrlen(widget->children); i++) {
w = widget->children[i];
if (*localX >= w->r.x && *localX < w->r.x + w->r.w && *localY >= w->r.y && *localY < w->r.y + w->r.h) {
// Ask this widget who we're pointing at.
p.x = *localX;
p.y = *localY;
return w->reg->findWidget(w, p.x, p.y, localX, localY);
}
}
// Didn't find a widget.
return NULL;
}

View file

@ -0,0 +1,57 @@
/*
* Roo/E, the Kangaroo Punch Portable GUI Toolkit
* Copyright (C) 2022 Scott Duensing
*
* http://kangaroopunch.com
*
*
* This file is part of Roo/E.
*
* Roo/E is free software: you can redistribute it and/or modify it under the
* terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option)
* any later version.
*
* Roo/E 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 Affero General Public License
* along with Roo/E. If not, see <https://www.gnu.org/licenses/>.
*
*/
#ifndef FRAME_H
#define FRAME_H
#include "../gui.h"
#define FRAME_NONE 0
#define FRAME_SINGLE 1
#define FRAME_DOUBLE 2
#define FRAME_FONT 4 // User will provide font to use.
typedef struct FrameS {
WidgetT base; // Required by all widgets.
uint8_t flags;
SurfaceT *surface;
PointT pixels; // Size of surface in pixels.
PointT chars; // Size of frame in characters (if there's a border).
char *title;
FontT *font;
} FrameT;
extern uint8_t __MAGIC_FRAME; // Magic ID assigned to us from the GUI.
FrameT *frameCreate(char *title, int16_t width, int16_t height, int flags, ...);
RegisterT *frameRegister(uint8_t magic);
#endif // FRAME_H

View file

@ -69,13 +69,12 @@ static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event,
return;
}
/*
// Clicking left of thumb? Also fakes dragging.
if (x < h->thumb.x) {
// Move content left.
h->value -= SCROLL_SPEED_FAST;
// Clip.
if (h->value < h->min) h->value = h->min;
if (h->value < 0) h->value = 0;
// Update.
widgetDirtySet(widget, 1);
// Call the actual click event.
@ -88,14 +87,13 @@ static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event,
// Move content right.
h->value += SCROLL_SPEED_FAST;
// Clip.
if (h->value > h->max - h->base.r.w) h->value = h->max - h->base.r.w;
if (h->value > h->maxValue) h->value = h->maxValue;
// Update.
widgetDirtySet(widget, 1);
// Call the actual click event.
if (h->handler) h->handler(widget, x, y, event, h->base.data);
return;
}
*/
}

View file

@ -69,13 +69,12 @@ static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event,
return;
}
/*
// Clicking above thumb? Also fakes dragging.
if (y < v->thumb.y) {
// Move content up.
v->value -= SCROLL_SPEED_FAST;
// Clip.
if (v->value < v->min) v->value = v->min;
if (v->value < 0) v->value = 0;
// Update.
widgetDirtySet(widget, 1);
// Call the actual click event.
@ -88,14 +87,13 @@ static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event,
// Move content down.
v->value += SCROLL_SPEED_FAST;
// Clip.
if (v->value > v->max - v->base.r.h) v->value = v->max - v->base.r.h;
if (v->value > v->maxValue) v->value = v->maxValue;
// Update.
widgetDirtySet(widget, 1);
// Call the actual click event.
if (v->handler) v->handler(widget, x, y, event, v->base.data);
return;
}
*/
}

View file

@ -639,6 +639,7 @@ static WidgetT *windowWidgetFinder(WidgetT *widget, uint16_t x, uint16_t y, int1
br.x = *localX;
br.y = *localY;
w = w->reg->findWidget(w, br.x, br.y, localX, localY);
if (w) logWrite("Over %s\n", w->reg->widgetName);
return w;
}
}
@ -902,10 +903,8 @@ void wmUpdate(EventT *event) {
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?
widget = windowWidgetFinder(W(win), event->x, event->y, &widgetLocal.x, &widgetLocal.y);
// Send to widget for processing or send cancel.
if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, widgetLocal.x, widgetLocal.y, (widget == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data);
// Are we stll over the same widget? Send to widget for processing or send cancel.
if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, widgetLocal.x, widgetLocal.y, (widgetOver == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data);
}
widgetDown = NULL;
} // widgetDown

View file

@ -26,16 +26,6 @@
#include "gui/gui-all.h"
VscrollT *_v = NULL;
HscrollT *_h = NULL;
void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
(void)widget;
logWrite("%d %dx%d %s %d %d\n", event, x, y, data, vscrollValueGet(_v), hscrollValueGet(_h));
}
int main(int argc, char *argv[]) {
char title[256];
uint16_t i;
@ -44,11 +34,10 @@ int main(int argc, char *argv[]) {
ButtonT *b = NULL;
CheckboxT *c = NULL;
RadioT *r = NULL;
ScrollableT *s = NULL;
FrameT *f = NULL;
// frame
// scrollarea
// layout
// listbox
// textbox
@ -72,15 +61,25 @@ int main(int argc, char *argv[]) {
l = labelCreate(LABEL_ALIGN_LEFT, __guiFontVGA8x16, "Label");
labelColorSet(l, __guiBaseColors[i], GUI_BLACK);
labelClickSet(l, clickHandler, title);
widgetAdd(W(w), 20, 10, W(l));
b = buttonCreate("Button", clickHandler, NULL);
b = buttonCreate("Button", NULL, NULL);
widgetAdd(W(w), 20, 40, W(b));
c = checkboxCreate("Checkbox", 0);
widgetAdd(W(w), 20, 80, W(c));
f = frameCreate("Frame", 310, 60, FRAME_SINGLE);
widgetAdd(W(w), 20, 110, W(f));
r = radioCreate("Radio 1", 0, 1);
widgetAdd(W(f), 0, 5, W(r));
r = radioCreate("Radio 2", 0, 0);
widgetAdd(W(f), 100, 5, W(r));
r = radioCreate("Radio 3", 0, 0);
widgetAdd(W(f), 200, 5, W(r));
/*
r = radioCreate("Radio 1", 0, 1);
widgetAdd(W(w), 20, 110, W(r));
r = radioCreate("Radio 2", 0, 0);
@ -94,17 +93,7 @@ int main(int argc, char *argv[]) {
widgetAdd(W(w), 120, 140, W(r));
r = radioCreate("Radio C", 1, 0);
widgetAdd(W(w), 220, 140, W(r));
_v = vscrollCreate(100, clickHandler, NULL);
vscrollRangeSet(_v, 0, 640);
widgetAdd(W(w), 200, 5, W(_v));
_h = hscrollCreate(100, clickHandler, NULL);
hscrollRangeSet(_h, 0, 640);
widgetAdd(W(w), 100, 5, W(_h));
s = scrollableCreate(300, 200, 648, 480, SCROLLABLE_STANDARD);
widgetAdd(W(w), 20, 170, W(s));
*/
}
guiRun();
guiShutdown();