// zlib open source license // // Copyright (c) 2020 to 2022 David Forsgren Piuva // // This software is provided 'as-is', without any express or implied // warranty. In no event will the authors be held liable for any damages // arising from the use of this software. // // Permission is granted to anyone to use this software for any purpose, // including commercial applications, and to alter it and redistribute it // freely, subject to the following restrictions: // // 1. The origin of this software must not be misrepresented; you must not // claim that you wrote the original software. If you use this software // in a product, an acknowledgment in the product documentation would be // appreciated but is not required. // // 2. Altered source versions must be plainly marked as such, and must not be // misrepresented as being the original software. // // 3. This notice may not be removed or altered from any source // distribution. #ifndef DFPSR_GUI_HELPER_SCROLL_BAR_IMPL #define DFPSR_GUI_HELPER_SCROLL_BAR_IMPL #include "../../VisualComponent.h" namespace dsr { struct ScrollRange { // The minimum value the scrollbar can be assigned in the current range. // Set minValue to 0 for scrolling through items in a list. int64_t minValue = 0; // The maximum value the scrollbar can be assigned in the current range. // Set maxValue to length - 1 and visibleItems to 1 for selecting an item in a list directly. // Set maxValue to length - visibleItems for scrolling through items with visibleItems sepresented by the knob's length. int64_t maxValue = 0; // Scrolling represents a range starting at the selected value of length visibleItems. // Use 1 if you are just selecting one integer value. // Use the value that you subtracted from the total length in maxValue if you want to represent a range of multiple values. // This argument only affects the knob size and how the selected range is constrained to include a certain value. int64_t visibleItems = 1; ScrollRange() {} ScrollRange(int64_t minValue, int64_t maxValue, int64_t visibleItems) : minValue(minValue), maxValue(maxValue), visibleItems(visibleItems) {} }; // To be value allocated inside of components that need a scroll-bar. // Initialized with true if the scroll-bar is vertical, and with false if the scroll-bar is horizontal. // Call loadTheme when the parent component loads a new theme, or you will have a crash when trying to draw the scroll-bar. // When the range of values or view's size changed, recalculate the range of valid values and send it to updateScrollRange. class ScrollBarImpl { private: // Locked settings. const bool vertical; // Calculated automatically. bool visible = false; // Temporary. bool pressScrollUp = false; bool pressScrollDown = false; bool holdingScrollBar = false; const int scrollBarThickness = 16; const int scrollButtonLength = 16; int64_t knobHoldOffset = 0; // The number of pixels right or down from the center that the knob was grabbed at. // Updated manually. ScrollRange scrollRange; // Range of valid values. int64_t value = 0; // The selected value. int64_t reservedStart = 0; // How many pixels to leave empty at the left/top side to avoid collisions. int64_t reservedEnd = 0; // How many pixels to leave empty at the right/bottom side to avoid collisions. // Scalable parametric images. MediaMethod scalableImage_scrollTop, scalableImage_scrollBottom, scalableImage_scrollBackground, scalableImage_scrollKnob; // Generated raster images. OrderedImageRgbaU8 scrollButtonTopImage_normal, scrollButtonTopImage_pressed; OrderedImageRgbaU8 scrollButtonBottomImage_normal, scrollButtonBottomImage_pressed; OrderedImageRgbaU8 scrollKnobImage_normal, scrollKnobImage_pressed; OrderedImageRgbaU8 scrollBarImage; private: IRect getScrollBarLocation(int32_t parentWidth, int32_t parentHeight); IRect getScrollRegion(const IRect &scrollBarLocation); IRect getDecreaseButton(const IRect &scrollBarLocation); IRect getIncreaseButton(const IRect &scrollBarLocation); IRect getKnobLocation(const IRect &scrollBarLocation); // Returns true iff value updated. bool pressScrollBar(const IRect &parentLocation, int64_t localY); public: ScrollBarImpl(bool vertical, bool reserveEnd = false) : vertical(vertical), reservedStart(0), reservedEnd(reserveEnd ? 16 : 0) {} void loadTheme(VisualTheme theme, const ColorRgbI32 &color); // Pre-condition: range.minValue <= range.maxValue void updateScrollRange(const ScrollRange &range); void setValue(int64_t newValue); int64_t getValue(); // Pre-condition: scrollRange must have been updated since the last changes that may affect it // Side-effects: Constrains value within minValue and maxValue. // If keepPinValueInRange is true, it will also try to constrain the selected range to include pinValue, // which is used for making sure that something selected stays visible, when scrolling is used for navigating a view. void limitScrolling(const IRect &parentLocation, bool keepPinValueInRange = false, int64_t pinValue = 0); // For mouse-down events, it returns true iff the event landed inside of the scroll-bar. // For other event types, it returns true iff the scroll-bar needs to be redrawn. bool receiveMouseEvent(const IRect &parentLocation, const MouseEvent& event); // Draw the scroll-bar on top of target. void draw(OrderedImageRgbaU8 &target, VisualTheme &theme, const ColorRgbI32 &color); }; } #endif