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

Window Hovering fading animation #1925

Open
sonoro1234 opened this issue Jul 4, 2018 · 12 comments
Open

Window Hovering fading animation #1925

sonoro1234 opened this issue Jul 4, 2018 · 12 comments

Comments

@sonoro1234
Copy link

sonoro1234 commented Jul 4, 2018

It has been commented several times.
Here is a proof of concept that it can be done without any ImGui modification

action

This Lua code could be done with a class in C++ or a lambda function and provide us a function that when called from the window to be hovered returns a value in animated variation between two values

-- duration, min desired value, max desired value
local function HoverActionFactory(dur,minv,maxv)

	minv = minv or 0
	maxv = maxv or 1
	local range = maxv - minv
	local lastFrameHovered = false
	local actionTime = 0
	local actionUP = false
	local iniVal = 0
	local currVal = 0
	
	local function SetAction(dir)
		lastFrameHovered = dir
		actionTime = 0
		actionUP = dir
		iniVal = currVal
	end

	local function HoverAction()
		if ig.IsWindowHovered(imgui.ImGuiHoveredFlags_AllowWhenBlockedByPopup + imgui.ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) then
			if not lastFrameHovered then SetAction(true) end
		elseif lastFrameHovered then
			SetAction(false)
		end
		local fac = actionTime/dur
		fac = actionUP and fac or -fac
		currVal = math.min(1,math.max(0,iniVal + fac))
		actionTime = actionTime + ig.GetIO().DeltaTime
		return minv + range*currVal
	end
	return HoverAction
end

To use it just use the HoverActionFactory as in

-- 0.5 sec transition from 0.001 to 1
local HoverAction = HoverActionFactory(0.5,0.0001,1)

And after ImGui::Begin

ig.PushStyleVarFloat(imgui.ImGuiStyleVar_Alpha, HoverAction())
@ocornut ocornut changed the title Window Hovering animation Window Hovering fading animation Jul 5, 2018
@AlessioR
Copy link

AlessioR commented Jul 5, 2018

Hi,

I'm not a Lua expert but should

ig.PushStyleVarFloat(imgui.ImGuiStyleVar_Alpha, HoverAction())

be

ig.PushStyleVarFloat(imgui.ImGuiStyleVar_Alpha, HoverAction)

without brackets ?

@sonoro1234
Copy link
Author

sonoro1234 commented Jul 5, 2018

HoverAction is the function but we want the return value HoverAction()

@AlessioR
Copy link

AlessioR commented Jul 5, 2018

ok,

so in Lua you can call a local function declared inside a local function!

@sonoro1234
Copy link
Author

local just means not global scope
https://www.lua.org/manual/5.1/manual.html#2.4.7

@ebachard
Copy link

ebachard commented Apr 1, 2020

@sonoro1234

FYI, I implemented something like you described. Just in case someone is interested.

https://framagit.org/ericb/miniDart/-/blob/master/Sources/src/3rdparty/imgui_custom/imgui_fade_in_out.cpp

https://framagit.org/ericb/miniDart/-/blob/master/Sources/src/3rdparty/imgui_custom/imgui_fade_in_out.hpp

@ebachard
Copy link

ebachard commented Apr 2, 2020

I forgot : I have added "heartbeat effect" too (e.g.for buttons). It was a must in Mac OS X at the beginning :-)

@ocornut
Copy link
Owner

ocornut commented Apr 2, 2020

Animated GIF would be nice to see what you've done.

@ebachard
Copy link

ebachard commented Apr 7, 2020

Ok, this gif is far better than the previous one.

Most of the issues are imho fixed, and it works very well.

fade_in_out_2020_04_07

I did all the tests in the SDL2 OpenGL3 example (Linux x86_64 / gcc g++)

include "imgui_fade_in_out.hpp"

in main : init

    // fade in-out effect with windows transparency
    md::FadeInOut fade_in_out;
    fade_in_out.init();

    md::FadeInOut heartbeat;
    heartbeat.init();


In the main loop:

        static bool b_child_window_visible = false;

        // 1. Show the big demo window (Most of the sample code is in ImGui::ShowDemoWindow()! You can browse its code to learn more about Dear ImGui!).
        if (show_demo_window)
            ImGui::ShowDemoWindow(&show_demo_window);

        // 2. Show a simple window that we create ourselves. We use a Begin/End pair to created a named window.
        {
            static float f = 0.0f;
            static int counter = 0;
            static bool b_inside_window = false;

            static float opacity = 1.0f;
            bool open = true;

           // little hack, found no other way to suppress the border. 
           style.WindowBorderSize = 0.0f;

            ImGuiWindowFlags flags = ImGuiWindowFlags_NoDecoration;
            ImGui::SetNextWindowBgAlpha(opacity);

            ImGui::Begin("Hello, world!", &open, flags);                          // Create a window called "Hello, world!" and append into it.


//  FADE IN / OUT
            // Later use ? (e.g. multi screen ?)
            //ImGuiViewport* viewport = ImGui::GetMainViewport();
            //ImVec2 work_area_pos = viewport->Pos;//GetWorkPos();   // Instead of using viewport->Pos we use GetWorkPos() to avoid menu bars, if any!
            //ImVec2 work_area_size = viewport->GetWorkSize();

            static bool b_inside_window = false;

            ImVec2 window_pos = ImGui::GetWindowPos();
            ImVec2 window_size = ImGui::GetContentRegionMax();  // Other possible use : ImGui::GetContentRegionAvail();
            ImVec2 mouse_pos = ImVec2(ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y);

            if (((mouse_pos.x < window_pos.x)||(mouse_pos.x > (window_pos.x + window_size.x))||
            (mouse_pos.y < window_pos.y)||(mouse_pos.y > (window_pos.y + window_size.y))) && (b_child_window_visible == false))
            {
                b_inside_window = false;
            }
            else
                b_inside_window = true;

            opacity = fade_in_out.fadeInOut(up_duration, down_duration, min, max, b_inside_window);
            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, opacity);

// END FADE IN / OUT

            ImGui::Text("This is some useful text.");               // Display some text (you can use a format strings too)
            ImGui::Checkbox("Demo Window", &show_demo_window);      // Edit bools storing our window open/close state
            ImGui::Checkbox("Another Window", &show_another_window);

            ImGui::SliderFloat("float", &f, 0.0f, 1.0f);            // Edit 1 float using a slider from 0.0f to 1.0f
            ImGui::ColorEdit3("clear color", (float*)&clear_color); // Edit 3 floats representing a color

            if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows|ImGuiHoveredFlags_AllowWhenBlockedByPopup|ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
                b_child_window_visible = true;
            else
                b_child_window_visible = false;


            if (ImGui::Button("Button"))                            // Buttons return true when clicked (most widgets return true when edited/activated)
                counter++;
            ImGui::SameLine();
            ImGui::Text("counter = %d", counter);

            ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate, ImGui::GetIO().Framerate);

            ImGui::Text("heartbeat effect parameters");
            ImGui::SliderFloat("Mini hb opacity ", &min_hb, 0.0f , 1.0f, "%.1f"  );
            ImGui::SliderFloat("Maxi hb opacity", &max_hb, 0.0f , 1.0f, "%.1f"  );
            ImGui::SliderFloat("Fade in heartbeat time", &up_duration_hb, 0.1f , 2.0f, "%.1f"  );
            ImGui::SliderFloat("Fade out heartbeat time", &down_duration_hb, 0.1f , 2.5f, "%.1f" );

            ImGui::Text("Fade in/out effect parameters");
            ImGui::SliderFloat("Min fade out", &min, 0.0f , 1.0f, "%.1f"  );
            ImGui::SliderFloat("Maxi fade in", &max, 0.0f , 1.0f, "%.1f"  );
            ImGui::SliderFloat("Fade in time", &up_duration, 0.1f , 2.0f, "%.1f"  );
            ImGui::SliderFloat("Fade out time", &down_duration, 0.1f , 2.5f, "%.1f" );

            //ImGui::Checkbox("");

            ImGui::PopStyleVar();
            ImGui::End();
        }
        // end of hack
        style.WindowBorderSize = 1.0f;



Second window ("Another window, with heartbeat effect):

        if (show_another_window)
        {
            ImGui::Begin("Another Window", &show_another_window);

            bool b_inside_window_hb = false;

            ImVec2 window_pos_hb = ImGui::GetWindowPos();
            ImVec2 window_size_hb = ImGui::GetWindowSize();
            ImVec2 mouse_pos_hb = ImVec2(ImGui::GetIO().MousePos.x, ImGui::GetIO().MousePos.y);

            if ((mouse_pos_hb.x < window_pos_hb.x)||(mouse_pos_hb.x > (window_pos_hb.x + window_size_hb.x))||
            (mouse_pos_hb.y < window_pos_hb.y)||(mouse_pos_hb.y > (window_pos_hb.y + window_size_hb.y)))
            {
                b_inside_window_hb = false;
            }
            else
                b_inside_window_hb = true;

            ImGui::PushStyleVar(ImGuiStyleVar_Alpha, heartbeat.heartBeat(up_duration_hb, down_duration_hb, min, max, b_inside_window_hb));

            ImGui::Text("Hello from another window!");

            if (ImGui::Button("Close Me"))
                show_another_window = false;

            ImGui::PopStyleVar();
            ImGui::End();
        }

One little issue : when both windows are superposed, the cursor is seen as hovering an hidden window. Could probably be solved using the focused window, and so on).

Edit : the child window issus is fixed. Seems to work as expected now.

@ebachard
Copy link

ebachard commented Apr 10, 2020

I forgot : the links for the files (.cpp and .hpp) didn't change, see above.

@colesnicov
Copy link

@ebachard I used your class to create an animation with a window. Just an experiment.

Somewhere in main.cpp file

float min = 0.2f;
float max = 1.0f;
float min_ws_w = 50.f;
float max_ws_w = 300.0f;
float min_ws_h = 50.f;
float max_ws_h = 600.0f;
float up_duration = 0.6f;
float down_duration = 1.6f;

md::FadeInOut size_in_out_w;
md::FadeInOut size_in_out_h;

size_in_out_w.init();
size_in_out_h.init();

in the loop

{
    ImGuiStyle &style = ImGui::GetStyle();

    // little hack, found no other way to suppress the border.
    style.WindowBorderSize = 0.0f;

    ImGui::Begin("Animated window!", 0, ImGuiWindowFlags_NoDecoration);

//  ANIMATE IN / OUT

    /// will standing opened if is active
    bool is_focused = ImGui::IsWindowFocused();

    if (ImGui::IsWindowHovered(
	    ImGuiHoveredFlags_ChildWindows | ImGuiHoveredFlags_AllowWhenBlockedByPopup
		    | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) || is_focused)
    {
	b_inside_window = true;
    }
    else
    {
	b_inside_window = false;
    }

    /// set alpha
    ImGui::PushStyleVar(ImGuiStyleVar_Alpha,
			fade_in_out.fadeInOut(up_duration, down_duration, min, max, b_inside_window));

    /// set new size
    ImGui::SetWindowSize(
	    ImVec2(size_in_out_w.fadeInOut(up_duration, down_duration, min_ws_w, max_ws_w, b_inside_window),
		   size_in_out_h.fadeInOut(up_duration, down_duration, min_ws_h, max_ws_h, b_inside_window)));
// END ANIMATE IN / OUT

    ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / ImGui::GetIO().Framerate,
		ImGui::GetIO().Framerate);

    ImGui::PopStyleVar();
    ImGui::End();

    style.WindowBorderSize = 1.0f;
}


    ImGui::Begin("Configs");

    ImGui::Text("Fade in/out effect parameters");
    ImGui::SliderFloat("Min fade out", &min, 0.0f, 1.0f, "%.1f");
    ImGui::SliderFloat("Maxi fade in", &max, 0.0f, 1.0f, "%.1f");
    ImGui::SliderFloat("Fade in time", &up_duration, 0.1f, 2.0f, "%.1f");
    ImGui::SliderFloat("Fade out time", &down_duration, 0.1f, 2.5f, "%.1f");

    ImGui::Text("Size in/out effect parameters");
    ImGui::SliderFloat("Min size w out", &min_ws_w, 0.0f, 1000.0f, "%.1f");
    ImGui::SliderFloat("Maxi size w in", &max_ws_w, 0.0f, 1000.0f, "%.1f");
    ImGui::SliderFloat("Min size h out", &min_ws_h, 0.0f, 1000.0f, "%.1f");
    ImGui::SliderFloat("Maxi size h in", &max_ws_h, 0.0f, 1000.0f, "%.1f");

    ImGui::End();

Screencast_20241230_204446.mp4

@colesnicov
Copy link

I forgot : the links for the files (.cpp and .hpp) didn't change, see above.

But before I found your implementation, I played with my own (about 10 minutes and then I went searching the internet). Just a 'drawing', maybe it will be useful to someone..

#include <imgui.h>

/**
 * @class AnimatedWindow
 * @brief Class to create windows what will closed with animation.
 *
 */
class AnimatedWindow
{

public:

    AnimatedWindow() :
		    m_is_open(false),
		    m_want_close(false),
		    m_size { 0, 0 },
		    m_size_cond(0),
		    m_pos { 0, 0 },
		    m_pos_cond(0),
		    m_scale(1.0f)
    {

    }

    /**
     * @fn void SetPosition(const ImVec2&, ImGuiCond=0)
     * @brief Set window original position.
     *
     * @param _pos Position.
     * @param _cond Conditions.
     */
    void SetPosition(const ImVec2& _pos, ImGuiCond _cond = 0)
    {
	m_pos = _pos;
	m_pos_cond = _cond;
    }

    /**
     * @fn void SetSize(const ImVec2&, ImGuiCond=0)
     * @brief Set window original size.
     *
     * @param _siz Size.
     * @param _cond Conditions.
     */
    void SetSize(const ImVec2& _siz, ImGuiCond _cond = 0)
    {
	m_size = _siz;
	m_size_cond = _cond;
    }

    /**
     * @fn bool Begin(const char*)
     * @brief Start draw window.
     *
     * @param _title Tile.
     *
     * @return true if open, overwise false.
     */
    bool Begin(const char* _title)
    {

	if (false == m_is_open)
	{
	    return false;
	}

	if (m_want_close)
	{
	    DoClose();
	}
	else
	{
	    ImGui::SetNextWindowSize(m_size, m_size_cond);
	}

	ImGui::SetNextWindowPos(m_pos, m_pos_cond);

	if (false == ImGui::Begin(_title))
	{
	    return false;
	}

	if (m_want_close)
	{
	    ImGui::SetWindowFontScale(m_scale);
	}

	ImGui::Text("Scale: %f", m_scale);

	return true;
    }

    /**
     * @fn void End()
     * @brief End draw window.
     *
     */
    void End()
    {
	ImGui::End();
    }

    /**
     * @fn void Close()
     * @brief Set flags to close window.
     *
     */
    void Close()
    {
	m_want_close = true;
    }

    /**
     * @fn void Open()
     * @brief Set flags to open window.
     *
     */
    void Open()
    {
	m_want_close = false;
	m_is_open = true;
	m_scale = 1.0f;
    }

private:

    /**
     * @var bool m_is_open
     * @brief Flag, is window open?
     */
    bool m_is_open;

    /**
     * @var bool m_want_close
     * @brief Flag, is window want to close?
     */
    bool m_want_close;

    /**
     * @var ImVec2 m_size
     * @brief Original size of window.
     */
    ImVec2 m_size;

    /**
     * @var ImGuiCond m_size_cond
     * @brief Flag, condition for window size.
     */
    ImGuiCond m_size_cond;

    /**
     * @var ImVec2 m_pos
     * @brief Original window position.
     */
    ImVec2 m_pos;

    /**
     * @var ImGuiCond m_pos_cond
     * @brief Flag, condition for window position.
     */
    ImGuiCond m_pos_cond;

    /**
     * @var float m_scale
     * @brief Scale factor for whole (window size, font size ...).
     */
    float m_scale;

    /**
     * @fn void DoClose()
     * @brief Calculate new sizes.
     *
     */
    void DoClose()
    {
	m_scale -= 0.002f;
	if (0 >= m_scale)
	{
	    /// NOTE: needs restore scale factor for next open..
	    m_scale = 1.0f;
	    m_is_open = false;
	}

	ImGui::SetNextWindowSize(m_size * m_scale, ImGuiCond_Always);

    }

};


Usage:

Somewhere in main.cpp

AnimatedWindow wd;

wd.Open();
wd.SetPosition(ImVec2(20, 20));
wd.SetSize(ImVec2(200, 200));

In main loop:


    if (wd.Begin("Animated"))
    {
	if (ImGui::Button("Close"))
	{
	    wd.Close();
	}

	wd.End();
    }

    if (ImGui::Begin("TOTO"))
    {
	if (ImGui::Button("Open"))
	{
	    wd.Open();
	}

	ImGui::End();
    }
Screencast_20241230_205516-1.mp4

@colesnicov
Copy link

@sonoro1234

FYI, I implemented something like you described. Just in case someone is interested.

https://framagit.org/ericb/miniDart/-/blob/master/Sources/src/3rdparty/imgui_custom/imgui_fade_in_out.cpp

https://framagit.org/ericb/miniDart/-/blob/master/Sources/src/3rdparty/imgui_custom/imgui_fade_in_out.hpp

You have a few errors there.

1)
On line 53 at yout header file you are asking about the property of the ImGuiIO structure io.DeltaTime but on line 46 at source file you are not assigning the structure:

void md::FadeInOut::init()
{
    ImGuiIO& io = ImGui::GetIO();
    (void)io; // makes the compiler happy
}

It has to be like this:

void md::FadeInOut::init()
{
    io = ImGui::GetIO();
}

This prevents unexpected behavior.

2)
The second problem is that on line 54 in source file you define the variable alpha as static:

static float opacity_hb = 1.0f;

But you need to define it in the class definition like this:

namespace md
{
class FadeInOut
{
 ...
private:
    float range;
    float opacity = 1.0f; // placed it here
};
}

This allows you to have multiple instances of the animator at the same time.

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

No branches or pull requests

5 participants