Added animations to file selector

This commit is contained in:
Yousef Khadadeh 2026-04-24 11:07:15 +03:00
parent 4e17d6e40c
commit 2d039dc47b
10 changed files with 250 additions and 178 deletions

View file

@ -11,59 +11,6 @@ void LayoutElement::layout(const Clay_ElementId& id, const std::function<void(La
layout(this, id);
}
void LayoutElement::update() {
for(auto& [id, animation] : animations) {
switch(animation.state) {
case InternalFloatAnimation::State::RUN: {
animation.currentTime += gui.io.deltaTime;
if(animation.currentTime >= animation.anim.duration) {
animation.currentTime = animation.anim.duration;
animation.state = InternalFloatAnimation::State::DONE;
}
gui.set_to_layout();
break;
}
case InternalFloatAnimation::State::RUN_REVERSE: {
animation.currentTime -= gui.io.deltaTime;
if(animation.currentTime <= 0.0f) {
animation.currentTime = 0.0f;
animation.state = InternalFloatAnimation::State::DONE;
}
gui.set_to_layout();
break;
}
case InternalFloatAnimation::State::DONE:
break;
}
}
}
float LayoutElement::get_float_animation(const char* animationID, const FloatAnimation& animation) {
InternalFloatAnimation internalAnim;
internalAnim.anim = animation;
auto [it, placed] = animations.emplace(animationID, internalAnim);
const InternalFloatAnimation& actualInternalAnim = it->second;
return std::lerp(actualInternalAnim.anim.startVal, actualInternalAnim.anim.endVal, actualInternalAnim.anim.easing(it->second.currentTime / actualInternalAnim.anim.duration));
}
void LayoutElement::animation_trigger(const char* animationID) {
auto it = animations.find(animationID);
if(it != animations.end()) {
InternalFloatAnimation& animation = it->second;
if(animation.currentTime < animation.anim.duration)
animation.state = InternalFloatAnimation::State::RUN;
}
}
void LayoutElement::animation_trigger_reverse(const char* animationID) {
auto it = animations.find(animationID);
if(it != animations.end()) {
InternalFloatAnimation& animation = it->second;
if(animation.currentTime > 0.0f)
animation.state = InternalFloatAnimation::State::RUN_REVERSE;
}
}
void LayoutElement::input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) {
if(c.mouseButton) c.mouseButton(this, button);
}

View file

@ -1,6 +1,5 @@
#pragma once
#include "Element.hpp"
#include "Helpers/BezierEasing.hpp"
namespace GUIStuff {
@ -13,32 +12,12 @@ class LayoutElement : public Element {
std::function<void(LayoutElement* l, const InputManager::MouseWheelCallbackArgs& wheel)> mouseWheel;
std::function<void(LayoutElement* l, const InputManager::KeyCallbackArgs& key)> key;
};
struct FloatAnimation {
float startVal = 0.0f;
float endVal = 1.0f;
float duration = 1.0f;
BezierEasing easing = BezierEasing::linear;
};
void layout(const Clay_ElementId& id, const std::function<void(LayoutElement*, const Clay_ElementId&)>& layout, const Callbacks& c = {});
virtual void update() override;
float get_float_animation(const char* animationID, const FloatAnimation& animation);
void animation_trigger(const char* animationID);
void animation_trigger_reverse(const char* animationID);
virtual void input_mouse_button_callback(const InputManager::MouseButtonCallbackArgs& button) override;
virtual void input_mouse_motion_callback(const InputManager::MouseMotionCallbackArgs& motion) override;
virtual void input_mouse_wheel_callback(const InputManager::MouseWheelCallbackArgs& wheel) override;
virtual void input_key_callback(const InputManager::KeyCallbackArgs& key) override;
private:
struct InternalFloatAnimation {
enum class State {
RUN,
RUN_REVERSE,
DONE
} state = State::DONE;
float currentTime = 0.0f;
FloatAnimation anim;
};
std::unordered_map<const char*, InternalFloatAnimation> animations;
Callbacks c;
};

View file

@ -0,0 +1,68 @@
#include "GUIFloatAnimation.hpp"
#include "GUIManager.hpp"
namespace GUIStuff {
GUIFloatAnimation::GUIFloatAnimation(const GUIFloatAnimationData& animData):
anim(animData),
animVal(animData.startVal)
{}
bool GUIFloatAnimation::is_at_start() {
return state == State::DONE && currentTime == 0.0f;
}
bool GUIFloatAnimation::is_at_end() {
return state == State::DONE && currentTime == anim.duration;
}
bool GUIFloatAnimation::is_done() {
return state == State::DONE;
}
void GUIFloatAnimation::calculate_anim_val() {
animVal = std::lerp(anim.startVal, anim.endVal, anim.easing(currentTime / anim.duration));
}
void GUIFloatAnimation::update(GUIManager& gui) {
switch(state) {
case State::RUN: {
currentTime += gui.io.deltaTime;
if(currentTime >= anim.duration) {
currentTime = anim.duration;
state = State::DONE;
}
calculate_anim_val();
gui.set_to_layout();
break;
}
case State::RUN_REVERSE: {
currentTime -= gui.io.deltaTime;
if(currentTime <= 0.0f) {
currentTime = 0.0f;
state = State::DONE;
}
calculate_anim_val();
gui.set_to_layout();
break;
}
case State::DONE:
break;
}
}
float GUIFloatAnimation::get_val() const {
return animVal;
}
void GUIFloatAnimation::animation_trigger() {
if(currentTime < anim.duration)
state = State::RUN;
}
void GUIFloatAnimation::animation_trigger_reverse() {
if(currentTime > 0.0f)
state = State::RUN_REVERSE;
}
}

View file

@ -0,0 +1,40 @@
#pragma once
#include <Helpers/BezierEasing.hpp>
namespace GUIStuff {
class GUIManager;
struct GUIFloatAnimationData {
float startVal = 0.0f;
float endVal = 1.0f;
float duration = 1.0f;
BezierEasing easing = BezierEasing::linear;
};
class GUIFloatAnimation {
public:
GUIFloatAnimation(const GUIFloatAnimationData& animData);
void update(GUIManager& gui);
void animation_trigger();
void animation_trigger_reverse();
float get_val() const;
bool is_at_start();
bool is_at_end();
bool is_done();
bool isUsedThisFrame;
private:
void calculate_anim_val();
enum class State {
RUN,
RUN_REVERSE,
DONE
} state = State::DONE;
float currentTime = 0.0f;
GUIFloatAnimationData anim;
float animVal;
};
}

View file

@ -506,6 +506,19 @@ void GUIManager::update_invalidated_draw_area_from_layout() {
void GUIManager::update() {
for(ElementContainer* e : orderedElements)
e->elem->update();
for(auto& [id, animation] : animations)
animation.update(*this);
}
GUIFloatAnimation* GUIManager::float_animation(const char* animationID, const GUIFloatAnimationData& animation) {
GUIFloatAnimation* toRet = nullptr;
new_id(animationID, [&] {
auto [it, placed] = animations.emplace(idStack, animation);
GUIFloatAnimation& actualInternalAnim = it->second;
actualInternalAnim.isUsedThisFrame = true;
toRet = &actualInternalAnim;
});
return toRet;
}
void GUIManager::update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier) {
@ -539,6 +552,8 @@ void GUIManager::layout() {
void GUIManager::layout_begin() {
for(auto& [id, e] : elements)
e.isUsedThisFrame = false;
for(auto& [id, a] : animations)
a.isUsedThisFrame = false;
Clay_SetLayoutDimensions(Clay_Dimensions(io.windowSize.x(), io.windowSize.y()));
Clay_SetCurrentContext(clayInstance);
@ -557,6 +572,9 @@ void GUIManager::layout_end() {
std::erase_if(elements, [](auto& p) {
return !p.second.isUsedThisFrame;
});
std::erase_if(animations, [](auto& p) {
return !p.second.isUsedThisFrame;
});
std::stable_sort(orderedElements.begin(), orderedElements.end(), [](ElementContainer* a, ElementContainer* b) {
return b->elem->zIndex < a->elem->zIndex; // Order from highest to lowest zIndex
});

View file

@ -4,6 +4,7 @@
#include "GUIManagerID.hpp"
#include <clay.h>
#include "Elements/Element.hpp"
#include "GUIFloatAnimation.hpp"
using namespace Eigen;
@ -22,6 +23,8 @@ class GUIManager {
void set_to_layout();
void layout_if_necessary();
GUIFloatAnimation* float_animation(const char* animationID, const GUIFloatAnimationData& animation);
void update();
void update_window(const Vector2f& windowPos, const Vector2f& windowSize, float guiScaleMultiplier);
@ -101,6 +104,8 @@ class GUIManager {
bool cursor_obstructed() const;
private:
std::unordered_map<GUIManagerIDStack, GUIFloatAnimation> animations;
void layout();
void layout_begin();
void layout_end();