This repository is a fork of the original aiekick/ImCoolBar. It keeps the original API spirit while fixing hover glitches and enabling smoothing and antialiasing by default (configurable).
Bug fixes
-
Removed the initial Y‑axis “jump” on first hover/unhover.
- Correct cross‑axis thickness:
normal + (hovered - normal) * anim_scale. anim_scaleis updated before positioning the window.- Predicted thickness used for positioning each frame.
- First item size is initialized from
normal_size(not 0). anchoris clamped to[0..1].
- Correct cross‑axis thickness:
Smoothing (time‑based EMA)
- Enabled by default with a 50 ms half‑life; set to
0to disable. - Mouse coordinate filtering with half‑life in milliseconds; frame‑rate invariant.
anim_scalesmoothing to targets 0/1 with its own half‑life; fallback to the old step‑basedanim_stepwhen disabled.
Antialiasing (on by default)
- Local AA for this bar’s draw list (
AntiAliasedFill|Lines) is enabled by default but can be disabled via config. - Optional local
FrameRoundingoverride for smoother visuals. - Draw‑list flags and style are restored in
EndCoolBar().
Pixel snapping (optional)
- Separate snapping controls for window position and inner item offsets to avoid visible “stepping” (both enabled by default).
Metrics
- Extra debug outputs:
MouseSmoothingMs,MouseSmoothingAlpha,AnimSmoothingMs,AnimSmoothingAlpha, currentAnimScale, per‑item sizes.
(If applicable) Minor API refactor
ImCoolBarConfigand flags may live in the global namespace to mirror Dear ImGui style (functions remain inImGui::). See Migration below.
Result:
- Stable branch:
stable— recommended for users. - Development:
main(ordev) — may contain work‑in‑progress changes. - Releases: tagged as
vX.Y.Z.
Works with Dear ImGui 1.92 on both docking and non‑docking branches.
Docking window flags are enabled automatically when IMGUI_HAS_DOCK is defined, or by defining IMCOOLBAR_HAS_DOCKING before including ImCoolBar.h.
// Define before including the header if you want to force docking host flags
#define IMCOOLBAR_HAS_DOCKING
#include "ImCoolBar.h"// Helper button that sizes itself to the current item width/scale
auto coolbar_button = [](const char* label) -> bool {
float w = ImGui::GetCoolBarItemWidth();
return ImGui::Button(label, ImVec2(w, w));
};
ImCoolBarConfig cfg; // defaults (50 ms smoothing, AA & pixel snapping on)
cfg.anchor = ImVec2(0.5f, 1.0f); // bottom-center of the viewport
cfg.mouse_smoothing_ms = 120.0f; // time-based mouse smoothing (default 50, 0 = off)
cfg.anim_smoothing_ms = 120.0f; // time-based anim smoothing (default 50, 0 = step mode)
cfg.local_antialiasing = true; // local AA just for this bar (default true)
cfg.frame_rounding_override = 6.0f; // optional per-bar rounding
cfg.snap_window_to_pixels = true; // snap window to whole pixels (default true)
cfg.snap_items_to_pixels = true; // snap inner item offsets to whole pixels (default true)
if (ImGui::BeginCoolBar("##CoolBarMain", ImCoolBarFlags_Horizontal, cfg)) {
const char* labels = "ABCDEFGHIJKL";
for (const char* p = labels; *p; ++p)
if (ImGui::CoolBarItem())
(void)coolbar_button(std::string(1, *p).c_str());
ImGui::EndCoolBar();
}Result:
// Shared smoothing/visuals
ImCoolBarConfig common; // defaults (50 ms smoothing, AA & pixel snapping on)
common.mouse_smoothing_ms = 100.0f;
common.anim_smoothing_ms = 120.0f;
common.local_antialiasing = true; // default true
common.frame_rounding_override = 6.0f;
common.snap_window_to_pixels = true; // default true
common.snap_items_to_pixels = true; // default true
// Bottom horizontal bar
{
auto cfg = common; cfg.anchor = ImVec2(0.5f, 1.0f);
if (ImGui::BeginCoolBar("##CoolBarBottom", ImCoolBarFlags_Horizontal, cfg)) {
for (char c = 'A'; c <= 'H'; ++c)
if (ImGui::CoolBarItem()) ImGui::Button(std::string(1, c).c_str(), ImVec2(ImGui::GetCoolBarItemWidth(), ImGui::GetCoolBarItemWidth()));
ImGui::EndCoolBar();
}
}
// Left vertical bar
{
auto cfg = common; cfg.anchor = ImVec2(0.0f, 0.5f);
if (ImGui::BeginCoolBar("##CoolBarLeft", ImCoolBarFlags_Vertical, cfg)) {
for (char c = '1'; c <= '6'; ++c)
if (ImGui::CoolBarItem()) ImGui::Button(std::string(1, c).c_str(), ImVec2(ImGui::GetCoolBarItemWidth(), ImGui::GetCoolBarItemWidth()));
ImGui::EndCoolBar();
}
}// Begin a coolbar window. Returns true while building items.
IMGUI_API bool BeginCoolBar(const char* label,
ImCoolBarFlags flags = ImCoolBarFlags_Vertical,
const ImCoolBarConfig& cfg = {},
ImGuiWindowFlags wflags = ImGuiWindowFlags_None);
IMGUI_API void EndCoolBar();
// Per-item call. Place your widget when this returns true.
IMGUI_API bool CoolBarItem();
// Helpers for sizing; valid only inside an active coolbar item.
IMGUI_API float GetCoolBarItemWidth();
IMGUI_API float GetCoolBarItemScale();
// Debug/metrics window
IMGUI_API void ShowCoolBarMetrics(bool* opened);| Field | Type | Default | Description |
|---|---|---|---|
anchor |
ImVec2 |
{-1,-1} |
Normalized anchor in the viewport; e.g. {0.5,1.0} = bottom center. |
normal_size |
float |
40.0 |
Base size for items. |
hovered_size |
float |
60.0 |
Max size when fully hovered. |
anim_step |
float |
0.15 |
Legacy step per frame for anim_scale (used when EMA disabled). |
effect_strength |
float |
0.5 |
Strength parameter for hover influence curve. |
mouse_smoothing_ms |
float |
50.0 |
EMA half‑life for mouse filtering; <=0 disables. |
anim_smoothing_ms |
float |
50.0 |
EMA half‑life for anim_scale; <=0 uses anim_step. |
local_antialiasing |
bool |
true |
Enable AA on this bar’s draw list only (default on). |
frame_rounding_override |
float |
-1.0 |
<0 keep global; >=0 push per‑bar FrameRounding. |
snap_window_to_pixels |
bool |
true |
Snap window position to whole pixels (crisp text). |
snap_items_to_pixels |
bool |
true |
Snap inner item offsets; turn off for subpixel smoothness. |
Notes
- Mouse/anim smoothing (50 ms half‑life) and local antialiasing are enabled by default; set smoothing to
0or antialiasing tofalseto disable. - EMA alpha per frame:
α = 1 - exp(-ln(2) * dt_ms / half_life_ms). - Subpixel movement is visually smoother with AA and non‑zero rounding.
Depending on your fork state:
-
If
ImCoolBarConfigmoved to the global namespace, update usages:ImGui::ImCoolBarConfig{...}→ImCoolBarConfig{...}- Flags remain
ImCoolBarFlags_*.
-
If you added an overload taking
ImVec2 anchor, you may call:ImGui::BeginCoolBar("##CoolBarMain", ImCoolBarFlags_Horizontal, ImVec2(0.5f, 1.0f));
Otherwise, construct
ImCoolBarConfigexplicitly.
-
This widget is a tiny pair of
.h/.cppfiles; just add them to your build with Dear ImGui. -
For docking:
- Use Dear ImGui’s docking branch or define
IMCOOLBAR_HAS_DOCKINGyourself.
- Use Dear ImGui’s docking branch or define
-
Backends: any Dear ImGui backend; for best visual smoothness you may enable MSAA on your renderer.
MIT. See the original license header in the source files.
If you distribute this fork, keep the original MIT license text and copyright notice.
You may add your own copyright line for your changes (e.g. © 2025 YourName).
- Original work by Stephane Cuillerdier (Aiekick) — aiekick/ImCoolBar.
- Improvements and maintenance in this fork by the community.


