diff --git a/client/assets/mouse.png b/client/assets/mouse.png index 2e0e81b..6a73e61 100644 --- a/client/assets/mouse.png +++ b/client/assets/mouse.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d3b2222b2872dad2ddd16fb8fb061a51f9fe8a9cb70281a4841dd68b305a7da0 -size 5748 +oid sha256:27589e481b1ff800e49890b46849f126a566f41dc66c2c6a031dab0134ff2b05 +size 9768 diff --git a/client/assets/resize.png b/client/assets/resize.png new file mode 100644 index 0000000..b9703b6 --- /dev/null +++ b/client/assets/resize.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ff81ea75ecc36256faa0f4eed8c656f528cf069c302c343e4e9b97c35c9c4f5d +size 5685 diff --git a/client/src/gui/gui.c b/client/src/gui/gui.c index bcd6e56..480aec3 100644 --- a/client/src/gui/gui.c +++ b/client/src/gui/gui.c @@ -18,11 +18,16 @@ FontT *__guiFontVGA8x14 = NULL; FontT *__guiFontVGA8x16 = NULL; -static uint8_t _magicCount = 0; -static WidgetCatalogT *_widgetCatalog = NULL; -static uint8_t _guiRunning = 1; -static SurfaceT *_mousePointer = NULL; -static ColorT _mouseTransparency; +static uint8_t _magicCount = 0; +static WidgetCatalogT *_widgetCatalog = NULL; +static uint8_t _guiRunning = 1; +static SurfaceT *_mousePointer[MOUSE_COUNT] = { 0 }; +static ColorT _mouseTransparency = 0; +static uint8_t _mouseCurrent = MOUSE_POINTER; +static PointT _mouseHotspot[MOUSE_COUNT] = { + { 0, 0 }, + { 8, 8 } + }; void guiEventsDo(void) { @@ -40,7 +45,7 @@ void guiEventsDo(void) { // Paint mouse pointer. surfaceSet(__guiBackBuffer); - surfaceBlitWithTransparency(event.x, event.y, _mousePointer, _mouseTransparency); + surfaceBlitWithTransparency(event.x - _mouseHotspot[_mouseCurrent].x, event.y - _mouseHotspot[_mouseCurrent].y, _mousePointer[_mouseCurrent], _mouseTransparency); // Copy to screen. videoBlit(0, 0, __guiBackBuffer); @@ -50,6 +55,16 @@ void guiEventsDo(void) { } +uint8_t guiMousePointerGet(void) { + return _mouseCurrent; +} + + +void guiMousePointerSet(uint8_t pointer) { + _mouseCurrent = pointer; +} + + void guiRegister(WidgetRegisterT widgetRegister) { RegisterT *reg = widgetRegister(_magicCount); hmput(_widgetCatalog, _magicCount, reg); @@ -70,6 +85,8 @@ void guiRun(void) { void guiShutdown(void) { + uint8_t i; + DEL(__guiBaseColors); while (hmlen(_widgetCatalog) > 0) { @@ -84,7 +101,7 @@ void guiShutdown(void) { fontUnload(&__guiFontVGA8x14); fontUnload(&__guiFontVGA8x8); - surfaceDestroy(&_mousePointer); + for (i=0; iflags & WIN_RESIZE) { - x1 = w->base.r.x + w->base.r.w - 2; - x2 = x1 - 3; - y1 = w->base.r.y + w->base.r.h - 21; - surfaceLineH(x1, x2, y1, GUI_BLACK); - surfaceLineH(x1, x2, y1 + 1, GUI_WHITE); - x1 = w->base.r.x + w->base.r.w - 21; - y1 = w->base.r.y + w->base.r.h - 2; - y2 = y1 - 3; - surfaceLineV(x1, y1, y2, GUI_BLACK); - surfaceLineV(x1 + 1, y1, y2, GUI_WHITE); + w->resize1.x2 = w->base.r.x + w->base.r.w - 2; + w->resize1.x = w->resize1.x2 - 3; + w->resize1.y2 = w->base.r.y + w->base.r.h; + w->resize1.y = w->resize1.y2 - 21; + surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y, GUI_BLACK); + surfaceLineH(w->resize1.x, w->resize1.x2, w->resize1.y + 1, GUI_WHITE); + w->resize2.x2 = w->base.r.x + w->base.r.w; + w->resize2.x = w->resize2.x2 - 21; + w->resize2.y2 = w->base.r.y + w->base.r.h - 2; + w->resize2.y = w->resize2.y2 - 3; + surfaceLineV(w->resize2.x, w->resize2.y, w->resize2.y2, GUI_BLACK); + surfaceLineV(w->resize2.x + 1, w->resize2.y, w->resize2.y2, GUI_WHITE); + } else { + w->resize1.x = w->resize1.y = w->resize1.x2 = w->resize1.y2 = 0; + w->resize2.x = w->resize2.y = w->resize2.x2 = w->resize2.y2 = 0; } // Blit contents. @@ -175,6 +180,7 @@ static void windowCache(WindowT *w) { } +#include "image.h" // Passing "flags" as a default int provides proper alignment for the following va_args list. WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *title, int flags, ...) { int16_t width; @@ -192,10 +198,22 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl win->titlebar.x = win->titlebar.y = win->titlebar.x2 = win->titlebar.y2 = 0; win->minimize.x = win->minimize.y = win->minimize.x2 = win->minimize.y2 = 0; win->maximize.x = win->maximize.y = win->maximize.x2 = win->maximize.y2 = 0; + win->resize1.x = win->resize1.y = win->resize1.x2 = win->resize1.y2 = 0; + win->resize2.x = win->resize2.y = win->resize2.x2 = win->resize2.y2 = 0; win->bounds.x = win->bounds.y = win->bounds.x2 = win->bounds.y2 = 0; win->cached = NULL; win->content = NULL; + //***DEBUG*** Hackery to get contents before we have widgets. + static uint8_t image = 1; + static char name[16]; + width = 640; + height = 480; + sprintf(name, "back%d.png", image++); + win->content = imageLoad(name); + win->flags |= WIN_RESIZE; + + /* // If the window is resizable, we need to get two more arguments for the content size. if (win->flags & WIN_RESIZE) { va_start(args, flags); @@ -214,6 +232,7 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl surfaceSet(win->content); surfaceClear(GUI_LIGHTGRAY); surfaceSet(t); + */ // Do we need scrollbars? if (width > win->bounds.x2 - win->bounds.x) win->flags |= WIN_SCROLL_H; @@ -338,6 +357,17 @@ void windowMoveTo(WindowT *w, uint16_t x, uint16_t y) { w->titlebar.y2 += dy; } + if (w->flags & WIN_RESIZE) { + w->resize1.x += dx; + w->resize1.y += dy; + w->resize1.x2 += dx; + w->resize1.y2 += dy; + w->resize2.x += dx; + w->resize2.y += dy; + w->resize2.x2 += dx; + w->resize2.y2 += dy; + } + w->bounds.x += dx; w->bounds.y += dy; w->bounds.x2 += dx; @@ -355,6 +385,8 @@ void windowPaint(struct WidgetS *widget, ...) { int16_t py; int16_t xi; int16_t yi; + int16_t xc; + int16_t yc; WindowT *w = (WindowT *)widget; // Do we need redrawn? @@ -365,13 +397,17 @@ void windowPaint(struct WidgetS *widget, ...) { // Are we minimized? if (w->flags & WIN_IS_ICON) { - // Draw iconized version of contents. + // Draw iconized version of contents. There are too many counters here but it's the only way it worked reliably. yi = (surfaceHeightGet(w->content) - 1) / ICON_SIZE; xi = (surfaceWidthGet(w->content) - 1) / ICON_SIZE; - py = videoDisplayHeightGet() - ICON_SIZE - 2; - for (y=0; ycontent) - 1; y+=yi) { + py = videoDisplayHeightGet() - ICON_SIZE; + y = 0; + x = 0; + for (yc=0; yccontent) - 1; x+=xi) { + for (xc=0; xccontent, x, y)); } py++; @@ -416,14 +452,20 @@ void wmUpdate(EventT *event) { int16_t i; int16_t x2; int16_t y2; + uint8_t onResize = 0; WidgetT *widget; WindowT *win; - static uint8_t dragging = 0; - static PointT dragOffset = { 0 }; + static uint8_t resizing = 0; + static PointT resizeOffset = { 0 }; + static uint8_t dragging = 0; + static PointT dragOffset = { 0 }; // Do we have windows? if (arrlen(_windowList) > 0) { + // Mouse is always the default pointer unless something changes it for this frame. + guiMousePointerSet(MOUSE_POINTER); + // Paint all windows. _iconCount = 0; for (i=0; iflags & WIN_RESIZE) { + // Are we over the resize of the topmost window? + if ((event->x <= win->resize1.x2 && event->x >= win->resize1.x && event->y <= win->resize1.y2 && event->y >= win->resize1.y) || + (event->x <= win->resize2.x2 && event->x >= win->resize2.x && event->y <= win->resize2.y2 && event->y >= win->resize2.y) || + resizing) { + onResize = 1; + guiMousePointerSet(MOUSE_RESIZE); + } + } + // Is the left mouse button down? if (event->buttons & BUTTON_LEFT) { @@ -464,88 +518,101 @@ void wmUpdate(EventT *event) { } else { // Dragging. - // Did the button just go down? - if (event->flags & EVENT_FLAG_LEFT_DOWN) { + if (resizing) { - // Are we on the topmost window? - if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) { + } else { // Resizing - // Are we inside the window content? Most likely, check first. - if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { - //***TODO*** Send to window for processing. - } + // Did the button just go down? + if (event->flags & EVENT_FLAG_LEFT_DOWN) { - // Are we inside the close button? Does not include button frame on purpose. - if (win->flags & WIN_CLOSE && event->x < win->close.x2 && event->x > win->close.x && event->y < win->close.y2 && event->y > win->close.y) { - //***TODO*** Close. - } + // Are we on the topmost window? + if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) { - // Are we inside the title bar to begin dragging? Does not include titlebar frame on purpose. - if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) { - dragging = 1; - dragOffset.x = event->x - win->base.r.x; - dragOffset.y = event->y - win->base.r.y; - break; - } - - // Are we inside the minimize button? Does not include button frame on purpose. - if (win->flags & WIN_MINIMIZE &&event->x < win->minimize.x2 && event->x > win->minimize.x && event->y < win->minimize.y2 && event->y > win->minimize.y) { - win->flags |= WIN_IS_ICON; - } - - // Are we inside the maximize button? Does not include button frame on purpose. - if (win->flags & WIN_MAXIMIZE &&event->x < win->maximize.x2 && event->x > win->maximize.x && event->y < win->maximize.y2 && event->y > win->maximize.y) { - //***TODO*** Maximize. - } - - } else { // On topmost window. - - // Not over topmost window. Search backwards to find first window we're inside. - i = arrlen(_windowList) - 2; - if (i >= 0) { - for (; i>=0; i--) { - win = _windowList[i]; - // Get right/bottom of window. - x2 = win->base.r.x + win->base.r.w - 1; - y2 = win->base.r.y + win->base.r.h - 1; - // Inside this window? - if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) { - // Bring this window forward. - windowFocusSet(win); - // If we happened to be in the title bar, go ahead and start dragging. Does not include titlebar frame on purpose. - if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) { - dragging = 1; - dragOffset.x = event->x - win->base.r.x; - dragOffset.y = event->y - win->base.r.y; - } - break; - } + // Are we on the resizing area? + if (onResize) { + resizing = 1; + resizeOffset.x = event->x - win->base.r.x; + resizeOffset.y = event->y - win->base.r.y; + break; } - } - } // On topmost window. + // Are we inside the window content? Most likely, check first. + if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { + //***TODO*** Send to window for processing. + } - // Do we have minimized windows? - if (_iconCount > 0) { - // Are we inside the minimized icons area? - if (event->x < (ICON_SIZE + 1) * _iconCount && event->y >= videoDisplayHeightGet() - ICON_SIZE - 1) { - // Figure out which icon we're over. - x2 = 0; - for (i=0; iflags & WIN_IS_ICON) { - x2 += ICON_SIZE; - // This window? - if (event->x < x2) { - // Restore it and stop looking for icons. - _windowList[i]->flags &= ~WIN_IS_ICON; - windowFocusSet(_windowList[i]); + // Are we inside the close button? Does not include button frame on purpose. + if (win->flags & WIN_CLOSE && event->x < win->close.x2 && event->x > win->close.x && event->y < win->close.y2 && event->y > win->close.y) { + //***TODO*** Close. + } + + // Are we inside the title bar to begin dragging? Does not include titlebar frame on purpose. + if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) { + dragging = 1; + dragOffset.x = event->x - win->base.r.x; + dragOffset.y = event->y - win->base.r.y; + break; + } + + // Are we inside the minimize button? Does not include button frame on purpose. + if (win->flags & WIN_MINIMIZE &&event->x < win->minimize.x2 && event->x > win->minimize.x && event->y < win->minimize.y2 && event->y > win->minimize.y) { + win->flags |= WIN_IS_ICON; + } + + // Are we inside the maximize button? Does not include button frame on purpose. + if (win->flags & WIN_MAXIMIZE &&event->x < win->maximize.x2 && event->x > win->maximize.x && event->y < win->maximize.y2 && event->y > win->maximize.y) { + //***TODO*** Maximize. + } + + } else { // On topmost window. + + // Not over topmost window. Search backwards to find first window we're inside. + i = arrlen(_windowList) - 2; + if (i >= 0) { + for (; i>=0; i--) { + win = _windowList[i]; + // Get right/bottom of window. + x2 = win->base.r.x + win->base.r.w - 1; + y2 = win->base.r.y + win->base.r.h - 1; + // Inside this window? + if (event->x <= x2 && event->x >= win->base.r.x && event->y <= y2 && event->y >= win->base.r.y) { + // Bring this window forward. + windowFocusSet(win); + // If we happened to be in the title bar, go ahead and start dragging. Does not include titlebar frame on purpose. + if (event->x < win->titlebar.x2 && event->x > win->titlebar.x && event->y < win->titlebar.y2 && event->y > win->titlebar.y) { + dragging = 1; + dragOffset.x = event->x - win->base.r.x; + dragOffset.y = event->y - win->base.r.y; + } break; } - // Next! (Skips pixel between icons.) - x2++; } } - } // Minimized windows? + + } // On topmost window. + + // Do we have minimized windows? + if (_iconCount > 0) { + // Are we inside the minimized icons area? + if (event->x < (ICON_SIZE + 1) * _iconCount && event->y >= videoDisplayHeightGet() - ICON_SIZE) { + // Figure out which icon we're over. + x2 = 0; + for (i=0; iflags & WIN_IS_ICON) { + x2 += ICON_SIZE; + // This window? + if (event->x < x2) { + // Restore it and stop looking for icons. + _windowList[i]->flags &= ~WIN_IS_ICON; + windowFocusSet(_windowList[i]); + break; + } + // Next! (Skips pixel between icons.) + x2++; + } + } + } // Minimized windows? + } } } // Button just went down. @@ -558,6 +625,9 @@ void wmUpdate(EventT *event) { // Can no longer be dragging. dragging = 0; + + // Can no longer be resizing. + resizing = 0; } break; diff --git a/client/src/gui/wmwindow.h b/client/src/gui/wmwindow.h index 20d75e8..d7cabbe 100644 --- a/client/src/gui/wmwindow.h +++ b/client/src/gui/wmwindow.h @@ -23,6 +23,8 @@ typedef struct WindowS { RectT titlebar; // Coordinates of title bar, if any. RectT minimize; // Coordinates of minimize box, if any. RectT maximize; // Coordinates of maximize box, if any. + RectT resize1; // First resize area. + RectT resize2; // Second resize area. RectT bounds; // Inside edge of window frame. SurfaceT *content; // Actual window contents - widgets and such. SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing.