diff --git a/roo-e/src/gui/gui.c b/roo-e/src/gui/gui.c index d216375..e00c902 100644 --- a/roo-e/src/gui/gui.c +++ b/roo-e/src/gui/gui.c @@ -54,7 +54,8 @@ static uint8_t _mouseCurrent = MOUSE_POINTER; static PointT _mouseHotspot[MOUSE_COUNT] = { { 0, 0 }, { 8, 8 } }; -static void guiDeleteListProcess(void); +static void guiDeleteListProcess(void); +static uint8_t widgetChildrenDirtyPaint(WidgetT *widget, uint8_t paint); static void guiDeleteListProcess(void) { @@ -212,10 +213,18 @@ void guiStop(void) { void widgetAdd(WidgetT *target, int16_t x, int16_t y, WidgetT *widget) { - widget->parent = target; + WidgetT *t = target; + + // ***TODO*** I don't like that this generic widget method needs specific knowledge of other widgets to work properly. + // If we're adding to a WindowT, then we REALLY want to add to the window's ScrollableT. + if ((t->magic == __MAGIC_WINDOW) && !(widget->flags & WIDGET_IS_WINDOW)) t = W(((WindowT *)t)->scroll); + + widget->parent = t; widget->r.x = x; widget->r.y = y; - arrput(target->children, widget); + arrput(t->children, widget); + + logWrite("Adding %s to %s\n", widget->reg->widgetName, t->reg->widgetName); } @@ -231,6 +240,42 @@ void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h) { } +uint8_t widgetChildrenDirty(WidgetT *widget) { + return widgetChildrenDirtyPaint(widget, 0); +} + + +static uint8_t widgetChildrenDirtyPaint(WidgetT *widget, uint8_t paint) { + int16_t x; + uint8_t updated = 0; + SurfaceT *t = surfaceGet(); + + // Are any child widgets dirty? + for (x=0; xchildren); x++) { + if (widgetDirtyGet(widget->children[x])) { + // Are we painting? Can it paint? + if (paint && widget->children[x]->reg->paint) { + // This is a flag for later that we need to update the cached surface. + updated = 1; + // Paint it. + widget->children[x]->reg->paint(widget->children[x]); + logWrite("Painted %s on %s\n", widget->children[x]->reg->widgetName, widget->children[x]->parent->reg->widgetName); + } else { + updated = 1; + } + } + } + surfaceSet(t); + + return updated; +} + + +uint8_t widgetChildrenPaint(WidgetT *widget) { + return widgetChildrenDirtyPaint(widget, 1); +} + + void widgetDestroy(WidgetT *widget) { // Add to list of widgets to delete. arrput(_deleteList, widget); @@ -265,6 +310,13 @@ uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent) { } +void widgetMove(WidgetT *widget, int16_t x, int16_t y) { + widget->r.x = x; + widget->r.y = y; + widgetDirtySet(widget, 1); +} + + void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y) { RectT r = widget->r; diff --git a/roo-e/src/gui/gui.h b/roo-e/src/gui/gui.h index db1f412..6b4368e 100644 --- a/roo-e/src/gui/gui.h +++ b/roo-e/src/gui/gui.h @@ -32,10 +32,11 @@ #include "font.h" -#define WIDGET_DIRTY 1 -#define WIDGET_HIDDEN 2 -#define WIDGET_DISABLED 4 -#define WIDGET_RAW_INPUT 8 +#define WIDGET_DIRTY 1 +#define WIDGET_HIDDEN 2 +#define WIDGET_DISABLED 4 +#define WIDGET_RAW_INPUT 8 +#define WIDGET_IS_WINDOW 16 // This lets us know if this widget is being used as one of the components of a window. #define CLICK_RAW_INPUT 1 #define CLICK_LEFT_CANCEL 2 @@ -81,7 +82,7 @@ typedef struct WidgetS { RectT r; // Outer bounds of widget. NOTE: USES WIDTH/HEIGHT, NOT X2/Y2! RegisterT *reg; // Registration information. void *data; // Pointer to arbitrary data for user. - uint8_t flags; // Widget flags (see defines above). + uint16_t flags; // Widget flags (see defines above). struct WidgetS *parent; // Who owns this widget? struct WidgetS **children; // Widgets contained in this widget. } WidgetT; @@ -107,6 +108,10 @@ extern FontT *__guiFontVGA8x16; #define MOUSE_COUNT 2 +#define SCROLL_SPEED_SLOW 5 +#define SCROLL_SPEED_FAST 25 + + #define GUI_BLACK __guiBaseColors[0] #define GUI_BLUE __guiBaseColors[1] #define GUI_GREEN __guiBaseColors[2] @@ -140,11 +145,14 @@ void guiStop(void); void widgetAdd(WidgetT *target, int16_t x, int16_t y, WidgetT *widget); void widgetBaseSet(WidgetT *widget, uint8_t magic, uint16_t w, uint16_t h); +uint8_t widgetChildrenDirty(WidgetT *widget); +uint8_t widgetChildrenPaint(WidgetT *widget); void widgetDestroy(WidgetT *widget); uint8_t widgetDirtyGet(WidgetT *widget); void widgetDirtySet(WidgetT *widget, uint8_t dirty); void widgetInputSetRaw(WidgetT *widget, uint8_t raw); uint8_t widgetIsInWidget(WidgetT *widget, WidgetT *parent); +void widgetMove(WidgetT *widget, int16_t x, int16_t y); void widgetPaintManually(WidgetT *widget, int16_t x, int16_t y); void widgetRemove(WidgetT *target, WidgetT *widget); diff --git a/roo-e/src/gui/widgets/hscroll.c b/roo-e/src/gui/widgets/hscroll.c index 3e755ab..fb79ab2 100644 --- a/roo-e/src/gui/widgets/hscroll.c +++ b/roo-e/src/gui/widgets/hscroll.c @@ -112,10 +112,10 @@ HscrollT *hscrollCreate(int16_t w, ClickHandlerT handler, void *data, ...) { h->max = 100; h->value = 1; - if (w < GADGET_SIZE * 3) w = GADGET_SIZE * 3; - widgetBaseSet(W(h), __MAGIC_HSCROLL, w, GADGET_SIZE); + hscrollWidthSet(h, w); + h->handler = handler; h->base.data = data; @@ -232,3 +232,13 @@ void hscrollValueSet(HscrollT *hscroll, int32_t value) { widgetDirtySet(W(hscroll), 1); } } + + +void hscrollWidthSet(HscrollT *hscroll, int16_t w) { + // Make sure it's at least wide enough to draw. + if (w < GADGET_SIZE * 3) w = GADGET_SIZE * 3; + + hscroll->base.r.w = w; + + widgetDirtySet(W(hscroll), 1); +} diff --git a/roo-e/src/gui/widgets/hscroll.h b/roo-e/src/gui/widgets/hscroll.h index 52dda67..866542f 100644 --- a/roo-e/src/gui/widgets/hscroll.h +++ b/roo-e/src/gui/widgets/hscroll.h @@ -49,6 +49,7 @@ void hscrollRangeSet(HscrollT *hscroll, int32_t min, int32_t max); RegisterT *hscrollRegister(uint8_t magic); int32_t hscrollValueGet(HscrollT *hscroll); void hscrollValueSet(HscrollT *hscroll, int32_t value); +void hscrollWidthSet(HscrollT *hscroll, int16_t w); #endif // HSCROLL_H diff --git a/roo-e/src/gui/widgets/scroll.c b/roo-e/src/gui/widgets/scroll.c index 351d0a0..f79364b 100644 --- a/roo-e/src/gui/widgets/scroll.c +++ b/roo-e/src/gui/widgets/scroll.c @@ -26,12 +26,15 @@ #include "../wmwindow.h" #include "scroll.h" +#include "array.h" + uint8_t __MAGIC_SCROLLABLE = 0; static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data); static void scrollableDestroy(struct WidgetS *widget, ...); +static void scrollableFixupSizes(ScrollableT *s); static void scrollablePaint(struct WidgetS *widget, ...); @@ -43,8 +46,6 @@ static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint (void)y; (void)event; - logWrite("Event from scrollable - %d %d\n", hscrollValueGet(s->scrollh), vscrollValueGet(s->scrollv)); - s->offset.x = hscrollValueGet(s->scrollh); s->offset.y = vscrollValueGet(s->scrollv); } @@ -61,14 +62,19 @@ ScrollableT *scrollableCreate(int16_t width, int16_t height, int16_t totalWidth, widgetBaseSet(W(s), __MAGIC_SCROLLABLE, width, height); + s->original.x = width; + s->original.y = height; + // Set up desired scroll bars. s->flags = flags; if (s->flags & SCROLLABLE_SCROLL_V) { + s->flags |= SCROLLABLE_NOT_SETUP; s->scrollv = vscrollCreate(height, scrollableClickHandler, s); vscrollRangeSet(s->scrollv, 0, totalHeight- 1); w = s->scrollv->base.r.w; // Used when creating horizontal scroll bar below. } if (s->flags & SCROLLABLE_SCROLL_H) { + s->flags |= SCROLLABLE_NOT_SETUP; s->scrollh = hscrollCreate(width - w, scrollableClickHandler, s); hscrollRangeSet(s->scrollh, 0, totalWidth - 1); } @@ -89,6 +95,11 @@ ScrollableT *scrollableCreate(int16_t width, int16_t height, int16_t totalWidth, static void scrollableDestroy(struct WidgetS *widget, ...) { ScrollableT *s = (ScrollableT *)widget; + uint16_t c; + + // Free children. + for (c=0; cbase.children); c++) widgetDestroy(s->base.children[c]); + arrfree(s->base.children); // Do not destroy scroll bars here - the parent owns them at this point. if (s->area) surfaceDestroy(&s->area); @@ -97,28 +108,80 @@ static void scrollableDestroy(struct WidgetS *widget, ...) { } +static void scrollableFixupSizes(ScrollableT *s) { + int16_t w = 0; + + // Vertical scrollbar. + if (s->scrollv) { + // Position for vertical scrollbar. + s->sizes.x = s->original.x - s->scrollv->base.r.w; + // Make scroll area smaller to make room for scrollbar. + s->base.r.w = s->original.x - s->scrollv->base.r.w; + // Resize vertical scrollbar. + vscrollHeightSet(s->scrollv, s->original.y); + // Position vertical scrollbar. + widgetMove(W(s->scrollv), s->base.r.x + s->sizes.x, s->base.r.y); + // Used when positioning vertical scrollbar below. + w = s->scrollv->base.r.w; + } else { + // No vertical scrollbar. Set this to a non-zero value. + s->sizes.x = s->base.r.w; + } + + // Horizontal scrollbar. + if (s->scrollh) { + // Position for horizontal scrollbar. + s->sizes.y = s->original.y - s->scrollh->base.r.h; + // Make scroll area smaller to make room for scrollbar. + s->base.r.h = s->original.y - s->scrollh->base.r.h; + // Resize horizontal scrollbar. + hscrollWidthSet(s->scrollh, s->original.x - w); + // Position horizontal scrollbar. + widgetMove(W(s->scrollh), s->base.r.x, s->base.r.y + s->sizes.y); + } else { + // No horizontal scrollbar. Set this to a non-zero value. + s->sizes.y = s->base.r.h; + } +} + + +void scrollableHeightSet(ScrollableT *scroll, int16_t h) { + scroll->original.y = h; + scrollableFixupSizes(scroll); + widgetDirtySet(W(scroll), 1); +} + + static void scrollablePaint(struct WidgetS *widget, ...) { - ScrollableT *s = (ScrollableT *)widget; + ScrollableT *s = (ScrollableT *)widget; + SurfaceT *t = surfaceGet(); + PointT o; if (widgetDirtyGet(widget)) { widgetDirtySet(widget, 0); // Finish initializing? - if (s->sizes.x == 0 && s->sizes.y == 0) { + if (s->flags & SCROLLABLE_NOT_SETUP) { + s->flags &= ~SCROLLABLE_NOT_SETUP; + scrollableFixupSizes(s); if (s->scrollh) { - s->sizes.y = s->base.r.h - s->scrollh->base.r.h; - s->base.r.h -= s->scrollh->base.r.h; + if (s->base.flags & WIDGET_IS_WINDOW) s->scrollh->base.flags |= WIDGET_IS_WINDOW; widgetAdd(s->base.parent, s->base.r.x, s->base.r.y + s->sizes.y, W(s->scrollh)); - } else { - s->sizes.y = s->base.r.h; } if (s->scrollv) { - s->sizes.x = s->base.r.w - s->scrollv->base.r.w; - s->base.r.w -= s->scrollv->base.r.w; + if (s->base.flags & WIDGET_IS_WINDOW) s->scrollv->base.flags |= WIDGET_IS_WINDOW; widgetAdd(s->base.parent, s->base.r.x + s->sizes.x, s->base.r.y, W(s->scrollv)); - } else { - s->sizes.x = s->base.r.w; } } + // Before painting contents, we need to offset everything by the window borders. + o.x = s->base.r.x; + o.y = s->base.r.y; + s->base.r.x = 0; + s->base.r.y = 0; + surfaceSet(s->area); + widgetChildrenPaint(widget); + surfaceSet(t); + s->base.r.x = o.x; + s->base.r.y = o.y; // Blit. surfaceBlit(s->base.r.x, s->base.r.y, s->offset.x, s->offset.y, s->sizes.x, s->sizes.y, s->area); } @@ -139,3 +202,11 @@ RegisterT *scrollableRegister(uint8_t magic) { return ® } + + +void scrollableWidthSet(ScrollableT *scroll, int16_t w) { + scroll->original.x = w; + scrollableFixupSizes(scroll); + widgetDirtySet(W(scroll), 1); +} + diff --git a/roo-e/src/gui/widgets/scroll.h b/roo-e/src/gui/widgets/scroll.h index 256fdfe..9446dd0 100644 --- a/roo-e/src/gui/widgets/scroll.h +++ b/roo-e/src/gui/widgets/scroll.h @@ -35,6 +35,7 @@ #define SCROLLABLE_NONE 0 #define SCROLLABLE_SCROLL_V 1 #define SCROLLABLE_SCROLL_H 2 +#define SCROLLABLE_NOT_SETUP 4 #define SCROLLABLE_STANDARD (SCROLLABLE_SCROLL_V | SCROLLABLE_SCROLL_H) @@ -46,6 +47,7 @@ typedef struct ScrollableS { HscrollT *scrollh; // Horizontal scroll bar. VscrollT *scrollv; // Vertical scroll bar. PointT sizes; // Scroll bar width and height info. + PointT original; // Original size of widget before being resized to make room for scollbars. uint8_t flags; // Flag bits. } ScrollableT; @@ -54,7 +56,9 @@ extern uint8_t __MAGIC_SCROLLABLE; // Magic ID assigned to us from the GUI. ScrollableT *scrollableCreate(int16_t width, int16_t height, int16_t totalWidth, int16_t totalHeight, int flags, ...); +void scrollableHeightSet(ScrollableT *scroll, int16_t h); RegisterT *scrollableRegister(uint8_t magic); +void scrollableWidthSet(ScrollableT *scroll, int16_t w); #endif // SCROLL_H diff --git a/roo-e/src/gui/widgets/vscroll.c b/roo-e/src/gui/widgets/vscroll.c index 5d11d47..64e2330 100644 --- a/roo-e/src/gui/widgets/vscroll.c +++ b/roo-e/src/gui/widgets/vscroll.c @@ -112,10 +112,10 @@ VscrollT *vscrollCreate(int16_t h, ClickHandlerT handler, void *data, ...) { v->max = 100; v->value = 1; - if (h < GADGET_SIZE * 3) h = GADGET_SIZE * 3; - widgetBaseSet(W(v), __MAGIC_VSCROLL, GADGET_SIZE, h); + vscrollHeightSet(v, h); + v->handler = handler; v->base.data = data; @@ -132,6 +132,16 @@ static void vscrollDestroy(struct WidgetS *widget, ...) { } +void vscrollHeightSet(VscrollT *vscroll, int16_t h) { + // Make sure it's at least tall enough to draw. + if (h < GADGET_SIZE * 3) h = GADGET_SIZE * 3; + + vscroll->base.r.h = h; + + widgetDirtySet(W(vscroll), 1); +} + + static void vscrollPaint(struct WidgetS *widget, ...) { VscrollT *v = (VscrollT *)widget; ColorT scrollBackgroundColor; diff --git a/roo-e/src/gui/widgets/vscroll.h b/roo-e/src/gui/widgets/vscroll.h index a1363fe..aee928d 100644 --- a/roo-e/src/gui/widgets/vscroll.h +++ b/roo-e/src/gui/widgets/vscroll.h @@ -45,6 +45,7 @@ extern uint8_t __MAGIC_VSCROLL; // Magic ID assigned to us from the GUI. void vscrollClickSet(VscrollT *vscroll, ClickHandlerT handler, void *data); VscrollT *vscrollCreate(int16_t h, ClickHandlerT handler, void *data, ...); +void vscrollHeightSet(VscrollT *vscroll, int16_t h); void vscrollRangeSet(VscrollT *vscroll, int32_t min, int32_t max); RegisterT *vscrollRegister(uint8_t magic); int32_t vscrollValueGet(VscrollT *vscroll); diff --git a/roo-e/src/gui/wmwindow.c b/roo-e/src/gui/wmwindow.c index 06058a4..07eff9b 100644 --- a/roo-e/src/gui/wmwindow.c +++ b/roo-e/src/gui/wmwindow.c @@ -31,16 +31,14 @@ uint8_t __MAGIC_WINDOW = 0; -static WindowT **_windowList = NULL; -static WindowT *_windowTop = NULL; -static int16_t _iconCount = 0; +static WindowT **_windowList = NULL; +static WindowT *_windowTop = NULL; +static int16_t _iconCount = 0; static void windowCache(WindowT *w, uint8_t redrawWindow); static void windowDestroy(struct WidgetS *widget, ...); static void windowPaint(struct WidgetS *widget, ...); -static void windowScrollHorizontalHandler(EventT *e, WindowT *w); -static void windowScrollVerticalHandler(EventT *e, WindowT *w); static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *localX, int16_t *localY); @@ -57,14 +55,12 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { int16_t ty2; int16_t originalX; int16_t originalY; - double d; - RectT originalBounds; - ColorT scrollBackgroundColor; - ColorT scrollThumbColor; ColorT titleBackgroundColor; - ColorT widgetColor; + ColorT gadgetColor; SurfaceT *target = surfaceGet(); + logWrite("Caching window\n"); + // Move the window to 0,0 to draw it into it's own surface. originalX = w->base.r.x; originalY = w->base.r.y; @@ -82,6 +78,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { // Do we need to create a surface? if (!w->cached) { w->cached = surfaceCreate(w->base.r.w, w->base.r.h); + logWrite("New cache surface\n"); } // Draw into cache. @@ -89,10 +86,8 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { if (redrawWindow) { // Determine some colors. - scrollBackgroundColor = (w == _windowTop) ? GUI_DARKGRAY : GUI_LIGHTGRAY; - scrollThumbColor = GUI_LIGHTGRAY; titleBackgroundColor = (w == _windowTop) ? GUI_DARKGRAY : GUI_LIGHTGRAY; - widgetColor = (w == _windowTop) ? GUI_LIGHTGRAY : GUI_DARKGRAY; + gadgetColor = (w == _windowTop) ? GUI_LIGHTGRAY : GUI_DARKGRAY; // Get ready! x1 = w->base.r.x; @@ -124,7 +119,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { w->close.x2 = tx1 - 1; w->close.y2 = ty2 - 1; surfaceBoxFilled(w->close.x + 1, w->close.y + 1, w->close.x2 - 1, w->close.y2 - 1, titleBackgroundColor); - surfaceBoxHighlight(w->close.x + 3, w->close.y + 8, w->close.x2 - 3, w->close.y2 - 8, GUI_WHITE, widgetColor); + surfaceBoxHighlight(w->close.x + 3, w->close.y + 8, w->close.x2 - 3, w->close.y2 - 8, GUI_WHITE, gadgetColor); surfaceBoxHighlight(w->close.x, w->close.y, w->close.x2, w->close.y2, GUI_WHITE, GUI_BLACK); } else { w->close.x = w->close.y = w->close.x2 = w->close.y2 = 0; @@ -140,8 +135,8 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { surfaceBoxFilled(w->maximize.x + 1, w->maximize.y + 1, w->maximize.x2 - 1, w->maximize.y2 - 1, titleBackgroundColor); surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y + 4, GUI_WHITE); surfaceLine(w->maximize.x + 4, w->maximize.y + 10, w->maximize.x + 10, w->maximize.y2 - 3, GUI_WHITE); - surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y + 4, widgetColor); - surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y2 - 3, widgetColor); + surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y + 4, gadgetColor); + surfaceLine(w->maximize.x2 - 3, w->maximize.y + 10, w->maximize.x2 - 9, w->maximize.y2 - 3, gadgetColor); surfaceBoxHighlight(w->maximize.x, w->maximize.y, w->maximize.x2, w->maximize.y2, GUI_WHITE, GUI_BLACK); } else { w->maximize.x = w->maximize.y = w->maximize.x2 = w->maximize.y2 = 0; @@ -155,7 +150,7 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { w->minimize.x2 = tx2 + GADGET_SIZE; w->minimize.y2 = ty2 - 1; surfaceBoxFilled(w->minimize.x + 1, w->minimize.y + 1, w->minimize.x2 - 1, w->minimize.y2 - 1, titleBackgroundColor); - surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, widgetColor); + surfaceBoxHighlight(w->minimize.x + 7, w->minimize.y + 7, w->minimize.x2 - 7, w->minimize.y2 - 7, GUI_WHITE, gadgetColor); surfaceBoxHighlight(w->minimize.x, w->minimize.y, w->minimize.x2, w->minimize.y2, GUI_WHITE, GUI_BLACK); } else { w->minimize.x = w->minimize.y = w->minimize.x2 = w->maximize.y2 = 0; @@ -196,111 +191,6 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { w->titlebar.x = w->titlebar.y = w->titlebar.x2 = w->titlebar.y2 = 0; } - // Vertical Scroll Bar? - if (w->flags & WIN_SCROLL_V) { - w->scrollv.x2 = x2; - w->scrollv.x = w->scrollv.x2 - (GADGET_SIZE - 1); - w->scrollv.y = y1; - w->scrollv.y2 = y2; - // Draw scroll bar. - surfaceBoxFilled(w->scrollv.x + 1, w->scrollv.y + 1, w->scrollv.x2 - 1, w->scrollv.y2 - 1, scrollBackgroundColor); - surfaceBoxHighlight(w->scrollv.x, w->scrollv.y, w->scrollv.x2, w->scrollv.y2, GUI_WHITE, GUI_BLACK); - surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y + (GADGET_SIZE - 1), GUI_BLACK); - surfaceLineH(w->scrollv.x + 1, w->scrollv.x2, w->scrollv.y2 - (GADGET_SIZE - 1), GUI_WHITE); - // Prepare font. - fontSet(__guiFontVGA8x8); - fontColorSet(widgetColor, scrollBackgroundColor); - // Draw arrows. - fontRender("\x1e", w->scrollv.x + 7, w->scrollv.y + 7); - fontRender("\x1f", w->scrollv.x + 7, w->scrollv.y2 - 12); - - x2 -= (GADGET_SIZE - 1); - } else { - w->scrollv.x = w->scrollv.y = w->scrollv.x2 = w->scrollv.y2 = 0; - } - - // Horizontal Scroll Bar? - if (w->flags & WIN_SCROLL_H) { - w->scrollh.x = x1; - w->scrollh.x2 = x2; - w->scrollh.y2 = y2; - w->scrollh.y = w->scrollh.y2 - (GADGET_SIZE - 1); - // Draw scroll bar. - surfaceBoxFilled(w->scrollh.x + 1, w->scrollh.y + 1, w->scrollh.x2 - 1, w->scrollh.y2 - 1, scrollBackgroundColor); - surfaceBoxHighlight(w->scrollh.x, w->scrollh.y, w->scrollh.x2, w->scrollh.y2, GUI_WHITE, GUI_BLACK); - surfaceLineV(w->scrollh.x + (GADGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_BLACK); - surfaceLineV(w->scrollh.x2 - (GADGET_SIZE - 1), w->scrollh.y + 1, w->scrollh.y2, GUI_WHITE); - // If we have both horizontal and vertical scroll bars, we need to fix a shadow. - if (w->flags & WIN_SCROLL_V) { - surfaceLineV(w->scrollh.x2 - 1, w->scrollh.y, w->scrollh.y2, GUI_BLACK); - surfaceLineV(w->scrollh.x2, w->scrollh.y, w->scrollh.y2, GUI_WHITE); - } - // Prepare font. - fontSet(__guiFontVGA8x8); - fontColorSet(widgetColor, scrollBackgroundColor); - // Draw arrows. - fontRender("\x11", w->scrollh.x + 7, w->scrollh.y + 7); - fontRender("\x10", w->scrollh.x2 - 12, w->scrollh.y + 7); - - y2 -= (GADGET_SIZE - 1); - } else { - w->scrollh.x = w->scrollh.y = w->scrollh.x2 = w->scrollh.y2 = 0; - } - - // Find content area. - w->bounds.x = x1; - w->bounds.y = y1; - w->bounds.x2 = x2; - w->bounds.y2 = y2; - - // Do we have content yet? - if (w->content) { - - // Vertical Scroll Bar Thumb? - if (w->flags & WIN_SCROLL_V) { - // Distance between arrow buttons on scroll bar. - i = w->scrollv.y2 - w->scrollv.y - (GADGET_SIZE * 2 - 2) - 2; - // Percentage to scale content height to scroll bar height. - d = (double)i / (double)surfaceHeightGet(w->content); - // Find position and size of thumb. - w->thumbv.x = w->scrollv.x + 1; - w->thumbv.x2 = w->scrollv.x2 - 1; - w->thumbv.y = w->scrollv.y + GADGET_SIZE + (w->offset.y * d); - w->thumbv.y2 = w->thumbv.y + ((w->bounds.y2 - w->bounds.y) * d); - // Clamp overflow due to doubles and my off-by-one brain. - if (w->thumbv.y2 >= w->thumbv.y + i - 1) w->thumbv.y2 = w->thumbv.y + i - 1; - // Draw thumb. - surfaceBoxFilled(w->thumbv.x + 1, w->thumbv.y + 1, w->thumbv.x2 - 1, w->thumbv.y2 - 1, scrollThumbColor); - surfaceBoxHighlight(w->thumbv.x, w->thumbv.y, w->thumbv.x2, w->thumbv.y2, GUI_WHITE, GUI_BLACK); - } else { - w->thumbv.x = w->thumbv.y = w->thumbv.x2 = w->thumbv.y2 = 0; - } - - // Horizontal Scroll Bar Thumb? - if (w->flags & WIN_SCROLL_H) { - // Distance between arrow buttons on scroll bar. - i = w->scrollh.x2 - w->scrollh.x - (GADGET_SIZE * 2 - 2) - 2; - // Percentage to scale content width to scroll bar width. - d = (double)i / (double)surfaceWidthGet(w->content); - // Find position and size of thumb. - w->thumbh.x = w->scrollh.x + GADGET_SIZE + (w->offset.x * d); - w->thumbh.x2 = w->thumbh.x + ((w->bounds.x2 - w->bounds.x) * d); - w->thumbh.y = w->scrollh.y + 1; - w->thumbh.y2 = w->scrollh.y2 - 1; - // Clamp overflow due to doubles and my off-by-one brain. - if (w->thumbh.x2 >= w->thumbh.x + i - 1) w->thumbh.x2 = w->thumbh.x + i - 1; - // Draw thumb. - surfaceBoxFilled(w->thumbh.x + 1, w->thumbh.y + 1, w->thumbh.x2 - 1, w->thumbh.y2 - 1, scrollThumbColor); - surfaceBoxHighlight(w->thumbh.x, w->thumbh.y, w->thumbh.x2, w->thumbh.y2, GUI_WHITE, GUI_BLACK); - } else { - w->thumbh.x = w->thumbh.y = w->thumbh.x2 = w->thumbh.y2 = 0; - } - - } else { // Do we have content yet? - w->thumbv.x = w->thumbv.y = w->thumbv.x2 = w->thumbv.y2 = 0; - w->thumbh.x = w->thumbh.y = w->thumbh.x2 = w->thumbh.y2 = 0; - } - // Resize handle. if (w->flags & WIN_RESIZE) { w->resize1.x2 = w->base.r.x + w->base.r.w - 2; @@ -320,27 +210,25 @@ static void windowCache(WindowT *w, uint8_t redrawWindow) { w->resize2.x = w->resize2.y = w->resize2.x2 = w->resize2.y2 = 0; } - } else { // Redraw window. + // Inside window frame. + w->bounds.x = x1; + w->bounds.y = y1; + w->bounds.x2 = x2; + w->bounds.y2 = y2; - // Since we didn't calculate them above, adjust bounds for content blit. - originalBounds = w->bounds; - w->bounds.x -= originalX; - w->bounds.y -= originalY; - w->bounds.x2 -= originalX; - w->bounds.y2 -= originalY; - } + // Resize scrollable to fill window. + if (w->scroll) { + w->scroll->base.r.x = x1; + w->scroll->base.r.y = y1; + scrollableWidthSet(w->scroll, x2 - x1); + scrollableHeightSet(w->scroll, y2 - y1); + } + } // Redraw window. - // Blit contents. - if (w->content) surfaceBlit(w->bounds.x, w->bounds.y, w->offset.x, w->offset.y, w->bounds.x2 - w->bounds.x, w->bounds.y2 - w->bounds.y, w->content); + widgetChildrenPaint(W(w)); // Fixup all the widget coordinates. - if (redrawWindow) { - windowMove(w, originalX, originalY); - } else { - w->bounds = originalBounds; - w->base.r.x = originalX; - w->base.r.y = originalY; - } + windowMove(w, originalX, originalY); surfaceSet(target); } @@ -352,7 +240,7 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl int16_t height; va_list args; WindowT *win = NULL; - SurfaceT *t = surfaceGet(); + int8_t sflags = SCROLLABLE_NONE; NEW(WindowT, win); memset(win, 0, sizeof(WindowT)); @@ -368,19 +256,20 @@ WindowT *windowCreate(uint16_t x, uint16_t y, uint16_t w, uint16_t h, char *titl width = va_arg(args, int); height = va_arg(args, int); va_end(args); + sflags = SCROLLABLE_STANDARD; } else { // Use whatever the default content area is. This causes an extra draw on create. Oh well. windowCache(win, 1); width = win->bounds.x2 - win->bounds.x; height = win->bounds.y2 - win->bounds.y; widgetDirtySet(W(win), 1); + if (flags & WIN_SCROLL_H) sflags |= SCROLLABLE_SCROLL_H; + if (flags & WIN_SCROLL_V) sflags |= SCROLLABLE_SCROLL_V; } - // Create content surface and clear it. - win->content = surfaceCreate(width, height); - surfaceSet(win->content); - surfaceClear(GUI_LIGHTGRAY); - surfaceSet(t); + win->scroll = scrollableCreate(w, h, width, height, sflags); + win->scroll->base.flags |= WIDGET_IS_WINDOW; + widgetAdd(W(win), 0, 0, W(win->scroll)); // Add to window list. arrput(_windowList, win); @@ -418,8 +307,6 @@ static void windowDestroy(struct WidgetS *widget, ...) { arrfree(window->base.children); // Free cached surface. if (window->cached) surfaceDestroy(&window->cached); - // Free content surface. - if (window->content) surfaceDestroy(&window->content); // Delete the window. DEL(window); // Fixup focus. @@ -494,24 +381,18 @@ void windowMaximizeRestore(WindowT *win) { // Restore to previous size. win->flags &= ~WIN_IS_MAX; win->base.r = win->restore; - win->offset = win->restoreOffset; } else { // Maximized? // Maximize window. Reposition if needed. win->flags |= WIN_IS_MAX; - // Remember current size and position. + // Remember current size. win->restore = win->base.r; - win->restoreOffset = win->offset; - - // Scroll contents to home. - win->offset.x = 0; - win->offset.y = 0; // Expand to full contents. - win->base.r.w = (win->base.r.w - (win->bounds.x2 - win->bounds.x) + surfaceWidthGet(win->content)); - win->base.r.h = (win->base.r.h - (win->bounds.y2 - win->bounds.y) + surfaceHeightGet(win->content)); + win->base.r.w = (win->base.r.w - (win->bounds.x2 - win->bounds.x) + win->scroll->original.x); + win->base.r.h = (win->base.r.h - (win->bounds.y2 - win->bounds.y) + win->scroll->original.y); // Does this go off the screen to the right? if (win->base.r.x + win->base.r.w >= videoDisplayWidthGet()) { @@ -592,28 +473,6 @@ void windowMove(WindowT *w, uint16_t x, uint16_t y) { w->titlebar.y2 += dy; } - if (w->flags & WIN_SCROLL_V) { - w->scrollv.x += dx; - w->scrollv.y += dy; - w->scrollv.x2 += dx; - w->scrollv.y2 += dy; - w->thumbv.x += dx; - w->thumbv.y += dy; - w->thumbv.x2 += dx; - w->thumbv.y2 += dy; - } - - if (w->flags & WIN_SCROLL_H) { - w->scrollh.x += dx; - w->scrollh.y += dy; - w->scrollh.x2 += dx; - w->scrollh.y2 += dy; - w->thumbh.x += dx; - w->thumbh.y += dy; - w->thumbh.x2 += dx; - w->thumbh.y2 += dy; - } - if (w->flags & WIN_RESIZE) { w->resize1.x += dx; w->resize1.y += dy; @@ -636,7 +495,7 @@ void windowMove(WindowT *w, uint16_t x, uint16_t y) { static void windowPaint(struct WidgetS *widget, ...) { - int16_t x; + int16_t x = 0; int16_t y; int16_t px; int16_t py; @@ -644,38 +503,22 @@ static void windowPaint(struct WidgetS *widget, ...) { int16_t yi; int16_t xc; int16_t yc; - WindowT *w = (WindowT *)widget; - SurfaceT *t = surfaceGet(); - - // Are any child widgets dirty? - y = 0; - for (x=0; xbase.children); x++) { - if (widgetDirtyGet(w->base.children[x])) { - y = 1; - if (w->base.children[x]->reg->paint) { - surfaceSet(w->content); - w->base.children[x]->reg->paint(w->base.children[x]); - } - } - } - surfaceSet(t); + WindowT *w = (WindowT *)widget; // Does the window itself need redrawn? if (widgetDirtyGet(widget)) { widgetDirtySet(widget, 0); - x = 1; - } else { - x = 0; + x = 1; // This is a flag for later that we need to update the cached surface. } // Did a widget or the window need redrawn? - if (x || y) windowCache(w, x); + if (x || widgetChildrenDirty(widget)) windowCache(w, x); // Are we minimized? if (w->flags & WIN_IS_ICON) { // 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; + yi = (surfaceHeightGet(w->scroll->area) - 1) / ICON_SIZE; + xi = (surfaceWidthGet(w->scroll->area) - 1) / ICON_SIZE; py = videoDisplayHeightGet() - ICON_SIZE; y = 0; x = 0; @@ -684,7 +527,7 @@ static void windowPaint(struct WidgetS *widget, ...) { px = (ICON_SIZE + 1) * _iconCount; for (xc=0; xccontent, x, y)); + surfacePixelSet(px++, py, surfacePixelGet(w->scroll->area, x, y)); } py++; } @@ -714,6 +557,7 @@ RegisterT *windowRegister(uint8_t magic) { void windowResize(WindowT *win, uint16_t width, uint16_t height) { + /* int16_t delta; // Too small? @@ -750,102 +594,7 @@ void windowResize(WindowT *win, uint16_t width, uint16_t height) { win->base.r.h =height; windowCache(win, 1); } -} - - -static void windowScrollHorizontalHandler(EventT *e, WindowT *w) { - - // Clicking in left arrow? - if (e->x <= w->scrollh.x + GADGET_SIZE) { - // Move content left. - w->offset.x -= SCROLL_SPEED_SLOW; - // Clip. - if (w->offset.x < 0) w->offset.x = 0; - // Update. - windowCache(w, 1); - return; - } - - // Clicking in right arrow? - if (e->x >= w->scrollh.x2 - GADGET_SIZE) { - // Move content right. - w->offset.x += SCROLL_SPEED_SLOW; - // Clip. - if (w->offset.x > surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x)) w->offset.x = surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x); - // Update. - windowCache(w, 1); - return; - } - - // Clicking left of thumb? Also fakes dragging. - if (e->x < w->thumbh.x) { - // Move content left. - w->offset.x -= SCROLL_SPEED_FAST; - // Clip. - if (w->offset.x < 0) w->offset.x = 0; - // Update. - windowCache(w, 1); - return; - } - - // Clicking right of thumb? Also fakes dragging. - if (e->x > w->thumbh.x2) { - // Move content right. - w->offset.x += SCROLL_SPEED_FAST; - // Clip. - if (w->offset.x > surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x)) w->offset.x = surfaceWidthGet(w->content) - (w->bounds.x2 - w->bounds.x); - // Update. - windowCache(w, 1); - return; - } -} - - -static void windowScrollVerticalHandler(EventT *e, WindowT *w) { - - // Clicking in up arrow? - if (e->y <= w->scrollv.y + GADGET_SIZE) { - // Move content up. - w->offset.y -= SCROLL_SPEED_SLOW; - // Clip. - if (w->offset.y < 0) w->offset.y = 0; - // Update. - windowCache(w, 1); - return; - } - - // Clicking in down arrow? - if (e->y >= w->scrollv.y2 - GADGET_SIZE) { - // Move content down. - w->offset.y += SCROLL_SPEED_SLOW; - // Clip. - if (w->offset.y > surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y)) w->offset.y = surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y); - // Update. - windowCache(w, 1); - return; - } - - // Clicking above thumb? Also fakes dragging. - if (e->y < w->thumbv.y) { - // Move content up. - w->offset.y -= SCROLL_SPEED_FAST; - // Clip. - if (w->offset.y < 0) w->offset.y = 0; - // Update. - windowCache(w, 1); - return; - } - - // Clicking below thumb? Also fakes dragging. - if (e->y > w->thumbv.y2) { - // Move content down. - w->offset.y += SCROLL_SPEED_FAST; - // Clip. - if (w->offset.y > surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y)) w->offset.y = surfaceHeightGet(w->content) - (w->bounds.y2 - w->bounds.y); - // Update. - windowCache(w, 1); - return; - } + */ } @@ -936,7 +685,6 @@ void wmUpdate(EventT *event) { // Is the left mouse button down? if (event->buttons & BUTTON_LEFT) { - /* // DEBUG - draw active regions. surfaceSet(__guiBackBuffer); surfaceBox(win->base.r.x, win->base.r.y, x2, y2, GUI_YELLOW); @@ -945,6 +693,7 @@ void wmUpdate(EventT *event) { surfaceBox(win->titlebar.x, win->titlebar.y, win->titlebar.x2, win->titlebar.y2, GUI_LIGHTCYAN); surfaceBox(win->minimize.x, win->minimize.y, win->minimize.x2, win->minimize.y2, GUI_LIGHTGREEN); surfaceBox(win->maximize.x, win->maximize.y, win->maximize.x2, win->maximize.y2, GUI_RED); + /* surfaceBox(win->scrollv.x, win->scrollv.y, win->scrollv.x2, win->scrollv.y2, GUI_BLUE); surfaceBox(win->scrollh.x, win->scrollh.y, win->scrollh.x2, win->scrollh.y2, GUI_BROWN); */ @@ -1013,18 +762,6 @@ void wmUpdate(EventT *event) { break; } - // Are we inside the vertical scroll bar? Does not include frame on purpose. - if (win->flags & WIN_SCROLL_V &&event->x < win->scrollv.x2 && event->x > win->scrollv.x && event->y < win->scrollv.y2 && event->y > win->scrollv.y) { - windowScrollVerticalHandler(event, win); - break; - } - - // Are we inside the horizontal scroll bar? Does not include frame on purpose. - if (win->flags & WIN_SCROLL_H &&event->x < win->scrollh.x2 && event->x > win->scrollh.x && event->y < win->scrollh.y2 && event->y > win->scrollh.y) { - windowScrollHorizontalHandler(event, win); - break; - } - } else { // On topmost window. // Not over topmost window. Search backwards to find first window we're inside. @@ -1081,17 +818,7 @@ void wmUpdate(EventT *event) { } else { // Button just went down / button being held down. - // Are we inside the vertical scroll bar? Does not include frame on purpose. - if (win->flags & WIN_SCROLL_V &&event->x < win->scrollv.x2 && event->x > win->scrollv.x && event->y < win->scrollv.y2 && event->y > win->scrollv.y) { - windowScrollVerticalHandler(event, win); - break; - } - - // Are we inside the horizontal scroll bar? Does not include frame on purpose. - if (win->flags & WIN_SCROLL_H &&event->x < win->scrollh.x2 && event->x > win->scrollh.x && event->y < win->scrollh.y2 && event->y > win->scrollh.y) { - windowScrollHorizontalHandler(event, win); - break; - } + // Nada } // Left button held down. @@ -1138,6 +865,7 @@ static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *loca int16_t i; WidgetT *widget; + /* // Are we over the provided window? if (event->x <= win->bounds.x2 && event->x >= win->bounds.x && event->y <= win->bounds.y2 && event->y >= win->bounds.y) { // Find window-local mouse coordinates. @@ -1152,6 +880,7 @@ static WidgetT *wuWidgetUnderMouseGet(WindowT *win, EventT *event, int16_t *loca } } } + */ return NULL; } diff --git a/roo-e/src/gui/wmwindow.h b/roo-e/src/gui/wmwindow.h index 509576f..e435fbc 100644 --- a/roo-e/src/gui/wmwindow.h +++ b/roo-e/src/gui/wmwindow.h @@ -29,11 +29,11 @@ #include "gui.h" +#include "widgets/scroll.h" + #define ICON_SIZE 32 #define GADGET_SIZE 20 -#define SCROLL_SPEED_SLOW 5 // ***TODO*** Move into GUI after we get scrollbar widgets. -#define SCROLL_SPEED_FAST 25 #define WIN_NONE 0 @@ -50,25 +50,28 @@ typedef struct WindowS { - WidgetT base; // Required by all widgets. - char *title; // Title of window. - uint8_t flags; // Window flags (see defines above). - RectT close; // Coordinates of close box, if any. - 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 scrollv; // Vertical scroll bar. - RectT scrollh; // Horizontal scroll bar. - RectT thumbv; // Vertical scroll bar thumb. - RectT thumbh; // Horizontal scroll bar thumb. - RectT bounds; // Inside edge of window frame. - RectT restore; // Size of window if they restore from maximized. - PointT restoreOffset; // Scroll position if they restore from maximized. - PointT offset; // Content scroll offset in window. - SurfaceT *content; // Actual window contents - widgets and such. - SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing. + WidgetT base; // Required by all widgets. + char *title; // Title of window. + uint8_t flags; // Window flags (see defines above). + RectT close; // Coordinates of close box, if any. + 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. + ScrollableT *scroll; // Window contents and scroll bars. + RectT restore; // Size of window if they restore from maximized. + PointT restoreOffset; // Scroll position if they restore from maximized. + RectT bounds; // Inside edge of window frame. + /* + RectT scrollv; // Vertical scroll bar. + RectT scrollh; // Horizontal scroll bar. + RectT thumbv; // Vertical scroll bar thumb. + RectT thumbh; // Horizontal scroll bar thumb. + PointT offset; // Content scroll offset in window. + SurfaceT *content; // Actual window contents - widgets and such. + */ + SurfaceT *cached; // Once rendered, keep a cached copy for faster redrawing. } WindowT;