diff --git a/extra/DefaultTheme.oss b/extra/DefaultTheme.oss index adf359a..14a5b84 100644 --- a/extra/DefaultTheme.oss +++ b/extra/DefaultTheme.oss @@ -43,7 +43,7 @@ window.backgroundColor = rgba(160, 160, 160, 255) (scrollbar) { (thumb) { color = rgb(140, 140, 140) - borderRadius = 0.0 + borderRadius = 16.0 borderColor = rgb(150, 150, 150) showBorder = true } diff --git a/src/ogfx/gui/widgets/Containers.cpp b/src/ogfx/gui/widgets/Containers.cpp index 231c26c..911b3cb 100644 --- a/src/ogfx/gui/widgets/Containers.cpp +++ b/src/ogfx/gui/widgets/Containers.cpp @@ -35,28 +35,6 @@ namespace ogfx disableDrawBox(); disableFocus(); enableStopEvents(); - allowVScroll(true); - allowHScroll(true); - m_vScrollbar.setMargin({ 0, getTitlebarHeight(), 0, 0 }); - m_vScrollbar.enableManualDraw(true); - addWidget(m_vScrollbar); - m_hScrollbar.setMargin({ 0, 0, 0, 0 }); - m_hScrollbar.enableManualDraw(true); - addWidget(m_hScrollbar); - m_smoothScrollTimer.create(60.0f, [&](f64 dt) -> void { - f32 stepX = m_scrollVelocity.x * (1.0f - m_scrollSmoothFactor); - f32 stepY = m_scrollVelocity.y * (1.0f - m_scrollSmoothFactor); - - addScrollOffset({ stepX, stepY }); - m_scrollVelocity -= { stepX, stepY }; - - if (std::abs(m_scrollVelocity.x) < 0.5f) m_scrollVelocity.x = 0; - if (std::abs(m_scrollVelocity.y) < 0.5f) m_scrollVelocity.y = 0; - }, true); - - m_smoothScrollTimer.setStopCondition([&](void) -> bool { - return m_scrollVelocity.x == 0 && m_scrollVelocity.y == 0; - }); validate(); return *this; } @@ -71,8 +49,8 @@ namespace ogfx setBorderColor(getThemeValue(theme, "panel.borderColor", Colors::Black)); setPadding(getThemeValue(theme, "panel.padding", { 15, 15, 15, 15 })); setMargin(getThemeValue(theme, "panel.margin", { 0, 0, 0, 0 })); - m_scrollSpeed = getThemeValue(theme, "panel.scrollSpeed", 0.8f); - m_scrollSmoothFactor = std::clamp(getThemeValue(theme, "panel.scrollSmoothFactor", 0.7f), 0.0f, 1.0f); + setScrollSpeed(getThemeValue(theme, "panel.scrollSpeed", 0.8f)); + setScrollSmoothFactor(getThemeValue(theme, "panel.scrollSmoothFactor", 0.7f)); m_titleColor = getThemeValue(theme, "panel.titleColor", Colors::Black); m_titlebarColor = getThemeValue(theme, "panel.titlebarColor", Colors::Transparent); m_titlebarBorderColor = getThemeValue(theme, "panel.titlebarBorderColor", Colors::Black); @@ -83,54 +61,10 @@ namespace ogfx setTitlebarType(getThemeValue(theme, "panel.titlebarType", TitleBarTypes::None)); } - void Panel::onDraw(ogfx::BasicRenderer2D& gfx) - { - // if (isScrollAllowed()) - // gfx.fillRect(getContentExtents() + Rectangle { getGlobalPosition(), 0, 0 }, { 80, 0, 0, 30 }); - } - - void Panel::onUpdate(void) - { - m_smoothScrollTimer.update(); - } - void Panel::afterDraw(ogfx::BasicRenderer2D& gfx) { draw_titlebar(gfx); - m_vScrollbar.__draw(gfx); - m_hScrollbar.__draw(gfx); - } - - void Panel::onMouseScrolled(const Event& event) - { - if (isVScrollAllowed()) - { - bool mouseInsideHScrollbar = m_hScrollbar.isMouseInsideThumb({ event.mouse->position_x, event.mouse->position_y }); - if (std::abs(event.mouse->scrollAmount.y) > 0 && !mouseInsideHScrollbar) - { - m_scrollVelocity.y += m_scrollSpeed * event.mouse->scrollAmount.y * m_scrollSpeedMultiplier; - if (m_smoothScrollTimer.isStopped()) - m_smoothScrollTimer.restart(); - event.handle(); - } - else if (std::abs(event.mouse->scrollAmount.y) > 0) - { - m_scrollVelocity.x += m_scrollSpeed * event.mouse->scrollAmount.y * m_scrollSpeedMultiplier; - if (m_smoothScrollTimer.isStopped()) - m_smoothScrollTimer.restart(); - event.handle(); - } - } - if (isHScrollAllowed()) - { - if (std::abs(event.mouse->scrollAmount.x) > 0) - { - m_scrollVelocity.x += m_scrollSpeed * event.mouse->scrollAmount.x * m_scrollSpeedMultiplier; - if (m_smoothScrollTimer.isStopped()) - m_smoothScrollTimer.restart(); - event.handle(); - } - } + drawScrollbars(gfx); } void Panel::setTitlebarType(const String& type) @@ -139,16 +73,19 @@ namespace ogfx if (t == TitleBarTypes::None) { setContentOffset({ 0, 0 }); + updateScrollbarsSize(); m_titlebarType = TitleBarTypes::NoneValue; } else if (t == TitleBarTypes::Minimal) { setContentOffset({ 0, m_titlebarHeight }); + updateScrollbarsSize(); m_titlebarType = TitleBarTypes::MinimalValue; } else if (t == TitleBarTypes::Full) { setContentOffset({ 0, m_titlebarHeight }); + updateScrollbarsSize(); m_titlebarType = TitleBarTypes::FullValue; } } @@ -164,72 +101,6 @@ namespace ogfx } } - void Panel::setScrollOffset(const Vec2& offset) - { - auto ext = getContentExtents(); - auto cont = getContentBounds(); - f32 maxScrollY = -(ext.h - cont.h); - f32 maxScrollX = -(ext.w - cont.w); - - m_scrollOffset = offset; - - if (m_scrollOffset.y < maxScrollY) m_scrollOffset.y = maxScrollY; - if (m_scrollOffset.y > 0) m_scrollOffset.y = 0; - if (m_scrollOffset.x < maxScrollX) m_scrollOffset.x = maxScrollX; - if (m_scrollOffset.x > 0) m_scrollOffset.x = 0; - } - - void Panel::addScrollOffset(const Vec2& offset) - { - auto ext = getContentExtents(); - auto cont = getContentBounds(); - f32 maxScrollY = -(ext.h - cont.h); - f32 maxScrollX = -(ext.w - cont.w); - - m_scrollOffset += offset; - - if (m_scrollOffset.y < maxScrollY) m_scrollOffset.y = maxScrollY; - if (m_scrollOffset.y > 0) m_scrollOffset.y = 0; - if (m_scrollOffset.x < maxScrollX) m_scrollOffset.x = maxScrollX; - if (m_scrollOffset.x > 0) m_scrollOffset.x = 0; - } - - bool Panel::needsVScroll(void) const - { - return isVScrollAllowed() && getContentExtents().h > getContentBounds().h; - } - - bool Panel::needsHScroll(void) const - { - return isHScrollAllowed() && getContentExtents().w > getContentBounds().w; - } - - void Panel::onWidgetAdded(Widget& child) - { - removeWidget(m_vScrollbar); - removeWidget(m_hScrollbar); - addWidget(m_vScrollbar, { 0, 0 }, true); - addWidget(m_hScrollbar, { 0, 0 }, true); - } - - f32 Panel::getVScrollbarSize(void) const - { - if (!isVScrollAllowed()) - return 0; - if (!needsVScroll()) - return 0; - return m_vScrollbar.getw(); - } - - f32 Panel::getHScrollbarSize(void) const - { - if (!isHScrollAllowed()) - return 0; - if (!needsHScroll()) - return 0; - return m_hScrollbar.geth(); - } - void Panel::draw_titlebar(BasicRenderer2D& gfx) { f32 br = cast(getBorderWidth()); diff --git a/src/ogfx/gui/widgets/Containers.hpp b/src/ogfx/gui/widgets/Containers.hpp index 334f40b..7cfb25b 100644 --- a/src/ogfx/gui/widgets/Containers.hpp +++ b/src/ogfx/gui/widgets/Containers.hpp @@ -30,7 +30,7 @@ namespace ogfx { namespace widgets { - class Panel : public Widget + class Panel : public ScrollableWidget { public: struct TitleBarTypes { @@ -43,27 +43,16 @@ namespace ogfx inline static constexpr i32 MinimalValue = 2; }; public: - inline Panel(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); } + inline Panel(WindowCore& window) : ScrollableWidget(window) { create(); } Panel& create(void); void applyTheme(const ostd::Stylesheet& theme) override; - void onDraw(ogfx::BasicRenderer2D& gfx) override; - void onUpdate(void) override; void afterDraw(ogfx::BasicRenderer2D& gfx) override; - void onMouseScrolled(const Event& event) override; void setTitlebarType(const String& type); String getTitlebarType(void) const; - void setScrollOffset(const Vec2& offset) override; - void addScrollOffset(const Vec2& offset) override; - bool needsVScroll(void) const override; - bool needsHScroll(void) const override; - void onWidgetAdded(Widget& child) override; - f32 getVScrollbarSize(void) const override; - f32 getHScrollbarSize(void) const override; inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; } inline Color getBackgroundColor(void) { return m_backgroundColor; } inline String getTitle(void) const { return m_title; } inline void setTitle(const String& title) { m_title = title; } - inline Vec2 getScrollOffset(void) const override { return m_scrollOffset; } inline f32 getTitlebarHeight(void) const { return m_titlebarHeight; } private: @@ -71,10 +60,6 @@ namespace ogfx private: String m_title { "Panel" }; - Vec2 m_scrollOffset { 0, 0 }; - VerticalScrollBar m_vScrollbar { getWindow() }; - HorizontalScrollbar m_hScrollbar { getWindow() }; - ostd::StepTimer m_smoothScrollTimer; Color m_titleColor { Colors::Black }; i32 m_titlebarType = TitleBarTypes::NoneValue; @@ -84,11 +69,6 @@ namespace ogfx Color m_titlebarColor { Colors::Transparent }; Color m_titlebarBorderColor { Colors::Black }; i32 m_titleTextAlign { 0 }; - f32 m_scrollSpeed { 0.8f }; - - Vec2 m_scrollVelocity { 0.0f, 0.0f }; - f32 m_scrollSmoothFactor { 0.7f }; - f32 m_scrollSpeedMultiplier { 15.0f }; }; } } diff --git a/src/ogfx/gui/widgets/Scrollbar.cpp b/src/ogfx/gui/widgets/Scrollbar.cpp index b205de0..6083db0 100644 --- a/src/ogfx/gui/widgets/Scrollbar.cpp +++ b/src/ogfx/gui/widgets/Scrollbar.cpp @@ -173,7 +173,7 @@ namespace ogfx m_thumbBorderColor = getThemeValue(theme, "scrollbar.thumb.borderColor", { 150, 150, 150 }); m_thumbShowBorder = getThemeValue(theme, "scrollbar.thumb.showBorder", true); m_trackColor = getThemeValue(theme, "scrollbar.track.color", { 70, 70, 70 }); - } + } void HorizontalScrollbar::afterDraw(ogfx::BasicRenderer2D& gfx) { @@ -268,6 +268,154 @@ namespace ogfx parentScrollOffset.x = maxScroll * scrollProgress; getParent()->setScrollOffset(parentScrollOffset); } + + + + + + + ScrollableWidget& ScrollableWidget::create(void) + { + setTypeName("ogfx::gui::widgets::ScrollableWidget"); + allowVScroll(true); + allowHScroll(true); + m_vScrollbar.enableManualDraw(true); + addWidget(m_vScrollbar); + m_hScrollbar.setMargin({ 0, 0, 0, 0 }); + m_hScrollbar.enableManualDraw(true); + addWidget(m_hScrollbar); + m_smoothScrollTimer.create(60.0f, [&](f64 dt) -> void { + f32 stepX = m_scrollVelocity.x * (1.0f - m_scrollSmoothFactor); + f32 stepY = m_scrollVelocity.y * (1.0f - m_scrollSmoothFactor); + + addScrollOffset({ stepX, stepY }); + m_scrollVelocity -= { stepX, stepY }; + + if (std::abs(m_scrollVelocity.x) < 0.5f) m_scrollVelocity.x = 0; + if (std::abs(m_scrollVelocity.y) < 0.5f) m_scrollVelocity.y = 0; + }, true); + + m_smoothScrollTimer.setStopCondition([&](void) -> bool { + return m_scrollVelocity.x == 0 && m_scrollVelocity.y == 0; + }); + updateScrollbarsSize(); + validate(); + return *this; + } + + void ScrollableWidget::onUpdate(void) + { + m_smoothScrollTimer.update(); + } + + void ScrollableWidget::drawScrollbars(ogfx::BasicRenderer2D& gfx) + { + m_vScrollbar.__draw(gfx); + m_hScrollbar.__draw(gfx); + } + + void ScrollableWidget::updateScrollbarsSize(void) + { + m_vScrollbar.setMargin({ 0, getPureContentBounds().y, 0, 0 }); + } + + void ScrollableWidget::onMouseScrolled(const Event& event) + { + if (isVScrollAllowed()) + { + bool mouseInsideHScrollbar = m_hScrollbar.isMouseInsideThumb({ event.mouse->position_x, event.mouse->position_y }); + if (std::abs(event.mouse->scrollAmount.y) > 0 && !mouseInsideHScrollbar) + { + m_scrollVelocity.y += m_scrollSpeed * event.mouse->scrollAmount.y * m_scrollSpeedMultiplier; + if (m_smoothScrollTimer.isStopped()) + m_smoothScrollTimer.restart(); + event.handle(); + } + else if (std::abs(event.mouse->scrollAmount.y) > 0) + { + m_scrollVelocity.x += m_scrollSpeed * event.mouse->scrollAmount.y * m_scrollSpeedMultiplier; + if (m_smoothScrollTimer.isStopped()) + m_smoothScrollTimer.restart(); + event.handle(); + } + } + if (isHScrollAllowed()) + { + if (std::abs(event.mouse->scrollAmount.x) > 0) + { + m_scrollVelocity.x += m_scrollSpeed * event.mouse->scrollAmount.x * m_scrollSpeedMultiplier; + if (m_smoothScrollTimer.isStopped()) + m_smoothScrollTimer.restart(); + event.handle(); + } + } + } + + void ScrollableWidget::setScrollOffset(const Vec2& offset) + { + auto ext = getContentExtents(); + auto cont = getContentBounds(); + f32 maxScrollY = -(ext.h - cont.h); + f32 maxScrollX = -(ext.w - cont.w); + + m_scrollOffset = offset; + + if (m_scrollOffset.y < maxScrollY) m_scrollOffset.y = maxScrollY; + if (m_scrollOffset.y > 0) m_scrollOffset.y = 0; + if (m_scrollOffset.x < maxScrollX) m_scrollOffset.x = maxScrollX; + if (m_scrollOffset.x > 0) m_scrollOffset.x = 0; + } + + void ScrollableWidget::addScrollOffset(const Vec2& offset) + { + auto ext = getContentExtents(); + auto cont = getContentBounds(); + f32 maxScrollY = -(ext.h - cont.h); + f32 maxScrollX = -(ext.w - cont.w); + + m_scrollOffset += offset; + + if (m_scrollOffset.y < maxScrollY) m_scrollOffset.y = maxScrollY; + if (m_scrollOffset.y > 0) m_scrollOffset.y = 0; + if (m_scrollOffset.x < maxScrollX) m_scrollOffset.x = maxScrollX; + if (m_scrollOffset.x > 0) m_scrollOffset.x = 0; + } + + bool ScrollableWidget::needsVScroll(void) const + { + return isVScrollAllowed() && getContentExtents().h > getContentBounds().h; + } + + bool ScrollableWidget::needsHScroll(void) const + { + return isHScrollAllowed() && getContentExtents().w > getContentBounds().w; + } + + void ScrollableWidget::onWidgetAdded(Widget& child) + { + removeWidget(m_vScrollbar); + removeWidget(m_hScrollbar); + addWidget(m_vScrollbar, { 0, 0 }, true); + addWidget(m_hScrollbar, { 0, 0 }, true); + } + + f32 ScrollableWidget::getVScrollbarSize(void) const + { + if (!isVScrollAllowed()) + return 0; + if (!needsVScroll()) + return 0; + return m_vScrollbar.getw(); + } + + f32 ScrollableWidget::getHScrollbarSize(void) const + { + if (!isHScrollAllowed()) + return 0; + if (!needsHScroll()) + return 0; + return m_hScrollbar.geth(); + } } } } diff --git a/src/ogfx/gui/widgets/Scrollbar.hpp b/src/ogfx/gui/widgets/Scrollbar.hpp index 8e0e9b2..3fa495f 100644 --- a/src/ogfx/gui/widgets/Scrollbar.hpp +++ b/src/ogfx/gui/widgets/Scrollbar.hpp @@ -21,6 +21,7 @@ #pragma once #include +#include namespace ogfx { @@ -104,6 +105,39 @@ namespace ogfx Color m_thumbBorderColor { 150, 150, 150 }; bool m_thumbShowBorder { true }; }; + class ScrollableWidget : public Widget + { + public: + inline ScrollableWidget(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); } + ScrollableWidget& create(void); + virtual void onUpdate(void) override; + void drawScrollbars(ogfx::BasicRenderer2D& gfx); + void updateScrollbarsSize(void); + virtual void onMouseScrolled(const Event& event) override; + virtual void setScrollOffset(const Vec2& offset) override; + virtual void addScrollOffset(const Vec2& offset) override; + virtual bool needsVScroll(void) const override; + virtual bool needsHScroll(void) const override; + virtual void onWidgetAdded(Widget& child) override; + virtual f32 getVScrollbarSize(void) const override; + virtual f32 getHScrollbarSize(void) const override; + inline Vec2 getScrollOffset(void) const override { return m_scrollOffset; } + inline void setScrollSpeed(f32 speed) { m_scrollSpeed = speed; } + inline f32 getScrollSpeed(void) const { return m_scrollSpeed; } + inline void setScrollSmoothFactor(f32 speed) { m_scrollSmoothFactor = std::clamp(speed, 0.0f, 1.0f); } + inline f32 getScrollSmoothFactor(void) const { return m_scrollSmoothFactor; } + + private: + String m_title { "Panel" }; + Vec2 m_scrollOffset { 0, 0 }; + VerticalScrollBar m_vScrollbar { getWindow() }; + HorizontalScrollbar m_hScrollbar { getWindow() }; + ostd::StepTimer m_smoothScrollTimer; + f32 m_scrollSpeed { 0.8f }; + Vec2 m_scrollVelocity { 0.0f, 0.0f }; + f32 m_scrollSmoothFactor { 0.7f }; + f32 m_scrollSpeedMultiplier { 15.0f }; + }; } } }