/* * 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 "hscroll.h" uint8_t __MAGIC_HSCROLL = 0; static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data); static void hscrollDestroy(struct WidgetS *widget, ...); static void hscrollPaint(struct WidgetS *widget, ...); static void hscrollClick(WidgetT *widget, uint16_t x, uint16_t y, uint8_t event, void *data) { HscrollT *h = (HscrollT *)widget; (void)data; // Clicking in left arrow? if (x <= GADGET_SIZE) { // Move content left. h->value -= SCROLL_SPEED_SLOW; // Clip. if (h->value < h->min) h->value = h->min; // Update. widgetDirtySet(widget, 1); // Call the actual click event. if (h->handler) h->handler(widget, x, y, event, h->base.data); return; } // Clicking in right arrow? if (x >= h->base.r.w - GADGET_SIZE) { // Move content right. h->value += SCROLL_SPEED_SLOW; // Clip. if (h->value > h->max - h->base.r.w) h->value = h->max - h->base.r.w; // Update. widgetDirtySet(widget, 1); // Call the actual click event. if (h->handler) h->handler(widget, x, y, event, h->base.data); return; } // Clicking left of thumb? Also fakes dragging. if (x < h->thumb.x) { // Move content left. h->value -= SCROLL_SPEED_FAST; // Clip. if (h->value < h->min) h->value = h->min; // Update. widgetDirtySet(widget, 1); // Call the actual click event. if (h->handler) h->handler(widget, x, y, event, h->base.data); return; } // Clicking right of thumb? Also fakes dragging. if (x > h->thumb.x2) { // Move content right. h->value += SCROLL_SPEED_FAST; // Clip. if (h->value > h->max - h->base.r.w) h->value = h->max - h->base.r.w; // Update. widgetDirtySet(widget, 1); // Call the actual click event. if (h->handler) h->handler(widget, x, y, event, h->base.data); return; } } void hscrollClickSet(HscrollT *hscroll, ClickHandlerT handler, void *data) { hscroll->handler = handler; hscroll->base.data = data; } HscrollT *hscrollCreate(int16_t w, ClickHandlerT handler, void *data, ...) { HscrollT *h = NULL; NEW(HscrollT, h); memset(h, 0, sizeof(HscrollT)); h->min = 1; h->max = 100; h->value = 1; widgetBaseSet(W(h), __MAGIC_HSCROLL, w, GADGET_SIZE); hscrollWidthSet(h, w); h->handler = handler; h->base.data = data; widgetInputSetRaw(W(h), 1); return h; } static void hscrollDestroy(struct WidgetS *widget, ...) { HscrollT *h = (HscrollT *)widget; DEL(h); } static void hscrollPaint(struct WidgetS *widget, ...) { HscrollT *h = (HscrollT *)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 = h->base.r; r.x2 = r.x + h->base.r.w - 1; r.y2 = r.y + h->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); surfaceLineV(r.x + (GADGET_SIZE - 1), r.y + 1, r.y2, GUI_BLACK); surfaceLineV(r.x2 - (GADGET_SIZE - 1), r.y + 1, r.y2, GUI_WHITE); // Prepare font. fontSet(__guiFontVGA8x8); fontColorSet(widgetColor, scrollBackgroundColor); // ***TODO*** /* // 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); } */ // Draw arrows. fontRender("\x11", r.x + 7, r.y + 7); fontRender("\x10", r.x2 - 12, r.y + 7); // Distance between arrow buttons on scroll bar. i = r.x2 - r.x - (GADGET_SIZE * 2 - 2) - 2; // Percentage to scale content height to scroll bar height. d = (double)i / (double)(h->max - h->min); // Find position and size of thumb. h->thumb.x = r.x + GADGET_SIZE + (h->value * d); h->thumb.x2 = h->thumb.x + (h->base.r.w * d); h->thumb.y = r.y + 1; h->thumb.y2 = r.y2 - 1; // Clamp overflow due to doubles and my off-by-one brain. if (h->thumb.x2 >= h->thumb.x + i - 1) h->thumb.x2 = h->thumb.x + i - 1; // Draw thumb. surfaceBoxFilled(h->thumb.x + 1, h->thumb.y + 1, h->thumb.x2 - 1, h->thumb.y2 - 1, GUI_LIGHTGRAY); surfaceBoxHighlight(h->thumb.x, h->thumb.y, h->thumb.x2, h->thumb.y2, GUI_WHITE, GUI_BLACK); // Adjust thumb values from window space to widget space for click handler. h->thumb.x -= h->base.r.x; h->thumb.x2 -= h->base.r.x; h->thumb.y -= h->base.r.y; h->thumb.y2 -= h->base.r.y; } } void hscrollRangeSet(HscrollT *hscroll, int32_t min, int32_t max) { hscroll->min = min; hscroll->max = max; hscrollValueSet(hscroll, min); } RegisterT *hscrollRegister(uint8_t magic) { static RegisterT reg = { "Hscroll", hscrollClick, hscrollDestroy, hscrollPaint, NULL // No unregister handler. }; // One-time widget startup code. __MAGIC_HSCROLL = magic; return ® } int32_t hscrollValueGet(HscrollT *hscroll) { return hscroll->value; } void hscrollValueSet(HscrollT *hscroll, int32_t value) { if (value < hscroll->min) value = hscroll->min; if (value > hscroll->max) value = hscroll->max; if (hscroll->value != value) { hscroll->value = 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); }