diff --git a/client/src/gui/button.c b/client/src/gui/button.c index 97d74e5..676ea37 100644 --- a/client/src/gui/button.c +++ b/client/src/gui/button.c @@ -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); } } diff --git a/client/src/gui/button.h b/client/src/gui/button.h index bc30449..be92367 100644 --- a/client/src/gui/button.h +++ b/client/src/gui/button.h @@ -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); diff --git a/client/src/gui/desktop.c b/client/src/gui/desktop.c index 7e3fade..f2e92a5 100644 --- a/client/src/gui/desktop.c +++ b/client/src/gui/desktop.c @@ -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)) { diff --git a/client/src/gui/desktop.h b/client/src/gui/desktop.h index c6f88ec..48c2c7d 100644 --- a/client/src/gui/desktop.h +++ b/client/src/gui/desktop.h @@ -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 diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c index ab9690c..9ba4ea5 100644 --- a/client/src/gui/gui.c +++ b/client/src/gui/gui.c @@ -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); +} diff --git a/client/src/gui/gui.h b/client/src/gui/gui.h index da7da32..0f163b8 100644 --- a/client/src/gui/gui.h +++ b/client/src/gui/gui.h @@ -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 diff --git a/client/src/gui/log.c b/client/src/gui/log.c index 4034c1e..b500dfb 100644 --- a/client/src/gui/log.c +++ b/client/src/gui/log.c @@ -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); } diff --git a/client/src/gui/widget.h b/client/src/gui/widget.h index c255512..722d602 100644 --- a/client/src/gui/widget.h +++ b/client/src/gui/widget.h @@ -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 diff --git a/client/src/gui/window.c b/client/src/gui/window.c index 630ca20..ca4bbac 100644 --- a/client/src/gui/window.c +++ b/client/src/gui/window.c @@ -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; } diff --git a/client/src/gui/window.h b/client/src/gui/window.h index 998a8bb..599b0c6 100644 --- a/client/src/gui/window.h +++ b/client/src/gui/window.h @@ -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); diff --git a/client/src/main.c b/client/src/main.c index 836a9e5..180f457 100644 --- a/client/src/main.c +++ b/client/src/main.c @@ -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 {