226 lines
6 KiB
C
226 lines
6 KiB
C
/*
|
|
* 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 <https://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
|
|
#include "../wmwindow.h"
|
|
#include "../font.h"
|
|
|
|
#include "vscroll.h"
|
|
|
|
|
|
uint8_t __MAGIC_VSCROLL = 0;
|
|
|
|
|
|
static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data);
|
|
static void vscrollDestroy(struct WidgetS *widget, ...);
|
|
static void vscrollPaint(struct WidgetS *widget, ...);
|
|
|
|
|
|
static void vscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) {
|
|
VscrollT *v = (VscrollT *)widget;
|
|
|
|
(void)data;
|
|
|
|
// Clicking in up arrow?
|
|
if (y <= GADGET_SIZE) {
|
|
// Move content up.
|
|
v->value -= SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (v->value < v->min) v->value = v->min;
|
|
// Update.
|
|
widgetDirtySet(widget, 1);
|
|
// Call the actual click event.
|
|
if (v->handler) v->handler(widget, x, y, event, v->base.data);
|
|
return;
|
|
}
|
|
|
|
// Clicking in down arrow?
|
|
if (y >= v->base.r.h - GADGET_SIZE) {
|
|
// Move content down.
|
|
v->value += SCROLL_SPEED_SLOW;
|
|
// Clip.
|
|
if (v->value > v->max - v->base.r.h) v->value = v->max - v->base.r.h;
|
|
// Update.
|
|
widgetDirtySet(widget, 1);
|
|
// Call the actual click event.
|
|
if (v->handler) v->handler(widget, x, y, event, v->base.data);
|
|
return;
|
|
}
|
|
|
|
// Clicking above thumb? Also fakes dragging.
|
|
if (y < v->thumb.y) {
|
|
// Move content up.
|
|
v->value -= SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (v->value < v->min) v->value = v->min;
|
|
// Update.
|
|
widgetDirtySet(widget, 1);
|
|
// Call the actual click event.
|
|
if (v->handler) v->handler(widget, x, y, event, v->base.data);
|
|
return;
|
|
}
|
|
|
|
// Clicking below thumb? Also fakes dragging.
|
|
if (y > v->thumb.y2) {
|
|
// Move content down.
|
|
v->value += SCROLL_SPEED_FAST;
|
|
// Clip.
|
|
if (v->value > v->max - v->base.r.h) v->value = v->max - v->base.r.h;
|
|
// Update.
|
|
widgetDirtySet(widget, 1);
|
|
// Call the actual click event.
|
|
if (v->handler) v->handler(widget, x, y, event, v->base.data);
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
void vscrollClickSet(VscrollT *vscroll, ClickHandlerT handler, void *data) {
|
|
vscroll->handler = handler;
|
|
vscroll->base.data = data;
|
|
}
|
|
|
|
|
|
VscrollT *vscrollCreate(int16_t h, ClickHandlerT handler, void *data, ...) {
|
|
VscrollT *v = NULL;
|
|
|
|
NEW(VscrollT, v);
|
|
memset(v, 0, sizeof(VscrollT));
|
|
|
|
v->min = 1;
|
|
v->max = 100;
|
|
v->value = 1;
|
|
|
|
if (h < GADGET_SIZE * 3) h = GADGET_SIZE * 3;
|
|
|
|
widgetBaseSet(W(v), __MAGIC_VSCROLL, GADGET_SIZE, h);
|
|
|
|
v->handler = handler;
|
|
v->base.data = data;
|
|
|
|
widgetInputSetRaw(W(v), 1);
|
|
|
|
return v;
|
|
}
|
|
|
|
|
|
static void vscrollDestroy(struct WidgetS *widget, ...) {
|
|
VscrollT *v = (VscrollT *)widget;
|
|
|
|
DEL(v);
|
|
}
|
|
|
|
|
|
static void vscrollPaint(struct WidgetS *widget, ...) {
|
|
VscrollT *v = (VscrollT *)widget;
|
|
ColorT scrollBackgroundColor;
|
|
ColorT widgetColor;
|
|
RectT r;
|
|
int16_t i;
|
|
double d;
|
|
|
|
if (widgetDirtyGet(widget)) {
|
|
widgetDirtySet(widget, 0);
|
|
// Find some colors.
|
|
if (widgetIsInWidget(widget, W(wmWindowOnTopGet()))) {
|
|
scrollBackgroundColor = GUI_DARKGRAY;
|
|
widgetColor = GUI_LIGHTGRAY;
|
|
} else {
|
|
scrollBackgroundColor = GUI_LIGHTGRAY;
|
|
widgetColor = GUI_DARKGRAY;
|
|
}
|
|
// Find coordinates.
|
|
r = v->base.r;
|
|
r.x2 = r.x + v->base.r.w - 1;
|
|
r.y2 = r.y + v->base.r.h - 1;
|
|
// Paint scrollbar.
|
|
surfaceBoxFilled(r.x + 1, r.y + 1, r.x2 - 1, r.y2 - 1, scrollBackgroundColor);
|
|
surfaceBoxHighlight(r.x, r.y, r.x2, r.y2, GUI_WHITE, GUI_BLACK);
|
|
surfaceLineH(r.x + 1, r.x2, r.y + (GADGET_SIZE - 1), GUI_BLACK);
|
|
surfaceLineH(r.x + 1, r.x2, r.y2 - (GADGET_SIZE - 1), GUI_WHITE);
|
|
// Prepare font.
|
|
fontSet(__guiFontVGA8x8);
|
|
fontColorSet(widgetColor, scrollBackgroundColor);
|
|
// Draw arrows.
|
|
fontRender("\x1e", r.x + 7, r.y + 7);
|
|
fontRender("\x1f", r.x + 7, r.y2 - 12);
|
|
// Distance between arrow buttons on scroll bar.
|
|
i = r.y2 - r.y - (GADGET_SIZE * 2 - 2) - 2;
|
|
// Percentage to scale content height to scroll bar height.
|
|
d = (double)i / (double)(v->max - v->min);
|
|
// Find position and size of thumb.
|
|
v->thumb.x = r.x + 1;
|
|
v->thumb.x2 = r.x2 - 1;
|
|
v->thumb.y = r.y + GADGET_SIZE + (v->value * d);
|
|
v->thumb.y2 = v->thumb.y + (v->base.r.h * d);
|
|
// Clamp overflow due to doubles and my off-by-one brain.
|
|
if (v->thumb.y2 >= v->thumb.y + i - 1) v->thumb.y2 = v->thumb.y + i - 1;
|
|
// Draw thumb.
|
|
surfaceBoxFilled(v->thumb.x + 1, v->thumb.y + 1, v->thumb.x2 - 1, v->thumb.y2 - 1, GUI_LIGHTGRAY);
|
|
surfaceBoxHighlight(v->thumb.x, v->thumb.y, v->thumb.x2, v->thumb.y2, GUI_WHITE, GUI_BLACK);
|
|
// Adjust thumb values from window space to widget space for click handler.
|
|
v->thumb.x -= v->base.r.x;
|
|
v->thumb.x2 -= v->base.r.x;
|
|
v->thumb.y -= v->base.r.y;
|
|
v->thumb.y2 -= v->base.r.y;
|
|
}
|
|
}
|
|
|
|
|
|
void vscrollRangeSet(VscrollT *vscroll, int32_t min, int32_t max) {
|
|
vscroll->min = min;
|
|
vscroll->max = max;
|
|
vscrollValueSet(vscroll, min);
|
|
}
|
|
|
|
|
|
RegisterT *vscrollRegister(uint8_t magic) {
|
|
static RegisterT reg = {
|
|
"Vscroll",
|
|
vscrollClick,
|
|
vscrollDestroy,
|
|
vscrollPaint,
|
|
NULL // No unregister handler.
|
|
};
|
|
|
|
// One-time widget startup code.
|
|
__MAGIC_VSCROLL = magic;
|
|
|
|
return ®
|
|
}
|
|
|
|
|
|
int32_t vscrollValueGet(VscrollT *vscroll) {
|
|
return vscroll->value;
|
|
}
|
|
|
|
|
|
void vscrollValueSet(VscrollT *vscroll, int32_t value) {
|
|
if (value < vscroll->min) value = vscroll->min;
|
|
if (value > vscroll->max) value = vscroll->max;
|
|
if (vscroll->value != value) {
|
|
vscroll->value = value;
|
|
widgetDirtySet(W(vscroll), 1);
|
|
}
|
|
}
|