Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enhancing State Management and Animations in ImGui Widgets #6905

Closed
pinwhell opened this issue Oct 6, 2023 · 7 comments
Closed

Enhancing State Management and Animations in ImGui Widgets #6905

pinwhell opened this issue Oct 6, 2023 · 7 comments

Comments

@pinwhell
Copy link

pinwhell commented Oct 6, 2023

  • Branch: Master
  • Version: Lastests
  • Backend: GLFW, GL

Dear ImGui is a versatile and widely-used GUI library, but managing state and animations within custom widgets can be a nuanced and challenging task. This inquiry aims to explore the mechanisms available for handling state and animations within the ImGui framework.

User as the Source of Truth:

ImGui adheres to the paradigm that "the user is always the source of truth." When considering state, this means that the user should ideally be responsible for maintaining and managing the state of widgets. However, this approach can lead to some practical challenges. For example, when dealing with animations that are unrelated to the user's immediate interaction, it can be cumbersome for users to pass a state struct to custom widgets every time they are invoked.

Framework Creator Challenges:

For those creating frameworks or higher-level abstractions on top of ImGui, managing the lifetime of state structs becomes a complex issue. ImGui itself lacks a built-in mechanism to automatically handle the preservation of state between frames or across multiple invocations. This can result in challenges related to memory management and the need for custom solutions.

Keep Alive Mechanism:

It's worth noting that core ImGui does not offer a built-in "keep alive" mechanism that automatically manages the lifetime of state structs. As such, developers are left to implement their own solutions to ensure the persistence of state across frames.

Given these considerations, it would be beneficial for ImGui to explore potential enhancements in state management, particularly with regards to animations and custom widget development. This could involve the introduction of a more robust state management system or a mechanism for automatically handling the lifetime of state structs. Such improvements could simplify the development process for both individual users and framework creators while maintaining ImGui's user-centric approach to UI design.

Say we are the Framework maker, sitting at the middle, say we are doing a simple Toggle Switch Widget, and say we want to animate, consider this dummy example:

struct ToggleAnimationState {
    bool last;
    float time;
};

// Define a map to store the state of all toggle switches
std::unordered_map<ImGuiID, ToggleAnimationState> toggleSwitchStates;

void ImGui::ToggleSwitch(const char* toggle_id, bool* b, const ImVec2& _toggleSize, float rounding)
{
    // Code ...
    const ImGuiID id = window->GetID(toggle_id);

   // Code ...
    
    if (toggleSwitchStates.find(id) == toggleSwitchStates.end())
    {
        // State didn't exits, Creating & Initializing here
        
        toggleSwitchStates[id].last = *b;
        toggleSwitchStates[id].time = 1.f;
    }

    ToggleAnimationState& state = toggleSwitchStates[id]; 

    if (state.last != *b)
    {
        state.time = 1.f - state.time;
        state.last = *b;
    }

    float animationSpeed = 1.f / TOGGLE_ANIM_DURATION; // Adjust the animation speed as needed
    state.time += ImGui::GetIO().DeltaTime * animationSpeed;

    if (state.time < 0.f)
        state.time = 0.f;
    if (state.time > 1.f)
        state.time = 1.f;
        
    // More Code ...
}

Managing the memory aspect of state in a custom ImGui widget, such as a Toggle Switch, can indeed become tricky. Here's a concise description of the issue:

When developing custom widgets in ImGui, like the Toggle Switch, memory management for the widget's state can be a concern. In the provided code, a map (toggleSwitchStates) is used to store the state of all Toggle Switches. While this approach allows for state persistence between frames, it lacks an efficient mechanism to clear entries when a Toggle Switch is no longer in use.

The problem arises when the user repeatedly calls the widget with different IDs. Unused entries in the map may accumulate, leading to a memory leak-like situation. These entries persist indefinitely unless the same ID is reused in the future.

To address this issue, a more efficient memory management strategy is needed. This could involve implementing a mechanism to clean up or recycle unused entries in the map when they are no longer in active use. This would help ensure that memory is used efficiently while maintaining the desired state persistence across frames for active Toggle Switches.

Thanks!!!

@nicolasnoble
Copy link
Contributor

Except that it's also the responsibility of the user in this case to generate these IDs. ImGui doesn't offer mechanisms to persist states for IDs because (1) the user calling into ImGui may not want any persistence either or (2) if using persistence, it is responsible for holding such persistence.

If you want to provide a middleware which would do things like stateful animations, then said middleware could provide a non-immediate paradigm to create and destroy widgets, and internally call into the corresponding ImGui API. Or if trying to use the same immediate paradigm as ImGui, rely on the fact the caller of the middleware would also consistently call into the API to draw the same widget over and over just like normal ImGui. At the beginning of each frame, you sweep the animation state map to clear out a boolean indicating it's been drawn, and at the end of each frame, you can garbage-collect any widget from the animation state map which wasn't drawn with a second sweep.

@pinwhell
Copy link
Author

pinwhell commented Oct 6, 2023

The perspective that "if using persistence, it is responsible for holding such persistence" is indeed noteworthy. However, it's crucial to recognize that this approach can potentially place an unwarranted burden on users. While ImGui adheres to the principle that the user should be the source of truth, there are situations where automatic state management, especially for animations, could vastly enhance the user experience.

One plausible solution is to create middleware or higher-level abstractions that offer a non-immediate paradigm for creating and destroying widgets. In this context, middleware could seamlessly interact with the ImGui API, effectively handling state management and animations. It's important to bear in mind that not all users may feel comfortable or possess the expertise to develop such middleware themselves.

Regarding the suggestion to "garbage-collect any widget from the animation state map which wasn't drawn with a second sweep," this approach does contribute to cleaning up unused widget states, but it does require additional manual intervention. The underlying concern here is that ImGui's design philosophy, which places the responsibility for managing state persistence largely on the user, can lead to repetitive and error-prone code, particularly when dealing with animations and custom widget development.

The overarching recommendation is that ImGui, renowned for its versatility as a GUI library, could greatly benefit from augmentations in state management, particularly concerning animations. This could entail the introduction of a mechanism within ImGui to handle rendering side state, a facet distinct from the source of truth represented by the bool* state being passed. Such an enhancement could significantly streamline the development process, mitigating the risk of memory-related issues, as previously mentioned. Ultimately, it would elevate the framework's user-friendliness by automating aspects of state management that currently fall under the purview of individual users or middleware developers.

In conclusion, while ImGui's philosophy respects user control and customization, there is room for improvement in state management, especially for animations. Introducing mechanisms that offer a more automated approach to state handling could enhance the framework's usability and efficiency, aligning it even more closely with the needs and expectations of its diverse user base.

@nicolasnoble
Copy link
Contributor

Is... is this ChatGPT? This feels like it's generated by ChatGPT.

@nicolasnoble
Copy link
Contributor

Yeah okay, this is Hacktoberfest ChatGPT spam. Apparently it's happening all over github. Good times.

@ocornut
Copy link
Owner

ocornut commented Oct 6, 2023

There are related discussions at #3418 so this is seemingly a duplicate topic. So let's move this there.

What's strange is that you provided 80% of the code you need, you only need an extra loop to evince value associated to old times, to do that sort of things.
I'm afraid you are misunderstanding that what's rather easy to handle on your side (because you have a specific tailored easy) could get hairy and complicated to design if it was provided in dear imgui land.. I'm not ruling out we implement some helper to facilitate variety of storage. But please read all the linked issues.

Also consider somehow related conversations about persistence at #6215 (comment) and #437.

Also see #1537: we currently provide a single timer for Activated/Hovered ID. This is the cheap and dumb solution that gets you 90% of the way for real world interactions like animating a toggle (which is your example).

@ocornut ocornut closed this as completed Oct 6, 2023
@pinwhell
Copy link
Author

pinwhell commented Oct 6, 2023

Is... is this ChatGPT? This feels like it's generated by ChatGPT.

I write down the answer myself, then ChatGPT Does the revision for me, polishing it etc, i feel it help me to better communicate in a more efficient way and help me to transmit exactly what i want to say/communicate in a very efficient manner!

we currently provide a single timer for Activated/Hovered ID. This is the cheap and dumb solution that gets you 90% of the way for real world interactions like animating a toggle (which is your example).

Very interesting, i will take a look

@nicolasnoble
Copy link
Contributor

I write down the answer myself, then ChatGPT Does the revision for me, polishing it etc, i feel it help me to better communicate in a more efficient way and help me to transmit exactly what i want to say/communicate in a very efficient manner!

You may feel this way, but it really doesn't. Plus there's been an increase in ChatGPT-driven spam issues and pull requests due to people trying to cheese their way into Hacktoberfest 2023, so clearly copy pasting the output of ChatGPT without even removing the useless introduction "imgui is a versatile GUI library" will just get you lumped into the same group.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants