/* * 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 "../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); } }