New ScrollableT windows are rendering. No clicking yet.

This commit is contained in:
Scott Duensing 2022-08-16 17:24:46 -05:00
parent 3bc40f02a5
commit 105a8a63a2
10 changed files with 255 additions and 366 deletions

View file

@ -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; x<arrlen(widget->children); 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;

View file

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

View file

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

View file

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

View file

@ -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; c<arrlen(s->base.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 &reg;
}
void scrollableWidthSet(ScrollableT *scroll, int16_t w) {
scroll->original.x = w;
scrollableFixupSizes(scroll);
widgetDirtySet(W(scroll), 1);
}

View file

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

View file

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

View file

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

View file

@ -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; x<arrlen(w->base.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; xc<ICON_SIZE; xc++) {
x += xi;
surfacePixelSet(px++, py, surfacePixelGet(w->content, 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;
}

View file

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