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

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())
Hi,
I'm not a Lua expert but should
ig.PushStyleVarFloat(imgui.ImGuiStyleVar_Alpha, HoverAction())
be
ig.PushStyleVarFloat(imgui.ImGuiStyleVar_Alpha, HoverAction)
without brackets ?
HoverAction is the function but we want the return value HoverAction()
ok,
so in Lua you can call a local function declared inside a local function!
local just means not global scope https://www.lua.org/manual/5.1/manual.html#2.4.7
@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
I forgot : I have added "heartbeat effect" too (e.g.for buttons). It was a must in Mac OS X at the beginning :-)
Animated GIF would be nice to see what you've done.
Ok, this gif is far better than the previous one.
Most of the issues are imho fixed, and it works very well.

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.
I forgot : the links for the files (.cpp and .hpp) didn't change, see above.
@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();
https://github.com/user-attachments/assets/f18e51da-8276-4629-9b95-c893f36c9898
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();
}
https://github.com/user-attachments/assets/fcc5b3e6-acc2-4eb4-b200-414e68058662
@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.
EDIT - https://github.com/colesnicov/imgui_anim_fade/