Started work on horizontal scrollbar
This commit is contained in:
parent
d8475ecb48
commit
891e17948a
10 changed files with 195 additions and 17 deletions
|
|
@ -1 +1 @@
|
|||
2069
|
||||
2070
|
||||
|
|
|
|||
|
|
@ -463,7 +463,7 @@ namespace ogfx
|
|||
{
|
||||
MouseEventData mmd = get_mouse_state(event);
|
||||
f32 deltaY = event.wheel.y;
|
||||
f32 deltaX = event.wheel.x;
|
||||
f32 deltaX = m_invertHorizontalScroll ? -event.wheel.x : event.wheel.x;
|
||||
if (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED)
|
||||
deltaY = -deltaY;
|
||||
if (deltaY < 0)
|
||||
|
|
|
|||
|
|
@ -156,6 +156,7 @@ namespace ogfx
|
|||
bool m_blockingEvents { false };
|
||||
bool m_resizeable { true };
|
||||
bool m_refreshScreen { true };
|
||||
bool m_invertHorizontalScroll { true };
|
||||
|
||||
f32 m_systemScale { 1.0f };
|
||||
f32 m_userScale { 1.0f };
|
||||
|
|
|
|||
|
|
@ -36,9 +36,12 @@ namespace ogfx
|
|||
disableFocus();
|
||||
enableStopEvents();
|
||||
allowScroll(true);
|
||||
m_scrollbar.setMargin({ 0, getTitlebarHeight(), 0, 0 });
|
||||
m_scrollbar.enableManualDraw(true);
|
||||
addWidget(m_scrollbar);
|
||||
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);
|
||||
|
|
@ -94,7 +97,8 @@ namespace ogfx
|
|||
void Panel::afterDraw(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
draw_titlebar(gfx);
|
||||
m_scrollbar.__draw(gfx);
|
||||
m_vScrollbar.__draw(gfx);
|
||||
m_hScrollbar.__draw(gfx);
|
||||
}
|
||||
|
||||
void Panel::onMouseScrolled(const Event& event)
|
||||
|
|
@ -174,15 +178,22 @@ namespace ogfx
|
|||
if (m_scrollOffset.x > 0) m_scrollOffset.x = 0;
|
||||
}
|
||||
|
||||
bool Panel::needsScroll(void) const
|
||||
bool Panel::needsVScroll(void) const
|
||||
{
|
||||
return isScrollAllowed() && getContentExtents().h > getContentBounds().h;
|
||||
}
|
||||
|
||||
bool Panel::needsHScroll(void) const
|
||||
{
|
||||
return isScrollAllowed() && getContentExtents().w > getContentBounds().w;
|
||||
}
|
||||
|
||||
void Panel::onWidgetAdded(Widget& child)
|
||||
{
|
||||
removeWidget(m_scrollbar);
|
||||
addWidget(m_scrollbar, { 0, 0 }, true);
|
||||
removeWidget(m_vScrollbar);
|
||||
removeWidget(m_hScrollbar);
|
||||
addWidget(m_vScrollbar, { 0, 0 }, true);
|
||||
addWidget(m_hScrollbar, { 0, 0 }, true);
|
||||
}
|
||||
|
||||
void Panel::draw_titlebar(BasicRenderer2D& gfx)
|
||||
|
|
|
|||
|
|
@ -54,7 +54,8 @@ namespace ogfx
|
|||
String getTitlebarType(void) const;
|
||||
void setScrollOffset(const Vec2& offset) override;
|
||||
void addScrollOffset(const Vec2& offset) override;
|
||||
bool needsScroll(void) const override;
|
||||
bool needsVScroll(void) const override;
|
||||
bool needsHScroll(void) const override;
|
||||
void onWidgetAdded(Widget& child) override;
|
||||
inline void setBackGroundColor(const Color& color) { m_backgroundColor = color; }
|
||||
inline Color getBackgroundColor(void) { return m_backgroundColor; }
|
||||
|
|
@ -69,7 +70,8 @@ namespace ogfx
|
|||
private:
|
||||
String m_title { "Panel" };
|
||||
Vec2 m_scrollOffset { 0, 0 };
|
||||
VerticalScrollBar m_scrollbar { getWindow() };
|
||||
VerticalScrollBar m_vScrollbar { getWindow() };
|
||||
HorizontalScrollbar m_hScrollbar { getWindow() };
|
||||
ostd::StepTimer m_smoothScrollTimer;
|
||||
|
||||
Color m_titleColor { Colors::Black };
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ namespace ogfx
|
|||
{
|
||||
namespace widgets
|
||||
{
|
||||
VerticalScrollBar& VerticalScrollBar::create(const String& text)
|
||||
VerticalScrollBar& VerticalScrollBar::create(void)
|
||||
{
|
||||
setPadding({ 0, 0, 0, 0 });
|
||||
setMargin({ 0, 0, 0, 0 });
|
||||
|
|
@ -55,7 +55,7 @@ namespace ogfx
|
|||
|
||||
void VerticalScrollBar::afterDraw(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
if (!getParent()->needsScroll())
|
||||
if (!getParent()->needsVScroll())
|
||||
return;
|
||||
gfx.fillRoundRect(getGlobalBounds() - m_correctionOffset, m_trackColor, m_trackBorderRadii);
|
||||
gfx.outlinedRoundRect(m_thumbGlobalBounds, m_thumbColor, m_thumbBorderColor, m_thumbBorderRadius, 1);
|
||||
|
|
@ -143,6 +143,129 @@ namespace ogfx
|
|||
{
|
||||
return m_thumbGlobalBounds.contains(mouse_pos, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
HorizontalScrollbar& HorizontalScrollbar::create(void)
|
||||
{
|
||||
setPadding({ 0, 0, 0, 0 });
|
||||
setMargin({ 0, 0, 0, 0 });
|
||||
setTypeName("ogfx::gui::widgets::Label");
|
||||
disableDrawBox();
|
||||
disableChildren();
|
||||
enableBackground(true);
|
||||
enableBorder(false);
|
||||
enableTopMost(true);
|
||||
allowIgnoreScroll(true);
|
||||
validate();
|
||||
return *this;
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::applyTheme(const ostd::Stylesheet& theme)
|
||||
{
|
||||
h = getThemeValue<f32>(theme, "scrollbar.width", 15);
|
||||
m_thumbColor = getThemeValue<Color>(theme, "scrollbar.thumb.color", { 120, 120, 120 });
|
||||
m_thumbBorderRadius = getThemeValue<f32>(theme, "scrollbar.thumb.borderRadius", 16);
|
||||
m_thumbBorderColor = getThemeValue<Color>(theme, "scrollbar.thumb.borderColor", { 150, 150, 150 });
|
||||
m_thumbShowBorder = getThemeValue<bool>(theme, "scrollbar.thumb.showBorder", true);
|
||||
m_trackColor = getThemeValue<Color>(theme, "scrollbar.track.color", { 70, 70, 70 });
|
||||
m_trackBorderRadii = getThemeValue<Rectangle>(theme, "scrollbar.track.borderRadii", { 0, 0, 10, 10 });
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::afterDraw(ogfx::BasicRenderer2D& gfx)
|
||||
{
|
||||
if (!getParent()->needsHScroll())
|
||||
return;
|
||||
gfx.fillRoundRect(getGlobalBounds() - m_correctionOffset, m_trackColor, m_trackBorderRadii);
|
||||
gfx.outlinedRoundRect(m_thumbGlobalBounds, m_thumbColor, m_thumbBorderColor, m_thumbBorderRadius, 1);
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::onMouseDragged(const Event& event)
|
||||
{
|
||||
if (!m_mousePressed)
|
||||
return;
|
||||
|
||||
if (is_mouse_in_thumb({ event.mouse->position_x, event.mouse->position_y }))
|
||||
m_mouseDragged = true;
|
||||
|
||||
if (m_mouseDragged)
|
||||
{
|
||||
auto bounds = getGlobalBounds() - m_correctionOffset;
|
||||
f32 newThumbX = (event.mouse->position_x - bounds.x) - m_dragGrabOffset;
|
||||
set_thumb_x(newThumbX);
|
||||
}
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::onMousePressed(const Event& event)
|
||||
{
|
||||
m_mousePressed = true;
|
||||
m_dragGrabOffset = event.mouse->position_x - m_thumbGlobalBounds.x;
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::onMouseReleased(const Event& event)
|
||||
{
|
||||
m_mousePressed = false;
|
||||
if (event.mouse->mousePressedOnWidget != this)
|
||||
return;
|
||||
if (!m_mouseDragged)
|
||||
{
|
||||
auto bounds = getGlobalBounds() - m_correctionOffset;
|
||||
f32 newThumbX = (event.mouse->position_x - bounds.x);
|
||||
newThumbX -= m_thumbWidth / 2.0f;
|
||||
set_thumb_x(newThumbX);
|
||||
}
|
||||
m_mouseDragged = false;
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::onUpdate(void)
|
||||
{
|
||||
update_thumb();
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::update_thumb(void)
|
||||
{
|
||||
x = 0;
|
||||
y = getParent()->getSize().y - h;
|
||||
w = getParent()->getGlobalBounds().w;
|
||||
|
||||
auto ext = getParent()->getContentExtents();
|
||||
auto cont = getParent()->getContentBounds();
|
||||
auto scrollOfset = getParent()->getScrollOffset();
|
||||
|
||||
// Thumb size is proportional to visible/total ratio
|
||||
f32 visibleRatio = cont.w / ext.w; // e.g. 0.4 means 40% visible
|
||||
m_thumbWidth = std::max(20.0f, getw() * visibleRatio); // min 20px for usability
|
||||
|
||||
// Thumb position is proportional to scroll progress
|
||||
f32 scrollProgress = -scrollOfset.x / (ext.w - cont.w); // 0 to 1
|
||||
m_thumbX = getx() + ((getw() - m_thumbWidth) * scrollProgress);
|
||||
|
||||
auto bounds = getGlobalBounds() - m_correctionOffset;
|
||||
m_thumbGlobalBounds = { bounds.x + 2 + m_thumbX, bounds.y + gety(), m_thumbWidth, geth() - 4 };
|
||||
std::cout << Rectangle::toString() << "\n";
|
||||
}
|
||||
|
||||
void HorizontalScrollbar::set_thumb_x(f32 thumbx)
|
||||
{
|
||||
auto bounds = getGlobalBounds() - m_correctionOffset;
|
||||
auto ext = getParent()->getContentExtents();
|
||||
auto cont = getParent()->getContentBounds();
|
||||
thumbx = std::clamp(thumbx, 0.0f, w - m_thumbWidth);
|
||||
m_thumbX = thumbx;
|
||||
f32 scrollProgress = (bounds.x + getx() + m_thumbX - bounds.x) / (bounds.w - m_thumbWidth);
|
||||
f32 maxScroll = -(ext.w - cont.w);
|
||||
auto parentScrollOffset = getParent()->getScrollOffset();
|
||||
parentScrollOffset.x = maxScroll * scrollProgress;
|
||||
getParent()->setScrollOffset(parentScrollOffset);
|
||||
}
|
||||
|
||||
bool HorizontalScrollbar::is_mouse_in_thumb(const Vec2& mouse_pos)
|
||||
{
|
||||
return m_thumbGlobalBounds.contains(mouse_pos, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,9 +31,8 @@ namespace ogfx
|
|||
class VerticalScrollBar : public Widget
|
||||
{
|
||||
public:
|
||||
inline VerticalScrollBar(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(""); }
|
||||
inline VerticalScrollBar(WindowCore& window, const String& text) : Widget({ 0, 0, 0, 0 }, window) { create(text); }
|
||||
VerticalScrollBar& create(const String& text);
|
||||
inline VerticalScrollBar(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
|
||||
VerticalScrollBar& create(void);
|
||||
void applyTheme(const ostd::Stylesheet& theme) override;
|
||||
void afterDraw(ogfx::BasicRenderer2D& gfx) override;
|
||||
void onMouseDragged(const Event& event) override;
|
||||
|
|
@ -67,6 +66,44 @@ namespace ogfx
|
|||
Color m_thumbBorderColor { 150, 150, 150 };
|
||||
bool m_thumbShowBorder { true };
|
||||
};
|
||||
class HorizontalScrollbar : public Widget
|
||||
{
|
||||
public:
|
||||
inline HorizontalScrollbar(WindowCore& window) : Widget({ 0, 0, 0, 0 }, window) { create(); }
|
||||
HorizontalScrollbar& create(void);
|
||||
void applyTheme(const ostd::Stylesheet& theme) override;
|
||||
void afterDraw(ogfx::BasicRenderer2D& gfx) override;
|
||||
void onMouseDragged(const Event& event) override;
|
||||
void onMousePressed(const Event& event) override;
|
||||
void onMouseReleased(const Event& event) override;
|
||||
void onUpdate(void) override;
|
||||
|
||||
inline void setx(f32 xx) override { }
|
||||
inline void sety(f32 yy) override { }
|
||||
inline void setw(f32 ww) override { }
|
||||
inline void seth(f32 hh) override { }
|
||||
|
||||
private:
|
||||
void update_thumb(void);
|
||||
void set_thumb_x(f32 thumbx);
|
||||
bool is_mouse_in_thumb(const Vec2& mouse_pos);
|
||||
|
||||
private:
|
||||
f32 m_thumbWidth { 0 };
|
||||
f32 m_thumbX { 0 };
|
||||
Rectangle m_thumbGlobalBounds { 0, 0, 0, 0 };
|
||||
bool m_mousePressed { false };
|
||||
bool m_mouseDragged { false };
|
||||
f32 m_dragGrabOffset { 0 };
|
||||
Rectangle m_correctionOffset { 0, 0, 0, 0 };
|
||||
|
||||
Rectangle m_trackBorderRadii { 0, 0, 10, 10 };
|
||||
f32 m_thumbBorderRadius { 16 };
|
||||
Color m_trackColor { 70, 70, 70 };
|
||||
Color m_thumbColor { 120, 120, 120 };
|
||||
Color m_thumbBorderColor { 150, 150, 150 };
|
||||
bool m_thumbShowBorder { true };
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,6 +211,7 @@ namespace ogfx
|
|||
gfx.fillRect({ getGlobalPosition(), getSize() }, getDrawBoxColor());
|
||||
else
|
||||
{
|
||||
beforeDraw(gfx);
|
||||
if (m_showBackground && m_showBorder)
|
||||
gfx.outlinedRoundRect({ getGlobalPosition(), getSize() }, m_backgroundColor, m_borderColor, m_borderRadius, m_borderWidth);
|
||||
else if (m_showBackground)
|
||||
|
|
|
|||
|
|
@ -56,7 +56,8 @@ namespace ogfx
|
|||
inline virtual Vec2 getScrollOffset(void) const { return { 0, 0 }; }
|
||||
inline virtual void setScrollOffset(const Vec2& offset) { }
|
||||
inline virtual void addScrollOffset(const Vec2& offset) { }
|
||||
inline virtual bool needsScroll(void) const { return false; }
|
||||
inline virtual bool needsVScroll(void) const { return false; }
|
||||
inline virtual bool needsHScroll(void) const { return false; }
|
||||
void addThemeOverride(const String& fullKey, ostd::Stylesheet::TypeVariant value);
|
||||
void reloadTheme(bool propagate = false);
|
||||
void setThemeQualifier(const String& qualifier, bool value = true);
|
||||
|
|
@ -68,6 +69,7 @@ namespace ogfx
|
|||
|
||||
inline virtual void onDraw(ogfx::BasicRenderer2D& gfx) { }
|
||||
inline virtual void afterDraw(ogfx::BasicRenderer2D& gfx) { }
|
||||
inline virtual void beforeDraw(ogfx::BasicRenderer2D& gfx) { }
|
||||
inline virtual void onUpdate(void) { }
|
||||
inline virtual void onWidgetAdded(Widget& child) { }
|
||||
|
||||
|
|
|
|||
|
|
@ -104,6 +104,7 @@ class Window : public ogfx::gui::Window
|
|||
void onRedraw(ogfx::BasicRenderer2D& gfx) override
|
||||
{
|
||||
gfx.drawAnimation(m_anim, { 200, 200 });
|
||||
// gfx.fillRect(m_panel2.getGlobalContentBounds(), { 0, 255, 0, 120 });
|
||||
}
|
||||
|
||||
void onFixedUpdate(void) override
|
||||
|
|
|
|||
Loading…
Reference in a new issue