Complete rewrite of mouse code. It is now sane. I think.
This commit is contained in:
parent
04cce38be1
commit
f507b0713b
11 changed files with 294 additions and 147 deletions
|
@ -20,6 +20,9 @@
|
|||
|
||||
#include "button.h"
|
||||
|
||||
static void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
||||
static void buttonPaint(WidgetT *widget);
|
||||
|
||||
|
||||
void buttonDel(WidgetT **widget) {
|
||||
ButtonT *b = (ButtonT *)*widget;
|
||||
|
@ -51,14 +54,28 @@ WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widget
|
|||
}
|
||||
|
||||
|
||||
void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y) {
|
||||
static void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) {
|
||||
ButtonT *b = (ButtonT *)widget;
|
||||
|
||||
(void)x;
|
||||
(void)y;
|
||||
(void)mouse;
|
||||
|
||||
// Button pressed?
|
||||
if (event == MOUSE_EVENT_LEFT_HOLD) {
|
||||
if (!GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
||||
GUI_SET_FLAG(widget, WIDGET_FLAG_ACTIVE);
|
||||
GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
} else {
|
||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE);
|
||||
GUI_SET_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
// Fire callback on mouse up.
|
||||
if (!mouse->buttonLeft && mouse->buttonLeftWasDown) {
|
||||
if (event == MOUSE_EVENT_LEFT_UP) {
|
||||
if (b->clicked) b->clicked(widget);
|
||||
}
|
||||
}
|
||||
|
@ -82,27 +99,27 @@ ButtonT *buttonNew(uint16_t x, uint16_t y, char *title, widgetCallback callback)
|
|||
}
|
||||
|
||||
|
||||
void buttonPaint(WidgetT *button) {
|
||||
ButtonT *b = (ButtonT *)button;
|
||||
static void buttonPaint(WidgetT *widget) {
|
||||
ButtonT *b = (ButtonT *)widget;
|
||||
int16_t i;
|
||||
uint16_t x1 = b->base.x + b->base.marginX;
|
||||
uint16_t y1 = b->base.y + b->base.marginY;
|
||||
PixelT highlight = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_BUTTON_SHADOW] : _guiColor[COLOR_BUTTON_HIGHLIGHT];
|
||||
PixelT shadow = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_BUTTON_HIGHLIGHT] : _guiColor[COLOR_BUTTON_SHADOW] ;
|
||||
|
||||
if (GUI_GET_FLAG(button, WIDGET_FLAG_DIRTY)) {
|
||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) {
|
||||
vbeSurfaceSet(b->base.surface);
|
||||
|
||||
// Draw bezel.
|
||||
for (i=0; i<_guiMetric[METRIC_BUTTON_BEZEL_SIZE]; i++) {
|
||||
guiDrawHighlightFrame(x1 + i, y1 + i, x1 + b->base.w - i, y1 + b->base.h - i, _guiColor[COLOR_BUTTON_HIGHLIGHT], _guiColor[COLOR_BUTTON_SHADOW]);
|
||||
guiDrawHighlightFrame(b->base.x + i, b->base.y + i, b->base.x + b->base.w - i, b->base.y + b->base.h - i, highlight, shadow);
|
||||
}
|
||||
|
||||
// Draw background (depends on x from above).
|
||||
guiDrawFilledRectangle(x1 + i, y1 + i, x1 + b->base.w - i, y1 + b->base.h - i, _guiColor[COLOR_BUTTON_BACKGROUND]);
|
||||
guiDrawFilledRectangle(b->base.x + i, b->base.y + i, b->base.x + b->base.w - i, b->base.y + b->base.h - i, _guiColor[COLOR_BUTTON_BACKGROUND]);
|
||||
|
||||
// Draw title (depends on x from above).
|
||||
fontRender(_guiFont, b->title, _guiColor[COLOR_BUTTON_TEXT], _guiColor[COLOR_BUTTON_BACKGROUND], x1 + i + _guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN], y1 + i + _guiMetric[METRIC_BUTTON_VERTICAL_MARGIN]);
|
||||
fontRender(_guiFont, b->title, _guiColor[COLOR_BUTTON_TEXT], _guiColor[COLOR_BUTTON_BACKGROUND], b->base.x + i + _guiMetric[METRIC_BUTTON_HORIZONTAL_MARGIN], b->base.y + i + _guiMetric[METRIC_BUTTON_VERTICAL_MARGIN]);
|
||||
|
||||
GUI_CLEAR_FLAG(button, WIDGET_FLAG_DIRTY);
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,9 +35,7 @@ typedef struct ButtonS {
|
|||
|
||||
void buttonDel(WidgetT **widget);
|
||||
WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widgetCallback callback);
|
||||
void buttonMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y);
|
||||
ButtonT *buttonNew(uint16_t x, uint16_t y, char *title, widgetCallback callback);
|
||||
void buttonPaint(WidgetT *button);
|
||||
void buttonSetTitle(ButtonT *button, char *title);
|
||||
|
||||
|
||||
|
|
|
@ -19,6 +19,10 @@
|
|||
|
||||
|
||||
#include "desktop.h"
|
||||
#include "window.h"
|
||||
|
||||
|
||||
static void desktopPaint(WidgetT *desktop);
|
||||
|
||||
|
||||
void desktopDel(WidgetT **widget) {
|
||||
|
@ -33,14 +37,11 @@ void desktopDel(WidgetT **widget) {
|
|||
WidgetT *desktopInit(WidgetT *desktop) {
|
||||
DesktopT *d = (DesktopT *)desktop;
|
||||
|
||||
d->base.magic = MAGIC_DESKTOP;
|
||||
d->base.w = vbeDisplayWidthGet();
|
||||
d->base.h = vbeDisplayHeightGet();
|
||||
d->base.delMethod = desktopDel;
|
||||
d->base.paintMethod = desktopPaint;
|
||||
d->dragOffsetX = 0;
|
||||
d->dragOffsetY = 0;
|
||||
d->dragWidget = NULL;
|
||||
d->base.magic = MAGIC_DESKTOP;
|
||||
d->base.w = vbeDisplayWidthGet();
|
||||
d->base.h = vbeDisplayHeightGet();
|
||||
d->base.delMethod = desktopDel;
|
||||
d->base.paintMethod = desktopPaint;
|
||||
|
||||
GUI_SET_FLAG(desktop, WIDGET_FLAG_OWNS_SURFACE);
|
||||
d->base.surface = vbeSurfaceCreate(d->base.w, d->base.h);
|
||||
|
@ -71,7 +72,7 @@ DesktopT *desktopNew(void) {
|
|||
}
|
||||
|
||||
|
||||
void desktopPaint(WidgetT *desktop) {
|
||||
static void desktopPaint(WidgetT *desktop) {
|
||||
DesktopT *d = (DesktopT *)desktop;
|
||||
|
||||
if (GUI_GET_FLAG(desktop, WIDGET_FLAG_DIRTY)) {
|
||||
|
|
|
@ -28,16 +28,12 @@
|
|||
|
||||
typedef struct DesktopS {
|
||||
WidgetT base; // Must be first in every widget
|
||||
uint16_t dragOffsetX;
|
||||
uint16_t dragOffsetY;
|
||||
WidgetT *dragWidget;
|
||||
} DesktopT;
|
||||
|
||||
|
||||
void desktopDel(WidgetT **widget);
|
||||
WidgetT *desktopInit(WidgetT *desktop);
|
||||
DesktopT *desktopNew(void);
|
||||
void desktopPaint(WidgetT *desktop);
|
||||
|
||||
|
||||
#endif // DESKTOP_H
|
||||
|
|
|
@ -24,12 +24,20 @@
|
|||
#include "window.h"
|
||||
|
||||
|
||||
int16_t _guiMetric[METRIC_COUNT];
|
||||
PixelT _guiColor[COLOR_COUNT];
|
||||
FontT *_guiFont = NULL;
|
||||
int16_t _guiMetric[METRIC_COUNT];
|
||||
PixelT _guiColor[COLOR_COUNT];
|
||||
FontT *_guiFont = NULL;
|
||||
WidgetT *_guiDragWidget = NULL;
|
||||
uint16_t _guiDragOffsetX = 0;
|
||||
uint16_t _guiDragOffsetY = 0;
|
||||
WindowT *_guiActiveWindow = NULL;
|
||||
|
||||
|
||||
static DesktopT *_guiDesktop = NULL;
|
||||
static DesktopT *_guiDesktop = NULL;
|
||||
static WidgetT *_guiLastWidgetLeft = NULL;
|
||||
static uint8_t _guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
|
||||
|
||||
static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse);
|
||||
|
||||
|
||||
void guiAttach(WidgetT *parent, WidgetT *child) {
|
||||
|
@ -39,6 +47,15 @@ void guiAttach(WidgetT *parent, WidgetT *child) {
|
|||
child->parent = parent;
|
||||
arrput(parent->children, child);
|
||||
|
||||
// If this widget is not a window or desktop, find its parent window.
|
||||
if (child->magic != MAGIC_WINDOW && child->magic != MAGIC_DESKTOP) {
|
||||
p = child;
|
||||
while (p != NULL && p->magic != MAGIC_WINDOW) {
|
||||
p = p->parent;
|
||||
}
|
||||
child->window = (WindowT *)p;
|
||||
}
|
||||
|
||||
// If this widget does not own a surface, find one for it to draw on.
|
||||
if (!GUI_GET_FLAG(child, WIDGET_FLAG_OWNS_SURFACE)) {
|
||||
p = child;
|
||||
|
@ -54,8 +71,12 @@ void guiAttach(WidgetT *parent, WidgetT *child) {
|
|||
child->surface = p->surface;
|
||||
}
|
||||
|
||||
// New windows should be active.
|
||||
// Move the specified location by the margin so the widget doesn't have to deal with margins.
|
||||
child->x += child->marginX;
|
||||
child->y += child->marginY;
|
||||
|
||||
if (child->magic == MAGIC_WINDOW) {
|
||||
// New windows should be active.
|
||||
windowSetActive((WindowT *)child);
|
||||
}
|
||||
}
|
||||
|
@ -190,6 +211,13 @@ void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, Pixe
|
|||
}
|
||||
|
||||
|
||||
void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *x, uint16_t *y) {
|
||||
guiWidgetPositionOnScreenGet(widget, x, y);
|
||||
*x = mouse->x - *x;
|
||||
*y = mouse->y - *y;
|
||||
}
|
||||
|
||||
|
||||
void guiPaint(WidgetT *widget) {
|
||||
size_t len = arrlenu(widget->children);
|
||||
size_t x;
|
||||
|
@ -210,94 +238,83 @@ void guiPaint(WidgetT *widget) {
|
|||
|
||||
|
||||
void guiProcessMouse(MouseT *mouse) {
|
||||
size_t len;
|
||||
int16_t x;
|
||||
WidgetT *child;
|
||||
WindowT *window;
|
||||
WidgetT *parent = (WidgetT *)_guiDesktop;
|
||||
static WidgetT *downOnWidget = NULL;
|
||||
guiProcessMouseChildren(W(_guiDesktop), mouse);
|
||||
}
|
||||
|
||||
// Is the left button down?
|
||||
if (mouse->buttonLeft) {
|
||||
// Was left button NOT down before?
|
||||
if (!mouse->buttonLeftWasDown) {
|
||||
// Initial click. Are we already dragging something?
|
||||
if (!_guiDesktop->dragWidget) {
|
||||
// Can we drag this?
|
||||
len = arrlenu(parent->children);
|
||||
for (x=len-1; x>=0; x--) {
|
||||
child = parent->children[x];
|
||||
// Are we clicking this widget?
|
||||
if (mouse->x >= child->x && mouse->y >= child->y && mouse->x < child->x + child->w && mouse->y < child->y + child->h) {
|
||||
// Remember this widget for when the mouse button is released. Buttons must come up on the same widget they went down on.
|
||||
downOnWidget = child;
|
||||
// Is this a Window?
|
||||
if (child->magic == MAGIC_WINDOW) {
|
||||
window = (WindowT *)child;
|
||||
// Is it the active window?
|
||||
if (GUI_GET_FLAG(window, WINDOW_FLAG_ACTIVE)) {
|
||||
// Are we on the draggable area of the titlebar / borders?
|
||||
_guiDesktop->dragOffsetX = mouse->x - window->base.x;
|
||||
_guiDesktop->dragOffsetY = mouse->y - window->base.y;
|
||||
if (_guiDesktop->dragOffsetY < _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]) {
|
||||
// Start dragging.
|
||||
_guiDesktop->dragWidget = child;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) {
|
||||
size_t len;
|
||||
int16_t x;
|
||||
uint16_t mx;
|
||||
uint16_t my;
|
||||
uint16_t sx;
|
||||
uint16_t sy;
|
||||
uint8_t event = MOUSE_EVENT_NONE;
|
||||
|
||||
// Search children backwards for active widget before checking this widget.
|
||||
len = arrlenu(widget->children);
|
||||
for (x=len-1; x>=0; --x) {
|
||||
if (guiProcessMouseChildren(widget->children[x], mouse)) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
guiWidgetPositionOnScreenGet(widget, &sx, &sy);
|
||||
guiMousePositionOnWidgetGet(widget, mouse, &mx, &my);
|
||||
|
||||
// Serious hack to make window dragging work better.
|
||||
// This is because it's possible to move the mouse faster than METRIC_WINDOW_TITLE_GRAB_HEIGHT pixels
|
||||
// which causes it to switch widgets. So this prevents that.
|
||||
if (widget->magic == MAGIC_WINDOW && widget == _guiDragWidget && mouse->buttonLeft && mouse->buttonLeftWasDown) {
|
||||
widget->mouseEventMethod(widget, mouse, mx, my, MOUSE_EVENT_LEFT_HOLD);
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Is the mouse inside this widget?
|
||||
if (mouse->x >= sx && mouse->y >= sy && mouse->x < sx + widget->w && mouse->y < sy + widget->h) {
|
||||
|
||||
// Is this the same widget we were over before?
|
||||
if (_guiLastWidgetLeft != widget) {
|
||||
// Tell previous widget we're moving out.
|
||||
if (_guiLastWidgetLeft->mouseEventMethod) _guiLastWidgetLeft->mouseEventMethod(_guiLastWidgetLeft, mouse, mx, my, MOUSE_EVENT_OUT);
|
||||
|
||||
// Tell new widget we've moved in.
|
||||
event = MOUSE_EVENT_IN;
|
||||
|
||||
} else { // Widget Changed.
|
||||
|
||||
// Left button depressed?
|
||||
if (_guiLastWidgetLeftEvent == MOUSE_EVENT_NONE && mouse->buttonLeft && !mouse->buttonLeftWasDown) event = MOUSE_EVENT_LEFT_DOWN;
|
||||
|
||||
// Left button held?
|
||||
if ((_guiLastWidgetLeftEvent == MOUSE_EVENT_LEFT_DOWN || _guiLastWidgetLeftEvent == MOUSE_EVENT_LEFT_HOLD) && mouse->buttonLeft && mouse->buttonLeftWasDown) event = MOUSE_EVENT_LEFT_HOLD;
|
||||
|
||||
// Left button coming up?
|
||||
if ((_guiLastWidgetLeftEvent == MOUSE_EVENT_LEFT_DOWN || _guiLastWidgetLeftEvent == MOUSE_EVENT_LEFT_HOLD) && !mouse->buttonLeft && mouse->buttonLeftWasDown) event = MOUSE_EVENT_LEFT_UP;
|
||||
|
||||
}
|
||||
|
||||
_guiLastWidgetLeft = widget;
|
||||
_guiLastWidgetLeftEvent = event;
|
||||
|
||||
// Is there an event?
|
||||
if (event != MOUSE_EVENT_NONE) {
|
||||
// Does it belong to the active window? Or does it target a window? A desktop?
|
||||
if (widget->window == _guiActiveWindow || widget->magic == MAGIC_WINDOW || widget->magic == MAGIC_DESKTOP) {
|
||||
// Is there a mouse handler?
|
||||
if (widget->mouseEventMethod) {
|
||||
// Ask child to handle event.
|
||||
widget->mouseEventMethod(widget, mouse, mx, my, event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else { // Was left button NOT down before?
|
||||
|
||||
// Still holding left button, but not the initial click. Update dragged widget location.
|
||||
if (_guiDesktop->dragWidget) {
|
||||
_guiDesktop->dragWidget->x = mouse->x - _guiDesktop->dragOffsetX;
|
||||
_guiDesktop->dragWidget->y = mouse->y - _guiDesktop->dragOffsetY;
|
||||
// Keep it on the screen.
|
||||
if (_guiDesktop->dragWidget->x < 0) _guiDesktop->dragWidget->x = 0;
|
||||
if (_guiDesktop->dragWidget->x + _guiDesktop->dragWidget->w > vbeDisplayWidthGet()) _guiDesktop->dragWidget->x = vbeDisplayWidthGet() - _guiDesktop->dragWidget->w;
|
||||
if (_guiDesktop->dragWidget->y < 0) _guiDesktop->dragWidget->y = 0;
|
||||
if (_guiDesktop->dragWidget->y + _guiDesktop->dragWidget->h > vbeDisplayHeightGet()) _guiDesktop->dragWidget->y = vbeDisplayHeightGet() - _guiDesktop->dragWidget->h;
|
||||
}
|
||||
|
||||
} // Was left button NOT down before?
|
||||
|
||||
} else { // Left button down?
|
||||
|
||||
// No longer holding left button. Stop dragging.
|
||||
_guiDesktop->dragWidget = NULL;
|
||||
|
||||
// Was the left button down last frame?
|
||||
if (mouse->buttonLeftWasDown) {
|
||||
//***TODO*** Right now, this only processes top-level windows attached directly to the desktop.
|
||||
len = arrlenu(parent->children);
|
||||
for (x=len-1; x>=0; x--) {
|
||||
child = parent->children[x];
|
||||
// Are we clicking this widget?
|
||||
if (mouse->x >= child->x && mouse->y >= child->y && mouse->x < child->x + child->w && mouse->y < child->y + child->h) {
|
||||
// Is this the widget we originally clicked? Buttons must come up on the same widget they went down on.
|
||||
if (child == downOnWidget) {
|
||||
// Is this a Window?
|
||||
if (child->magic == MAGIC_WINDOW) {
|
||||
window = (WindowT *)child;
|
||||
// Bring window to top.
|
||||
arrdel(parent->children, x);
|
||||
arrput(parent->children, child);
|
||||
windowSetActive(window);
|
||||
} else {
|
||||
//***TODO*** Dispatch to proper control if the containing window is active.
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} // Left button was down last frame.
|
||||
|
||||
} // Left button down.
|
||||
// Proper child found.
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Not for this widget.
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -349,6 +366,13 @@ DesktopT *guiStartup(void) {
|
|||
// Create desktop and return it. Remember it for later.
|
||||
_guiDesktop = desktopNew();
|
||||
|
||||
// First thing the mouse is over is the desktop.
|
||||
_guiLastWidgetLeft = W(_guiDesktop);
|
||||
_guiLastWidgetLeftEvent = MOUSE_EVENT_NONE;
|
||||
// Synthesize a MOUSE_EVENT_IN for the desktop.
|
||||
//***TODO*** Uncomment this after removing 'mouse' from the parameter list.
|
||||
//if (_guiDesktop->base.mouseEventMethod) _guiDesktop->base.mouseEventMethod(W(_guiDesktop), 0, 0, MOUSE_EVENT_IN);
|
||||
|
||||
return _guiDesktop;
|
||||
}
|
||||
|
||||
|
@ -369,3 +393,17 @@ void *guiUserDataGet(WidgetT *widget) {
|
|||
void guiUserDataSet(WidgetT *widget, void *userData) {
|
||||
widget->userData = userData;
|
||||
}
|
||||
|
||||
|
||||
void guiWidgetPositionOnScreenGet(WidgetT *widget, uint16_t *x, uint16_t *y) {
|
||||
WidgetT *p = widget;
|
||||
|
||||
*x = 0;
|
||||
*y = 0;
|
||||
|
||||
do {
|
||||
*x += p->x;
|
||||
*y += p->y;
|
||||
p = p->parent;
|
||||
} while (p != NULL);
|
||||
}
|
||||
|
|
|
@ -76,14 +76,29 @@ enum ColorE {
|
|||
COLOR_COUNT
|
||||
};
|
||||
|
||||
// Mouse Events
|
||||
enum MouseE {
|
||||
MOUSE_EVENT_NONE = 0,
|
||||
MOUSE_EVENT_IN,
|
||||
MOUSE_EVENT_OUT,
|
||||
MOUSE_EVENT_LEFT_DOWN,
|
||||
MOUSE_EVENT_LEFT_HOLD,
|
||||
MOUSE_EVENT_LEFT_UP
|
||||
};
|
||||
|
||||
|
||||
typedef struct WidgetS WidgetT;
|
||||
typedef struct DesktopS DesktopT;
|
||||
typedef struct WidgetS WidgetT;
|
||||
typedef struct WindowS WindowT;
|
||||
|
||||
|
||||
extern int16_t _guiMetric[METRIC_COUNT];
|
||||
extern PixelT _guiColor[COLOR_COUNT];
|
||||
extern FontT *_guiFont;
|
||||
extern int16_t _guiMetric[METRIC_COUNT];
|
||||
extern PixelT _guiColor[COLOR_COUNT];
|
||||
extern FontT *_guiFont;
|
||||
extern WidgetT *_guiDragWidget;
|
||||
extern uint16_t _guiDragOffsetX;
|
||||
extern uint16_t _guiDragOffsetY;
|
||||
extern WindowT *_guiActiveWindow;
|
||||
|
||||
|
||||
void guiAttach(WidgetT *parent, WidgetT *child);
|
||||
|
@ -92,6 +107,7 @@ void guiDelete(WidgetT **widget);
|
|||
void guiDrawHighlightFrame(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, PixelT upperLeft, PixelT lowerRight);
|
||||
void guiDrawLine(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT pixel);
|
||||
void guiDrawFilledRectangle(int16_t x1, int16_t y1, int16_t x2, int16_t y2, PixelT pixel);
|
||||
void guiMousePositionOnWidgetGet(WidgetT *widget, MouseT *mouse, uint16_t *x, uint16_t *y);
|
||||
void guiPaint(WidgetT *widget);
|
||||
void guiProcessMouse(MouseT *mouse);
|
||||
WidgetT *guiRootGet(void);
|
||||
|
@ -100,6 +116,7 @@ DesktopT *guiStartup(void);
|
|||
void guiShutdown(void);
|
||||
void *guiUserDataGet(WidgetT *widget);
|
||||
void guiUserDataSet(WidgetT *widget, void *userData);
|
||||
void guiWidgetPositionOnScreenGet(WidgetT *widget, uint16_t *x, uint16_t *y);
|
||||
|
||||
|
||||
#endif // GUI_H
|
||||
|
|
|
@ -41,10 +41,21 @@ void logClose(void) {
|
|||
void logWrite(char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
#ifdef __linux__
|
||||
va_list args2;
|
||||
|
||||
va_copy(args2, args);
|
||||
vfprintf(stdout, format, args2);
|
||||
fflush(stdout);
|
||||
va_end(args2);
|
||||
#endif
|
||||
|
||||
if (_log) {
|
||||
va_start(args, format);
|
||||
vfprintf(_log, format, args);
|
||||
va_end(args);
|
||||
fflush(_log);
|
||||
}
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
|
|
@ -27,31 +27,34 @@
|
|||
|
||||
enum WidgetE {
|
||||
WIDGET_FLAG_DIRTY = 0,
|
||||
WIDGET_FLAG_ACTIVE,
|
||||
WIDGET_FLAG_OWNS_SURFACE
|
||||
};
|
||||
|
||||
|
||||
struct WidgetS;
|
||||
typedef struct WidgetS WidgetT;
|
||||
typedef struct WindowS WindowT;
|
||||
|
||||
|
||||
typedef void (*widgetCallback)(struct WidgetS *widget);
|
||||
typedef void (*widgetDelMethod)(struct WidgetS **widget);
|
||||
typedef void (*widgetPaintMethod)(struct WidgetS *widget);
|
||||
typedef void (*widgetMouseEventMethod)(struct WidgetS *widget, MouseT *mouse, uint16_t x, uint16_t y);
|
||||
typedef void (*widgetMouseEventMethod)(struct WidgetS *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
||||
|
||||
|
||||
typedef struct WidgetS {
|
||||
uint8_t magic; // Widget identifier constant
|
||||
uint8_t flags; // See above enum
|
||||
SurfaceT *surface; // Pointer to compositable surface or NULL
|
||||
WindowT *window; // The window holding this widget or NULL
|
||||
int16_t x; // Position of widget on parent
|
||||
int16_t y; // Position of widget on parent
|
||||
uint16_t w; // Width of widget
|
||||
uint16_t h; // Height of widget
|
||||
uint16_t marginX; // Pixels to skip when placing child widgets
|
||||
uint16_t marginY; // Pixels to skip when placing child widgets
|
||||
struct WidgetS **children; // List of children
|
||||
struct WidgetS *parent; // Parent of this widget
|
||||
WidgetT **children; // List of children
|
||||
WidgetT *parent; // Parent of this widget
|
||||
widgetDelMethod delMethod; // Delete method
|
||||
widgetPaintMethod paintMethod; // Paint method
|
||||
widgetMouseEventMethod mouseEventMethod; // Mouse event handler
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
|
||||
|
||||
static void windowDeactivateAll(WidgetT *widget);
|
||||
static void windowMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event);
|
||||
static void windowPaint(WidgetT *widget);
|
||||
|
||||
|
||||
static void windowDeactivateAll(WidgetT *widget) {
|
||||
|
@ -31,7 +33,7 @@ static void windowDeactivateAll(WidgetT *widget) {
|
|||
// Is this a Window?
|
||||
if (widget->magic == MAGIC_WINDOW) {
|
||||
// Deactivate it.
|
||||
GUI_CLEAR_FLAG((WindowT *)widget, WINDOW_FLAG_ACTIVE);
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE);
|
||||
guiSetWidgetAndChildrenDirty(widget);
|
||||
}
|
||||
|
||||
|
@ -57,15 +59,16 @@ void windowDel(WidgetT **widget) {
|
|||
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
|
||||
WindowT *win = (WindowT *)window;
|
||||
|
||||
win->base.magic = MAGIC_WINDOW;
|
||||
win->base.x = x;
|
||||
win->base.y = y;
|
||||
win->base.w = w;
|
||||
win->base.h = h;
|
||||
win->base.delMethod = windowDel;
|
||||
win->base.paintMethod = windowPaint;
|
||||
win->flags = 0;
|
||||
win->title = NULL;
|
||||
win->base.magic = MAGIC_WINDOW;
|
||||
win->base.x = x;
|
||||
win->base.y = y;
|
||||
win->base.w = w;
|
||||
win->base.h = h;
|
||||
win->base.delMethod = windowDel;
|
||||
win->base.paintMethod = windowPaint;
|
||||
win->base.mouseEventMethod = windowMouseEvent;
|
||||
win->flags = 0;
|
||||
win->title = NULL;
|
||||
|
||||
win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2;
|
||||
win->base.marginY += _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT];
|
||||
|
@ -84,6 +87,45 @@ WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_
|
|||
}
|
||||
|
||||
|
||||
static void windowMouseEvent(WidgetT *widget, MouseT *mouse, uint16_t x, uint16_t y, uint8_t event) {
|
||||
|
||||
WindowT *window = (WindowT *)widget;
|
||||
|
||||
(void)x;
|
||||
|
||||
// Raise window?
|
||||
if (event == MOUSE_EVENT_LEFT_UP && !GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) windowSetActive(window);
|
||||
|
||||
// Start dragging?
|
||||
if (event == MOUSE_EVENT_LEFT_DOWN && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
||||
// Are we on the draggable area of the titlebar / borders?
|
||||
if (y < _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]) {
|
||||
// Start dragging.
|
||||
_guiDragWidget = widget;
|
||||
_guiDragOffsetX = mouse->x - window->base.x;
|
||||
_guiDragOffsetY = mouse->y - window->base.y;
|
||||
}
|
||||
}
|
||||
|
||||
// Still dragging? We use raw mouse data here because it's possible to drag too quickly and trigger "OUT" events.
|
||||
if (_guiDragWidget == widget && mouse->buttonLeft && GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE)) {
|
||||
// Move window.
|
||||
window->base.x = mouse->x - _guiDragOffsetX;
|
||||
window->base.y = mouse->y - _guiDragOffsetY;
|
||||
// Keep it on the screen.
|
||||
if (window->base.x < 0) window->base.x = 0;
|
||||
if (window->base.x + window->base.w > vbeDisplayWidthGet()) window->base.x = vbeDisplayWidthGet() - window->base.w;
|
||||
if (window->base.y < 0) window->base.y = 0;
|
||||
if (window->base.y + window->base.h > vbeDisplayHeightGet()) window->base.y = vbeDisplayHeightGet() - window->base.h;
|
||||
}
|
||||
|
||||
// Be sure we stop dragging on mouse up or move out.
|
||||
if (_guiDragWidget == widget && event == MOUSE_EVENT_LEFT_UP) {
|
||||
_guiDragWidget = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
|
||||
WindowT *window = (WindowT *)malloc(sizeof(WindowT));
|
||||
WidgetT *widget = NULL;
|
||||
|
@ -102,16 +144,14 @@ WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title)
|
|||
}
|
||||
|
||||
|
||||
void windowPaint(WidgetT *window) {
|
||||
WindowT *w = (WindowT *)window;
|
||||
static void windowPaint(WidgetT *widget) {
|
||||
WindowT *w = (WindowT *)widget;
|
||||
uint16_t x2 = w->base.w - 1;
|
||||
uint16_t y2 = w->base.h - 1;
|
||||
PixelT background = GUI_GET_FLAG(w, WINDOW_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_INACTIVE];
|
||||
PixelT text = GUI_GET_FLAG(w, WINDOW_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE];
|
||||
PixelT background = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_INACTIVE];
|
||||
PixelT text = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_WINDOW_TITLE_TEXT_ACTIVE] : _guiColor[COLOR_WINDOW_TITLE_TEXT_INACTIVE];
|
||||
|
||||
//***NOTE*** This doesn't obey margins since desktops don't have any.
|
||||
|
||||
if (GUI_GET_FLAG(window, WIDGET_FLAG_DIRTY)) {
|
||||
if (GUI_GET_FLAG(widget, WIDGET_FLAG_DIRTY)) {
|
||||
vbeSurfaceSet(w->base.surface);
|
||||
|
||||
// Background.
|
||||
|
@ -129,14 +169,37 @@ void windowPaint(WidgetT *window) {
|
|||
|
||||
fontRender(_guiFont, w->title, text, background, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 16, _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 5);
|
||||
|
||||
GUI_CLEAR_FLAG(window, WIDGET_FLAG_DIRTY);
|
||||
GUI_CLEAR_FLAG(widget, WIDGET_FLAG_DIRTY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void windowSetActive(WindowT *window) {
|
||||
size_t len;
|
||||
int16_t i;
|
||||
WidgetT *parent = W(window)->parent;
|
||||
WidgetT *child;
|
||||
|
||||
// Deactivate all windows.
|
||||
windowDeactivateAll(guiRootGet());
|
||||
GUI_SET_FLAG(window, WINDOW_FLAG_ACTIVE);
|
||||
|
||||
// Activate us.
|
||||
GUI_SET_FLAG(W(window), WIDGET_FLAG_ACTIVE);
|
||||
|
||||
// Find our window in the widget list.
|
||||
len = arrlenu(parent->children);
|
||||
for (i=len-1; i>=0; i--) {
|
||||
child = parent->children[i];
|
||||
if (child == W(window)) {
|
||||
// Move to the top of the widget list.
|
||||
arrdel(parent->children, i);
|
||||
arrput(parent->children, child);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Tell the GUI.
|
||||
_guiActiveWindow = window;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -27,8 +27,7 @@
|
|||
|
||||
|
||||
enum WindowE {
|
||||
WINDOW_FLAG_ACTIVE = 0,
|
||||
WINDOW_FLAG_MODAL,
|
||||
WINDOW_FLAG_MODAL = 0,
|
||||
WINDOW_FLAG_RESIZABLE
|
||||
};
|
||||
|
||||
|
@ -43,7 +42,6 @@ typedef struct WindowS {
|
|||
void windowDel(WidgetT **widget);
|
||||
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
|
||||
WindowT *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title);
|
||||
void windowPaint(WidgetT *window);
|
||||
void windowSetActive(WindowT *window);
|
||||
void windowSetTitle(WindowT *window, char *title);
|
||||
|
||||
|
|
|
@ -29,6 +29,11 @@
|
|||
#include "button.h"
|
||||
|
||||
|
||||
void buttonClick(WidgetT *widget) {
|
||||
logWrite("'%s' was clicked.\n", ((ButtonT *)widget)->title);
|
||||
}
|
||||
|
||||
|
||||
void test(void) {
|
||||
MouseT *mouse = NULL;
|
||||
ImageT *pointer = NULL;
|
||||
|
@ -53,7 +58,7 @@ void test(void) {
|
|||
guiAttach(W(desktop), W(w2));
|
||||
guiAttach(W(desktop), W(w3));
|
||||
|
||||
b1 = buttonNew(25, 25, "Test Button", NULL);
|
||||
b1 = buttonNew(25, 25, "Test Button", buttonClick);
|
||||
guiAttach(W(w3), W(b1));
|
||||
|
||||
do {
|
||||
|
|
Loading…
Add table
Reference in a new issue