Added Context Menu ANimation
This commit is contained in:
parent
68bf336530
commit
2de45908a9
5 changed files with 50 additions and 4 deletions
|
|
@ -287,6 +287,8 @@ const $backgroundColor = rgba(30, 30, 30, 255)
|
||||||
borderColor = $borderColor
|
borderColor = $borderColor
|
||||||
useSelectionGradient = true
|
useSelectionGradient = true
|
||||||
selectionGradient = gradientV($accentColor - $accentColorDark)
|
selectionGradient = gradientV($accentColor - $accentColorDark)
|
||||||
|
animateOpen = true
|
||||||
|
animationDelay = 120
|
||||||
}
|
}
|
||||||
% ==========================
|
% ==========================
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -49,6 +49,8 @@ FIX: Button state getting hung after showing an openFileDialog
|
||||||
FIX: ListView last item is covered by scrollbar
|
FIX: ListView last item is covered by scrollbar
|
||||||
FIX: ListView last item not clickable even when no horizontal scrollbar present
|
FIX: ListView last item not clickable even when no horizontal scrollbar present
|
||||||
FIX: Refresh display text in ComboBox when font size changes and also on theme reload
|
FIX: Refresh display text in ComboBox when font size changes and also on theme reload
|
||||||
|
Add setSelectedMenuItem() function to ComboBox
|
||||||
|
FIX: ContextMenu rendering partly outside the screen when showing it close to the right Window border
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -80,7 +82,7 @@ Implement following widgets:
|
||||||
***Horizontal
|
***Horizontal
|
||||||
***Grid
|
***Grid
|
||||||
***Fill
|
***Fill
|
||||||
ComboBox
|
***ComboBox
|
||||||
TreeView
|
TreeView
|
||||||
Text Input
|
Text Input
|
||||||
Text Area
|
Text Area
|
||||||
|
|
|
||||||
|
|
@ -62,20 +62,52 @@ namespace ogfx
|
||||||
setBorderColor(theme.get<Color>("context.borderColor", getBorderColor(), {}, {}));
|
setBorderColor(theme.get<Color>("context.borderColor", getBorderColor(), {}, {}));
|
||||||
enableSelectionGradient(theme.get<bool>("context.useSelectionGradient", isSelectionGradientEnabled(), {}, {}));
|
enableSelectionGradient(theme.get<bool>("context.useSelectionGradient", isSelectionGradientEnabled(), {}, {}));
|
||||||
setSelectionGradient(theme.get<ColorGradient>("context.selectionGradient", getSelectionGradient(), {}, {}));
|
setSelectionGradient(theme.get<ColorGradient>("context.selectionGradient", getSelectionGradient(), {}, {}));
|
||||||
|
enableOpenAnimation(theme.get<bool>("context.animateOpen", isOpenAnimationEnabled(), {}, {}));
|
||||||
|
setAnimationDelayMS(theme.get<i32>("context.animationDelay", getAnimationDelayMS(), {}, {}));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextMenu::draw(BasicRenderer2D& gfx)
|
void ContextMenu::draw(BasicRenderer2D& gfx)
|
||||||
{
|
{
|
||||||
if (!m_visible) return;
|
if (!m_visible) return;
|
||||||
for (const auto& panel : m_panels)
|
for (const auto& panel : m_panels)
|
||||||
|
{
|
||||||
|
// Apply easing for a more natural feel
|
||||||
|
f32 t = panel.animProgress;
|
||||||
|
f32 eased = 1.0f - (1.0f - t) * (1.0f - t); // ease-out quadratic
|
||||||
|
|
||||||
|
f32 visibleHeight = panel.size.y * eased;
|
||||||
|
|
||||||
|
Rectangle clip {
|
||||||
|
panel.position.x,
|
||||||
|
panel.position.y,
|
||||||
|
panel.size.x,
|
||||||
|
visibleHeight
|
||||||
|
};
|
||||||
|
|
||||||
|
gfx.pushClippingRect(clip);
|
||||||
draw_panel(gfx, panel);
|
draw_panel(gfx, panel);
|
||||||
|
gfx.popClippingRect();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextMenu::update(void)
|
void ContextMenu::update(void)
|
||||||
{
|
{
|
||||||
if (!m_visible) return;
|
if (!m_visible) return;
|
||||||
|
|
||||||
if (m_pendingOpenPanelDepth >= 0 && m_hoverOpenTimerActive && m_hoverOpenTimer.read() >= SubmenuOpenDelayMs)
|
// Advance animation for any panel that isn't fully open yet.
|
||||||
|
f64 deltaMs = m_animClock.read(); // milliseconds since last update
|
||||||
|
m_animClock.restart(ostd::eTimeUnits::Milliseconds);
|
||||||
|
|
||||||
|
for (auto& panel : m_panels)
|
||||||
|
{
|
||||||
|
if (panel.animProgress < 1.0f)
|
||||||
|
{
|
||||||
|
panel.animProgress += (f32)(deltaMs / (f64)OpenAnimDurationMs);
|
||||||
|
if (panel.animProgress > 1.0f) panel.animProgress = 1.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (m_pendingOpenPanelDepth >= 0 && m_hoverOpenTimerActive && m_hoverOpenTimer.read() >= m_animationDelayMS)
|
||||||
{
|
{
|
||||||
Panel& parent = m_panels[m_pendingOpenPanelDepth];
|
Panel& parent = m_panels[m_pendingOpenPanelDepth];
|
||||||
i32 entryIdx = m_pendingOpenEntryIndex;
|
i32 entryIdx = m_pendingOpenEntryIndex;
|
||||||
|
|
@ -271,6 +303,7 @@ namespace ogfx
|
||||||
m_panels.clear();
|
m_panels.clear();
|
||||||
push_panel(m_data.entries, pos, false);
|
push_panel(m_data.entries, pos, false);
|
||||||
m_visible = true;
|
m_visible = true;
|
||||||
|
m_animClock.startCount(ostd::eTimeUnits::Milliseconds);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContextMenu::hide(void)
|
void ContextMenu::hide(void)
|
||||||
|
|
@ -282,6 +315,7 @@ namespace ogfx
|
||||||
m_hoverCloseTimerActive = false;
|
m_hoverCloseTimerActive = false;
|
||||||
m_pendingOpenPanelDepth = -1;
|
m_pendingOpenPanelDepth = -1;
|
||||||
m_pendingOpenEntryIndex = -1;
|
m_pendingOpenEntryIndex = -1;
|
||||||
|
m_animClock.endCount();
|
||||||
m_visible = false;
|
m_visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -327,6 +361,7 @@ namespace ogfx
|
||||||
if (p.position.y < 0) p.position.y = 0;
|
if (p.position.y < 0) p.position.y = 0;
|
||||||
if (p.position.x < 0) p.position.x = 0;
|
if (p.position.x < 0) p.position.x = 0;
|
||||||
|
|
||||||
|
p.animProgress = m_animateOpen ? 0.0f : 1.0f;
|
||||||
m_panels.push_back(p);
|
m_panels.push_back(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -110,6 +110,8 @@ namespace ogfx
|
||||||
f32 entryHeight { 0 };
|
f32 entryHeight { 0 };
|
||||||
i32 hoveredIndex { -1 };
|
i32 hoveredIndex { -1 };
|
||||||
i32 openedSubmenuIndex { -1 };
|
i32 openedSubmenuIndex { -1 };
|
||||||
|
|
||||||
|
f32 animProgress { 0 }; // 0.0 = collapsed, 1.0 = fully open
|
||||||
};
|
};
|
||||||
public:
|
public:
|
||||||
inline ContextMenu(WindowCore& window) : m_window(window) { create(); }
|
inline ContextMenu(WindowCore& window) : m_window(window) { create(); }
|
||||||
|
|
@ -140,6 +142,8 @@ namespace ogfx
|
||||||
OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
|
OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
|
||||||
OSTD_PARAM_GETSET(ColorGradient, SelectionGradient, m_selectionGradient);
|
OSTD_PARAM_GETSET(ColorGradient, SelectionGradient, m_selectionGradient);
|
||||||
OSTD_BOOL_PARAM_GETSET_E(SelectionGradient, m_useSelectionGradient);
|
OSTD_BOOL_PARAM_GETSET_E(SelectionGradient, m_useSelectionGradient);
|
||||||
|
OSTD_BOOL_PARAM_GETSET_E(OpenAnimation, m_animateOpen);
|
||||||
|
OSTD_PARAM_GETSET(u64, AnimationDelayMS, m_animationDelayMS);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void push_panel(stdvec<Entry>& entries, const Vec2& anchorTopLeft, bool flipLeft = false);
|
void push_panel(stdvec<Entry>& entries, const Vec2& anchorTopLeft, bool flipLeft = false);
|
||||||
|
|
@ -156,6 +160,7 @@ namespace ogfx
|
||||||
Instance m_data;
|
Instance m_data;
|
||||||
f32 m_entryHeight { 0 };
|
f32 m_entryHeight { 0 };
|
||||||
Vec2 m_mousePos { 0, 0 };
|
Vec2 m_mousePos { 0, 0 };
|
||||||
|
ostd::Timer m_animClock;
|
||||||
|
|
||||||
stdvec<Panel> m_panels;
|
stdvec<Panel> m_panels;
|
||||||
|
|
||||||
|
|
@ -178,9 +183,11 @@ namespace ogfx
|
||||||
Color m_borderColor { "#400000FF" };
|
Color m_borderColor { "#400000FF" };
|
||||||
bool m_useSelectionGradient { true };
|
bool m_useSelectionGradient { true };
|
||||||
ColorGradient m_selectionGradient { { "#C21135FF", "#820B23FF" }, { 1.0f } };
|
ColorGradient m_selectionGradient { { "#C21135FF", "#820B23FF" }, { 1.0f } };
|
||||||
|
bool m_animateOpen { true };
|
||||||
|
u64 m_animationDelayMS { 300 };
|
||||||
|
|
||||||
static constexpr u64 SubmenuOpenDelayMs { 300 };
|
|
||||||
static constexpr u64 SubmenuCloseDelayMs { 50 };
|
static constexpr u64 SubmenuCloseDelayMs { 50 };
|
||||||
|
static constexpr u64 OpenAnimDurationMs { 120 };
|
||||||
friend class Instance;
|
friend class Instance;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -829,7 +829,7 @@ namespace ogfx
|
||||||
setTypeName("ogfx::gui::Window");
|
setTypeName("ogfx::gui::Window");
|
||||||
m_gfx.init(*this);
|
m_gfx.init(*this);
|
||||||
loadDefaultTHeme();
|
loadDefaultTHeme();
|
||||||
setBlockingEventsRefreshFPS(30);
|
setBlockingEventsRefreshFPS(60);
|
||||||
|
|
||||||
m_fixedUpdateTimer.create(60.0, [this](f64 dt) {
|
m_fixedUpdateTimer.create(60.0, [this](f64 dt) {
|
||||||
__on_fixed_update();
|
__on_fixed_update();
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue