diff --git a/roo-e/roo-e.pro b/roo-e/roo-e.pro index 45d2adf..1150cfa 100644 --- a/roo-e/roo-e.pro +++ b/roo-e/roo-e.pro @@ -59,6 +59,7 @@ HEADERS += \ src/gui/widgets/picture.h \ src/gui/widgets/radio.h \ src/gui/widgets/hscroll.h \ + src/gui/widgets/scroll.h \ src/gui/widgets/vscroll.h \ src/gui/wmwindow.h \ src/os.h \ @@ -81,6 +82,7 @@ SOURCES += \ src/gui/widgets/picture.c \ src/gui/widgets/radio.c \ src/gui/widgets/hscroll.c \ + src/gui/widgets/scroll.c \ src/gui/widgets/vscroll.c \ src/gui/wmwindow.c \ src/main.c \ diff --git a/roo-e/src/gui/gui-all.h b/roo-e/src/gui/gui-all.h index b67eef2..63db501 100644 --- a/roo-e/src/gui/gui-all.h +++ b/roo-e/src/gui/gui-all.h @@ -38,6 +38,7 @@ #include "widgets/radio.h" #include "widgets/vscroll.h" #include "widgets/hscroll.h" +#include "widgets/scroll.h" #endif // GUIALL_H diff --git a/roo-e/src/gui/gui.c b/roo-e/src/gui/gui.c index afb6453..5128491 100644 --- a/roo-e/src/gui/gui.c +++ b/roo-e/src/gui/gui.c @@ -199,6 +199,7 @@ uint8_t guiStartup(int16_t width, int16_t height, int16_t depth) { guiRegister(radioRegister); guiRegister(vscrollRegister); guiRegister(hscrollRegister); + guiRegister(scrollableRegister); // After hscroll and vscroll. return SUCCESS; } diff --git a/roo-e/src/gui/widgets/scroll.c b/roo-e/src/gui/widgets/scroll.c new file mode 100644 index 0000000..9a7287c --- /dev/null +++ b/roo-e/src/gui/widgets/scroll.c @@ -0,0 +1,130 @@ +/* + * Roo/E, the Kangaroo Punch Portable GUI Toolkit + * Copyright (C) 2022 Scott Duensing + * + * http://kangaroopunch.com + * + * + * This file is part of Roo/E. + * + * Roo/E is free software: you can redistribute it and/or modify it under the + * terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Roo/E. If not, see . + * + */ + + +#include "../image.h" + +#include "scroll.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 scrollablePaint(struct WidgetS *widget, ...); + + +static void scrollableClickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) { +} + + +// Passing "flags" as a default int provides proper alignment for the following va_args list. +ScrollableT *scrollableCreate(int16_t width, int16_t height, int16_t totalWidth, int16_t totalHeight, int flags, ...) { + ScrollableT *s = NULL; + SurfaceT *t = surfaceGet(); + int16_t w = 0; + + NEW(ScrollableT, s); + memset(s, 0, sizeof(ScrollableT)); + + // Set up desired scroll bars. + s->flags = flags; + if (s->flags & SCROLLABLE_SCROLL_V) { + s->scrollv = vscrollCreate(height, scrollableClickHandler, NULL); + vscrollRangeSet(s->scrollv, 0, totalHeight- 1); + w = s->scrollv->base.r.w; + } + if (s->flags & SCROLLABLE_SCROLL_H) { + s->scrollh = hscrollCreate(width - w, scrollableClickHandler, NULL); + hscrollRangeSet(s->scrollh, 0, totalWidth - 1); + } + + // Create scrollable surface. + s->area = surfaceCreate(totalWidth, totalHeight); + if (!s->area) { + DEL(s); + return NULL; + } + surfaceSet(s->area); + surfaceClear(GUI_LIGHTBLUE); + surfaceSet(t); + + widgetBaseSet(W(s), __MAGIC_SCROLLABLE, width, height); + + return s; +} + + +static void scrollableDestroy(struct WidgetS *widget, ...) { + ScrollableT *s = (ScrollableT *)widget; + + if (s->scrollh) widgetDestroy(W(s->scrollh)); + if (s->scrollv) widgetDestroy(W(s->scrollv)); + if (s->area) surfaceDestroy(&s->area); + + DEL(s); +} + + +static void scrollablePaint(struct WidgetS *widget, ...) { + ScrollableT *s = (ScrollableT *)widget; + int16_t width; + int16_t height; + + if (widgetDirtyGet(widget)) { + widgetDirtySet(widget, 0); + // Find height and width of blittable area, based on presence of scrollbars. + if (s->scrollh) { + height = s->base.r.h - s->scrollh->base.r.h; + widgetPaintManually(W(s->scrollh), s->base.r.x, s->base.r.y + height); + } else { + height = s->base.r.h; + } + if (s->scrollv) { + width = s->base.r.w - s->scrollv->base.r.w; + widgetPaintManually(W(s->scrollv), s->base.r.x + width, s->base.r.y); + } else { + width = s->base.r.w; + } + // Blit. + surfaceBlit(s->base.r.x, s->base.r.y, s->offset.x, s->offset.y, width, height, s->area); + } +} + + +RegisterT *scrollableRegister(uint8_t magic) { + static RegisterT reg = { + "Scrollable", + NULL, // No default on-click handler. + scrollableDestroy, + scrollablePaint, + NULL // No unregister handler. + }; + + // One-time widget startup code. + __MAGIC_SCROLLABLE = magic; + + return ® +} diff --git a/roo-e/src/gui/widgets/scroll.h b/roo-e/src/gui/widgets/scroll.h new file mode 100644 index 0000000..fadd216 --- /dev/null +++ b/roo-e/src/gui/widgets/scroll.h @@ -0,0 +1,59 @@ +/* + * Roo/E, the Kangaroo Punch Portable GUI Toolkit + * Copyright (C) 2022 Scott Duensing + * + * http://kangaroopunch.com + * + * + * This file is part of Roo/E. + * + * Roo/E is free software: you can redistribute it and/or modify it under the + * terms of the GNU Affero General Public License as published by the Free + * Software Foundation, either version 3 of the License, or (at your option) + * any later version. + * + * Roo/E is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU Affero General Public License + * along with Roo/E. If not, see . + * + */ + + +#ifndef SCROLL_H +#define SCROLL_H + + +#include "../gui.h" +#include "hscroll.h" +#include "vscroll.h" + + +#define SCROLLABLE_NONE 0 +#define SCROLLABLE_SCROLL_V 1 +#define SCROLLABLE_SCROLL_H 2 + +#define SCROLLABLE_STANDARD (SCROLLABLE_SCROLL_V | SCROLLABLE_SCROLL_H) + + +typedef struct ScrollableS { + WidgetT base; // Required by all widgets. + PointT offset; // View offset. + SurfaceT *area; // Scrollable area buffer. + HscrollT *scrollh; // Horizontal scroll bar. + VscrollT *scrollv; // Vertical scroll bar. + uint8_t flags; // Flag bits. +} ScrollableT; + + +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, ...); +RegisterT *scrollableRegister(uint8_t magic); + + +#endif // SCROLL_H diff --git a/roo-e/src/main.c b/roo-e/src/main.c index 9f239e3..37b8a49 100644 --- a/roo-e/src/main.c +++ b/roo-e/src/main.c @@ -27,7 +27,7 @@ VscrollT *_v = NULL; -VscrollT *_h = NULL; +HscrollT *_h = NULL; void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) { @@ -37,20 +37,19 @@ void clickHandler(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void * int main(int argc, char *argv[]) { - char title[256]; - uint16_t i; - WindowT *w = NULL; - LabelT *l = NULL; - ButtonT *b = NULL; - CheckboxT *c = NULL; - RadioT *r = NULL; + char title[256]; + uint16_t i; + WindowT *w = NULL; + LabelT *l = NULL; + ButtonT *b = NULL; + CheckboxT *c = NULL; + RadioT *r = NULL; + ScrollableT *s = NULL; // frame // scrollarea - // vscroll - // hscroll // listbox // textbox // up/down @@ -69,7 +68,7 @@ int main(int argc, char *argv[]) { for (i=1; i<4; i++) { sprintf(title, "Testing %d", i); - w = windowCreate(i * 50, i * 50, 300, 200, title, WIN_STANDARD, 640, 480); + w = windowCreate(i * 50, i * 50, 600, 400, title, WIN_STANDARD, 640, 480); l = labelCreate(LABEL_ALIGN_LEFT, __guiFontVGA8x16, "Label"); labelColorSet(l, __guiBaseColors[i], GUI_BLACK); @@ -102,7 +101,10 @@ int main(int argc, char *argv[]) { _h = hscrollCreate(100, clickHandler, NULL); hscrollRangeSet(_h, 0, 640); - windowWidgetAdd(w, 70, 5, W(_h)); + windowWidgetAdd(w, 100, 5, W(_h)); + + s = scrollableCreate(300, 200, 648, 480, SCROLLABLE_STANDARD); + windowWidgetAdd(w, 20, 170, W(s)); } guiRun(); guiShutdown();