Refactor tweening some.

This commit is contained in:
2025-04-07 00:09:17 -04:00
parent 2e0ce74753
commit d0fcf9cce2
3 changed files with 63 additions and 25 deletions

View File

@@ -34,8 +34,7 @@ namespace JUI {
/// Widget is the base class for all JUI elements and represents any object that can be in the tree hierarchy.
/// Some widgets are expressly used for layout, and therefore do not strictly speaking 'Appear' on screen.
/// Widgets exist in a tree hierarchy where each object has one parent, and an arbitrary number of children. No circular references are allowed.
class Widget
{
class Widget {
public:
/// The default constructor for Widget. Generally, JUI widgets will initialize member data,
/// and apply a default style in this constructor. Be aware of this, as this is not "idiomatic C++".
@@ -44,6 +43,7 @@ namespace JUI {
Widget(Widget* parent);
virtual ~Widget() {}
public:
#pragma region Events
/// An event that triggers when the widget is in-focus, generally when the mouse is hovering it.
/// (The actual trigger may differ for each widget)
Event<> Focused;
@@ -61,10 +61,9 @@ namespace JUI {
Event<Widget *> ChildRemoved;
/// This event triggers right before this widget gets deallocated.
Event<Widget *> Destroying;
#pragma endregion
public:
Tween* TweenPosition(const UDim2& goal, TweenInfo params = {});
Tween* TweenSize(const UDim2& goal, TweenInfo params = {});
#pragma region Hierarchy
/// Adds a given widget to this widget's list of children.
/// @return The widget in question.
Widget* Add(Widget* newChild);
@@ -95,6 +94,24 @@ namespace JUI {
/// @see GetFamilyTreeRoot().
Widget* GetParent() const;
/// Sets the parent object of this widget. Positioning and sizing of a widget is relative to it's parent.
void Parent(Widget*);
/// Returns true if this widget is a 'descendant' of the specified potential ancestor. Otherwise returns false.
bool IsDescendantOf(Widget *ancestor);
/// Returns true if this widget is a 'ancestor' of the specified potential descendant. Otherwise returns false.
bool IsAncestorOf(Widget *descendant);
/// Returns the first ancestor in this widgets hierarchy that does not have its own parent.
/// In a well-formed JUI menu, this **should** always be a Scene.
Widget* GetFamilyTreeRoot() const;
#pragma endregion
#pragma region Layout
/// Returns the menu-coordinates that are used to position this widget in relation to its parent.
/// @see class UDim2, Position(const UDim2&),
[[nodiscard]] UDim2 Position() const;
@@ -125,17 +142,13 @@ namespace JUI {
/// @see Size(), class UDim2.
void Size(const UDim2&);
/// Sets the parent object of this widget. Positioning and sizing of a widget is relative to it's parent.
void Parent(Widget*);
/// Creates and runs an animation on the Position of this widget.
Tween* TweenPosition(const UDim2& goal, TweenInfo params = {});
/// Returns true if this widget is a 'descendant' of the specified potential ancestor. Otherwise returns false.
bool IsDescendantOf(Widget *ancestor);
/// Returns true if this widget is a 'ancestor' of the specified potential descendant. Otherwise returns false.
bool IsAncestorOf(Widget *descendant);
/// Creates and runs an animation on the Size of this widget.
Tween* TweenSize(const UDim2& goal, TweenInfo params = {});
/// Determines the origin point of a Widget, relative to it's absolute size.
/// TODO: Better explain what this allows for.
[[nodiscard]] Vector2 AnchorPoint() const;
///
@@ -144,6 +157,8 @@ namespace JUI {
///
Tween* TweenAnchorPoint(const Vector2& goal, TweenInfo info = {});
#pragma endregion
#pragma region Padding
/// Returns the padding factor on the left of this widget.
/// Padding refers to spacing on the inside of elements, while margin is spacing outside the element.
@@ -245,6 +260,7 @@ namespace JUI {
#pragma endregion
#pragma region Metadata
/// Returns this widgets mnemonic name.
/// Widgets can optionally be assigned a name that can be used to retrieve it from a widget tree node.
/// @see Name().
@@ -264,9 +280,7 @@ namespace JUI {
/// @see IsVisible().
void Visible(bool enabled);
/// Returns the first ancestor in this widgets hierarchy that does not have its own parent.
/// In a well-formed JUI menu, this **should** always be a Scene.
Widget* GetFamilyTreeRoot() const;
/// Returns whether or not the mouse is inside this widget's approximate bounding-box.
bool IsMouseInside() const;
@@ -275,6 +289,10 @@ namespace JUI {
void LayoutOrder(int value) { layout_order = value;}
#pragma endregion
/// Returns the complete bounding box around this instance that will be rendered onto.
/// This differs from AbsolutePosition and AbsoluteSize in that they are computed for positioning elements relative to each other.
/// Only this method represents the full bounding box of the widget.
@@ -290,12 +308,8 @@ namespace JUI {
public:
// TODO: Consider calling J2D::Begin here.
virtual void PreDraw() {}
// TODO: Consider calling J2D::End here.
virtual void PostDraw() {}
virtual void InnerDraw() {}

View File

@@ -85,13 +85,14 @@ namespace JUI
int repeats = 0;
bool reverse = false;
EasingFunc easing = &EasingFunctions::EaseInOutLinear;
bool overwritable = true;
};
/// A class that represents an animation-in-action.
class Tween {
public:
Tween(TweenTickFunc tick_func);
Tween(TweenTickFunc tick_func, TweenInfo info) {
Tween(TweenTickFunc tick_func, const TweenInfo& info) {
this->tick_func = tick_func;
this->time = info.time;
@@ -99,6 +100,7 @@ namespace JUI
this->repeat_count = info.repeats;
this->reverses = info.reverse;
this->easing_func = info.easing;
this->overwritable = info.overwritable;
}
Event<> Completed;
@@ -120,6 +122,7 @@ namespace JUI
bool alive = true;
bool paused = false;
bool completed = false;
bool overwritable = true;
void Cancel();

View File

@@ -270,9 +270,14 @@ void Widget::UpdateTweens(float elapsed) {
t->Update(elapsed);
// TODO: Remove tweens if "dead"
std::ranges::remove_if(tweens.begin(), tweens.end(), [](Tween* t){
return t->HasCompleted();
});
tweens.erase(std::remove_if(tweens.begin(), tweens.end(), [](Tween* t){
if (t->HasCompleted())
{
return true;
}
return false;
}), tweens.end());
}
void Widget::Update(float delta) {
@@ -604,8 +609,24 @@ Tween* Widget::TweenMarginBottom(const JUI::UDim& goal, JUI::TweenInfo info) {
return t;
}
Tween *Widget::TweenAnchorPoint(const Vector2 &goal, TweenInfo info) {
Vector2 start = this->AnchorPoint();
TweenTickFunc updateTillGoalReached = [this, start, goal] (float elapsed, float progress) mutable {
Vector2 step = start.Lerp(goal, progress);
AnchorPoint(step);
};
Tween* t = new Tween(updateTillGoalReached, info);
tweens.push_back(t);
return t;
}
float Widget::ComputeElementPadding(float size, const UDim &padding) {
return padding.Pixels + (padding.Scale * size);
}
}