Scrollbar widgets and raw mouse handling for widgets.
This commit is contained in:
parent
b5eec0431d
commit
93b29de643
18 changed files with 1064 additions and 104 deletions
|
@ -49,6 +49,7 @@ HEADERS += \
|
||||||
$$SHARED/log.h \
|
$$SHARED/log.h \
|
||||||
$$SHARED/util.h \
|
$$SHARED/util.h \
|
||||||
src/gui/font.h \
|
src/gui/font.h \
|
||||||
|
src/gui/gui-all.h \
|
||||||
src/gui/gui.h \
|
src/gui/gui.h \
|
||||||
src/gui/image.h \
|
src/gui/image.h \
|
||||||
src/gui/surface.h \
|
src/gui/surface.h \
|
||||||
|
@ -56,6 +57,9 @@ HEADERS += \
|
||||||
src/gui/widgets/checkbox.h \
|
src/gui/widgets/checkbox.h \
|
||||||
src/gui/widgets/label.h \
|
src/gui/widgets/label.h \
|
||||||
src/gui/widgets/picture.h \
|
src/gui/widgets/picture.h \
|
||||||
|
src/gui/widgets/radio.h \
|
||||||
|
src/gui/widgets/hscroll.h \
|
||||||
|
src/gui/widgets/vscroll.h \
|
||||||
src/gui/wmwindow.h \
|
src/gui/wmwindow.h \
|
||||||
src/os.h \
|
src/os.h \
|
||||||
src/platform/platform.h \
|
src/platform/platform.h \
|
||||||
|
@ -75,6 +79,9 @@ SOURCES += \
|
||||||
src/gui/widgets/checkbox.c \
|
src/gui/widgets/checkbox.c \
|
||||||
src/gui/widgets/label.c \
|
src/gui/widgets/label.c \
|
||||||
src/gui/widgets/picture.c \
|
src/gui/widgets/picture.c \
|
||||||
|
src/gui/widgets/radio.c \
|
||||||
|
src/gui/widgets/hscroll.c \
|
||||||
|
src/gui/widgets/vscroll.c \
|
||||||
src/gui/wmwindow.c \
|
src/gui/wmwindow.c \
|
||||||
src/main.c \
|
src/main.c \
|
||||||
src/platform/djgpp.c \
|
src/platform/djgpp.c \
|
||||||
|
|
43
roo-e/src/gui/gui-all.h
Normal file
43
roo-e/src/gui/gui-all.h
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 GUIALL_H
|
||||||
|
#define GUIALL_H
|
||||||
|
|
||||||
|
|
||||||
|
// All headers for standard Roo/E features.
|
||||||
|
|
||||||
|
#include "gui.h"
|
||||||
|
#include "wmwindow.h"
|
||||||
|
#include "widgets/label.h"
|
||||||
|
#include "widgets/picture.h"
|
||||||
|
#include "widgets/button.h"
|
||||||
|
#include "widgets/checkbox.h"
|
||||||
|
#include "widgets/radio.h"
|
||||||
|
#include "widgets/vscroll.h"
|
||||||
|
#include "widgets/hscroll.h"
|
||||||
|
|
||||||
|
|
||||||
|
#endif // GUIALL_H
|
|
@ -23,16 +23,12 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gui.h"
|
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "array.h"
|
#include "array.h"
|
||||||
|
|
||||||
#include "wmwindow.h"
|
#include "../gui/gui.h"
|
||||||
#include "widgets/button.h"
|
#include "../gui/gui-all.h"
|
||||||
#include "widgets/checkbox.h"
|
|
||||||
#include "widgets/label.h"
|
|
||||||
#include "widgets/picture.h"
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct WidgetCatalogS {
|
typedef struct WidgetCatalogS {
|
||||||
|
@ -200,6 +196,9 @@ uint8_t guiStartup(int16_t width, int16_t height, int16_t depth) {
|
||||||
guiRegister(buttonRegister);
|
guiRegister(buttonRegister);
|
||||||
guiRegister(checkboxRegister);
|
guiRegister(checkboxRegister);
|
||||||
guiRegister(pictureRegister);
|
guiRegister(pictureRegister);
|
||||||
|
guiRegister(radioRegister);
|
||||||
|
guiRegister(vscrollRegister);
|
||||||
|
guiRegister(hscrollRegister);
|
||||||
|
|
||||||
return SUCCESS;
|
return SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -210,7 +209,7 @@ void guiStop(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h) {
|
void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h) {
|
||||||
widget->magic = magic;
|
widget->magic = magic;
|
||||||
|
|
||||||
widget->r.w = w;
|
widget->r.w = w;
|
||||||
|
@ -222,18 +221,18 @@ void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void guiWidgetDestroy(WidgetT *widget) {
|
void widgetDestroy(WidgetT *widget) {
|
||||||
// Add to list of widgets to delete.
|
// Add to list of widgets to delete.
|
||||||
arrput(_deleteList, widget);
|
arrput(_deleteList, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t guiWidgetDirtyGet(WidgetT *widget) {
|
uint8_t widgetDirtyGet(WidgetT *widget) {
|
||||||
return (widget->flags & WIDGET_DIRTY) != 0;
|
return (widget->flags & WIDGET_DIRTY) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void guiWidgetDirtySet(WidgetT *widget, uint8_t dirty) {
|
void widgetDirtySet(WidgetT *widget, uint8_t dirty) {
|
||||||
if (dirty) {
|
if (dirty) {
|
||||||
widget->flags |= WIDGET_DIRTY;
|
widget->flags |= WIDGET_DIRTY;
|
||||||
} else {
|
} else {
|
||||||
|
@ -242,10 +241,24 @@ void guiWidgetDirtySet(WidgetT *widget, uint8_t dirty) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void guiWidgetPaintManually(WidgetT *widget, int16_t x, int16_t y) {
|
void widgetInputSetRaw(WidgetT *widget, uint8_t raw) {
|
||||||
|
if (raw) {
|
||||||
|
widget->flags |= WIDGET_RAW_INPUT;
|
||||||
|
} else {
|
||||||
|
widget->flags &= ~WIDGET_RAW_INPUT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t widgetIsInWindow(WidgetT *widget, struct WindowS *window) {
|
||||||
|
return widget->parent == window;;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y) {
|
||||||
RectT r = widget->r;
|
RectT r = widget->r;
|
||||||
|
|
||||||
guiWidgetDirtySet(widget, 1);
|
widgetDirtySet(widget, 1);
|
||||||
widget->r.x = x;
|
widget->r.x = x;
|
||||||
widget->r.y = y;
|
widget->r.y = y;
|
||||||
widget->reg->paint(widget);
|
widget->reg->paint(widget);
|
||||||
|
|
|
@ -35,10 +35,12 @@
|
||||||
#define WIDGET_DIRTY 1
|
#define WIDGET_DIRTY 1
|
||||||
#define WIDGET_HIDDEN 2
|
#define WIDGET_HIDDEN 2
|
||||||
#define WIDGET_DISABLED 4
|
#define WIDGET_DISABLED 4
|
||||||
|
#define WIDGET_RAW_INPUT 8
|
||||||
|
|
||||||
#define CLICK_LEFT_CANCEL 1
|
#define CLICK_RAW_INPUT 1
|
||||||
#define CLICK_LEFT_DOWN 2
|
#define CLICK_LEFT_CANCEL 2
|
||||||
#define CLICK_LEFT_UP 3
|
#define CLICK_LEFT_DOWN 3
|
||||||
|
#define CLICK_LEFT_UP 4
|
||||||
|
|
||||||
|
|
||||||
struct WidgetS;
|
struct WidgetS;
|
||||||
|
@ -80,8 +82,14 @@ typedef struct WidgetS {
|
||||||
RegisterT *reg; // Registration information.
|
RegisterT *reg; // Registration information.
|
||||||
void *data; // Pointer to arbitrary data for user.
|
void *data; // Pointer to arbitrary data for user.
|
||||||
uint8_t flags; // Widget flags (see defines above).
|
uint8_t flags; // Widget flags (see defines above).
|
||||||
|
struct WindowS *parent; // Who owns this widget?
|
||||||
} WidgetT;
|
} WidgetT;
|
||||||
|
|
||||||
|
typedef struct ClickRawInputS {
|
||||||
|
void *data;
|
||||||
|
EventT *event;
|
||||||
|
} ClickRawInputT;
|
||||||
|
|
||||||
typedef RegisterT *(*WidgetRegisterT)(uint8_t);
|
typedef RegisterT *(*WidgetRegisterT)(uint8_t);
|
||||||
|
|
||||||
|
|
||||||
|
@ -128,11 +136,14 @@ void guiRun(void);
|
||||||
void guiShutdown(void);
|
void guiShutdown(void);
|
||||||
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth);
|
uint8_t guiStartup(int16_t width, int16_t height, int16_t depth);
|
||||||
void guiStop(void);
|
void guiStop(void);
|
||||||
void guiWidgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h);
|
|
||||||
void guiWidgetDestroy(WidgetT *widget);
|
void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h);
|
||||||
uint8_t guiWidgetDirtyGet(WidgetT *widget);
|
void widgetDestroy(WidgetT *widget);
|
||||||
void guiWidgetDirtySet(WidgetT *widget, uint8_t dirty);
|
uint8_t widgetDirtyGet(WidgetT *widget);
|
||||||
void guiWidgetPaintManually(WidgetT *widget, int16_t x, int16_t y);
|
void widgetDirtySet(WidgetT *widget, uint8_t dirty);
|
||||||
|
void widgetInputSetRaw(WidgetT *widget, uint8_t raw);
|
||||||
|
uint8_t widgetIsInWindow(WidgetT *widget, struct WindowS *window);
|
||||||
|
void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y);
|
||||||
|
|
||||||
|
|
||||||
#endif // GUI_H
|
#endif // GUI_H
|
||||||
|
|
|
@ -55,7 +55,7 @@ static void buttonClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
guiWidgetDirtySet(widget, 1);
|
widgetDirtySet(widget, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -85,7 +85,7 @@ ButtonT *buttonCreate(char *label, ClickHandlerT handler, void *data, ...) {
|
||||||
width = fontWidthCharactersGet(label) * fontWidthGet(f) + (b->offset.x * 2);
|
width = fontWidthCharactersGet(label) * fontWidthGet(f) + (b->offset.x * 2);
|
||||||
height = fontHeightGet(f) + (b->offset.y * 2);
|
height = fontHeightGet(f) + (b->offset.y * 2);
|
||||||
|
|
||||||
guiWidgetBaseSet(W(b), __MAGIC_BUTTON, width, height);
|
widgetBaseSet(W(b), __MAGIC_BUTTON, width, height);
|
||||||
|
|
||||||
buttonClickSet(b, handler, data);
|
buttonClickSet(b, handler, data);
|
||||||
|
|
||||||
|
@ -96,7 +96,7 @@ ButtonT *buttonCreate(char *label, ClickHandlerT handler, void *data, ...) {
|
||||||
static void buttonDestroy(struct WidgetS *widget, ...) {
|
static void buttonDestroy(struct WidgetS *widget, ...) {
|
||||||
ButtonT *b = (ButtonT *)widget;
|
ButtonT *b = (ButtonT *)widget;
|
||||||
|
|
||||||
guiWidgetDestroy(W(b->label));
|
widgetDestroy(W(b->label));
|
||||||
DEL(b);
|
DEL(b);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,14 +106,14 @@ static void buttonPaint(struct WidgetS *widget, ...) {
|
||||||
ColorT h = b->isPressed ? GUI_BLACK : GUI_WHITE;
|
ColorT h = b->isPressed ? GUI_BLACK : GUI_WHITE;
|
||||||
ColorT s = b->isPressed ? GUI_WHITE : GUI_BLACK;
|
ColorT s = b->isPressed ? GUI_WHITE : GUI_BLACK;
|
||||||
|
|
||||||
if (guiWidgetDirtyGet(widget)) {
|
if (widgetDirtyGet(widget)) {
|
||||||
guiWidgetDirtySet(widget, 0);
|
widgetDirtySet(widget, 0);
|
||||||
// Paint button.
|
// Paint button.
|
||||||
surfaceBoxHighlight(b->base.r.x, b->base.r.y, b->base.r.x + b->base.r.x2 - 1, b->base.r.y + b->base.r.y2 - 1, h, s);
|
surfaceBoxHighlight(b->base.r.x, b->base.r.y, b->base.r.x + b->base.r.x2 - 1, b->base.r.y + b->base.r.y2 - 1, h, s);
|
||||||
surfaceBoxHighlight(b->base.r.x + 1, b->base.r.y + 1, b->base.r.x + b->base.r.x2 - 2, b->base.r.y + b->base.r.y2 - 2, h, s);
|
surfaceBoxHighlight(b->base.r.x + 1, b->base.r.y + 1, b->base.r.x + b->base.r.x2 - 2, b->base.r.y + b->base.r.y2 - 2, h, s);
|
||||||
surfaceBoxFilled(b->base.r.x + 2, b->base.r.y + 2, b->base.r.x + b->base.r.x2 - 3, b->base.r.y + b->base.r.y2 - 3, GUI_LIGHTGRAY);
|
surfaceBoxFilled(b->base.r.x + 2, b->base.r.y + 2, b->base.r.x + b->base.r.x2 - 3, b->base.r.y + b->base.r.y2 - 3, GUI_LIGHTGRAY);
|
||||||
// Paint label.
|
// Paint label.
|
||||||
guiWidgetPaintManually(W(b->label), b->base.r.x + b->offset.x + b->isPressed, b->base.r.y + b->offset.y + b->isPressed);
|
widgetPaintManually(W(b->label), b->base.r.x + b->offset.x + b->isPressed, b->base.r.y + b->offset.y + b->isPressed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,7 +47,7 @@ static void checkboxClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event
|
||||||
if (c->handler) c->handler(widget, x, y, event, data);
|
if (c->handler) c->handler(widget, x, y, event, data);
|
||||||
|
|
||||||
// Repaint.
|
// Repaint.
|
||||||
guiWidgetDirtySet(widget, 1);
|
widgetDirtySet(widget, 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,7 +78,7 @@ CheckboxT *checkboxCreate(char *label, uint8_t value, ...) {
|
||||||
height = fontHeightGet(f);
|
height = fontHeightGet(f);
|
||||||
width = fontWidthCharactersGet(label) * fontWidthGet(f) + (height * 3);
|
width = fontWidthCharactersGet(label) * fontWidthGet(f) + (height * 3);
|
||||||
|
|
||||||
guiWidgetBaseSet(W(c), __MAGIC_CHECKBOX, width, height);
|
widgetBaseSet(W(c), __MAGIC_CHECKBOX, width, height);
|
||||||
|
|
||||||
return c;
|
return c;
|
||||||
}
|
}
|
||||||
|
@ -87,7 +87,7 @@ CheckboxT *checkboxCreate(char *label, uint8_t value, ...) {
|
||||||
static void checkboxDestroy(struct WidgetS *widget, ...) {
|
static void checkboxDestroy(struct WidgetS *widget, ...) {
|
||||||
CheckboxT *c = (CheckboxT *)widget;
|
CheckboxT *c = (CheckboxT *)widget;
|
||||||
|
|
||||||
guiWidgetDestroy(W(c->label));
|
widgetDestroy(W(c->label));
|
||||||
DEL(c);
|
DEL(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,15 +97,15 @@ static void checkboxPaint(struct WidgetS *widget, ...) {
|
||||||
int16_t w;
|
int16_t w;
|
||||||
int16_t h;
|
int16_t h;
|
||||||
|
|
||||||
if (guiWidgetDirtyGet(widget)) {
|
if (widgetDirtyGet(widget)) {
|
||||||
guiWidgetDirtySet(widget, 0);
|
widgetDirtySet(widget, 0);
|
||||||
h = fontHeightGet(c->label->font) - 2;
|
h = fontHeightGet(c->label->font) - 2;
|
||||||
w = h * 1.5;
|
w = h * 1.5;
|
||||||
// Paint checkbox.
|
// Paint checkbox.
|
||||||
surfaceBoxHighlight(c->base.r.x, c->base.r.y + 1, c->base.r.x + h, c->base.r.y + h, GUI_BLACK, GUI_WHITE);
|
surfaceBoxHighlight(c->base.r.x, c->base.r.y + 1, c->base.r.x + h, c->base.r.y + h, c->value ? GUI_BLACK : GUI_WHITE, c->value ? GUI_WHITE : GUI_BLACK);
|
||||||
surfaceBoxFilled(c->base.r.x + 1, c->base.r.y + 2, c->base.r.x + h - 1, c->base.r.y + h - 1, c->value ? GUI_DARKGRAY : GUI_WHITE);
|
surfaceBoxFilled(c->base.r.x + 1, c->base.r.y + 2, c->base.r.x + h - 1, c->base.r.y + h - 1, c->value ? GUI_DARKGRAY : GUI_WHITE);
|
||||||
// Paint label.
|
// Paint label.
|
||||||
guiWidgetPaintManually(W(c->label), c->base.r.x + w, c->base.r.y);
|
widgetPaintManually(W(c->label), c->base.r.x + w, c->base.r.y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,5 +134,5 @@ uint8_t checkboxValueGet(CheckboxT *checkbox) {
|
||||||
void checkboxValueSet(CheckboxT *checkbox, uint8_t value) {
|
void checkboxValueSet(CheckboxT *checkbox, uint8_t value) {
|
||||||
checkbox->value = (value != 0);
|
checkbox->value = (value != 0);
|
||||||
// Repaint.
|
// Repaint.
|
||||||
guiWidgetDirtySet(W(checkbox), 1);
|
widgetDirtySet(W(checkbox), 1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,7 +35,7 @@ typedef struct CheckboxS {
|
||||||
WidgetT base; // Required by all widgets.
|
WidgetT base; // Required by all widgets.
|
||||||
LabelT *label; // Label to display text.
|
LabelT *label; // Label to display text.
|
||||||
ClickHandlerT handler; // Actual event handler.
|
ClickHandlerT handler; // Actual event handler.
|
||||||
uint8_t value; // Is the button being pressed?
|
uint8_t value; // Is theis checkbox selected?
|
||||||
} CheckboxT;
|
} CheckboxT;
|
||||||
|
|
||||||
|
|
||||||
|
|
232
roo-e/src/gui/widgets/hscroll.c
Normal file
232
roo-e/src/gui/widgets/hscroll.c
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* 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 "../wmwindow.h"
|
||||||
|
#include "../font.h"
|
||||||
|
|
||||||
|
#include "hscroll.h"
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t __MAGIC_HSCROLL = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
|
||||||
|
static void hscrollDestroy(struct WidgetS *widget, ...);
|
||||||
|
static void hscrollPaint(struct WidgetS *widget, ...);
|
||||||
|
|
||||||
|
|
||||||
|
static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
||||||
|
HscrollT *h = (HscrollT *)widget;
|
||||||
|
|
||||||
|
// Clicking in left arrow?
|
||||||
|
if (x <= GADGET_SIZE) {
|
||||||
|
// Move content left.
|
||||||
|
h->value -= SCROLL_SPEED_SLOW;
|
||||||
|
// Clip.
|
||||||
|
if (h->value < h->min) h->value = h->min;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (h->handler) h->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicking in right arrow?
|
||||||
|
if (x >= h->base.r.w - GADGET_SIZE) {
|
||||||
|
// Move content right.
|
||||||
|
h->value += SCROLL_SPEED_SLOW;
|
||||||
|
// Clip.
|
||||||
|
if (h->value > h->max - h->base.r.w) h->value = h->max - h->base.r.w;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (h->handler) h->handler(widget, x, y, event, data);
|
||||||
|
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;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (h->handler) h->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicking right of thumb? Also fakes dragging.
|
||||||
|
if (x > h->thumb.x2) {
|
||||||
|
// 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;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (h->handler) h->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hscrollClickSet(HscrollT *hscroll, ClickHandlerT handler, void *data) {
|
||||||
|
hscroll->handler = handler;
|
||||||
|
hscroll->base.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
HscrollT *hscrollCreate(int16_t w, ClickHandlerT handler, void *data, ...) {
|
||||||
|
HscrollT *h = NULL;
|
||||||
|
|
||||||
|
NEW(HscrollT, h);
|
||||||
|
memset(h, 0, sizeof(HscrollT));
|
||||||
|
|
||||||
|
h->min = 1;
|
||||||
|
h->max = 100;
|
||||||
|
h->value = 1;
|
||||||
|
|
||||||
|
if (w < GADGET_SIZE * 3) w = GADGET_SIZE * 3;
|
||||||
|
|
||||||
|
widgetBaseSet(W(h), __MAGIC_HSCROLL, w, GADGET_SIZE);
|
||||||
|
|
||||||
|
h->handler = handler;
|
||||||
|
h->base.data = data;
|
||||||
|
|
||||||
|
widgetInputSetRaw(W(h), 1);
|
||||||
|
|
||||||
|
return h;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hscrollDestroy(struct WidgetS *widget, ...) {
|
||||||
|
HscrollT *h = (HscrollT *)widget;
|
||||||
|
|
||||||
|
DEL(h);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hscrollPaint(struct WidgetS *widget, ...) {
|
||||||
|
HscrollT *h = (HscrollT *)widget;
|
||||||
|
ColorT scrollBackgroundColor;
|
||||||
|
ColorT widgetColor;
|
||||||
|
RectT r;
|
||||||
|
int16_t i;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
if (widgetDirtyGet(widget)) {
|
||||||
|
widgetDirtySet(widget, 0);
|
||||||
|
// Find some colors.
|
||||||
|
if (widgetIsInWindow(widget, wmWindowOnTopGet())) {
|
||||||
|
scrollBackgroundColor = GUI_DARKGRAY;
|
||||||
|
widgetColor = GUI_LIGHTGRAY;
|
||||||
|
} else {
|
||||||
|
scrollBackgroundColor = GUI_LIGHTGRAY;
|
||||||
|
widgetColor = GUI_DARKGRAY;
|
||||||
|
}
|
||||||
|
// Find coordinates.
|
||||||
|
r = h->base.r;
|
||||||
|
r.x2 = r.x + h->base.r.w - 1;
|
||||||
|
r.y2 = r.y + h->base.r.h - 1;
|
||||||
|
// Paint scrollbar.
|
||||||
|
surfaceBoxFilled(r.x + 1, r.y + 1, r.x2 - 1, r.y2 - 1, scrollBackgroundColor);
|
||||||
|
surfaceBoxHighlight(r.x, r.y, r.x2, r.y2, GUI_WHITE, GUI_BLACK);
|
||||||
|
surfaceLineV(r.x + (GADGET_SIZE - 1), r.y + 1, r.y2, GUI_BLACK);
|
||||||
|
surfaceLineV(r.x2 - (GADGET_SIZE - 1), r.y + 1, r.y2, GUI_WHITE);
|
||||||
|
// Prepare font.
|
||||||
|
fontSet(__guiFontVGA8x8);
|
||||||
|
fontColorSet(widgetColor, scrollBackgroundColor);
|
||||||
|
// ***TODO***
|
||||||
|
/*
|
||||||
|
// If we have both horizontal and vertical scroll bars, we need to fix a shadow.
|
||||||
|
if (w->flags & WIN_SCROLL_V) {
|
||||||
|
surfaceLineV(w->scrollh.x2 - 1, w->scrollh.y, w->scrollh.y2, GUI_BLACK);
|
||||||
|
surfaceLineV(w->scrollh.x2, w->scrollh.y, w->scrollh.y2, GUI_WHITE);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Draw arrows.
|
||||||
|
fontRender("\x11", r.x + 7, r.y + 7);
|
||||||
|
fontRender("\x10", r.x2 - 12, r.y + 7);
|
||||||
|
// Distance between arrow buttons on scroll bar.
|
||||||
|
i = r.x2 - r.x - (GADGET_SIZE * 2 - 2) - 2;
|
||||||
|
// Percentage to scale content height to scroll bar height.
|
||||||
|
d = (double)i / (double)(h->max - h->min);
|
||||||
|
// Find position and size of thumb.
|
||||||
|
h->thumb.x = r.x + GADGET_SIZE + (h->value * d);
|
||||||
|
h->thumb.x2 = h->thumb.x + (h->base.r.w * d);
|
||||||
|
h->thumb.y = r.y + 1;
|
||||||
|
h->thumb.y2 = r.y2 - 1;
|
||||||
|
// Clamp overflow due to doubles and my off-by-one brain.
|
||||||
|
if (h->thumb.x2 >= h->thumb.x + i - 1) h->thumb.x2 = h->thumb.x + i - 1;
|
||||||
|
// Draw thumb.
|
||||||
|
surfaceBoxFilled(h->thumb.x + 1, h->thumb.y + 1, h->thumb.x2 - 1, h->thumb.y2 - 1, GUI_LIGHTGRAY);
|
||||||
|
surfaceBoxHighlight(h->thumb.x, h->thumb.y, h->thumb.x2, h->thumb.y2, GUI_WHITE, GUI_BLACK);
|
||||||
|
// Adjust thumb values from window space to widget space for click handler.
|
||||||
|
h->thumb.x -= h->base.r.x;
|
||||||
|
h->thumb.x2 -= h->base.r.x;
|
||||||
|
h->thumb.y -= h->base.r.y;
|
||||||
|
h->thumb.y2 -= h->base.r.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hscrollRangeSet(HscrollT *hscroll, int32_t min, int32_t max) {
|
||||||
|
hscroll->min = min;
|
||||||
|
hscroll->max = max;
|
||||||
|
widgetDirtySet(W(hscroll), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegisterT *hscrollRegister(uint8_t magic) {
|
||||||
|
static RegisterT reg = {
|
||||||
|
"Hscroll",
|
||||||
|
hscrollClick,
|
||||||
|
hscrollDestroy,
|
||||||
|
hscrollPaint,
|
||||||
|
NULL // No unregister handler.
|
||||||
|
};
|
||||||
|
|
||||||
|
// One-time widget startup code.
|
||||||
|
__MAGIC_HSCROLL = magic;
|
||||||
|
|
||||||
|
return ®
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t hscrollValueGet(HscrollT *hscroll) {
|
||||||
|
return hscroll->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void hscrollValueSet(HscrollT *hscroll, int32_t value) {
|
||||||
|
if (value < hscroll->min) value = hscroll->min;
|
||||||
|
if (value > hscroll->max) value = hscroll->max;
|
||||||
|
if (hscroll->value != value) {
|
||||||
|
hscroll->value = value;
|
||||||
|
widgetDirtySet(W(hscroll), 1);
|
||||||
|
}
|
||||||
|
}
|
54
roo-e/src/gui/widgets/hscroll.h
Normal file
54
roo-e/src/gui/widgets/hscroll.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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 HSCROLL_H
|
||||||
|
#define HSCROLL_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "../gui.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct HscrollS {
|
||||||
|
WidgetT base; // Required by all widgets.
|
||||||
|
int32_t min;
|
||||||
|
int32_t max;
|
||||||
|
int32_t value;
|
||||||
|
RectT thumb;
|
||||||
|
ClickHandlerT handler; // Actual event handler.
|
||||||
|
} HscrollT;
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t __MAGIC_HSCROLL; // Magic ID assigned to us from the GUI.
|
||||||
|
|
||||||
|
|
||||||
|
void hscrollClickSet(HscrollT *hscroll, ClickHandlerT handler, void *data);
|
||||||
|
HscrollT *hscrollCreate(int16_t w, ClickHandlerT handler, void *data, ...);
|
||||||
|
void hscrollRangeSet(HscrollT *hscroll, int32_t min, int32_t max);
|
||||||
|
RegisterT *hscrollRegister(uint8_t magic);
|
||||||
|
int32_t hscrollValueGet(HscrollT *hscroll);
|
||||||
|
void hscrollValueSet(HscrollT *hscroll, int32_t value);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // HSCROLL_H
|
|
@ -42,7 +42,7 @@ void labelClickSet(LabelT *label, ClickHandlerT handler, void *data) {
|
||||||
void labelColorSet(LabelT *label, ColorT foreground, ColorT background) {
|
void labelColorSet(LabelT *label, ColorT foreground, ColorT background) {
|
||||||
label->foreground = foreground;
|
label->foreground = foreground;
|
||||||
label->background = background;
|
label->background = background;
|
||||||
guiWidgetDirtySet(W(label), 1);
|
widgetDirtySet(W(label), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ void labelContentSet(LabelT *label, char *content) {
|
||||||
label->base.r.y = y;
|
label->base.r.y = y;
|
||||||
|
|
||||||
// Fixup width and height.
|
// Fixup width and height.
|
||||||
guiWidgetBaseSet(W(label), __MAGIC_LABEL, width, height);
|
widgetBaseSet(W(label), __MAGIC_LABEL, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ LabelT *labelCreate(uint8_t alignment, FontT *font, char *contents, ...) {
|
||||||
l->text = strdup(contents);
|
l->text = strdup(contents);
|
||||||
l->pos.x = -1; // Flag for later indicating we need to set up the widget position.
|
l->pos.x = -1; // Flag for later indicating we need to set up the widget position.
|
||||||
|
|
||||||
guiWidgetBaseSet(W(l), __MAGIC_LABEL, 0, 0);
|
widgetBaseSet(W(l), __MAGIC_LABEL, 0, 0);
|
||||||
|
|
||||||
return l;
|
return l;
|
||||||
}
|
}
|
||||||
|
@ -127,8 +127,8 @@ static void labelPaint(struct WidgetS *widget, ...) {
|
||||||
DEL(temp);
|
DEL(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (guiWidgetDirtyGet(widget)) {
|
if (widgetDirtyGet(widget)) {
|
||||||
guiWidgetDirtySet(widget, 0);
|
widgetDirtySet(widget, 0);
|
||||||
fontSet(l->font);
|
fontSet(l->font);
|
||||||
fontColorSet(l->foreground, l->background);
|
fontColorSet(l->foreground, l->background);
|
||||||
fontModsEnabledSet(l->modsEnabled);
|
fontModsEnabledSet(l->modsEnabled);
|
||||||
|
|
|
@ -51,7 +51,7 @@ PictureT *pictureCreate(char *filename, ...) {
|
||||||
DEL(p);
|
DEL(p);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
guiWidgetBaseSet(W(p), __MAGIC_PICTURE, surfaceWidthGet(p->picture), surfaceHeightGet(p->picture));
|
widgetBaseSet(W(p), __MAGIC_PICTURE, surfaceWidthGet(p->picture), surfaceHeightGet(p->picture));
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
@ -68,8 +68,8 @@ static void pictureDestroy(struct WidgetS *widget, ...) {
|
||||||
static void picturePaint(struct WidgetS *widget, ...) {
|
static void picturePaint(struct WidgetS *widget, ...) {
|
||||||
PictureT *p = (PictureT *)widget;
|
PictureT *p = (PictureT *)widget;
|
||||||
|
|
||||||
if (guiWidgetDirtyGet(widget)) {
|
if (widgetDirtyGet(widget)) {
|
||||||
guiWidgetDirtySet(widget, 0);
|
widgetDirtySet(widget, 0);
|
||||||
// ***TODO*** Clipping.
|
// ***TODO*** Clipping.
|
||||||
surfaceBlit(p->base.r.x, p->base.r.y, 0, 0, 0, 0, p->picture);
|
surfaceBlit(p->base.r.x, p->base.r.y, 0, 0, 0, 0, p->picture);
|
||||||
}
|
}
|
||||||
|
|
210
roo-e/src/gui/widgets/radio.c
Normal file
210
roo-e/src/gui/widgets/radio.c
Normal file
|
@ -0,0 +1,210 @@
|
||||||
|
/*
|
||||||
|
* 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 "../wmwindow.h"
|
||||||
|
#include "array.h"
|
||||||
|
|
||||||
|
#include "radio.h"
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t __MAGIC_RADIO = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void radioClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
|
||||||
|
static void radioDestroy(struct WidgetS *widget, ...);
|
||||||
|
static void radioPaint(struct WidgetS *widget, ...);
|
||||||
|
|
||||||
|
|
||||||
|
static void radioClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
||||||
|
RadioT *r = (RadioT *)widget;
|
||||||
|
|
||||||
|
if (event == CLICK_LEFT_UP) {
|
||||||
|
// Select this radio button.
|
||||||
|
radioValueSet(r, 1);
|
||||||
|
|
||||||
|
// Call the actual click event if it exists.
|
||||||
|
if (r->handler) r->handler(widget, x, y, event, data);
|
||||||
|
|
||||||
|
// Repaint.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void radioClickSet(RadioT *radio, ClickHandlerT handler, void *data) {
|
||||||
|
radio->handler = handler;
|
||||||
|
radio->base.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RadioT *radioCreate(char *label, uint8_t group, uint8_t value, ...) {
|
||||||
|
RadioT *r = NULL;
|
||||||
|
uint16_t width;
|
||||||
|
uint16_t height;
|
||||||
|
FontT *f = __guiFontVGA8x16;
|
||||||
|
|
||||||
|
NEW(RadioT, r);
|
||||||
|
memset(r, 0, sizeof(RadioT));
|
||||||
|
|
||||||
|
r->group = group;
|
||||||
|
r->value = value;
|
||||||
|
r->label = labelCreate(LABEL_ALIGN_LEFT, f, label);
|
||||||
|
if (!r->label) {
|
||||||
|
DEL(r);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Radio button is (height - 3) square. We skip two pixels on the bottom and one on the top to look okay with decender characters.
|
||||||
|
height = fontHeightGet(f);
|
||||||
|
width = fontWidthCharactersGet(label) * fontWidthGet(f) + (height * 3);
|
||||||
|
|
||||||
|
widgetBaseSet(W(r), __MAGIC_RADIO, width, height);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void radioDestroy(struct WidgetS *widget, ...) {
|
||||||
|
RadioT *r = (RadioT *)widget;
|
||||||
|
|
||||||
|
widgetDestroy(W(r->label));
|
||||||
|
DEL(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void radioPaint(struct WidgetS *widget, ...) {
|
||||||
|
RadioT *r = (RadioT *)widget;
|
||||||
|
int16_t w;
|
||||||
|
int16_t h;
|
||||||
|
int16_t y;
|
||||||
|
int16_t x;
|
||||||
|
int16_t d;
|
||||||
|
int16_t i;
|
||||||
|
int16_t change;
|
||||||
|
ColorT temp;
|
||||||
|
ColorT top;
|
||||||
|
ColorT bottom;
|
||||||
|
ColorT fill;
|
||||||
|
|
||||||
|
if (widgetDirtyGet(widget)) {
|
||||||
|
widgetDirtySet(widget, 0);
|
||||||
|
// Work out some coordinates.
|
||||||
|
h = fontHeightGet(r->label->font) - 2;
|
||||||
|
w = h * 1.5;
|
||||||
|
x = r->base.r.x + (h * 0.5); // X center coordinate.
|
||||||
|
change = r->base.r.y + (h * 0.5); // Where, vertically, we start drawing the bottom of the diamond.
|
||||||
|
d = 1; // Direction of increment.
|
||||||
|
i = 0; // X increment.
|
||||||
|
// Set up colors.
|
||||||
|
if (r->value) {
|
||||||
|
fill = GUI_DARKGRAY;
|
||||||
|
top = GUI_BLACK;
|
||||||
|
bottom = GUI_WHITE;
|
||||||
|
} else {
|
||||||
|
fill = GUI_WHITE;
|
||||||
|
top = GUI_WHITE;
|
||||||
|
bottom = GUI_BLACK;
|
||||||
|
}
|
||||||
|
// Paint radio button.
|
||||||
|
for (y=r->base.r.y + 1; y<=r->base.r.y + h - 1; y++) {
|
||||||
|
surfaceLineH(x - i, x + i, y, fill);
|
||||||
|
surfacePixelSet(x - i, y, top);
|
||||||
|
surfacePixelSet(x + i, y, top);
|
||||||
|
if (y == change) {
|
||||||
|
d = -d;
|
||||||
|
temp = top;
|
||||||
|
top = bottom;
|
||||||
|
bottom = temp;
|
||||||
|
}
|
||||||
|
i += d;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Paint label.
|
||||||
|
widgetPaintManually(W(r->label), r->base.r.x + w, r->base.r.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegisterT *radioRegister(uint8_t magic) {
|
||||||
|
static RegisterT reg = {
|
||||||
|
"Radio",
|
||||||
|
radioClick,
|
||||||
|
radioDestroy,
|
||||||
|
radioPaint,
|
||||||
|
NULL // No unregister handler.
|
||||||
|
};
|
||||||
|
|
||||||
|
// One-time widget startup code.
|
||||||
|
__MAGIC_RADIO = magic;
|
||||||
|
|
||||||
|
return ®
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t radioValueGet(RadioT *radio) {
|
||||||
|
return radio->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void radioValueSet(RadioT *radio, uint8_t value) {
|
||||||
|
int16_t i;
|
||||||
|
WindowT *p;
|
||||||
|
RadioT *r;
|
||||||
|
|
||||||
|
radio->value = (value != 0);
|
||||||
|
p = radio->base.parent;
|
||||||
|
if (radio->value) {
|
||||||
|
// We were selected, deselect other radio buttons in this group.
|
||||||
|
for (i=0; i<arrlen(p->children); i++) {
|
||||||
|
// Is this a radio button? Is it not us?
|
||||||
|
if (p->children[i]->magic == __MAGIC_RADIO && p->children[i] != W(radio)) {
|
||||||
|
r = (RadioT *)p->children[i];
|
||||||
|
// Is it currently selected?
|
||||||
|
if (r->value && r->group == radio->group) {
|
||||||
|
// Clear it and redraw.
|
||||||
|
r->value = 0;
|
||||||
|
widgetDirtySet(W(r), 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// We were cleared. Select another radio button in this group.
|
||||||
|
for (i=0; i<arrlen(p->children); i++) {
|
||||||
|
// Is this a radio button? Is it not us?
|
||||||
|
if (p->children[i]->magic == __MAGIC_RADIO && p->children[i] != W(radio)) {
|
||||||
|
r = (RadioT *)p->children[i];
|
||||||
|
if (r->group == radio->group) {
|
||||||
|
// Select it and redraw.
|
||||||
|
r->value = 1;
|
||||||
|
widgetDirtySet(W(r), 1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Repaint.
|
||||||
|
widgetDirtySet(W(radio), 1);
|
||||||
|
}
|
53
roo-e/src/gui/widgets/radio.h
Normal file
53
roo-e/src/gui/widgets/radio.h
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
/*
|
||||||
|
* 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 RADIO_H
|
||||||
|
#define RADIO_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "../gui.h"
|
||||||
|
#include "label.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct RadioS {
|
||||||
|
WidgetT base; // Required by all widgets.
|
||||||
|
LabelT *label; // Label to display text.
|
||||||
|
ClickHandlerT handler; // Actual event handler.
|
||||||
|
uint8_t value; // Is this radio button selected?
|
||||||
|
uint8_t group; // Which group does this radio button belong to?
|
||||||
|
} RadioT;
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t __MAGIC_RADIO; // Magic ID assigned to us from the GUI.
|
||||||
|
|
||||||
|
|
||||||
|
void radioClickSet(RadioT *radio, ClickHandlerT handler, void *data);
|
||||||
|
RadioT *radioCreate(char *label, uint8_t group, uint8_t value, ...);
|
||||||
|
RegisterT *radioRegister(uint8_t magic);
|
||||||
|
uint8_t radioValueGet(RadioT *radio);
|
||||||
|
void radioValueSet(RadioT *radio, uint8_t value);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // RADIO_H
|
224
roo-e/src/gui/widgets/vscroll.c
Normal file
224
roo-e/src/gui/widgets/vscroll.c
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
/*
|
||||||
|
* 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 "../wmwindow.h"
|
||||||
|
#include "../font.h"
|
||||||
|
|
||||||
|
#include "vscroll.h"
|
||||||
|
|
||||||
|
|
||||||
|
uint8_t __MAGIC_VSCROLL = 0;
|
||||||
|
|
||||||
|
|
||||||
|
static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
|
||||||
|
static void vscrollDestroy(struct WidgetS *widget, ...);
|
||||||
|
static void vscrollPaint(struct WidgetS *widget, ...);
|
||||||
|
|
||||||
|
|
||||||
|
static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
||||||
|
VscrollT *v = (VscrollT *)widget;
|
||||||
|
|
||||||
|
// Clicking in up arrow?
|
||||||
|
if (y <= GADGET_SIZE) {
|
||||||
|
// Move content up.
|
||||||
|
v->value -= SCROLL_SPEED_SLOW;
|
||||||
|
// Clip.
|
||||||
|
if (v->value < v->min) v->value = v->min;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (v->handler) v->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicking in down arrow?
|
||||||
|
if (y >= v->base.r.h - GADGET_SIZE) {
|
||||||
|
// Move content down.
|
||||||
|
v->value += SCROLL_SPEED_SLOW;
|
||||||
|
// Clip.
|
||||||
|
if (v->value > v->max - v->base.r.h) v->value = v->max - v->base.r.h;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (v->handler) v->handler(widget, x, y, event, data);
|
||||||
|
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;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (v->handler) v->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clicking below thumb? Also fakes dragging.
|
||||||
|
if (y > v->thumb.y2) {
|
||||||
|
// 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;
|
||||||
|
// Update.
|
||||||
|
widgetDirtySet(widget, 1);
|
||||||
|
// Call the actual click event.
|
||||||
|
if (v->handler) v->handler(widget, x, y, event, data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vscrollClickSet(VscrollT *vscroll, ClickHandlerT handler, void *data) {
|
||||||
|
vscroll->handler = handler;
|
||||||
|
vscroll->base.data = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VscrollT *vscrollCreate(int16_t h, ClickHandlerT handler, void *data, ...) {
|
||||||
|
VscrollT *v = NULL;
|
||||||
|
|
||||||
|
NEW(VscrollT, v);
|
||||||
|
memset(v, 0, sizeof(VscrollT));
|
||||||
|
|
||||||
|
v->min = 1;
|
||||||
|
v->max = 100;
|
||||||
|
v->value = 1;
|
||||||
|
|
||||||
|
if (h < GADGET_SIZE * 3) h = GADGET_SIZE * 3;
|
||||||
|
|
||||||
|
widgetBaseSet(W(v), __MAGIC_VSCROLL, GADGET_SIZE, h);
|
||||||
|
|
||||||
|
v->handler = handler;
|
||||||
|
v->base.data = data;
|
||||||
|
|
||||||
|
widgetInputSetRaw(W(v), 1);
|
||||||
|
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vscrollDestroy(struct WidgetS *widget, ...) {
|
||||||
|
VscrollT *v = (VscrollT *)widget;
|
||||||
|
|
||||||
|
DEL(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void vscrollPaint(struct WidgetS *widget, ...) {
|
||||||
|
VscrollT *v = (VscrollT *)widget;
|
||||||
|
ColorT scrollBackgroundColor;
|
||||||
|
ColorT widgetColor;
|
||||||
|
RectT r;
|
||||||
|
int16_t i;
|
||||||
|
double d;
|
||||||
|
|
||||||
|
if (widgetDirtyGet(widget)) {
|
||||||
|
widgetDirtySet(widget, 0);
|
||||||
|
// Find some colors.
|
||||||
|
if (widgetIsInWindow(widget, wmWindowOnTopGet())) {
|
||||||
|
scrollBackgroundColor = GUI_DARKGRAY;
|
||||||
|
widgetColor = GUI_LIGHTGRAY;
|
||||||
|
} else {
|
||||||
|
scrollBackgroundColor = GUI_LIGHTGRAY;
|
||||||
|
widgetColor = GUI_DARKGRAY;
|
||||||
|
}
|
||||||
|
// Find coordinates.
|
||||||
|
r = v->base.r;
|
||||||
|
r.x2 = r.x + v->base.r.w - 1;
|
||||||
|
r.y2 = r.y + v->base.r.h - 1;
|
||||||
|
// Paint scrollbar.
|
||||||
|
surfaceBoxFilled(r.x + 1, r.y + 1, r.x2 - 1, r.y2 - 1, scrollBackgroundColor);
|
||||||
|
surfaceBoxHighlight(r.x, r.y, r.x2, r.y2, GUI_WHITE, GUI_BLACK);
|
||||||
|
surfaceLineH(r.x + 1, r.x2, r.y + (GADGET_SIZE - 1), GUI_BLACK);
|
||||||
|
surfaceLineH(r.x + 1, r.x2, r.y2 - (GADGET_SIZE - 1), GUI_WHITE);
|
||||||
|
// Prepare font.
|
||||||
|
fontSet(__guiFontVGA8x8);
|
||||||
|
fontColorSet(widgetColor, scrollBackgroundColor);
|
||||||
|
// Draw arrows.
|
||||||
|
fontRender("\x1e", r.x + 7, r.y + 7);
|
||||||
|
fontRender("\x1f", r.x + 7, r.y2 - 12);
|
||||||
|
// Distance between arrow buttons on scroll bar.
|
||||||
|
i = r.y2 - r.y - (GADGET_SIZE * 2 - 2) - 2;
|
||||||
|
// Percentage to scale content height to scroll bar height.
|
||||||
|
d = (double)i / (double)(v->max - v->min);
|
||||||
|
// Find position and size of thumb.
|
||||||
|
v->thumb.x = r.x + 1;
|
||||||
|
v->thumb.x2 = r.x2 - 1;
|
||||||
|
v->thumb.y = r.y + GADGET_SIZE + (v->value * d);
|
||||||
|
v->thumb.y2 = v->thumb.y + (v->base.r.h * d);
|
||||||
|
// Clamp overflow due to doubles and my off-by-one brain.
|
||||||
|
if (v->thumb.y2 >= v->thumb.y + i - 1) v->thumb.y2 = v->thumb.y + i - 1;
|
||||||
|
// Draw thumb.
|
||||||
|
surfaceBoxFilled(v->thumb.x + 1, v->thumb.y + 1, v->thumb.x2 - 1, v->thumb.y2 - 1, GUI_LIGHTGRAY);
|
||||||
|
surfaceBoxHighlight(v->thumb.x, v->thumb.y, v->thumb.x2, v->thumb.y2, GUI_WHITE, GUI_BLACK);
|
||||||
|
// Adjust thumb values from window space to widget space for click handler.
|
||||||
|
v->thumb.x -= v->base.r.x;
|
||||||
|
v->thumb.x2 -= v->base.r.x;
|
||||||
|
v->thumb.y -= v->base.r.y;
|
||||||
|
v->thumb.y2 -= v->base.r.y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vscrollRangeSet(VscrollT *vscroll, int32_t min, int32_t max) {
|
||||||
|
vscroll->min = min;
|
||||||
|
vscroll->max = max;
|
||||||
|
widgetDirtySet(W(vscroll), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
RegisterT *vscrollRegister(uint8_t magic) {
|
||||||
|
static RegisterT reg = {
|
||||||
|
"Vscroll",
|
||||||
|
vscrollClick,
|
||||||
|
vscrollDestroy,
|
||||||
|
vscrollPaint,
|
||||||
|
NULL // No unregister handler.
|
||||||
|
};
|
||||||
|
|
||||||
|
// One-time widget startup code.
|
||||||
|
__MAGIC_VSCROLL = magic;
|
||||||
|
|
||||||
|
return ®
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t vscrollValueGet(VscrollT *vscroll) {
|
||||||
|
return vscroll->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void vscrollValueSet(VscrollT *vscroll, int32_t value) {
|
||||||
|
if (value < vscroll->min) value = vscroll->min;
|
||||||
|
if (value > vscroll->max) value = vscroll->max;
|
||||||
|
if (vscroll->value != value) {
|
||||||
|
vscroll->value = value;
|
||||||
|
widgetDirtySet(W(vscroll), 1);
|
||||||
|
}
|
||||||
|
}
|
54
roo-e/src/gui/widgets/vscroll.h
Normal file
54
roo-e/src/gui/widgets/vscroll.h
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
/*
|
||||||
|
* 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 VSCROLL_H
|
||||||
|
#define VSCROLL_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "../gui.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct VscrollS {
|
||||||
|
WidgetT base; // Required by all widgets.
|
||||||
|
int32_t min;
|
||||||
|
int32_t max;
|
||||||
|
int32_t value;
|
||||||
|
RectT thumb;
|
||||||
|
ClickHandlerT handler; // Actual event handler.
|
||||||
|
} VscrollT;
|
||||||
|
|
||||||
|
|
||||||
|
extern uint8_t __MAGIC_VSCROLL; // Magic ID assigned to us from the GUI.
|
||||||
|
|
||||||
|
|
||||||
|
void vscrollClickSet(VscrollT *vscroll, ClickHandlerT handler, void *data);
|
||||||
|
VscrollT *vscrollCreate(int16_t h, ClickHandlerT handler, void *data, ...);
|
||||||
|
void vscrollRangeSet(VscrollT *vscroll, int32_t min, int32_t max);
|
||||||
|
RegisterT *vscrollRegister(uint8_t magic);
|
||||||
|
int32_t vscrollValueGet(VscrollT *vscroll);
|
||||||
|
void vscrollValueSet(VscrollT *vscroll, int32_t value);
|
||||||
|
|
||||||
|
|
||||||
|
#endif // VSCROLL_H
|
|
@ -28,12 +28,6 @@
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
|
||||||
|
|
||||||
#define ICON_SIZE 32
|
|
||||||
#define WIDGET_SIZE 20
|
|
||||||
#define SCROLL_SPEED_SLOW 5 // ***TODO*** Move into GUI after we get scrollbar widgets.
|
|
||||||
#define SCROLL_SPEED_FAST 25
|
|
||||||
|
|
||||||
|
|
||||||
uint8_t __MAGIC_WINDOW = 0;
|
uint8_t __MAGIC_WINDOW = 0;
|
||||||
|
|
||||||
|
|
||||||
|
@ -120,11 +114,11 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
|
if (w->title || w->flags & WIN_CLOSE || w->flags & WIN_MAXIMIZE || w->flags & WIN_MINIMIZE) {
|
||||||
tx1 = x1;
|
tx1 = x1;
|
||||||
tx2 = x2;
|
tx2 = x2;
|
||||||
ty2 = y1 + WIDGET_SIZE;
|
ty2 = y1 + GADGET_SIZE;
|
||||||
|
|
||||||
// Close box?
|
// Close box?
|
||||||
if (w->flags & WIN_CLOSE) {
|
if (w->flags & WIN_CLOSE) {
|
||||||
tx1 += WIDGET_SIZE;
|
tx1 += GADGET_SIZE;
|
||||||
w->close.x = x1;
|
w->close.x = x1;
|
||||||
w->close.y = y1;
|
w->close.y = y1;
|
||||||
w->close.x2 = tx1 - 1;
|
w->close.x2 = tx1 - 1;
|
||||||
|
@ -138,10 +132,10 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
|
|
||||||
// Maximize box?
|
// Maximize box?
|
||||||
if (w->flags & WIN_MAXIMIZE) {
|
if (w->flags & WIN_MAXIMIZE) {
|
||||||
tx2 -= WIDGET_SIZE;
|
tx2 -= GADGET_SIZE;
|
||||||
w->maximize.x = tx2 + 1;
|
w->maximize.x = tx2 + 1;
|
||||||
w->maximize.y = y1;
|
w->maximize.y = y1;
|
||||||
w->maximize.x2 = tx2 + WIDGET_SIZE;
|
w->maximize.x2 = tx2 + GADGET_SIZE;
|
||||||
w->maximize.y2 = ty2 - 1;
|
w->maximize.y2 = ty2 - 1;
|
||||||
surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, titleBackgroundColor);
|
surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, titleBackgroundColor);
|
||||||
surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y + 4, GUI_WHITE);
|
surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y + 4, GUI_WHITE);
|
||||||
|
@ -155,10 +149,10 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
|
|
||||||
// Minimize box?
|
// Minimize box?
|
||||||
if (w->flags & WIN_MINIMIZE) {
|
if (w->flags & WIN_MINIMIZE) {
|
||||||
tx2 -= WIDGET_SIZE;
|
tx2 -= GADGET_SIZE;
|
||||||
w->minimize.x = tx2 + 1;
|
w->minimize.x = tx2 + 1;
|
||||||
w->minimize.y = y1;
|
w->minimize.y = y1;
|
||||||
w->minimize.x2 = tx2 + WIDGET_SIZE;
|
w->minimize.x2 = tx2 + GADGET_SIZE;
|
||||||
w->minimize.y2 = ty2 - 1;
|
w->minimize.y2 = ty2 - 1;
|
||||||
surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, titleBackgroundColor);
|
surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, titleBackgroundColor);
|
||||||
surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, widgetColor);
|
surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, widgetColor);
|
||||||
|
@ -194,7 +188,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
}
|
}
|
||||||
surfaceBoxHighlight(w->titlebar.x, w->titlebar.y, w->titlebar.x2, w->titlebar.y2, GUI_WHITE, GUI_BLACK);
|
surfaceBoxHighlight(w->titlebar.x, w->titlebar.y, w->titlebar.x2, w->titlebar.y2, GUI_WHITE, GUI_BLACK);
|
||||||
|
|
||||||
y1 += WIDGET_SIZE;
|
y1 += GADGET_SIZE;
|
||||||
} else {
|
} else {
|
||||||
w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
|
w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0;
|
||||||
w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
|
w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0;
|
||||||
|
@ -205,14 +199,14 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
// Vertical Scroll Bar?
|
// Vertical Scroll Bar?
|
||||||
if (w->flags & WIN_SCROLL_V) {
|
if (w->flags & WIN_SCROLL_V) {
|
||||||
w->scrollv.x2 = x2;
|
w->scrollv.x2 = x2;
|
||||||
w->scrollv.x = w->scrollv.x2 - (WIDGET_SIZE - 1);
|
w->scrollv.x = w->scrollv.x2 - (GADGET_SIZE - 1);
|
||||||
w->scrollv.y = y1;
|
w->scrollv.y = y1;
|
||||||
w->scrollv.y2 = y2;
|
w->scrollv.y2 = y2;
|
||||||
// Draw scroll bar.
|
// Draw scroll bar.
|
||||||
surfaceBoxFilled(w->scrollv.x + 1, w->scrollv.y + 1, w->scrollv.x2 - 1, w->scrollv.y2 - 1, scrollBackgroundColor);
|
surfaceBoxFilled(w->scrollv.x + 1, w->scrollv.y + 1, w->scrollv.x2 - 1, w->scrollv.y2 - 1, scrollBackgroundColor);
|
||||||
surfaceBoxHighlight(w->scrollv.x, w->scrollv.y, w->scrollv.x2, w->scrollv.y2, GUI_WHITE, GUI_BLACK);
|
surfaceBoxHighlight(w->scrollv.x, w->scrollv.y, w->scrollv.x2, w->scrollv.y2, GUI_WHITE, GUI_BLACK);
|
||||||
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y + (WIDGET_SIZE - 1), GUI_BLACK);
|
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y + (GADGET_SIZE - 1), GUI_BLACK);
|
||||||
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y2 - (WIDGET_SIZE - 1), GUI_WHITE);
|
surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y2 - (GADGET_SIZE - 1), GUI_WHITE);
|
||||||
// Prepare font.
|
// Prepare font.
|
||||||
fontSet(__guiFontVGA8x8);
|
fontSet(__guiFontVGA8x8);
|
||||||
fontColorSet(widgetColor, scrollBackgroundColor);
|
fontColorSet(widgetColor, scrollBackgroundColor);
|
||||||
|
@ -220,7 +214,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
fontRender("\x1e", w->scrollv.x + 7, w->scrollv.y + 7);
|
fontRender("\x1e", w->scrollv.x + 7, w->scrollv.y + 7);
|
||||||
fontRender("\x1f", w->scrollv.x + 7, w->scrollv.y2 - 12);
|
fontRender("\x1f", w->scrollv.x + 7, w->scrollv.y2 - 12);
|
||||||
|
|
||||||
x2 -= (WIDGET_SIZE - 1);
|
x2 -= (GADGET_SIZE - 1);
|
||||||
} else {
|
} else {
|
||||||
w->scrollv.x = w->scrollv.y = w->scrollv.x2 = w->scrollv.y2 = 0;
|
w->scrollv.x = w->scrollv.y = w->scrollv.x2 = w->scrollv.y2 = 0;
|
||||||
}
|
}
|
||||||
|
@ -230,12 +224,12 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
w->scrollh.x = x1;
|
w->scrollh.x = x1;
|
||||||
w->scrollh.x2 = x2;
|
w->scrollh.x2 = x2;
|
||||||
w->scrollh.y2 = y2;
|
w->scrollh.y2 = y2;
|
||||||
w->scrollh.y = w->scrollh.y2 - (WIDGET_SIZE - 1);
|
w->scrollh.y = w->scrollh.y2 - (GADGET_SIZE - 1);
|
||||||
// Draw scroll bar.
|
// Draw scroll bar.
|
||||||
surfaceBoxFilled(w->scrollh.x + 1, w->scrollh.y + 1, w->scrollh.x2 - 1, w->scrollh.y2 - 1, scrollBackgroundColor);
|
surfaceBoxFilled(w->scrollh.x + 1, w->scrollh.y + 1, w->scrollh.x2 - 1, w->scrollh.y2 - 1, scrollBackgroundColor);
|
||||||
surfaceBoxHighlight(w->scrollh.x, w->scrollh.y, w->scrollh.x2, w->scrollh.y2, GUI_WHITE, GUI_BLACK);
|
surfaceBoxHighlight(w->scrollh.x, w->scrollh.y, w->scrollh.x2, w->scrollh.y2, GUI_WHITE, GUI_BLACK);
|
||||||
surfaceLineV(w->scrollh.x + (WIDGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_BLACK);
|
surfaceLineV(w->scrollh.x + (GADGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_BLACK);
|
||||||
surfaceLineV(w->scrollh.x2 - (WIDGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_WHITE);
|
surfaceLineV(w->scrollh.x2 - (GADGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_WHITE);
|
||||||
// If we have both horizontal and vertical scroll bars, we need to fix a shadow.
|
// If we have both horizontal and vertical scroll bars, we need to fix a shadow.
|
||||||
if (w->flags & WIN_SCROLL_V) {
|
if (w->flags & WIN_SCROLL_V) {
|
||||||
surfaceLineV(w->scrollh.x2 - 1, w->scrollh.y, w->scrollh.y2, GUI_BLACK);
|
surfaceLineV(w->scrollh.x2 - 1, w->scrollh.y, w->scrollh.y2, GUI_BLACK);
|
||||||
|
@ -248,7 +242,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
fontRender("\x11", w->scrollh.x + 7, w->scrollh.y + 7);
|
fontRender("\x11", w->scrollh.x + 7, w->scrollh.y + 7);
|
||||||
fontRender("\x10", w->scrollh.x2 - 12, w->scrollh.y + 7);
|
fontRender("\x10", w->scrollh.x2 - 12, w->scrollh.y + 7);
|
||||||
|
|
||||||
y2 -= (WIDGET_SIZE - 1);
|
y2 -= (GADGET_SIZE - 1);
|
||||||
} else {
|
} else {
|
||||||
w->scrollh.x = w->scrollh.y = w->scrollh.x2 = w->scrollh.y2 = 0;
|
w->scrollh.x = w->scrollh.y = w->scrollh.x2 = w->scrollh.y2 = 0;
|
||||||
}
|
}
|
||||||
|
@ -265,13 +259,13 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
// Vertical Scroll Bar Thumb?
|
// Vertical Scroll Bar Thumb?
|
||||||
if (w->flags & WIN_SCROLL_V) {
|
if (w->flags & WIN_SCROLL_V) {
|
||||||
// Distance between arrow buttons on scroll bar.
|
// Distance between arrow buttons on scroll bar.
|
||||||
i = w->scrollv.y2 - w->scrollv.y - (WIDGET_SIZE * 2 - 2) - 2;
|
i = w->scrollv.y2 - w->scrollv.y - (GADGET_SIZE * 2 - 2) - 2;
|
||||||
// Percentage to scale content height to scroll bar height.
|
// Percentage to scale content height to scroll bar height.
|
||||||
d = (double)i / (double)surfaceHeightGet(w->content);
|
d = (double)i / (double)surfaceHeightGet(w->content);
|
||||||
// Find position and size of thumb.
|
// Find position and size of thumb.
|
||||||
w->thumbv.x = w->scrollv.x + 1;
|
w->thumbv.x = w->scrollv.x + 1;
|
||||||
w->thumbv.x2 = w->scrollv.x2 - 1;
|
w->thumbv.x2 = w->scrollv.x2 - 1;
|
||||||
w->thumbv.y = w->scrollv.y + WIDGET_SIZE + (w->offset.y * d);
|
w->thumbv.y = w->scrollv.y + GADGET_SIZE + (w->offset.y * d);
|
||||||
w->thumbv.y2 = w->thumbv.y + ((w->bounds.y2 - w->bounds.y) * d);
|
w->thumbv.y2 = w->thumbv.y + ((w->bounds.y2 - w->bounds.y) * d);
|
||||||
// Clamp overflow due to doubles and my off-by-one brain.
|
// Clamp overflow due to doubles and my off-by-one brain.
|
||||||
if (w->thumbv.y2 >= w->thumbv.y + i - 1) w->thumbv.y2 = w->thumbv.y + i - 1;
|
if (w->thumbv.y2 >= w->thumbv.y + i - 1) w->thumbv.y2 = w->thumbv.y + i - 1;
|
||||||
|
@ -285,11 +279,11 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
// Horizontal Scroll Bar Thumb?
|
// Horizontal Scroll Bar Thumb?
|
||||||
if (w->flags & WIN_SCROLL_H) {
|
if (w->flags & WIN_SCROLL_H) {
|
||||||
// Distance between arrow buttons on scroll bar.
|
// Distance between arrow buttons on scroll bar.
|
||||||
i = w->scrollh.x2 - w->scrollh.x - (WIDGET_SIZE * 2 - 2) - 2;
|
i = w->scrollh.x2 - w->scrollh.x - (GADGET_SIZE * 2 - 2) - 2;
|
||||||
// Percentage to scale content width to scroll bar width.
|
// Percentage to scale content width to scroll bar width.
|
||||||
d = (double)i / (double)surfaceWidthGet(w->content);
|
d = (double)i / (double)surfaceWidthGet(w->content);
|
||||||
// Find position and size of thumb.
|
// Find position and size of thumb.
|
||||||
w->thumbh.x = w->scrollh.x + WIDGET_SIZE + (w->offset.x * d);
|
w->thumbh.x = w->scrollh.x + GADGET_SIZE + (w->offset.x * d);
|
||||||
w->thumbh.x2 = w->thumbh.x + ((w->bounds.x2 - w->bounds.x) * d);
|
w->thumbh.x2 = w->thumbh.x + ((w->bounds.x2 - w->bounds.x) * d);
|
||||||
w->thumbh.y = w->scrollh.y + 1;
|
w->thumbh.y = w->scrollh.y + 1;
|
||||||
w->thumbh.y2 = w->scrollh.y2 - 1;
|
w->thumbh.y2 = w->scrollh.y2 - 1;
|
||||||
|
@ -312,11 +306,11 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
w->resize1.x2 = w->base.r.x + w->base.r.w - 2;
|
w->resize1.x2 = w->base.r.x + w->base.r.w - 2;
|
||||||
w->resize1.x = w->resize1.x2 - 3;
|
w->resize1.x = w->resize1.x2 - 3;
|
||||||
w->resize1.y2 = w->base.r.y + w->base.r.h;
|
w->resize1.y2 = w->base.r.y + w->base.r.h;
|
||||||
w->resize1.y = w->resize1.y2 - (WIDGET_SIZE + 5);
|
w->resize1.y = w->resize1.y2 - (GADGET_SIZE + 5);
|
||||||
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y, GUI_BLACK);
|
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y, GUI_BLACK);
|
||||||
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y + 1, GUI_WHITE);
|
surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y + 1, GUI_WHITE);
|
||||||
w->resize2.x2 = w->base.r.x + w->base.r.w;
|
w->resize2.x2 = w->base.r.x + w->base.r.w;
|
||||||
w->resize2.x = w->resize2.x2 - (WIDGET_SIZE + 5);
|
w->resize2.x = w->resize2.x2 - (GADGET_SIZE + 5);
|
||||||
w->resize2.y2 = w->base.r.y + w->base.r.h - 2;
|
w->resize2.y2 = w->base.r.y + w->base.r.h - 2;
|
||||||
w->resize2.y = w->resize2.y2 - 3;
|
w->resize2.y = w->resize2.y2 - 3;
|
||||||
surfaceLineV(w->resize2.x, w->resize2.y, w->resize2.y2, GUI_BLACK);
|
surfaceLineV(w->resize2.x, w->resize2.y, w->resize2.y2, GUI_BLACK);
|
||||||
|
@ -352,7 +346,6 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#include "image.h"
|
|
||||||
// Passing "flags" as a default int provides proper alignment for the following va_args list.
|
// Passing "flags" as a default int provides proper alignment for the following va_args list.
|
||||||
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, int flags, ...) {
|
WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, int flags, ...) {
|
||||||
int16_t width;
|
int16_t width;
|
||||||
|
@ -363,7 +356,7 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl
|
||||||
|
|
||||||
NEW(WindowT, win);
|
NEW(WindowT, win);
|
||||||
memset(win, 0, sizeof(WindowT));
|
memset(win, 0, sizeof(WindowT));
|
||||||
guiWidgetBaseSet((WidgetT *)win, __MAGIC_WINDOW, w, h);
|
widgetBaseSet((WidgetT *)win, __MAGIC_WINDOW, w, h);
|
||||||
win->base.r.x = x;
|
win->base.r.x = x;
|
||||||
win->base.r.y = y;
|
win->base.r.y = y;
|
||||||
win->title = strdup(title);
|
win->title = strdup(title);
|
||||||
|
@ -380,8 +373,9 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl
|
||||||
windowCache(win, 1);
|
windowCache(win, 1);
|
||||||
width = win->bounds.x2 - win->bounds.x;
|
width = win->bounds.x2 - win->bounds.x;
|
||||||
height = win->bounds.y2 - win->bounds.y;
|
height = win->bounds.y2 - win->bounds.y;
|
||||||
guiWidgetDirtySet(W(win), 1);
|
widgetDirtySet(W(win), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create content surface and clear it.
|
// Create content surface and clear it.
|
||||||
win->content = surfaceCreate(width, height);
|
win->content = surfaceCreate(width, height);
|
||||||
surfaceSet(win->content);
|
surfaceSet(win->content);
|
||||||
|
@ -420,7 +414,7 @@ static void windowDestroy(struct WidgetS *widget, ...) {
|
||||||
// Free the title.
|
// Free the title.
|
||||||
if (window->title) DEL(window->title);
|
if (window->title) DEL(window->title);
|
||||||
// Free children.
|
// Free children.
|
||||||
for (c=0; c<arrlen(window->children); c++) guiWidgetDestroy(window->children[c]);
|
for (c=0; c<arrlen(window->children); c++) widgetDestroy(window->children[c]);
|
||||||
arrfree(window->children);
|
arrfree(window->children);
|
||||||
// Free cached surface.
|
// Free cached surface.
|
||||||
if (window->cached) surfaceDestroy(&window->cached);
|
if (window->cached) surfaceDestroy(&window->cached);
|
||||||
|
@ -450,7 +444,7 @@ void windowFocusSet(WindowT *win) {
|
||||||
} else {
|
} else {
|
||||||
// Open window. Use as new top.
|
// Open window. Use as new top.
|
||||||
_windowTop = _windowList[i];
|
_windowTop = _windowList[i];
|
||||||
guiWidgetDirtySet(W(_windowTop), 1);
|
widgetDirtySet(W(_windowTop), 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -471,8 +465,8 @@ void windowFocusSet(WindowT *win) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark old focus and new focus dirty to repaint title bar.
|
// Mark old focus and new focus dirty to repaint title bar.
|
||||||
guiWidgetDirtySet(W(win), 1);
|
widgetDirtySet(W(win), 1);
|
||||||
guiWidgetDirtySet(W(_windowTop), 1);
|
widgetDirtySet(W(_windowTop), 1);
|
||||||
|
|
||||||
// Change who has focus.
|
// Change who has focus.
|
||||||
_windowTop = win;
|
_windowTop = win;
|
||||||
|
@ -656,7 +650,7 @@ static void windowPaint(struct WidgetS *widget, ...) {
|
||||||
// Are any child widgets dirty?
|
// Are any child widgets dirty?
|
||||||
y = 0;
|
y = 0;
|
||||||
for (x=0; x<arrlen(w->children); x++) {
|
for (x=0; x<arrlen(w->children); x++) {
|
||||||
if (guiWidgetDirtyGet(w->children[x])) {
|
if (widgetDirtyGet(w->children[x])) {
|
||||||
y = 1;
|
y = 1;
|
||||||
if (w->children[x]->reg->paint) {
|
if (w->children[x]->reg->paint) {
|
||||||
surfaceSet(w->content);
|
surfaceSet(w->content);
|
||||||
|
@ -667,8 +661,8 @@ static void windowPaint(struct WidgetS *widget, ...) {
|
||||||
surfaceSet(t);
|
surfaceSet(t);
|
||||||
|
|
||||||
// Does the window itself need redrawn?
|
// Does the window itself need redrawn?
|
||||||
if (guiWidgetDirtyGet(widget)) {
|
if (widgetDirtyGet(widget)) {
|
||||||
guiWidgetDirtySet(widget, 0);
|
widgetDirtySet(widget, 0);
|
||||||
x = 1;
|
x = 1;
|
||||||
} else {
|
} else {
|
||||||
x = 0;
|
x = 0;
|
||||||
|
@ -723,8 +717,8 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) {
|
||||||
int16_t delta;
|
int16_t delta;
|
||||||
|
|
||||||
// Too small?
|
// Too small?
|
||||||
if (width < (WIDGET_SIZE * 4) + 15) width = (WIDGET_SIZE * 4) + 15;
|
if (width < (GADGET_SIZE * 4) + 15) width = (GADGET_SIZE * 4) + 15;
|
||||||
if (height < (WIDGET_SIZE * 4) + 15) height = (WIDGET_SIZE * 4) + 15;
|
if (height < (GADGET_SIZE * 4) + 15) height = (GADGET_SIZE * 4) + 15;
|
||||||
|
|
||||||
// Too big?
|
// Too big?
|
||||||
if (win->bounds.w - win->bounds.x + (width - win->base.r.w) + win->offset.x > surfaceWidthGet(win->content)) {
|
if (win->bounds.w - win->bounds.x + (width - win->base.r.w) + win->offset.x > surfaceWidthGet(win->content)) {
|
||||||
|
@ -762,7 +756,7 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) {
|
||||||
static void windowScrollHorizontalHandler(EventT *e, WindowT *w) {
|
static void windowScrollHorizontalHandler(EventT *e, WindowT *w) {
|
||||||
|
|
||||||
// Clicking in left arrow?
|
// Clicking in left arrow?
|
||||||
if (e->x <= w->scrollh.x + WIDGET_SIZE) {
|
if (e->x <= w->scrollh.x + GADGET_SIZE) {
|
||||||
// Move content left.
|
// Move content left.
|
||||||
w->offset.x -= SCROLL_SPEED_SLOW;
|
w->offset.x -= SCROLL_SPEED_SLOW;
|
||||||
// Clip.
|
// Clip.
|
||||||
|
@ -773,7 +767,7 @@ static void windowScrollHorizontalHandler(EventT *e, WindowT *w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicking in right arrow?
|
// Clicking in right arrow?
|
||||||
if (e->x >= w->scrollh.x2 - WIDGET_SIZE) {
|
if (e->x >= w->scrollh.x2 - GADGET_SIZE) {
|
||||||
// Move content right.
|
// Move content right.
|
||||||
w->offset.x += SCROLL_SPEED_SLOW;
|
w->offset.x += SCROLL_SPEED_SLOW;
|
||||||
// Clip.
|
// Clip.
|
||||||
|
@ -810,7 +804,7 @@ static void windowScrollHorizontalHandler(EventT *e, WindowT *w) {
|
||||||
static void windowScrollVerticalHandler(EventT *e, WindowT *w) {
|
static void windowScrollVerticalHandler(EventT *e, WindowT *w) {
|
||||||
|
|
||||||
// Clicking in up arrow?
|
// Clicking in up arrow?
|
||||||
if (e->y <= w->scrollv.y + WIDGET_SIZE) {
|
if (e->y <= w->scrollv.y + GADGET_SIZE) {
|
||||||
// Move content up.
|
// Move content up.
|
||||||
w->offset.y -= SCROLL_SPEED_SLOW;
|
w->offset.y -= SCROLL_SPEED_SLOW;
|
||||||
// Clip.
|
// Clip.
|
||||||
|
@ -821,7 +815,7 @@ static void windowScrollVerticalHandler(EventT *e, WindowT *w) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clicking in down arrow?
|
// Clicking in down arrow?
|
||||||
if (e->y >= w->scrollv.y2 - WIDGET_SIZE) {
|
if (e->y >= w->scrollv.y2 - GADGET_SIZE) {
|
||||||
// Move content down.
|
// Move content down.
|
||||||
w->offset.y += SCROLL_SPEED_SLOW;
|
w->offset.y += SCROLL_SPEED_SLOW;
|
||||||
// Clip.
|
// Clip.
|
||||||
|
@ -856,6 +850,7 @@ static void windowScrollVerticalHandler(EventT *e, WindowT *w) {
|
||||||
|
|
||||||
|
|
||||||
void windowWidgetAdd(WindowT *window, int16_t x, int16_t y, WidgetT *widget) {
|
void windowWidgetAdd(WindowT *window, int16_t x, int16_t y, WidgetT *widget) {
|
||||||
|
widget->parent = window;
|
||||||
widget->r.x = x;
|
widget->r.x = x;
|
||||||
widget->r.y = y;
|
widget->r.y = y;
|
||||||
arrput(window->children, widget);
|
arrput(window->children, widget);
|
||||||
|
@ -877,7 +872,7 @@ void windowWidgetRemove(WindowT *window, WidgetT *widget) {
|
||||||
void wmShutdown(void) {
|
void wmShutdown(void) {
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
|
||||||
for (i=0; i<arrlen(_windowList); i++) guiWidgetDestroy(W(_windowList[i]));
|
for (i=0; i<arrlen(_windowList); i++) widgetDestroy(W(_windowList[i]));
|
||||||
arrfree(_windowList);
|
arrfree(_windowList);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -889,13 +884,15 @@ void wmStartup(void) {
|
||||||
|
|
||||||
void wmUpdate(EventT *event) {
|
void wmUpdate(EventT *event) {
|
||||||
int16_t i;
|
int16_t i;
|
||||||
int16_t x;
|
int16_t windowLocalX;
|
||||||
int16_t y;
|
int16_t windowLocalY;
|
||||||
int16_t x2;
|
int16_t x2;
|
||||||
int16_t y2;
|
int16_t y2;
|
||||||
uint8_t onResize = 0;
|
uint8_t onResize = 0;
|
||||||
WidgetT *widget;
|
WidgetT *widget;
|
||||||
|
WidgetT *widgetOver = NULL;
|
||||||
WindowT *win = NULL;
|
WindowT *win = NULL;
|
||||||
|
ClickRawInputT rawEvent = { 0 };
|
||||||
static uint8_t resizing = 0;
|
static uint8_t resizing = 0;
|
||||||
static PointT resizeOffset = { 0 };
|
static PointT resizeOffset = { 0 };
|
||||||
static uint8_t dragging = 0;
|
static uint8_t dragging = 0;
|
||||||
|
@ -928,6 +925,19 @@ void wmUpdate(EventT *event) {
|
||||||
y2 = 0;
|
y2 = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Are we over a widget?
|
||||||
|
widgetOver = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
|
||||||
|
|
||||||
|
// If we're over a widget that has raw input processing enabled and we haven't started a click on another widget yet, send to target for raw processing.
|
||||||
|
if (widgetOver && !widgetDown && (widgetOver->flags & WIDGET_RAW_INPUT) && (event->buttons != 0)) {
|
||||||
|
if (widgetOver->reg->click) {
|
||||||
|
rawEvent.event = event;
|
||||||
|
rawEvent.data = widget->data;
|
||||||
|
widgetOver->reg->click(widgetOver, windowLocalX - widgetOver->r.x, windowLocalY - widgetOver->r.y, CLICK_RAW_INPUT, &rawEvent);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Wrap left button processing with a 'for' so we can 'break' out of it.
|
// Wrap left button processing with a 'for' so we can 'break' out of it.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
|
|
||||||
|
@ -991,9 +1001,9 @@ void wmUpdate(EventT *event) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Are we over a widget?
|
// Are we over a widget?
|
||||||
widget = wuWidgetUnderMouseGet(win, event, &x, &y);
|
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
|
||||||
if (widget) {
|
if (widget) {
|
||||||
if (widget->reg->click) widget->reg->click(widget, x - widget->r.x, y - widget->r.y, CLICK_LEFT_DOWN, widget->data);
|
if (widget->reg->click) widget->reg->click(widget, windowLocalX - widget->r.x, windowLocalY - widget->r.y, CLICK_LEFT_DOWN, widget->data);
|
||||||
widgetDown = widget;
|
widgetDown = widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1126,9 +1136,9 @@ void wmUpdate(EventT *event) {
|
||||||
// Are we still inside the window content?
|
// 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) {
|
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?
|
// Are we stll over the same widget?
|
||||||
widget = wuWidgetUnderMouseGet(win, event, &x, &y);
|
widget = wuWidgetUnderMouseGet(win, event, &windowLocalX, &windowLocalY);
|
||||||
// Send to widget for processing or send cancel. Convert mouse to widget-local coordinates.
|
// Send to widget for processing or send cancel. Convert mouse to widget-local coordinates.
|
||||||
if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, x - widgetDown->r.x, y - widgetDown->r.y, (widget == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data);
|
if (widgetDown->reg->click) widgetDown->reg->click(widgetDown, windowLocalX - widgetDown->r.x, windowLocalY - widgetDown->r.y, (widget == widgetDown) ? CLICK_LEFT_UP : CLICK_LEFT_CANCEL, widgetDown->data);
|
||||||
}
|
}
|
||||||
widgetDown = NULL;
|
widgetDown = NULL;
|
||||||
} // widgetDown
|
} // widgetDown
|
||||||
|
@ -1164,3 +1174,8 @@ static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *loca
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
WindowT *wmWindowOnTopGet(void) {
|
||||||
|
return _windowTop;
|
||||||
|
}
|
||||||
|
|
|
@ -30,6 +30,12 @@
|
||||||
#include "gui.h"
|
#include "gui.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define ICON_SIZE 32
|
||||||
|
#define GADGET_SIZE 20
|
||||||
|
#define SCROLL_SPEED_SLOW 5 // ***TODO*** Move into GUI after we get scrollbar widgets.
|
||||||
|
#define SCROLL_SPEED_FAST 25
|
||||||
|
|
||||||
|
|
||||||
#define WIN_NONE 0
|
#define WIN_NONE 0
|
||||||
#define WIN_CLOSE 1
|
#define WIN_CLOSE 1
|
||||||
#define WIN_MAXIMIZE 2
|
#define WIN_MAXIMIZE 2
|
||||||
|
@ -81,9 +87,10 @@ void windowWidgetAdd(WindowT *window, int16_t x, int16_t y, WidgetT *widge
|
||||||
void windowWidgetRemove(WindowT *window, WidgetT *widget);
|
void windowWidgetRemove(WindowT *window, WidgetT *widget);
|
||||||
|
|
||||||
|
|
||||||
void wmShutdown(void);
|
void wmShutdown(void);
|
||||||
void wmStartup(void);
|
void wmStartup(void);
|
||||||
void wmUpdate(EventT *event);
|
void wmUpdate(EventT *event);
|
||||||
|
WindowT *wmWindowOnTopGet(void);
|
||||||
|
|
||||||
|
|
||||||
#endif // WMWINDOW_H
|
#endif // WMWINDOW_H
|
||||||
|
|
|
@ -23,27 +23,42 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
#include "gui/gui.h"
|
#include "gui/gui-all.h"
|
||||||
#include "gui/wmwindow.h"
|
|
||||||
#include "gui/widgets/label.h"
|
|
||||||
#include "gui/widgets/picture.h"
|
VscrollT *_v = NULL;
|
||||||
#include "gui/widgets/button.h"
|
VscrollT *_h = NULL;
|
||||||
#include "gui/widgets/checkbox.h"
|
|
||||||
|
|
||||||
|
|
||||||
void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
||||||
(void)widget;
|
(void)widget;
|
||||||
logWrite("%d %dx%d %s\n", event, x, y, data);
|
logWrite("%d %dx%d %s %d %d\n", event, x, y, data, vscrollValueGet(_v), hscrollValueGet(_h));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
char title[256];
|
char title[256];
|
||||||
uint16_t i;
|
uint16_t i;
|
||||||
|
WindowT *w = NULL;
|
||||||
LabelT *l = NULL;
|
LabelT *l = NULL;
|
||||||
ButtonT *b = NULL;
|
ButtonT *b = NULL;
|
||||||
CheckboxT *c = NULL;
|
CheckboxT *c = NULL;
|
||||||
WindowT *w = NULL;
|
RadioT *r = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
// frame
|
||||||
|
// scrollarea
|
||||||
|
|
||||||
|
// vscroll
|
||||||
|
// hscroll
|
||||||
|
// listbox
|
||||||
|
// textbox
|
||||||
|
// up/down
|
||||||
|
// terminal
|
||||||
|
// timer
|
||||||
|
|
||||||
|
// msgbox
|
||||||
|
|
||||||
|
|
||||||
(void)argc;
|
(void)argc;
|
||||||
|
|
||||||
|
@ -66,6 +81,28 @@ int main(int argc, char *argv[]) {
|
||||||
|
|
||||||
c = checkboxCreate("Checkbox", 0);
|
c = checkboxCreate("Checkbox", 0);
|
||||||
windowWidgetAdd(w, 20, 80, W(c));
|
windowWidgetAdd(w, 20, 80, W(c));
|
||||||
|
|
||||||
|
r = radioCreate("Radio 1", 0, 1);
|
||||||
|
windowWidgetAdd(w, 20, 110, W(r));
|
||||||
|
r = radioCreate("Radio 2", 0, 0);
|
||||||
|
windowWidgetAdd(w, 120, 110, W(r));
|
||||||
|
r = radioCreate("Radio 3", 0, 0);
|
||||||
|
windowWidgetAdd(w, 220, 110, W(r));
|
||||||
|
|
||||||
|
r = radioCreate("Radio A", 1, 0);
|
||||||
|
windowWidgetAdd(w, 20, 140, W(r));
|
||||||
|
r = radioCreate("Radio B", 1, 1);
|
||||||
|
windowWidgetAdd(w, 120, 140, W(r));
|
||||||
|
r = radioCreate("Radio C", 1, 0);
|
||||||
|
windowWidgetAdd(w, 220, 140, W(r));
|
||||||
|
|
||||||
|
_v = vscrollCreate(100, clickHandler, NULL);
|
||||||
|
vscrollRangeSet(_v, 0, 640);
|
||||||
|
windowWidgetAdd(w, 200, 5, W(_v));
|
||||||
|
|
||||||
|
_h = hscrollCreate(100, clickHandler, NULL);
|
||||||
|
hscrollRangeSet(_h, 0, 640);
|
||||||
|
windowWidgetAdd(w, 70, 5, W(_h));
|
||||||
}
|
}
|
||||||
guiRun();
|
guiRun();
|
||||||
guiShutdown();
|
guiShutdown();
|
||||||
|
|
Loading…
Add table
Reference in a new issue