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"
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);
}
}

View file

@ -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);

View file

@ -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)) {

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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);
}

View file

@ -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

View file

@ -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;
}

View file

@ -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);

View file

@ -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 {