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
|
||||
useSelectionGradient = true
|
||||
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 not clickable even when no horizontal scrollbar present
|
||||
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
|
||||
***Grid
|
||||
***Fill
|
||||
ComboBox
|
||||
***ComboBox
|
||||
TreeView
|
||||
Text Input
|
||||
Text Area
|
||||
|
|
|
|||
|
|
@ -62,20 +62,52 @@ namespace ogfx
|
|||
setBorderColor(theme.get<Color>("context.borderColor", getBorderColor(), {}, {}));
|
||||
enableSelectionGradient(theme.get<bool>("context.useSelectionGradient", isSelectionGradientEnabled(), {}, {}));
|
||||
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)
|
||||
{
|
||||
if (!m_visible) return;
|
||||
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);
|
||||
gfx.popClippingRect();
|
||||
}
|
||||
}
|
||||
|
||||
void ContextMenu::update(void)
|
||||
{
|
||||
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];
|
||||
i32 entryIdx = m_pendingOpenEntryIndex;
|
||||
|
|
@ -271,6 +303,7 @@ namespace ogfx
|
|||
m_panels.clear();
|
||||
push_panel(m_data.entries, pos, false);
|
||||
m_visible = true;
|
||||
m_animClock.startCount(ostd::eTimeUnits::Milliseconds);
|
||||
}
|
||||
|
||||
void ContextMenu::hide(void)
|
||||
|
|
@ -282,6 +315,7 @@ namespace ogfx
|
|||
m_hoverCloseTimerActive = false;
|
||||
m_pendingOpenPanelDepth = -1;
|
||||
m_pendingOpenEntryIndex = -1;
|
||||
m_animClock.endCount();
|
||||
m_visible = false;
|
||||
}
|
||||
|
||||
|
|
@ -327,6 +361,7 @@ namespace ogfx
|
|||
if (p.position.y < 0) p.position.y = 0;
|
||||
if (p.position.x < 0) p.position.x = 0;
|
||||
|
||||
p.animProgress = m_animateOpen ? 0.0f : 1.0f;
|
||||
m_panels.push_back(p);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -110,6 +110,8 @@ namespace ogfx
|
|||
f32 entryHeight { 0 };
|
||||
i32 hoveredIndex { -1 };
|
||||
i32 openedSubmenuIndex { -1 };
|
||||
|
||||
f32 animProgress { 0 }; // 0.0 = collapsed, 1.0 = fully open
|
||||
};
|
||||
public:
|
||||
inline ContextMenu(WindowCore& window) : m_window(window) { create(); }
|
||||
|
|
@ -140,6 +142,8 @@ namespace ogfx
|
|||
OSTD_PARAM_GETSET(Color, BorderColor, m_borderColor);
|
||||
OSTD_PARAM_GETSET(ColorGradient, SelectionGradient, m_selectionGradient);
|
||||
OSTD_BOOL_PARAM_GETSET_E(SelectionGradient, m_useSelectionGradient);
|
||||
OSTD_BOOL_PARAM_GETSET_E(OpenAnimation, m_animateOpen);
|
||||
OSTD_PARAM_GETSET(u64, AnimationDelayMS, m_animationDelayMS);
|
||||
|
||||
private:
|
||||
void push_panel(stdvec<Entry>& entries, const Vec2& anchorTopLeft, bool flipLeft = false);
|
||||
|
|
@ -156,6 +160,7 @@ namespace ogfx
|
|||
Instance m_data;
|
||||
f32 m_entryHeight { 0 };
|
||||
Vec2 m_mousePos { 0, 0 };
|
||||
ostd::Timer m_animClock;
|
||||
|
||||
stdvec<Panel> m_panels;
|
||||
|
||||
|
|
@ -178,9 +183,11 @@ namespace ogfx
|
|||
Color m_borderColor { "#400000FF" };
|
||||
bool m_useSelectionGradient { true };
|
||||
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 OpenAnimDurationMs { 120 };
|
||||
friend class Instance;
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -829,7 +829,7 @@ namespace ogfx
|
|||
setTypeName("ogfx::gui::Window");
|
||||
m_gfx.init(*this);
|
||||
loadDefaultTHeme();
|
||||
setBlockingEventsRefreshFPS(30);
|
||||
setBlockingEventsRefreshFPS(60);
|
||||
|
||||
m_fixedUpdateTimer.create(60.0, [this](f64 dt) {
|
||||
__on_fixed_update();
|
||||
|
|
|
|||
Loading…
Reference in a new issue