Complete rewrite of mouse code. It is now sane. I think.

This commit is contained in:
Scott Duensing 2021-10-17 20:39:01 -05:00
parent 04cce38be1
commit f507b0713b
11 changed files with 294 additions and 147 deletions

View file

@ -20,6 +20,9 @@
#include "button.h" #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) { void buttonDel(WidgetT **widget) {
ButtonT *b = (ButtonT *)*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; ButtonT *b = (ButtonT *)widget;
(void)x; (void)x;
(void)y; (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. // Fire callback on mouse up.
if (!mouse->buttonLeft && mouse->buttonLeftWasDown) { if (event == MOUSE_EVENT_LEFT_UP) {
if (b->clicked) b->clicked(widget); 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) { static void buttonPaint(WidgetT *widget) {
ButtonT *b = (ButtonT *)button; ButtonT *b = (ButtonT *)widget;
int16_t i; int16_t i;
uint16_t x1 = b->base.x + b->base.marginX; PixelT highlight = GUI_GET_FLAG(widget, WIDGET_FLAG_ACTIVE) ? _guiColor[COLOR_BUTTON_SHADOW] : _guiColor[COLOR_BUTTON_HIGHLIGHT];
uint16_t y1 = b->base.y + b->base.marginY; 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); vbeSurfaceSet(b->base.surface);
// Draw bezel. // Draw bezel.
for (i=0; i<_guiMetric[METRIC_BUTTON_BEZEL_SIZE]; i++) { 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). // 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). // 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);
} }
} }

View file

@ -35,9 +35,7 @@ typedef struct ButtonS {
void buttonDel(WidgetT **widget); void buttonDel(WidgetT **widget);
WidgetT *buttonInit(WidgetT *button, uint16_t x, uint16_t y, char *title, widgetCallback callback); 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); ButtonT *buttonNew(uint16_t x, uint16_t y, char *title, widgetCallback callback);
void buttonPaint(WidgetT *button);
void buttonSetTitle(ButtonT *button, char *title); void buttonSetTitle(ButtonT *button, char *title);

View file

@ -19,6 +19,10 @@
#include "desktop.h" #include "desktop.h"
#include "window.h"
static void desktopPaint(WidgetT *desktop);
void desktopDel(WidgetT **widget) { void desktopDel(WidgetT **widget) {
@ -33,14 +37,11 @@ void desktopDel(WidgetT **widget) {
WidgetT *desktopInit(WidgetT *desktop) { WidgetT *desktopInit(WidgetT *desktop) {
DesktopT *d = (DesktopT *)desktop; DesktopT *d = (DesktopT *)desktop;
d->base.magic = MAGIC_DESKTOP; d->base.magic = MAGIC_DESKTOP;
d->base.w = vbeDisplayWidthGet(); d->base.w = vbeDisplayWidthGet();
d->base.h = vbeDisplayHeightGet(); d->base.h = vbeDisplayHeightGet();
d->base.delMethod = desktopDel; d->base.delMethod = desktopDel;
d->base.paintMethod = desktopPaint; d->base.paintMethod = desktopPaint;
d->dragOffsetX = 0;
d->dragOffsetY = 0;
d->dragWidget = NULL;
GUI_SET_FLAG(desktop, WIDGET_FLAG_OWNS_SURFACE); GUI_SET_FLAG(desktop, WIDGET_FLAG_OWNS_SURFACE);
d->base.surface = vbeSurfaceCreate(d->base.w, d->base.h); 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; DesktopT *d = (DesktopT *)desktop;
if (GUI_GET_FLAG(desktop, WIDGET_FLAG_DIRTY)) { if (GUI_GET_FLAG(desktop, WIDGET_FLAG_DIRTY)) {

View file

@ -28,16 +28,12 @@
typedef struct DesktopS { typedef struct DesktopS {
WidgetT base; // Must be first in every widget WidgetT base; // Must be first in every widget
uint16_t dragOffsetX;
uint16_t dragOffsetY;
WidgetT *dragWidget;
} DesktopT; } DesktopT;
void desktopDel(WidgetT **widget); void desktopDel(WidgetT **widget);
WidgetT *desktopInit(WidgetT *desktop); WidgetT *desktopInit(WidgetT *desktop);
DesktopT *desktopNew(void); DesktopT *desktopNew(void);
void desktopPaint(WidgetT *desktop);
#endif // DESKTOP_H #endif // DESKTOP_H

View file

@ -24,12 +24,20 @@
#include "window.h" #include "window.h"
int16_t _guiMetric[METRIC_COUNT]; int16_t _guiMetric[METRIC_COUNT];
PixelT _guiColor[COLOR_COUNT]; PixelT _guiColor[COLOR_COUNT];
FontT *_guiFont = NULL; 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) { void guiAttach(WidgetT *parent, WidgetT *child) {
@ -39,6 +47,15 @@ void guiAttach(WidgetT *parent, WidgetT *child) {
child->parent = parent; child->parent = parent;
arrput(parent->children, child); 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 this widget does not own a surface, find one for it to draw on.
if (!GUI_GET_FLAG(child, WIDGET_FLAG_OWNS_SURFACE)) { if (!GUI_GET_FLAG(child, WIDGET_FLAG_OWNS_SURFACE)) {
p = child; p = child;
@ -54,8 +71,12 @@ void guiAttach(WidgetT *parent, WidgetT *child) {
child->surface = p->surface; 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) { if (child->magic == MAGIC_WINDOW) {
// New windows should be active.
windowSetActive((WindowT *)child); 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) { void guiPaint(WidgetT *widget) {
size_t len = arrlenu(widget->children); size_t len = arrlenu(widget->children);
size_t x; size_t x;
@ -210,94 +238,83 @@ void guiPaint(WidgetT *widget) {
void guiProcessMouse(MouseT *mouse) { void guiProcessMouse(MouseT *mouse) {
size_t len; guiProcessMouseChildren(W(_guiDesktop), mouse);
int16_t x; }
WidgetT *child;
WindowT *window;
WidgetT *parent = (WidgetT *)_guiDesktop;
static WidgetT *downOnWidget = NULL;
// Is the left button down?
if (mouse->buttonLeft) { static uint8_t guiProcessMouseChildren(WidgetT *widget, MouseT *mouse) {
// Was left button NOT down before? size_t len;
if (!mouse->buttonLeftWasDown) { int16_t x;
// Initial click. Are we already dragging something? uint16_t mx;
if (!_guiDesktop->dragWidget) { uint16_t my;
// Can we drag this? uint16_t sx;
len = arrlenu(parent->children); uint16_t sy;
for (x=len-1; x>=0; x--) { uint8_t event = MOUSE_EVENT_NONE;
child = parent->children[x];
// Are we clicking this widget? // Search children backwards for active widget before checking this widget.
if (mouse->x >= child->x && mouse->y >= child->y && mouse->x < child->x + child->w && mouse->y < child->y + child->h) { len = arrlenu(widget->children);
// Remember this widget for when the mouse button is released. Buttons must come up on the same widget they went down on. for (x=len-1; x>=0; --x) {
downOnWidget = child; if (guiProcessMouseChildren(widget->children[x], mouse)) {
// Is this a Window? return 1;
if (child->magic == MAGIC_WINDOW) { }
window = (WindowT *)child; }
// Is it the active window?
if (GUI_GET_FLAG(window, WINDOW_FLAG_ACTIVE)) { guiWidgetPositionOnScreenGet(widget, &sx, &sy);
// Are we on the draggable area of the titlebar / borders? guiMousePositionOnWidgetGet(widget, mouse, &mx, &my);
_guiDesktop->dragOffsetX = mouse->x - window->base.x;
_guiDesktop->dragOffsetY = mouse->y - window->base.y; // Serious hack to make window dragging work better.
if (_guiDesktop->dragOffsetY < _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]) { // This is because it's possible to move the mouse faster than METRIC_WINDOW_TITLE_GRAB_HEIGHT pixels
// Start dragging. // which causes it to switch widgets. So this prevents that.
_guiDesktop->dragWidget = child; if (widget->magic == MAGIC_WINDOW && widget == _guiDragWidget && mouse->buttonLeft && mouse->buttonLeftWasDown) {
} widget->mouseEventMethod(widget, mouse, mx, my, MOUSE_EVENT_LEFT_HOLD);
} return 1;
} }
break;
} // 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? // Proper child found.
return 1;
// 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.
// Not for this widget.
return 0;
} }
@ -349,6 +366,13 @@ DesktopT *guiStartup(void) {
// Create desktop and return it. Remember it for later. // Create desktop and return it. Remember it for later.
_guiDesktop = desktopNew(); _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; return _guiDesktop;
} }
@ -369,3 +393,17 @@ void *guiUserDataGet(WidgetT *widget) {
void guiUserDataSet(WidgetT *widget, void *userData) { void guiUserDataSet(WidgetT *widget, void *userData) {
widget->userData = 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);
}

View file

@ -76,14 +76,29 @@ enum ColorE {
COLOR_COUNT 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 DesktopS DesktopT;
typedef struct WidgetS WidgetT;
typedef struct WindowS WindowT;
extern int16_t _guiMetric[METRIC_COUNT]; extern int16_t _guiMetric[METRIC_COUNT];
extern PixelT _guiColor[COLOR_COUNT]; extern PixelT _guiColor[COLOR_COUNT];
extern FontT *_guiFont; extern FontT *_guiFont;
extern WidgetT *_guiDragWidget;
extern uint16_t _guiDragOffsetX;
extern uint16_t _guiDragOffsetY;
extern WindowT *_guiActiveWindow;
void guiAttach(WidgetT *parent, WidgetT *child); 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 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 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 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 guiPaint(WidgetT *widget);
void guiProcessMouse(MouseT *mouse); void guiProcessMouse(MouseT *mouse);
WidgetT *guiRootGet(void); WidgetT *guiRootGet(void);
@ -100,6 +116,7 @@ DesktopT *guiStartup(void);
void guiShutdown(void); void guiShutdown(void);
void *guiUserDataGet(WidgetT *widget); void *guiUserDataGet(WidgetT *widget);
void guiUserDataSet(WidgetT *widget, void *userData); void guiUserDataSet(WidgetT *widget, void *userData);
void guiWidgetPositionOnScreenGet(WidgetT *widget, uint16_t *x, uint16_t *y);
#endif // GUI_H #endif // GUI_H

View file

@ -41,10 +41,21 @@ void logClose(void) {
void logWrite(char *format, ...) { void logWrite(char *format, ...) {
va_list args; 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) { if (_log) {
va_start(args, format);
vfprintf(_log, format, args); vfprintf(_log, format, args);
va_end(args);
fflush(_log); fflush(_log);
} }
va_end(args);
} }

View file

@ -27,31 +27,34 @@
enum WidgetE { enum WidgetE {
WIDGET_FLAG_DIRTY = 0, WIDGET_FLAG_DIRTY = 0,
WIDGET_FLAG_ACTIVE,
WIDGET_FLAG_OWNS_SURFACE WIDGET_FLAG_OWNS_SURFACE
}; };
struct WidgetS; typedef struct WidgetS WidgetT;
typedef struct WindowS WindowT;
typedef void (*widgetCallback)(struct WidgetS *widget); typedef void (*widgetCallback)(struct WidgetS *widget);
typedef void (*widgetDelMethod)(struct WidgetS **widget); typedef void (*widgetDelMethod)(struct WidgetS **widget);
typedef void (*widgetPaintMethod)(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 { typedef struct WidgetS {
uint8_t magic; // Widget identifier constant uint8_t magic; // Widget identifier constant
uint8_t flags; // See above enum uint8_t flags; // See above enum
SurfaceT *surface; // Pointer to compositable surface or NULL 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 x; // Position of widget on parent
int16_t y; // Position of widget on parent int16_t y; // Position of widget on parent
uint16_t w; // Width of widget uint16_t w; // Width of widget
uint16_t h; // Height of widget uint16_t h; // Height of widget
uint16_t marginX; // Pixels to skip when placing child widgets uint16_t marginX; // Pixels to skip when placing child widgets
uint16_t marginY; // Pixels to skip when placing child widgets uint16_t marginY; // Pixels to skip when placing child widgets
struct WidgetS **children; // List of children WidgetT **children; // List of children
struct WidgetS *parent; // Parent of this widget WidgetT *parent; // Parent of this widget
widgetDelMethod delMethod; // Delete method widgetDelMethod delMethod; // Delete method
widgetPaintMethod paintMethod; // Paint method widgetPaintMethod paintMethod; // Paint method
widgetMouseEventMethod mouseEventMethod; // Mouse event handler widgetMouseEventMethod mouseEventMethod; // Mouse event handler

View file

@ -22,6 +22,8 @@
static void windowDeactivateAll(WidgetT *widget); 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) { static void windowDeactivateAll(WidgetT *widget) {
@ -31,7 +33,7 @@ static void windowDeactivateAll(WidgetT *widget) {
// Is this a Window? // Is this a Window?
if (widget->magic == MAGIC_WINDOW) { if (widget->magic == MAGIC_WINDOW) {
// Deactivate it. // Deactivate it.
GUI_CLEAR_FLAG((WindowT *)widget, WINDOW_FLAG_ACTIVE); GUI_CLEAR_FLAG(widget, WIDGET_FLAG_ACTIVE);
guiSetWidgetAndChildrenDirty(widget); 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) { WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
WindowT *win = (WindowT *)window; WindowT *win = (WindowT *)window;
win->base.magic = MAGIC_WINDOW; win->base.magic = MAGIC_WINDOW;
win->base.x = x; win->base.x = x;
win->base.y = y; win->base.y = y;
win->base.w = w; win->base.w = w;
win->base.h = h; win->base.h = h;
win->base.delMethod = windowDel; win->base.delMethod = windowDel;
win->base.paintMethod = windowPaint; win->base.paintMethod = windowPaint;
win->flags = 0; win->base.mouseEventMethod = windowMouseEvent;
win->title = NULL; win->flags = 0;
win->title = NULL;
win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2; win->base.marginX += _guiMetric[METRIC_WINDOW_BORDER_WIDTH] + 2;
win->base.marginY += _guiMetric[METRIC_WINDOW_TITLE_GRAB_HEIGHT]; 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 *windowNew(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title) {
WindowT *window = (WindowT *)malloc(sizeof(WindowT)); WindowT *window = (WindowT *)malloc(sizeof(WindowT));
WidgetT *widget = NULL; 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) { static void windowPaint(WidgetT *widget) {
WindowT *w = (WindowT *)window; WindowT *w = (WindowT *)widget;
uint16_t x2 = w->base.w - 1; uint16_t x2 = w->base.w - 1;
uint16_t y2 = w->base.h - 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 background = GUI_GET_FLAG(widget, WIDGET_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 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(widget, WIDGET_FLAG_DIRTY)) {
if (GUI_GET_FLAG(window, WIDGET_FLAG_DIRTY)) {
vbeSurfaceSet(w->base.surface); vbeSurfaceSet(w->base.surface);
// Background. // 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); 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) { void windowSetActive(WindowT *window) {
size_t len;
int16_t i;
WidgetT *parent = W(window)->parent;
WidgetT *child;
// Deactivate all windows.
windowDeactivateAll(guiRootGet()); 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;
} }

View file

@ -27,8 +27,7 @@
enum WindowE { enum WindowE {
WINDOW_FLAG_ACTIVE = 0, WINDOW_FLAG_MODAL = 0,
WINDOW_FLAG_MODAL,
WINDOW_FLAG_RESIZABLE WINDOW_FLAG_RESIZABLE
}; };
@ -43,7 +42,6 @@ typedef struct WindowS {
void windowDel(WidgetT **widget); void windowDel(WidgetT **widget);
WidgetT *windowInit(WidgetT *window, uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title); 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); 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 windowSetActive(WindowT *window);
void windowSetTitle(WindowT *window, char *title); void windowSetTitle(WindowT *window, char *title);

View file

@ -29,6 +29,11 @@
#include "button.h" #include "button.h"
void buttonClick(WidgetT *widget) {
logWrite("'%s' was clicked.\n", ((ButtonT *)widget)->title);
}
void test(void) { void test(void) {
MouseT *mouse = NULL; MouseT *mouse = NULL;
ImageT *pointer = NULL; ImageT *pointer = NULL;
@ -53,7 +58,7 @@ void test(void) {
guiAttach(W(desktop), W(w2)); guiAttach(W(desktop), W(w2));
guiAttach(W(desktop), W(w3)); guiAttach(W(desktop), W(w3));
b1 = buttonNew(25, 25, "Test Button", NULL); b1 = buttonNew(25, 25, "Test Button", buttonClick);
guiAttach(W(w3), W(b1)); guiAttach(W(w3), W(b1));
do { do {