[Scummvm-git-logs] scummvm master -> cff87d8c2e98b16f2669c54445f65240d23ecc9f
sev-
noreply at scummvm.org
Mon Oct 7 16:40:34 UTC 2024
This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .
Summary:
cff87d8c2e BACKENDS: IMGUI: Bumped to v1.91.3 docking branch
Commit: cff87d8c2e98b16f2669c54445f65240d23ecc9f
https://github.com/scummvm/scummvm/commit/cff87d8c2e98b16f2669c54445f65240d23ecc9f
Author: Eugene Sandulenko (sev at scummvm.org)
Date: 2024-10-07T18:36:00+02:00
Commit Message:
BACKENDS: IMGUI: Bumped to v1.91.3 docking branch
Commit b4c96355c9b51b54c4deb52e7d7cdfc7bf79bc2f from
https://github.com/ocornut/imgui/tree/docking
This adds global shortcuts and better table handling.
Update process:
1. In ScummVM backends/imgui directory:
for i in `find .`;do cp -v ../../../../imgui/$i $i;done
patch <scummvm.patch
2. Compile, test with launching engines using ImGui
3. Regenerate patch, in imgui directory:
diff -rbu . ../scummvm/scummvm/backends/imgui/|grep -v ^Only >../scummvm/scummvm/backends/imgui/scummvm.patch
4. Commit
Changed paths:
backends/imgui/backends/imgui_impl_opengl3.cpp
backends/imgui/backends/imgui_impl_opengl3.h
backends/imgui/backends/imgui_impl_opengl3_loader.h
backends/imgui/backends/imgui_impl_sdl2.cpp
backends/imgui/backends/imgui_impl_sdl2.h
backends/imgui/backends/imgui_impl_sdlrenderer2.h
backends/imgui/imconfig.h
backends/imgui/imgui.cpp
backends/imgui/imgui.h
backends/imgui/imgui_demo.cpp
backends/imgui/imgui_draw.cpp
backends/imgui/imgui_internal.h
backends/imgui/imgui_tables.cpp
backends/imgui/imgui_widgets.cpp
backends/imgui/imstb_textedit.h
backends/imgui/misc/freetype/imgui_freetype.cpp
backends/imgui/scummvm.patch
diff --git a/backends/imgui/backends/imgui_impl_opengl3.cpp b/backends/imgui/backends/imgui_impl_opengl3.cpp
index c288b577e2e..b363ba075c0 100644
--- a/backends/imgui/backends/imgui_impl_opengl3.cpp
+++ b/backends/imgui/backends/imgui_impl_opengl3.cpp
@@ -24,6 +24,7 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
+// 2024-06-28: OpenGL: ImGui_ImplOpenGL3_NewFrame() recreates font texture if it has been destroyed by ImGui_ImplOpenGL3_DestroyFontsTexture(). (#7748)
// 2024-05-07: OpenGL: Update loader for Linux to support EGL/GLVND. (#7562)
// 2024-04-16: OpenGL: Detect ES3 contexts on desktop based on version string, to e.g. avoid calling glPolygonMode() on them. (#7447)
// 2024-01-09: OpenGL: Update GL3W based imgui_impl_opengl3_loader.h to load "libGL.so" and variants, fixing regression on distros missing a symlink.
@@ -125,6 +126,7 @@
// Clang/GCC warnings with -Weverything
#if defined(__clang__)
#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunknown-warning-option" // warning: ignore unknown flags
#pragma clang diagnostic ignored "-Wold-style-cast" // warning: use of old-style cast
#pragma clang diagnostic ignored "-Wsign-conversion" // warning: implicit conversion changes signedness
#pragma clang diagnostic ignored "-Wunused-macros" // warning: macro is not used
@@ -414,6 +416,8 @@ void ImGui_ImplOpenGL3_NewFrame()
if (!bd->ShaderHandle)
ImGui_ImplOpenGL3_CreateDeviceObjects();
+ if (!bd->FontTexture)
+ ImGui_ImplOpenGL3_CreateFontsTexture();
}
static void ImGui_ImplOpenGL3_SetupRenderState(ImDrawData* draw_data, int fb_width, int fb_height, GLuint vertex_array_object)
diff --git a/backends/imgui/backends/imgui_impl_opengl3.h b/backends/imgui/backends/imgui_impl_opengl3.h
index bac3225f6a9..ecb865db4b0 100644
--- a/backends/imgui/backends/imgui_impl_opengl3.h
+++ b/backends/imgui/backends/imgui_impl_opengl3.h
@@ -30,7 +30,7 @@
#include "backends/imgui/imgui.h" // IMGUI_IMPL_API
#ifndef IMGUI_DISABLE
-// Backend API
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplOpenGL3_Init(const char* glsl_version = nullptr);
IMGUI_IMPL_API void ImGui_ImplOpenGL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplOpenGL3_NewFrame();
diff --git a/backends/imgui/backends/imgui_impl_opengl3_loader.h b/backends/imgui/backends/imgui_impl_opengl3_loader.h
index e91af76e9eb..2f290421207 100644
--- a/backends/imgui/backends/imgui_impl_opengl3_loader.h
+++ b/backends/imgui/backends/imgui_impl_opengl3_loader.h
@@ -123,7 +123,7 @@ extern "C" {
** included as <GL/glcorearb.h>.
**
** glcorearb.h includes only APIs in the latest OpenGL core profile
-** implementation together with APIs in newer ARB extensions which
+** implementation together with APIs in newer ARB extensions which
** can be supported by the core profile. It does not, and never will
** include functionality removed from the core profile, such as
** fixed-function vertex and fragment processing.
diff --git a/backends/imgui/backends/imgui_impl_sdl2.cpp b/backends/imgui/backends/imgui_impl_sdl2.cpp
index 6670f83143d..e0c56d06c5c 100644
--- a/backends/imgui/backends/imgui_impl_sdl2.cpp
+++ b/backends/imgui/backends/imgui_impl_sdl2.cpp
@@ -26,6 +26,16 @@
// CHANGELOG
// (minor and older changes stripped away, please see git history for details)
// 2024-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
+// 2024-09-09: use SDL_Vulkan_GetDrawableSize() when available. (#7967, #3190)
+// 2024-08-22: moved some OS/backend related function pointers from ImGuiIO to ImGuiPlatformIO:
+// - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn
+// - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn
+// - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn
+// - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
+// 2024-08-19: Storing SDL's Uint32 WindowID inside ImGuiViewport::PlatformHandle instead of SDL_Window*.
+// 2024-08-19: ImGui_ImplSDL2_ProcessEvent() now ignores events intended for other SDL windows. (#7853)
+// 2024-07-02: Emscripten: Added io.PlatformOpenInShellFn() handler for Emscripten versions.
+// 2024-07-02: Update for io.SetPlatformImeDataFn() -> io.PlatformSetImeDataFn() renaming in main library.
// 2024-02-14: Inputs: Handle gamepad disconnection. Added ImGui_ImplSDL2_SetGamepadMode().
// 2023-10-05: Inputs: Added support for extra ImGuiKey values: F13 to F24 function keys, app back/forward keys.
// 2023-04-06: Inputs: Avoid calling SDL_StartTextInput()/SDL_StopTextInput() as they don't only pertain to IME. It's unclear exactly what their relation is to IME. (#6306)
@@ -98,9 +108,12 @@
// (the multi-viewports feature requires SDL features supported from SDL 2.0.4+. SDL 2.0.5+ is highly recommended)
#include <SDL.h>
#include <SDL_syswm.h>
-#if defined(__APPLE__)
+#ifdef __APPLE__
#include <TargetConditionals.h>
#endif
+#ifdef __EMSCRIPTEN__
+#include <emscripten/em_js.h>
+#endif
#if SDL_VERSION_ATLEAST(2,0,4) && !defined(__EMSCRIPTEN__) && !defined(__ANDROID__) && !(defined(__APPLE__) && TARGET_OS_IOS) && !defined(__amigaos4__)
#define SDL_HAS_CAPTURE_AND_GLOBAL_MOUSE 1
@@ -113,7 +126,10 @@
#define SDL_HAS_PER_MONITOR_DPI SDL_VERSION_ATLEAST(2,0,4)
#define SDL_HAS_VULKAN SDL_VERSION_ATLEAST(2,0,6)
#define SDL_HAS_DISPLAY_EVENT SDL_VERSION_ATLEAST(2,0,9)
-#if !SDL_HAS_VULKAN
+#define SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT SDL_VERSION_ATLEAST(2,0,18)
+#if SDL_HAS_VULKAN
+extern "C" { extern DECLSPEC void SDLCALL SDL_Vulkan_GetDrawableSize(SDL_Window* window, int* w, int* h); }
+#elif
static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
#endif
@@ -121,6 +137,7 @@ static const Uint32 SDL_WINDOW_VULKAN = 0x10000000;
struct ImGui_ImplSDL2_Data
{
SDL_Window* Window;
+ Uint32 WindowID;
SDL_Renderer* Renderer;
Uint64 Time;
char* ClipboardTextData;
@@ -159,7 +176,7 @@ static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_g
static void ImGui_ImplSDL2_ShutdownPlatformInterface();
// Functions
-static const char* ImGui_ImplSDL2_GetClipboardText(void*)
+static const char* ImGui_ImplSDL2_GetClipboardText(ImGuiContext*)
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
if (bd->ClipboardTextData)
@@ -168,13 +185,13 @@ static const char* ImGui_ImplSDL2_GetClipboardText(void*)
return bd->ClipboardTextData;
}
-static void ImGui_ImplSDL2_SetClipboardText(void*, const char* text)
+static void ImGui_ImplSDL2_SetClipboardText(ImGuiContext*, const char* text)
{
SDL_SetClipboardText(text);
}
// Note: native IME will only display if user calls SDL_SetHint(SDL_HINT_IME_SHOW_UI, "1") _before_ SDL_CreateWindow().
-static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
+static void ImGui_ImplSDL2_PlatformSetImeData(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
if (data->WantVisible)
{
@@ -187,8 +204,10 @@ static void ImGui_ImplSDL2_SetPlatformImeData(ImGuiViewport* viewport, ImGuiPlat
}
}
-static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
+// Not static to allow third-party code to use that if they want to (but undocumented)
+ImGuiKey ImGui_ImplSDL2_KeyEventToImGuiKey(SDL_Keycode keycode, SDL_Scancode scancode)
{
+ IM_UNUSED(scancode);
switch (keycode)
{
case SDLK_TAB: return ImGuiKey_Tab;
@@ -310,6 +329,7 @@ static ImGuiKey ImGui_ImplSDL2_KeycodeToImGuiKey(int keycode)
case SDLK_F24: return ImGuiKey_F24;
case SDLK_AC_BACK: return ImGuiKey_AppBack;
case SDLK_AC_FORWARD: return ImGuiKey_AppForward;
+ default: break;
}
return ImGuiKey_None;
}
@@ -323,6 +343,11 @@ static void ImGui_ImplSDL2_UpdateKeyModifiers(SDL_Keymod sdl_key_mods)
io.AddKeyEvent(ImGuiMod_Super, (sdl_key_mods & KMOD_GUI) != 0);
}
+static ImGuiViewport* ImGui_ImplSDL2_GetViewportForWindowID(Uint32 window_id)
+{
+ return ImGui::FindViewportByPlatformHandle((void*)(intptr_t)window_id);
+}
+
bool ImGui_ImplSDL2_Ready()
{
return ImGui_ImplSDL2_GetBackendData() != nullptr;
@@ -332,7 +357,6 @@ bool ImGui_ImplSDL2_Ready()
// - When io.WantCaptureMouse is true, do not dispatch mouse input data to your main application, or clear/overwrite your copy of the mouse data.
// - When io.WantCaptureKeyboard is true, do not dispatch keyboard input data to your main application, or clear/overwrite your copy of the keyboard data.
// Generally you may always pass all inputs to dear imgui, and hide them from your application based on those two flags.
-// If you have multiple SDL events and some of them are not meant to be used by dear imgui, you may need to filter events based on their windowID field.
bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();
@@ -343,6 +367,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
{
case SDL_MOUSEMOTION:
{
+ if (ImGui_ImplSDL2_GetViewportForWindowID(event->motion.windowID) == NULL)
+ return false;
ImVec2 mouse_pos((float)event->motion.x, (float)event->motion.y);
if (io.ConfigFlags & ImGuiConfigFlags_ViewportsEnable)
{
@@ -357,6 +383,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
}
case SDL_MOUSEWHEEL:
{
+ if (ImGui_ImplSDL2_GetViewportForWindowID(event->wheel.windowID) == NULL)
+ return false;
//IMGUI_DEBUG_LOG("wheel %.2f %.2f, precise %.2f %.2f\n", (float)event->wheel.x, (float)event->wheel.y, event->wheel.preciseX, event->wheel.preciseY);
#if SDL_VERSION_ATLEAST(2,0,18) // If this fails to compile on Emscripten: update to latest Emscripten!
float wheel_x = -event->wheel.preciseX;
@@ -375,6 +403,8 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
case SDL_MOUSEBUTTONDOWN:
case SDL_MOUSEBUTTONUP:
{
+ if (ImGui_ImplSDL2_GetViewportForWindowID(event->button.windowID) == NULL)
+ return false;
int mouse_button = -1;
if (event->button.button == SDL_BUTTON_LEFT) { mouse_button = 0; }
if (event->button.button == SDL_BUTTON_RIGHT) { mouse_button = 1; }
@@ -390,14 +420,18 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
}
case SDL_TEXTINPUT:
{
+ if (ImGui_ImplSDL2_GetViewportForWindowID(event->text.windowID) == NULL)
+ return false;
io.AddInputCharactersUTF8(event->text.text);
return true;
}
case SDL_KEYDOWN:
case SDL_KEYUP:
{
+ if (ImGui_ImplSDL2_GetViewportForWindowID(event->key.windowID) == NULL)
+ return false;
ImGui_ImplSDL2_UpdateKeyModifiers((SDL_Keymod)event->key.keysym.mod);
- ImGuiKey key = ImGui_ImplSDL2_KeycodeToImGuiKey(event->key.keysym.sym);
+ ImGuiKey key = ImGui_ImplSDL2_KeyEventToImGuiKey(event->key.keysym.sym, event->key.keysym.scancode);
io.AddKeyEvent(key, (event->type == SDL_KEYDOWN));
io.SetKeyEventNativeData(key, event->key.keysym.sym, event->key.keysym.scancode, event->key.keysym.scancode); // To support legacy indexing (<1.87 user code). Legacy backend uses SDLK_*** as indices to IsKeyXXX() functions.
return true;
@@ -413,6 +447,10 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
#endif
case SDL_WINDOWEVENT:
{
+ ImGuiViewport* viewport = ImGui_ImplSDL2_GetViewportForWindowID(event->window.windowID);
+ if (viewport == NULL)
+ return false;
+
// - When capturing mouse, SDL will send a bunch of conflicting LEAVE/ENTER event on every mouse move, but the final ENTER tends to be right.
// - However we won't get a correct LEAVE event for a captured window.
// - In some cases, when detaching a window from main viewport SDL may send SDL_WINDOWEVENT_ENTER one frame too late,
@@ -430,17 +468,12 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
io.AddFocusEvent(true);
else if (window_event == SDL_WINDOWEVENT_FOCUS_LOST)
io.AddFocusEvent(false);
- if (window_event == SDL_WINDOWEVENT_CLOSE || window_event == SDL_WINDOWEVENT_MOVED || window_event == SDL_WINDOWEVENT_RESIZED)
- if (ImGuiViewport* viewport = ImGui::FindViewportByPlatformHandle((void*)SDL_GetWindowFromID(event->window.windowID)))
- {
- if (window_event == SDL_WINDOWEVENT_CLOSE)
- viewport->PlatformRequestClose = true;
- if (window_event == SDL_WINDOWEVENT_MOVED)
- viewport->PlatformRequestMove = true;
- if (window_event == SDL_WINDOWEVENT_RESIZED)
- viewport->PlatformRequestResize = true;
- return true;
- }
+ else if (window_event == SDL_WINDOWEVENT_CLOSE)
+ viewport->PlatformRequestClose = true;
+ else if (window_event == SDL_WINDOWEVENT_MOVED)
+ viewport->PlatformRequestMove = true;
+ else if (window_event == SDL_WINDOWEVENT_RESIZED)
+ viewport->PlatformRequestResize = true;
return true;
}
case SDL_CONTROLLERDEVICEADDED:
@@ -453,6 +486,10 @@ bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event)
return false;
}
+#ifdef __EMSCRIPTEN__
+EM_JS(void, ImGui_ImplSDL2_EmscriptenOpenURL, (char const* url), { url = url ? UTF8ToString(url) : null; if (url) window.open(url, '_blank'); });
+#endif
+
static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void* sdl_gl_context)
{
ImGuiIO& io = ImGui::GetIO();
@@ -480,6 +517,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
io.BackendFlags |= ImGuiBackendFlags_PlatformHasViewports; // We can create multi-viewports on the Platform side (optional)
bd->Window = window;
+ bd->WindowID = SDL_GetWindowID(window);
bd->Renderer = renderer;
// SDL on Linux/OSX doesn't report events for unfocused windows (see https://github.com/ocornut/imgui/issues/4960)
@@ -490,12 +528,18 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
#else
bd->MouseCanReportHoveredViewport = false;
#endif
- bd->WantUpdateMonitors = true;
- io.SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
- io.GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
- io.ClipboardUserData = nullptr;
- io.SetPlatformImeDataFn = ImGui_ImplSDL2_SetPlatformImeData;
+ ImGuiPlatformIO& platform_io = ImGui::GetPlatformIO();
+ platform_io.Platform_SetClipboardTextFn = ImGui_ImplSDL2_SetClipboardText;
+ platform_io.Platform_GetClipboardTextFn = ImGui_ImplSDL2_GetClipboardText;
+ platform_io.Platform_ClipboardUserData = nullptr;
+ platform_io.Platform_SetImeDataFn = ImGui_ImplSDL2_PlatformSetImeData;
+#ifdef __EMSCRIPTEN__
+ platform_io.Platform_OpenInShellFn = [](ImGuiContext*, const char* url) { ImGui_ImplSDL2_EmscriptenOpenURL(url); return true; };
+#endif
+
+ // Update monitor a first time during init
+ ImGui_ImplSDL2_UpdateMonitors();
// Gamepad handling
bd->GamepadMode = ImGui_ImplSDL2_GamepadMode_AutoFirst;
@@ -515,7 +559,7 @@ static bool ImGui_ImplSDL2_Init(SDL_Window* window, SDL_Renderer* renderer, void
// Set platform dependent data in viewport
// Our mouse update function expect PlatformHandle to be filled for the main viewport
ImGuiViewport* main_viewport = ImGui::GetMainViewport();
- main_viewport->PlatformHandle = (void*)window;
+ main_viewport->PlatformHandle = (void*)(intptr_t)bd->WindowID;
main_viewport->PlatformHandleRaw = nullptr;
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
@@ -630,7 +674,7 @@ static void ImGui_ImplSDL2_UpdateMouseData()
// SDL_CaptureMouse() let the OS know e.g. that our imgui drag outside the SDL window boundaries shouldn't e.g. trigger other operations outside
SDL_CaptureMouse((bd->MouseButtonsDown != 0) ? SDL_TRUE : SDL_FALSE);
SDL_Window* focused_window = SDL_GetKeyboardFocus();
- const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui::FindViewportByPlatformHandle((void*)focused_window)));
+ const bool is_app_focused = (focused_window && (bd->Window == focused_window || ImGui_ImplSDL2_GetViewportForWindowID(SDL_GetWindowID(focused_window)) != NULL));
#else
SDL_Window* focused_window = bd->Window;
const bool is_app_focused = (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_INPUT_FOCUS) != 0; // SDL 2.0.3 and non-windowed systems: single-viewport only
@@ -676,9 +720,8 @@ static void ImGui_ImplSDL2_UpdateMouseData()
if (io.BackendFlags & ImGuiBackendFlags_HasMouseHoveredViewport)
{
ImGuiID mouse_viewport_id = 0;
- if (SDL_Window* sdl_mouse_window = SDL_GetWindowFromID(bd->MouseWindowID))
- if (ImGuiViewport* mouse_viewport = ImGui::FindViewportByPlatformHandle((void*)sdl_mouse_window))
- mouse_viewport_id = mouse_viewport->ID;
+ if (ImGuiViewport* mouse_viewport = ImGui_ImplSDL2_GetViewportForWindowID(bd->MouseWindowID))
+ mouse_viewport_id = mouse_viewport->ID;
io.AddMouseViewportEvent(mouse_viewport_id);
}
}
@@ -840,7 +883,11 @@ static void ImGui_ImplSDL2_UpdateMonitors()
// DpiScale to cocoa_window.backingScaleFactor here.
float dpi = 0.0f;
if (!SDL_GetDisplayDPI(n, &dpi, nullptr, nullptr))
+ {
+ if (dpi <= 0.0f)
+ continue; // Some accessibility applications are declaring virtual monitors with a DPI of 0, see #7902.
monitor.DpiScale = dpi / 96.0f;
+ }
#endif
monitor.PlatformHandle = (void*)(intptr_t)n;
platform_io.Monitors.push_back(monitor);
@@ -861,6 +908,10 @@ void ImGui_ImplSDL2_NewFrame()
w = h = 0;
if (bd->Renderer != nullptr)
SDL_GetRendererOutputSize(bd->Renderer, &display_w, &display_h);
+#if SDL_HAS_VULKAN
+ else if (SDL_GetWindowFlags(bd->Window) & SDL_WINDOW_VULKAN)
+ SDL_Vulkan_GetDrawableSize(bd->Window, &display_w, &display_h);
+#endif
else
SDL_GL_GetDrawableSize(bd->Window, &display_w, &display_h);
io.DisplaySize = ImVec2((float)w, (float)h);
@@ -888,7 +939,7 @@ void ImGui_ImplSDL2_NewFrame()
}
// Our io.AddMouseViewportEvent() calls will only be valid when not capturing.
- // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rygorous, but testing for payload reduces noise and potential side-effects.
+ // Technically speaking testing for 'bd->MouseButtonsDown == 0' would be more rigorous, but testing for payload reduces noise and potential side-effects.
if (bd->MouseCanReportHoveredViewport && ImGui::GetDragDropPayload() == nullptr)
io.BackendFlags |= ImGuiBackendFlags_HasMouseHoveredViewport;
else
@@ -961,7 +1012,7 @@ static void ImGui_ImplSDL2_CreateWindow(ImGuiViewport* viewport)
if (use_opengl && backup_context)
SDL_GL_MakeCurrent(vd->Window, backup_context);
- viewport->PlatformHandle = (void*)vd->Window;
+ viewport->PlatformHandle = (void*)(intptr_t)SDL_GetWindowID(vd->Window);
viewport->PlatformHandleRaw = nullptr;
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
@@ -993,7 +1044,7 @@ static void ImGui_ImplSDL2_DestroyWindow(ImGuiViewport* viewport)
static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
{
ImGui_ImplSDL2_ViewportData* vd = (ImGui_ImplSDL2_ViewportData*)viewport->PlatformUserData;
-#if defined(_WIN32)
+#if defined(_WIN32) && !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP || WINAPI_FAMILY == WINAPI_FAMILY_GAMES))
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
// SDL hack: Hide icon from task bar
@@ -1005,7 +1056,11 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
ex_style |= WS_EX_TOOLWINDOW;
::SetWindowLong(hwnd, GWL_EXSTYLE, ex_style);
}
+#endif
+#if SDL_HAS_SHOW_WINDOW_ACTIVATION_HINT
+ SDL_SetHint(SDL_HINT_WINDOW_NO_ACTIVATION_WHEN_SHOWN, (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing) ? "1" : "0");
+#elif defined(_WIN32)
// SDL hack: SDL always activate/focus windows :/
if (viewport->Flags & ImGuiViewportFlags_NoFocusOnAppearing)
{
@@ -1013,7 +1068,6 @@ static void ImGui_ImplSDL2_ShowWindow(ImGuiViewport* viewport)
return;
}
#endif
-
SDL_ShowWindow(vd->Window);
}
@@ -1140,7 +1194,7 @@ static void ImGui_ImplSDL2_InitPlatformInterface(SDL_Window* window, void* sdl_g
vd->WindowOwned = false;
vd->GLContext = sdl_gl_context;
main_viewport->PlatformUserData = vd;
- main_viewport->PlatformHandle = vd->Window;
+ main_viewport->PlatformHandle = (void*)(intptr_t)vd->WindowID;
}
static void ImGui_ImplSDL2_ShutdownPlatformInterface()
diff --git a/backends/imgui/backends/imgui_impl_sdl2.h b/backends/imgui/backends/imgui_impl_sdl2.h
index 2b6d04393d8..d0313bbe106 100644
--- a/backends/imgui/backends/imgui_impl_sdl2.h
+++ b/backends/imgui/backends/imgui_impl_sdl2.h
@@ -31,6 +31,7 @@ struct SDL_Renderer;
struct _SDL_GameController;
typedef union SDL_Event SDL_Event;
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOpenGL(SDL_Window* window, void* sdl_gl_context);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
diff --git a/backends/imgui/backends/imgui_impl_sdlrenderer2.h b/backends/imgui/backends/imgui_impl_sdlrenderer2.h
index 6b7ff09ade1..ce00c5c676e 100644
--- a/backends/imgui/backends/imgui_impl_sdlrenderer2.h
+++ b/backends/imgui/backends/imgui_impl_sdlrenderer2.h
@@ -27,6 +27,7 @@
struct SDL_Renderer;
+// Follow "Getting Started" link and check examples/ folder to learn about using backends!
IMGUI_IMPL_API bool ImGui_ImplSDLRenderer2_Init(SDL_Renderer* renderer);
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDLRenderer2_NewFrame();
diff --git a/backends/imgui/imconfig.h b/backends/imgui/imconfig.h
index 9bd5d1c2166..b8d55842b9b 100644
--- a/backends/imgui/imconfig.h
+++ b/backends/imgui/imconfig.h
@@ -21,10 +21,11 @@
//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using Dear ImGui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
-// DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
-// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
-//#define IMGUI_API __declspec( dllexport )
-//#define IMGUI_API __declspec( dllimport )
+// - Windows DLL users: heaps and globals are not shared across DLL boundaries! You will need to call SetCurrentContext() + SetAllocatorFunctions()
+// for each static/DLL boundary you are calling from. Read "Context and Memory Allocators" section of imgui.cpp for more details.
+//#define IMGUI_API __declspec(dllexport) // MSVC Windows: DLL export
+//#define IMGUI_API __declspec(dllimport) // MSVC Windows: DLL import
+//#define IMGUI_API __attribute__((visibility("default"))) // GCC/Clang: override visibility when set is hidden
//---- Don't define obsolete functions/enums/behaviors. Consider enabling from time to time after updating to clean your code of obsolete function/names.
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@@ -42,6 +43,7 @@
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] [Default with non-Visual Studio compilers] Don't implement default IME handler (won't require imm32.lib/.a)
//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, IME).
//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices', this is why this is not the default).
+//#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS // Don't implement default platform_io.Platform_OpenInShellFn() handler (Win32: ShellExecute(), require shell32.lib/.a, Mac/Linux: use system("")).
//#define IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself (e.g. if you don't want to link with vsnprintf)
//#define IMGUI_DISABLE_DEFAULT_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 so you can implement them yourself.
//#define IMGUI_DISABLE_FILE_FUNCTIONS // Don't implement ImFileOpen/ImFileClose/ImFileRead/ImFileWrite and ImFileHandle at all (replace them with dummies)
@@ -49,6 +51,9 @@
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
//#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available
+//---- Enable Test Engine / Automation features.
+//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details.
+
//---- Include imgui_user.h at the end of imgui.h as a convenience
// May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
//#define IMGUI_INCLUDE_IMGUI_USER_H
@@ -76,7 +81,7 @@
//---- Use FreeType to build and rasterize the font atlas (instead of stb_truetype which is embedded by default in Dear ImGui)
// Requires FreeType headers to be available in the include path. Requires program to be compiled with 'misc/freetype/imgui_freetype.cpp' (in this repository) + the FreeType library (not provided).
// On Windows you may use vcpkg with 'vcpkg install freetype --triplet=x64-windows' + 'vcpkg integrate install'.
-#define IMGUI_ENABLE_FREETYPE
+//#define IMGUI_ENABLE_FREETYPE
//---- Use FreeType+lunasvg library to render OpenType SVG fonts (SVGinOT)
// Requires lunasvg headers to be available in the include path + program to be linked with the lunasvg library (not provided).
diff --git a/backends/imgui/imgui.cpp b/backends/imgui/imgui.cpp
index f1ef235a021..50c8d362efe 100644
--- a/backends/imgui/imgui.cpp
+++ b/backends/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.90.7 WIP
+// dear imgui, v1.91.3
// (main code and documentation)
// Help:
@@ -10,7 +10,7 @@
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
// - Homepage ................... https://github.com/ocornut/imgui
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
-// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!)
+// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!)
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
@@ -63,7 +63,7 @@ CODE
// [SECTION] INCLUDES
// [SECTION] FORWARD DECLARATIONS
// [SECTION] CONTEXT AND MEMORY ALLOCATORS
-// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
+// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO)
// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
// [SECTION] MISC HELPERS/UTILITIES (String, Format, Hash functions)
// [SECTION] MISC HELPERS/UTILITIES (File functions)
@@ -79,7 +79,7 @@ CODE
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
// [SECTION] ID STACK
// [SECTION] INPUTS
-// [SECTION] ERROR CHECKING
+// [SECTION] ERROR CHECKING, STATE RECOVERY
// [SECTION] ITEM SUBMISSION
// [SECTION] LAYOUT
// [SECTION] SCROLLING
@@ -438,6 +438,58 @@ CODE
- likewise io.MousePos and GetMousePos() will use OS coordinates.
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
+ - 2024/10/03 (1.91.3) - drags: treat v_min==v_max as a valid clamping range when != 0.0f. Zero is a still special value due to legacy reasons, unless using ImGuiSliderFlags_ClampZeroRange. (#7968, #3361, #76)
+ - drags: extended behavior of ImGuiSliderFlags_AlwaysClamp to include _ClampZeroRange. It considers v_min==v_max==0.0f as a valid clamping range (aka edits not allowed).
+ although unlikely, it you wish to only clamp on text input but want v_min==v_max==0.0f to mean unclamped drags, you can use _ClampOnInput instead of _AlwaysClamp. (#7968, #3361, #76)
+ - 2024/09/10 (1.91.2) - internals: using multiple overlayed ButtonBehavior() with same ID will now have io.ConfigDebugHighlightIdConflicts=true feature emit a warning. (#8030)
+ it was one of the rare case where using same ID is legal. workarounds: (1) use single ButtonBehavior() call with multiple _MouseButton flags, or (2) surround the calls with PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()
+ - 2024/08/23 (1.91.1) - renamed ImGuiChildFlags_Border to ImGuiChildFlags_Borders for consistency. kept inline redirection flag.
+ - 2024/08/22 (1.91.1) - moved some functions from ImGuiIO to ImGuiPlatformIO structure:
+ - io.GetClipboardTextFn -> platform_io.Platform_GetClipboardTextFn + changed 'void* user_data' to 'ImGuiContext* ctx'. Pull your user data from platform_io.ClipboardUserData.
+ - io.SetClipboardTextFn -> platform_io.Platform_SetClipboardTextFn + same as above line.
+ - io.PlatformOpenInShellFn -> platform_io.Platform_OpenInShellFn (#7660)
+ - io.PlatformSetImeDataFn -> platform_io.Platform_SetImeDataFn
+ - io.PlatformLocaleDecimalPoint -> platform_io.Platform_LocaleDecimalPoint (#7389, #6719, #2278)
+ - access those via GetPlatformIO() instead of GetIO().
+ some were introduced very recently and often automatically setup by core library and backends, so for those we are exceptionally not maintaining a legacy redirection symbol.
+ - commented the old ImageButton() signature obsoleted in 1.89 (~August 2022). As a reminder:
+ - old ImageButton() before 1.89 used ImTextureId as item id (created issue with e.g. multiple buttons in same scope, transient texture id values, opaque computation of ID)
+ - new ImageButton() since 1.89 requires an explicit 'const char* str_id'
+ - old ImageButton() before 1.89 had frame_padding' override argument.
+ - new ImageButton() since 1.89 always use style.FramePadding, which you can freely override with PushStyleVar()/PopStyleVar().
+ - 2024/07/25 (1.91.0) - obsoleted GetContentRegionMax(), GetWindowContentRegionMin() and GetWindowContentRegionMax(). (see #7838 on GitHub for more info)
+ you should never need those functions. you can do everything with GetCursorScreenPos() and GetContentRegionAvail() in a more simple way.
+ - instead of: GetWindowContentRegionMax().x - GetCursorPos().x
+ - you can use: GetContentRegionAvail().x
+ - instead of: GetWindowContentRegionMax().x + GetWindowPos().x
+ - you can use: GetCursorScreenPos().x + GetContentRegionAvail().x // when called from left edge of window
+ - instead of: GetContentRegionMax()
+ - you can use: GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos() // right edge in local coordinates
+ - instead of: GetWindowContentRegionMax().x - GetWindowContentRegionMin().x
+ - you can use: GetContentRegionAvail() // when called from left edge of window
+ - 2024/07/15 (1.91.0) - renamed ImGuiSelectableFlags_DontClosePopups to ImGuiSelectableFlags_NoAutoClosePopups. (#1379, #1468, #2200, #4936, #5216, #7302, #7573)
+ (internals: also renamed ImGuiItemFlags_SelectableDontClosePopup into ImGuiItemFlags_AutoClosePopups with inverted behaviors)
+ - 2024/07/15 (1.91.0) - obsoleted PushButtonRepeat()/PopButtonRepeat() in favor of using new PushItemFlag(ImGuiItemFlags_ButtonRepeat, ...)/PopItemFlag().
+ - 2024/07/02 (1.91.0) - commented out obsolete ImGuiModFlags (renamed to ImGuiKeyChord in 1.89). (#4921, #456)
+ - commented out obsolete ImGuiModFlags_XXX values (renamed to ImGuiMod_XXX in 1.89). (#4921, #456)
+ - ImGuiModFlags_Ctrl -> ImGuiMod_Ctrl, ImGuiModFlags_Shift -> ImGuiMod_Shift etc.
+ - 2024/07/02 (1.91.0) - IO, IME: renamed platform IME hook and added explicit context for consistency and future-proofness.
+ - old: io.SetPlatformImeDataFn(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
+ - new: io.PlatformSetImeDataFn(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
+ - 2024/06/21 (1.90.9) - BeginChild: added ImGuiChildFlags_NavFlattened as a replacement for the window flag ImGuiWindowFlags_NavFlattened: the feature only ever made sense for BeginChild() anyhow.
+ - old: BeginChild("Name", size, 0, ImGuiWindowFlags_NavFlattened);
+ - new: BeginChild("Name", size, ImGuiChildFlags_NavFlattened, 0);
+ - 2024/06/21 (1.90.9) - io: ClearInputKeys() (first exposed in 1.89.8) doesn't clear mouse data, newly added ClearInputMouse() does.
+ - 2024/06/20 (1.90.9) - renamed ImGuiDragDropFlags_SourceAutoExpirePayload to ImGuiDragDropFlags_PayloadAutoExpire.
+ - 2024/06/18 (1.90.9) - style: renamed ImGuiCol_TabActive -> ImGuiCol_TabSelected, ImGuiCol_TabUnfocused -> ImGuiCol_TabDimmed, ImGuiCol_TabUnfocusedActive -> ImGuiCol_TabDimmedSelected.
+ - 2024/06/10 (1.90.9) - removed old nested structure: renaming ImGuiStorage::ImGuiStoragePair type to ImGuiStoragePair (simpler for many languages).
+ - 2024/06/06 (1.90.8) - reordered ImGuiInputTextFlags values. This should not be breaking unless you are using generated headers that have values not matching the main library.
+ - 2024/06/06 (1.90.8) - removed 'ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft', was mostly unused and misleading.
+ - 2024/05/27 (1.90.7) - commented out obsolete symbols marked obsolete in 1.88 (May 2022):
+ - old: CaptureKeyboardFromApp(bool)
+ - new: SetNextFrameWantCaptureKeyboard(bool)
+ - old: CaptureMouseFromApp(bool)
+ - new: SetNextFrameWantCaptureMouse(bool)
- 2024/05/22 (1.90.7) - inputs (internals): renamed ImGuiKeyOwner_None to ImGuiKeyOwner_NoOwner, to make use more explicit and reduce confusion with the default it is a non-zero value and cannot be the default value (never made public, but disclosing as I expect a few users caught on owner-aware inputs).
- inputs (internals): renamed ImGuiInputFlags_RouteGlobalLow -> ImGuiInputFlags_RouteGlobal, ImGuiInputFlags_RouteGlobal -> ImGuiInputFlags_RouteGlobalOverFocused, ImGuiInputFlags_RouteGlobalHigh -> ImGuiInputFlags_RouteGlobalHighest.
- inputs (internals): Shortcut(), SetShortcutRouting(): swapped last two parameters order in function signatures:
@@ -479,6 +531,7 @@ CODE
- new: BeginChild("Name", size, ImGuiChildFlags_Border)
- old: BeginChild("Name", size, false)
- new: BeginChild("Name", size) or BeginChild("Name", 0) or BeginChild("Name", size, ImGuiChildFlags_None)
+ **AMEND FROM THE FUTURE: from 1.91.1, 'ImGuiChildFlags_Border' is called 'ImGuiChildFlags_Borders'**
- 2023/11/02 (1.90.0) - BeginChild: added child-flag ImGuiChildFlags_AlwaysUseWindowPadding as a replacement for the window-flag ImGuiWindowFlags_AlwaysUseWindowPadding: the feature only ever made sense for BeginChild() anyhow.
- old: BeginChild("Name", size, 0, ImGuiWindowFlags_AlwaysUseWindowPadding);
- new: BeginChild("Name", size, ImGuiChildFlags_AlwaysUseWindowPadding, 0);
@@ -1012,7 +1065,7 @@ CODE
#endif
// [Windows] OS specific includes (optional)
-#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
+#if defined(_WIN32) && defined(IMGUI_DISABLE_DEFAULT_FILE_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS) && defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS) && defined(IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
#define IMGUI_DISABLE_WIN32_FUNCTIONS
#endif
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
@@ -1031,6 +1084,7 @@ CODE
// The UWP and GDK Win32 API subsets don't support clipboard nor IME functions
#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS
#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS
+#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
#endif
#endif
@@ -1083,7 +1137,7 @@ CODE
#endif
// Debug options
-#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
+#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Hold CTRL to display for all candidates. CTRL+Arrow to change last direction.
#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window
// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
@@ -1098,7 +1152,9 @@ static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduc
static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 0.70f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certain time, unless mouse moved.
// Tooltip offset
-static const ImVec2 TOOLTIP_DEFAULT_OFFSET = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale
+static const ImVec2 TOOLTIP_DEFAULT_OFFSET_MOUSE = ImVec2(16, 10); // Multiplied by g.Style.MouseCursorScale
+static const ImVec2 TOOLTIP_DEFAULT_OFFSET_TOUCH = ImVec2(0, -20); // Multiplied by g.Style.MouseCursorScale
+static const ImVec2 TOOLTIP_DEFAULT_PIVOT_TOUCH = ImVec2(0.5f, 1.0f); // Multiplied by g.Style.MouseCursorScale
// Docking
static const float DOCKING_TRANSPARENT_PAYLOAD_ALPHA = 0.50f; // For use with io.ConfigDockingTransparentPayload. Apply to Viewport _or_ WindowBg in host viewport.
@@ -1120,10 +1176,11 @@ static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSetti
static void WindowSettingsHandler_ApplyAll(ImGuiContext*, ImGuiSettingsHandler*);
static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
-// Platform Dependents default implementation for IO functions
-static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx);
-static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text);
-static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
+// Platform Dependents default implementation for ImGuiPlatformIO functions
+static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx);
+static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text);
+static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
+static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext* ctx, const char* path);
namespace ImGui
{
@@ -1234,7 +1291,7 @@ static ImGuiMemFreeFunc GImAllocatorFreeFunc = FreeWrapper;
static void* GImAllocatorUserData = NULL;
//-----------------------------------------------------------------------------
-// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO)
+// [SECTION] USER FACING STRUCTURES (ImGuiStyle, ImGuiIO, ImGuiPlatformIO)
//-----------------------------------------------------------------------------
ImGuiStyle::ImGuiStyle()
@@ -1269,12 +1326,13 @@ ImGuiStyle::ImGuiStyle()
TabBorderSize = 0.0f; // Thickness of border around tabs.
TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
+ TabBarOverlineSize = 2.0f; // Thickness of tab-bar overline, which highlights the selected tab-bar.
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
- SeparatorTextBorderSize = 3.0f; // Thickkness of border in SeparatorText()
+ SeparatorTextBorderSize = 3.0f; // Thickness of border in SeparatorText()
SeparatorTextAlign = ImVec2(0.0f,0.5f);// Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
SeparatorTextPadding = ImVec2(20.0f,3.f);// Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
@@ -1322,6 +1380,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
LogSliderDeadzone = ImTrunc(LogSliderDeadzone * scale_factor);
TabRounding = ImTrunc(TabRounding * scale_factor);
TabMinWidthForCloseButton = (TabMinWidthForCloseButton != FLT_MAX) ? ImTrunc(TabMinWidthForCloseButton * scale_factor) : FLT_MAX;
+ TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor);
SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor);
DockingSeparatorSize = ImTrunc(DockingSeparatorSize * scale_factor);
DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor);
@@ -1374,16 +1433,25 @@ ImGuiIO::ImGuiIO()
#else
ConfigMacOSXBehaviors = false;
#endif
+ ConfigNavSwapGamepadButtons = false;
ConfigInputTrickleEventQueue = true;
ConfigInputTextCursorBlink = true;
ConfigInputTextEnterKeepActive = false;
ConfigDragClickToInputText = false;
ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false;
+ ConfigScrollbarScrollByPage = true;
ConfigMemoryCompactTimer = 60.0f;
+ ConfigDebugIsDebuggerPresent = false;
+ ConfigDebugHighlightIdConflicts = true;
ConfigDebugBeginReturnValueOnce = false;
ConfigDebugBeginReturnValueLoop = false;
+ ConfigErrorRecovery = true;
+ ConfigErrorRecoveryEnableAssert = true;
+ ConfigErrorRecoveryEnableDebugLog = true;
+ ConfigErrorRecoveryEnableTooltip = true;
+
// Inputs Behaviors
MouseDoubleClickTime = 0.30f;
MouseDoubleClickMaxDist = 6.0f;
@@ -1395,7 +1463,6 @@ ImGuiIO::ImGuiIO()
// Note: Initialize() will setup default clipboard/ime handlers.
BackendPlatformName = BackendRendererName = NULL;
BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
- PlatformLocaleDecimalPoint = '.';
// Input (NB: we already have memset zero the entire structure!)
MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
@@ -1483,7 +1550,7 @@ void ImGuiIO::ClearEventsQueue()
g.InputEventsQueue.clear();
}
-// Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
+// Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
void ImGuiIO::ClearInputKeys()
{
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@@ -1491,12 +1558,26 @@ void ImGuiIO::ClearInputKeys()
#endif
for (int n = 0; n < IM_ARRAYSIZE(KeysData); n++)
{
+ if (ImGui::IsMouseKey((ImGuiKey)(n + ImGuiKey_KeysData_OFFSET)))
+ continue;
KeysData[n].Down = false;
KeysData[n].DownDuration = -1.0f;
KeysData[n].DownDurationPrev = -1.0f;
}
KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
KeyMods = ImGuiMod_None;
+ InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
+}
+
+void ImGuiIO::ClearInputMouse()
+{
+ for (ImGuiKey key = ImGuiKey_Mouse_BEGIN; key < ImGuiKey_Mouse_END; key = (ImGuiKey)(key + 1))
+ {
+ ImGuiKeyData* key_data = &KeysData[key - ImGuiKey_KeysData_OFFSET];
+ key_data->Down = false;
+ key_data->DownDuration = -1.0f;
+ key_data->DownDurationPrev = -1.0f;
+ }
MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
for (int n = 0; n < IM_ARRAYSIZE(MouseDown); n++)
{
@@ -1504,7 +1585,6 @@ void ImGuiIO::ClearInputKeys()
MouseDownDuration[n] = MouseDownDurationPrev[n] = -1.0f;
}
MouseWheel = MouseWheelH = 0.0f;
- InputQueueCharacters.resize(0); // Behavior of old ClearInputCharacters().
}
// Removed this as it is ambiguous/misleading and generally incorrect to use with the existence of a higher-level input queue.
@@ -1771,6 +1851,13 @@ void ImGuiIO::AddFocusEvent(bool focused)
g.InputEventsQueue.push_back(e);
}
+ImGuiPlatformIO::ImGuiPlatformIO()
+{
+ // Most fields are initialized with zero
+ memset(this, 0, sizeof(*this));
+ Platform_LocaleDecimalPoint = '.';
+}
+
//-----------------------------------------------------------------------------
// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
//-----------------------------------------------------------------------------
@@ -1961,7 +2048,7 @@ const char* ImStreolRange(const char* str, const char* str_end)
return p ? p : str_end;
}
-const ImWchar* ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin) // find beginning-of-line
+const char* ImStrbol(const char* buf_mid_line, const char* buf_begin) // find beginning-of-line
{
while (buf_mid_line > buf_begin && buf_mid_line[-1] != '\n')
buf_mid_line--;
@@ -2079,6 +2166,10 @@ void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end,
va_end(args);
}
+// FIXME: Should rework API toward allowing multiple in-flight temp buffers (easier and safer for caller)
+// by making the caller acquire a temp buffer token, with either explicit or destructor release, e.g.
+// ImGuiTempBufferToken token;
+// ImFormatStringToTempBuffer(token, ...);
void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
@@ -2556,18 +2647,16 @@ void ImGui::ColorConvertHSVtoRGB(float h, float s, float v, float& out_r, float&
//-----------------------------------------------------------------------------
// std::lower_bound but without the bullshit
-static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
+ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key)
{
- ImGuiStorage::ImGuiStoragePair* first = data.Data;
- ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
- size_t count = (size_t)(last - first);
- while (count > 0)
+ ImGuiStoragePair* in_p = in_begin;
+ for (size_t count = (size_t)(in_end - in_p); count > 0; )
{
size_t count2 = count >> 1;
- ImGuiStorage::ImGuiStoragePair* mid = first + count2;
+ ImGuiStoragePair* mid = in_p + count2;
if (mid->key < key)
{
- first = ++mid;
+ in_p = ++mid;
count -= count2 + 1;
}
else
@@ -2575,29 +2664,28 @@ static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiSt
count = count2;
}
}
- return first;
+ return in_p;
+}
+
+IM_MSVC_RUNTIME_CHECKS_OFF
+static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
+{
+ // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
+ ImGuiID lhs_v = ((const ImGuiStoragePair*)lhs)->key;
+ ImGuiID rhs_v = ((const ImGuiStoragePair*)rhs)->key;
+ return (lhs_v > rhs_v ? +1 : lhs_v < rhs_v ? -1 : 0);
}
// For quicker full rebuild of a storage (instead of an incremental one), you may add all your contents and then sort once.
void ImGuiStorage::BuildSortByKey()
{
- struct StaticFunc
- {
- static int IMGUI_CDECL PairComparerByID(const void* lhs, const void* rhs)
- {
- // We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
- if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
- if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
- return 0;
- }
- };
- ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairComparerByID);
+ ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), PairComparerByID);
}
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
{
- ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
+ if (it == Data.Data + Data.Size || it->key != key)
return default_val;
return it->val_i;
}
@@ -2609,16 +2697,16 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
{
- ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
+ if (it == Data.Data + Data.Size || it->key != key)
return default_val;
return it->val_f;
}
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
{
- ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(const_cast<ImGuiStoragePair*>(Data.Data), const_cast<ImGuiStoragePair*>(Data.Data + Data.Size), key);
+ if (it == Data.Data + Data.Size || it->key != key)
return NULL;
return it->val_p;
}
@@ -2626,8 +2714,8 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_i;
}
@@ -2639,16 +2727,16 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_f;
}
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_p;
}
@@ -2656,8 +2744,8 @@ void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
void ImGuiStorage::SetInt(ImGuiID key, int val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
it->val_i = val;
@@ -2670,8 +2758,8 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val)
void ImGuiStorage::SetFloat(ImGuiID key, float val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
it->val_f = val;
@@ -2679,8 +2767,8 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val)
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
{
- ImGuiStoragePair* it = LowerBound(Data, key);
- if (it == Data.end() || it->key != key)
+ ImGuiStoragePair* it = ImLowerBound(Data.Data, Data.Data + Data.Size, key);
+ if (it == Data.Data + Data.Size || it->key != key)
Data.insert(it, ImGuiStoragePair(key, val));
else
it->val_p = val;
@@ -2691,6 +2779,7 @@ void ImGuiStorage::SetAllInt(int v)
for (int i = 0; i < Data.Size; i++)
Data[i].val_i = v;
}
+IM_MSVC_RUNTIME_CHECKS_RESTORE
//-----------------------------------------------------------------------------
// [SECTION] ImGuiTextFilter
@@ -2758,15 +2847,15 @@ void ImGuiTextFilter::Build()
bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
{
- if (Filters.empty())
+ if (Filters.Size == 0)
return true;
if (text == NULL)
- text = "";
+ text = text_end = "";
for (const ImGuiTextRange& f : Filters)
{
- if (f.empty())
+ if (f.b == f.e)
continue;
if (f.b[0] == '-')
{
@@ -2933,15 +3022,6 @@ static void ImGuiListClipper_SeekCursorAndSetupPrevLine(float pos_y, float line_
}
}
-static void ImGuiListClipper_SeekCursorForItem(ImGuiListClipper* clipper, int item_n)
-{
- // StartPosY starts from ItemsFrozen hence the subtraction
- // Perform the add and multiply with double to allow seeking through larger ranges
- ImGuiListClipperData* data = (ImGuiListClipperData*)clipper->TempData;
- float pos_y = (float)((double)clipper->StartPosY + data->LossynessOffset + (double)(item_n - data->ItemsFrozen) * clipper->ItemsHeight);
- ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, clipper->ItemsHeight);
-}
-
ImGuiListClipper::ImGuiListClipper()
{
memset(this, 0, sizeof(*this));
@@ -2978,6 +3058,7 @@ void ImGuiListClipper::Begin(int items_count, float items_height)
data->Reset(this);
data->LossynessOffset = window->DC.CursorStartPosLossyness.y;
TempData = data;
+ StartSeekOffsetY = data->LossynessOffset;
}
void ImGuiListClipper::End()
@@ -2988,7 +3069,7 @@ void ImGuiListClipper::End()
ImGuiContext& g = *Ctx;
IMGUI_DEBUG_LOG_CLIPPER("Clipper: End() in '%s'\n", g.CurrentWindow->Name);
if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
- ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
+ SeekCursorForItem(ItemsCount);
// Restore temporary buffer and fix back pointers which may be invalidated when nesting
IM_ASSERT(data->ListClipper == this);
@@ -3012,6 +3093,17 @@ void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
data->Ranges.push_back(ImGuiListClipperRange::FromIndices(item_begin, item_end));
}
+// This is already called while stepping.
+// The ONLY reason you may want to call this is if you passed INT_MAX to ImGuiListClipper::Begin() because you couldn't step item count beforehand.
+void ImGuiListClipper::SeekCursorForItem(int item_n)
+{
+ // - Perform the add and multiply with double to allow seeking through larger ranges.
+ // - StartPosY starts from ItemsFrozen, by adding SeekOffsetY we generally cancel that out (SeekOffsetY == LossynessOffset - ItemsFrozen * ItemsHeight).
+ // - The reason we store SeekOffsetY instead of inferring it, is because we want to allow user to perform Seek after the last step, where ImGuiListClipperData is already done.
+ float pos_y = (float)((double)StartPosY + StartSeekOffsetY + (double)item_n * ItemsHeight);
+ ImGuiListClipper_SeekCursorAndSetupPrevLine(pos_y, ItemsHeight);
+}
+
static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
{
ImGuiContext& g = *clipper->Ctx;
@@ -3066,7 +3158,8 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision(clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
if (affected_by_floating_point_precision)
clipper->ItemsHeight = window->DC.PrevLineSize.y + g.Style.ItemSpacing.y; // FIXME: Technically wouldn't allow multi-line entries.
-
+ if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode.
+ return false;
IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!");
calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
}
@@ -3075,6 +3168,9 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
const int already_submitted = clipper->DisplayEnd;
if (calc_clipping)
{
+ // Record seek offset, this is so ImGuiListClipper::Seek() can be called after ImGuiListClipperData is done
+ clipper->StartSeekOffsetY = (double)data->LossynessOffset - data->ItemsFrozen * (double)clipper->ItemsHeight;
+
if (g.LogEnabled)
{
// If logging is active, do not perform any clipping
@@ -3095,9 +3191,27 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
data->Ranges.push_back(ImGuiListClipperRange::FromPositions(nav_rect_abs.Min.y, nav_rect_abs.Max.y, 0, 0));
// Add visible range
+ float min_y = window->ClipRect.Min.y;
+ float max_y = window->ClipRect.Max.y;
+
+ // Add box selection range
+ ImGuiBoxSelectState* bs = &g.BoxSelectState;
+ if (bs->IsActive && bs->Window == window)
+ {
+ // FIXME: Selectable() use of half-ItemSpacing isn't consistent in matter of layout, as ItemAdd(bb) stray above ItemSize()'s CursorPos.
+ // RangeSelect's BoxSelect relies on comparing overlap of previous and current rectangle and is sensitive to that.
+ // As a workaround we currently half ItemSpacing worth on each side.
+ min_y -= g.Style.ItemSpacing.y;
+ max_y += g.Style.ItemSpacing.y;
+
+ // Box-select on 2D area requires different clipping.
+ if (bs->UnclipMode)
+ data->Ranges.push_back(ImGuiListClipperRange::FromPositions(bs->UnclipRect.Min.y, bs->UnclipRect.Max.y, 0, 0));
+ }
+
const int off_min = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Up) ? -1 : 0;
const int off_max = (is_nav_request && g.NavMoveClipDir == ImGuiDir_Down) ? 1 : 0;
- data->Ranges.push_back(ImGuiListClipperRange::FromPositions(window->ClipRect.Min.y, window->ClipRect.Max.y, off_min, off_max));
+ data->Ranges.push_back(ImGuiListClipperRange::FromPositions(min_y, max_y, off_min, off_max));
}
// Convert position ranges to item index ranges
@@ -3122,7 +3236,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
if (clipper->DisplayStart > already_submitted) //-V1051
- ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);
+ clipper->SeekCursorForItem(clipper->DisplayStart);
data->StepNo++;
if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)
continue;
@@ -3132,7 +3246,7 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
// After the last step: Let the clipper validate that we have reached the expected Y position (corresponding to element DisplayEnd),
// Advance the cursor to the end of the list and then returns 'false' to end the loop.
if (clipper->ItemsCount < INT_MAX)
- ImGuiListClipper_SeekCursorForItem(clipper, clipper->ItemsCount);
+ clipper->SeekCursorForItem(clipper->ItemsCount);
return false;
}
@@ -3231,7 +3345,7 @@ void ImGui::PopStyleColor(int count)
ImGuiContext& g = *GImGui;
if (g.ColorStack.Size < count)
{
- IM_ASSERT_USER_ERROR(g.ColorStack.Size > count, "Calling PopStyleColor() too many times!");
+ IM_ASSERT_USER_ERROR(0, "Calling PopStyleColor() too many times!");
count = g.ColorStack.Size;
}
while (count > 0)
@@ -3245,7 +3359,7 @@ void ImGui::PopStyleColor(int count)
static const ImGuiCol GWindowDockStyleColors[ImGuiWindowDockStyleCol_COUNT] =
{
- ImGuiCol_Text, ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive
+ ImGuiCol_Text, ImGuiCol_TabHovered, ImGuiCol_Tab, ImGuiCol_TabSelected, ImGuiCol_TabSelectedOverline, ImGuiCol_TabDimmed, ImGuiCol_TabDimmedSelected, ImGuiCol_TabDimmedSelectedOverline,
};
static const ImGuiDataVarInfo GStyleVarInfo[] =
@@ -3275,6 +3389,7 @@ static const ImGuiDataVarInfo GStyleVarInfo[] =
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabRounding) }, // ImGuiStyleVar_TabRounding
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBorderSize) }, // ImGuiStyleVar_TabBorderSize
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarBorderSize) }, // ImGuiStyleVar_TabBarBorderSize
+ { ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TabBarOverlineSize) }, // ImGuiStyleVar_TabBarOverlineSize
{ ImGuiDataType_Float, 1, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
{ ImGuiDataType_Float, 2, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
@@ -3296,28 +3411,56 @@ void ImGui::PushStyleVar(ImGuiStyleVar idx, float val)
{
ImGuiContext& g = *GImGui;
const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
- if (var_info->Type == ImGuiDataType_Float && var_info->Count == 1)
+ if (var_info->Type != ImGuiDataType_Float || var_info->Count != 1)
{
- float* pvar = (float*)var_info->GetVarPtr(&g.Style);
- g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
- *pvar = val;
+ IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
return;
}
- IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
+ float* pvar = (float*)var_info->GetVarPtr(&g.Style);
+ g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
+ *pvar = val;
+}
+
+void ImGui::PushStyleVarX(ImGuiStyleVar idx, float val_x)
+{
+ ImGuiContext& g = *GImGui;
+ const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
+ if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
+ return;
+ }
+ ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
+ g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
+ pvar->x = val_x;
+}
+
+void ImGui::PushStyleVarY(ImGuiStyleVar idx, float val_y)
+{
+ ImGuiContext& g = *GImGui;
+ const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
+ if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
+ return;
+ }
+ ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
+ g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
+ pvar->y = val_y;
}
void ImGui::PushStyleVar(ImGuiStyleVar idx, const ImVec2& val)
{
ImGuiContext& g = *GImGui;
const ImGuiDataVarInfo* var_info = GetStyleVarInfo(idx);
- if (var_info->Type == ImGuiDataType_Float && var_info->Count == 2)
+ if (var_info->Type != ImGuiDataType_Float || var_info->Count != 2)
{
- ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
- g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
- *pvar = val;
+ IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
return;
}
- IM_ASSERT_USER_ERROR(0, "Calling PushStyleVar() variant with wrong type!");
+ ImVec2* pvar = (ImVec2*)var_info->GetVarPtr(&g.Style);
+ g.StyleVarStack.push_back(ImGuiStyleMod(idx, *pvar));
+ *pvar = val;
}
void ImGui::PopStyleVar(int count)
@@ -3325,7 +3468,7 @@ void ImGui::PopStyleVar(int count)
ImGuiContext& g = *GImGui;
if (g.StyleVarStack.Size < count)
{
- IM_ASSERT_USER_ERROR(g.StyleVarStack.Size > count, "Calling PopStyleVar() too many times!");
+ IM_ASSERT_USER_ERROR(0, "Calling PopStyleVar() too many times!");
count = g.StyleVarStack.Size;
}
while (count > 0)
@@ -3379,11 +3522,13 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_ResizeGrip: return "ResizeGrip";
case ImGuiCol_ResizeGripHovered: return "ResizeGripHovered";
case ImGuiCol_ResizeGripActive: return "ResizeGripActive";
- case ImGuiCol_Tab: return "Tab";
case ImGuiCol_TabHovered: return "TabHovered";
- case ImGuiCol_TabActive: return "TabActive";
- case ImGuiCol_TabUnfocused: return "TabUnfocused";
- case ImGuiCol_TabUnfocusedActive: return "TabUnfocusedActive";
+ case ImGuiCol_Tab: return "Tab";
+ case ImGuiCol_TabSelected: return "TabSelected";
+ case ImGuiCol_TabSelectedOverline: return "TabSelectedOverline";
+ case ImGuiCol_TabDimmed: return "TabDimmed";
+ case ImGuiCol_TabDimmedSelected: return "TabDimmedSelected";
+ case ImGuiCol_TabDimmedSelectedOverline: return "TabDimmedSelectedOverline";
case ImGuiCol_DockingPreview: return "DockingPreview";
case ImGuiCol_DockingEmptyBg: return "DockingEmptyBg";
case ImGuiCol_PlotLines: return "PlotLines";
@@ -3395,6 +3540,7 @@ const char* ImGui::GetStyleColorName(ImGuiCol idx)
case ImGuiCol_TableBorderLight: return "TableBorderLight";
case ImGuiCol_TableRowBg: return "TableRowBg";
case ImGuiCol_TableRowBgAlt: return "TableRowBgAlt";
+ case ImGuiCol_TextLink: return "TextLink";
case ImGuiCol_TextSelectedBg: return "TextSelectedBg";
case ImGuiCol_DragDropTarget: return "DragDropTarget";
case ImGuiCol_NavHighlight: return "NavHighlight";
@@ -3540,7 +3686,7 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
const ImFont* font = draw_list->_Data->Font;
const float font_size = draw_list->_Data->FontSize;
- const float font_scale = font_size / font->FontSize;
+ const float font_scale = draw_list->_Data->FontScale;
const char* text_end_ellipsis = NULL;
const float ellipsis_width = font->EllipsisWidth * font_scale;
@@ -3577,13 +3723,13 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, con
}
// Render a rectangle shaped with optional rounding and borders
-void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
+void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool borders, float rounding)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
window->DrawList->AddRectFilled(p_min, p_max, fill_col, rounding);
const float border_size = g.Style.FrameBorderSize;
- if (border && border_size > 0.0f)
+ if (borders && border_size > 0.0f)
{
window->DrawList->AddRect(p_min + ImVec2(1, 1), p_max + ImVec2(1, 1), GetColorU32(ImGuiCol_BorderShadow), rounding, 0, border_size);
window->DrawList->AddRect(p_min, p_max, GetColorU32(ImGuiCol_Border), rounding, 0, border_size);
@@ -3637,7 +3783,8 @@ void ImGui::RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFl
void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
+ if (mouse_cursor <= ImGuiMouseCursor_None || mouse_cursor >= ImGuiMouseCursor_COUNT) // We intentionally accept out of bound values.
+ mouse_cursor = ImGuiMouseCursor_Arrow;
ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
for (ImGuiViewportP* viewport : g.Viewports)
{
@@ -3717,7 +3864,7 @@ void ImGui::DestroyContext(ImGuiContext* ctx)
IM_DELETE(ctx);
}
-// IMPORTANT: ###xxx suffixes must be same in ALL languages
+// IMPORTANT: interactive elements requires a fixed ###xxx suffix, it must be same in ALL languages to allow for automation.
static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{
{ ImGuiLocKey_VersionStr, "Dear ImGui " IMGUI_VERSION " (" IM_STRINGIFY(IMGUI_VERSION_NUM) ")" },
@@ -3728,11 +3875,238 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" },
{ ImGuiLocKey_WindowingPopup, "(Popup)" },
{ ImGuiLocKey_WindowingUntitled, "(Untitled)" },
- { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
+ { ImGuiLocKey_OpenLink_s, "Open '%s'" },
+ { ImGuiLocKey_CopyLink, "Copy Link###CopyLink" },
+ { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
{ ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window." },
{ ImGuiLocKey_DockingDragToUndockOrMoveNode,"Click and drag to move or undock whole node." },
};
+ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
+{
+ IO.Ctx = this;
+ InputTextState.Ctx = this;
+
+ Initialized = false;
+ ConfigFlagsCurrFrame = ConfigFlagsLastFrame = ImGuiConfigFlags_None;
+ FontAtlasOwnedByContext = shared_font_atlas ? false : true;
+ Font = NULL;
+ FontSize = FontBaseSize = FontScale = CurrentDpiScale = 0.0f;
+ IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
+ Time = 0.0f;
+ FrameCount = 0;
+ FrameCountEnded = FrameCountPlatformEnded = FrameCountRendered = -1;
+ WithinFrameScope = WithinFrameScopeWithImplicitWindow = WithinEndChild = false;
+ GcCompactAll = false;
+ TestEngineHookItems = false;
+ TestEngine = NULL;
+ memset(ContextName, 0, sizeof(ContextName));
+
+ InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
+ InputEventsNextEventId = 1;
+
+ WindowsActiveCount = 0;
+ CurrentWindow = NULL;
+ HoveredWindow = NULL;
+ HoveredWindowUnderMovingWindow = NULL;
+ HoveredWindowBeforeClear = NULL;
+ MovingWindow = NULL;
+ WheelingWindow = NULL;
+ WheelingWindowStartFrame = WheelingWindowScrolledFrame = -1;
+ WheelingWindowReleaseTimer = 0.0f;
+
+ DebugDrawIdConflicts = 0;
+ DebugHookIdInfo = 0;
+ HoveredId = HoveredIdPreviousFrame = 0;
+ HoveredIdPreviousFrameItemCount = 0;
+ HoveredIdAllowOverlap = false;
+ HoveredIdIsDisabled = false;
+ HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
+ ItemUnclipByLog = false;
+ ActiveId = 0;
+ ActiveIdIsAlive = 0;
+ ActiveIdTimer = 0.0f;
+ ActiveIdIsJustActivated = false;
+ ActiveIdAllowOverlap = false;
+ ActiveIdNoClearOnFocusLoss = false;
+ ActiveIdHasBeenPressedBefore = false;
+ ActiveIdHasBeenEditedBefore = false;
+ ActiveIdHasBeenEditedThisFrame = false;
+ ActiveIdFromShortcut = false;
+ ActiveIdClickOffset = ImVec2(-1, -1);
+ ActiveIdWindow = NULL;
+ ActiveIdSource = ImGuiInputSource_None;
+ ActiveIdMouseButton = -1;
+ ActiveIdPreviousFrame = 0;
+ ActiveIdPreviousFrameIsAlive = false;
+ ActiveIdPreviousFrameHasBeenEditedBefore = false;
+ ActiveIdPreviousFrameWindow = NULL;
+ LastActiveId = 0;
+ LastActiveIdTimer = 0.0f;
+
+ LastKeyboardKeyPressTime = LastKeyModsChangeTime = LastKeyModsChangeFromNoneTime = -1.0;
+
+ ActiveIdUsingNavDirMask = 0x00;
+ ActiveIdUsingAllKeyboardKeys = false;
+
+ CurrentFocusScopeId = 0;
+ CurrentItemFlags = ImGuiItemFlags_None;
+ DebugShowGroupRects = false;
+
+ CurrentViewport = NULL;
+ MouseViewport = MouseLastHoveredViewport = NULL;
+ PlatformLastFocusedViewportId = 0;
+ ViewportCreatedCount = PlatformWindowsCreatedCount = 0;
+ ViewportFocusedStampCount = 0;
+
+ NavWindow = NULL;
+ NavId = NavFocusScopeId = NavActivateId = NavActivateDownId = NavActivatePressedId = 0;
+ NavLayer = ImGuiNavLayer_Main;
+ NavNextActivateId = 0;
+ NavActivateFlags = NavNextActivateFlags = ImGuiActivateFlags_None;
+ NavHighlightActivatedId = 0;
+ NavHighlightActivatedTimer = 0.0f;
+ NavInputSource = ImGuiInputSource_Keyboard;
+ NavLastValidSelectionUserData = ImGuiSelectionUserData_Invalid;
+ NavIdIsAlive = false;
+ NavMousePosDirty = false;
+ NavDisableHighlight = true;
+ NavDisableMouseHover = false;
+
+ NavAnyRequest = false;
+ NavInitRequest = false;
+ NavInitRequestFromMove = false;
+ NavMoveSubmitted = false;
+ NavMoveScoringItems = false;
+ NavMoveForwardToNextFrame = false;
+ NavMoveFlags = ImGuiNavMoveFlags_None;
+ NavMoveScrollFlags = ImGuiScrollFlags_None;
+ NavMoveKeyMods = ImGuiMod_None;
+ NavMoveDir = NavMoveDirForDebug = NavMoveClipDir = ImGuiDir_None;
+ NavScoringDebugCount = 0;
+ NavTabbingDir = 0;
+ NavTabbingCounter = 0;
+
+ NavJustMovedFromFocusScopeId = NavJustMovedToId = NavJustMovedToFocusScopeId = 0;
+ NavJustMovedToKeyMods = ImGuiMod_None;
+ NavJustMovedToIsTabbing = false;
+ NavJustMovedToHasSelectionData = false;
+
+ // All platforms use Ctrl+Tab but Ctrl<>Super are swapped on Mac...
+ // FIXME: Because this value is stored, it annoyingly interfere with toggling io.ConfigMacOSXBehaviors updating this..
+ ConfigNavWindowingKeyNext = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiKey_Tab);
+ ConfigNavWindowingKeyPrev = IO.ConfigMacOSXBehaviors ? (ImGuiMod_Super | ImGuiMod_Shift | ImGuiKey_Tab) : (ImGuiMod_Ctrl | ImGuiMod_Shift | ImGuiKey_Tab);
+ NavWindowingTarget = NavWindowingTargetAnim = NavWindowingListWindow = NULL;
+ NavWindowingTimer = NavWindowingHighlightAlpha = 0.0f;
+ NavWindowingToggleLayer = false;
+ NavWindowingToggleKey = ImGuiKey_None;
+
+ DimBgRatio = 0.0f;
+
+ DragDropActive = DragDropWithinSource = DragDropWithinTarget = false;
+ DragDropSourceFlags = ImGuiDragDropFlags_None;
+ DragDropSourceFrameCount = -1;
+ DragDropMouseButton = -1;
+ DragDropTargetId = 0;
+ DragDropAcceptFlags = ImGuiDragDropFlags_None;
+ DragDropAcceptIdCurrRectSurface = 0.0f;
+ DragDropAcceptIdPrev = DragDropAcceptIdCurr = 0;
+ DragDropAcceptFrameCount = -1;
+ DragDropHoldJustPressedId = 0;
+ memset(DragDropPayloadBufLocal, 0, sizeof(DragDropPayloadBufLocal));
+
+ ClipperTempDataStacked = 0;
+
+ CurrentTable = NULL;
+ TablesTempDataStacked = 0;
+ CurrentTabBar = NULL;
+ CurrentMultiSelect = NULL;
+ MultiSelectTempDataStacked = 0;
+
+ HoverItemDelayId = HoverItemDelayIdPreviousFrame = HoverItemUnlockedStationaryId = HoverWindowUnlockedStationaryId = 0;
+ HoverItemDelayTimer = HoverItemDelayClearTimer = 0.0f;
+
+ MouseCursor = ImGuiMouseCursor_Arrow;
+ MouseStationaryTimer = 0.0f;
+
+ TempInputId = 0;
+ memset(&DataTypeZeroValue, 0, sizeof(DataTypeZeroValue));
+ BeginMenuDepth = BeginComboDepth = 0;
+ ColorEditOptions = ImGuiColorEditFlags_DefaultOptions_;
+ ColorEditCurrentID = ColorEditSavedID = 0;
+ ColorEditSavedHue = ColorEditSavedSat = 0.0f;
+ ColorEditSavedColor = 0;
+ WindowResizeRelativeMode = false;
+ ScrollbarSeekMode = 0;
+ ScrollbarClickDeltaToGrabCenter = 0.0f;
+ SliderGrabClickOffset = 0.0f;
+ SliderCurrentAccum = 0.0f;
+ SliderCurrentAccumDirty = false;
+ DragCurrentAccumDirty = false;
+ DragCurrentAccum = 0.0f;
+ DragSpeedDefaultRatio = 1.0f / 100.0f;
+ DisabledAlphaBackup = 0.0f;
+ DisabledStackSize = 0;
+ LockMarkEdited = 0;
+ TooltipOverrideCount = 0;
+ TooltipPreviousWindow = NULL;
+
+ PlatformImeData.InputPos = ImVec2(0.0f, 0.0f);
+ PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission
+ PlatformImeViewport = 0;
+
+ DockNodeWindowMenuHandler = NULL;
+
+ SettingsLoaded = false;
+ SettingsDirtyTimer = 0.0f;
+ HookIdNext = 0;
+
+ memset(LocalizationTable, 0, sizeof(LocalizationTable));
+
+ LogEnabled = false;
+ LogType = ImGuiLogType_None;
+ LogNextPrefix = LogNextSuffix = NULL;
+ LogFile = NULL;
+ LogLinePosY = FLT_MAX;
+ LogLineFirstItem = false;
+ LogDepthRef = 0;
+ LogDepthToExpand = LogDepthToExpandDefault = 2;
+
+ ErrorCallback = NULL;
+ ErrorCallbackUserData = NULL;
+ ErrorFirst = true;
+ ErrorCountCurrentFrame = 0;
+ StackSizesInBeginForCurrentWindow = NULL;
+
+ DebugDrawIdConflictsCount = 0;
+ DebugLogFlags = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_OutputToTTY;
+ DebugLocateId = 0;
+ DebugLogSkippedErrors = 0;
+ DebugLogAutoDisableFlags = ImGuiDebugLogFlags_None;
+ DebugLogAutoDisableFrames = 0;
+ DebugLocateFrames = 0;
+ DebugBeginReturnValueCullDepth = -1;
+ DebugItemPickerActive = false;
+ DebugItemPickerMouseButton = ImGuiMouseButton_Left;
+ DebugItemPickerBreakId = 0;
+ DebugFlashStyleColorTime = 0.0f;
+ DebugFlashStyleColorIdx = ImGuiCol_COUNT;
+ DebugHoveredDockNode = NULL;
+
+ // Same as DebugBreakClearData(). Those fields are scattered in their respective subsystem to stay in hot-data locations
+ DebugBreakInWindow = 0;
+ DebugBreakInTable = 0;
+ DebugBreakInLocateId = false;
+ DebugBreakKeyChord = ImGuiKey_Pause;
+ DebugBreakInShortcutRouting = ImGuiKey_None;
+
+ memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
+ FramerateSecPerFrameIdx = FramerateSecPerFrameCount = 0;
+ FramerateSecPerFrameAccum = 0.0f;
+ WantCaptureMouseNextFrame = WantCaptureKeyboardNextFrame = WantTextInputNextFrame = -1;
+ memset(TempKeychordName, 0, sizeof(TempKeychordName));
+}
+
void ImGui::Initialize()
{
ImGuiContext& g = *GImGui;
@@ -3755,11 +4129,11 @@ void ImGui::Initialize()
// Setup default localization table
LocalizeRegisterEntries(GLocalizationEntriesEnUS, IM_ARRAYSIZE(GLocalizationEntriesEnUS));
- // Setup default platform clipboard/IME handlers.
- g.IO.GetClipboardTextFn = GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
- g.IO.SetClipboardTextFn = SetClipboardTextFn_DefaultImpl;
- g.IO.ClipboardUserData = (void*)&g; // Default implementation use the ImGuiContext as user data (ideally those would be arguments to the function)
- g.IO.SetPlatformImeDataFn = SetPlatformImeDataFn_DefaultImpl;
+ // Setup default ImGuiPlatformIO clipboard/IME handlers.
+ g.PlatformIO.Platform_GetClipboardTextFn = Platform_GetClipboardTextFn_DefaultImpl; // Platform dependent default implementations
+ g.PlatformIO.Platform_SetClipboardTextFn = Platform_SetClipboardTextFn_DefaultImpl;
+ g.PlatformIO.Platform_OpenInShellFn = Platform_OpenInShellFn_DefaultImpl;
+ g.PlatformIO.Platform_SetImeDataFn = Platform_SetImeDataFn_DefaultImpl;
// Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
@@ -3839,7 +4213,7 @@ void ImGui::Shutdown()
g.FontStack.clear();
g.OpenPopupStack.clear();
g.BeginPopupStack.clear();
- g.NavTreeNodeStack.clear();
+ g.TreeNodeStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
g.Viewports.clear_delete();
@@ -3854,6 +4228,9 @@ void ImGui::Shutdown()
g.TablesTempData.clear_destruct();
g.DrawChannelsTempMergeBuffer.clear();
+ g.MultiSelectStorage.Clear();
+ g.MultiSelectTempData.clear_destruct();
+
g.ClipboardHandlerData.clear();
g.MenusIdSubmittedThisFrame.clear();
g.InputTextState.ClearFreeMemory();
@@ -3955,10 +4332,12 @@ static void SetCurrentWindow(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
g.CurrentWindow = window;
+ g.StackSizesInBeginForCurrentWindow = g.CurrentWindow ? &g.CurrentWindowStack.back().StackSizesInBegin : NULL;
g.CurrentTable = window && window->DC.CurrentTableIdx != -1 ? g.Tables.GetByIndex(window->DC.CurrentTableIdx) : NULL;
if (window)
{
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
+ g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
ImGui::NavUpdateCurrentWindowIsScrollPushableX();
}
}
@@ -3968,6 +4347,8 @@ void ImGui::GcCompactTransientMiscBuffers()
ImGuiContext& g = *GImGui;
g.ItemFlagsStack.clear();
g.GroupStack.clear();
+ g.MultiSelectTempDataStacked = 0;
+ g.MultiSelectTempData.clear_destruct();
TableGcCompactSettings();
}
@@ -4052,9 +4433,6 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingAllKeyboardKeys = false;
-#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
- g.ActiveIdUsingNavInputMask = 0x00;
-#endif
}
void ImGui::ClearActiveID()
@@ -4092,7 +4470,7 @@ void ImGui::MarkItemEdited(ImGuiID id)
// We accept a MarkItemEdited() on drag and drop targets (see https://github.com/ocornut/imgui/issues/1875#issuecomment-978243343)
// We accept 'ActiveIdPreviousFrame == id' for InputText() returning an edit after it has been taken ActiveId away (#4714)
- IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id);
+ IM_ASSERT(g.DragDropActive || g.ActiveId == id || g.ActiveId == 0 || g.ActiveIdPreviousFrame == id || (g.CurrentMultiSelect != NULL && g.BoxSelectState.IsActive));
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_Edited;
@@ -4222,7 +4600,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
const float delay = CalcDelayFromHoveredFlags(flags);
if (delay > 0.0f || (flags & ImGuiHoveredFlags_Stationary))
{
- ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromRectangle(g.LastItemData.Rect);
+ ImGuiID hover_delay_id = (g.LastItemData.ID != 0) ? g.LastItemData.ID : window->GetIDFromPos(g.LastItemData.Rect.Min);
if ((flags & ImGuiHoveredFlags_NoSharedDelay) && (g.HoverItemDelayIdPreviousFrame != hover_delay_id))
g.HoverItemDelayTimer = 0.0f;
g.HoverItemDelayId = hover_delay_id;
@@ -4250,6 +4628,17 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+
+ // Detect ID conflicts
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ if (id != 0 && g.HoveredIdPreviousFrame == id && (item_flags & ImGuiItemFlags_AllowDuplicateId) == 0)
+ {
+ g.HoveredIdPreviousFrameItemCount++;
+ if (g.DebugDrawIdConflicts == id)
+ window->DrawList->AddRect(bb.Min - ImVec2(1,1), bb.Max + ImVec2(1,1), IM_COL32(255, 0, 0, 255), 0.0f, ImDrawFlags_None, 2.0f);
+ }
+#endif
+
if (g.HoveredWindow != window)
return false;
if (!IsMouseHoveringRect(bb.Min, bb.Max))
@@ -4264,7 +4653,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// Done with rectangle culling so we can perform heavier checks now.
if (!(item_flags & ImGuiItemFlags_NoWindowHoverableCheck) && !IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
{
- g.HoveredIdDisabled = true;
+ g.HoveredIdIsDisabled = true;
return false;
}
@@ -4288,7 +4677,8 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
}
// Display shortcut (only works with mouse)
- if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut))
+ // (ImGuiItemStatusFlags_HasShortcut in LastItemData denotes we want a tooltip)
+ if (id == g.LastItemData.ID && (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasShortcut) && g.ActiveId != id)
if (IsItemHovered(ImGuiHoveredFlags_ForTooltip | ImGuiHoveredFlags_DelayNormal))
SetTooltip("%s", GetKeyChordName(g.LastItemData.Shortcut));
}
@@ -4299,7 +4689,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// Release active id if turning disabled
if (g.ActiveId == id && id != 0)
ClearActiveID();
- g.HoveredIdDisabled = true;
+ g.HoveredIdIsDisabled = true;
return false;
}
@@ -4331,7 +4721,7 @@ bool ImGui::IsClippedEx(const ImRect& bb, ImGuiID id)
ImGuiWindow* window = g.CurrentWindow;
if (!bb.Overlaps(window->ClipRect))
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
- if (!g.LogEnabled)
+ if (!g.ItemUnclipByLog)
return true;
return false;
}
@@ -4422,14 +4812,14 @@ void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr
const char* ImGui::GetClipboardText()
{
ImGuiContext& g = *GImGui;
- return g.IO.GetClipboardTextFn ? g.IO.GetClipboardTextFn(g.IO.ClipboardUserData) : "";
+ return g.PlatformIO.Platform_GetClipboardTextFn ? g.PlatformIO.Platform_GetClipboardTextFn(&g) : "";
}
void ImGui::SetClipboardText(const char* text)
{
ImGuiContext& g = *GImGui;
- if (g.IO.SetClipboardTextFn)
- g.IO.SetClipboardTextFn(g.IO.ClipboardUserData, text);
+ if (g.PlatformIO.Platform_SetClipboardTextFn != NULL)
+ g.PlatformIO.Platform_SetClipboardTextFn(&g, text);
}
const char* ImGui::GetVersion()
@@ -4445,7 +4835,7 @@ ImGuiIO& ImGui::GetIO()
ImGuiPlatformIO& ImGui::GetPlatformIO()
{
- IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() or ImGui::SetCurrentContext()?");
+ IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext()?");
return GImGui->PlatformIO;
}
@@ -4493,26 +4883,18 @@ static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t draw
ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
{
+ if (viewport == NULL)
+ viewport = GImGui->CurrentWindow->Viewport;
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
}
-ImDrawList* ImGui::GetBackgroundDrawList()
-{
- ImGuiContext& g = *GImGui;
- return GetBackgroundDrawList(g.CurrentWindow->Viewport);
-}
-
ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
{
+ if (viewport == NULL)
+ viewport = GImGui->CurrentWindow->Viewport;
return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
}
-ImDrawList* ImGui::GetForegroundDrawList()
-{
- ImGuiContext& g = *GImGui;
- return GetForegroundDrawList(g.CurrentWindow->Viewport);
-}
-
ImDrawListSharedData* ImGui::GetDrawListSharedData()
{
return &GImGui->DrawListSharedData;
@@ -4662,7 +5044,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
g.MovingWindow = NULL;
// Cancel moving if clicked over an item which was disabled or inhibited by popups (note that we know HoveredId == 0 already)
- if (g.HoveredIdDisabled)
+ if (g.HoveredIdIsDisabled)
g.MovingWindow = NULL;
}
else if (root_window == NULL && g.NavWindow != NULL)
@@ -4730,13 +5112,14 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
bool clear_hovered_windows = false;
FindHoveredWindowEx(g.IO.MousePos, false, &g.HoveredWindow, &g.HoveredWindowUnderMovingWindow);
IM_ASSERT(g.HoveredWindow == NULL || g.HoveredWindow == g.MovingWindow || g.HoveredWindow->Viewport == g.MouseViewport);
+ g.HoveredWindowBeforeClear = g.HoveredWindow;
// Modal windows prevents mouse from hovering behind them.
ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window && g.HoveredWindow && !IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, modal_window)) // FIXME-MERGE: RootWindowDockTree ?
clear_hovered_windows = true;
- // Disabled mouse?
+ // Disabled mouse hovering (we don't currently clear MousePos, we could)
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
clear_hovered_windows = true;
@@ -4754,7 +5137,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
io.MouseDownOwnedUnlessPopupClose[i] = (g.HoveredWindow != NULL) || has_open_modal;
}
mouse_any_down |= io.MouseDown[i];
- if (io.MouseDown[i])
+ if (io.MouseDown[i] || io.MouseReleased[i]) // Increase release frame for our evaluation of earliest button (#1392)
if (mouse_earliest_down == -1 || io.MouseClickedTime[i] < io.MouseClickedTime[mouse_earliest_down])
mouse_earliest_down = i;
}
@@ -4874,6 +5257,12 @@ void ImGui::NewFrame()
if (g.DragDropActive && g.DragDropPayload.SourceId == g.ActiveId)
KeepAliveID(g.DragDropPayload.SourceId);
+ // [DEBUG]
+ if (!g.IO.ConfigDebugHighlightIdConflicts || !g.IO.KeyCtrl) // Count is locked while holding CTRL
+ g.DebugDrawIdConflicts = 0;
+ if (g.IO.ConfigDebugHighlightIdConflicts && g.HoveredIdPreviousFrameItemCount > 1)
+ g.DebugDrawIdConflicts = g.HoveredIdPreviousFrame;
+
// Update HoveredId data
if (!g.HoveredIdPreviousFrame)
g.HoveredIdTimer = 0.0f;
@@ -4884,9 +5273,10 @@ void ImGui::NewFrame()
if (g.HoveredId && g.ActiveId != g.HoveredId)
g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
g.HoveredIdPreviousFrame = g.HoveredId;
+ g.HoveredIdPreviousFrameItemCount = 0;
g.HoveredId = 0;
g.HoveredIdAllowOverlap = false;
- g.HoveredIdDisabled = false;
+ g.HoveredIdIsDisabled = false;
// Clear ActiveID if the item is not alive anymore.
// In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
@@ -4914,24 +5304,7 @@ void ImGui::NewFrame()
{
g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingAllKeyboardKeys = false;
-#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
- g.ActiveIdUsingNavInputMask = 0x00;
-#endif
- }
-
-#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
- if (g.ActiveId == 0)
- g.ActiveIdUsingNavInputMask = 0;
- else if (g.ActiveIdUsingNavInputMask != 0)
- {
- // If your custom widget code used: { g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel); }
- // Since IMGUI_VERSION_NUM >= 18804 it should be: { SetKeyOwner(ImGuiKey_Escape, g.ActiveId); SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId); }
- if (g.ActiveIdUsingNavInputMask & (1 << ImGuiNavInput_Cancel))
- SetKeyOwner(ImGuiKey_Escape, g.ActiveId);
- if (g.ActiveIdUsingNavInputMask & ~(1 << ImGuiNavInput_Cancel))
- IM_ASSERT(0); // Other values unsupported
}
-#endif
// Record when we have been stationary as this state is preserved while over same item.
// FIXME: The way this is expressed means user cannot alter HoverStationaryDelay during the frame to use varying values.
@@ -4969,6 +5342,7 @@ void ImGui::NewFrame()
g.DragDropWithinSource = false;
g.DragDropWithinTarget = false;
g.DragDropHoldJustPressedId = 0;
+ g.TooltipPreviousWindow = NULL;
// Close popups on focus lost (currently wip/opt-in)
//if (g.IO.AppFocusLost)
@@ -4992,8 +5366,25 @@ void ImGui::NewFrame()
// (needs to be before UpdateMouseMovingWindowNewFrame so the window is already offset and following the mouse on the detaching frame)
DockContextNewFrameUpdateUndocking(&g);
+ // Mark all windows as not visible and compact unused memory.
+ IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
+ const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
+ for (ImGuiWindow* window : g.Windows)
+ {
+ window->WasActive = window->Active;
+ window->Active = false;
+ window->WriteAccessed = false;
+ window->BeginCountPreviousFrame = window->BeginCount;
+ window->BeginCount = 0;
+
+ // Garbage collect transient buffers of recently unused windows
+ if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
+ GcCompactTransientWindowBuffers(window);
+ }
+
// Find hovered window
// (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
+ // (currently needs to be done after the WasActive=Active loop and FindHoveredWindowEx uses ->Active)
UpdateHoveredWindowAndCaptureFlags();
// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
@@ -5015,22 +5406,6 @@ void ImGui::NewFrame()
// Mouse wheel scrolling, scale
UpdateMouseWheel();
- // Mark all windows as not visible and compact unused memory.
- IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
- const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
- for (ImGuiWindow* window : g.Windows)
- {
- window->WasActive = window->Active;
- window->Active = false;
- window->WriteAccessed = false;
- window->BeginCountPreviousFrame = window->BeginCount;
- window->BeginCount = 0;
-
- // Garbage collect transient buffers of recently unused windows
- if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
- GcCompactTransientWindowBuffers(window);
- }
-
// Garbage collect transient buffers of recently unused tables
for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
@@ -5051,7 +5426,8 @@ void ImGui::NewFrame()
g.CurrentWindowStack.resize(0);
g.BeginPopupStack.resize(0);
g.ItemFlagsStack.resize(0);
- g.ItemFlagsStack.push_back(ImGuiItemFlags_None);
+ g.ItemFlagsStack.push_back(ImGuiItemFlags_AutoClosePopups); // Default flags
+ g.CurrentItemFlags = g.ItemFlagsStack.back();
g.GroupStack.resize(0);
// Docking
@@ -5083,6 +5459,10 @@ void ImGui::NewFrame()
Begin("Debug##Default");
IM_ASSERT(g.CurrentWindow->IsFallbackWindow == true);
+ // Store stack sizes
+ g.ErrorCountCurrentFrame = 0;
+ ErrorRecoveryStoreState(&g.StackSizesInNewFrame);
+
// [DEBUG] When io.ConfigDebugBeginReturnValue is set, we make Begin()/BeginChild() return false at different level of the window-stack,
// allowing to validate correct Begin/End behavior in user code.
#ifndef IMGUI_DISABLE_DEBUG_TOOLS
@@ -5199,6 +5579,8 @@ static void InitViewportDrawData(ImGuiViewportP* viewport)
// - If the code here changes, may need to update code of functions like NextColumn() and PushColumnClipRect():
// some frequently called functions which to modify both channels and clipping simultaneously tend to use the
// more specialized SetWindowClipRectBeforeSetChannel() to avoid extraneous updates of underlying ImDrawCmds.
+// - This is analoguous to PushFont()/PopFont() in the sense that are a mixing a global stack and a window stack,
+// which in the case of ClipRect is not so problematic but tends to be more restrictive for fonts.
void ImGui::PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect)
{
ImGuiWindow* window = GetCurrentWindow();
@@ -5349,17 +5731,21 @@ void ImGui::EndFrame()
CallContextHooks(&g, ImGuiContextHookType_EndFramePre);
+ // [EXPERIMENTAL] Recover from errors
+ if (g.IO.ConfigErrorRecovery)
+ ErrorRecoveryTryToRecoverState(&g.StackSizesInNewFrame);
ErrorCheckEndFrameSanityChecks();
+ ErrorCheckEndFrameFinalizeErrorTooltip();
// Notify Platform/OS when our Input Method Editor cursor has moved (e.g. CJK inputs using Microsoft IME)
ImGuiPlatformImeData* ime_data = &g.PlatformImeData;
- if (g.IO.SetPlatformImeDataFn && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
+ if (g.PlatformIO.Platform_SetImeDataFn != NULL && memcmp(ime_data, &g.PlatformImeDataPrev, sizeof(ImGuiPlatformImeData)) != 0)
{
ImGuiViewport* viewport = FindViewportByID(g.PlatformImeViewport);
- IMGUI_DEBUG_LOG_IO("[io] Calling io.SetPlatformImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
+ IMGUI_DEBUG_LOG_IO("[io] Calling Platform_SetImeDataFn(): WantVisible: %d, InputPos (%.2f,%.2f)\n", ime_data->WantVisible, ime_data->InputPos.x, ime_data->InputPos.y);
if (viewport == NULL)
viewport = GetMainViewport();
- g.IO.SetPlatformImeDataFn(viewport, ime_data);
+ g.PlatformIO.Platform_SetImeDataFn(&g, viewport, ime_data);
}
// Hide implicit/fallback "Debug" window if it hasn't been used
@@ -5380,13 +5766,17 @@ void ImGui::EndFrame()
if (g.DragDropActive)
{
bool is_delivered = g.DragDropPayload.Delivery;
- bool is_elapsed = (g.DragDropPayload.DataFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceAutoExpirePayload) || !IsMouseDown(g.DragDropMouseButton));
+ bool is_elapsed = (g.DragDropSourceFrameCount + 1 < g.FrameCount) && ((g.DragDropSourceFlags & ImGuiDragDropFlags_PayloadAutoExpire) || g.DragDropMouseButton == -1 || !IsMouseDown(g.DragDropMouseButton));
if (is_delivered || is_elapsed)
ClearDragDrop();
}
- // Drag and Drop: Fallback for source tooltip. This is not ideal but better than nothing.
- if (g.DragDropActive && g.DragDropSourceFrameCount < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
+ // Drag and Drop: Fallback for missing source tooltip. This is not ideal but better than nothing.
+ // If you want to handle source item disappearing: instead of submitting your description tooltip
+ // in the BeginDragDropSource() block of the dragged item, you can submit them from a safe single spot
+ // (e.g. end of your item loop, or before EndFrame) by reading payload data.
+ // In the typical case, the contents of drag tooltip should be possible to infer solely from payload data.
+ if (g.DragDropActive && g.DragDropSourceFrameCount + 1 < g.FrameCount && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
{
g.DragDropWithinSource = true;
SetTooltip("...");
@@ -5556,7 +5946,7 @@ void ImGui::FindHoveredWindowEx(const ImVec2& pos, bool find_first_and_in_any_vi
{
ImGuiWindow* window = g.Windows[i];
IM_MSVC_WARNING_SUPPRESS(28182); // [Static Analyzer] Dereferencing NULL pointer.
- if (!window->Active || window->Hidden)
+ if (!window->WasActive || window->Hidden)
continue;
if (window->Flags & ImGuiWindowFlags_NoMouseInputs)
continue;
@@ -5663,9 +6053,15 @@ bool ImGui::IsItemToggledOpen()
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
}
+// Call after a Selectable() or TreeNode() involved in multi-selection.
+// Useful if you need the per-item information before reaching EndMultiSelect(), e.g. for rendering purpose.
+// This is only meant to be called inside a BeginMultiSelect()/EndMultiSelect() block.
+// (Outside of multi-select, it would be misleading/ambiguous to report this signal, as widgets
+// return e.g. a pressed event and user code is in charge of altering selection in ways we cannot predict.)
bool ImGui::IsItemToggledSelection()
{
ImGuiContext& g = *GImGui;
+ IM_ASSERT(g.CurrentMultiSelect != NULL); // Can only be used inside a BeginMultiSelect()/EndMultiSelect()
return (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_ToggledSelection) ? true : false;
}
@@ -5725,7 +6121,8 @@ void ImGui::SetItemAllowOverlap()
}
#endif
-// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version for the two users of this function.
+// This is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations.
+// FIXME: It might be undesirable that this will likely disable KeyOwner-aware shortcuts systems. Consider a more fine-tuned version if needed?
void ImGui::SetActiveIdUsingAllKeyboardKeys()
{
ImGuiContext& g = *GImGui;
@@ -5760,7 +6157,7 @@ ImVec2 ImGui::GetItemRectSize()
}
// Prior to v1.90 2023/10/16, the BeginChild() function took a 'bool border = false' parameter instead of 'ImGuiChildFlags child_flags = 0'.
-// ImGuiChildFlags_Border is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details!
+// ImGuiChildFlags_Borders is defined as always == 1 in order to allow old code passing 'true'. Read comments in imgui.h for details!
bool ImGui::BeginChild(const char* str_id, const ImVec2& size_arg, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags)
{
ImGuiID id = GetCurrentWindow()->GetID(str_id);
@@ -5779,7 +6176,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
IM_ASSERT(id != 0);
// Sanity check as it is likely that some user will accidentally pass ImGuiWindowFlags into the ImGuiChildFlags argument.
- const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle;
+ const ImGuiChildFlags ImGuiChildFlags_SupportedMask_ = ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY | ImGuiChildFlags_AutoResizeX | ImGuiChildFlags_AutoResizeY | ImGuiChildFlags_AlwaysAutoResize | ImGuiChildFlags_FrameStyle | ImGuiChildFlags_NavFlattened;
IM_UNUSED(ImGuiChildFlags_SupportedMask_);
IM_ASSERT((child_flags & ~ImGuiChildFlags_SupportedMask_) == 0 && "Illegal ImGuiChildFlags value. Did you pass ImGuiWindowFlags values instead of ImGuiChildFlags?");
IM_ASSERT((window_flags & ImGuiWindowFlags_AlwaysAutoResize) == 0 && "Cannot specify ImGuiWindowFlags_AlwaysAutoResize for BeginChild(). Use ImGuiChildFlags_AlwaysAutoResize!");
@@ -5791,6 +6188,8 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (window_flags & ImGuiWindowFlags_AlwaysUseWindowPadding)
child_flags |= ImGuiChildFlags_AlwaysUseWindowPadding;
+ if (window_flags & ImGuiWindowFlags_NavFlattened)
+ child_flags |= ImGuiChildFlags_NavFlattened;
#endif
if (child_flags & ImGuiChildFlags_AutoResizeX)
child_flags &= ~ImGuiChildFlags_ResizeX;
@@ -5812,22 +6211,39 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
PushStyleVar(ImGuiStyleVar_ChildRounding, g.Style.FrameRounding);
PushStyleVar(ImGuiStyleVar_ChildBorderSize, g.Style.FrameBorderSize);
PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.FramePadding);
- child_flags |= ImGuiChildFlags_Border | ImGuiChildFlags_AlwaysUseWindowPadding;
+ child_flags |= ImGuiChildFlags_Borders | ImGuiChildFlags_AlwaysUseWindowPadding;
window_flags |= ImGuiWindowFlags_NoMove;
}
- // Forward child flags
- g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags;
- g.NextWindowData.ChildFlags = child_flags;
-
// Forward size
// Important: Begin() has special processing to switch condition to ImGuiCond_FirstUseEver for a given axis when ImGuiChildFlags_ResizeXXX is set.
// (the alternative would to store conditional flags per axis, which is possible but more code)
const ImVec2 size_avail = GetContentRegionAvail();
const ImVec2 size_default((child_flags & ImGuiChildFlags_AutoResizeX) ? 0.0f : size_avail.x, (child_flags & ImGuiChildFlags_AutoResizeY) ? 0.0f : size_avail.y);
- const ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y);
+ ImVec2 size = CalcItemSize(size_arg, size_default.x, size_default.y);
+
+ // A SetNextWindowSize() call always has priority (#8020)
+ // (since the code in Begin() never supported SizeVal==0.0f aka auto-resize via SetNextWindowSize() call, we don't support it here for now)
+ // FIXME: We only support ImGuiCond_Always in this path. Supporting other paths would requires to obtain window pointer.
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) != 0 && (g.NextWindowData.SizeCond & ImGuiCond_Always) != 0)
+ {
+ if (g.NextWindowData.SizeVal.x > 0.0f)
+ {
+ size.x = g.NextWindowData.SizeVal.x;
+ child_flags &= ~ImGuiChildFlags_ResizeX;
+ }
+ if (g.NextWindowData.SizeVal.y > 0.0f)
+ {
+ size.y = g.NextWindowData.SizeVal.y;
+ child_flags &= ~ImGuiChildFlags_ResizeY;
+ }
+ }
SetNextWindowSize(size);
+ // Forward child flags
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasChildFlags;
+ g.NextWindowData.ChildFlags = child_flags;
+
// Build up name. If you need to append to a same child from multiple location in the ID stack, use BeginChild(ImGuiID id) with a stable value.
// FIXME: 2023/11/14: commented out shorted version. We had an issue with multiple ### in child window path names, which the trailing hash helped workaround.
// e.g. "ParentName###ParentIdentifier/ChildName###ChildIdentifier" would get hashed incorrectly by ImHashStr(), trailing _%08X somehow fixes it.
@@ -5842,7 +6258,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
// Set style
const float backup_border_size = g.Style.ChildBorderSize;
- if ((child_flags & ImGuiChildFlags_Border) == 0)
+ if ((child_flags & ImGuiChildFlags_Borders) == 0)
g.Style.ChildBorderSize = 0.0f;
// Begin into window
@@ -5869,7 +6285,7 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, I
const ImGuiID temp_id_for_activation = ImHashStr("##Child", 0, id);
if (g.ActiveId == temp_id_for_activation)
ClearActiveID();
- if (g.NavActivateId == id && !(window_flags & ImGuiWindowFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))
+ if (g.NavActivateId == id && !(child_flags & ImGuiChildFlags_NavFlattened) && (child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY))
{
FocusWindow(child_window);
NavInitWindow(child_window, false);
@@ -5895,7 +6311,8 @@ void ImGui::EndChild()
ImGuiWindow* parent_window = g.CurrentWindow;
ImRect bb(parent_window->DC.CursorPos, parent_window->DC.CursorPos + child_size);
ItemSize(child_size);
- if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !(child_window->Flags & ImGuiWindowFlags_NavFlattened))
+ const bool nav_flattened = (child_window->ChildFlags & ImGuiChildFlags_NavFlattened) != 0;
+ if ((child_window->DC.NavLayersActiveMask != 0 || child_window->DC.NavWindowHasScrollY) && !nav_flattened)
{
ItemAdd(bb, child_window->ChildId);
RenderNavHighlight(bb, child_window->ChildId);
@@ -5912,7 +6329,7 @@ void ImGui::EndChild()
ItemAdd(bb, child_window->ChildId, NULL, ImGuiItemFlags_NoNav);
// But when flattened we directly reach items, adjust active layer mask accordingly
- if (child_window->Flags & ImGuiWindowFlags_NavFlattened)
+ if (nav_flattened)
parent_window->DC.NavLayersActiveMaskNext |= child_window->DC.NavLayersActiveMaskNext;
}
if (g.HoveredWindow == child_window)
@@ -6068,7 +6485,7 @@ static inline ImVec2 CalcWindowMinSize(ImGuiWindow* window)
// Reduce artifacts with very small windows
ImGuiWindow* window_for_height = GetWindowForTitleAndMenuHeight(window);
- size_min.y = ImMax(size_min.y, window_for_height->TitleBarHeight() + window_for_height->MenuBarHeight() + ImMax(0.0f, g.Style.WindowRounding - 1.0f));
+ size_min.y = ImMax(size_min.y, window_for_height->TitleBarHeight + window_for_height->MenuBarHeight + ImMax(0.0f, g.Style.WindowRounding - 1.0f));
return size_min;
}
@@ -6138,10 +6555,18 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
{
// Maximum window size is determined by the viewport size or monitor size
ImVec2 size_min = CalcWindowMinSize(window);
- ImVec2 size_max = (window->ViewportOwned || ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_Popup))) ? ImVec2(FLT_MAX, FLT_MAX) : ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f;
- const int monitor_idx = window->ViewportAllowPlatformMonitorExtend;
- if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0)
- size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f;
+ ImVec2 size_max = ImVec2(FLT_MAX, FLT_MAX);
+
+ // Child windows are layed within their parent (unless they are also popups/menus) and thus have no restriction
+ if ((window->Flags & ImGuiWindowFlags_ChildWindow) == 0 || (window->Flags & ImGuiWindowFlags_Popup) != 0)
+ {
+ if (!window->ViewportOwned)
+ size_max = ImGui::GetMainViewport()->WorkSize - style.DisplaySafeAreaPadding * 2.0f;
+ const int monitor_idx = window->ViewportAllowPlatformMonitorExtend;
+ if (monitor_idx >= 0 && monitor_idx < g.PlatformIO.Monitors.Size)
+ size_max = g.PlatformIO.Monitors[monitor_idx].WorkSize - style.DisplaySafeAreaPadding * 2.0f;
+ }
+
ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, size_max));
// FIXME: CalcWindowAutoFitSize() doesn't take into account that only one axis may be auto-fit when calculating scrollbars,
@@ -6282,7 +6707,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
ImRect clamp_rect = visibility_rect;
const bool window_move_from_title_bar = g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar);
if (window_move_from_title_bar)
- clamp_rect.Min.y -= window->TitleBarHeight();
+ clamp_rect.Min.y -= window->TitleBarHeight;
ImVec2 pos_target(FLT_MAX, FLT_MAX);
ImVec2 size_target(FLT_MAX, FLT_MAX);
@@ -6317,7 +6742,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
ButtonBehavior(resize_rect, resize_grip_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
//GetForegroundDrawList(window)->AddRect(resize_rect.Min, resize_rect.Max, IM_COL32(255, 255, 0, 255));
if (hovered || held)
- g.MouseCursor = (resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE;
+ SetMouseCursor((resize_grip_n & 1) ? ImGuiMouseCursor_ResizeNESW : ImGuiMouseCursor_ResizeNWSE);
if (held && g.IO.MouseDoubleClicked[0])
{
@@ -6363,7 +6788,7 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
if (hovered && g.HoveredIdTimer <= WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER)
hovered = false;
if (hovered || held)
- g.MouseCursor = (axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS;
+ SetMouseCursor((axis == ImGuiAxis_X) ? ImGuiMouseCursor_ResizeEW : ImGuiMouseCursor_ResizeNS);
if (held && g.IO.MouseDoubleClicked[0])
{
// Double-clicking bottom or right border auto-fit on this axis
@@ -6415,12 +6840,13 @@ static int ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& si
border_target = ImClamp(border_target, clamp_min, clamp_max);
if (flags & ImGuiWindowFlags_ChildWindow) // Clamp resizing of childs within parent
{
- ImGuiWindowFlags parent_flags = window->ParentWindow->Flags;
- ImRect border_limit_rect = window->ParentWindow->InnerRect;
- border_limit_rect.Expand(ImVec2(-ImMax(window->WindowPadding.x, window->WindowBorderSize), -ImMax(window->WindowPadding.y, window->WindowBorderSize)));
- if ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar))
+ ImGuiWindow* parent_window = window->ParentWindow;
+ ImGuiWindowFlags parent_flags = parent_window->Flags;
+ ImRect border_limit_rect = parent_window->InnerRect;
+ border_limit_rect.Expand(ImVec2(-ImMax(parent_window->WindowPadding.x, parent_window->WindowBorderSize), -ImMax(parent_window->WindowPadding.y, parent_window->WindowBorderSize)));
+ if ((axis == ImGuiAxis_X) && ((parent_flags & (ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar)) == 0 || (parent_flags & ImGuiWindowFlags_NoScrollbar)))
border_target.x = ImClamp(border_target.x, border_limit_rect.Min.x, border_limit_rect.Max.x);
- if (parent_flags & ImGuiWindowFlags_NoScrollbar)
+ if ((axis == ImGuiAxis_Y) && (parent_flags & ImGuiWindowFlags_NoScrollbar))
border_target.y = ImClamp(border_target.y, border_limit_rect.Min.y, border_limit_rect.Max.y);
}
if (!ignore_resize)
@@ -6490,8 +6916,10 @@ static inline void ClampWindowPos(ImGuiWindow* window, const ImRect& visibility_
{
ImGuiContext& g = *GImGui;
ImVec2 size_for_clamping = window->Size;
- if (g.IO.ConfigWindowsMoveFromTitleBarOnly && (!(window->Flags & ImGuiWindowFlags_NoTitleBar) || window->DockNodeAsHost))
+ if (g.IO.ConfigWindowsMoveFromTitleBarOnly && window->DockNodeAsHost)
size_for_clamping.y = ImGui::GetFrameHeight(); // Not using window->TitleBarHeight() as DockNodeAsHost will report 0.0f here.
+ else if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
+ size_for_clamping.y = window->TitleBarHeight;
window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
}
@@ -6527,7 +6955,7 @@ static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
}
if (g.Style.FrameBorderSize > 0 && !(window->Flags & ImGuiWindowFlags_NoTitleBar) && !window->DockIsActive)
{
- float y = window->Pos.y + window->TitleBarHeight() - 1;
+ float y = window->Pos.y + window->TitleBarHeight - 1;
window->DrawList->AddLine(ImVec2(window->Pos.x + border_size, y), ImVec2(window->Pos.x + window->Size.x - border_size, y), border_col, g.Style.FrameBorderSize);
}
}
@@ -6601,7 +7029,7 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
ImDrawList* bg_draw_list = window->DockIsActive ? window->DockNode->HostWindow->DrawList : window->DrawList;
if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
bg_draw_list->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_BG);
- bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
+ bg_draw_list->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? 0 : ImDrawFlags_RoundCornersBottom);
if (window->DockIsActive || (flags & ImGuiWindowFlags_DockNodeHost))
bg_draw_list->ChannelsSetCurrent(DOCKING_HOST_DRAW_CHANNEL_FG);
}
@@ -6783,7 +7211,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup))) // FIXME: simply use _NoTitleBar ?
window->RootWindowForTitleBarHighlight = parent_window->RootWindowForTitleBarHighlight;
- while (window->RootWindowForNav->Flags & ImGuiWindowFlags_NavFlattened)
+ while (window->RootWindowForNav->ChildFlags & ImGuiChildFlags_NavFlattened)
{
IM_ASSERT(window->RootWindowForNav->ParentWindow != NULL);
window->RootWindowForNav = window->RootWindowForNav->ParentWindow;
@@ -6805,15 +7233,28 @@ void ImGui::UpdateWindowSkipRefresh(ImGuiWindow* window)
return;
if (window->Hidden) // If was hidden (previous frame)
return;
- if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow && window->RootWindow == g.HoveredWindow->RootWindow)
- return;
- if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow && window->RootWindow == g.NavWindow->RootWindow)
- return;
+ if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnHover) && g.HoveredWindow)
+ if (window->RootWindow == g.HoveredWindow->RootWindow || IsWindowWithinBeginStackOf(g.HoveredWindow->RootWindow, window))
+ return;
+ if ((g.NextWindowData.RefreshFlagsVal & ImGuiWindowRefreshFlags_RefreshOnFocus) && g.NavWindow)
+ if (window->RootWindow == g.NavWindow->RootWindow || IsWindowWithinBeginStackOf(g.NavWindow->RootWindow, window))
+ return;
window->DrawList = NULL;
window->SkipRefresh = true;
}
}
+static void SetWindowActiveForSkipRefresh(ImGuiWindow* window)
+{
+ window->Active = true;
+ for (ImGuiWindow* child : window->DC.ChildWindows)
+ if (!child->Hidden)
+ {
+ child->Active = child->SkipRefresh = true;
+ SetWindowActiveForSkipRefresh(child);
+ }
+}
+
// When a modal popup is open, newly created windows that want focus (i.e. are not popups and do not specify ImGuiWindowFlags_NoFocusOnAppearing)
// should be positioned behind that modal window, unless the window was created inside the modal begin-stack.
// In case of multiple stacked modals newly created window honors begin stack order and does not go below its own modal parent.
@@ -6879,9 +7320,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if ((flags & ImGuiWindowFlags_NoInputs) == ImGuiWindowFlags_NoInputs)
flags |= ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize;
- if (flags & ImGuiWindowFlags_NavFlattened)
- IM_ASSERT(flags & ImGuiWindowFlags_ChildWindow);
-
const int current_frame = g.FrameCount;
const bool first_begin_of_the_frame = (window->LastFrameActive != current_frame);
window->IsFallbackWindow = (g.CurrentWindowStack.Size == 0 && g.WithinFrameScopeWithImplicitWindow);
@@ -6961,11 +7399,13 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Add to stack
g.CurrentWindow = window;
- ImGuiWindowStackData window_stack_data;
+ g.CurrentWindowStack.resize(g.CurrentWindowStack.Size + 1);
+ ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
window_stack_data.Window = window;
window_stack_data.ParentLastItemDataBackup = g.LastItemData;
- window_stack_data.StackSizesOnBegin.SetToContextState(&g);
- g.CurrentWindowStack.push_back(window_stack_data);
+ window_stack_data.DisabledOverrideReenable = (flags & ImGuiWindowFlags_Tooltip) && (g.CurrentItemFlags & ImGuiItemFlags_Disabled);
+ ErrorRecoveryStoreState(&window_stack_data.StackSizesInBegin);
+ g.StackSizesInBeginForCurrentWindow = &window_stack_data.StackSizesInBegin;
if (flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuDepth++;
@@ -6992,7 +7432,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Add to focus scope stack
- PushFocusScope((flags & ImGuiWindowFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
+ PushFocusScope((window->ChildFlags & ImGuiChildFlags_NavFlattened) ? g.CurrentFocusScopeId : window->ID);
window->NavRootFocusScopeId = g.CurrentFocusScopeId;
// Add to popup stacks: update OpenPopupStack[] data, push to BeginPopupStack[]
@@ -7064,6 +7504,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// [EXPERIMENTAL] Skip Refresh mode
UpdateWindowSkipRefresh(window);
+ // Nested root windows (typically tooltips) override disabled state
+ if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
+ BeginDisabledOverrideReenable();
+
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
g.CurrentWindow = NULL;
@@ -7160,6 +7604,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Lock menu offset so size calculation can use it as menu-bar windows need a minimum size.
window->DC.MenuBarOffset.x = ImMax(ImMax(window->WindowPadding.x, style.ItemSpacing.x), g.NextWindowData.MenuBarOffsetMinVal.x);
window->DC.MenuBarOffset.y = g.NextWindowData.MenuBarOffsetMinVal.y;
+ window->TitleBarHeight = (flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : g.FontSize + g.Style.FramePadding.y * 2.0f;
+ window->MenuBarHeight = (flags & ImGuiWindowFlags_MenuBar) ? window->DC.MenuBarOffset.y + g.FontSize + g.Style.FramePadding.y * 2.0f : 0.0f;
// Depending on condition we use previous or current window size to compare against contents size to decide if a scrollbar should be visible.
// Those flags will be altered further down in the function depending on more conditions.
@@ -7174,9 +7620,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// At this point we don't have a clipping rectangle setup yet, so we can use the title bar area for hit detection and drawing
if (!(flags & ImGuiWindowFlags_NoTitleBar) && !(flags & ImGuiWindowFlags_NoCollapse) && !window->DockIsActive)
{
- // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed), so verify that we don't have items over the title bar.
+ // We don't use a regular button+id to test for double-click on title bar (mostly due to legacy reason, could be fixed),
+ // so verify that we don't have items over the title bar.
ImRect title_bar_rect = window->TitleBarRect();
- if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max))
+ if (g.HoveredWindow == window && g.HoveredId == 0 && g.HoveredIdPreviousFrame == 0 && g.ActiveId == 0 && IsMouseHoveringRect(title_bar_rect.Min, title_bar_rect.Max))
if (g.IO.MouseClickedCount[0] == 2 && GetKeyOwner(ImGuiKey_MouseLeft) == ImGuiKeyOwner_NoOwner)
window->WantCollapseToggle = true;
if (window->WantCollapseToggle)
@@ -7200,7 +7647,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const ImVec2 scrollbar_sizes_from_last_frame = window->ScrollbarSizes;
window->DecoOuterSizeX1 = 0.0f;
window->DecoOuterSizeX2 = 0.0f;
- window->DecoOuterSizeY1 = window->TitleBarHeight() + window->MenuBarHeight();
+ window->DecoOuterSizeY1 = window->TitleBarHeight + window->MenuBarHeight;
window->DecoOuterSizeY2 = 0.0f;
window->ScrollbarSizes = ImVec2(0.0f, 0.0f);
@@ -7409,7 +7856,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
if (window->ScrollbarX && !window->ScrollbarY)
- window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
+ window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
// Amend the partially filled window->DecorationXXX values.
@@ -7431,7 +7878,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const ImRect title_bar_rect = window->TitleBarRect();
window->OuterRectClipped = outer_rect;
if (window->DockIsActive)
- window->OuterRectClipped.Min.y += window->TitleBarHeight();
+ window->OuterRectClipped.Min.y += window->TitleBarHeight;
window->OuterRectClipped.ClipWith(host_rect);
// Inner rectangle
@@ -7455,10 +7902,14 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Affected by window/frame border size. Used by:
// - Begin() initial clip rect
float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
- window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize);
- window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
- window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - window->WindowBorderSize);
- window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
+
+ // Try to match the fact that our border is drawn centered over the window rectangle, rather than inner.
+ // This is why we do a *0.5f here. We don't currently even technically support large values for WindowBorderSize,
+ // see e.g #7887 #7888, but may do after we move the window border to become an inner border (and then we can remove the 0.5f here).
+ window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + window->WindowBorderSize * 0.5f);
+ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size * 0.5f);
+ window->InnerClipRect.Max.x = ImFloor(window->InnerRect.Max.x - window->WindowBorderSize * 0.5f);
+ window->InnerClipRect.Max.y = ImFloor(window->InnerRect.Max.y - window->WindowBorderSize * 0.5f);
window->InnerClipRect.ClipWithFull(host_rect);
// Default item width. Make it proportional to window size if window manually resizes
@@ -7573,7 +8024,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.MenuBarAppending = false;
window->DC.MenuColumns.Update(style.ItemSpacing.x, window_just_activated_by_user);
window->DC.TreeDepth = 0;
- window->DC.TreeJumpToParentOnPopMask = 0x00;
+ window->DC.TreeHasStackDataDepthMask = 0x00;
window->DC.ChildWindows.resize(0);
window->DC.StateStorage = &window->StateStorage;
window->DC.CurrentColumns = NULL;
@@ -7619,6 +8070,9 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Clear hit test shape every frame
window->HitTestHoleSize.x = window->HitTestHoleSize.y = 0;
+ if (flags & ImGuiWindowFlags_Tooltip)
+ g.TooltipPreviousWindow = window;
+
// Pressing CTRL+C while holding on a window copy its content to the clipboard
// This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
// Maybe we can support CTRL+C on every element?
@@ -7663,7 +8117,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
// Skip refresh always mark active
if (window->SkipRefresh)
- window->Active = true;
+ SetWindowActiveForSkipRefresh(window);
// Append
SetCurrentViewport(window, window->Viewport);
@@ -7698,8 +8152,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
// Child window can be out of sight and have "negative" clip windows.
// Mark them as collapsed so commands are skipped earlier (we can't manually collapse them because they have no title bar).
- IM_ASSERT((flags& ImGuiWindowFlags_NoTitleBar) != 0 || window->DockIsActive);
- const bool nav_request = (flags & ImGuiWindowFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
+ IM_ASSERT((flags & ImGuiWindowFlags_NoTitleBar) != 0 || window->DockIsActive);
+ const bool nav_request = (window->ChildFlags & ImGuiChildFlags_NavFlattened) && (g.NavAnyRequest && g.NavWindow && g.NavWindow->RootWindowForNav == window->RootWindowForNav);
if (!g.LogEnabled && !nav_request)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
{
@@ -7789,7 +8243,7 @@ void ImGui::End()
IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size > 1, "Calling End() too many times!");
return;
}
- IM_ASSERT(g.CurrentWindowStack.Size > 0);
+ ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
// Error checking: verify that user doesn't directly call End() on a child window.
if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive)
@@ -7801,6 +8255,8 @@ void ImGui::End()
if (!(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->SkipRefresh) // Pop inner window clip rectangle
PopClipRect();
PopFocusScope();
+ if (window_stack_data.DisabledOverrideReenable && window->RootWindow == window)
+ EndDisabledOverrideReenable();
if (window->SkipRefresh)
{
@@ -7821,12 +8277,16 @@ void ImGui::End()
host_window->DC.CursorMaxPos = window->DC.CursorMaxPos + window->WindowPadding - host_window->WindowPadding;
// Pop from window stack
- g.LastItemData = g.CurrentWindowStack.back().ParentLastItemDataBackup;
+ g.LastItemData = window_stack_data.ParentLastItemDataBackup;
if (window->Flags & ImGuiWindowFlags_ChildMenu)
g.BeginMenuDepth--;
if (window->Flags & ImGuiWindowFlags_Popup)
g.BeginPopupStack.pop_back();
- g.CurrentWindowStack.back().StackSizesOnBegin.CompareWithContextState(&g);
+
+ // Error handling, state recovery
+ if (g.IO.ConfigErrorRecovery)
+ ErrorRecoveryTryToRecoverWindowState(&window_stack_data.StackSizesInBegin);
+
g.CurrentWindowStack.pop_back();
SetCurrentWindow(g.CurrentWindowStack.Size == 0 ? NULL : g.CurrentWindowStack.back().Window);
if (g.CurrentWindow)
@@ -7920,9 +8380,13 @@ void ImGui::FocusWindow(ImGuiWindow* window, ImGuiFocusRequestFlags flags)
if ((flags & ImGuiFocusRequestFlags_UnlessBelowModal) && (g.NavWindow != window)) // Early out in common case.
if (ImGuiWindow* blocking_modal = FindBlockingModal(window))
{
+ // This block would typically be reached in two situations:
+ // - API call to FocusWindow() with a window under a modal and ImGuiFocusRequestFlags_UnlessBelowModal flag.
+ // - User clicking on void or anything behind a modal while a modal is open (window == NULL)
IMGUI_DEBUG_LOG_FOCUS("[focus] FocusWindow(\"%s\", UnlessBelowModal): prevented by \"%s\".\n", window ? window->Name : "<NULL>", blocking_modal->Name);
if (window && window == window->RootWindow && (window->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus) == 0)
- BringWindowToDisplayBehind(window, blocking_modal); // Still bring to right below modal.
+ BringWindowToDisplayBehind(window, blocking_modal); // Still bring right under modal. (FIXME: Could move in focus list too?)
+ ClosePopupsOverWindow(GetTopMostPopupModal(), false); // Note how we need to use GetTopMostPopupModal() aad NOT blocking_modal, to handle nested modals
return;
}
@@ -8023,30 +8487,45 @@ void ImGui::SetCurrentFont(ImFont* font)
g.Font = font;
g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale);
g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f;
+ g.FontScale = g.FontSize / g.Font->FontSize;
ImFontAtlas* atlas = g.Font->ContainerAtlas;
g.DrawListSharedData.TexUvWhitePixel = atlas->TexUvWhitePixel;
g.DrawListSharedData.TexUvLines = atlas->TexUvLines;
g.DrawListSharedData.Font = g.Font;
g.DrawListSharedData.FontSize = g.FontSize;
+ g.DrawListSharedData.FontScale = g.FontScale;
}
+// Use ImDrawList::_SetTextureID(), making our shared g.FontStack[] authorative against window-local ImDrawList.
+// - Whereas ImDrawList::PushTextureID()/PopTextureID() is not to be used across Begin() calls.
+// - Note that we don't propagate current texture id when e.g. Begin()-ing into a new window, we never really did...
+// - Some code paths never really fully worked with multiple atlas textures.
+// - The right-ish solution may be to remove _SetTextureID() and make AddText/RenderText lazily call PushTextureID()/PopTextureID()
+// the same way AddImage() does, but then all other primitives would also need to? I don't think we should tackle this problem
+// because we have a concrete need and a test bed for multiple atlas textures.
void ImGui::PushFont(ImFont* font)
{
ImGuiContext& g = *GImGui;
- if (!font)
+ if (font == NULL)
font = GetDefaultFont();
- SetCurrentFont(font);
g.FontStack.push_back(font);
- g.CurrentWindow->DrawList->PushTextureID(font->ContainerAtlas->TexID);
+ SetCurrentFont(font);
+ g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID);
}
void ImGui::PopFont()
{
ImGuiContext& g = *GImGui;
- g.CurrentWindow->DrawList->PopTextureID();
+ if (g.FontStack.Size <= 0)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PopFont() too many times!");
+ return;
+ }
g.FontStack.pop_back();
- SetCurrentFont(g.FontStack.empty() ? GetDefaultFont() : g.FontStack.back());
+ ImFont* font = g.FontStack.Size == 0 ? GetDefaultFont() : g.FontStack.back();
+ SetCurrentFont(font);
+ g.CurrentWindow->DrawList->_SetTextureID(font->ContainerAtlas->TexID);
}
void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
@@ -8065,7 +8544,11 @@ void ImGui::PushItemFlag(ImGuiItemFlags option, bool enabled)
void ImGui::PopItemFlag()
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(g.ItemFlagsStack.Size > 1); // Too many calls to PopItemFlag() - we always leave a 0 at the bottom of the stack.
+ if (g.ItemFlagsStack.Size <= 1)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PopItemFlag() too many times!");
+ return;
+ }
g.ItemFlagsStack.pop_back();
g.CurrentItemFlags = g.ItemFlagsStack.back();
}
@@ -8074,8 +8557,9 @@ void ImGui::PopItemFlag()
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
// - Visually this is currently altering alpha, but it is expected that in a future styling system this would work differently.
// - Feedback welcome at https://github.com/ocornut/imgui/issues/211
-// - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
-// - Optimized shortcuts instead of PushStyleVar() + PushItemFlag()
+// - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions.
+// (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls)
+// - Note: mixing up BeginDisabled() and PushItemFlag(ImGuiItemFlags_Disabled) is currently NOT SUPPORTED.
void ImGui::BeginDisabled(bool disabled)
{
ImGuiContext& g = *GImGui;
@@ -8087,14 +8571,18 @@ void ImGui::BeginDisabled(bool disabled)
}
if (was_disabled || disabled)
g.CurrentItemFlags |= ImGuiItemFlags_Disabled;
- g.ItemFlagsStack.push_back(g.CurrentItemFlags);
+ g.ItemFlagsStack.push_back(g.CurrentItemFlags); // FIXME-OPT: can we simply skip this and use DisabledStackSize?
g.DisabledStackSize++;
}
void ImGui::EndDisabled()
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(g.DisabledStackSize > 0);
+ if (g.DisabledStackSize <= 0)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling EndDisabled() too many times!");
+ return;
+ }
g.DisabledStackSize--;
bool was_disabled = (g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
//PopItemFlag();
@@ -8104,36 +8592,46 @@ void ImGui::EndDisabled()
g.Style.Alpha = g.DisabledAlphaBackup; //PopStyleVar();
}
-void ImGui::PushTabStop(bool tab_stop)
+// Could have been called BeginDisabledDisable() but it didn't want to be award nominated for most awkward function name.
+// Ideally we would use a shared e.g. BeginDisabled()->BeginDisabledEx() but earlier needs to be optimal.
+// The whole code for this is awkward, will reevaluate if we find a way to implement SetNextItemDisabled().
+void ImGui::BeginDisabledOverrideReenable()
{
- PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop);
-}
-
-void ImGui::PopTabStop()
-{
- PopItemFlag();
-}
-
-void ImGui::PushButtonRepeat(bool repeat)
-{
- PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat);
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(g.CurrentItemFlags & ImGuiItemFlags_Disabled);
+ g.Style.Alpha = g.DisabledAlphaBackup;
+ g.CurrentItemFlags &= ~ImGuiItemFlags_Disabled;
+ g.ItemFlagsStack.push_back(g.CurrentItemFlags);
+ g.DisabledStackSize++;
}
-void ImGui::PopButtonRepeat()
+void ImGui::EndDisabledOverrideReenable()
{
- PopItemFlag();
+ ImGuiContext& g = *GImGui;
+ g.DisabledStackSize--;
+ IM_ASSERT(g.DisabledStackSize > 0);
+ g.ItemFlagsStack.pop_back();
+ g.CurrentItemFlags = g.ItemFlagsStack.back();
+ g.Style.Alpha = g.DisabledAlphaBackup * g.Style.DisabledAlpha;
}
void ImGui::PushTextWrapPos(float wrap_pos_x)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
window->DC.TextWrapPosStack.push_back(window->DC.TextWrapPos);
window->DC.TextWrapPos = wrap_pos_x;
}
void ImGui::PopTextWrapPos()
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ if (window->DC.TextWrapPosStack.Size <= 0)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PopTextWrapPos() too many times!");
+ return;
+ }
window->DC.TextWrapPos = window->DC.TextWrapPosStack.back();
window->DC.TextWrapPosStack.pop_back();
}
@@ -8604,6 +9102,7 @@ void ImGui::SetWindowFontScale(float scale)
ImGuiWindow* window = GetCurrentWindow();
window->FontWindowScale = scale;
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
+ g.FontScale = g.DrawListSharedData.FontScale = g.FontSize / g.Font->FontSize;
}
void ImGui::PushFocusScope(ImGuiID id)
@@ -8619,9 +9118,9 @@ void ImGui::PushFocusScope(ImGuiID id)
void ImGui::PopFocusScope()
{
ImGuiContext& g = *GImGui;
- if (g.FocusScopeStack.Size == 0)
+ if (g.FocusScopeStack.Size <= g.StackSizesInBeginForCurrentWindow->SizeOfFocusScopeStack)
{
- IM_ASSERT_USER_ERROR(g.FocusScopeStack.Size > 0, "Calling PopFocusScope() too many times!");
+ IM_ASSERT_USER_ERROR(0, "Calling PopFocusScope() too many times!");
return;
}
g.FocusScopeStack.pop_back();
@@ -8764,6 +9263,7 @@ bool ImGui::IsRectVisible(const ImVec2& rect_min, const ImVec2& rect_max)
// This is one of the very rare legacy case where we use ImGuiWindow methods,
// it should ideally be flattened at some point but it's been used a lots by widgets.
+IM_MSVC_RUNTIME_CHECKS_OFF
ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
@@ -8801,6 +9301,16 @@ ImGuiID ImGuiWindow::GetID(int n)
}
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
+// FIXME: Consider instead storing last non-zero ID + count of successive zero-ID, and combine those?
+ImGuiID ImGuiWindow::GetIDFromPos(const ImVec2& p_abs)
+{
+ ImGuiID seed = IDStack.back();
+ ImVec2 p_rel = ImGui::WindowPosAbsToRel(this, p_abs);
+ ImGuiID id = ImHashData(&p_rel, sizeof(p_rel), seed);
+ return id;
+}
+
+// "
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
{
ImGuiID seed = IDStack.back();
@@ -8881,7 +9391,11 @@ ImGuiID ImGui::GetIDWithSeed(int n, ImGuiID seed)
void ImGui::PopID()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- IM_ASSERT(window->IDStack.Size > 1); // Too many PopID(), or could be popping in a wrong/different window?
+ if (window->IDStack.Size <= 1)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PopID() too many times!");
+ return;
+ }
window->IDStack.pop_back();
}
@@ -8903,10 +9417,17 @@ ImGuiID ImGui::GetID(const void* ptr_id)
return window->GetID(ptr_id);
}
+ImGuiID ImGui::GetID(int int_id)
+{
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->GetID(int_id);
+}
+IM_MSVC_RUNTIME_CHECKS_RESTORE
+
//-----------------------------------------------------------------------------
// [SECTION] INPUTS
//-----------------------------------------------------------------------------
-// - GetModForModKey() [Internal]
+// - GetModForLRModKey() [Internal]
// - FixupKeyChord() [Internal]
// - GetKeyData() [Internal]
// - GetKeyIndex() [Internal]
@@ -8969,7 +9490,7 @@ ImGuiID ImGui::GetID(const void* ptr_id)
// - Shortcut() [Internal]
//-----------------------------------------------------------------------------
-static ImGuiKeyChord GetModForModKey(ImGuiKey key)
+static ImGuiKeyChord GetModForLRModKey(ImGuiKey key)
{
if (key == ImGuiKey_LeftCtrl || key == ImGuiKey_RightCtrl)
return ImGuiMod_Ctrl;
@@ -8986,8 +9507,8 @@ ImGuiKeyChord ImGui::FixupKeyChord(ImGuiKeyChord key_chord)
{
// Add ImGuiMod_XXXX when a corresponding ImGuiKey_LeftXXX/ImGuiKey_RightXXX is specified.
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
- if (IsModKey(key))
- key_chord |= GetModForModKey(key);
+ if (IsLRModKey(key))
+ key_chord |= GetModForLRModKey(key);
return key_chord;
}
@@ -9010,6 +9531,7 @@ ImGuiKeyData* ImGui::GetKeyData(ImGuiContext* ctx, ImGuiKey key)
}
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
+// Formally moved to obsolete section in 1.90.5 in spite of documented as obsolete since 1.87
ImGuiKey ImGui::GetKeyIndex(ImGuiKey key)
{
ImGuiContext& g = *GImGui;
@@ -9077,8 +9599,8 @@ const char* ImGui::GetKeyChordName(ImGuiKeyChord key_chord)
ImGuiContext& g = *GImGui;
const ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
- if (IsModKey(key))
- key_chord &= ~GetModForModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift"
+ if (IsLRModKey(key))
+ key_chord &= ~GetModForLRModKey(key); // Return "Ctrl+LeftShift" instead of "Ctrl+Shift+LeftShift"
ImFormatString(g.TempKeychordName, IM_ARRAYSIZE(g.TempKeychordName), "%s%s%s%s%s",
(key_chord & ImGuiMod_Ctrl) ? "Ctrl+" : "",
(key_chord & ImGuiMod_Shift) ? "Shift+" : "",
@@ -9229,9 +9751,9 @@ ImGuiKeyRoutingData* ImGui::GetShortcutRoutingData(ImGuiKeyChord key_chord)
}
// Current score encoding (lower is highest priority):
-// - 0: ImGuiInputFlags_RouteGlobalOverActive
+// - 0: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverActive
// - 1: ImGuiInputFlags_ActiveItem or ImGuiInputFlags_RouteFocused (if item active)
-// - 2: ImGuiInputFlags_RouteGlobalOverFocused
+// - 2: ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused
// - 3+: ImGuiInputFlags_RouteFocused (if window in focus-stack)
// - 254: ImGuiInputFlags_RouteGlobal
// - 255: never route
@@ -9258,27 +9780,29 @@ static int CalcRoutingScore(ImGuiID focus_scope_id, ImGuiID owner_id, ImGuiInput
for (int index_in_focus_path = 0; index_in_focus_path < g.NavFocusRoute.Size; index_in_focus_path++)
if (g.NavFocusRoute.Data[index_in_focus_path].ID == focus_scope_id)
return 3 + index_in_focus_path;
-
return 255;
}
- if (flags & ImGuiInputFlags_RouteActive)
+ else if (flags & ImGuiInputFlags_RouteActive)
{
if (owner_id != 0 && g.ActiveId == owner_id)
return 1;
return 255;
}
- if (flags & ImGuiInputFlags_RouteOverFocused)
- return 2;
- if (flags & ImGuiInputFlags_RouteGlobal)
+ else if (flags & ImGuiInputFlags_RouteGlobal)
+ {
+ if (flags & ImGuiInputFlags_RouteOverActive)
+ return 0;
+ if (flags & ImGuiInputFlags_RouteOverFocused)
+ return 2;
return 254;
- if (flags & ImGuiInputFlags_RouteOverActive)
- return 0;
+ }
IM_ASSERT(0);
return 0;
}
-// We need this to filter some Shortcut() routes when an item e.g. an InputText() is active
-// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be.
+// - We need this to filter some Shortcut() routes when an item e.g. an InputText() is active
+// e.g. ImGuiKey_G won't be considered a shortcut when item is active, but ImGuiMod|ImGuiKey_G can be.
+// - This is also used by UpdateInputEvents() to avoid trickling in the most common case of e.g. pressing ImGuiKey_G also emitting a G character.
static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
{
// Mimic 'ignore_char_inputs' logic in InputText()
@@ -9292,6 +9816,8 @@ static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
// Return true for A-Z, 0-9 and other keys associated to char inputs. Other keys such as F1-F12 won't be filtered.
ImGuiKey key = (ImGuiKey)(key_chord & ~ImGuiMod_Mask_);
+ if (key == ImGuiKey_None)
+ return false;
return g.KeysMayBeCharInput.TestBit(key);
}
@@ -9303,7 +9829,10 @@ static bool IsKeyChordPotentiallyCharInput(ImGuiKeyChord key_chord)
bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID owner_id)
{
ImGuiContext& g = *GImGui;
- IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteTypeMask_)); // Check that only 1 routing flag is used
+ if ((flags & ImGuiInputFlags_RouteTypeMask_) == 0)
+ flags |= ImGuiInputFlags_RouteGlobal | ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive; // IMPORTANT: This is the default for SetShortcutRouting() but NOT Shortcut()
+ else
+ IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiInputFlags_RouteTypeMask_)); // Check that only 1 routing flag is used
IM_ASSERT(owner_id != ImGuiKeyOwner_Any && owner_id != ImGuiKeyOwner_NoOwner);
if (flags & (ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused))
IM_ASSERT(flags & ImGuiInputFlags_RouteGlobal);
@@ -9329,20 +9858,20 @@ bool ImGui::SetShortcutRouting(ImGuiKeyChord key_chord, ImGuiInputFlags flags, I
// Specific culling when there's an active item.
if (g.ActiveId != 0 && g.ActiveId != owner_id)
{
+ if (flags & ImGuiInputFlags_RouteActive)
+ return false;
+
// Cull shortcuts with no modifiers when it could generate a character.
// e.g. Shortcut(ImGuiKey_G) also generates 'g' character, should not trigger when InputText() is active.
// but Shortcut(Ctrl+G) should generally trigger when InputText() is active.
// TL;DR: lettered shortcut with no mods or with only Alt mod will not trigger while an item reading text input is active.
// (We cannot filter based on io.InputQueueCharacters[] contents because of trickling and key<>chars submission order are undefined)
- if ((flags & ImGuiInputFlags_RouteFocused) && g.IO.WantTextInput && IsKeyChordPotentiallyCharInput(key_chord))
+ if (g.IO.WantTextInput && IsKeyChordPotentiallyCharInput(key_chord))
{
IMGUI_DEBUG_LOG_INPUTROUTING("SetShortcutRouting(%s, flags=%04X, owner_id=0x%08X) -> filtered as potential char input\n", GetKeyChordName(key_chord), flags, owner_id);
return false;
}
- if (flags & ImGuiInputFlags_RouteActive)
- return false;
-
// ActiveIdUsingAllKeyboardKeys trumps all for ActiveId
if ((flags & ImGuiInputFlags_RouteOverActive) == 0 && g.ActiveIdUsingAllKeyboardKeys)
{
@@ -9412,7 +9941,7 @@ bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
return IsKeyPressed(key, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any);
}
-// Important: unless legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
+// Important: unlike legacy IsKeyPressed(ImGuiKey, bool repeat=true) which DEFAULT to repeat, this requires EXPLICIT repeat.
bool ImGui::IsKeyPressed(ImGuiKey key, ImGuiInputFlags flags, ImGuiID owner_id)
{
const ImGuiKeyData* key_data = GetKeyData(key);
@@ -9483,7 +10012,7 @@ bool ImGui::IsMouseDown(ImGuiMouseButton button, ImGuiID owner_id)
bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
{
- return IsMouseClicked(button, ImGuiKeyOwner_Any, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None);
+ return IsMouseClicked(button, repeat ? ImGuiInputFlags_Repeat : ImGuiInputFlags_None, ImGuiKeyOwner_Any);
}
bool ImGui::IsMouseClicked(ImGuiMouseButton button, ImGuiInputFlags flags, ImGuiID owner_id)
@@ -9664,6 +10193,9 @@ ImGuiMouseCursor ImGui::GetMouseCursor()
return g.MouseCursor;
}
+// We intentionally accept values of ImGuiMouseCursor that are outside our bounds, in case users needs to hack-in a custom cursor value.
+// Custom cursors may be handled by custom backends. If you are using a standard backend and want to hack in a custom cursor, you may
+// handle it before the backend _NewFrame() call and temporarily set ImGuiConfigFlags_NoMouseCursorChange during the backend _NewFrame() call.
void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
{
ImGuiContext& g = *GImGui;
@@ -9694,6 +10226,9 @@ static void ImGui::UpdateKeyboardInputs()
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
+ if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
+ io.ClearInputKeys();
+
// Import legacy keys or verify they are not used
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
if (io.BackendUsingLegacyKeyArrays == 0)
@@ -10096,9 +10631,9 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
// Only trickle chars<>key when working with InputText()
// FIXME: InputText() could parse event trail?
// FIXME: Could specialize chars<>keys trickling rules for control keys (those not typically associated to characters)
- const bool trickle_interleaved_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1);
+ const bool trickle_interleaved_nonchar_keys_and_text = (trickle_fast_inputs && g.WantTextInputNextFrame == 1);
- bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false;
+ bool mouse_moved = false, mouse_wheeled = false, key_changed = false, key_changed_nonchar = false, text_inputted = false;
int mouse_button_changed = 0x00;
ImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;
@@ -10148,16 +10683,25 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
else if (e->Type == ImGuiInputEventType_Key)
{
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
+ if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
+ continue;
ImGuiKey key = e->Key.Key;
IM_ASSERT(key != ImGuiKey_None);
ImGuiKeyData* key_data = GetKeyData(key);
const int key_data_index = (int)(key_data - g.IO.KeysData);
- if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || text_inputted || mouse_button_changed != 0))
+ if (trickle_fast_inputs && key_data->Down != e->Key.Down && (key_changed_mask.TestBit(key_data_index) || mouse_button_changed != 0))
+ break;
+
+ const bool key_is_potentially_for_char_input = IsKeyChordPotentiallyCharInput(GetMergedModsFromKeys() | key);
+ if (trickle_interleaved_nonchar_keys_and_text && (text_inputted && !key_is_potentially_for_char_input))
break;
+
key_data->Down = e->Key.Down;
key_data->AnalogValue = e->Key.AnalogValue;
key_changed = true;
key_changed_mask.SetBit(key_data_index);
+ if (trickle_interleaved_nonchar_keys_and_text && !key_is_potentially_for_char_input)
+ key_changed_nonchar = true;
// Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@@ -10168,12 +10712,16 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
}
else if (e->Type == ImGuiInputEventType_Text)
{
+ if (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard)
+ continue;
// Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
- if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
+ if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
+ break;
+ if (trickle_interleaved_nonchar_keys_and_text && key_changed_nonchar)
break;
unsigned int c = e->Text.Char;
io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
- if (trickle_interleaved_keys_and_text)
+ if (trickle_interleaved_nonchar_keys_and_text)
text_inputted = true;
}
else if (e->Type == ImGuiInputEventType_Focus)
@@ -10212,7 +10760,10 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
// - we clear in EndFrame() and not now in order allow application/user code polling this flag
// (e.g. custom backend may want to clear additional data, custom widgets may want to react with a "canceling" event).
if (g.IO.AppFocusLost)
+ {
g.IO.ClearInputKeys();
+ g.IO.ClearInputMouse();
+ }
}
ImGuiID ImGui::GetKeyOwner(ImGuiKey key)
@@ -10315,10 +10866,15 @@ void ImGui::SetItemKeyOwner(ImGuiKey key, ImGuiInputFlags flags)
}
}
+void ImGui::SetItemKeyOwner(ImGuiKey key)
+{
+ SetItemKeyOwner(key, ImGuiInputFlags_None);
+}
+
// This is the only public API until we expose owner_id versions of the API as replacements.
bool ImGui::IsKeyChordPressed(ImGuiKeyChord key_chord)
{
- return IsKeyChordPressed(key_chord, 0, ImGuiInputFlags_None);
+ return IsKeyChordPressed(key_chord, ImGuiInputFlags_None, ImGuiKeyOwner_Any);
}
// This is equivalent to comparing KeyMods + doing a IsKeyPressed()
@@ -10347,12 +10903,15 @@ void ImGui::SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags)
g.NextItemData.ShortcutFlags = flags;
}
+// Called from within ItemAdd: at this point we can read from NextItemData and write to LastItemData
void ImGui::ItemHandleShortcut(ImGuiID id)
{
ImGuiContext& g = *GImGui;
ImGuiInputFlags flags = g.NextItemData.ShortcutFlags;
IM_ASSERT((flags & ~ImGuiInputFlags_SupportedBySetNextItemShortcut) == 0); // Passing flags not supported by SetNextItemShortcut()!
+ if (g.LastItemData.InFlags & ImGuiItemFlags_Disabled)
+ return;
if (flags & ImGuiInputFlags_Tooltip)
{
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasShortcut;
@@ -10376,7 +10935,7 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags)
bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID owner_id)
{
- //ImGuiContext& g = *GImGui;
+ ImGuiContext& g = *GImGui;
//IMGUI_DEBUG_LOG("Shortcut(%s, flags=%X, owner_id=0x%08X)\n", GetKeyChordName(key_chord, g.TempBuffer.Data, g.TempBuffer.Size), flags, owner_id);
// When using (owner_id == 0/Any): SetShortcutRouting() will use CurrentFocusScopeId and filter with this, so IsKeyPressed() is fine with he 0/Any.
@@ -10388,6 +10947,9 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own
if (owner_id == ImGuiKeyOwner_Any || owner_id == ImGuiKeyOwner_NoOwner)
owner_id = GetRoutingIdFromOwnerId(owner_id);
+ if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
+ return false;
+
// Submit route
if (!SetShortcutRouting(key_chord, flags, owner_id))
return false;
@@ -10409,7 +10971,16 @@ bool ImGui::Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags, ImGuiID own
//-----------------------------------------------------------------------------
-// [SECTION] ERROR CHECKING
+// [SECTION] ERROR CHECKING, STATE RECOVERY
+//-----------------------------------------------------------------------------
+// - DebugCheckVersionAndDataLayout() (called via IMGUI_CHECKVERSION() macros)
+// - ErrorCheckUsingSetCursorPosToExtendParentBoundaries()
+// - ErrorCheckNewFrameSanityChecks()
+// - ErrorCheckEndFrameSanityChecks()
+// - ErrorRecoveryStoreState()
+// - ErrorRecoveryTryToRecoverState()
+// - ErrorRecoveryTryToRecoverWindowState()
+// - ErrorLog()
//-----------------------------------------------------------------------------
// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
@@ -10508,9 +11079,17 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
IM_ASSERT(g.IO.KeyMap[ImGuiKey_Space] != -1 && "ImGuiKey_Space is not mapped, required for keyboard navigation.");
#endif
- // Check: the io.ConfigWindowsResizeFromEdges option requires backend to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
- if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
- g.IO.ConfigWindowsResizeFromEdges = false;
+ // Error handling: we do not accept 100% silent recovery! Please contact me if you feel this is getting in your way.
+ if (g.IO.ConfigErrorRecovery)
+ IM_ASSERT(g.IO.ConfigErrorRecoveryEnableAssert || g.IO.ConfigErrorRecoveryEnableDebugLog || g.IO.ConfigErrorRecoveryEnableTooltip || g.ErrorCallback != NULL);
+
+ // Remap legacy clipboard handlers (OBSOLETED in 1.91.1, August 2024)
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ if (g.IO.GetClipboardTextFn != NULL && (g.PlatformIO.Platform_GetClipboardTextFn == NULL || g.PlatformIO.Platform_GetClipboardTextFn == Platform_GetClipboardTextFn_DefaultImpl))
+ g.PlatformIO.Platform_GetClipboardTextFn = [](ImGuiContext* ctx) { return ctx->IO.GetClipboardTextFn(ctx->IO.ClipboardUserData); };
+ if (g.IO.SetClipboardTextFn != NULL && (g.PlatformIO.Platform_SetClipboardTextFn == NULL || g.PlatformIO.Platform_SetClipboardTextFn == Platform_SetClipboardTextFn_DefaultImpl))
+ g.PlatformIO.Platform_SetClipboardTextFn = [](ImGuiContext* ctx, const char* text) { return ctx->IO.SetClipboardTextFn(ctx->IO.ClipboardUserData, text); };
+#endif
// Perform simple check: error if Docking or Viewport are enabled _exactly_ on frame 1 (instead of frame 0 or later), which is a common error leading to loss of .ini data.
if (g.FrameCount == 1 && (g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable) && (g.ConfigFlagsLastFrame & ImGuiConfigFlags_DockingEnable) == 0)
@@ -10554,175 +11133,268 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
static void ImGui::ErrorCheckEndFrameSanityChecks()
{
- ImGuiContext& g = *GImGui;
-
// Verify that io.KeyXXX fields haven't been tampered with. Key mods should not be modified between NewFrame() and EndFrame()
// One possible reason leading to this assert is that your backends update inputs _AFTER_ NewFrame().
// It is known that when some modal native windows called mid-frame takes focus away, some backends such as GLFW will
// send key release events mid-frame. This would normally trigger this assertion and lead to sheared inputs.
// We silently accommodate for this case by ignoring the case where all io.KeyXXX modifiers were released (aka key_mod_flags == 0),
// while still correctly asserting on mid-frame key press events.
+ ImGuiContext& g = *GImGui;
const ImGuiKeyChord key_mods = GetMergedModsFromKeys();
+ IM_UNUSED(g);
+ IM_UNUSED(key_mods);
IM_ASSERT((key_mods == 0 || g.IO.KeyMods == key_mods) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
IM_UNUSED(key_mods);
- // [EXPERIMENTAL] Recover from errors: You may call this yourself before EndFrame().
- //ErrorCheckEndFrameRecover();
-
- // Report when there is a mismatch of Begin/BeginChild vs End/EndChild calls. Important: Remember that the Begin/BeginChild API requires you
- // to always call End/EndChild even if Begin/BeginChild returns false! (this is unfortunately inconsistent with most other Begin* API).
- if (g.CurrentWindowStack.Size != 1)
- {
- if (g.CurrentWindowStack.Size > 1)
- {
- ImGuiWindow* window = g.CurrentWindowStack.back().Window; // <-- This window was not Ended!
- IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you forget to call End/EndChild?");
- IM_UNUSED(window);
- while (g.CurrentWindowStack.Size > 1)
- End();
- }
- else
- {
- IM_ASSERT_USER_ERROR(g.CurrentWindowStack.Size == 1, "Mismatched Begin/BeginChild vs End/EndChild calls: did you call End/EndChild too much?");
- }
- }
+ IM_ASSERT(g.CurrentWindowStack.Size == 1);
+ IM_ASSERT(g.CurrentWindowStack[0].Window->IsFallbackWindow);
+}
- IM_ASSERT_USER_ERROR(g.GroupStack.Size == 0, "Missing EndGroup call!");
+// Save current stack sizes. Called e.g. by NewFrame() and by Begin() but may be called for manual recovery.
+void ImGui::ErrorRecoveryStoreState(ImGuiErrorRecoveryState* state_out)
+{
+ ImGuiContext& g = *GImGui;
+ state_out->SizeOfWindowStack = (short)g.CurrentWindowStack.Size;
+ state_out->SizeOfIDStack = (short)g.CurrentWindow->IDStack.Size;
+ state_out->SizeOfTreeStack = (short)g.CurrentWindow->DC.TreeDepth; // NOT g.TreeNodeStack.Size which is a partial stack!
+ state_out->SizeOfColorStack = (short)g.ColorStack.Size;
+ state_out->SizeOfStyleVarStack = (short)g.StyleVarStack.Size;
+ state_out->SizeOfFontStack = (short)g.FontStack.Size;
+ state_out->SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;
+ state_out->SizeOfGroupStack = (short)g.GroupStack.Size;
+ state_out->SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size;
+ state_out->SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;
+ state_out->SizeOfDisabledStack = (short)g.DisabledStackSize;
}
-// Experimental recovery from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
-// Must be called during or before EndFrame().
-// This is generally flawed as we are not necessarily End/Popping things in the right order.
-// FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.
-// FIXME: Can't recover from interleaved BeginTabBar/Begin
-void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data)
+// Chosen name "Try to recover" over e.g. "Restore" to suggest this is not a 100% guaranteed recovery.
+// Called by e.g. EndFrame() but may be called for manual recovery.
+// Attempt to recover full window stack.
+void ImGui::ErrorRecoveryTryToRecoverState(const ImGuiErrorRecoveryState* state_in)
{
// PVS-Studio V1044 is "Loop break conditions do not depend on the number of iterations"
ImGuiContext& g = *GImGui;
- while (g.CurrentWindowStack.Size > 0) //-V1044
+ while (g.CurrentWindowStack.Size > state_in->SizeOfWindowStack) //-V1044
{
- ErrorCheckEndWindowRecover(log_callback, user_data);
+ // Recap:
+ // - Begin()/BeginChild() return false to indicate the window is collapsed or fully clipped.
+ // - Always call a matching End() for each Begin() call, regardless of its return value!
+ // - Begin/End and BeginChild/EndChild logic is KNOWN TO BE INCONSISTENT WITH ALL OTHER BEGIN/END FUNCTIONS.
+ // - We will fix that in a future major update.
ImGuiWindow* window = g.CurrentWindow;
- if (g.CurrentWindowStack.Size == 1)
- {
- IM_ASSERT(window->IsFallbackWindow);
- break;
- }
if (window->Flags & ImGuiWindowFlags_ChildWindow)
{
- if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing EndChild()");
EndChild();
}
else
{
- if (log_callback) log_callback(user_data, "Recovered from missing End() for '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing End()");
End();
}
}
+ if (g.CurrentWindowStack.Size == state_in->SizeOfWindowStack)
+ ErrorRecoveryTryToRecoverWindowState(state_in);
}
-// Must be called before End()/EndChild()
-void ImGui::ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data)
+// Called by e.g. End() but may be called for manual recovery.
+// Read '// Error Handling [BETA]' block in imgui_internal.h for details.
+// Attempt to recover from incorrect usage of BeginXXX/EndXXX/PushXXX/PopXXX calls.
+void ImGui::ErrorRecoveryTryToRecoverWindowState(const ImGuiErrorRecoveryState* state_in)
{
ImGuiContext& g = *GImGui;
- while (g.CurrentTable && (g.CurrentTable->OuterWindow == g.CurrentWindow || g.CurrentTable->InnerWindow == g.CurrentWindow))
+
+ while (g.CurrentTable != NULL && g.CurrentTable->InnerWindow == g.CurrentWindow) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing EndTable() in '%s'", g.CurrentTable->OuterWindow->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing EndTable()");
EndTable();
}
ImGuiWindow* window = g.CurrentWindow;
- ImGuiStackSizes* stack_sizes = &g.CurrentWindowStack.back().StackSizesOnBegin;
- IM_ASSERT(window != NULL);
- while (g.CurrentTabBar != NULL) //-V1044
+
+ // FIXME: Can't recover from inside BeginTabItem/EndTabItem yet.
+ while (g.CurrentTabBar != NULL && g.CurrentTabBar->Window == window) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing EndTabBar() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing EndTabBar()");
EndTabBar();
}
- while (window->DC.TreeDepth > 0)
+ while (g.CurrentMultiSelect != NULL && g.CurrentMultiSelect->Storage->Window == window) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing TreePop() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing EndMultiSelect()");
+ EndMultiSelect();
+ }
+ while (window->DC.TreeDepth > state_in->SizeOfTreeStack) //-V1044
+ {
+ IM_ASSERT_USER_ERROR(0, "Missing TreePop()");
TreePop();
}
- while (g.GroupStack.Size > stack_sizes->SizeOfGroupStack) //-V1044
+ while (g.GroupStack.Size > state_in->SizeOfGroupStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing EndGroup() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing EndGroup()");
EndGroup();
}
- while (window->IDStack.Size > 1)
+ IM_ASSERT(g.GroupStack.Size == state_in->SizeOfGroupStack);
+ while (window->IDStack.Size > state_in->SizeOfIDStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopID() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing PopID()");
PopID();
}
- while (g.DisabledStackSize > stack_sizes->SizeOfDisabledStack) //-V1044
+ while (g.DisabledStackSize > state_in->SizeOfDisabledStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing EndDisabled() in '%s'", window->Name);
- EndDisabled();
+ IM_ASSERT_USER_ERROR(0, "Missing EndDisabled()");
+ if (g.CurrentItemFlags & ImGuiItemFlags_Disabled)
+ EndDisabled();
+ else
+ {
+ EndDisabledOverrideReenable();
+ g.CurrentWindowStack.back().DisabledOverrideReenable = false;
+ }
}
- while (g.ColorStack.Size > stack_sizes->SizeOfColorStack)
+ IM_ASSERT(g.DisabledStackSize == state_in->SizeOfDisabledStack);
+ while (g.ColorStack.Size > state_in->SizeOfColorStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopStyleColor() in '%s' for ImGuiCol_%s", window->Name, GetStyleColorName(g.ColorStack.back().Col));
+ IM_ASSERT_USER_ERROR(0, "Missing PopStyleColor()");
PopStyleColor();
}
- while (g.ItemFlagsStack.Size > stack_sizes->SizeOfItemFlagsStack) //-V1044
+ while (g.ItemFlagsStack.Size > state_in->SizeOfItemFlagsStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopItemFlag() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing PopItemFlag()");
PopItemFlag();
}
- while (g.StyleVarStack.Size > stack_sizes->SizeOfStyleVarStack) //-V1044
+ while (g.StyleVarStack.Size > state_in->SizeOfStyleVarStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopStyleVar() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing PopStyleVar()");
PopStyleVar();
}
- while (g.FontStack.Size > stack_sizes->SizeOfFontStack) //-V1044
+ while (g.FontStack.Size > state_in->SizeOfFontStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopFont() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing PopFont()");
PopFont();
}
- while (g.FocusScopeStack.Size > stack_sizes->SizeOfFocusScopeStack + 1) //-V1044
+ while (g.FocusScopeStack.Size > state_in->SizeOfFocusScopeStack) //-V1044
{
- if (log_callback) log_callback(user_data, "Recovered from missing PopFocusScope() in '%s'", window->Name);
+ IM_ASSERT_USER_ERROR(0, "Missing PopFocusScope()");
PopFocusScope();
}
+ //IM_ASSERT(g.FocusScopeStack.Size == state_in->SizeOfFocusScopeStack);
}
-// Save current stack sizes for later compare
-void ImGuiStackSizes::SetToContextState(ImGuiContext* ctx)
+bool ImGui::ErrorLog(const char* msg)
{
- ImGuiContext& g = *ctx;
+ ImGuiContext& g = *GImGui;
+
+ // Output to debug log
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
ImGuiWindow* window = g.CurrentWindow;
- SizeOfIDStack = (short)window->IDStack.Size;
- SizeOfColorStack = (short)g.ColorStack.Size;
- SizeOfStyleVarStack = (short)g.StyleVarStack.Size;
- SizeOfFontStack = (short)g.FontStack.Size;
- SizeOfFocusScopeStack = (short)g.FocusScopeStack.Size;
- SizeOfGroupStack = (short)g.GroupStack.Size;
- SizeOfItemFlagsStack = (short)g.ItemFlagsStack.Size;
- SizeOfBeginPopupStack = (short)g.BeginPopupStack.Size;
- SizeOfDisabledStack = (short)g.DisabledStackSize;
+
+ if (g.IO.ConfigErrorRecoveryEnableDebugLog)
+ {
+ if (g.ErrorFirst)
+ IMGUI_DEBUG_LOG_ERROR("[imgui-error] (current settings: Assert=%d, Log=%d, Tooltip=%d)\n",
+ g.IO.ConfigErrorRecoveryEnableAssert, g.IO.ConfigErrorRecoveryEnableDebugLog, g.IO.ConfigErrorRecoveryEnableTooltip);
+ IMGUI_DEBUG_LOG_ERROR("[imgui-error] In window '%s': %s\n", window ? window->Name : "NULL", msg);
+ }
+ g.ErrorFirst = false;
+
+ // Output to tooltip
+ if (g.IO.ConfigErrorRecoveryEnableTooltip)
+ {
+ if (BeginErrorTooltip())
+ {
+ if (g.ErrorCountCurrentFrame < 20)
+ {
+ Text("In window '%s': %s", window ? window->Name : "NULL", msg);
+ if (window && (!window->IsFallbackWindow || window->WasActive))
+ GetForegroundDrawList(window)->AddRect(window->Pos, window->Pos + window->Size, IM_COL32(255, 0, 0, 255));
+ }
+ if (g.ErrorCountCurrentFrame == 20)
+ Text("(and more errors)");
+ // EndFrame() will amend debug buttons to this window, after all errors have been submitted.
+ EndErrorTooltip();
+ }
+ g.ErrorCountCurrentFrame++;
+ }
+#endif
+
+ // Output to callback
+ if (g.ErrorCallback != NULL)
+ g.ErrorCallback(&g, g.ErrorCallbackUserData, msg);
+
+ // Return whether we should assert
+ return g.IO.ConfigErrorRecoveryEnableAssert;
}
-// Compare to detect usage errors
-void ImGuiStackSizes::CompareWithContextState(ImGuiContext* ctx)
+void ImGui::ErrorCheckEndFrameFinalizeErrorTooltip()
{
- ImGuiContext& g = *ctx;
- ImGuiWindow* window = g.CurrentWindow;
- IM_UNUSED(window);
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ ImGuiContext& g = *GImGui;
+ if (g.DebugDrawIdConflicts != 0 && g.IO.KeyCtrl == false)
+ g.DebugDrawIdConflictsCount = g.HoveredIdPreviousFrameItemCount;
+ if (g.DebugDrawIdConflicts != 0 && g.DebugItemPickerActive == false && BeginErrorTooltip())
+ {
+ Text("Programmer error: %d visible items with conflicting ID!", g.DebugDrawIdConflictsCount);
+ BulletText("Code should use PushID()/PopID() in loops, or append \"##xx\" to same-label identifiers!");
+ BulletText("Empty label e.g. Button(\"\") == same ID as parent widget/node. Use Button(\"##xx\") instead!");
+ //BulletText("Code intending to use duplicate ID may use e.g. PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true); ... PopItemFlag()"); // Not making this too visible for fear of it being abused.
+ BulletText("Set io.ConfigDebugDetectIdConflicts=false to disable this warning in non-programmers builds.");
+ Separator();
+ Text("(Hold CTRL to: use");
+ SameLine();
+ if (SmallButton("Item Picker"))
+ DebugStartItemPicker();
+ SameLine();
+ Text("to break in item call-stack, or");
+ SameLine();
+ if (SmallButton("Open FAQ->About ID Stack System") && g.PlatformIO.Platform_OpenInShellFn != NULL)
+ g.PlatformIO.Platform_OpenInShellFn(&g, "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#qa-usage");
+ EndErrorTooltip();
+ }
- // Window stacks
- // NOT checking: DC.ItemWidth, DC.TextWrapPos (per window) to allow user to conveniently push once and not pop (they are cleared on Begin)
- IM_ASSERT(SizeOfIDStack == window->IDStack.Size && "PushID/PopID or TreeNode/TreePop Mismatch!");
+ if (g.ErrorCountCurrentFrame > 0 && BeginErrorTooltip()) // Amend at end of frame
+ {
+ Separator();
+ Text("(Hold CTRL to:");
+ SameLine();
+ if (SmallButton("Enable Asserts"))
+ g.IO.ConfigErrorRecoveryEnableAssert = true;
+ //SameLine();
+ //if (SmallButton("Hide Error Tooltips"))
+ // g.IO.ConfigErrorRecoveryEnableTooltip = false; // Too dangerous
+ SameLine(0, 0);
+ Text(")");
+ EndErrorTooltip();
+ }
+#endif
+}
+
+// Pseudo-tooltip. Follow mouse until CTRL is held. When CTRL is held we lock position, allowing to click it.
+bool ImGui::BeginErrorTooltip()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = FindWindowByName("##Tooltip_Error");
+ const bool use_locked_pos = (g.IO.KeyCtrl && window && window->WasActive);
+ PushStyleColor(ImGuiCol_PopupBg, ImLerp(g.Style.Colors[ImGuiCol_PopupBg], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.15f));
+ if (use_locked_pos)
+ SetNextWindowPos(g.ErrorTooltipLockedPos);
+ bool is_visible = Begin("##Tooltip_Error", NULL, ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize);
+ PopStyleColor();
+ if (is_visible && g.CurrentWindow->BeginCount == 1)
+ {
+ SeparatorText("MESSAGE FROM DEAR IMGUI");
+ BringWindowToDisplayFront(g.CurrentWindow);
+ BringWindowToFocusFront(g.CurrentWindow);
+ g.ErrorTooltipLockedPos = GetWindowPos();
+ }
+ else if (!is_visible)
+ {
+ End();
+ }
+ return is_visible;
+}
- // Global stacks
- // For color, style and font stacks there is an incentive to use Push/Begin/Pop/.../End patterns, so we relax our checks a little to allow them.
- IM_ASSERT(SizeOfGroupStack == g.GroupStack.Size && "BeginGroup/EndGroup Mismatch!");
- IM_ASSERT(SizeOfBeginPopupStack == g.BeginPopupStack.Size && "BeginPopup/EndPopup or BeginMenu/EndMenu Mismatch!");
- IM_ASSERT(SizeOfDisabledStack == g.DisabledStackSize && "BeginDisabled/EndDisabled Mismatch!");
- IM_ASSERT(SizeOfItemFlagsStack >= g.ItemFlagsStack.Size && "PushItemFlag/PopItemFlag Mismatch!");
- IM_ASSERT(SizeOfColorStack >= g.ColorStack.Size && "PushStyleColor/PopStyleColor Mismatch!");
- IM_ASSERT(SizeOfStyleVarStack >= g.StyleVarStack.Size && "PushStyleVar/PopStyleVar Mismatch!");
- IM_ASSERT(SizeOfFontStack >= g.FontStack.Size && "PushFont/PopFont Mismatch!");
- IM_ASSERT(SizeOfFocusScopeStack == g.FocusScopeStack.Size && "PushFocusScope/PopFocusScope Mismatch!");
+void ImGui::EndErrorTooltip()
+{
+ End();
}
//-----------------------------------------------------------------------------
@@ -10746,6 +11418,7 @@ void ImGui::KeepAliveID(ImGuiID id)
// Note that the size can be different than the one provided to ItemSize(). Typically, widgets that spread over available surface
// declare their minimum size requirement to ItemSize() and provide a larger region to ItemAdd() which is used drawing/interaction.
// THIS IS IN THE PERFORMANCE CRITICAL PATH (UNTIL THE CLIPPING TEST AND EARLY-RETURN)
+IM_MSVC_RUNTIME_CHECKS_OFF
bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGuiItemFlags extra_flags)
{
ImGuiContext& g = *GImGui;
@@ -10780,7 +11453,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
window->DC.NavLayersActiveMaskNext |= (1 << window->DC.NavLayerCurrent);
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
- if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
+ if (window == g.NavWindow || ((window->ChildFlags | g.NavWindow->ChildFlags) & ImGuiChildFlags_NavFlattened))
NavProcessItem();
}
@@ -10798,15 +11471,12 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
#endif
// Clipping test
- // (this is a modified copy of IsClippedEx() so we can reuse the is_rect_visible value)
- //const bool is_clipped = IsClippedEx(bb, id);
- //if (is_clipped)
- // return false;
+ // (this is an inline copy of IsClippedEx() so we can reuse the is_rect_visible value, otherwise we'd do 'if (IsClippedEx(bb, id)) return false')
// g.NavActivateId is not necessarily == g.NavId, in the case of remote activation (e.g. shortcuts)
const bool is_rect_visible = bb.Overlaps(window->ClipRect);
if (!is_rect_visible)
if (id == 0 || (id != g.ActiveId && id != g.ActiveIdPreviousFrame && id != g.NavId && id != g.NavActivateId))
- if (!g.LogEnabled)
+ if (!g.ItemUnclipByLog)
return false;
// [DEBUG]
@@ -10833,7 +11503,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
return true;
}
-
+IM_MSVC_RUNTIME_CHECKS_RESTORE
//-----------------------------------------------------------------------------
// [SECTION] LAYOUT
@@ -10858,9 +11528,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// - GetFrameHeight()
// - GetFrameHeightWithSpacing()
// - GetContentRegionMax()
-// - GetContentRegionMaxAbs() [Internal]
// - GetContentRegionAvail(),
-// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
// - BeginGroup()
// - EndGroup()
// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns.
@@ -10870,6 +11538,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// Register minimum needed size so it can extend the bounding box used for auto-fit calculation.
// See comments in ItemAdd() about how/why the size provided to ItemSize() vs ItemAdd() may often different.
// THIS IS IN THE PERFORMANCE CRITICAL PATH.
+IM_MSVC_RUNTIME_CHECKS_OFF
void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
{
ImGuiContext& g = *GImGui;
@@ -10905,6 +11574,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
SameLine();
}
+IM_MSVC_RUNTIME_CHECKS_RESTORE
// Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item
@@ -11056,7 +11726,13 @@ void ImGui::PushMultiItemsWidths(int components, float w_full)
void ImGui::PopItemWidth()
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ if (window->DC.ItemWidthStack.Size <= 0)
+ {
+ IM_ASSERT_USER_ERROR(0, "Calling PopItemWidth() too many times!");
+ return;
+ }
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
window->DC.ItemWidthStack.pop_back();
}
@@ -11074,8 +11750,8 @@ float ImGui::CalcItemWidth()
w = window->DC.ItemWidth;
if (w < 0.0f)
{
- float region_max_x = GetContentRegionMaxAbs().x;
- w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
+ float region_avail_x = GetContentRegionAvail().x;
+ w = ImMax(1.0f, region_avail_x + w);
}
w = IM_TRUNC(w);
return w;
@@ -11087,22 +11763,19 @@ float ImGui::CalcItemWidth()
// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
-
- ImVec2 region_max;
+ ImVec2 avail;
if (size.x < 0.0f || size.y < 0.0f)
- region_max = GetContentRegionMaxAbs();
+ avail = GetContentRegionAvail();
if (size.x == 0.0f)
size.x = default_w;
else if (size.x < 0.0f)
- size.x = ImMax(4.0f, region_max.x - window->DC.CursorPos.x + size.x);
+ size.x = ImMax(4.0f, avail.x + size.x); // <-- size.x is negative here so we are subtracting
if (size.y == 0.0f)
size.y = default_h;
else if (size.y < 0.0f)
- size.y = ImMax(4.0f, region_max.y - window->DC.CursorPos.y + size.y);
+ size.y = ImMax(4.0f, avail.y + size.y); // <-- size.y is negative here so we are subtracting
return size;
}
@@ -11131,33 +11804,23 @@ float ImGui::GetFrameHeightWithSpacing()
return g.FontSize + g.Style.FramePadding.y * 2.0f + g.Style.ItemSpacing.y;
}
-// FIXME: All the Contents Region function are messy or misleading. WE WILL AIM TO OBSOLETE ALL OF THEM WITH A NEW "WORK RECT" API. Thanks for your patience!
-
-// FIXME: This is in window space (not screen space!).
-ImVec2 ImGui::GetContentRegionMax()
+ImVec2 ImGui::GetContentRegionAvail()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max;
- return mx - window->Pos;
+ return mx - window->DC.CursorPos;
}
-// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
-ImVec2 ImGui::GetContentRegionMaxAbs()
-{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- ImVec2 mx = (window->DC.CurrentColumns || g.CurrentTable) ? window->WorkRect.Max : window->ContentRegionRect.Max;
- return mx;
-}
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-ImVec2 ImGui::GetContentRegionAvail()
+// You should never need those functions. Always use GetCursorScreenPos() and GetContentRegionAvail()!
+// They are bizarre local-coordinates which don't play well with scrolling.
+ImVec2 ImGui::GetContentRegionMax()
{
- ImGuiWindow* window = GImGui->CurrentWindow;
- return GetContentRegionMaxAbs() - window->DC.CursorPos;
+ return GetContentRegionAvail() + GetCursorScreenPos() - GetWindowPos();
}
-// In window space (not screen space!)
ImVec2 ImGui::GetWindowContentRegionMin()
{
ImGuiWindow* window = GImGui->CurrentWindow;
@@ -11169,6 +11832,7 @@ ImVec2 ImGui::GetWindowContentRegionMax()
ImGuiWindow* window = GImGui->CurrentWindow;
return window->ContentRegionRect.Max - window->Pos;
}
+#endif
// Lock horizontal starting position + capture group bounding box into one "item" (so you can use IsItemHovered() or layout primitives such as SameLine() on whole group, etc.)
// Groups are currently a mishmash of functionalities which should perhaps be clarified and separated.
@@ -11214,11 +11878,11 @@ void ImGui::EndGroup()
if (window->DC.IsSetPos)
ErrorCheckUsingSetCursorPosToExtendParentBoundaries();
- ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
-
+ // Include LastItemData.Rect.Max as a workaround for e.g. EndTable() undershooting with CursorMaxPos report. (#7543)
+ ImRect group_bb(group_data.BackupCursorPos, ImMax(ImMax(window->DC.CursorMaxPos, g.LastItemData.Rect.Max), group_data.BackupCursorPos));
window->DC.CursorPos = group_data.BackupCursorPos;
window->DC.CursorPosPrevLine = group_data.BackupCursorPosPrevLine;
- window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
+ window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, group_bb.Max);
window->DC.Indent = group_data.BackupIndent;
window->DC.GroupOffset = group_data.BackupGroupOffset;
window->DC.CurrLineSize = group_data.BackupCurrLineSize;
@@ -11233,7 +11897,7 @@ void ImGui::EndGroup()
return;
}
- window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
+ window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
ItemSize(group_bb.GetSize());
ItemAdd(group_bb, 0, NULL, ImGuiItemFlags_NoTabStop);
@@ -11530,7 +12194,8 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext
{
ImGuiContext& g = *GImGui;
- if (g.DragDropWithinSource || g.DragDropWithinTarget)
+ const bool is_dragdrop_tooltip = g.DragDropWithinSource || g.DragDropWithinTarget;
+ if (is_dragdrop_tooltip)
{
// Drag and Drop tooltips are positioning differently than other tooltips:
// - offset visibility to increase visibility around mouse.
@@ -11538,23 +12203,30 @@ bool ImGui::BeginTooltipEx(ImGuiTooltipFlags tooltip_flags, ImGuiWindowFlags ext
// We call SetNextWindowPos() to enforce position and disable clamping.
// See FindBestWindowPosForPopup() for positionning logic of other tooltips (not drag and drop ones).
//ImVec2 tooltip_pos = g.IO.MousePos - g.ActiveIdClickOffset - g.Style.WindowPadding;
- ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET * g.Style.MouseCursorScale;
- SetNextWindowPos(tooltip_pos);
+ const bool is_touchscreen = (g.IO.MouseSource == ImGuiMouseSource_TouchScreen);
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
+ {
+ ImVec2 tooltip_pos = is_touchscreen ? (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * g.Style.MouseCursorScale) : (g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * g.Style.MouseCursorScale);
+ ImVec2 tooltip_pivot = is_touchscreen ? TOOLTIP_DEFAULT_PIVOT_TOUCH : ImVec2(0.0f, 0.0f);
+ SetNextWindowPos(tooltip_pos, ImGuiCond_None, tooltip_pivot);
+ }
+
SetNextWindowBgAlpha(g.Style.Colors[ImGuiCol_PopupBg].w * 0.60f);
//PushStyleVar(ImGuiStyleVar_Alpha, g.Style.Alpha * 0.60f); // This would be nice but e.g ColorButton with checkboard has issue with transparent colors :(
tooltip_flags |= ImGuiTooltipFlags_OverridePrevious;
}
- char window_name[16];
- ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", g.TooltipOverrideCount);
- if (tooltip_flags & ImGuiTooltipFlags_OverridePrevious)
- if (ImGuiWindow* window = FindWindowByName(window_name))
- if (window->Active)
- {
- // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
- SetWindowHiddenAndSkipItemsForCurrentFrame(window);
- ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
- }
+ const char* window_name_template = is_dragdrop_tooltip ? "##Tooltip_DragDrop_%02d" : "##Tooltip_%02d";
+ char window_name[32];
+ ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, g.TooltipOverrideCount);
+ if ((tooltip_flags & ImGuiTooltipFlags_OverridePrevious) && g.TooltipPreviousWindow != NULL && g.TooltipPreviousWindow->Active)
+ {
+ // Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
+ //IMGUI_DEBUG_LOG("[tooltip] '%s' already active, using +1 for this frame\n", window_name);
+ SetWindowHiddenAndSkipItemsForCurrentFrame(g.TooltipPreviousWindow);
+ ImFormatString(window_name, IM_ARRAYSIZE(window_name), window_name_template, ++g.TooltipOverrideCount);
+ }
+
ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking;
Begin(window_name, NULL, flags | extra_window_flags);
// 2023-03-09: Added bool return value to the API, but currently always returning true.
@@ -11811,6 +12483,9 @@ void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_
ImGuiContext& g = *GImGui;
IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_under=%d\n", remaining, restore_focus_to_window_under_popup);
IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
+ if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup)
+ for (int n = remaining; n < g.OpenPopupStack.Size; n++)
+ IMGUI_DEBUG_LOG_POPUP("[popup] - Closing PopupID 0x%08X Window \"%s\"\n", g.OpenPopupStack[n].PopupId, g.OpenPopupStack[n].Window ? g.OpenPopupStack[n].Window->Name : NULL);
// Trim open popup stack
ImGuiPopupData prev_popup = g.OpenPopupStack[remaining];
@@ -11859,8 +12534,8 @@ void ImGui::CloseCurrentPopup()
window->DC.NavHideHighlightOneFrame = true;
}
-// Attention! BeginPopup() adds default flags which BeginPopupEx()!
-bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
+// Attention! BeginPopup() adds default flags when calling BeginPopupEx()!
+bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_window_flags)
{
ImGuiContext& g = *GImGui;
if (!IsPopupOpen(id, ImGuiPopupFlags_None))
@@ -11870,13 +12545,12 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags flags)
}
char name[20];
- if (flags & ImGuiWindowFlags_ChildMenu)
+ if (extra_window_flags & ImGuiWindowFlags_ChildMenu)
ImFormatString(name, IM_ARRAYSIZE(name), "##Menu_%02d", g.BeginMenuDepth); // Recycle windows based on depth
else
ImFormatString(name, IM_ARRAYSIZE(name), "##Popup_%08x", id); // Not recycling, so we can close/open during the same frame
- flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking;
- bool is_open = Begin(name, NULL, flags);
+ bool is_open = Begin(name, NULL, extra_window_flags | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoDocking);
if (!is_open) // NB: Begin can return false when the popup is completely clipped (e.g. zero size display)
EndPopup();
@@ -12154,18 +12828,30 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
if (window->Flags & ImGuiWindowFlags_Tooltip)
{
// Position tooltip (always follows mouse + clamp within outer boundaries)
- // Note that drag and drop tooltips are NOT using this path: BeginTooltipEx() manually sets their position.
- // In theory we could handle both cases in same location, but requires a bit of shuffling as drag and drop tooltips are calling SetWindowPos() leading to 'window_pos_set_by_api' being set in Begin()
+ // FIXME:
+ // - Too many paths. One problem is that FindBestWindowPosForPopupEx() doesn't allow passing a suggested position (so touch screen path doesn't use it by default).
+ // - Drag and drop tooltips are not using this path either: BeginTooltipEx() manually sets their position.
+ // - Require some tidying up. In theory we could handle both cases in same location, but requires a bit of shuffling
+ // as drag and drop tooltips are calling SetNextWindowPos() leading to 'window_pos_set_by_api' being set in Begin().
IM_ASSERT(g.CurrentWindow == window);
const float scale = g.Style.MouseCursorScale;
const ImVec2 ref_pos = NavCalcPreferredRefPos();
- const ImVec2 tooltip_pos = ref_pos + TOOLTIP_DEFAULT_OFFSET * scale;
+
+ if (g.IO.MouseSource == ImGuiMouseSource_TouchScreen)
+ {
+ ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_TOUCH * scale - (TOOLTIP_DEFAULT_PIVOT_TOUCH * window->Size);
+ if (r_outer.Contains(ImRect(tooltip_pos, tooltip_pos + window->Size)))
+ return tooltip_pos;
+ }
+
+ ImVec2 tooltip_pos = g.IO.MousePos + TOOLTIP_DEFAULT_OFFSET_MOUSE * scale;
ImRect r_avoid;
if (!g.NavDisableHighlight && g.NavDisableMouseHover && !(g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos))
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 16, ref_pos.y + 8);
else
r_avoid = ImRect(ref_pos.x - 16, ref_pos.y - 8, ref_pos.x + 24 * scale, ref_pos.y + 24 * scale); // FIXME: Hard-coded based on mouse cursor shape expectation. Exact dimension not very important.
//GetForegroundDrawList()->AddRect(r_avoid.Min, r_avoid.Max, IM_COL32(255, 0, 255, 255));
+
return FindBestWindowPosForPopupEx(tooltip_pos, window->Size, &window->AutoPosLastDirection, r_outer, r_avoid, ImGuiPopupPositionPolicy_Tooltip);
}
IM_ASSERT(0);
@@ -12282,7 +12968,7 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
// When entering through a NavFlattened border, we consider child window items as fully clipped for scoring
if (window->ParentWindow == g.NavWindow)
{
- IM_ASSERT((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened);
+ IM_ASSERT((window->ChildFlags | g.NavWindow->ChildFlags) & ImGuiChildFlags_NavFlattened);
if (!window->ClipRect.Overlaps(cand))
return false;
cand.ClipWithFull(window->ClipRect); // This allows the scored item to not overlap other candidates in the parent window
@@ -12307,6 +12993,9 @@ static bool ImGui::NavScoreItem(ImGuiNavItemData* result)
if (dbx != 0.0f || dby != 0.0f)
{
// For non-overlapping boxes, use distance between boxes
+ // FIXME-NAV: Quadrant may be incorrect because of (1) dbx bias and (2) curr.Max.y bias applied by NavBiasScoringRect() where typically curr.Max.y==curr.Min.y
+ // One typical case where this happens, with style.WindowMenuButtonPosition == ImGuiDir_Right, pressing Left to navigate from Close to Collapse tends to fail.
+ // Also see #6344. Calling ImGetDirQuadrantFromDelta() with unbiased values may be good but side-effects are plenty.
dax = dbx;
day = dby;
dist_axial = dist_box;
@@ -12585,6 +13274,7 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavWindow != NULL);
+ //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequestSubmit: dir %c, window \"%s\"\n", "-WENS"[move_dir + 1], g.NavWindow->Name);
if (move_flags & ImGuiNavMoveFlags_IsTabbing)
move_flags |= ImGuiNavMoveFlags_AllowCurrentNavId;
@@ -12614,7 +13304,7 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
}
// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere
-void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data)
+void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiTreeNodeStackData* tree_node_data)
{
ImGuiContext& g = *GImGui;
g.NavMoveScoringItems = false;
@@ -12837,6 +13527,7 @@ static void ImGui::NavUpdate()
// Process navigation init request (select first/default focus)
g.NavJustMovedToId = 0;
+ g.NavJustMovedToFocusScopeId = g.NavJustMovedFromFocusScopeId = 0;
if (g.NavInitResult.ID != 0)
NavInitRequestApplyResult();
g.NavInitRequest = false;
@@ -12989,9 +13680,12 @@ void ImGui::NavInitRequestApplyResult()
ImGuiNavItemData* result = &g.NavInitResult;
if (g.NavId != result->ID)
{
+ g.NavJustMovedFromFocusScopeId = g.NavFocusScopeId;
g.NavJustMovedToId = result->ID;
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = 0;
+ g.NavJustMovedToIsTabbing = false;
+ g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
}
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
@@ -13245,9 +13939,13 @@ void ImGui::NavMoveRequestApplyResult()
// PageUp/PageDown however sets always set NavJustMovedTo (vs Home/End which doesn't) mimicking Windows behavior.
if ((g.NavId != result->ID || (g.NavMoveFlags & ImGuiNavMoveFlags_IsPageMove)) && (g.NavMoveFlags & ImGuiNavMoveFlags_NoSelect) == 0)
{
+ g.NavJustMovedFromFocusScopeId = g.NavFocusScopeId;
g.NavJustMovedToId = result->ID;
g.NavJustMovedToFocusScopeId = result->FocusScopeId;
g.NavJustMovedToKeyMods = g.NavMoveKeyMods;
+ g.NavJustMovedToIsTabbing = (g.NavMoveFlags & ImGuiNavMoveFlags_IsTabbing) != 0;
+ g.NavJustMovedToHasSelectionData = (result->InFlags & ImGuiItemFlags_HasSelectionUserData) != 0;
+ //IMGUI_DEBUG_LOG_NAV("[nav] NavJustMovedFromFocusScopeId = 0x%08X, NavJustMovedToFocusScopeId = 0x%08X\n", g.NavJustMovedFromFocusScopeId, g.NavJustMovedToFocusScopeId);
}
// Apply new NavID/Focus
@@ -13609,9 +14307,11 @@ static void ImGui::NavUpdateWindowing()
// Keyboard: Press and Release ALT to toggle menu layer
const ImGuiKey windowing_toggle_keys[] = { ImGuiKey_LeftAlt, ImGuiKey_RightAlt };
+ bool windowing_toggle_layer_start = false;
for (ImGuiKey windowing_toggle_key : windowing_toggle_keys)
if (nav_keyboard_active && IsKeyPressed(windowing_toggle_key, 0, ImGuiKeyOwner_NoOwner))
{
+ windowing_toggle_layer_start = true;
g.NavWindowingToggleLayer = true;
g.NavWindowingToggleKey = windowing_toggle_key;
g.NavInputSource = ImGuiInputSource_Keyboard;
@@ -13625,7 +14325,9 @@ static void ImGui::NavUpdateWindowing()
// We cancel toggling nav layer if an owner has claimed the key.
if (io.InputQueueCharacters.Size > 0 || io.KeyCtrl || io.KeyShift || io.KeySuper)
g.NavWindowingToggleLayer = false;
- if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false)
+ else if (windowing_toggle_layer_start == false && g.LastKeyboardKeyPressTime == g.Time)
+ g.NavWindowingToggleLayer = false;
+ else if (TestKeyOwner(g.NavWindowingToggleKey, ImGuiKeyOwner_NoOwner) == false || TestKeyOwner(ImGuiMod_Alt, ImGuiKeyOwner_NoOwner) == false)
g.NavWindowingToggleLayer = false;
// Apply layer toggle on Alt release
@@ -13754,6 +14456,8 @@ void ImGui::NavUpdateWindowingOverlay()
SetNextWindowPos(viewport->GetCenter(), ImGuiCond_Always, ImVec2(0.5f, 0.5f));
PushStyleVar(ImGuiStyleVar_WindowPadding, g.Style.WindowPadding * 2.0f);
Begin("###NavWindowingList", NULL, ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings);
+ if (g.ContextName[0] != 0)
+ SeparatorText(g.ContextName);
for (int n = g.WindowsFocusOrder.Size - 1; n >= 0; n--)
{
ImGuiWindow* window = g.WindowsFocusOrder[n];
@@ -13783,6 +14487,8 @@ bool ImGui::IsDragDropActive()
void ImGui::ClearDragDrop()
{
ImGuiContext& g = *GImGui;
+ if (g.DragDropActive)
+ IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] ClearDragDrop()\n");
g.DragDropActive = false;
g.DragDropPayload.Clear();
g.DragDropAcceptFlags = ImGuiDragDropFlags_None;
@@ -13821,7 +14527,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
bool source_drag_active = false;
ImGuiID source_id = 0;
ImGuiID source_parent_id = 0;
- if (!(flags & ImGuiDragDropFlags_SourceExtern))
+ if ((flags & ImGuiDragDropFlags_SourceExtern) == 0)
{
source_id = g.LastItemData.ID;
if (source_id != 0)
@@ -13877,49 +14583,55 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
}
else
{
+ // When ImGuiDragDropFlags_SourceExtern is set:
window = NULL;
source_id = ImHashStr("#SourceExtern");
source_drag_active = true;
+ mouse_button = g.IO.MouseDown[0] ? 0 : -1;
+ KeepAliveID(source_id);
+ SetActiveID(source_id, NULL);
}
IM_ASSERT(g.DragDropWithinTarget == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
- if (source_drag_active)
- {
- if (!g.DragDropActive)
- {
- IM_ASSERT(source_id != 0);
- ClearDragDrop();
- ImGuiPayload& payload = g.DragDropPayload;
- payload.SourceId = source_id;
- payload.SourceParentId = source_parent_id;
- g.DragDropActive = true;
- g.DragDropSourceFlags = flags;
- g.DragDropMouseButton = mouse_button;
- if (payload.SourceId == g.ActiveId)
- g.ActiveIdNoClearOnFocusLoss = true;
- }
- g.DragDropSourceFrameCount = g.FrameCount;
- g.DragDropWithinSource = true;
+ if (!source_drag_active)
+ return false;
- if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
- {
- // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
- // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
- bool ret;
- if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
- ret = BeginTooltipHidden();
- else
- ret = BeginTooltip();
- IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
- IM_UNUSED(ret);
- }
+ // Activate drag and drop
+ if (!g.DragDropActive)
+ {
+ IM_ASSERT(source_id != 0);
+ ClearDragDrop();
+ IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] BeginDragDropSource() DragDropActive = true, source_id = 0x%08X%s\n",
+ source_id, (flags & ImGuiDragDropFlags_SourceExtern) ? " (EXTERN)" : "");
+ ImGuiPayload& payload = g.DragDropPayload;
+ payload.SourceId = source_id;
+ payload.SourceParentId = source_parent_id;
+ g.DragDropActive = true;
+ g.DragDropSourceFlags = flags;
+ g.DragDropMouseButton = mouse_button;
+ if (payload.SourceId == g.ActiveId)
+ g.ActiveIdNoClearOnFocusLoss = true;
+ }
+ g.DragDropSourceFrameCount = g.FrameCount;
+ g.DragDropWithinSource = true;
+
+ if (!(flags & ImGuiDragDropFlags_SourceNoPreviewTooltip))
+ {
+ // Target can request the Source to not display its tooltip (we use a dedicated flag to make this request explicit)
+ // We unfortunately can't just modify the source flags and skip the call to BeginTooltip, as caller may be emitting contents.
+ bool ret;
+ if (g.DragDropAcceptIdPrev && (g.DragDropAcceptFlags & ImGuiDragDropFlags_AcceptNoPreviewTooltip))
+ ret = BeginTooltipHidden();
+ else
+ ret = BeginTooltip();
+ IM_ASSERT(ret); // FIXME-NEWBEGIN: If this ever becomes false, we need to Begin("##Hidden", NULL, ImGuiWindowFlags_NoSavedSettings) + SetWindowHiddendAndSkipItemsForCurrentFrame().
+ IM_UNUSED(ret);
+ }
- if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
- g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
+ if (!(flags & ImGuiDragDropFlags_SourceNoDisableHover) && !(flags & ImGuiDragDropFlags_SourceExtern))
+ g.LastItemData.StatusFlags &= ~ImGuiItemStatusFlags_HoveredRect;
- return true;
- }
- return false;
+ return true;
}
void ImGui::EndDragDropSource()
@@ -13949,7 +14661,7 @@ bool ImGui::SetDragDropPayload(const char* type, const void* data, size_t data_s
IM_ASSERT(strlen(type) < IM_ARRAYSIZE(payload.DataType) && "Payload type can be at most 32 characters long");
IM_ASSERT((data != NULL && data_size > 0) || (data == NULL && data_size == 0));
IM_ASSERT(cond == ImGuiCond_Always || cond == ImGuiCond_Once);
- IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
+ IM_ASSERT(payload.SourceId != 0); // Not called between BeginDragDropSource() and EndDragDropSource()
if (cond == ImGuiCond_Always || payload.DataFrameCount == -1)
{
@@ -14000,7 +14712,7 @@ bool ImGui::BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id)
IM_ASSERT(g.DragDropWithinTarget == false && g.DragDropWithinSource == false); // Can't nest BeginDragDropSource() and BeginDragDropTarget()
g.DragDropTargetRect = bb;
- g.DragDropTargetClipRect = window->ClipRect; // May want to be overriden by user depending on use case?
+ g.DragDropTargetClipRect = window->ClipRect; // May want to be overridden by user depending on use case?
g.DragDropTargetId = id;
g.DragDropWithinTarget = true;
return true;
@@ -14076,11 +14788,15 @@ const ImGuiPayload* ImGui::AcceptDragDropPayload(const char* type, ImGuiDragDrop
RenderDragDropTargetRect(r, g.DragDropTargetClipRect);
g.DragDropAcceptFrameCount = g.FrameCount;
- payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
+ if ((g.DragDropSourceFlags & ImGuiDragDropFlags_SourceExtern) && g.DragDropMouseButton == -1)
+ payload.Delivery = was_accepted_previously && (g.DragDropSourceFrameCount < g.FrameCount);
+ else
+ payload.Delivery = was_accepted_previously && !IsMouseDown(g.DragDropMouseButton); // For extern drag sources affecting OS window focus, it's easier to just test !IsMouseDown() instead of IsMouseReleased()
if (!payload.Delivery && !(flags & ImGuiDragDropFlags_AcceptBeforeDelivery))
return NULL;
- //IMGUI_DEBUG_LOG("AcceptDragDropPayload(): %08X: return payload\n", g.DragDropTargetId);
+ if (payload.Delivery)
+ IMGUI_DEBUG_LOG_ACTIVEID("[dragdrop] AcceptDragDropPayload(): 0x%08X: payload delivery\n", g.DragDropTargetId);
return &payload;
}
@@ -14230,7 +14946,7 @@ void ImGui::LogBegin(ImGuiLogType type, int auto_open_depth)
IM_ASSERT(g.LogEnabled == false);
IM_ASSERT(g.LogFile == NULL);
IM_ASSERT(g.LogBuffer.empty());
- g.LogEnabled = true;
+ g.LogEnabled = g.ItemUnclipByLog = true;
g.LogType = type;
g.LogNextPrefix = g.LogNextSuffix = NULL;
g.LogDepthRef = window->DC.TreeDepth;
@@ -14329,7 +15045,7 @@ void ImGui::LogFinish()
break;
}
- g.LogEnabled = false;
+ g.LogEnabled = g.ItemUnclipByLog = false;
g.LogType = ImGuiLogType_None;
g.LogFile = NULL;
g.LogBuffer.clear();
@@ -14349,10 +15065,10 @@ void ImGui::LogButtons()
#endif
const bool log_to_file = Button("Log To File"); SameLine();
const bool log_to_clipboard = Button("Log To Clipboard"); SameLine();
- PushTabStop(false);
+ PushItemFlag(ImGuiItemFlags_NoTabStop, true);
SetNextItemWidth(80.0f);
SliderInt("Default Depth", &g.LogDepthToExpandDefault, 0, 9, NULL);
- PopTabStop();
+ PopItemFlag();
PopID();
// Start logging at the end of the function so that the buttons don't appear in the log
@@ -14909,7 +15625,7 @@ static bool ImGui::UpdateTryMergeWindowIntoHostViewports(ImGuiWindow* window)
// Translate Dear ImGui windows when a Host Viewport has been moved
// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
-void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos)
+void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& old_pos, const ImVec2& new_pos, const ImVec2& old_size, const ImVec2& new_size)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(viewport->Window == NULL && (viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows));
@@ -14923,7 +15639,7 @@ void ImGui::TranslateWindowsInViewport(ImGuiViewportP* viewport, const ImVec2& o
ImRect test_still_fit_rect(old_pos, old_pos + viewport->Size);
ImVec2 delta_pos = new_pos - old_pos;
for (ImGuiWindow* window : g.Windows) // FIXME-OPT
- if (translate_all_windows || (window->Viewport == viewport && test_still_fit_rect.Contains(window->Rect())))
+ if (translate_all_windows || (window->Viewport == viewport && (old_size == new_size || test_still_fit_rect.Contains(window->Rect()))))
TranslateWindow(window, delta_pos);
}
@@ -15079,10 +15795,18 @@ static void ImGui::UpdateViewportsNewFrame()
// Update/copy monitor info
UpdateViewportPlatformMonitor(viewport);
- // Lock down space taken by menu bars and status bars, reset the offset for functions like BeginMainMenuBar() to alter them again.
- viewport->WorkOffsetMin = viewport->BuildWorkOffsetMin;
- viewport->WorkOffsetMax = viewport->BuildWorkOffsetMax;
- viewport->BuildWorkOffsetMin = viewport->BuildWorkOffsetMax = ImVec2(0.0f, 0.0f);
+ // Lock down space taken by menu bars and status bars + query initial insets from backend
+ // Setup initial value for functions like BeginMainMenuBar(), DockSpaceOverViewport() etc.
+ viewport->WorkInsetMin = viewport->BuildWorkInsetMin;
+ viewport->WorkInsetMax = viewport->BuildWorkInsetMax;
+ viewport->BuildWorkInsetMin = viewport->BuildWorkInsetMax = ImVec2(0.0f, 0.0f);
+ if (g.PlatformIO.Platform_GetWindowWorkAreaInsets != NULL && platform_funcs_available)
+ {
+ ImVec4 insets = g.PlatformIO.Platform_GetWindowWorkAreaInsets(viewport);
+ IM_ASSERT(insets.x >= 0.0f && insets.y >= 0.0f && insets.z >= 0.0f && insets.w >= 0.0f);
+ viewport->BuildWorkInsetMin = ImVec2(insets.x, insets.y);
+ viewport->BuildWorkInsetMax = ImVec2(insets.z, insets.w);
+ }
viewport->UpdateWorkRect();
// Reset alpha every frame. Users of transparency (docking) needs to request a lower alpha back.
@@ -15092,7 +15816,7 @@ static void ImGui::UpdateViewportsNewFrame()
// (This additionally keeps windows at the same place when ImGuiConfigFlags_ViewportsEnable is toggled!)
const ImVec2 viewport_delta_pos = viewport->Pos - viewport->LastPos;
if ((viewport->Flags & ImGuiViewportFlags_CanHostOtherWindows) && (viewport_delta_pos.x != 0.0f || viewport_delta_pos.y != 0.0f))
- TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos);
+ TranslateWindowsInViewport(viewport, viewport->LastPos, viewport->Pos, viewport->LastSize, viewport->Size);
// Update DPI scale
float new_dpi_scale;
@@ -15132,6 +15856,10 @@ static void ImGui::UpdateViewportsNewFrame()
g.PlatformMonitorsFullWorkRect.Add(monitor->WorkPos);
g.PlatformMonitorsFullWorkRect.Add(monitor->WorkPos + monitor->WorkSize);
}
+ else
+ {
+ g.FallbackMonitor = g.PlatformIO.Monitors[0];
+ }
for (ImGuiPlatformMonitor& monitor : g.PlatformIO.Monitors)
{
g.PlatformMonitorsFullWorkRect.Add(monitor.WorkPos);
@@ -15198,6 +15926,7 @@ static void ImGui::UpdateViewportsEndFrame()
{
ImGuiViewportP* viewport = g.Viewports[i];
viewport->LastPos = viewport->Pos;
+ viewport->LastSize = viewport->Size;
if (viewport->LastFrameActive < g.FrameCount || viewport->Size.x <= 0.0f || viewport->Size.y <= 0.0f)
if (i > 0) // Always include main viewport in the list
continue;
@@ -15244,7 +15973,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
viewport->ID = id;
viewport->Idx = g.Viewports.Size;
viewport->Pos = viewport->LastPos = pos;
- viewport->Size = size;
+ viewport->Size = viewport->LastSize = size;
viewport->Flags = flags;
UpdateViewportPlatformMonitor(viewport);
g.Viewports.push_back(viewport);
@@ -17651,6 +18380,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Begin tab bar
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons);
tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode;// | ImGuiTabBarFlags_FittingPolicyScroll;
+ tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
if (!host_window->Collapsed && is_focused)
tab_bar_flags |= ImGuiTabBarFlags_IsFocused;
tab_bar->ID = GetID("#TabBar");
@@ -18134,7 +18864,7 @@ static void ImGui::DockNodePreviewDockRender(ImGuiWindow* host_window, ImGuiDock
ImRect tab_bb(tab_pos.x, tab_pos.y, tab_pos.x + tab_size.x, tab_pos.y + tab_size.y);
tab_pos.x += tab_size.x + g.Style.ItemInnerSpacing.x;
const ImU32 overlay_col_text = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_Text]);
- const ImU32 overlay_col_tabs = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_TabActive]);
+ const ImU32 overlay_col_tabs = GetColorU32(payload_window->DockStyle.Colors[ImGuiWindowDockStyleCol_TabSelected]);
PushStyleColor(ImGuiCol_Text, overlay_col_text);
for (int overlay_n = 0; overlay_n < overlay_draw_lists_count; overlay_n++)
{
@@ -19393,7 +20123,8 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
bool is_drag_docking = (g.IO.ConfigDockingWithShift) || ImRect(0, 0, window->SizeFull.x, GetFrameHeight()).Contains(g.ActiveIdClickOffset); // FIXME-DOCKING: Need to make this stateful and explicit
- if (is_drag_docking && BeginDragDropSource(ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_SourceAutoExpirePayload))
+ ImGuiDragDropFlags drag_drop_flags = ImGuiDragDropFlags_SourceNoPreviewTooltip | ImGuiDragDropFlags_SourceNoHoldToOpenOthers | ImGuiDragDropFlags_PayloadAutoExpire | ImGuiDragDropFlags_PayloadNoCrossContext | ImGuiDragDropFlags_PayloadNoCrossProcess;
+ if (is_drag_docking && BeginDragDropSource(drag_drop_flags))
{
SetDragDropPayload(IMGUI_PAYLOAD_TYPE_WINDOW, &window, sizeof(window));
EndDragDropSource();
@@ -19711,6 +20442,10 @@ static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettings
//-----------------------------------------------------------------------------
// [SECTION] PLATFORM DEPENDENT HELPERS
//-----------------------------------------------------------------------------
+// - Default clipboard handlers
+// - Default shell function handlers
+// - Default IME handlers
+//-----------------------------------------------------------------------------
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
@@ -19721,9 +20456,9 @@ static void ImGui::DockSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettings
// Win32 clipboard implementation
// We use g.ClipboardHandlerData for temporary storage to ensure it is freed on Shutdown()
-static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
+static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx)
{
- ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
+ ImGuiContext& g = *ctx;
g.ClipboardHandlerData.clear();
if (!::OpenClipboard(NULL))
return NULL;
@@ -19744,7 +20479,7 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
return g.ClipboardHandlerData.Data;
}
-static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
+static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text)
{
if (!::OpenClipboard(NULL))
return;
@@ -19771,7 +20506,7 @@ static PasteboardRef main_clipboard = 0;
// OSX clipboard implementation
// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
-static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
+static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext*, const char* text)
{
if (!main_clipboard)
PasteboardCreate(kPasteboardClipboard, &main_clipboard);
@@ -19784,9 +20519,9 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
}
}
-static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
+static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx)
{
- ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
+ ImGuiContext& g = *ctx;
if (!main_clipboard)
PasteboardCreate(kPasteboardClipboard, &main_clipboard);
PasteboardSynchronize(main_clipboard);
@@ -19820,15 +20555,15 @@ static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
#else
// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
-static const char* GetClipboardTextFn_DefaultImpl(void* user_data_ctx)
+static const char* Platform_GetClipboardTextFn_DefaultImpl(ImGuiContext* ctx)
{
- ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
+ ImGuiContext& g = *ctx;
return g.ClipboardHandlerData.empty() ? NULL : g.ClipboardHandlerData.begin();
}
-static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text)
+static void Platform_SetClipboardTextFn_DefaultImpl(ImGuiContext* ctx, const char* text)
{
- ImGuiContext& g = *(ImGuiContext*)user_data_ctx;
+ ImGuiContext& g = *ctx;
g.ClipboardHandlerData.clear();
const char* text_end = text + strlen(text);
g.ClipboardHandlerData.resize((int)(text_end - text) + 1);
@@ -19836,8 +20571,62 @@ static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text
g.ClipboardHandlerData[(int)(text_end - text)] = 0;
}
+#endif // Default clipboard handlers
+
+//-----------------------------------------------------------------------------
+
+#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
+#if defined(__APPLE__) && TARGET_OS_IPHONE
+#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
#endif
+#if defined(_WIN32) && defined(IMGUI_DISABLE_WIN32_FUNCTIONS)
+#define IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
+#endif
+#endif
+
+#ifndef IMGUI_DISABLE_DEFAULT_SHELL_FUNCTIONS
+#ifdef _WIN32
+#include <shellapi.h> // ShellExecuteA()
+#ifdef _MSC_VER
+#pragma comment(lib, "shell32")
+#endif
+static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path)
+{
+ return (INT_PTR)::ShellExecuteA(NULL, "open", path, NULL, NULL, SW_SHOWDEFAULT) > 32;
+}
+#else
+#include <sys/wait.h>
+#include <unistd.h>
+static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char* path)
+{
+#if defined(__APPLE__)
+ const char* args[] { "open", "--", path, NULL };
+#else
+ const char* args[] { "xdg-open", path, NULL };
+#endif
+ pid_t pid = fork();
+ if (pid < 0)
+ return false;
+ if (!pid)
+ {
+ execvp(args[0], const_cast<char **>(args));
+ exit(-1);
+ }
+ else
+ {
+ int status;
+ waitpid(pid, &status, 0);
+ return WEXITSTATUS(status) == 0;
+ }
+}
+#endif
+#else
+static bool Platform_OpenInShellFn_DefaultImpl(ImGuiContext*, const char*) { return false; }
+#endif // Default shell handlers
+
+//-----------------------------------------------------------------------------
+
// Win32 API IME support (for Asian languages, etc.)
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
@@ -19846,7 +20635,7 @@ static void SetClipboardTextFn_DefaultImpl(void* user_data_ctx, const char* text
#pragma comment(lib, "imm32")
#endif
-static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatformImeData* data)
+static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport* viewport, ImGuiPlatformImeData* data)
{
// Notify OS Input Method Editor of text input position
HWND hwnd = (HWND)viewport->PlatformHandleRaw;
@@ -19872,9 +20661,9 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport* viewport, ImGuiPlatf
#else
-static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeData*) {}
+static void Platform_SetImeDataFn_DefaultImpl(ImGuiContext*, ImGuiViewport*, ImGuiPlatformImeData*) {}
-#endif
+#endif // Default IME handlers
//-----------------------------------------------------------------------------
// [SECTION] METRICS/DEBUGGER WINDOW
@@ -20079,7 +20868,7 @@ void ImGui::UpdateDebugToolFlashStyleColor()
ImGuiContext& g = *GImGui;
if (g.DebugFlashStyleColorTime <= 0.0f)
return;
- ColorConvertHSVtoRGB(cosf(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z);
+ ColorConvertHSVtoRGB(ImCos(g.DebugFlashStyleColorTime * 6.0f) * 0.5f + 0.5f, 0.5f, 0.5f, g.Style.Colors[g.DebugFlashStyleColorIdx].x, g.Style.Colors[g.DebugFlashStyleColorIdx].y, g.Style.Colors[g.DebugFlashStyleColorIdx].z);
g.Style.Colors[g.DebugFlashStyleColorIdx].w = 1.0f;
if ((g.DebugFlashStyleColorTime -= g.IO.DeltaTime) <= 0.0f)
DebugFlashStyleColorStop();
@@ -20139,7 +20928,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
DebugBreakClearData();
// Basic info
- Text("Dear ImGui %s", GetVersion());
+ Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
+ if (g.ContextName[0] != 0)
+ {
+ SameLine();
+ Text("(Context Name: \"%s\")", g.ContextName);
+ }
Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
Text("%d vertices, %d indices (%d triangles)", io.MetricsRenderVertices, io.MetricsRenderIndices, io.MetricsRenderIndices / 3);
Text("%d visible windows, %d current allocations", io.MetricsRenderWindows, g.DebugAllocInfo.TotalAllocCount - g.DebugAllocInfo.TotalFreeCount);
@@ -20356,14 +21150,11 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
for (int i = 0; i < g.PlatformIO.Monitors.Size; i++)
{
- const ImGuiPlatformMonitor& mon = g.PlatformIO.Monitors[i];
- BulletText("Monitor #%d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)",
- i, mon.DpiScale * 100.0f,
- mon.MainPos.x, mon.MainPos.y, mon.MainPos.x + mon.MainSize.x, mon.MainPos.y + mon.MainSize.y, mon.MainSize.x, mon.MainSize.y,
- mon.WorkPos.x, mon.WorkPos.y, mon.WorkPos.x + mon.WorkSize.x, mon.WorkPos.y + mon.WorkSize.y, mon.WorkSize.x, mon.WorkSize.y);
+ DebugNodePlatformMonitor(&g.PlatformIO.Monitors[i], "Monitor", i);
if (IsItemHovered())
cfg->HighlightMonitorIdx = i;
}
+ DebugNodePlatformMonitor(&g.FallbackMonitor, "Fallback", 0);
TreePop();
}
@@ -20458,6 +21249,17 @@ void ImGui::ShowMetricsWindow(bool* p_open)
TreePop();
}
+ // Details for MultiSelect
+ if (TreeNode("MultiSelect", "MultiSelect (%d)", g.MultiSelectStorage.GetAliveCount()))
+ {
+ ImGuiBoxSelectState* bs = &g.BoxSelectState;
+ BulletText("BoxSelect ID=0x%08X, Starting = %d, Active %d", bs->ID, bs->IsStarting, bs->IsActive);
+ for (int n = 0; n < g.MultiSelectStorage.GetMapSize(); n++)
+ if (ImGuiMultiSelectState* state = g.MultiSelectStorage.TryGetMapData(n))
+ DebugNodeMultiSelectState(state);
+ TreePop();
+ }
+
// Details for Docking
#ifdef IMGUI_HAS_DOCK
if (TreeNode("Docking"))
@@ -20560,7 +21362,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
for (int n = buf_size - 1; n >= 0; n--)
{
ImGuiDebugAllocEntry* entry = &info->LastEntriesBuf[(info->LastEntriesIdx - n + buf_size) % buf_size];
- BulletText("Frame %06d: %+3d ( %2d malloc, %2d free )%s", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount, (n == 0) ? " (most recent)" : "");
+ BulletText("Frame %06d: %+3d ( %2d alloc, %2d free )", entry->FrameCount, entry->AllocCount - entry->FreeCount, entry->AllocCount, entry->FreeCount);
+ if (n == 0)
+ {
+ SameLine();
+ Text("<- %d frames ago", g.FrameCount - entry->FrameCount);
+ }
}
TreePop();
}
@@ -21184,8 +21991,11 @@ void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
return;
- for (const ImGuiStorage::ImGuiStoragePair& p : storage->Data)
+ for (const ImGuiStoragePair& p : storage->Data)
+ {
BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
+ DebugLocateItemOnHover(p.key);
+ }
TreePop();
}
@@ -21240,9 +22050,9 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport)
if (open)
{
ImGuiWindowFlags flags = viewport->Flags;
- BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Offset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%",
+ BulletText("Main Pos: (%.0f,%.0f), Size: (%.0f,%.0f)\nWorkArea Inset Left: %.0f Top: %.0f, Right: %.0f, Bottom: %.0f\nMonitor: %d, DpiScale: %.0f%%",
viewport->Pos.x, viewport->Pos.y, viewport->Size.x, viewport->Size.y,
- viewport->WorkOffsetMin.x, viewport->WorkOffsetMin.y, viewport->WorkOffsetMax.x, viewport->WorkOffsetMax.y,
+ viewport->WorkInsetMin.x, viewport->WorkInsetMin.y, viewport->WorkInsetMax.x, viewport->WorkInsetMax.y,
viewport->PlatformMonitor, viewport->DpiScale * 100.0f);
if (viewport->Idx > 0) { SameLine(); if (SmallButton("Reset Pos")) { viewport->Pos = ImVec2(200, 200); viewport->UpdateWorkRect(); if (viewport->Window) viewport->Window->Pos = viewport->Pos; } }
BulletText("Flags: 0x%04X =%s%s%s%s%s%s%s%s%s%s%s%s%s", viewport->Flags,
@@ -21266,6 +22076,14 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport)
}
}
+void ImGui::DebugNodePlatformMonitor(ImGuiPlatformMonitor* monitor, const char* label, int idx)
+{
+ BulletText("%s %d: DPI %.0f%%\n MainMin (%.0f,%.0f), MainMax (%.0f,%.0f), MainSize (%.0f,%.0f)\n WorkMin (%.0f,%.0f), WorkMax (%.0f,%.0f), WorkSize (%.0f,%.0f)",
+ label, idx, monitor->DpiScale * 100.0f,
+ monitor->MainPos.x, monitor->MainPos.y, monitor->MainPos.x + monitor->MainSize.x, monitor->MainPos.y + monitor->MainSize.y, monitor->MainSize.x, monitor->MainSize.y,
+ monitor->WorkPos.x, monitor->WorkPos.y, monitor->WorkPos.x + monitor->WorkSize.x, monitor->WorkPos.y + monitor->WorkSize.y, monitor->WorkSize.x, monitor->WorkSize.y);
+}
+
void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
{
if (window == NULL)
@@ -21298,6 +22116,12 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
+ if (flags & ImGuiWindowFlags_ChildWindow)
+ BulletText("ChildFlags: 0x%08X (%s%s%s%s..)", window->ChildFlags,
+ (window->ChildFlags & ImGuiChildFlags_Borders) ? "Borders " : "",
+ (window->ChildFlags & ImGuiChildFlags_ResizeX) ? "ResizeX " : "",
+ (window->ChildFlags & ImGuiChildFlags_ResizeY) ? "ResizeY " : "",
+ (window->ChildFlags & ImGuiChildFlags_NavFlattened) ? "NavFlattened " : "");
BulletText("WindowClassId: 0x%08X", window->WindowClass.ClassId);
BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f) Scrollbar:%s%s", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y, window->ScrollbarX ? "X" : "", window->ScrollbarY ? "Y" : "");
BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
@@ -21394,14 +22218,20 @@ void ImGui::DebugLogV(const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
const int old_size = g.DebugLogBuf.size();
- g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
+ if (g.ContextName[0] != 0)
+ g.DebugLogBuf.appendf("[%s] [%05d] ", g.ContextName, g.FrameCount);
+ else
+ g.DebugLogBuf.appendf("[%05d] ", g.FrameCount);
g.DebugLogBuf.appendfv(fmt, args);
g.DebugLogIndex.append(g.DebugLogBuf.c_str(), old_size, g.DebugLogBuf.size());
if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY)
IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size);
#ifdef IMGUI_ENABLE_TEST_ENGINE
+ // IMGUI_TEST_ENGINE_LOG() adds a trailing \n automatically
+ const int new_size = g.DebugLogBuf.size();
+ const bool trailing_carriage_return = (g.DebugLogBuf[new_size - 1] == '\n');
if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTestEngine)
- IMGUI_TEST_ENGINE_LOG("%s", g.DebugLogBuf.begin() + old_size);
+ IMGUI_TEST_ENGINE_LOG("%.*s", new_size - old_size - (trailing_carriage_return ? 1 : 0), g.DebugLogBuf.begin() + old_size);
#endif
}
@@ -21411,7 +22241,7 @@ static void SameLineOrWrap(const ImVec2& size)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 pos(window->DC.CursorPosPrevLine.x + g.Style.ItemSpacing.x, window->DC.CursorPosPrevLine.y);
- if (window->ClipRect.Contains(ImRect(pos, pos + size)))
+ if (window->WorkRect.Contains(ImRect(pos, pos + size)))
ImGui::SameLine();
}
@@ -21420,18 +22250,30 @@ static void ShowDebugLogFlag(const char* name, ImGuiDebugLogFlags flags)
ImGuiContext& g = *GImGui;
ImVec2 size(ImGui::GetFrameHeight() + g.Style.ItemInnerSpacing.x + ImGui::CalcTextSize(name).x, ImGui::GetFrameHeight());
SameLineOrWrap(size); // FIXME-LAYOUT: To be done automatically once we rework ItemSize/ItemAdd into ItemLayout.
+
+ bool highlight_errors = (flags == ImGuiDebugLogFlags_EventError && g.DebugLogSkippedErrors > 0);
+ if (highlight_errors)
+ ImGui::PushStyleColor(ImGuiCol_Text, ImLerp(g.Style.Colors[ImGuiCol_Text], ImVec4(1.0f, 0.0f, 0.0f, 1.0f), 0.30f));
if (ImGui::CheckboxFlags(name, &g.DebugLogFlags, flags) && g.IO.KeyShift && (g.DebugLogFlags & flags) != 0)
{
g.DebugLogAutoDisableFrames = 2;
g.DebugLogAutoDisableFlags |= flags;
}
- ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)");
+ if (highlight_errors)
+ {
+ ImGui::PopStyleColor();
+ ImGui::SetItemTooltip("%d past errors skipped.", g.DebugLogSkippedErrors);
+ }
+ else
+ {
+ ImGui::SetItemTooltip("Hold SHIFT when clicking to enable for 2 frames only (useful for spammy log entries)");
+ }
}
void ImGui::ShowDebugLogWindow(bool* p_open)
{
ImGuiContext& g = *GImGui;
- if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0)
SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver);
if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1)
{
@@ -21443,6 +22285,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
CheckboxFlags("All", &g.DebugLogFlags, all_enable_flags);
SetItemTooltip("(except InputRouting which is spammy)");
+ ShowDebugLogFlag("Errors", ImGuiDebugLogFlags_EventError);
ShowDebugLogFlag("ActiveId", ImGuiDebugLogFlags_EventActiveId);
ShowDebugLogFlag("Clipper", ImGuiDebugLogFlags_EventClipper);
ShowDebugLogFlag("Docking", ImGuiDebugLogFlags_EventDocking);
@@ -21450,7 +22293,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
ShowDebugLogFlag("IO", ImGuiDebugLogFlags_EventIO);
ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav);
ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup);
- //ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection);
+ ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection);
ShowDebugLogFlag("Viewport", ImGuiDebugLogFlags_EventViewport);
ShowDebugLogFlag("InputRouting", ImGuiDebugLogFlags_EventInputRouting);
@@ -21458,11 +22301,28 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
{
g.DebugLogBuf.clear();
g.DebugLogIndex.clear();
+ g.DebugLogSkippedErrors = 0;
}
SameLine();
if (SmallButton("Copy"))
SetClipboardText(g.DebugLogBuf.c_str());
- BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
+ SameLine();
+ if (SmallButton("Configure Outputs.."))
+ OpenPopup("Outputs");
+ if (BeginPopup("Outputs"))
+ {
+ CheckboxFlags("OutputToTTY", &g.DebugLogFlags, ImGuiDebugLogFlags_OutputToTTY);
+#ifndef IMGUI_ENABLE_TEST_ENGINE
+ BeginDisabled();
+#endif
+ CheckboxFlags("OutputToTestEngine", &g.DebugLogFlags, ImGuiDebugLogFlags_OutputToTestEngine);
+#ifndef IMGUI_ENABLE_TEST_ENGINE
+ EndDisabled();
+#endif
+ EndPopup();
+ }
+
+ BeginChild("##log", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
const ImGuiDebugLogFlags backup_log_flags = g.DebugLogFlags;
g.DebugLogFlags &= ~ImGuiDebugLogFlags_EventClipper;
@@ -21471,25 +22331,7 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
clipper.Begin(g.DebugLogIndex.size());
while (clipper.Step())
for (int line_no = clipper.DisplayStart; line_no < clipper.DisplayEnd; line_no++)
- {
- const char* line_begin = g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no);
- const char* line_end = g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no);
- TextUnformatted(line_begin, line_end); // Display line
- ImRect text_rect = g.LastItemData.Rect;
- if (IsItemHovered())
- for (const char* p = line_begin; p <= line_end - 10; p++) // Search for 0x???????? identifiers
- {
- ImGuiID id = 0;
- if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1)
- continue;
- ImVec2 p0 = CalcTextSize(line_begin, p);
- ImVec2 p1 = CalcTextSize(p, p + 10);
- g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
- if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true))
- DebugLocateItemOnHover(id);
- p += 10;
- }
- }
+ DebugTextUnformattedWithLocateItem(g.DebugLogIndex.get_line_begin(g.DebugLogBuf.c_str(), line_no), g.DebugLogIndex.get_line_end(g.DebugLogBuf.c_str(), line_no));
g.DebugLogFlags = backup_log_flags;
if (GetScrollY() >= GetScrollMaxY())
SetScrollHereY(1.0f);
@@ -21498,6 +22340,28 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
End();
}
+// Display line, search for 0xXXXXXXXX identifiers and call DebugLocateItemOnHover() when hovered.
+void ImGui::DebugTextUnformattedWithLocateItem(const char* line_begin, const char* line_end)
+{
+ TextUnformatted(line_begin, line_end);
+ if (!IsItemHovered())
+ return;
+ ImGuiContext& g = *GImGui;
+ ImRect text_rect = g.LastItemData.Rect;
+ for (const char* p = line_begin; p <= line_end - 10; p++)
+ {
+ ImGuiID id = 0;
+ if (p[0] != '0' || (p[1] != 'x' && p[1] != 'X') || sscanf(p + 2, "%X", &id) != 1 || ImCharIsXdigitA(p[10]))
+ continue;
+ ImVec2 p0 = CalcTextSize(line_begin, p);
+ ImVec2 p1 = CalcTextSize(p, p + 10);
+ g.LastItemData.Rect = ImRect(text_rect.Min + ImVec2(p0.x, 0.0f), text_rect.Min + ImVec2(p0.x + p1.x, p1.y));
+ if (IsMouseHoveringRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, true))
+ DebugLocateItemOnHover(id);
+ p += 10;
+ }
+}
+
//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, ID STACK TOOL)
//-----------------------------------------------------------------------------
@@ -21730,7 +22594,7 @@ static int StackToolFormatLevelInfo(ImGuiIDStackTool* tool, int n, bool format_f
void ImGui::ShowIDStackToolWindow(bool* p_open)
{
ImGuiContext& g = *GImGui;
- if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0)
SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 8.0f), ImGuiCond_FirstUseEver);
if (!Begin("Dear ImGui ID Stack Tool", p_open) || GetCurrentWindow()->BeginCount > 1)
{
@@ -21818,8 +22682,6 @@ void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}
void ImGui::DebugNodeViewport(ImGuiViewportP*) {}
-void ImGui::DebugLog(const char*, ...) {}
-void ImGui::DebugLogV(const char*, va_list) {}
void ImGui::ShowDebugLogWindow(bool*) {}
void ImGui::ShowIDStackToolWindow(bool*) {}
void ImGui::DebugStartItemPicker() {}
diff --git a/backends/imgui/imgui.h b/backends/imgui/imgui.h
index f6af5da13c0..24a004b670a 100644
--- a/backends/imgui/imgui.h
+++ b/backends/imgui/imgui.h
@@ -1,16 +1,17 @@
-// dear imgui, v1.90.7 WIP
+// dear imgui, v1.91.3
// (headers)
// Help:
// - See links below.
// - Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp. All applications in examples/ are doing that.
// - Read top of imgui.cpp for more details, links and comments.
+// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
// Resources:
// - FAQ ........................ https://dearimgui.com/faq (in repository as docs/FAQ.md)
// - Homepage ................... https://github.com/ocornut/imgui
// - Releases & changelog ....... https://github.com/ocornut/imgui/releases
-// - Gallery .................... https://github.com/ocornut/imgui/issues/7503 (please post your screenshots/video there!)
+// - Gallery .................... https://github.com/ocornut/imgui/issues?q=label%3Agallery (please post your screenshots/video there!)
// - Wiki ....................... https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Getting Started https://github.com/ocornut/imgui/wiki/Getting-Started (how to integrate in an existing app by adding ~25 lines of code)
// - Third-party Extensions https://github.com/ocornut/imgui/wiki/Useful-Extensions (ImPlot & many more)
@@ -27,8 +28,8 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
-#define IMGUI_VERSION "1.90.7 WIP"
-#define IMGUI_VERSION_NUM 19067
+#define IMGUI_VERSION "1.91.3"
+#define IMGUI_VERSION_NUM 19130
#define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch
@@ -41,15 +42,16 @@ Index of this file:
// [SECTION] Dear ImGui end-user API functions
// [SECTION] Flags & Enumerations
// [SECTION] Tables API flags and structures (ImGuiTableFlags, ImGuiTableColumnFlags, ImGuiTableRowFlags, ImGuiTableBgTarget, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs)
-// [SECTION] Helpers: Memory allocations macros, ImVector<>
+// [SECTION] Helpers: Debug log, Memory allocations macros, ImVector<>
// [SECTION] ImGuiStyle
// [SECTION] ImGuiIO
// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload)
// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, Math Operators, ImColor)
+// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiMultiSelectIO, ImGuiSelectionRequest, ImGuiSelectionBasicStorage, ImGuiSelectionExternalStorage)
// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawFlags, ImDrawListFlags, ImDrawList, ImDrawData)
// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
// [SECTION] Viewports (ImGuiViewportFlags, ImGuiViewport)
-// [SECTION] Platform Dependent Interfaces (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiPlatformImeData)
+// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData)
// [SECTION] Obsolete functions and types
*/
@@ -147,6 +149,17 @@ Index of this file:
// [SECTION] Forward declarations and basic types
//-----------------------------------------------------------------------------
+// Scalar data types
+typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string)
+typedef signed char ImS8; // 8-bit signed integer
+typedef unsigned char ImU8; // 8-bit unsigned integer
+typedef signed short ImS16; // 16-bit signed integer
+typedef unsigned short ImU16; // 16-bit unsigned integer
+typedef signed int ImS32; // 32-bit signed integer == int
+typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors)
+typedef signed long long ImS64; // 64-bit signed integer
+typedef unsigned long long ImU64; // 64-bit unsigned integer
+
// Forward declarations
struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit()
struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)
@@ -163,17 +176,22 @@ struct ImFontGlyph; // A single font glyph (code point + coordin
struct ImFontGlyphRangesBuilder; // Helper to build glyph ranges from text/string data
struct ImColor; // Helper functions to create a color that can be converted to either u32 or float4 (*OBSOLETE* please avoid using)
struct ImGuiContext; // Dear ImGui context (opaque structure, unless including imgui_internal.h)
-struct ImGuiIO; // Main configuration and I/O between your application and ImGui
+struct ImGuiIO; // Main configuration and I/O between your application and ImGui (also see: ImGuiPlatformIO)
struct ImGuiInputTextCallbackData; // Shared state of InputText() when using custom ImGuiInputTextCallback (rare/advanced use)
struct ImGuiKeyData; // Storage for ImGuiIO and IsKeyDown(), IsKeyPressed() etc functions.
struct ImGuiListClipper; // Helper to manually clip large list of items
+struct ImGuiMultiSelectIO; // Structure to interact with a BeginMultiSelect()/EndMultiSelect() block
struct ImGuiOnceUponAFrame; // Helper for running a block of code not more than once a frame
struct ImGuiPayload; // User data payload for drag and drop operations
-struct ImGuiPlatformIO; // Multi-viewport support: interface for Platform/Renderer backends + viewports to render
+struct ImGuiPlatformIO; // Interface between platform/renderer backends and ImGui (e.g. Clipboard, IME, Multi-Viewport support). Extends ImGuiIO.
+struct ImGuiPlatformImeData; // Platform IME data for io.PlatformSetImeDataFn() function.
struct ImGuiPlatformMonitor; // Multi-viewport support: user-provided bounds for each connected monitor/display. Used when positioning popups and tooltips to avoid them straddling monitors
-struct ImGuiPlatformImeData; // Platform IME data for io.SetPlatformImeDataFn() function.
+struct ImGuiSelectionBasicStorage; // Optional helper to store multi-selection state + apply multi-selection requests.
+struct ImGuiSelectionExternalStorage;//Optional helper to apply multi-selection requests to existing randomly accessible storage.
+struct ImGuiSelectionRequest; // A selection request (stored in ImGuiMultiSelectIO)
struct ImGuiSizeCallbackData; // Callback data when using SetNextWindowSizeConstraints() (rare/advanced use)
-struct ImGuiStorage; // Helper for key->value storage
+struct ImGuiStorage; // Helper for key->value storage (container sorted by key)
+struct ImGuiStoragePair; // Helper for key->value storage (pair)
struct ImGuiStyle; // Runtime data for styling/colors
struct ImGuiTableSortSpecs; // Sorting specifications for a table (often handling sort specs for a single column, occasionally more)
struct ImGuiTableColumnSortSpecs; // Sorting specification for one column of a table
@@ -188,15 +206,15 @@ struct ImGuiWindowClass; // Window class (rare/advanced uses: provide
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
+enum ImGuiDir : int; // -> enum ImGuiDir // Enum: A cardinal direction (Left, Right, Up, Down)
enum ImGuiKey : int; // -> enum ImGuiKey // Enum: A key identifier (ImGuiKey_XXX or ImGuiMod_XXX value)
enum ImGuiMouseSource : int; // -> enum ImGuiMouseSource // Enum; A mouse input source identifier (Mouse, TouchScreen, Pen)
+enum ImGuiSortDirection : ImU8; // -> enum ImGuiSortDirection // Enum: A sorting direction (ascending or descending)
typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
-typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction
typedef int ImGuiMouseButton; // -> enum ImGuiMouseButton_ // Enum: A mouse button identifier (0=left, 1=right, 2=middle)
typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor shape
-typedef int ImGuiSortDirection; // -> enum ImGuiSortDirection_ // Enum: A sorting direction (ascending or descending)
typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling
typedef int ImGuiTableBgTarget; // -> enum ImGuiTableBgTarget_ // Enum: A color target for TableSetBgColor()
@@ -220,8 +238,10 @@ typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: f
typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
typedef int ImGuiInputFlags; // -> enum ImGuiInputFlags_ // Flags: for Shortcut(), SetNextItemShortcut()
typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline()
+typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), shared by all items
typedef int ImGuiKeyChord; // -> ImGuiKey | ImGuiMod_XXX // Flags: for IsKeyChordPressed(), Shortcut() etc. an ImGuiKey optionally OR-ed with one or more ImGuiMod_XXX values.
typedef int ImGuiPopupFlags; // -> enum ImGuiPopupFlags_ // Flags: for OpenPopup*(), BeginPopupContext*(), IsPopupOpen()
+typedef int ImGuiMultiSelectFlags; // -> enum ImGuiMultiSelectFlags_// Flags: for BeginMultiSelect()
typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.
typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar()
@@ -247,17 +267,6 @@ typedef void* ImTextureID; // Default: store a pointer or an integer fi
typedef unsigned short ImDrawIdx; // Default: 16-bit (for maximum compatibility with renderer backends)
#endif
-// Scalar data types
-typedef unsigned int ImGuiID;// A unique ID used by widgets (typically the result of hashing a stack of string)
-typedef signed char ImS8; // 8-bit signed integer
-typedef unsigned char ImU8; // 8-bit unsigned integer
-typedef signed short ImS16; // 16-bit signed integer
-typedef unsigned short ImU16; // 16-bit unsigned integer
-typedef signed int ImS32; // 32-bit signed integer == int
-typedef unsigned int ImU32; // 32-bit unsigned integer (often used to store packed colors)
-typedef signed long long ImS64; // 64-bit signed integer
-typedef unsigned long long ImU64; // 64-bit unsigned integer
-
// Character types
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
@@ -268,6 +277,11 @@ typedef ImWchar32 ImWchar;
typedef ImWchar16 ImWchar;
#endif
+// Multi-Selection item index or identifier when using BeginMultiSelect()
+// - Used by SetNextItemSelectionUserData() + and inside ImGuiMultiSelectIO structure.
+// - Most users are likely to use this store an item INDEX but this may be used to store a POINTER/ID as well. Read comments near ImGuiMultiSelectIO for details.
+typedef ImS64 ImGuiSelectionUserData;
+
// Callback and functions types
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
@@ -275,8 +289,8 @@ typedef void* (*ImGuiMemAllocFunc)(size_t sz, void* user_data);
typedef void (*ImGuiMemFreeFunc)(void* ptr, void* user_data); // Function signature for ImGui::SetAllocatorFunctions()
// ImVec2: 2D vector used to store positions, sizes etc. [Compile-time configurable type]
-// This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type.
-// Add '#define IMGUI_DEFINE_MATH_OPERATORS' in your imconfig.h file to benefit from courtesy maths operators for those types.
+// - This is a frequently used type in the API. Consider using IM_VEC2_CLASS_EXTRA to create implicit cast from/to our preferred type.
+// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
IM_MSVC_RUNTIME_CHECKS_OFF
struct ImVec2
{
@@ -319,7 +333,8 @@ namespace ImGui
IMGUI_API void SetCurrentContext(ImGuiContext* ctx);
// Main
- IMGUI_API ImGuiIO& GetIO(); // access the IO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags)
+ IMGUI_API ImGuiIO& GetIO(); // access the ImGuiIO structure (mouse/keyboard/gamepad inputs, time, various configuration options/flags)
+ IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // access the ImGuiPlatformIO structure (mostly hooks/functions to connect to platform/renderer and OS Clipboard, IME etc.)
IMGUI_API ImGuiStyle& GetStyle(); // access the Style structure (colors, sizes). Always use PushStyleColor(), PushStyleVar() to modify style mid-frame!
IMGUI_API void NewFrame(); // start a new Dear ImGui frame, you can submit any command from this point until Render()/EndFrame().
IMGUI_API void EndFrame(); // ends the Dear ImGui frame. automatically called by Render(). If you don't need to render data (skipping rendering) you may call EndFrame() without Render()... but you'll have wasted CPU already! If you don't need to render, better to not create any windows and not call NewFrame() at all!
@@ -361,10 +376,10 @@ namespace ImGui
// Child Windows
// - Use child windows to begin into a self-contained independent scrolling/clipping regions within a host window. Child windows can embed their own child.
// - Before 1.90 (November 2023), the "ImGuiChildFlags child_flags = 0" parameter was "bool border = false".
- // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Border == true.
+ // This API is backward compatible with old code, as we guarantee that ImGuiChildFlags_Borders == true.
// Consider updating your old code:
// BeginChild("Name", size, false) -> Begin("Name", size, 0); or Begin("Name", size, ImGuiChildFlags_None);
- // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Border);
+ // BeginChild("Name", size, true) -> Begin("Name", size, ImGuiChildFlags_Borders);
// - Manual sizing (each axis can use a different setting e.g. ImVec2(0.0f, 400.0f)):
// == 0.0f: use remaining parent window size for this axis.
// > 0.0f: use specified size for this axis.
@@ -388,10 +403,10 @@ namespace ImGui
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered and hoverable (e.g. not blocked by a popup/modal)? See ImGuiHoveredFlags_ for options. IMPORTANT: If you are trying to check whether your mouse should be dispatched to Dear ImGui or to your underlying app, you should not use this function! Use the 'io.WantCaptureMouse' boolean for that! Refer to FAQ entry "How can I tell whether to dispatch mouse/keyboard to Dear ImGui or my application?" for details.
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport.
- IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetCursorScreenPos())
- IMGUI_API ImVec2 GetWindowSize(); // get current window size (note: it is unlikely you need to use this. Consider using GetCursorScreenPos() and e.g. GetContentRegionAvail() instead)
- IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x)
- IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y)
+ IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead)
+ IMGUI_API ImVec2 GetWindowSize(); // get current window size (IT IS UNLIKELY YOU EVER NEED TO USE THIS. Consider always using GetCursorScreenPos() and GetContentRegionAvail() instead)
+ IMGUI_API float GetWindowWidth(); // get current window width (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().x.
+ IMGUI_API float GetWindowHeight(); // get current window height (IT IS UNLIKELY YOU EVER NEED TO USE THIS). Shortcut for GetWindowSize().y.
IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window.
// Window manipulation
@@ -415,14 +430,6 @@ namespace ImGui
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state
IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus.
- // Content region
- // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful.
- // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion)
- IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos()
- IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
- IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min for the full window (roughly (0,0)-Scroll), in window coordinates
- IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max for the full window (roughly (0,0)+Size-Scroll) where Size can be overridden with SetNextWindowContentSize(), in window coordinates
-
// Windows Scrolling
// - Any change of Scroll will be applied at the beginning of next frame in the first call to Begin().
// - You may instead use SetNextWindowScroll() prior to calling Begin() to avoid this delay, as an alternative to using SetScrollX()/SetScrollY().
@@ -443,13 +450,13 @@ namespace ImGui
IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame().
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col);
IMGUI_API void PopStyleColor(int count = 1);
- IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame().
- IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame().
+ IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame()!
+ IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. "
+ IMGUI_API void PushStyleVarX(ImGuiStyleVar idx, float val_x); // modify X component of a style ImVec2 variable. "
+ IMGUI_API void PushStyleVarY(ImGuiStyleVar idx, float val_y); // modify Y component of a style ImVec2 variable. "
IMGUI_API void PopStyleVar(int count = 1);
- IMGUI_API void PushTabStop(bool tab_stop); // == tab stop enable. Allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
- IMGUI_API void PopTabStop();
- IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
- IMGUI_API void PopButtonRepeat();
+ IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled); // modify specified shared item flag, e.g. PushItemFlag(ImGuiItemFlags_NoTabStop, true)
+ IMGUI_API void PopItemFlag();
// Parameters stacks (current window)
IMGUI_API void PushItemWidth(float item_width); // push width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -FLT_MIN always align width to the right side).
@@ -463,7 +470,7 @@ namespace ImGui
// - Use the ShowStyleEditor() function to interactively see/edit the colors.
IMGUI_API ImFont* GetFont(); // get current font
IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied
- IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
+ IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a white pixel, useful to draw custom shapes via the ImDrawList API
IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList
IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList
IMGUI_API ImU32 GetColorU32(ImU32 col, float alpha_mul = 1.0f); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList
@@ -473,19 +480,22 @@ namespace ImGui
// - By "cursor" we mean the current output position.
// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
// - You can call SameLine() between widgets to undo the last carriage return and output at the right of the preceding widget.
+ // - YOU CAN DO 99% OF WHAT YOU NEED WITH ONLY GetCursorScreenPos() and GetContentRegionAvail().
// - Attention! We currently have inconsistencies between window-local and absolute positions we will aim to fix with future API:
// - Absolute coordinate: GetCursorScreenPos(), SetCursorScreenPos(), all ImDrawList:: functions. -> this is the preferred way forward.
- // - Window-local coordinates: SameLine(), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), GetContentRegionMax(), GetWindowContentRegion*(), PushTextWrapPos()
- // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates.
- IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position in absolute coordinates (prefer using this, also more useful to work with ImDrawList API).
- IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position in absolute coordinates
- IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window coordinates (relative to window position)
+ // - Window-local coordinates: SameLine(offset), GetCursorPos(), SetCursorPos(), GetCursorStartPos(), PushTextWrapPos()
+ // - Window-local coordinates: GetContentRegionMax(), GetWindowContentRegionMin(), GetWindowContentRegionMax() --> all obsoleted. YOU DON'T NEED THEM.
+ // - GetCursorScreenPos() = GetCursorPos() + GetWindowPos(). GetWindowPos() is almost only ever useful to convert from window-local to absolute coordinates. Try not to use it.
+ IMGUI_API ImVec2 GetCursorScreenPos(); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND (prefer using this rather than GetCursorPos(), also more useful to work with ImDrawList API).
+ IMGUI_API void SetCursorScreenPos(const ImVec2& pos); // cursor position, absolute coordinates. THIS IS YOUR BEST FRIEND.
+ IMGUI_API ImVec2 GetContentRegionAvail(); // available space from current position. THIS IS YOUR BEST FRIEND.
+ IMGUI_API ImVec2 GetCursorPos(); // [window-local] cursor position in window-local coordinates. This is not your best friend.
IMGUI_API float GetCursorPosX(); // [window-local] "
IMGUI_API float GetCursorPosY(); // [window-local] "
IMGUI_API void SetCursorPos(const ImVec2& local_pos); // [window-local] "
IMGUI_API void SetCursorPosX(float local_x); // [window-local] "
IMGUI_API void SetCursorPosY(float local_y); // [window-local] "
- IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window coordinates
+ IMGUI_API ImVec2 GetCursorStartPos(); // [window-local] initial cursor position, in window-local coordinates. Call GetCursorScreenPos() after Begin() to get the absolute coordinates version.
// Other layout functions
IMGUI_API void Separator(); // separator, generally horizontal. inside a menu bar or in horizontal layout mode, this becomes a vertical separator.
@@ -522,6 +532,7 @@ namespace ImGui
IMGUI_API ImGuiID GetID(const char* str_id); // calculate unique ID (hash of whole ID stack + given parameter). e.g. if you want to query into ImGuiStorage yourself
IMGUI_API ImGuiID GetID(const char* str_id_begin, const char* str_id_end);
IMGUI_API ImGuiID GetID(const void* ptr_id);
+ IMGUI_API ImGuiID GetID(int int_id);
// Widgets: Text
IMGUI_API void TextUnformatted(const char* text, const char* text_end = NULL); // raw text without formatting. Roughly equivalent to Text("%s", text) but: A) doesn't require null terminated string if 'text_end' is specified, B) it's faster, no memory copy is done, no buffer size limits, recommended for long chunks of text.
@@ -553,6 +564,8 @@ namespace ImGui
IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer
IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL);
IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
+ IMGUI_API bool TextLink(const char* label); // hyperlink text button, return true when clicked
+ IMGUI_API void TextLinkOpenURL(const char* label, const char* url = NULL); // hyperlink text button, automatically open file/url when clicked
// Widgets: Images
// - Read about ImTextureID here: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
@@ -663,6 +676,7 @@ namespace ImGui
IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().
IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header.
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
+ IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id).
// Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected.
@@ -670,6 +684,18 @@ namespace ImGui
IMGUI_API bool Selectable(const char* label, bool selected = false, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool selected" carry the selection state (read-only). Selectable() is clicked is returns true so you can modify your selection state. size.x==0.0: use remaining width, size.x>0.0: specify width. size.y==0.0: use label height, size.y>0.0: specify height
IMGUI_API bool Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags flags = 0, const ImVec2& size = ImVec2(0, 0)); // "bool* p_selected" point to the selection state (read-write), as a convenient helper.
+ // Multi-selection system for Selectable(), Checkbox(), TreeNode() functions [BETA]
+ // - This enables standard multi-selection/range-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc.) in a way that also allow a clipper to be used.
+ // - ImGuiSelectionUserData is often used to store your item index within the current view (but may store something else).
+ // - Read comments near ImGuiMultiSelectIO for instructions/details and see 'Demo->Widgets->Selection State & Multi-Select' for demo.
+ // - TreeNode() is technically supported but... using this correctly is more complicated. You need some sort of linear/random access to your tree,
+ // which is suited to advanced trees setups already implementing filters and clipper. We will work simplifying the current demo.
+ // - 'selection_size' and 'items_count' parameters are optional and used by a few features. If they are costly for you to compute, you may avoid them.
+ IMGUI_API ImGuiMultiSelectIO* BeginMultiSelect(ImGuiMultiSelectFlags flags, int selection_size = -1, int items_count = -1);
+ IMGUI_API ImGuiMultiSelectIO* EndMultiSelect();
+ IMGUI_API void SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data);
+ IMGUI_API bool IsItemToggledSelection(); // Was the last item selection state toggled? Useful if you need the per-item information _before_ reaching EndMultiSelect(). We only returns toggle _event_ in order to handle clipping correctly.
+
// Widgets: List Boxes
// - This is essentially a thin wrapper to using BeginChild/EndChild with the ImGuiChildFlags_FrameStyle flag for stylistic changes + displaying a label.
// - You can submit contents and manage your selection state however you want it, by creating e.g. Selectable() or any other items.
@@ -789,7 +815,7 @@ namespace ImGui
// - TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row!
// - TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
// - 5. Call EndTable()
- IMGUI_API bool BeginTable(const char* str_id, int column, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
+ IMGUI_API bool BeginTable(const char* str_id, int columns, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0.0f, 0.0f), float inner_width = 0.0f);
IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true!
IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.
IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
@@ -822,11 +848,12 @@ namespace ImGui
IMGUI_API const char* TableGetColumnName(int column_n = -1); // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.
IMGUI_API ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1); // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags. Pass -1 to use current column.
IMGUI_API void TableSetColumnEnabled(int column_n, bool v);// change user accessible enabled/disabled state of a column. Set to false to hide the column. User can use the context menu to change this themselves (right-click in headers, or right-click in columns body with ImGuiTableFlags_ContextMenuInBody)
+ IMGUI_API int TableGetHoveredColumn(); // return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered. Can also use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead.
IMGUI_API void TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n = -1); // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details.
// Legacy Columns API (prefer using Tables!)
// - You can also use SameLine(pos_x) to mimic simplified columns.
- IMGUI_API void Columns(int count = 1, const char* id = NULL, bool border = true);
+ IMGUI_API void Columns(int count = 1, const char* id = NULL, bool borders = true);
IMGUI_API void NextColumn(); // next column, defaults to current row or next row if the current row is finished
IMGUI_API int GetColumnIndex(); // get current column index
IMGUI_API float GetColumnWidth(int column_index = -1); // get column width (in pixels). pass -1 to use current column
@@ -890,7 +917,8 @@ namespace ImGui
// Disabling [BETA API]
// - Disable all user interactions and dim items visuals (applying style.DisabledAlpha over current colors)
// - Those can be nested but it cannot be used to enable an already disabled section (a single BeginDisabled(true) in the stack is enough to keep everything disabled)
- // - BeginDisabled(false) essentially does nothing useful but is provided to facilitate use of boolean expressions. If you can avoid calling BeginDisabled(False)/EndDisabled() best to avoid it.
+ // - Tooltips windows by exception are opted out of disabling.
+ // - BeginDisabled(false)/EndDisabled() essentially does nothing but is provided to facilitate use of boolean expressions (as a micro-optimization: if you have tens of thousands of BeginDisabled(false)/EndDisabled() pairs, you might want to reformulate your code to avoid making those calls)
IMGUI_API void BeginDisabled(bool disabled = true);
IMGUI_API void EndDisabled();
@@ -935,10 +963,8 @@ namespace ImGui
IMGUI_API ImGuiViewport* GetMainViewport(); // return primary/default viewport. This can never be NULL.
// Background/Foreground Draw Lists
- IMGUI_API ImDrawList* GetBackgroundDrawList(); // get background draw list for the viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
- IMGUI_API ImDrawList* GetForegroundDrawList(); // get foreground draw list for the viewport associated to the current window. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
- IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport); // get background draw list for the given viewport. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
- IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport); // get foreground draw list for the given viewport. this draw list will be the last rendered one. Useful to quickly draw shapes/text over dear imgui contents.
+ IMGUI_API ImDrawList* GetBackgroundDrawList(ImGuiViewport* viewport = NULL); // get background draw list for the given viewport or viewport associated to the current window. this draw list will be the first rendering one. Useful to quickly draw shapes/text behind dear imgui contents.
+ IMGUI_API ImDrawList* GetForegroundDrawList(ImGuiViewport* viewport = NULL); // get foreground draw list for the given viewport or viewport associated to the current window. this draw list will be the top-most rendered one. Useful to quickly draw shapes/text over dear imgui contents.
// Miscellaneous Utilities
IMGUI_API bool IsRectVisible(const ImVec2& size); // test if rectangle (of given size, starting from cursor position) is visible / not clipped.
@@ -972,7 +998,7 @@ namespace ImGui
IMGUI_API const char* GetKeyName(ImGuiKey key); // [DEBUG] returns English name of the key. Those names a provided for debugging purpose and are not meant to be saved persistently not compared.
IMGUI_API void SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard); // Override io.WantCaptureKeyboard flag next frame (said flag is left for your application to handle, typically when true it instructs your app to ignore inputs). e.g. force capture keyboard when your widget is being hovered. This is equivalent to setting "io.WantCaptureKeyboard = want_capture_keyboard"; after the next NewFrame() call.
- // Inputs Utilities: Shortcut Testing & Routing
+ // Inputs Utilities: Shortcut Testing & Routing [BETA]
// - ImGuiKeyChord = a ImGuiKey + optional ImGuiMod_Alt/ImGuiMod_Ctrl/ImGuiMod_Shift/ImGuiMod_Super.
// ImGuiKey_C // Accepted by functions taking ImGuiKey or ImGuiKeyChord arguments)
// ImGuiMod_Ctrl | ImGuiKey_C // Accepted by functions taking ImGuiKeyChord arguments)
@@ -990,6 +1016,14 @@ namespace ImGui
IMGUI_API bool Shortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0);
IMGUI_API void SetNextItemShortcut(ImGuiKeyChord key_chord, ImGuiInputFlags flags = 0);
+ // Inputs Utilities: Key/Input Ownership [BETA]
+ // - One common use case would be to allow your items to disable standard inputs behaviors such
+ // as Tab or Alt key handling, Mouse Wheel scrolling, etc.
+ // e.g. Button(...); SetItemKeyOwner(ImGuiKey_MouseWheelY); to make hovering/activating a button disable wheel for scrolling.
+ // - Reminder ImGuiKey enum include access to mouse buttons and gamepad, so key ownership can apply to them.
+ // - Many related features are still in imgui_internal.h. For instance, most IsKeyXXX()/IsMouseXXX() functions have an owner-id-aware version.
+ IMGUI_API void SetItemKeyOwner(ImGuiKey key); // Set key owner to last item ID if it is hovered or active. Equivalent to 'if (IsItemHovered() || IsItemActive()) { SetKeyOwner(key, GetItemID());'.
+
// Inputs Utilities: Mouse specific
// - To refer to a mouse button, you may use named enums in your code e.g. ImGuiMouseButton_Left, ImGuiMouseButton_Right.
// - You can also use regular integer: it is forever guaranteed that 0=Left, 1=Right, 2=Middle.
@@ -1004,8 +1038,8 @@ namespace ImGui
IMGUI_API bool IsAnyMouseDown(); // [WILL OBSOLETE] is any mouse button held? This was designed for backends, but prefer having backend maintain a mask of held mouse buttons, because upcoming input queue system will make this invalid.
IMGUI_API ImVec2 GetMousePos(); // shortcut to ImGui::GetIO().MousePos provided by user, to be consistent with other calls
IMGUI_API ImVec2 GetMousePosOnOpeningCurrentPopup(); // retrieve mouse position at the time of opening popup we have BeginPopup() into (helper to avoid user backing that value themselves)
- IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)
- IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (if lock_threshold < -1.0f, uses io.MouseDraggingThreshold)
+ IMGUI_API bool IsMouseDragging(ImGuiMouseButton button, float lock_threshold = -1.0f); // is mouse dragging? (uses io.MouseDraggingThreshold if lock_threshold < 0.0f)
+ IMGUI_API ImVec2 GetMouseDragDelta(ImGuiMouseButton button = 0, float lock_threshold = -1.0f); // return the delta from the initial clicking position while the mouse button is pressed or was just released. This is locked and return 0.0f until the mouse moves past a distance threshold at least once (uses io.MouseDraggingThreshold if lock_threshold < 0.0f)
IMGUI_API void ResetMouseDragDelta(ImGuiMouseButton button = 0); //
IMGUI_API ImGuiMouseCursor GetMouseCursor(); // get desired mouse cursor shape. Important: reset in ImGui::NewFrame(), this is updated during the frame. valid before Render(). If you use software rendering by setting io.MouseDrawCursor ImGui will render those for you
IMGUI_API void SetMouseCursor(ImGuiMouseCursor cursor_type); // set desired mouse cursor shape
@@ -1031,6 +1065,10 @@ namespace ImGui
IMGUI_API void DebugFlashStyleColor(ImGuiCol idx);
IMGUI_API void DebugStartItemPicker();
IMGUI_API bool DebugCheckVersionAndDataLayout(const char* version_str, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_drawvert, size_t sz_drawidx); // This is called by IMGUI_CHECKVERSION() macro.
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ IMGUI_API void DebugLog(const char* fmt, ...) IM_FMTARGS(1); // Call via IMGUI_DEBUG_LOG() for maximum stripping in caller code!
+ IMGUI_API void DebugLogV(const char* fmt, va_list args) IM_FMTLIST(1);
+#endif
// Memory Allocators
// - Those functions are not reliant on the current context.
@@ -1044,7 +1082,6 @@ namespace ImGui
// (Optional) Platform/OS interface for multi-viewport support
// Read comments around the ImGuiPlatformIO structure for more details.
// Note: You may use GetWindowViewport() to get the current viewport of the current window.
- IMGUI_API ImGuiPlatformIO& GetPlatformIO(); // platform/renderer functions, for backend to setup + viewports list.
IMGUI_API void UpdatePlatformWindows(); // call in main loop. will call CreateWindow/ResizeWindow/etc. platform functions for each secondary viewport, and DestroyWindow for each inactive viewport.
IMGUI_API void RenderPlatformWindowsDefault(void* platform_render_arg = NULL, void* renderer_render_arg = NULL); // call in main loop. will call RenderWindow/SwapBuffers platform functions for each secondary viewport which doesn't have the ImGuiViewportFlags_Minimized flag set. May be reimplemented by user for custom rendering needs.
IMGUI_API void DestroyPlatformWindows(); // call DestroyWindow platform functions for all viewports. call from backend Shutdown() if you need to close platform windows before imgui shutdown. otherwise will be called by DestroyContext().
@@ -1087,7 +1124,6 @@ enum ImGuiWindowFlags_
ImGuiWindowFlags_NoInputs = ImGuiWindowFlags_NoMouseInputs | ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
// [Internal]
- ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] On child window: share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
ImGuiWindowFlags_ChildWindow = 1 << 24, // Don't use! For internal use by BeginChild()
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
@@ -1097,12 +1133,13 @@ enum ImGuiWindowFlags_
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
+ ImGuiWindowFlags_AlwaysUseWindowPadding = 1 << 30, // Obsoleted in 1.90.0: Use ImGuiChildFlags_AlwaysUseWindowPadding in BeginChild() call.
+ ImGuiWindowFlags_NavFlattened = 1 << 31, // Obsoleted in 1.90.9: Use ImGuiChildFlags_NavFlattened in BeginChild() call.
#endif
};
// Flags for ImGui::BeginChild()
-// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Border to be backward compatible with old API using 'bool border = false'.
+// (Legacy: bit 0 must always correspond to ImGuiChildFlags_Borders to be backward compatible with old API using 'bool border = false'.
// About using AutoResizeX/AutoResizeY flags:
// - May be combined with SetNextWindowSizeConstraints() to set a min/max size for each axis (see "Demo->Child->Auto-resize with Constraints").
// - Size measurement for a given axis is only performed when the child window is within visible boundaries, or is just appearing.
@@ -1113,7 +1150,7 @@ enum ImGuiWindowFlags_
enum ImGuiChildFlags_
{
ImGuiChildFlags_None = 0,
- ImGuiChildFlags_Border = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason)
+ ImGuiChildFlags_Borders = 1 << 0, // Show an outer border and enable WindowPadding. (IMPORTANT: this is always == 1 == true for legacy reason)
ImGuiChildFlags_AlwaysUseWindowPadding = 1 << 1, // Pad with style.WindowPadding even if no border are drawn (no padding by default for non-bordered child windows because it makes more sense)
ImGuiChildFlags_ResizeX = 1 << 2, // Allow resize from right border (layout direction). Enable .ini saving (unless ImGuiWindowFlags_NoSavedSettings passed to window flags)
ImGuiChildFlags_ResizeY = 1 << 3, // Allow resize from bottom border (layout direction). "
@@ -1121,34 +1158,62 @@ enum ImGuiChildFlags_
ImGuiChildFlags_AutoResizeY = 1 << 5, // Enable auto-resizing height. Read "IMPORTANT: Size measurement" details above.
ImGuiChildFlags_AlwaysAutoResize = 1 << 6, // Combined with AutoResizeX/AutoResizeY. Always measure size even when child is hidden, always return true, always disable clipping optimization! NOT RECOMMENDED.
ImGuiChildFlags_FrameStyle = 1 << 7, // Style the child window like a framed item: use FrameBg, FrameRounding, FrameBorderSize, FramePadding instead of ChildBg, ChildRounding, ChildBorderSize, WindowPadding.
+ ImGuiChildFlags_NavFlattened = 1 << 8, // [BETA] Share focus scope, allow gamepad/keyboard navigation to cross over parent border to this child or between sibling child windows.
+
+ // Obsolete names
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ ImGuiChildFlags_Border = ImGuiChildFlags_Borders, // Renamed in 1.91.1 (August 2024) for consistency.
+#endif
+};
+
+// Flags for ImGui::PushItemFlag()
+// (Those are shared by all items)
+enum ImGuiItemFlags_
+{
+ ImGuiItemFlags_None = 0, // (Default)
+ ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav.
+ ImGuiItemFlags_NoNav = 1 << 1, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls).
+ ImGuiItemFlags_NoNavDefaultFocus = 1 << 2, // false // Disable item being a candidate for default focus (e.g. used by title bar items).
+ ImGuiItemFlags_ButtonRepeat = 1 << 3, // false // Any button-like behavior will have repeat mode enabled (based on io.KeyRepeatDelay and io.KeyRepeatRate values). Note that you can also call IsItemActive() after any button to tell if it is being held.
+ ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window.
+ ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
};
// Flags for ImGui::InputText()
// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigInputTextCursorBlink and io.ConfigInputTextEnterKeepActive)
enum ImGuiInputTextFlags_
{
+ // Basic filters (also see ImGuiInputTextFlags_CallbackCharFilter)
ImGuiInputTextFlags_None = 0,
ImGuiInputTextFlags_CharsDecimal = 1 << 0, // Allow 0123456789.+-*/
ImGuiInputTextFlags_CharsHexadecimal = 1 << 1, // Allow 0123456789ABCDEFabcdef
- ImGuiInputTextFlags_CharsUppercase = 1 << 2, // Turn a..z into A..Z
- ImGuiInputTextFlags_CharsNoBlank = 1 << 3, // Filter out spaces, tabs
- ImGuiInputTextFlags_AutoSelectAll = 1 << 4, // Select entire text when first taking mouse focus
- ImGuiInputTextFlags_EnterReturnsTrue = 1 << 5, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function.
- ImGuiInputTextFlags_CallbackCompletion = 1 << 6, // Callback on pressing TAB (for completion handling)
- ImGuiInputTextFlags_CallbackHistory = 1 << 7, // Callback on pressing Up/Down arrows (for history handling)
- ImGuiInputTextFlags_CallbackAlways = 1 << 8, // Callback on each iteration. User code may query cursor position, modify text buffer.
- ImGuiInputTextFlags_CallbackCharFilter = 1 << 9, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
- ImGuiInputTextFlags_AllowTabInput = 1 << 10, // Pressing TAB input a '\t' character into the text field
- ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 11, // In multi-line mode, unfocus with Enter, add new line with Ctrl+Enter (default is opposite: unfocus with Ctrl+Enter, add line with Enter).
- ImGuiInputTextFlags_NoHorizontalScroll = 1 << 12, // Disable following the cursor horizontally
- ImGuiInputTextFlags_AlwaysOverwrite = 1 << 13, // Overwrite mode
- ImGuiInputTextFlags_ReadOnly = 1 << 14, // Read-only mode
- ImGuiInputTextFlags_Password = 1 << 15, // Password mode, display all characters as '*'
+ ImGuiInputTextFlags_CharsScientific = 1 << 2, // Allow 0123456789.+-*/eE (Scientific notation input)
+ ImGuiInputTextFlags_CharsUppercase = 1 << 3, // Turn a..z into A..Z
+ ImGuiInputTextFlags_CharsNoBlank = 1 << 4, // Filter out spaces, tabs
+
+ // Inputs
+ ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field
+ ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider looking at the IsItemDeactivatedAfterEdit() function.
+ ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)
+ ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter).
+
+ // Other options
+ ImGuiInputTextFlags_ReadOnly = 1 << 9, // Read-only mode
+ ImGuiInputTextFlags_Password = 1 << 10, // Password mode, display all characters as '*', disable copy
+ ImGuiInputTextFlags_AlwaysOverwrite = 1 << 11, // Overwrite mode
+ ImGuiInputTextFlags_AutoSelectAll = 1 << 12, // Select entire text when first taking mouse focus
+ ImGuiInputTextFlags_ParseEmptyRefVal = 1 << 13, // InputFloat(), InputInt(), InputScalar() etc. only: parse empty string as zero value.
+ ImGuiInputTextFlags_DisplayEmptyRefVal = 1 << 14, // InputFloat(), InputInt(), InputScalar() etc. only: when value is zero, do not display it. Generally used with ImGuiInputTextFlags_ParseEmptyRefVal.
+ ImGuiInputTextFlags_NoHorizontalScroll = 1 << 15, // Disable following the cursor horizontally
ImGuiInputTextFlags_NoUndoRedo = 1 << 16, // Disable undo/redo. Note that input text owns the text data while active, if you want to provide your own undo/redo stack you need e.g. to call ClearActiveID().
- ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input)
- ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
- ImGuiInputTextFlags_CallbackEdit = 1 << 19, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
- ImGuiInputTextFlags_EscapeClearsAll = 1 << 20, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)
+
+ // Callback features
+ ImGuiInputTextFlags_CallbackCompletion = 1 << 17, // Callback on pressing TAB (for completion handling)
+ ImGuiInputTextFlags_CallbackHistory = 1 << 18, // Callback on pressing Up/Down arrows (for history handling)
+ ImGuiInputTextFlags_CallbackAlways = 1 << 19, // Callback on each iteration. User code may query cursor position, modify text buffer.
+ ImGuiInputTextFlags_CallbackCharFilter = 1 << 20, // Callback on character inputs to replace or discard them. Modify 'EventChar' to replace or discard, or return 1 in callback to discard.
+ ImGuiInputTextFlags_CallbackResize = 1 << 21, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
+ ImGuiInputTextFlags_CallbackEdit = 1 << 22, // Callback on any edit (note that InputText() already returns true on edit, the callback is useful mainly to manipulate the underlying buffer while focus is active)
// Obsolete names
//ImGuiInputTextFlags_AlwaysInsertMode = ImGuiInputTextFlags_AlwaysOverwrite // [renamed in 1.82] name was not matching behavior
@@ -1164,11 +1229,11 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_NoTreePushOnOpen = 1 << 3, // Don't do a TreePush() when open (e.g. for CollapsingHeader) = no extra indent nor pushing on ID stack
ImGuiTreeNodeFlags_NoAutoOpenOnLog = 1 << 4, // Don't automatically and temporarily open node when Logging is active (by default logging will automatically open tree nodes)
ImGuiTreeNodeFlags_DefaultOpen = 1 << 5, // Default node to be open
- ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node
- ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.
+ ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Open on double-click instead of simple click (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined.
+ ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Open when clicking on the arrow part (default for multi-select unless any _OpenOnXXX behavior is set explicitly). Both behaviors may be combined.
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes).
ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag!
- ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
+ ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding() before the node.
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line without using AllowOverlap mode.
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (cover the indent area).
ImGuiTreeNodeFlags_SpanTextWidth = 1 << 13, // Narrow hit box + narrow hovering highlight, will only cover the label text.
@@ -1211,14 +1276,16 @@ enum ImGuiPopupFlags_
enum ImGuiSelectableFlags_
{
ImGuiSelectableFlags_None = 0,
- ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this doesn't close parent popup window
+ ImGuiSelectableFlags_NoAutoClosePopups = 1 << 0, // Clicking this doesn't close parent popup window (overrides ImGuiItemFlags_AutoClosePopups)
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Frame will span all columns of its container table (text will still fit in current column)
ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too
ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
ImGuiSelectableFlags_AllowOverlap = 1 << 4, // (WIP) Hit testing to allow subsequent widgets to overlap this one
+ ImGuiSelectableFlags_Highlight = 1 << 5, // Make the item be displayed as if it is hovered
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7
+ ImGuiSelectableFlags_DontClosePopups = ImGuiSelectableFlags_NoAutoClosePopups, // Renamed in 1.91.0
+ ImGuiSelectableFlags_AllowItemOverlap = ImGuiSelectableFlags_AllowOverlap, // Renamed in 1.89.7
#endif
};
@@ -1247,8 +1314,9 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You may handle this behavior manually on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)
ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
- ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit
- ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit
+ ImGuiTabBarFlags_DrawSelectedOverline = 1 << 6, // Draw selected overline markers over selected tab
+ ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 7, // Resize tabs when they don't fit
+ ImGuiTabBarFlags_FittingPolicyScroll = 1 << 8, // Add scroll buttons when tabs don't fit
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown,
};
@@ -1351,12 +1419,18 @@ enum ImGuiDragDropFlags_
ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.
ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.
ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
- ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
+ ImGuiDragDropFlags_PayloadAutoExpire = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
+ ImGuiDragDropFlags_PayloadNoCrossContext = 1 << 6, // Hint to specify that the payload may not be copied outside current dear imgui context.
+ ImGuiDragDropFlags_PayloadNoCrossProcess = 1 << 7, // Hint to specify that the payload may not be copied outside current process.
// AcceptDragDropPayload() flags
ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.
ImGuiDragDropFlags_AcceptNoDrawDefaultRect = 1 << 11, // Do not draw the default highlight rectangle when hovering over target.
ImGuiDragDropFlags_AcceptNoPreviewTooltip = 1 << 12, // Request hiding the BeginDragDropSource tooltip from the BeginDragDropTarget site.
ImGuiDragDropFlags_AcceptPeekOnly = ImGuiDragDropFlags_AcceptBeforeDelivery | ImGuiDragDropFlags_AcceptNoDrawDefaultRect, // For peeking ahead and inspecting the payload before delivery.
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ ImGuiDragDropFlags_SourceAutoExpirePayload = ImGuiDragDropFlags_PayloadAutoExpire, // Renamed in 1.90.9
+#endif
};
// Standard Drag and Drop payload types. You can define you own payload types using short strings. Types starting with '_' are defined by Dear ImGui.
@@ -1376,11 +1450,12 @@ enum ImGuiDataType_
ImGuiDataType_U64, // unsigned long long / unsigned __int64
ImGuiDataType_Float, // float
ImGuiDataType_Double, // double
+ ImGuiDataType_Bool, // bool (provided for user convenience, not supported by scalar widgets)
ImGuiDataType_COUNT
};
// A cardinal direction
-enum ImGuiDir_
+enum ImGuiDir : int
{
ImGuiDir_None = -1,
ImGuiDir_Left = 0,
@@ -1391,7 +1466,7 @@ enum ImGuiDir_
};
// A sorting direction
-enum ImGuiSortDirection_
+enum ImGuiSortDirection : ImU8
{
ImGuiSortDirection_None = 0,
ImGuiSortDirection_Ascending = 1, // Ascending = 0->9, A->Z etc.
@@ -1548,7 +1623,7 @@ enum ImGuiInputFlags_
ImGuiInputFlags_Repeat = 1 << 0, // Enable repeat. Return true on successive repeats. Default for legacy IsKeyPressed(). NOT Default for legacy IsMouseClicked(). MUST BE == 1.
// Flags for Shortcut(), SetNextItemShortcut()
- // - Routing policies: RouteGlobalOverActive >> RouteActive or RouteFocused (if owner is active item) >> RouteGlobalOverFocused >> RouteFocused (if in focused window stack) >> RouteGlobal.
+ // - Routing policies: RouteGlobal+OverActive >> RouteActive or RouteFocused (if owner is active item) >> RouteGlobal+OverFocused >> RouteFocused (if in focused window stack) >> RouteGlobal.
// - Default policy is RouteFocused. Can select only 1 policy among all available.
ImGuiInputFlags_RouteActive = 1 << 10, // Route to active item only.
ImGuiInputFlags_RouteFocused = 1 << 11, // Route to windows in the focus stack (DEFAULT). Deep-most focused window takes inputs. Active item takes inputs over deep-most focused window.
@@ -1561,7 +1636,7 @@ enum ImGuiInputFlags_
ImGuiInputFlags_RouteFromRootWindow = 1 << 17, // Option: route evaluated from the point of view of root window rather than current window.
// Flags for SetNextItemShortcut()
- ImGuiInputFlags_Tooltip = 1 << 18, // Automatically display a tooltip when hovering item.
+ ImGuiInputFlags_Tooltip = 1 << 18, // Automatically display a tooltip when hovering item [BETA] Unsure of right api (opt-in/opt-out)
};
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
@@ -1584,11 +1659,12 @@ enum ImGuiConfigFlags_
ImGuiConfigFlags_NavEnableGamepad = 1 << 1, // Master gamepad navigation enable flag. Backend also needs to set ImGuiBackendFlags_HasGamepad.
ImGuiConfigFlags_NavEnableSetMousePos = 1 << 2, // Instruct navigation to move the mouse cursor. May be useful on TV/console systems where moving a virtual mouse is awkward. Will update io.MousePos and set io.WantSetMousePos=true. If enabled you MUST honor io.WantSetMousePos requests in your backend, otherwise ImGui will react as if the mouse is jumping around back and forth.
ImGuiConfigFlags_NavNoCaptureKeyboard = 1 << 3, // Instruct navigation to not set the io.WantCaptureKeyboard flag when io.NavActive is set.
- ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the backend.
+ ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct dear imgui to disable mouse inputs and interactions.
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct backend to not alter mouse cursor shape and visibility. Use if the backend cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
+ ImGuiConfigFlags_NoKeyboard = 1 << 6, // Instruct dear imgui to disable keyboard inputs and interactions. This is done by ignoring keyboard events and clearing existing states.
// [BETA] Docking
- ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags.
+ ImGuiConfigFlags_DockingEnable = 1 << 7, // Docking enable flags.
// [BETA] Viewports
// When using viewports it is recommended that your default value for ImGuiCol_WindowBg is opaque (Alpha=1.0) so transition to a viewport won't be noticeable.
@@ -1652,11 +1728,13 @@ enum ImGuiCol_
ImGuiCol_ResizeGrip, // Resize grip in lower-right and lower-left corners of windows.
ImGuiCol_ResizeGripHovered,
ImGuiCol_ResizeGripActive,
- ImGuiCol_Tab, // TabItem in a TabBar
- ImGuiCol_TabHovered,
- ImGuiCol_TabActive,
- ImGuiCol_TabUnfocused,
- ImGuiCol_TabUnfocusedActive,
+ ImGuiCol_TabHovered, // Tab background, when hovered
+ ImGuiCol_Tab, // Tab background, when tab-bar is focused & tab is unselected
+ ImGuiCol_TabSelected, // Tab background, when tab-bar is focused & tab is selected
+ ImGuiCol_TabSelectedOverline, // Tab horizontal overline, when tab-bar is focused & tab is selected
+ ImGuiCol_TabDimmed, // Tab background, when tab-bar is unfocused & tab is unselected
+ ImGuiCol_TabDimmedSelected, // Tab background, when tab-bar is unfocused & tab is selected
+ ImGuiCol_TabDimmedSelectedOverline,//..horizontal overline, when tab-bar is unfocused & tab is selected
ImGuiCol_DockingPreview, // Preview overlay color when about to docking something
ImGuiCol_DockingEmptyBg, // Background color for empty node (e.g. CentralNode with no window docked into it)
ImGuiCol_PlotLines,
@@ -1668,13 +1746,20 @@ enum ImGuiCol_
ImGuiCol_TableBorderLight, // Table inner borders (prefer using Alpha=1.0 here)
ImGuiCol_TableRowBg, // Table row background (even rows)
ImGuiCol_TableRowBgAlt, // Table row background (odd rows)
+ ImGuiCol_TextLink, // Hyperlink color
ImGuiCol_TextSelectedBg,
ImGuiCol_DragDropTarget, // Rectangle highlighting a drop target
ImGuiCol_NavHighlight, // Gamepad/keyboard: current highlighted item
ImGuiCol_NavWindowingHighlight, // Highlight window when using CTRL+TAB
ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active
ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active
- ImGuiCol_COUNT
+ ImGuiCol_COUNT,
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ ImGuiCol_TabActive = ImGuiCol_TabSelected, // [renamed in 1.90.9]
+ ImGuiCol_TabUnfocused = ImGuiCol_TabDimmed, // [renamed in 1.90.9]
+ ImGuiCol_TabUnfocusedActive = ImGuiCol_TabDimmedSelected, // [renamed in 1.90.9]
+#endif
};
// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure.
@@ -1713,6 +1798,7 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TabRounding, // float TabRounding
ImGuiStyleVar_TabBorderSize, // float TabBorderSize
ImGuiStyleVar_TabBarBorderSize, // float TabBarBorderSize
+ ImGuiStyleVar_TabBarOverlineSize, // float TabBarOverlineSize
ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle
ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
@@ -1731,10 +1817,8 @@ enum ImGuiButtonFlags_
ImGuiButtonFlags_MouseButtonLeft = 1 << 0, // React on left mouse button (default)
ImGuiButtonFlags_MouseButtonRight = 1 << 1, // React on right mouse button
ImGuiButtonFlags_MouseButtonMiddle = 1 << 2, // React on center mouse button
-
- // [Internal]
- ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle,
- ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft,
+ ImGuiButtonFlags_MouseButtonMask_ = ImGuiButtonFlags_MouseButtonLeft | ImGuiButtonFlags_MouseButtonRight | ImGuiButtonFlags_MouseButtonMiddle, // [Internal]
+ //ImGuiButtonFlags_MouseButtonDefault_ = ImGuiButtonFlags_MouseButtonLeft,
};
// Flags for ColorEdit3() / ColorEdit4() / ColorPicker3() / ColorPicker4() / ColorButton()
@@ -1783,18 +1867,18 @@ enum ImGuiColorEditFlags_
// Flags for DragFloat(), DragInt(), SliderFloat(), SliderInt() etc.
// We use the same sets of flags for DragXXX() and SliderXXX() functions as the features are the same and it makes it easier to swap them.
-// (Those are per-item flags. There are shared flags in ImGuiIO: io.ConfigDragClickToInputText)
+// (Those are per-item flags. There is shared behavior flag too: ImGuiIO: io.ConfigDragClickToInputText)
enum ImGuiSliderFlags_
{
- ImGuiSliderFlags_None = 0,
- ImGuiSliderFlags_AlwaysClamp = 1 << 4, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
- ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
- ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits)
- ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget
- ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
-
- // Obsolete names
- //ImGuiSliderFlags_ClampOnInput = ImGuiSliderFlags_AlwaysClamp, // [renamed in 1.79]
+ ImGuiSliderFlags_None = 0,
+ ImGuiSliderFlags_Logarithmic = 1 << 5, // Make the widget logarithmic (linear otherwise). Consider using ImGuiSliderFlags_NoRoundToFormat with this if using a format-string with small amount of digits.
+ ImGuiSliderFlags_NoRoundToFormat = 1 << 6, // Disable rounding underlying value to match precision of the display format string (e.g. %.3f values are rounded to those 3 digits).
+ ImGuiSliderFlags_NoInput = 1 << 7, // Disable CTRL+Click or Enter key allowing to input text directly into the widget.
+ ImGuiSliderFlags_WrapAround = 1 << 8, // Enable wrapping around from max to min and from min to max. Only supported by DragXXX() functions for now.
+ ImGuiSliderFlags_ClampOnInput = 1 << 9, // Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.
+ ImGuiSliderFlags_ClampZeroRange = 1 << 10, // Clamp even if min==max==0.0f. Otherwise due to legacy reason DragXXX functions don't clamp with those values. When your clamping limits are dynamic you almost always want to use it.
+ ImGuiSliderFlags_AlwaysClamp = ImGuiSliderFlags_ClampOnInput | ImGuiSliderFlags_ClampZeroRange,
+ ImGuiSliderFlags_InvalidMask_ = 0x7000000F, // [Internal] We treat using those bits as being potentially a 'float power' argument from the previous API that has got miscast to this enum, and will trigger an assert if needed.
};
// Identify a mouse button.
@@ -1943,7 +2027,7 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).
ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction.
ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction.
- ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit horizontal label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers.
+ ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will submit an empty label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers. You may append into this cell by calling TableSetColumnIndex() right after the TableHeadersRow() call.
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width.
ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default).
ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column.
@@ -2007,14 +2091,24 @@ struct ImGuiTableColumnSortSpecs
ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call)
ImS16 ColumnIndex; // Index of the column
ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here)
- ImGuiSortDirection SortDirection : 8; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
+ ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
ImGuiTableColumnSortSpecs() { memset(this, 0, sizeof(*this)); }
};
//-----------------------------------------------------------------------------
-// [SECTION] Helpers: Memory allocations macros, ImVector<>
+// [SECTION] Helpers: Debug log, memory allocations macros, ImVector<>
+//-----------------------------------------------------------------------------
+
//-----------------------------------------------------------------------------
+// Debug Logging into ShowDebugLogWindow(), tty and more.
+//-----------------------------------------------------------------------------
+
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+#define IMGUI_DEBUG_LOG(...) ImGui::DebugLog(__VA_ARGS__)
+#else
+#define IMGUI_DEBUG_LOG(...) ((void)0)
+#endif
//-----------------------------------------------------------------------------
// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
@@ -2148,16 +2242,17 @@ struct ImGuiStyle
float TabBorderSize; // Thickness of border around tabs.
float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
+ float TabBarOverlineSize; // Thickness of tab-bar overline, which highlights the selected tab-bar.
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
- float SeparatorTextBorderSize; // Thickkness of border in SeparatorText()
+ float SeparatorTextBorderSize; // Thickness of border in SeparatorText()
ImVec2 SeparatorTextAlign; // Alignment of text within the separator. Defaults to (0.0f, 0.5f) (left aligned, center).
ImVec2 SeparatorTextPadding; // Horizontal offset of text from each edge of the separator + spacing on other axis. Generally small values. .y is recommended to be == FramePadding.y.
- ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area or monitors by at least this amount. Only applies to regular windows.
- ImVec2 DisplaySafeAreaPadding; // If you cannot see the edges of your screen (e.g. on a TV) increase the safe area padding. Apply to popups/tooltips as well regular windows. NB: Prefer configuring your TV sets correctly!
+ ImVec2 DisplayWindowPadding; // Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.
+ ImVec2 DisplaySafeAreaPadding; // Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).
float DockingSeparatorSize; // Thickness of resizing border between docked windows
float MouseCursorScale; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). We apply per-monitor DPI scaling over this scale. May be removed later.
bool AntiAliasedLines; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU. Latched at the beginning of the frame (copied to ImDrawList).
@@ -2188,6 +2283,8 @@ struct ImGuiStyle
// - initialization: backends and user code writes to ImGuiIO.
// - main loop: backends writes to ImGuiIO, user code and imgui code reads from ImGuiIO.
//-----------------------------------------------------------------------------
+// Also see ImGui::GetPlatformIO() and ImGuiPlatformIO struct for OS/platform related functions: clipboard, IME etc.
+//-----------------------------------------------------------------------------
// [Internal] Storage used by IsKeyDown(), IsKeyPressed() etc functions.
// If prior to 1.87 you used io.KeysDownDuration[] (which was marked as internal), you should use GetKeyData(key)->DownDuration and *NOT* io.KeysData[key]->DownDuration.
@@ -2214,6 +2311,7 @@ struct ImGuiIO
const char* LogFilename; // = "imgui_log.txt"// Path to .log file (default parameter to ImGui::LogToFile when no file is specified).
void* UserData; // = NULL // Store your own data.
+ // Font system
ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture.
float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
@@ -2233,14 +2331,17 @@ struct ImGuiIO
bool ConfigViewportsNoDefaultParent; // = false // Disable default OS parenting to main viewport for secondary viewports. By default, viewports are marked with ParentViewportId = <main_viewport>, expecting the platform backend to setup a parent/child relationship between the OS windows (some backend may ignore this). Set to true if you want the default to be 0, then all viewports will be top-level OS windows.
// Miscellaneous options
+ // (you can visualize and interact with all options in 'Demo->Configuration')
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // Swap Cmd<>Ctrl keys + OS X style text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.
+ bool ConfigNavSwapGamepadButtons; // = false // Swap Activate<>Cancel (A<>B) buttons, matching typical "Nintendo/Japanese style" gamepad layout.
bool ConfigInputTrickleEventQueue; // = true // Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.
bool ConfigInputTextCursorBlink; // = true // Enable blinking cursor (optional as some users consider it to be distracting).
bool ConfigInputTextEnterKeepActive; // = false // [BETA] Pressing Enter will keep item active and select contents (single-line only).
bool ConfigDragClickToInputText; // = false // [BETA] Enable turning DragXXX widgets into text input with a simple mouse click-release (without moving). Not desirable on devices without a keyboard.
bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
bool ConfigWindowsMoveFromTitleBarOnly; // = false // Enable allowing to move windows only when clicking on their title bar. Does not apply to windows without a title bar.
+ bool ConfigScrollbarScrollByPage; // = true // Enable scrolling page by page when clicking outside the scrollbar grab. When disabled, always scroll to clicked location. When enabled, Shift+Click scrolls to clicked location.
float ConfigMemoryCompactTimer; // = 60.0f // Timer (in seconds) to free transient windows/tables memory buffers when unused. Set to -1.0f to disable.
// Inputs Behaviors
@@ -2255,12 +2356,37 @@ struct ImGuiIO
// Debug options
//------------------------------------------------------------------
+ // Options to configure Error Handling and how we handle recoverable errors [EXPERIMENTAL]
+ // - Error recovery is provided as a way to facilitate:
+ // - Recovery after a programming error (native code or scripting language - the later tends to facilitate iterating on code while running).
+ // - Recovery after running an exception handler or any error processing which may skip code after an error has been detected.
+ // - Error recovery is not perfect nor guaranteed! It is a feature to ease development.
+ // You not are not supposed to rely on it in the course of a normal application run.
+ // - Functions that support error recovery are using IM_ASSERT_USER_ERROR() instead of IM_ASSERT().
+ // - By design, we do NOT allow error recovery to be 100% silent. One of the three options needs to be checked!
+ // - Always ensure that on programmers seats you have at minimum Asserts or Tooltips enabled when making direct imgui API calls!
+ // Otherwise it would severely hinder your ability to catch and correct mistakes!
+ // Read https://github.com/ocornut/imgui/wiki/Error-Handling for details.
+ // - Programmer seats: keep asserts (default), or disable asserts and keep error tooltips (new and nice!)
+ // - Non-programmer seats: maybe disable asserts, but make sure errors are resurfaced (tooltips, visible log entries, use callback etc.)
+ // - Recovery after error/exception: record stack sizes with ErrorRecoveryStoreState(), disable assert, set log callback (to e.g. trigger high-level breakpoint), recover with ErrorRecoveryTryToRecoverState(), restore settings.
+ bool ConfigErrorRecovery; // = true // Enable error recovery support. Some errors won't be detected and lead to direct crashes if recovery is disabled.
+ bool ConfigErrorRecoveryEnableAssert; // = true // Enable asserts on recoverable error. By default call IM_ASSERT() when returning from a failing IM_ASSERT_USER_ERROR()
+ bool ConfigErrorRecoveryEnableDebugLog; // = true // Enable debug log output on recoverable errors.
+ bool ConfigErrorRecoveryEnableTooltip; // = true // Enable tooltip on recoverable errors. The tooltip include a way to enable asserts if they were disabled.
+
// Option to enable various debug tools showing buttons that will call the IM_DEBUG_BREAK() macro.
// - The Item Picker tool will be available regardless of this being enabled, in order to maximize its discoverability.
// - Requires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.
// e.g. io.ConfigDebugIsDebuggerPresent = ::IsDebuggerPresent() on Win32, or refer to ImOsIsDebuggerPresent() imgui_test_engine/imgui_te_utils.cpp for a Unix compatible version).
bool ConfigDebugIsDebuggerPresent; // = false // Enable various tools calling IM_DEBUG_BREAK().
+ // Tools to detect code submitting items with conflicting/duplicate IDs
+ // - Code should use PushID()/PopID() in loops, or append "##xx" to same-label identifiers.
+ // - Empty label e.g. Button("") == same ID as parent widget/node. Use Button("##xx") instead!
+ // - See FAQ https://github.com/ocornut/imgui/blob/master/docs/FAQ.md#q-about-the-id-stack-system
+ bool ConfigDebugHighlightIdConflicts;// = true // Highlight and show an error message when multiple items have conflicting identifiers.
+
// Tools to test correct Begin/End and BeginChild/EndChild behaviors.
// - Presently Begin()/End() and BeginChild()/EndChild() needs to ALWAYS be called in tandem, regardless of return value of BeginXXX()
// - This is inconsistent with other BeginXXX functions and create confusion for many users.
@@ -2271,13 +2397,13 @@ struct ImGuiIO
// Option to deactivate io.AddFocusEvent(false) handling.
// - May facilitate interactions with a debugger when focus loss leads to clearing inputs data.
// - Backends may have other side-effects on focus loss, so this will reduce side-effects but not necessary remove all of them.
- bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys() in input processing.
+ bool ConfigDebugIgnoreFocusLoss; // = false // Ignore io.AddFocusEvent(false), consequently not calling io.ClearInputKeys()/io.ClearInputMouse() in input processing.
// Option to audit .ini data
bool ConfigDebugIniSettings; // = false // Save .ini data with extra comments (particularly helpful for Docking, but makes saving slower)
//------------------------------------------------------------------
- // Platform Functions
+ // Platform Identifiers
// (the imgui_impl_xxxx backend files are setting those up for you)
//------------------------------------------------------------------
@@ -2288,19 +2414,6 @@ struct ImGuiIO
void* BackendRendererUserData; // = NULL // User data for renderer backend
void* BackendLanguageUserData; // = NULL // User data for non C++ programming language backend
- // Optional: Access OS clipboard
- // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
- const char* (*GetClipboardTextFn)(void* user_data);
- void (*SetClipboardTextFn)(void* user_data, const char* text);
- void* ClipboardUserData;
-
- // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows)
- // (default to use native imm32 api on Windows)
- void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data);
-
- // Optional: Platform locale
- ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
-
//------------------------------------------------------------------
// Input - Call before calling NewFrame()
//------------------------------------------------------------------
@@ -2321,7 +2434,8 @@ struct ImGuiIO
IMGUI_API void SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native_scancode, int native_legacy_index = -1); // [Optional] Specify index for legacy <1.87 IsKeyXXX() functions with native indices + specify native keycode, scancode.
IMGUI_API void SetAppAcceptingEvents(bool accepting_events); // Set master flag for accepting key/mouse/text events (default to true). Useful if you have native dialog boxes that are interrupting your application loop/refresh, and you want to disable events being queued while your app is frozen.
IMGUI_API void ClearEventsQueue(); // Clear all incoming events.
- IMGUI_API void ClearInputKeys(); // Clear current keyboard/mouse/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
+ IMGUI_API void ClearInputKeys(); // Clear current keyboard/gamepad state + current frame text input buffer. Equivalent to releasing all keys/buttons.
+ IMGUI_API void ClearInputMouse(); // Clear current mouse state.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
IMGUI_API void ClearInputCharacters(); // [Obsoleted in 1.89.8] Clear the current frame text input buffer. Now included within ClearInputKeys().
#endif
@@ -2404,6 +2518,14 @@ struct ImGuiIO
//void* ImeWindowHandle; // [Obsoleted in 1.87] Set ImGuiViewport::PlatformHandleRaw instead. Set this to your HWND to get automatic IME cursor positioning.
#endif
+ // Legacy: before 1.91.1, clipboard functions were stored in ImGuiIO instead of ImGuiPlatformIO.
+ // As this is will affect all users of custom engines/backends, we are providing proper legacy redirection (will obsolete).
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ const char* (*GetClipboardTextFn)(void* user_data);
+ void (*SetClipboardTextFn)(void* user_data, const char* text);
+ void* ClipboardUserData;
+#endif
+
IMGUI_API ImGuiIO();
};
@@ -2574,6 +2696,16 @@ struct ImGuiTextBuffer
IMGUI_API void appendfv(const char* fmt, va_list args) IM_FMTLIST(2);
};
+// [Internal] Key+Value for ImGuiStorage
+struct ImGuiStoragePair
+{
+ ImGuiID key;
+ union { int val_i; float val_f; void* val_p; };
+ ImGuiStoragePair(ImGuiID _key, int _val) { key = _key; val_i = _val; }
+ ImGuiStoragePair(ImGuiID _key, float _val) { key = _key; val_f = _val; }
+ ImGuiStoragePair(ImGuiID _key, void* _val) { key = _key; val_p = _val; }
+};
+
// Helper: Key->Value storage
// Typically you don't have to worry about this since a storage is held within each Window.
// We use it to e.g. store collapse state for a tree (Int 0/1)
@@ -2585,15 +2717,6 @@ struct ImGuiTextBuffer
struct ImGuiStorage
{
// [Internal]
- struct ImGuiStoragePair
- {
- ImGuiID key;
- union { int val_i; float val_f; void* val_p; };
- ImGuiStoragePair(ImGuiID _key, int _val) { key = _key; val_i = _val; }
- ImGuiStoragePair(ImGuiID _key, float _val) { key = _key; val_f = _val; }
- ImGuiStoragePair(ImGuiID _key, void* _val) { key = _key; val_p = _val; }
- };
-
ImVector<ImGuiStoragePair> Data;
// - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
@@ -2622,6 +2745,10 @@ struct ImGuiStorage
IMGUI_API void BuildSortByKey();
// Obsolete: use on your own storage if you know only integer are being stored (open/close all tree nodes)
IMGUI_API void SetAllInt(int val);
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ //typedef ::ImGuiStoragePair ImGuiStoragePair; // 1.90.8: moved type outside struct
+#endif
};
// Helper: Manually clip large list of items.
@@ -2652,9 +2779,10 @@ struct ImGuiListClipper
int ItemsCount; // [Internal] Number of items
float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it
float StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed
+ double StartSeekOffsetY; // [Internal] Account for frozen rows in a table and initial loss of precision in very large windows.
void* TempData; // [Internal] Internal data
- // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step)
+ // items_count: Use INT_MAX if you don't know how many items you have (in which case the cursor won't be advanced in the final step, and you can call SeekCursorForItem() manually if you need)
// items_height: Use -1.0f to be calculated automatically on first step. Otherwise pass in the distance between your items, typically GetTextLineHeightWithSpacing() or GetFrameHeightWithSpacing().
IMGUI_API ImGuiListClipper();
IMGUI_API ~ImGuiListClipper();
@@ -2667,6 +2795,11 @@ struct ImGuiListClipper
inline void IncludeItemByIndex(int item_index) { IncludeItemsByIndex(item_index, item_index + 1); }
IMGUI_API void IncludeItemsByIndex(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped.
+ // Seek cursor toward given item. This is automatically called while stepping.
+ // - The only reason to call this is: you can use ImGuiListClipper::Begin(INT_MAX) if you don't know item count ahead of time.
+ // - In this case, after all steps are done, you'll want to call SeekCursorForItem(item_count).
+ IMGUI_API void SeekCursorForItem(int item_index);
+
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
inline void IncludeRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.9]
inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6]
@@ -2677,7 +2810,7 @@ struct ImGuiListClipper
// Helpers: ImVec2/ImVec4 operators
// - It is important that we are keeping those disabled by default so they don't leak in user space.
// - This is in order to allow user enabling implicit cast operators between ImVec2/ImVec4 and their own types (using IM_VEC2_CLASS_EXTRA in imconfig.h)
-// - You can use '#define IMGUI_DEFINE_MATH_OPERATORS' to import our operators, provided as a courtesy.
+// - Add '#define IMGUI_DEFINE_MATH_OPERATORS' before including this file (or in imconfig.h) to access courtesy maths operators for ImVec2 and ImVec4.
#ifdef IMGUI_DEFINE_MATH_OPERATORS
#define IMGUI_DEFINE_MATH_OPERATORS_IMPLEMENTED
IM_MSVC_RUNTIME_CHECKS_OFF
@@ -2747,6 +2880,154 @@ struct ImColor
static ImColor HSV(float h, float s, float v, float a = 1.0f) { float r, g, b; ImGui::ColorConvertHSVtoRGB(h, s, v, r, g, b); return ImColor(r, g, b, a); }
};
+//-----------------------------------------------------------------------------
+// [SECTION] Multi-Select API flags and structures (ImGuiMultiSelectFlags, ImGuiSelectionRequestType, ImGuiSelectionRequest, ImGuiMultiSelectIO, ImGuiSelectionBasicStorage)
+//-----------------------------------------------------------------------------
+
+// Multi-selection system
+// Documentation at: https://github.com/ocornut/imgui/wiki/Multi-Select
+// - Refer to 'Demo->Widgets->Selection State & Multi-Select' for demos using this.
+// - This system implements standard multi-selection idioms (CTRL+Mouse/Keyboard, SHIFT+Mouse/Keyboard, etc)
+// with support for clipper (skipping non-visible items), box-select and many other details.
+// - Selectable(), Checkbox() are supported but custom widgets may use it as well.
+// - TreeNode() is technically supported but... using this correctly is more complicated: you need some sort of linear/random access to your tree,
+// which is suited to advanced trees setups also implementing filters and clipper. We will work toward simplifying and demoing it.
+// - In the spirit of Dear ImGui design, your code owns actual selection data.
+// This is designed to allow all kinds of selection storage you may use in your application e.g. set/map/hash.
+// About ImGuiSelectionBasicStorage:
+// - This is an optional helper to store a selection state and apply selection requests.
+// - It is used by our demos and provided as a convenience to quickly implement multi-selection.
+// Usage:
+// - Identify submitted items with SetNextItemSelectionUserData(), most likely using an index into your current data-set.
+// - Store and maintain actual selection data using persistent object identifiers.
+// - Usage flow:
+// BEGIN - (1) Call BeginMultiSelect() and retrieve the ImGuiMultiSelectIO* result.
+// - (2) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 6.
+// - (3) [If using clipper] You need to make sure RangeSrcItem is always submitted. Calculate its index and pass to clipper.IncludeItemByIndex(). If storing indices in ImGuiSelectionUserData, a simple clipper.IncludeItemByIndex(ms_io->RangeSrcItem) call will work.
+// LOOP - (4) Submit your items with SetNextItemSelectionUserData() + Selectable()/TreeNode() calls.
+// END - (5) Call EndMultiSelect() and retrieve the ImGuiMultiSelectIO* result.
+// - (6) Honor request list (SetAll/SetRange requests) by updating your selection data. Same code as Step 2.
+// If you submit all items (no clipper), Step 2 and 3 are optional and will be handled by each item themselves. It is fine to always honor those steps.
+// About ImGuiSelectionUserData:
+// - This can store an application-defined identifier (e.g. index or pointer) submitted via SetNextItemSelectionUserData().
+// - In return we store them into RangeSrcItem/RangeFirstItem/RangeLastItem and other fields in ImGuiMultiSelectIO.
+// - Most applications will store an object INDEX, hence the chosen name and type. Storing an index is natural, because
+// SetRange requests will give you two end-points and you will need to iterate/interpolate between them to update your selection.
+// - However it is perfectly possible to store a POINTER or another IDENTIFIER inside ImGuiSelectionUserData.
+// Our system never assume that you identify items by indices, it never attempts to interpolate between two values.
+// - If you enable ImGuiMultiSelectFlags_NoRangeSelect then it is guaranteed that you will never have to interpolate
+// between two ImGuiSelectionUserData, which may be a convenient way to use part of the feature with less code work.
+// - As most users will want to store an index, for convenience and to reduce confusion we use ImS64 instead of void*,
+// being syntactically easier to downcast. Feel free to reinterpret_cast and store a pointer inside.
+
+// Flags for BeginMultiSelect()
+enum ImGuiMultiSelectFlags_
+{
+ ImGuiMultiSelectFlags_None = 0,
+ ImGuiMultiSelectFlags_SingleSelect = 1 << 0, // Disable selecting more than one item. This is available to allow single-selection code to share same code/logic if desired. It essentially disables the main purpose of BeginMultiSelect() tho!
+ ImGuiMultiSelectFlags_NoSelectAll = 1 << 1, // Disable CTRL+A shortcut to select all.
+ ImGuiMultiSelectFlags_NoRangeSelect = 1 << 2, // Disable Shift+selection mouse/keyboard support (useful for unordered 2D selection). With BoxSelect is also ensure contiguous SetRange requests are not combined into one. This allows not handling interpolation in SetRange requests.
+ ImGuiMultiSelectFlags_NoAutoSelect = 1 << 3, // Disable selecting items when navigating (useful for e.g. supporting range-select in a list of checkboxes).
+ ImGuiMultiSelectFlags_NoAutoClear = 1 << 4, // Disable clearing selection when navigating or selecting another one (generally used with ImGuiMultiSelectFlags_NoAutoSelect. useful for e.g. supporting range-select in a list of checkboxes).
+ ImGuiMultiSelectFlags_NoAutoClearOnReselect = 1 << 5, // Disable clearing selection when clicking/selecting an already selected item.
+ ImGuiMultiSelectFlags_BoxSelect1d = 1 << 6, // Enable box-selection with same width and same x pos items (e.g. full row Selectable()). Box-selection works better with little bit of spacing between items hit-box in order to be able to aim at empty space.
+ ImGuiMultiSelectFlags_BoxSelect2d = 1 << 7, // Enable box-selection with varying width or varying x pos items support (e.g. different width labels, or 2D layout/grid). This is slower: alters clipping logic so that e.g. horizontal movements will update selection of normally clipped items.
+ ImGuiMultiSelectFlags_BoxSelectNoScroll = 1 << 8, // Disable scrolling when box-selecting near edges of scope.
+ ImGuiMultiSelectFlags_ClearOnEscape = 1 << 9, // Clear selection when pressing Escape while scope is focused.
+ ImGuiMultiSelectFlags_ClearOnClickVoid = 1 << 10, // Clear selection when clicking on empty location within scope.
+ ImGuiMultiSelectFlags_ScopeWindow = 1 << 11, // Scope for _BoxSelect and _ClearOnClickVoid is whole window (Default). Use if BeginMultiSelect() covers a whole window or used a single time in same window.
+ ImGuiMultiSelectFlags_ScopeRect = 1 << 12, // Scope for _BoxSelect and _ClearOnClickVoid is rectangle encompassing BeginMultiSelect()/EndMultiSelect(). Use if BeginMultiSelect() is called multiple times in same window.
+ ImGuiMultiSelectFlags_SelectOnClick = 1 << 13, // Apply selection on mouse down when clicking on unselected item. (Default)
+ ImGuiMultiSelectFlags_SelectOnClickRelease = 1 << 14, // Apply selection on mouse release when clicking an unselected item. Allow dragging an unselected item without altering selection.
+ //ImGuiMultiSelectFlags_RangeSelect2d = 1 << 15, // Shift+Selection uses 2d geometry instead of linear sequence, so possible to use Shift+up/down to select vertically in grid. Analogous to what BoxSelect does.
+ ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one.
+};
+
+// Main IO structure returned by BeginMultiSelect()/EndMultiSelect().
+// This mainly contains a list of selection requests.
+// - Use 'Demo->Tools->Debug Log->Selection' to see requests as they happen.
+// - Some fields are only useful if your list is dynamic and allows deletion (getting post-deletion focus/state right is shown in the demo)
+// - Below: who reads/writes each fields? 'r'=read, 'w'=write, 'ms'=multi-select code, 'app'=application/user code.
+struct ImGuiMultiSelectIO
+{
+ //------------------------------------------// BeginMultiSelect / EndMultiSelect
+ ImVector<ImGuiSelectionRequest> Requests; // ms:w, app:r / ms:w app:r // Requests to apply to your selection data.
+ ImGuiSelectionUserData RangeSrcItem; // ms:w app:r / // (If using clipper) Begin: Source item (often the first selected item) must never be clipped: use clipper.IncludeItemByIndex() to ensure it is submitted.
+ ImGuiSelectionUserData NavIdItem; // ms:w, app:r / // (If using deletion) Last known SetNextItemSelectionUserData() value for NavId (if part of submitted items).
+ bool NavIdSelected; // ms:w, app:r / app:r // (If using deletion) Last known selection state for NavId (if part of submitted items).
+ bool RangeSrcReset; // app:w / ms:r // (If using deletion) Set before EndMultiSelect() to reset ResetSrcItem (e.g. if deleted selection).
+ int ItemsCount; // ms:w, app:r / app:r // 'int items_count' parameter to BeginMultiSelect() is copied here for convenience, allowing simpler calls to your ApplyRequests handler. Not used internally.
+};
+
+// Selection request type
+enum ImGuiSelectionRequestType
+{
+ ImGuiSelectionRequestType_None = 0,
+ ImGuiSelectionRequestType_SetAll, // Request app to clear selection (if Selected==false) or select all items (if Selected==true). We cannot set RangeFirstItem/RangeLastItem as its contents is entirely up to user (not necessarily an index)
+ ImGuiSelectionRequestType_SetRange, // Request app to select/unselect [RangeFirstItem..RangeLastItem] items (inclusive) based on value of Selected. Only EndMultiSelect() request this, app code can read after BeginMultiSelect() and it will always be false.
+};
+
+// Selection request item
+struct ImGuiSelectionRequest
+{
+ //------------------------------------------// BeginMultiSelect / EndMultiSelect
+ ImGuiSelectionRequestType Type; // ms:w, app:r / ms:w, app:r // Request type. You'll most often receive 1 Clear + 1 SetRange with a single-item range.
+ bool Selected; // ms:w, app:r / ms:w, app:r // Parameter for SetAll/SetRange requests (true = select, false = unselect)
+ ImS8 RangeDirection; // / ms:w app:r // Parameter for SetRange request: +1 when RangeFirstItem comes before RangeLastItem, -1 otherwise. Useful if you want to preserve selection order on a backward Shift+Click.
+ ImGuiSelectionUserData RangeFirstItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from top to bottom).
+ ImGuiSelectionUserData RangeLastItem; // / ms:w, app:r // Parameter for SetRange request (this is generally == RangeSrcItem when shift selecting from bottom to top). Inclusive!
+};
+
+// Optional helper to store multi-selection state + apply multi-selection requests.
+// - Used by our demos and provided as a convenience to easily implement basic multi-selection.
+// - Iterate selection with 'void* it = NULL; ImGuiID id; while (selection.GetNextSelectedItem(&it, &id)) { ... }'
+// Or you can check 'if (Contains(id)) { ... }' for each possible object if their number is not too high to iterate.
+// - USING THIS IS NOT MANDATORY. This is only a helper and not a required API.
+// To store a multi-selection, in your application you could:
+// - Use this helper as a convenience. We use our simple key->value ImGuiStorage as a std::set<ImGuiID> replacement.
+// - Use your own external storage: e.g. std::set<MyObjectId>, std::vector<MyObjectId>, interval trees, intrusively stored selection etc.
+// In ImGuiSelectionBasicStorage we:
+// - always use indices in the multi-selection API (passed to SetNextItemSelectionUserData(), retrieved in ImGuiMultiSelectIO)
+// - use the AdapterIndexToStorageId() indirection layer to abstract how persistent selection data is derived from an index.
+// - use decently optimized logic to allow queries and insertion of very large selection sets.
+// - do not preserve selection order.
+// Many combinations are possible depending on how you prefer to store your items and how you prefer to store your selection.
+// Large applications are likely to eventually want to get rid of this indirection layer and do their own thing.
+// See https://github.com/ocornut/imgui/wiki/Multi-Select for details and pseudo-code using this helper.
+struct ImGuiSelectionBasicStorage
+{
+ // Members
+ int Size; // // Number of selected items, maintained by this helper.
+ bool PreserveOrder; // = false // GetNextSelectedItem() will return ordered selection (currently implemented by two additional sorts of selection. Could be improved)
+ void* UserData; // = NULL // User data for use by adapter function // e.g. selection.UserData = (void*)my_items;
+ ImGuiID (*AdapterIndexToStorageId)(ImGuiSelectionBasicStorage* self, int idx); // e.g. selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { return ((MyItems**)self->UserData)[idx]->ID; };
+ int _SelectionOrder;// [Internal] Increasing counter to store selection order
+ ImGuiStorage _Storage; // [Internal] Selection set. Think of this as similar to e.g. std::set<ImGuiID>. Prefer not accessing directly: iterate with GetNextSelectedItem().
+
+ // Methods
+ IMGUI_API ImGuiSelectionBasicStorage();
+ IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests coming from BeginMultiSelect() and EndMultiSelect() functions. It uses 'items_count' passed to BeginMultiSelect()
+ IMGUI_API bool Contains(ImGuiID id) const; // Query if an item id is in selection.
+ IMGUI_API void Clear(); // Clear selection
+ IMGUI_API void Swap(ImGuiSelectionBasicStorage& r); // Swap two selections
+ IMGUI_API void SetItemSelected(ImGuiID id, bool selected); // Add/remove an item from selection (generally done by ApplyRequests() function)
+ IMGUI_API bool GetNextSelectedItem(void** opaque_it, ImGuiID* out_id); // Iterate selection with 'void* it = NULL; ImGuiId id; while (selection.GetNextSelectedItem(&it, &id)) { ... }'
+ inline ImGuiID GetStorageIdFromIndex(int idx) { return AdapterIndexToStorageId(this, idx); } // Convert index to item id based on provided adapter.
+};
+
+// Optional helper to apply multi-selection requests to existing randomly accessible storage.
+// Convenient if you want to quickly wire multi-select API on e.g. an array of bool or items storing their own selection state.
+struct ImGuiSelectionExternalStorage
+{
+ // Members
+ void* UserData; // User data for use by adapter function // e.g. selection.UserData = (void*)my_items;
+ void (*AdapterSetItemSelected)(ImGuiSelectionExternalStorage* self, int idx, bool selected); // e.g. AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int idx, bool selected) { ((MyItems**)self->UserData)[idx]->Selected = selected; }
+
+ // Methods
+ IMGUI_API ImGuiSelectionExternalStorage();
+ IMGUI_API void ApplyRequests(ImGuiMultiSelectIO* ms_io); // Apply selection requests by using AdapterSetItemSelected() calls
+};
+
//-----------------------------------------------------------------------------
// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.
@@ -3005,8 +3286,8 @@ struct ImDrawList
//inline void AddEllipse(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0, float thickness = 1.0f) { AddEllipse(center, ImVec2(radius_x, radius_y), col, rot, num_segments, thickness); } // OBSOLETED in 1.90.5 (Mar 2024)
//inline void AddEllipseFilled(const ImVec2& center, float radius_x, float radius_y, ImU32 col, float rot = 0.0f, int num_segments = 0) { AddEllipseFilled(center, ImVec2(radius_x, radius_y), col, rot, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024)
//inline void PathEllipticalArcTo(const ImVec2& center, float radius_x, float radius_y, float rot, float a_min, float a_max, int num_segments = 0) { PathEllipticalArcTo(center, ImVec2(radius_x, radius_y), rot, a_min, a_max, num_segments); } // OBSOLETED in 1.90.5 (Mar 2024)
- //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
- //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
+ //inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
+ //inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); } // OBSOLETED in 1.80 (Jan 2021)
// [Internal helpers]
IMGUI_API void _ResetForNewFrame();
@@ -3016,6 +3297,7 @@ struct ImDrawList
IMGUI_API void _OnChangedClipRect();
IMGUI_API void _OnChangedTextureID();
IMGUI_API void _OnChangedVtxOffset();
+ IMGUI_API void _SetTextureID(ImTextureID texture_id);
IMGUI_API int _CalcCircleAutoSegmentCount(float radius) const;
IMGUI_API void _PathArcToFastEx(const ImVec2& center, float radius, int a_min_sample, int a_max_sample, int a_step);
IMGUI_API void _PathArcToN(const ImVec2& center, float radius, float a_min, float a_max, int num_segments);
@@ -3250,7 +3532,7 @@ struct ImFontAtlas
struct ImFont
{
// Members: Hot ~20/24 bytes (for CalcTextSize)
- ImVector<float> IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this this info, and are often bottleneck in large UI).
+ ImVector<float> IndexAdvanceX; // 12-16 // out // // Sparse. Glyphs->AdvanceX in a directly indexable way (cache-friendly for CalcTextSize functions which only this info, and are often bottleneck in large UI).
float FallbackAdvanceX; // 4 // out // = FallbackGlyph->AdvanceX
float FontSize; // 4 // in // // Height of characters/line, set during loading (don't change after loading)
@@ -3270,7 +3552,7 @@ struct ImFont
float EllipsisCharStep; // 4 // out // Step between characters when EllipsisCount > 0
bool DirtyLookupTables; // 1 // out //
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
- float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
+ float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize] (unscaled)
int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
ImU8 Used4kPagesMap[(IM_UNICODE_CODEPOINT_MAX+1)/4096/8]; // 2 bytes if ImWchar=ImWchar16, 34 bytes if ImWchar==ImWchar32. Store 1-bit for each block of 4K codepoints that has one active glyph. This is mainly used to facilitate iterations across all used codepoints.
@@ -3310,7 +3592,7 @@ enum ImGuiViewportFlags_
ImGuiViewportFlags_None = 0,
ImGuiViewportFlags_IsPlatformWindow = 1 << 0, // Represent a Platform Window
ImGuiViewportFlags_IsPlatformMonitor = 1 << 1, // Represent a Platform Monitor (unused yet)
- ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Was created/managed by the user application? (rather than our backend)
+ ImGuiViewportFlags_OwnedByApp = 1 << 2, // Platform Window: Is created/managed by the user application? (rather than our backend)
ImGuiViewportFlags_NoDecoration = 1 << 3, // Platform Window: Disable platform decorations: title bar, borders, etc. (generally set all windows, but if ImGuiConfigFlags_ViewportsDecoration is set we only set this on popups/tooltips)
ImGuiViewportFlags_NoTaskBarIcon = 1 << 4, // Platform Window: Disable platform task bar icon (generally set on popups/tooltips, or all windows if ImGuiConfigFlags_ViewportsNoTaskBarIcon is set)
ImGuiViewportFlags_NoFocusOnAppearing = 1 << 5, // Platform Window: Don't take focus when created.
@@ -3352,7 +3634,7 @@ struct ImGuiViewport
// The library never uses those fields, they are merely storage to facilitate backend implementation.
void* RendererUserData; // void* to hold custom data structure for the renderer (e.g. swap chain, framebuffers etc.). generally set by your Renderer_CreateWindow function.
void* PlatformUserData; // void* to hold custom data structure for the OS / platform (e.g. windowing info, render context). generally set by your Platform_CreateWindow function.
- void* PlatformHandle; // void* for FindViewportByPlatformHandle(). (e.g. suggested to use natural platform handle such as HWND, GLFWWindow*, SDL_Window*)
+ void* PlatformHandle; // void* to hold higher-level, platform window handle (e.g. HWND, GLFWWindow*, SDL_Window*), for FindViewportByPlatformHandle().
void* PlatformHandleRaw; // void* to hold lower-level, platform-native window handle (under Win32 this is expected to be a HWND, unused for other platforms), when using an abstraction layer like GLFW or SDL (where PlatformHandle would be a SDL_Window*)
bool PlatformWindowCreated; // Platform window has been created (Platform_CreateWindow() has been called). This is false during the first frame where a viewport is being created.
bool PlatformRequestMove; // Platform window requested move (e.g. window was moved by the OS / host window manager, authoritative position will be OS window position)
@@ -3368,17 +3650,18 @@ struct ImGuiViewport
};
//-----------------------------------------------------------------------------
-// [SECTION] Platform Dependent Interfaces (for e.g. multi-viewport support)
+// [SECTION] ImGuiPlatformIO + other Platform Dependent Interfaces (ImGuiPlatformMonitor, ImGuiPlatformImeData)
//-----------------------------------------------------------------------------
-// [BETA] (Optional) This is completely optional, for advanced users!
+
+// [BETA] (Optional) Multi-Viewport Support!
// If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now.
//
// This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport.
// This is achieved by creating new Platform/OS windows on the fly, and rendering into them.
// Dear ImGui manages the viewport structures, and the backend create and maintain one Platform/OS window for each of those viewports.
//
+// See Recap: https://github.com/ocornut/imgui/wiki/Multi-Viewports
// See Glossary https://github.com/ocornut/imgui/wiki/Glossary for details about some of the terminology.
-// See Thread https://github.com/ocornut/imgui/issues/1542 for gifs, news and questions about this evolving feature.
//
// About the coordinates system:
// - When multi-viewports are enabled, all Dear ImGui coordinates become absolute coordinates (same as OS coordinates!)
@@ -3416,14 +3699,40 @@ struct ImGuiViewport
// or you may decide to never setup those pointers and call your code directly. They are a convenience, not an obligatory interface.
//-----------------------------------------------------------------------------
-// (Optional) Access via ImGui::GetPlatformIO()
+// Access via ImGui::GetPlatformIO()
struct ImGuiPlatformIO
{
+ IMGUI_API ImGuiPlatformIO();
+
+ //------------------------------------------------------------------
+ // Input - Interface with OS/backends (basic)
//------------------------------------------------------------------
- // Input - Backend interface/functions + Monitor List
+
+ // Optional: Access OS clipboard
+ // (default to use native Win32 clipboard on Windows, otherwise uses a private clipboard. Override to access OS clipboard on other architectures)
+ const char* (*Platform_GetClipboardTextFn)(ImGuiContext* ctx);
+ void (*Platform_SetClipboardTextFn)(ImGuiContext* ctx, const char* text);
+ void* Platform_ClipboardUserData;
+
+ // Optional: Open link/folder/file in OS Shell
+ // (default to use ShellExecuteA() on Windows, system() on Linux/Mac)
+ bool (*Platform_OpenInShellFn)(ImGuiContext* ctx, const char* path);
+ void* Platform_OpenInShellUserData;
+
+ // Optional: Notify OS Input Method Editor of the screen position of your cursor for text input position (e.g. when using Japanese/Chinese IME on Windows)
+ // (default to use native imm32 api on Windows)
+ void (*Platform_SetImeDataFn)(ImGuiContext* ctx, ImGuiViewport* viewport, ImGuiPlatformImeData* data);
+ void* Platform_ImeUserData;
+ //void (*SetPlatformImeDataFn)(ImGuiViewport* viewport, ImGuiPlatformImeData* data); // [Renamed to platform_io.PlatformSetImeDataFn in 1.91.1]
+
+ // Optional: Platform locale
+ // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
+ ImWchar Platform_LocaleDecimalPoint; // '.'
+
+ //------------------------------------------------------------------
+ // Input - Interface with OS/backends (Multi-Viewport support!)
//------------------------------------------------------------------
- // (Optional) Platform functions (e.g. Win32, GLFW, SDL2)
// For reference, the second column shows which function are generally calling the Platform Functions:
// N = ImGui::NewFrame() ~ beginning of the dear imgui frame: read info from platform/OS windows (latest size/position)
// F = ImGui::Begin(), ImGui::EndFrame() ~ during the dear imgui frame
@@ -3431,12 +3740,12 @@ struct ImGuiPlatformIO
// R = ImGui::RenderPlatformWindowsDefault() ~ render
// D = ImGui::DestroyPlatformWindows() ~ shutdown
// The general idea is that NewFrame() we will read the current Platform/OS state, and UpdatePlatformWindows() will write to it.
- //
- // The functions are designed so we can mix and match 2 imgui_impl_xxxx files, one for the Platform (~window/input handling), one for Renderer.
- // Custom engine backends will often provide both Platform and Renderer interfaces and so may not need to use all functions.
- // Platform functions are typically called before their Renderer counterpart, apart from Destroy which are called the other way.
- // Platform function --------------------------------------------------- Called by -----
+ // The handlers are designed so we can mix and match two imgui_impl_xxxx files, one Platform backend and one Renderer backend.
+ // Custom engine backends will often provide both Platform and Renderer interfaces together and so may not need to use all functions.
+ // Platform functions are typically called _before_ their Renderer counterpart, apart from Destroy which are called the other way.
+
+ // Platform Backend functions (e.g. Win32, GLFW, SDL) ------------------- Called by -----
void (*Platform_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create a new platform window for the given viewport
void (*Platform_DestroyWindow)(ImGuiViewport* vp); // N . U . D //
void (*Platform_ShowWindow)(ImGuiViewport* vp); // . . U . . // Newly created windows are initially hidden so SetWindowPos/Size/Title can be called on them before showing the window
@@ -3454,9 +3763,10 @@ struct ImGuiPlatformIO
void (*Platform_SwapBuffers)(ImGuiViewport* vp, void* render_arg); // . . . R . // (Optional) Call Present/SwapBuffers (platform side! This is often unused!). 'render_arg' is the value passed to RenderPlatformWindowsDefault().
float (*Platform_GetWindowDpiScale)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Return DPI scale for this viewport. 1.0f = 96 DPI.
void (*Platform_OnChangedViewport)(ImGuiViewport* vp); // . F . . . // (Optional) [BETA] FIXME-DPI: DPI handling: Called during Begin() every time the viewport we are outputting into changes, so backend has a chance to swap fonts to adjust style.
+ ImVec4 (*Platform_GetWindowWorkAreaInsets)(ImGuiViewport* vp); // N . . . . // (Optional) [BETA] Get initial work area inset for the viewport (won't be covered by main menu bar, dockspace over viewport etc.). Default to (0,0),(0,0). 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land.
int (*Platform_CreateVkSurface)(ImGuiViewport* vp, ImU64 vk_inst, const void* vk_allocators, ImU64* out_vk_surface); // (Optional) For a Vulkan Renderer to call into Platform code (since the surface creation needs to tie them both).
- // (Optional) Renderer functions (e.g. DirectX, OpenGL, Vulkan)
+ // Renderer Backend functions (e.g. DirectX, OpenGL, Vulkan) ------------ Called by -----
void (*Renderer_CreateWindow)(ImGuiViewport* vp); // . . U . . // Create swap chain, frame buffers etc. (called after Platform_CreateWindow)
void (*Renderer_DestroyWindow)(ImGuiViewport* vp); // N . U . D // Destroy swap chain, frame buffers etc. (called before Platform_DestroyWindow)
void (*Renderer_SetWindowSize)(ImGuiViewport* vp, ImVec2 size); // . . U . . // Resize swap chain, frame buffers etc. (called after Platform_SetWindowSize)
@@ -3475,7 +3785,6 @@ struct ImGuiPlatformIO
// Viewports list (the list is updated by calling ImGui::EndFrame or ImGui::Render)
// (in the future we will attempt to organize this feature to remove the need for a "main viewport")
ImVector<ImGuiViewport*> Viewports; // Main viewports, followed by all secondary viewports.
- ImGuiPlatformIO() { memset(this, 0, sizeof(*this)); } // Zero clear
};
// (Optional) This is required when enabling multi-viewport. Represent the bounds of each connected monitor/display and their DPI.
@@ -3489,7 +3798,7 @@ struct ImGuiPlatformMonitor
ImGuiPlatformMonitor() { MainPos = MainSize = WorkPos = WorkSize = ImVec2(0, 0); DpiScale = 1.0f; PlatformHandle = NULL; }
};
-// (Optional) Support for IME (Input Method Editor) via the io.SetPlatformImeDataFn() function.
+// (Optional) Support for IME (Input Method Editor) via the platform_io.Platform_SetImeDataFn() function.
struct ImGuiPlatformImeData
{
bool WantVisible; // A widget wants the IME to be visible
@@ -3508,29 +3817,37 @@ struct ImGuiPlatformImeData
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui
{
+ // OBSOLETED in 1.91.0 (from July 2024)
+ static inline void PushButtonRepeat(bool repeat) { PushItemFlag(ImGuiItemFlags_ButtonRepeat, repeat); }
+ static inline void PopButtonRepeat() { PopItemFlag(); }
+ static inline void PushTabStop(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); }
+ static inline void PopTabStop() { PopItemFlag(); }
+ IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
+ IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
+ IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
// OBSOLETED in 1.90.0 (from September 2023)
- static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); }
- static inline void EndChildFrame() { EndChild(); }
- //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border
- //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool border, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, border ? ImGuiChildFlags_Border : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Border
- static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); }
- IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1);
+ static inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags window_flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, window_flags); }
+ static inline void EndChildFrame() { EndChild(); }
+ //static inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags){ return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
+ //static inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
+ static inline void ShowStackToolWindow(bool* p_open = NULL) { ShowIDStackToolWindow(p_open); }
IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1);
+ IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1);
// OBSOLETED in 1.89.7 (from June 2023)
- IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item.
+ IMGUI_API void SetItemAllowOverlap(); // Use SetNextItemAllowOverlap() before item.
// OBSOLETED in 1.89.4 (from March 2023)
- static inline void PushAllowKeyboardFocus(bool tab_stop) { PushTabStop(tab_stop); }
- static inline void PopAllowKeyboardFocus() { PopTabStop(); }
- // OBSOLETED in 1.89 (from August 2022)
- IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // Use new ImageButton() signature (explicit item id, regular FramePadding)
- // OBSOLETED in 1.88 (from May 2022)
- static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value.
- static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value.
- // OBSOLETED in 1.87 (from February 2022)
- IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value!
- //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; }
+ static inline void PushAllowKeyboardFocus(bool tab_stop) { PushItemFlag(ImGuiItemFlags_NoTabStop, !tab_stop); }
+ static inline void PopAllowKeyboardFocus() { PopItemFlag(); }
+ // OBSOLETED in 1.87 (from February 2022 but more formally obsoleted April 2024)
+ IMGUI_API ImGuiKey GetKeyIndex(ImGuiKey key); // Map ImGuiKey_* values into legacy native key index. == io.KeyMap[key]. When using a 1.87+ backend using io.AddKeyEvent(), calling GetKeyIndex() with ANY ImGuiKey_XXXX values will return the same value!
+ //static inline ImGuiKey GetKeyIndex(ImGuiKey key) { IM_ASSERT(key >= ImGuiKey_NamedKey_BEGIN && key < ImGuiKey_NamedKey_END); return key; }
// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)
+ //-- OBSOLETED in 1.89 (from August 2022)
+ //IMGUI_API bool ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0 = ImVec2(0, 0), const ImVec2& uv1 = ImVec2(1, 1), int frame_padding = -1, const ImVec4& bg_col = ImVec4(0, 0, 0, 0), const ImVec4& tint_col = ImVec4(1, 1, 1, 1)); // --> Use new ImageButton() signature (explicit item id, regular FramePadding). Refer to code in 1.91 if you want to grab a copy of this version.
+ //-- OBSOLETED in 1.88 (from May 2022)
+ //static inline void CaptureKeyboardFromApp(bool want_capture_keyboard = true) { SetNextFrameWantCaptureKeyboard(want_capture_keyboard); } // Renamed as name was misleading + removed default value.
+ //static inline void CaptureMouseFromApp(bool want_capture_mouse = true) { SetNextFrameWantCaptureMouse(want_capture_mouse); } // Renamed as name was misleading + removed default value.
//-- OBSOLETED in 1.86 (from November 2021)
//IMGUI_API void CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end); // Code removed, see 1.90 for last version of the code. Calculate range of visible items for large list of evenly sized items. Prefer using ImGuiListClipper.
//-- OBSOLETED in 1.85 (from August 2021)
@@ -3603,8 +3920,8 @@ namespace ImGui
// RENAMED and MERGED both ImGuiKey_ModXXX and ImGuiModFlags_XXX into ImGuiMod_XXX (from September 2022)
// RENAMED ImGuiKeyModFlags -> ImGuiModFlags in 1.88 (from April 2022). Exceptionally commented out ahead of obscolescence schedule to reduce confusion and because they were not meant to be used in the first place.
-typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with any number of ImGuiMod_XXX value", but you may store only mods in there.
-enum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super };
+//typedef ImGuiKeyChord ImGuiModFlags; // == int. We generally use ImGuiKeyChord to mean "a ImGuiKey or-ed with any number of ImGuiMod_XXX value", so you may store mods in there.
+//enum ImGuiModFlags_ { ImGuiModFlags_None = 0, ImGuiModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiModFlags_Shift = ImGuiMod_Shift, ImGuiModFlags_Alt = ImGuiMod_Alt, ImGuiModFlags_Super = ImGuiMod_Super };
//typedef ImGuiKeyChord ImGuiKeyModFlags; // == int
//enum ImGuiKeyModFlags_ { ImGuiKeyModFlags_None = 0, ImGuiKeyModFlags_Ctrl = ImGuiMod_Ctrl, ImGuiKeyModFlags_Shift = ImGuiMod_Shift, ImGuiKeyModFlags_Alt = ImGuiMod_Alt, ImGuiKeyModFlags_Super = ImGuiMod_Super };
diff --git a/backends/imgui/imgui_demo.cpp b/backends/imgui/imgui_demo.cpp
index d57375c3863..7ed778b5783 100644
--- a/backends/imgui/imgui_demo.cpp
+++ b/backends/imgui/imgui_demo.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.90.7 WIP
+// dear imgui, v1.91.3
// (demo code)
// Help:
@@ -11,7 +11,7 @@
// Get the latest version at https://github.com/ocornut/imgui
// How to easily locate code?
-// - Use the Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
+// - Use Tools->Item Picker to debug break in code by clicking any widgets: https://github.com/ocornut/imgui/wiki/Debug-Tools
// - Browse an online version the demo with code linked to hovered widgets: https://pthom.github.io/imgui_manual_online/manual/imgui_manual.html
// - Find a visible string and search for it in the code!
@@ -62,6 +62,7 @@
// - In Visual Studio: CTRL+comma ("Edit.GoToAll") can follow symbols inside comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - In Visual Studio w/ Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols inside comments.
// - In VS Code, CLion, etc.: CTRL+click can follow symbols inside comments.
+// - You can search/grep for all sections listed in the index to find the section.
/*
@@ -69,13 +70,15 @@ Index of this file:
// [SECTION] Forward Declarations
// [SECTION] Helpers
+// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor & Multi-Select demos)
// [SECTION] Demo Window / ShowDemoWindow()
-// - ShowDemoWindow()
-// - sub section: ShowDemoWindowWidgets()
-// - sub section: ShowDemoWindowLayout()
-// - sub section: ShowDemoWindowPopups()
-// - sub section: ShowDemoWindowTables()
-// - sub section: ShowDemoWindowInputs()
+// [SECTION] ShowDemoWindowMenuBar()
+// [SECTION] ShowDemoWindowWidgets()
+// [SECTION] ShowDemoWindowMultiSelect()
+// [SECTION] ShowDemoWindowLayout()
+// [SECTION] ShowDemoWindowPopups()
+// [SECTION] ShowDemoWindowTables()
+// [SECTION] ShowDemoWindowInputs()
// [SECTION] About Window / ShowAboutWindow()
// [SECTION] Style Editor / ShowStyleEditor()
// [SECTION] User Guide / ShowUserGuide()
@@ -93,6 +96,7 @@ Index of this file:
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
+// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
*/
@@ -113,6 +117,9 @@ Index of this file:
#if !defined(_MSC_VER) || _MSC_VER >= 1800
#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
#endif
+#ifdef __EMSCRIPTEN__
+#include <emscripten/version.h> // __EMSCRIPTEN_major__ etc.
+#endif
// Visual Studio warnings
#ifdef _MSC_VER
@@ -190,20 +197,22 @@ Index of this file:
#endif
//-----------------------------------------------------------------------------
-// [SECTION] Forward Declarations, Helpers
+// [SECTION] Forward Declarations
//-----------------------------------------------------------------------------
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
// Forward Declarations
+struct ImGuiDemoWindowData;
static void ShowExampleAppMainMenuBar();
+static void ShowExampleAppAssetsBrowser(bool* p_open);
static void ShowExampleAppConsole(bool* p_open);
static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleAppDockSpace(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppLog(bool* p_open);
static void ShowExampleAppLayout(bool* p_open);
-static void ShowExampleAppPropertyEditor(bool* p_open);
+static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data);
static void ShowExampleAppSimpleOverlay(bool* p_open);
static void ShowExampleAppAutoResize(bool* p_open);
static void ShowExampleAppConstrainedResize(bool* p_open);
@@ -213,8 +222,10 @@ static void ShowExampleAppWindowTitles(bool* p_open);
static void ShowExampleMenuFile();
// We split the contents of the big ShowDemoWindow() function into smaller functions
-// (because the link time of very large functions grow non-linearly)
-static void ShowDemoWindowWidgets();
+// (because the link time of very large functions tends to grow non-linearly)
+static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data);
+static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data);
+static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data);
static void ShowDemoWindowLayout();
static void ShowDemoWindowPopups();
static void ShowDemoWindowTables();
@@ -258,17 +269,123 @@ void* GImGuiDemoMarkerCallbackUserData = NULL;
#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback(__FILE__, __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
//-----------------------------------------------------------------------------
-// [SECTION] Demo Window / ShowDemoWindow()
+// [SECTION] Helpers: ExampleTreeNode, ExampleMemberInfo (for use by Property Editor etc.)
+//-----------------------------------------------------------------------------
+
+// Simple representation for a tree
+// (this is designed to be simple to understand for our demos, not to be fancy or efficient etc.)
+struct ExampleTreeNode
+{
+ // Tree structure
+ char Name[28] = "";
+ int UID = 0;
+ ExampleTreeNode* Parent = NULL;
+ ImVector<ExampleTreeNode*> Childs;
+ unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
+
+ // Leaf Data
+ bool HasData = false; // All leaves have data
+ bool DataMyBool = true;
+ int DataMyInt = 128;
+ ImVec2 DataMyVec2 = ImVec2(0.0f, 3.141592f);
+};
+
+// Simple representation of struct metadata/serialization data.
+// (this is a minimal version of what a typical advanced application may provide)
+struct ExampleMemberInfo
+{
+ const char* Name; // Member name
+ ImGuiDataType DataType; // Member type
+ int DataCount; // Member count (1 when scalar)
+ int Offset; // Offset inside parent structure
+};
+
+// Metadata description of ExampleTreeNode struct.
+static const ExampleMemberInfo ExampleTreeNodeMemberInfos[]
+{
+ { "MyBool", ImGuiDataType_Bool, 1, offsetof(ExampleTreeNode, DataMyBool) },
+ { "MyInt", ImGuiDataType_S32, 1, offsetof(ExampleTreeNode, DataMyInt) },
+ { "MyVec2", ImGuiDataType_Float, 2, offsetof(ExampleTreeNode, DataMyVec2) },
+};
+
+static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, ExampleTreeNode* parent)
+{
+ ExampleTreeNode* node = IM_NEW(ExampleTreeNode);
+ snprintf(node->Name, IM_ARRAYSIZE(node->Name), "%s", name);
+ node->UID = uid;
+ node->Parent = parent;
+ node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
+ if (parent)
+ parent->Childs.push_back(node);
+ return node;
+}
+
+// Create example tree data
+// (this allocates _many_ more times than most other code in either Dear ImGui or others demo)
+static ExampleTreeNode* ExampleTree_CreateDemoTree()
+{
+ static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
+ const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
+ char name_buf[NAME_MAX_LEN];
+ int uid = 0;
+ ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
+ const int root_items_multiplier = 2;
+ for (int idx_L0 = 0; idx_L0 < IM_ARRAYSIZE(root_names) * root_items_multiplier; idx_L0++)
+ {
+ snprintf(name_buf, IM_ARRAYSIZE(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
+ ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
+ const int number_of_childs = (int)strlen(node_L1->Name);
+ for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
+ {
+ snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Child %d", idx_L1);
+ ExampleTreeNode* node_L2 = ExampleTree_CreateNode(name_buf, ++uid, node_L1);
+ node_L2->HasData = true;
+ if (idx_L1 == 0)
+ {
+ snprintf(name_buf, IM_ARRAYSIZE(name_buf), "Sub-child %d", 0);
+ ExampleTreeNode* node_L3 = ExampleTree_CreateNode(name_buf, ++uid, node_L2);
+ node_L3->HasData = true;
+ }
+ }
+ }
+ return node_L0;
+}
+
//-----------------------------------------------------------------------------
-// - ShowDemoWindow()
-// - ShowDemoWindowWidgets()
-// - ShowDemoWindowLayout()
-// - ShowDemoWindowPopups()
-// - ShowDemoWindowTables()
-// - ShowDemoWindowColumns()
-// - ShowDemoWindowInputs()
+// [SECTION] Demo Window / ShowDemoWindow()
//-----------------------------------------------------------------------------
+// Data to be shared accross different functions of the demo.
+struct ImGuiDemoWindowData
+{
+ // Examples Apps (accessible from the "Examples" menu)
+ bool ShowMainMenuBar = false;
+ bool ShowAppAssetsBrowser = false;
+ bool ShowAppConsole = false;
+ bool ShowAppCustomRendering = false;
+ bool ShowAppDocuments = false;
+ bool ShowAppDockSpace = false;
+ bool ShowAppLog = false;
+ bool ShowAppLayout = false;
+ bool ShowAppPropertyEditor = false;
+ bool ShowAppSimpleOverlay = false;
+ bool ShowAppAutoResize = false;
+ bool ShowAppConstrainedResize = false;
+ bool ShowAppFullscreen = false;
+ bool ShowAppLongText = false;
+ bool ShowAppWindowTitles = false;
+
+ // Dear ImGui Tools (accessible from the "Tools" menu)
+ bool ShowMetrics = false;
+ bool ShowDebugLog = false;
+ bool ShowIDStackTool = false;
+ bool ShowStyleEditor = false;
+ bool ShowAbout = false;
+
+ // Other data
+ ExampleTreeNode* DemoTree = NULL;
+};
+
// Demonstrate most Dear ImGui features (this is big function!)
// You may execute this function to experiment with the UI and understand what it does.
// You may then search for keywords in the code when you are interested by a specific feature.
@@ -281,58 +398,37 @@ void ImGui::ShowDemoWindow(bool* p_open)
// Verify ABI compatibility between caller code and compiled version of Dear ImGui. This helps detects some build issues.
IMGUI_CHECKVERSION();
+ // Stored data
+ static ImGuiDemoWindowData demo_data;
+
// Examples Apps (accessible from the "Examples" menu)
- static bool show_app_main_menu_bar = false;
- static bool show_app_console = false;
- static bool show_app_custom_rendering = false;
- static bool show_app_dockspace = false;
- static bool show_app_documents = false;
- static bool show_app_log = false;
- static bool show_app_layout = false;
- static bool show_app_property_editor = false;
- static bool show_app_simple_overlay = false;
- static bool show_app_auto_resize = false;
- static bool show_app_constrained_resize = false;
- static bool show_app_fullscreen = false;
- static bool show_app_long_text = false;
- static bool show_app_window_titles = false;
-
- if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
- if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
- if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
- if (show_app_console) ShowExampleAppConsole(&show_app_console);
- if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
- if (show_app_log) ShowExampleAppLog(&show_app_log);
- if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
- if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
- if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
- if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
- if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
- if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen);
- if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
- if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
+ if (demo_data.ShowMainMenuBar) { ShowExampleAppMainMenuBar(); }
+ if (demo_data.ShowAppDockSpace) { ShowExampleAppDockSpace(&demo_data.ShowAppDockSpace); } // Important: Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
+ if (demo_data.ShowAppDocuments) { ShowExampleAppDocuments(&demo_data.ShowAppDocuments); } // ...process the Document app next, as it may also use a DockSpace()
+ if (demo_data.ShowAppAssetsBrowser) { ShowExampleAppAssetsBrowser(&demo_data.ShowAppAssetsBrowser); }
+ if (demo_data.ShowAppConsole) { ShowExampleAppConsole(&demo_data.ShowAppConsole); }
+ if (demo_data.ShowAppCustomRendering) { ShowExampleAppCustomRendering(&demo_data.ShowAppCustomRendering); }
+ if (demo_data.ShowAppLog) { ShowExampleAppLog(&demo_data.ShowAppLog); }
+ if (demo_data.ShowAppLayout) { ShowExampleAppLayout(&demo_data.ShowAppLayout); }
+ if (demo_data.ShowAppPropertyEditor) { ShowExampleAppPropertyEditor(&demo_data.ShowAppPropertyEditor, &demo_data); }
+ if (demo_data.ShowAppSimpleOverlay) { ShowExampleAppSimpleOverlay(&demo_data.ShowAppSimpleOverlay); }
+ if (demo_data.ShowAppAutoResize) { ShowExampleAppAutoResize(&demo_data.ShowAppAutoResize); }
+ if (demo_data.ShowAppConstrainedResize) { ShowExampleAppConstrainedResize(&demo_data.ShowAppConstrainedResize); }
+ if (demo_data.ShowAppFullscreen) { ShowExampleAppFullscreen(&demo_data.ShowAppFullscreen); }
+ if (demo_data.ShowAppLongText) { ShowExampleAppLongText(&demo_data.ShowAppLongText); }
+ if (demo_data.ShowAppWindowTitles) { ShowExampleAppWindowTitles(&demo_data.ShowAppWindowTitles); }
// Dear ImGui Tools (accessible from the "Tools" menu)
- static bool show_tool_metrics = false;
- static bool show_tool_debug_log = false;
- static bool show_tool_id_stack_tool = false;
- static bool show_tool_style_editor = false;
- static bool show_tool_about = false;
-
- if (show_tool_metrics)
- ImGui::ShowMetricsWindow(&show_tool_metrics);
- if (show_tool_debug_log)
- ImGui::ShowDebugLogWindow(&show_tool_debug_log);
- if (show_tool_id_stack_tool)
- ImGui::ShowIDStackToolWindow(&show_tool_id_stack_tool);
- if (show_tool_style_editor)
- {
- ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor);
+ if (demo_data.ShowMetrics) { ImGui::ShowMetricsWindow(&demo_data.ShowMetrics); }
+ if (demo_data.ShowDebugLog) { ImGui::ShowDebugLogWindow(&demo_data.ShowDebugLog); }
+ if (demo_data.ShowIDStackTool) { ImGui::ShowIDStackToolWindow(&demo_data.ShowIDStackTool); }
+ if (demo_data.ShowAbout) { ImGui::ShowAboutWindow(&demo_data.ShowAbout); }
+ if (demo_data.ShowStyleEditor)
+ {
+ ImGui::Begin("Dear ImGui Style Editor", &demo_data.ShowStyleEditor);
ImGui::ShowStyleEditor();
ImGui::End();
}
- if (show_tool_about)
- ImGui::ShowAboutWindow(&show_tool_about);
// Demonstrate the various window flags. Typically you would just use the default!
static bool no_titlebar = false;
@@ -377,68 +473,11 @@ void ImGui::ShowDemoWindow(bool* p_open)
}
// Most "big" widgets share a common width settings by default. See 'Demo->Layout->Widgets Width' for details.
- // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
- //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f);
- // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
- ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
+ ImGui::PushItemWidth(ImGui::GetFontSize() * -12); // e.g. Leave a fixed amount of width for labels (by passing a negative value), the rest goes to widgets.
+ //ImGui::PushItemWidth(-ImGui::GetWindowWidth() * 0.35f); // e.g. Use 2/3 of the space for widgets and 1/3 for labels (right align)
// Menu Bar
- if (ImGui::BeginMenuBar())
- {
- if (ImGui::BeginMenu("Menu"))
- {
- IMGUI_DEMO_MARKER("Menu/File");
- ShowExampleMenuFile();
- ImGui::EndMenu();
- }
- if (ImGui::BeginMenu("Examples"))
- {
- IMGUI_DEMO_MARKER("Menu/Examples");
- ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
-
- ImGui::SeparatorText("Mini apps");
- ImGui::MenuItem("Console", NULL, &show_app_console);
- ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
- ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
- ImGui::MenuItem("Documents", NULL, &show_app_documents);
- ImGui::MenuItem("Log", NULL, &show_app_log);
- ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
- ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
- ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
-
- ImGui::SeparatorText("Concepts");
- ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
- ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
- ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
- ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
- ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
-
- ImGui::EndMenu();
- }
- //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
- if (ImGui::BeginMenu("Tools"))
- {
- IMGUI_DEMO_MARKER("Menu/Tools");
-#ifndef IMGUI_DISABLE_DEBUG_TOOLS
- const bool has_debug_tools = true;
-#else
- const bool has_debug_tools = false;
-#endif
- ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools);
- ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools);
- ImGui::MenuItem("ID Stack Tool", NULL, &show_tool_id_stack_tool, has_debug_tools);
- ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor);
- bool is_debugger_present = ImGui::GetIO().ConfigDebugIsDebuggerPresent;
- if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
- ImGui::DebugStartItemPicker();
- if (!is_debugger_present)
- ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
- ImGui::Separator();
- ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about);
- ImGui::EndMenu();
- }
- ImGui::EndMenuBar();
- }
+ ShowDemoWindowMenuBar(&demo_data);
ImGui::Text("dear imgui says hello! (%s) (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
ImGui::Spacing();
@@ -456,7 +495,9 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::BulletText("See the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
ImGui::BulletText("See comments in imgui.cpp.");
ImGui::BulletText("See example applications in the examples/ folder.");
- ImGui::BulletText("Read the FAQ at https://www.dearimgui.com/faq/");
+ ImGui::BulletText("Read the FAQ at ");
+ ImGui::SameLine(0, 0);
+ ImGui::TextLinkOpenURL("https://www.dearimgui.com/faq/");
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
ImGui::BulletText("Set 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
@@ -479,19 +520,25 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::CheckboxFlags("io.ConfigFlags: NavEnableSetMousePos", &io.ConfigFlags, ImGuiConfigFlags_NavEnableSetMousePos);
ImGui::SameLine(); HelpMarker("Instruct navigation to move the mouse cursor. See comment for ImGuiConfigFlags_NavEnableSetMousePos.");
ImGui::CheckboxFlags("io.ConfigFlags: NoMouse", &io.ConfigFlags, ImGuiConfigFlags_NoMouse);
+ ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable mouse inputs and interactions.");
+
+ // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
if (io.ConfigFlags & ImGuiConfigFlags_NoMouse)
{
- // The "NoMouse" option can get us stuck with a disabled mouse! Let's provide an alternative way to fix it:
if (fmodf((float)ImGui::GetTime(), 0.40f) < 0.20f)
{
ImGui::SameLine();
ImGui::Text("<<PRESS SPACE TO DISABLE>>");
}
- if (ImGui::IsKeyPressed(ImGuiKey_Space))
+ // Prevent both being checked
+ if (ImGui::IsKeyPressed(ImGuiKey_Space) || (io.ConfigFlags & ImGuiConfigFlags_NoKeyboard))
io.ConfigFlags &= ~ImGuiConfigFlags_NoMouse;
}
- ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
+
+ ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", &io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
ImGui::SameLine(); HelpMarker("Instruct backend to not alter mouse cursor shape and visibility.");
+ ImGui::CheckboxFlags("io.ConfigFlags: NoKeyboard", &io.ConfigFlags, ImGuiConfigFlags_NoKeyboard);
+ ImGui::SameLine(); HelpMarker("Instruct dear imgui to disable keyboard inputs and interactions.");
ImGui::Checkbox("io.ConfigInputTrickleEventQueue", &io.ConfigInputTrickleEventQueue);
ImGui::SameLine(); HelpMarker("Enable input queue trickling: some types of events submitted during the same frame (e.g. button down + up) will be spread over multiple frames, improving interactions with low framerates.");
@@ -546,15 +593,37 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
+ ImGui::Checkbox("io.ConfigScrollbarScrollByPage", &io.ConfigScrollbarScrollByPage);
+ ImGui::SameLine(); HelpMarker("Enable scrolling page by page when clicking outside the scrollbar grab.\nWhen disabled, always scroll to clicked location.\nWhen enabled, Shift+Click scrolls to clicked location.");
ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
ImGui::SameLine(); HelpMarker("Swap Cmd<>Ctrl keys, enable various MacOS style behaviors.");
ImGui::Text("Also see Style->Rendering for rendering options.");
+ // Also read: https://github.com/ocornut/imgui/wiki/Error-Handling
+ ImGui::SeparatorText("Error Handling");
+
+ ImGui::Checkbox("io.ConfigErrorRecovery", &io.ConfigErrorRecovery);
+ ImGui::SameLine(); HelpMarker(
+ "Options to configure how we handle recoverable errors.\n"
+ "- Error recovery is not perfect nor guaranteed! It is a feature to ease development.\n"
+ "- You not are not supposed to rely on it in the course of a normal application run.\n"
+ "- Possible usage: facilitate recovery from errors triggered from a scripting language or after specific exceptions handlers.\n"
+ "- Always ensure that on programmers seat you have at minimum Asserts or Tooltips enabled when making direct imgui API call!"
+ "Otherwise it would severely hinder your ability to catch and correct mistakes!");
+ ImGui::Checkbox("io.ConfigErrorRecoveryEnableAssert", &io.ConfigErrorRecoveryEnableAssert);
+ ImGui::Checkbox("io.ConfigErrorRecoveryEnableDebugLog", &io.ConfigErrorRecoveryEnableDebugLog);
+ ImGui::Checkbox("io.ConfigErrorRecoveryEnableTooltip", &io.ConfigErrorRecoveryEnableTooltip);
+ if (!io.ConfigErrorRecoveryEnableAssert && !io.ConfigErrorRecoveryEnableDebugLog && !io.ConfigErrorRecoveryEnableTooltip)
+ io.ConfigErrorRecoveryEnableAssert = io.ConfigErrorRecoveryEnableDebugLog = io.ConfigErrorRecoveryEnableTooltip = true;
+
+ // Also read: https://github.com/ocornut/imgui/wiki/Debug-Tools
ImGui::SeparatorText("Debug");
ImGui::Checkbox("io.ConfigDebugIsDebuggerPresent", &io.ConfigDebugIsDebuggerPresent);
ImGui::SameLine(); HelpMarker("Enable various tools calling IM_DEBUG_BREAK().\n\nRequires a debugger being attached, otherwise IM_DEBUG_BREAK() options will appear to crash your application.");
+ ImGui::Checkbox("io.ConfigDebugHighlightIdConflicts", &io.ConfigDebugHighlightIdConflicts);
+ ImGui::SameLine(); HelpMarker("Highlight and show an error message when multiple items have conflicting identifiers.");
ImGui::BeginDisabled();
- ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce); // .
+ ImGui::Checkbox("io.ConfigDebugBeginReturnValueOnce", &io.ConfigDebugBeginReturnValueOnce);
ImGui::EndDisabled();
ImGui::SameLine(); HelpMarker("First calls to Begin()/BeginChild() will return false.\n\nTHIS OPTION IS DISABLED because it needs to be set at application boot-time to make sense. Showing the disabled option is a way to make this feature easier to discover.");
ImGui::Checkbox("io.ConfigDebugBeginReturnValueLoop", &io.ConfigDebugBeginReturnValueLoop);
@@ -586,6 +655,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", &io.BackendFlags, ImGuiBackendFlags_RendererHasVtxOffset);
ImGui::CheckboxFlags("io.BackendFlags: RendererHasViewports", &io.BackendFlags, ImGuiBackendFlags_RendererHasViewports);
ImGui::EndDisabled();
+
ImGui::TreePop();
ImGui::Spacing();
}
@@ -593,8 +663,9 @@ void ImGui::ShowDemoWindow(bool* p_open)
IMGUI_DEMO_MARKER("Configuration/Style");
if (ImGui::TreeNode("Style"))
{
+ ImGui::Checkbox("Style Editor", &demo_data.ShowStyleEditor);
+ ImGui::SameLine();
HelpMarker("The same contents can be accessed in 'Tools->Style Editor' or by calling the ShowStyleEditor() function.");
- ImGui::ShowStyleEditor();
ImGui::TreePop();
ImGui::Spacing();
}
@@ -641,7 +712,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
}
// All demo contents
- ShowDemoWindowWidgets();
+ ShowDemoWindowWidgets(&demo_data);
ShowDemoWindowLayout();
ShowDemoWindowPopups();
ShowDemoWindowTables();
@@ -652,9 +723,83 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::End();
}
-static void ShowDemoWindowWidgets()
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowMenuBar()
+//-----------------------------------------------------------------------------
+
+static void ShowDemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
+{
+ IMGUI_DEMO_MARKER("Menu");
+ if (ImGui::BeginMenuBar())
+ {
+ if (ImGui::BeginMenu("Menu"))
+ {
+ IMGUI_DEMO_MARKER("Menu/File");
+ ShowExampleMenuFile();
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Examples"))
+ {
+ IMGUI_DEMO_MARKER("Menu/Examples");
+ ImGui::MenuItem("Main menu bar", NULL, &demo_data->ShowMainMenuBar);
+
+ ImGui::SeparatorText("Mini apps");
+ ImGui::MenuItem("Assets Browser", NULL, &demo_data->ShowAppAssetsBrowser);
+ ImGui::MenuItem("Console", NULL, &demo_data->ShowAppConsole);
+ ImGui::MenuItem("Custom rendering", NULL, &demo_data->ShowAppCustomRendering);
+ ImGui::MenuItem("Documents", NULL, &demo_data->ShowAppDocuments);
+ ImGui::MenuItem("Dockspace", NULL, &demo_data->ShowAppDockSpace);
+ ImGui::MenuItem("Log", NULL, &demo_data->ShowAppLog);
+ ImGui::MenuItem("Property editor", NULL, &demo_data->ShowAppPropertyEditor);
+ ImGui::MenuItem("Simple layout", NULL, &demo_data->ShowAppLayout);
+ ImGui::MenuItem("Simple overlay", NULL, &demo_data->ShowAppSimpleOverlay);
+
+ ImGui::SeparatorText("Concepts");
+ ImGui::MenuItem("Auto-resizing window", NULL, &demo_data->ShowAppAutoResize);
+ ImGui::MenuItem("Constrained-resizing window", NULL, &demo_data->ShowAppConstrainedResize);
+ ImGui::MenuItem("Fullscreen window", NULL, &demo_data->ShowAppFullscreen);
+ ImGui::MenuItem("Long text display", NULL, &demo_data->ShowAppLongText);
+ ImGui::MenuItem("Manipulating window titles", NULL, &demo_data->ShowAppWindowTitles);
+
+ ImGui::EndMenu();
+ }
+ //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
+ if (ImGui::BeginMenu("Tools"))
+ {
+ IMGUI_DEMO_MARKER("Menu/Tools");
+ ImGuiIO& io = ImGui::GetIO();
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
+ const bool has_debug_tools = true;
+#else
+ const bool has_debug_tools = false;
+#endif
+ ImGui::MenuItem("Metrics/Debugger", NULL, &demo_data->ShowMetrics, has_debug_tools);
+ ImGui::MenuItem("Debug Log", NULL, &demo_data->ShowDebugLog, has_debug_tools);
+ ImGui::MenuItem("ID Stack Tool", NULL, &demo_data->ShowIDStackTool, has_debug_tools);
+ bool is_debugger_present = io.ConfigDebugIsDebuggerPresent;
+ if (ImGui::MenuItem("Item Picker", NULL, false, has_debug_tools && is_debugger_present))
+ ImGui::DebugStartItemPicker();
+ if (!is_debugger_present)
+ ImGui::SetItemTooltip("Requires io.ConfigDebugIsDebuggerPresent=true to be set.\n\nWe otherwise disable the menu option to avoid casual users crashing the application.\n\nYou can however always access the Item Picker in Metrics->Tools.");
+ ImGui::MenuItem("Style Editor", NULL, &demo_data->ShowStyleEditor);
+ ImGui::MenuItem("About Dear ImGui", NULL, &demo_data->ShowAbout);
+
+ ImGui::SeparatorText("Debug Options");
+ ImGui::MenuItem("Highlight ID Conflicts", NULL, &io.ConfigDebugHighlightIdConflicts, has_debug_tools);
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowWidgets()
+//-----------------------------------------------------------------------------
+
+static void ShowDemoWindowWidgets(ImGuiDemoWindowData* demo_data)
{
IMGUI_DEMO_MARKER("Widgets");
+ //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (!ImGui::CollapsingHeader("Widgets"))
return;
@@ -713,11 +858,11 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Basic/Buttons (Repeating)");
static int counter = 0;
float spacing = ImGui::GetStyle().ItemInnerSpacing.x;
- ImGui::PushButtonRepeat(true);
+ ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true);
if (ImGui::ArrowButton("##left", ImGuiDir_Left)) { counter--; }
ImGui::SameLine(0.0f, spacing);
if (ImGui::ArrowButton("##right", ImGuiDir_Right)) { counter++; }
- ImGui::PopButtonRepeat();
+ ImGui::PopItemFlag();
ImGui::SameLine();
ImGui::Text("%d", counter);
@@ -774,18 +919,19 @@ static void ShowDemoWindowWidgets()
{
IMGUI_DEMO_MARKER("Widgets/Basic/DragInt, DragFloat");
- static int i1 = 50, i2 = 42;
+ static int i1 = 50, i2 = 42, i3 = 128;
ImGui::DragInt("drag int", &i1, 1);
ImGui::SameLine(); HelpMarker(
"Click and drag to edit value.\n"
"Hold SHIFT/ALT for faster/slower edit.\n"
"Double-click or CTRL+click to input value.");
-
ImGui::DragInt("drag int 0..100", &i2, 1, 0, 100, "%d%%", ImGuiSliderFlags_AlwaysClamp);
+ ImGui::DragInt("drag int wrap 100..200", &i3, 1, 100, 200, "%d", ImGuiSliderFlags_WrapAround);
static float f1 = 1.00f, f2 = 0.0067f;
ImGui::DragFloat("drag float", &f1, 0.005f);
ImGui::DragFloat("drag small float", &f2, 0.0001f, 0.0f, 0.0f, "%.06f ns");
+ //ImGui::DragFloat("drag wrap -1..1", &f3, 0.005f, -1.0f, 1.0f, NULL, ImGuiSliderFlags_WrapAround);
}
ImGui::SeparatorText("Sliders");
@@ -942,12 +1088,11 @@ static void ShowDemoWindowWidgets()
// Using ImGuiHoveredFlags_ForTooltip will pull flags from 'style.HoverFlagsForTooltipMouse' or 'style.HoverFlagsForTooltipNav',
// which default value include the ImGuiHoveredFlags_AllowWhenDisabled flag.
- // As a result, Set
ImGui::BeginDisabled();
ImGui::Button("Disabled item", sz);
- ImGui::EndDisabled();
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip))
ImGui::SetTooltip("I am a a tooltip for a disabled item.");
+ ImGui::EndDisabled();
ImGui::TreePop();
}
@@ -1004,6 +1149,7 @@ static void ShowDemoWindowWidgets()
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAllColumns", &base_flags, ImGuiTreeNodeFlags_SpanAllColumns); ImGui::SameLine(); HelpMarker("For use in Tables only.");
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_AllowOverlap", &base_flags, ImGuiTreeNodeFlags_AllowOverlap);
ImGui::CheckboxFlags("ImGuiTreeNodeFlags_Framed", &base_flags, ImGuiTreeNodeFlags_Framed); ImGui::SameLine(); HelpMarker("Draw frame with background (e.g. for CollapsingHeader)");
+ ImGui::CheckboxFlags("ImGuiTreeNodeFlags_NavLeftJumpsBackHere", &base_flags, ImGuiTreeNodeFlags_NavLeftJumpsBackHere);
ImGui::Checkbox("Align label with current X position", &align_label_with_current_x_position);
ImGui::Checkbox("Test tree node as drag source", &test_drag_and_drop);
ImGui::Text("Hello!");
@@ -1036,7 +1182,7 @@ static void ShowDemoWindowWidgets()
ImGui::Text("This is a drag and drop source");
ImGui::EndDragDropSource();
}
- if (i == 2)
+ if (i == 2 && (base_flags & ImGuiTreeNodeFlags_SpanTextWidth))
{
// Item 2 has an additional inline button to help demonstrate SpanTextWidth.
ImGui::SameLine();
@@ -1045,6 +1191,8 @@ static void ShowDemoWindowWidgets()
if (node_open)
{
ImGui::BulletText("Blah blah\nBlah Blah");
+ ImGui::SameLine();
+ ImGui::SmallButton("Button");
ImGui::TreePop();
}
}
@@ -1306,18 +1454,18 @@ static void ShowDemoWindowWidgets()
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
- static int item_current_idx = 0; // Here we store our selection data as an index.
+ static int item_selected_idx = 0; // Here we store our selection data as an index.
// Pass in the preview value visible before opening the combo (it could technically be different contents or not pulled from items[])
- const char* combo_preview_value = items[item_current_idx];
+ const char* combo_preview_value = items[item_selected_idx];
if (ImGui::BeginCombo("combo 1", combo_preview_value, flags))
{
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
{
- const bool is_selected = (item_current_idx == n);
+ const bool is_selected = (item_selected_idx == n);
if (ImGui::Selectable(items[n], is_selected))
- item_current_idx = n;
+ item_selected_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
@@ -1359,14 +1507,22 @@ static void ShowDemoWindowWidgets()
// (your selection data could be an index, a pointer to the object, an id for the object, a flag intrusively
// stored in the object itself, etc.)
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIII", "JJJJ", "KKKK", "LLLLLLL", "MMMM", "OOOOOOO" };
- static int item_current_idx = 0; // Here we store our selection data as an index.
+ static int item_selected_idx = 0; // Here we store our selected data as an index.
+
+ static bool item_highlight = false;
+ int item_highlighted_idx = -1; // Here we store our highlighted data as an index.
+ ImGui::Checkbox("Highlight hovered item in second listbox", &item_highlight);
+
if (ImGui::BeginListBox("listbox 1"))
{
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
{
- const bool is_selected = (item_current_idx == n);
+ const bool is_selected = (item_selected_idx == n);
if (ImGui::Selectable(items[n], is_selected))
- item_current_idx = n;
+ item_selected_idx = n;
+
+ if (item_highlight && ImGui::IsItemHovered())
+ item_highlighted_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
@@ -1382,9 +1538,10 @@ static void ShowDemoWindowWidgets()
{
for (int n = 0; n < IM_ARRAYSIZE(items); n++)
{
- const bool is_selected = (item_current_idx == n);
- if (ImGui::Selectable(items[n], is_selected))
- item_current_idx = n;
+ bool is_selected = (item_selected_idx == n);
+ ImGuiSelectableFlags flags = (item_highlighted_idx == n) ? ImGuiSelectableFlags_Highlight : 0;
+ if (ImGui::Selectable(items[n], is_selected, flags))
+ item_selected_idx = n;
// Set the initial focus when opening the combo (scrolling + keyboard navigation focus)
if (is_selected)
@@ -1397,6 +1554,7 @@ static void ShowDemoWindowWidgets()
}
IMGUI_DEMO_MARKER("Widgets/Selectables");
+ //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
if (ImGui::TreeNode("Selectables"))
{
// Selectable() has 2 overloads:
@@ -1418,37 +1576,6 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
- IMGUI_DEMO_MARKER("Widgets/Selectables/Single Selection");
- if (ImGui::TreeNode("Selection State: Single Selection"))
- {
- static int selected = -1;
- for (int n = 0; n < 5; n++)
- {
- char buf[32];
- sprintf(buf, "Object %d", n);
- if (ImGui::Selectable(buf, selected == n))
- selected = n;
- }
- ImGui::TreePop();
- }
- IMGUI_DEMO_MARKER("Widgets/Selectables/Multiple Selection");
- if (ImGui::TreeNode("Selection State: Multiple Selection"))
- {
- HelpMarker("Hold CTRL and click to select multiple items.");
- static bool selection[5] = { false, false, false, false, false };
- for (int n = 0; n < 5; n++)
- {
- char buf[32];
- sprintf(buf, "Object %d", n);
- if (ImGui::Selectable(buf, selection[n]))
- {
- if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
- memset(selection, 0, sizeof(selection));
- selection[n] ^= 1;
- }
- }
- ImGui::TreePop();
- }
IMGUI_DEMO_MARKER("Widgets/Selectables/Rendering more items on the same line");
if (ImGui::TreeNode("Rendering more items on the same line"))
{
@@ -1461,8 +1588,8 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
- IMGUI_DEMO_MARKER("Widgets/Selectables/In columns");
- if (ImGui::TreeNode("In columns"))
+ IMGUI_DEMO_MARKER("Widgets/Selectables/In Tables");
+ if (ImGui::TreeNode("In Tables"))
{
static bool selected[10] = {};
@@ -1556,6 +1683,8 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
+ ShowDemoWindowMultiSelect(demo_data);
+
// To wire InputText() with std::string or any other custom string type,
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
IMGUI_DEMO_MARKER("Widgets/Text Input");
@@ -1791,6 +1920,7 @@ static void ShowDemoWindowWidgets()
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", &tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", &tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton);
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", &tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
+ ImGui::CheckboxFlags("ImGuiTabBarFlags_DrawSelectedOverline", &tab_bar_flags, ImGuiTabBarFlags_DrawSelectedOverline);
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", &tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
@@ -1799,11 +1929,13 @@ static void ShowDemoWindowWidgets()
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
// Tab Bar
+ ImGui::AlignTextToFramePadding();
+ ImGui::Text("Opened:");
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
static bool opened[4] = { true, true, true, true }; // Persistent user state
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
{
- if (n > 0) { ImGui::SameLine(); }
+ ImGui::SameLine();
ImGui::Checkbox(names[n], &opened[n]);
}
@@ -1954,8 +2086,12 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine();
ImGui::SliderInt("Sample count", &display_count, 1, 400);
float (*func)(void*, int) = (func_type == 0) ? Funcs::Sin : Funcs::Saw;
- ImGui::PlotLines("Lines", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
- ImGui::PlotHistogram("Histogram", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
+ ImGui::PlotLines("Lines##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
+ ImGui::PlotHistogram("Histogram##2", func, NULL, display_count, 0, NULL, -1.0f, 1.0f, ImVec2(0, 80));
+ ImGui::Separator();
+
+ ImGui::Text("Need better plotting and graphing? Consider using ImPlot:");
+ ImGui::TextLinkOpenURL("https://github.com/epezent/implot");
ImGui::Separator();
ImGui::TreePop();
@@ -2189,13 +2325,18 @@ static void ShowDemoWindowWidgets()
// Demonstrate using advanced flags for DragXXX and SliderXXX functions. Note that the flags are the same!
static ImGuiSliderFlags flags = ImGuiSliderFlags_None;
ImGui::CheckboxFlags("ImGuiSliderFlags_AlwaysClamp", &flags, ImGuiSliderFlags_AlwaysClamp);
- ImGui::SameLine(); HelpMarker("Always clamp value to min/max bounds (if any) when input manually with CTRL+Click.");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_ClampOnInput", &flags, ImGuiSliderFlags_ClampOnInput);
+ ImGui::SameLine(); HelpMarker("Clamp value to min/max bounds when input manually with CTRL+Click. By default CTRL+Click allows going out of bounds.");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_ClampZeroRange", &flags, ImGuiSliderFlags_ClampZeroRange);
+ ImGui::SameLine(); HelpMarker("Clamp even if min==max==0.0f. Otherwise DragXXX functions don't clamp.");
ImGui::CheckboxFlags("ImGuiSliderFlags_Logarithmic", &flags, ImGuiSliderFlags_Logarithmic);
ImGui::SameLine(); HelpMarker("Enable logarithmic editing (more precision for small values).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoRoundToFormat", &flags, ImGuiSliderFlags_NoRoundToFormat);
ImGui::SameLine(); HelpMarker("Disable rounding underlying value to match precision of the format string (e.g. %.3f values are rounded to those 3 digits).");
ImGui::CheckboxFlags("ImGuiSliderFlags_NoInput", &flags, ImGuiSliderFlags_NoInput);
ImGui::SameLine(); HelpMarker("Disable CTRL+Click or Enter key allowing to input text directly into the widget.");
+ ImGui::CheckboxFlags("ImGuiSliderFlags_WrapAround", &flags, ImGuiSliderFlags_WrapAround);
+ ImGui::SameLine(); HelpMarker("Enable wrapping around from max to min and from min to max (only supported by DragXXX() functions)");
// Drags
static float drag_f = 0.5f;
@@ -2205,14 +2346,17 @@ static void ShowDemoWindowWidgets()
ImGui::DragFloat("DragFloat (0 -> +inf)", &drag_f, 0.005f, 0.0f, FLT_MAX, "%.3f", flags);
ImGui::DragFloat("DragFloat (-inf -> 1)", &drag_f, 0.005f, -FLT_MAX, 1.0f, "%.3f", flags);
ImGui::DragFloat("DragFloat (-inf -> +inf)", &drag_f, 0.005f, -FLT_MAX, +FLT_MAX, "%.3f", flags);
+ //ImGui::DragFloat("DragFloat (0 -> 0)", &drag_f, 0.005f, 0.0f, 0.0f, "%.3f", flags); // To test ClampZeroRange
+ //ImGui::DragFloat("DragFloat (100 -> 100)", &drag_f, 0.005f, 100.0f, 100.0f, "%.3f", flags);
ImGui::DragInt("DragInt (0 -> 100)", &drag_i, 0.5f, 0, 100, "%d", flags);
// Sliders
static float slider_f = 0.5f;
static int slider_i = 50;
+ const ImGuiSliderFlags flags_for_sliders = flags & ~ImGuiSliderFlags_WrapAround;
ImGui::Text("Underlying float value: %f", slider_f);
- ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags);
- ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags);
+ ImGui::SliderFloat("SliderFloat (0 -> 1)", &slider_f, 0.0f, 1.0f, "%.3f", flags_for_sliders);
+ ImGui::SliderInt("SliderInt (0 -> 100)", &slider_i, 0, 100, "%d", flags_for_sliders);
ImGui::TreePop();
}
@@ -2334,20 +2478,24 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
static bool inputs_step = true;
+ static ImGuiInputTextFlags flags = ImGuiInputTextFlags_None;
ImGui::SeparatorText("Inputs");
ImGui::Checkbox("Show step buttons", &inputs_step);
- ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d");
- ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u");
- ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d");
- ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u");
- ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d");
- ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X");
- ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u");
- ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X");
- ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL);
- ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL);
- ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL);
- ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL);
+ ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", &flags, ImGuiInputTextFlags_ReadOnly);
+ ImGui::CheckboxFlags("ImGuiInputTextFlags_ParseEmptyRefVal", &flags, ImGuiInputTextFlags_ParseEmptyRefVal);
+ ImGui::CheckboxFlags("ImGuiInputTextFlags_DisplayEmptyRefVal", &flags, ImGuiInputTextFlags_DisplayEmptyRefVal);
+ ImGui::InputScalar("input s8", ImGuiDataType_S8, &s8_v, inputs_step ? &s8_one : NULL, NULL, "%d", flags);
+ ImGui::InputScalar("input u8", ImGuiDataType_U8, &u8_v, inputs_step ? &u8_one : NULL, NULL, "%u", flags);
+ ImGui::InputScalar("input s16", ImGuiDataType_S16, &s16_v, inputs_step ? &s16_one : NULL, NULL, "%d", flags);
+ ImGui::InputScalar("input u16", ImGuiDataType_U16, &u16_v, inputs_step ? &u16_one : NULL, NULL, "%u", flags);
+ ImGui::InputScalar("input s32", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%d", flags);
+ ImGui::InputScalar("input s32 hex", ImGuiDataType_S32, &s32_v, inputs_step ? &s32_one : NULL, NULL, "%04X", flags);
+ ImGui::InputScalar("input u32", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%u", flags);
+ ImGui::InputScalar("input u32 hex", ImGuiDataType_U32, &u32_v, inputs_step ? &u32_one : NULL, NULL, "%08X", flags);
+ ImGui::InputScalar("input s64", ImGuiDataType_S64, &s64_v, inputs_step ? &s64_one : NULL, NULL, NULL, flags);
+ ImGui::InputScalar("input u64", ImGuiDataType_U64, &u64_v, inputs_step ? &u64_one : NULL, NULL, NULL, flags);
+ ImGui::InputScalar("input float", ImGuiDataType_Float, &f32_v, inputs_step ? &f32_one : NULL, NULL, NULL, flags);
+ ImGui::InputScalar("input double", ImGuiDataType_Double, &f64_v, inputs_step ? &f64_one : NULL, NULL, NULL, flags);
ImGui::TreePop();
}
@@ -2539,6 +2687,11 @@ static void ShowDemoWindowWidgets()
IMGUI_DEMO_MARKER("Widgets/Drag and Drop/Drag to reorder items (simple)");
if (ImGui::TreeNode("Drag to reorder items (simple)"))
{
+ // FIXME: there is temporary (usually single-frame) ID Conflict during reordering as a same item may be submitting twice.
+ // This code was always slightly faulty but in a way which was not easily noticeable.
+ // Until we fix this, enable ImGuiItemFlags_AllowDuplicateId to disable detecting the issue.
+ ImGui::PushItemFlag(ImGuiItemFlags_AllowDuplicateId, true);
+
// Simple reordering
HelpMarker(
"We don't use the drag and drop api at all here! "
@@ -2560,6 +2713,8 @@ static void ShowDemoWindowWidgets()
}
}
}
+
+ ImGui::PopItemFlag();
ImGui::TreePop();
}
@@ -2619,7 +2774,7 @@ static void ShowDemoWindowWidgets()
ImGui::BeginDisabled(true);
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
- if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
+ if (item_type == 2) { ImGui::PushItemFlag(ImGuiItemFlags_ButtonRepeat, true); ret = ImGui::Button("ITEM: Button"); ImGui::PopItemFlag(); } // Testing button (with repeater)
if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
@@ -2712,7 +2867,7 @@ static void ShowDemoWindowWidgets()
static bool embed_all_inside_a_child_window = false;
ImGui::Checkbox("Embed everything inside a child window for testing _RootWindow flag.", &embed_all_inside_a_child_window);
if (embed_all_inside_a_child_window)
- ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Border);
+ ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20.0f), ImGuiChildFlags_Borders);
// Testing IsWindowFocused() function with its various flags.
ImGui::BulletText(
@@ -2772,7 +2927,7 @@ static void ShowDemoWindowWidgets()
ImGui::IsWindowHovered(ImGuiHoveredFlags_AnyWindow),
ImGui::IsWindowHovered(ImGuiHoveredFlags_Stationary));
- ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Border);
+ ImGui::BeginChild("child", ImVec2(0, 50), ImGuiChildFlags_Borders);
ImGui::Text("This is another child window for testing the _ChildWindows flag.");
ImGui::EndChild();
if (embed_all_inside_a_child_window)
@@ -2808,35 +2963,1006 @@ static void ShowDemoWindowWidgets()
if (disable_all)
ImGui::EndDisabled();
- IMGUI_DEMO_MARKER("Widgets/Disable Block");
- if (ImGui::TreeNode("Disable block"))
- {
- ImGui::Checkbox("Disable entire section above", &disable_all);
- ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
- ImGui::TreePop();
- }
+ IMGUI_DEMO_MARKER("Widgets/Disable Block");
+ if (ImGui::TreeNode("Disable block"))
+ {
+ ImGui::Checkbox("Disable entire section above", &disable_all);
+ ImGui::SameLine(); HelpMarker("Demonstrate using BeginDisabled()/EndDisabled() across this section.");
+ ImGui::TreePop();
+ }
+
+ IMGUI_DEMO_MARKER("Widgets/Text Filter");
+ if (ImGui::TreeNode("Text Filter"))
+ {
+ // Helper class to easy setup a text filter.
+ // You may want to implement a more feature-full filtering scheme in your own application.
+ HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
+ static ImGuiTextFilter filter;
+ ImGui::Text("Filter usage:\n"
+ " \"\" display all lines\n"
+ " \"xxx\" display lines containing \"xxx\"\n"
+ " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
+ " \"-xxx\" hide lines containing \"xxx\"");
+ filter.Draw();
+ const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
+ for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
+ if (filter.PassFilter(lines[i]))
+ ImGui::BulletText("%s", lines[i]);
+ ImGui::TreePop();
+ }
+}
+
+static const char* ExampleNames[] =
+{
+ "Artichoke", "Arugula", "Asparagus", "Avocado", "Bamboo Shoots", "Bean Sprouts", "Beans", "Beet", "Belgian Endive", "Bell Pepper",
+ "Bitter Gourd", "Bok Choy", "Broccoli", "Brussels Sprouts", "Burdock Root", "Cabbage", "Calabash", "Capers", "Carrot", "Cassava",
+ "Cauliflower", "Celery", "Celery Root", "Celcuce", "Chayote", "Chinese Broccoli", "Corn", "Cucumber"
+};
+
+// Extra functions to add deletion support to ImGuiSelectionBasicStorage
+struct ExampleSelectionWithDeletion : ImGuiSelectionBasicStorage
+{
+ // Find which item should be Focused after deletion.
+ // Call _before_ item submission. Retunr an index in the before-deletion item list, your item loop should call SetKeyboardFocusHere() on it.
+ // The subsequent ApplyDeletionPostLoop() code will use it to apply Selection.
+ // - We cannot provide this logic in core Dear ImGui because we don't have access to selection data.
+ // - We don't actually manipulate the ImVector<> here, only in ApplyDeletionPostLoop(), but using similar API for consistency and flexibility.
+ // - Important: Deletion only works if the underlying ImGuiID for your items are stable: aka not depend on their index, but on e.g. item id/ptr.
+ // FIXME-MULTISELECT: Doesn't take account of the possibility focus target will be moved during deletion. Need refocus or scroll offset.
+ int ApplyDeletionPreLoop(ImGuiMultiSelectIO* ms_io, int items_count)
+ {
+ if (Size == 0)
+ return -1;
+
+ // If focused item is not selected...
+ const int focused_idx = (int)ms_io->NavIdItem; // Index of currently focused item
+ if (ms_io->NavIdSelected == false) // This is merely a shortcut, == Contains(adapter->IndexToStorage(items, focused_idx))
+ {
+ ms_io->RangeSrcReset = true; // Request to recover RangeSrc from NavId next frame. Would be ok to reset even when NavIdSelected==true, but it would take an extra frame to recover RangeSrc when deleting a selected item.
+ return focused_idx; // Request to focus same item after deletion.
+ }
+
+ // If focused item is selected: land on first unselected item after focused item.
+ for (int idx = focused_idx + 1; idx < items_count; idx++)
+ if (!Contains(GetStorageIdFromIndex(idx)))
+ return idx;
+
+ // If focused item is selected: otherwise return last unselected item before focused item.
+ for (int idx = IM_MIN(focused_idx, items_count) - 1; idx >= 0; idx--)
+ if (!Contains(GetStorageIdFromIndex(idx)))
+ return idx;
+
+ return -1;
+ }
+
+ // Rewrite item list (delete items) + update selection.
+ // - Call after EndMultiSelect()
+ // - We cannot provide this logic in core Dear ImGui because we don't have access to your items, nor to selection data.
+ template<typename ITEM_TYPE>
+ void ApplyDeletionPostLoop(ImGuiMultiSelectIO* ms_io, ImVector<ITEM_TYPE>& items, int item_curr_idx_to_select)
+ {
+ // Rewrite item list (delete items) + convert old selection index (before deletion) to new selection index (after selection).
+ // If NavId was not part of selection, we will stay on same item.
+ ImVector<ITEM_TYPE> new_items;
+ new_items.reserve(items.Size - Size);
+ int item_next_idx_to_select = -1;
+ for (int idx = 0; idx < items.Size; idx++)
+ {
+ if (!Contains(GetStorageIdFromIndex(idx)))
+ new_items.push_back(items[idx]);
+ if (item_curr_idx_to_select == idx)
+ item_next_idx_to_select = new_items.Size - 1;
+ }
+ items.swap(new_items);
+
+ // Update selection
+ Clear();
+ if (item_next_idx_to_select != -1 && ms_io->NavIdSelected)
+ SetItemSelected(GetStorageIdFromIndex(item_next_idx_to_select), true);
+ }
+};
+
+// Example: Implement dual list box storage and interface
+struct ExampleDualListBox
+{
+ ImVector<ImGuiID> Items[2]; // ID is index into ExampleName[]
+ ImGuiSelectionBasicStorage Selections[2]; // Store ExampleItemId into selection
+ bool OptKeepSorted = true;
+
+ void MoveAll(int src, int dst)
+ {
+ IM_ASSERT((src == 0 && dst == 1) || (src == 1 && dst == 0));
+ for (ImGuiID item_id : Items[src])
+ Items[dst].push_back(item_id);
+ Items[src].clear();
+ SortItems(dst);
+ Selections[src].Swap(Selections[dst]);
+ Selections[src].Clear();
+ }
+ void MoveSelected(int src, int dst)
+ {
+ for (int src_n = 0; src_n < Items[src].Size; src_n++)
+ {
+ ImGuiID item_id = Items[src][src_n];
+ if (!Selections[src].Contains(item_id))
+ continue;
+ Items[src].erase(&Items[src][src_n]); // FIXME-OPT: Could be implemented more optimally (rebuild src items and swap)
+ Items[dst].push_back(item_id);
+ src_n--;
+ }
+ if (OptKeepSorted)
+ SortItems(dst);
+ Selections[src].Swap(Selections[dst]);
+ Selections[src].Clear();
+ }
+ void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, int side)
+ {
+ // In this example we store item id in selection (instead of item index)
+ Selections[side].UserData = Items[side].Data;
+ Selections[side].AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImGuiID* items = (ImGuiID*)self->UserData; return items[idx]; };
+ Selections[side].ApplyRequests(ms_io);
+ }
+ static int IMGUI_CDECL CompareItemsByValue(const void* lhs, const void* rhs)
+ {
+ const int* a = (const int*)lhs;
+ const int* b = (const int*)rhs;
+ return (*a - *b) > 0 ? +1 : -1;
+ }
+ void SortItems(int n)
+ {
+ qsort(Items[n].Data, (size_t)Items[n].Size, sizeof(Items[n][0]), CompareItemsByValue);
+ }
+ void Show()
+ {
+ //ImGui::Checkbox("Sorted", &OptKeepSorted);
+ if (ImGui::BeginTable("split", 3, ImGuiTableFlags_None))
+ {
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Left side
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed); // Buttons
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch); // Right side
+ ImGui::TableNextRow();
+
+ int request_move_selected = -1;
+ int request_move_all = -1;
+ float child_height_0 = 0.0f;
+ for (int side = 0; side < 2; side++)
+ {
+ // FIXME-MULTISELECT: Dual List Box: Add context menus
+ // FIXME-NAV: Using ImGuiWindowFlags_NavFlattened exhibit many issues.
+ ImVector<ImGuiID>& items = Items[side];
+ ImGuiSelectionBasicStorage& selection = Selections[side];
+
+ ImGui::TableSetColumnIndex((side == 0) ? 0 : 2);
+ ImGui::Text("%s (%d)", (side == 0) ? "Available" : "Basket", items.Size);
+
+ // Submit scrolling range to avoid glitches on moving/deletion
+ const float items_height = ImGui::GetTextLineHeightWithSpacing();
+ ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
+
+ bool child_visible;
+ if (side == 0)
+ {
+ // Left child is resizable
+ ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetFrameHeightWithSpacing() * 4), ImVec2(FLT_MAX, FLT_MAX));
+ child_visible = ImGui::BeginChild("0", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY);
+ child_height_0 = ImGui::GetWindowSize().y;
+ }
+ else
+ {
+ // Right child use same height as left one
+ child_visible = ImGui::BeginChild("1", ImVec2(-FLT_MIN, child_height_0), ImGuiChildFlags_FrameStyle);
+ }
+ if (child_visible)
+ {
+ ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_None;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
+ ApplySelectionRequests(ms_io, side);
+
+ for (int item_n = 0; item_n < items.Size; item_n++)
+ {
+ ImGuiID item_id = items[item_n];
+ bool item_is_selected = selection.Contains(item_id);
+ ImGui::SetNextItemSelectionUserData(item_n);
+ ImGui::Selectable(ExampleNames[item_id], item_is_selected, ImGuiSelectableFlags_AllowDoubleClick);
+ if (ImGui::IsItemFocused())
+ {
+ // FIXME-MULTISELECT: Dual List Box: Transfer focus
+ if (ImGui::IsKeyPressed(ImGuiKey_Enter) || ImGui::IsKeyPressed(ImGuiKey_KeypadEnter))
+ request_move_selected = side;
+ if (ImGui::IsMouseDoubleClicked(0)) // FIXME-MULTISELECT: Double-click on multi-selection?
+ request_move_selected = side;
+ }
+ }
+
+ ms_io = ImGui::EndMultiSelect();
+ ApplySelectionRequests(ms_io, side);
+ }
+ ImGui::EndChild();
+ }
+
+ // Buttons columns
+ ImGui::TableSetColumnIndex(1);
+ ImGui::NewLine();
+ //ImVec2 button_sz = { ImGui::CalcTextSize(">>").x + ImGui::GetStyle().FramePadding.x * 2.0f, ImGui::GetFrameHeight() + padding.y * 2.0f };
+ ImVec2 button_sz = { ImGui::GetFrameHeight(), ImGui::GetFrameHeight() };
+
+ // (Using BeginDisabled()/EndDisabled() works but feels distracting given how it is currently visualized)
+ if (ImGui::Button(">>", button_sz))
+ request_move_all = 0;
+ if (ImGui::Button(">", button_sz))
+ request_move_selected = 0;
+ if (ImGui::Button("<", button_sz))
+ request_move_selected = 1;
+ if (ImGui::Button("<<", button_sz))
+ request_move_all = 1;
+
+ // Process requests
+ if (request_move_all != -1)
+ MoveAll(request_move_all, request_move_all ^ 1);
+ if (request_move_selected != -1)
+ MoveSelected(request_move_selected, request_move_selected ^ 1);
+
+ // FIXME-MULTISELECT: Support action from outside
+ /*
+ if (OptKeepSorted == false)
+ {
+ ImGui::NewLine();
+ if (ImGui::ArrowButton("MoveUp", ImGuiDir_Up)) {}
+ if (ImGui::ArrowButton("MoveDown", ImGuiDir_Down)) {}
+ }
+ */
+
+ ImGui::EndTable();
+ }
+ }
+};
+
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowMultiSelect()
+//-----------------------------------------------------------------------------
+// Multi-selection demos
+// Also read: https://github.com/ocornut/imgui/wiki/Multi-Select
+//-----------------------------------------------------------------------------
+
+static void ShowDemoWindowMultiSelect(ImGuiDemoWindowData* demo_data)
+{
+ IMGUI_DEMO_MARKER("Widgets/Selection State & Multi-Select");
+ if (ImGui::TreeNode("Selection State & Multi-Select"))
+ {
+ HelpMarker("Selections can be built using Selectable(), TreeNode() or other widgets. Selection state is owned by application code/data.");
+
+ // Without any fancy API: manage single-selection yourself.
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Single-Select");
+ if (ImGui::TreeNode("Single-Select"))
+ {
+ static int selected = -1;
+ for (int n = 0; n < 5; n++)
+ {
+ char buf[32];
+ sprintf(buf, "Object %d", n);
+ if (ImGui::Selectable(buf, selected == n))
+ selected = n;
+ }
+ ImGui::TreePop();
+ }
+
+ // Demonstrate implementation a most-basic form of multi-selection manually
+ // This doesn't support the SHIFT modifier which requires BeginMultiSelect()!
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (manual/simplified, without BeginMultiSelect)");
+ if (ImGui::TreeNode("Multi-Select (manual/simplified, without BeginMultiSelect)"))
+ {
+ HelpMarker("Hold CTRL and click to select multiple items.");
+ static bool selection[5] = { false, false, false, false, false };
+ for (int n = 0; n < 5; n++)
+ {
+ char buf[32];
+ sprintf(buf, "Object %d", n);
+ if (ImGui::Selectable(buf, selection[n]))
+ {
+ if (!ImGui::GetIO().KeyCtrl) // Clear selection when CTRL is not held
+ memset(selection, 0, sizeof(selection));
+ selection[n] ^= 1; // Toggle current item
+ }
+ }
+ ImGui::TreePop();
+ }
+
+ // Demonstrate handling proper multi-selection using the BeginMultiSelect/EndMultiSelect API.
+ // SHIFT+Click w/ CTRL and other standard features are supported.
+ // We use the ImGuiSelectionBasicStorage helper which you may freely reimplement.
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select");
+ if (ImGui::TreeNode("Multi-Select"))
+ {
+ ImGui::Text("Supported features:");
+ ImGui::BulletText("Keyboard navigation (arrows, page up/down, home/end, space).");
+ ImGui::BulletText("Ctrl modifier to preserve and toggle selection.");
+ ImGui::BulletText("Shift modifier for range selection.");
+ ImGui::BulletText("CTRL+A to select all.");
+ ImGui::BulletText("Escape to clear selection.");
+ ImGui::BulletText("Click and drag to box-select.");
+ ImGui::Text("Tip: Use 'Demo->Tools->Debug Log->Selection' to see selection requests as they happen.");
+
+ // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
+ const int ITEMS_COUNT = 50;
+ static ImGuiSelectionBasicStorage selection;
+ ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
+
+ // The BeginChild() has no purpose for selection logic, other that offering a scrolling region.
+ if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
+ {
+ ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
+ selection.ApplyRequests(ms_io);
+
+ for (int n = 0; n < ITEMS_COUNT; n++)
+ {
+ char label[64];
+ sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
+ bool item_is_selected = selection.Contains((ImGuiID)n);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Selectable(label, item_is_selected);
+ }
+
+ ms_io = ImGui::EndMultiSelect();
+ selection.ApplyRequests(ms_io);
+ }
+ ImGui::EndChild();
+ ImGui::TreePop();
+ }
+
+ // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with clipper)");
+ if (ImGui::TreeNode("Multi-Select (with clipper)"))
+ {
+ // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
+ static ImGuiSelectionBasicStorage selection;
+
+ ImGui::Text("Added features:");
+ ImGui::BulletText("Using ImGuiListClipper.");
+
+ const int ITEMS_COUNT = 10000;
+ ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
+ if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
+ {
+ ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
+ selection.ApplyRequests(ms_io);
+
+ ImGuiListClipper clipper;
+ clipper.Begin(ITEMS_COUNT);
+ if (ms_io->RangeSrcItem != -1)
+ clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
+ while (clipper.Step())
+ {
+ for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
+ {
+ char label[64];
+ sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
+ bool item_is_selected = selection.Contains((ImGuiID)n);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Selectable(label, item_is_selected);
+ }
+ }
+
+ ms_io = ImGui::EndMultiSelect();
+ selection.ApplyRequests(ms_io);
+ }
+ ImGui::EndChild();
+ ImGui::TreePop();
+ }
+
+ // Demonstrate dynamic item list + deletion support using the BeginMultiSelect/EndMultiSelect API.
+ // In order to support Deletion without any glitches you need to:
+ // - (1) If items are submitted in their own scrolling area, submit contents size SetNextWindowContentSize() ahead of time to prevent one-frame readjustment of scrolling.
+ // - (2) Items needs to have persistent ID Stack identifier = ID needs to not depends on their index. PushID(index) = KO. PushID(item_id) = OK. This is in order to focus items reliably after a selection.
+ // - (3) BeginXXXX process
+ // - (4) Focus process
+ // - (5) EndXXXX process
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (with deletion)");
+ if (ImGui::TreeNode("Multi-Select (with deletion)"))
+ {
+ // Storing items data separately from selection data.
+ // (you may decide to store selection data inside your item (aka intrusive storage) if you don't need multiple views over same items)
+ // Use a custom selection.Adapter: store item identifier in Selection (instead of index)
+ static ImVector<ImGuiID> items;
+ static ExampleSelectionWithDeletion selection;
+ selection.UserData = (void*)&items;
+ selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self, int idx) { ImVector<ImGuiID>* p_items = (ImVector<ImGuiID>*)self->UserData; return (*p_items)[idx]; }; // Index -> ID
+
+ ImGui::Text("Added features:");
+ ImGui::BulletText("Dynamic list with Delete key support.");
+ ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
+
+ // Initialize default list with 50 items + button to add/remove items.
+ static ImGuiID items_next_id = 0;
+ if (items_next_id == 0)
+ for (ImGuiID n = 0; n < 50; n++)
+ items.push_back(items_next_id++);
+ if (ImGui::SmallButton("Add 20 items")) { for (int n = 0; n < 20; n++) { items.push_back(items_next_id++); } }
+ ImGui::SameLine();
+ if (ImGui::SmallButton("Remove 20 items")) { for (int n = IM_MIN(20, items.Size); n > 0; n--) { selection.SetItemSelected(items.back(), false); items.pop_back(); } }
+
+ // (1) Extra to support deletion: Submit scrolling range to avoid glitches on deletion
+ const float items_height = ImGui::GetTextLineHeightWithSpacing();
+ ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
+
+ if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
+ {
+ ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
+ selection.ApplyRequests(ms_io);
+
+ const bool want_delete = ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0);
+ const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
+
+ for (int n = 0; n < items.Size; n++)
+ {
+ const ImGuiID item_id = items[n];
+ char label[64];
+ sprintf(label, "Object %05u: %s", item_id, ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)]);
+
+ bool item_is_selected = selection.Contains(item_id);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Selectable(label, item_is_selected);
+ if (item_curr_idx_to_focus == n)
+ ImGui::SetKeyboardFocusHere(-1);
+ }
+
+ // Apply multi-select requests
+ ms_io = ImGui::EndMultiSelect();
+ selection.ApplyRequests(ms_io);
+ if (want_delete)
+ selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
+ }
+ ImGui::EndChild();
+ ImGui::TreePop();
+ }
+
+ // Implement a Dual List Box (#6648)
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (dual list box)");
+ if (ImGui::TreeNode("Multi-Select (dual list box)"))
+ {
+ // Init default state
+ static ExampleDualListBox dlb;
+ if (dlb.Items[0].Size == 0 && dlb.Items[1].Size == 0)
+ for (int item_id = 0; item_id < IM_ARRAYSIZE(ExampleNames); item_id++)
+ dlb.Items[0].push_back((ImGuiID)item_id);
+
+ // Show
+ dlb.Show();
+
+ ImGui::TreePop();
+ }
+
+ // Demonstrate using the clipper with BeginMultiSelect()/EndMultiSelect()
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (in a table)");
+ if (ImGui::TreeNode("Multi-Select (in a table)"))
+ {
+ static ImGuiSelectionBasicStorage selection;
+
+ const int ITEMS_COUNT = 10000;
+ ImGui::Text("Selection: %d/%d", selection.Size, ITEMS_COUNT);
+ if (ImGui::BeginTable("##Basket", 2, ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter))
+ {
+ ImGui::TableSetupColumn("Object");
+ ImGui::TableSetupColumn("Action");
+ ImGui::TableSetupScrollFreeze(0, 1);
+ ImGui::TableHeadersRow();
+
+ ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, ITEMS_COUNT);
+ selection.ApplyRequests(ms_io);
+
+ ImGuiListClipper clipper;
+ clipper.Begin(ITEMS_COUNT);
+ if (ms_io->RangeSrcItem != -1)
+ clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
+ while (clipper.Step())
+ {
+ for (int n = clipper.DisplayStart; n < clipper.DisplayEnd; n++)
+ {
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+ char label[64];
+ sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
+ bool item_is_selected = selection.Contains((ImGuiID)n);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap);
+ ImGui::TableNextColumn();
+ ImGui::SmallButton("hello");
+ }
+ }
+
+ ms_io = ImGui::EndMultiSelect();
+ selection.ApplyRequests(ms_io);
+ ImGui::EndTable();
+ }
+ ImGui::TreePop();
+ }
+
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (checkboxes)");
+ if (ImGui::TreeNode("Multi-Select (checkboxes)"))
+ {
+ ImGui::Text("In a list of checkboxes (not selectable):");
+ ImGui::BulletText("Using _NoAutoSelect + _NoAutoClear flags.");
+ ImGui::BulletText("Shift+Click to check multiple boxes.");
+ ImGui::BulletText("Shift+Keyboard to copy current value to other boxes.");
+
+ // If you have an array of checkboxes, you may want to use NoAutoSelect + NoAutoClear and the ImGuiSelectionExternalStorage helper.
+ static bool items[20] = {};
+ static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_NoAutoSelect | ImGuiMultiSelectFlags_NoAutoClear | ImGuiMultiSelectFlags_ClearOnEscape;
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d); // Cannot use ImGuiMultiSelectFlags_BoxSelect1d as checkboxes are varying width.
+
+ if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
+ {
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, -1, IM_ARRAYSIZE(items));
+ ImGuiSelectionExternalStorage storage_wrapper;
+ storage_wrapper.UserData = (void*)items;
+ storage_wrapper.AdapterSetItemSelected = [](ImGuiSelectionExternalStorage* self, int n, bool selected) { bool* array = (bool*)self->UserData; array[n] = selected; };
+ storage_wrapper.ApplyRequests(ms_io);
+ for (int n = 0; n < 20; n++)
+ {
+ char label[32];
+ sprintf(label, "Item %d", n);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Checkbox(label, &items[n]);
+ }
+ ms_io = ImGui::EndMultiSelect();
+ storage_wrapper.ApplyRequests(ms_io);
+ }
+ ImGui::EndChild();
+
+ ImGui::TreePop();
+ }
+
+ // Demonstrate individual selection scopes in same window
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (multiple scopes)");
+ if (ImGui::TreeNode("Multi-Select (multiple scopes)"))
+ {
+ // Use default select: Pass index to SetNextItemSelectionUserData(), store index in Selection
+ const int SCOPES_COUNT = 3;
+ const int ITEMS_COUNT = 8; // Per scope
+ static ImGuiSelectionBasicStorage selections_data[SCOPES_COUNT];
+
+ // Use ImGuiMultiSelectFlags_ScopeRect to not affect other selections in same window.
+ static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ScopeRect | ImGuiMultiSelectFlags_ClearOnEscape;// | ImGuiMultiSelectFlags_ClearOnClickVoid;
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
+ flags &= ~ImGuiMultiSelectFlags_ScopeRect;
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
+ flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
+
+ for (int selection_scope_n = 0; selection_scope_n < SCOPES_COUNT; selection_scope_n++)
+ {
+ ImGui::PushID(selection_scope_n);
+ ImGuiSelectionBasicStorage* selection = &selections_data[selection_scope_n];
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection->Size, ITEMS_COUNT);
+ selection->ApplyRequests(ms_io);
+
+ ImGui::SeparatorText("Selection scope");
+ ImGui::Text("Selection size: %d/%d", selection->Size, ITEMS_COUNT);
+
+ for (int n = 0; n < ITEMS_COUNT; n++)
+ {
+ char label[64];
+ sprintf(label, "Object %05d: %s", n, ExampleNames[n % IM_ARRAYSIZE(ExampleNames)]);
+ bool item_is_selected = selection->Contains((ImGuiID)n);
+ ImGui::SetNextItemSelectionUserData(n);
+ ImGui::Selectable(label, item_is_selected);
+ }
+
+ // Apply multi-select requests
+ ms_io = ImGui::EndMultiSelect();
+ selection->ApplyRequests(ms_io);
+ ImGui::PopID();
+ }
+ ImGui::TreePop();
+ }
+
+ // See ShowExampleAppAssetsBrowser()
+ if (ImGui::TreeNode("Multi-Select (tiled assets browser)"))
+ {
+ ImGui::Checkbox("Assets Browser", &demo_data->ShowAppAssetsBrowser);
+ ImGui::Text("(also access from 'Examples->Assets Browser' in menu)");
+ ImGui::TreePop();
+ }
+
+ // Demonstrate supporting multiple-selection in a tree.
+ // - We don't use linear indices for selection user data, but our ExampleTreeNode* pointer directly!
+ // This showcase how SetNextItemSelectionUserData() never assume indices!
+ // - The difficulty here is to "interpolate" from RangeSrcItem to RangeDstItem in the SetAll/SetRange request.
+ // We want this interpolation to match what the user sees: in visible order, skipping closed nodes.
+ // This is implemented by our TreeGetNextNodeInVisibleOrder() user-space helper.
+ // - Important: In a real codebase aiming to implement full-featured selectable tree with custom filtering, you
+ // are more likely to build an array mapping sequential indices to visible tree nodes, since your
+ // filtering/search + clipping process will benefit from it. Having this will make this interpolation much easier.
+ // - Consider this a prototype: we are working toward simplifying some of it.
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (trees)");
+ if (ImGui::TreeNode("Multi-Select (trees)"))
+ {
+ HelpMarker(
+ "This is rather advanced and experimental. If you are getting started with multi-select,"
+ "please don't start by looking at how to use it for a tree!\n\n"
+ "Future versions will try to simplify and formalize some of this.");
+
+ struct ExampleTreeFuncs
+ {
+ static void DrawNode(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection)
+ {
+ ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
+ tree_node_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Enable pressing left to jump to parent
+ if (node->Childs.Size == 0)
+ tree_node_flags |= ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_Leaf;
+ if (selection->Contains((ImGuiID)node->UID))
+ tree_node_flags |= ImGuiTreeNodeFlags_Selected;
+
+ // Using SetNextItemStorageID() to specify storage id, so we can easily peek into
+ // the storage holding open/close stage, using our TreeNodeGetOpen/TreeNodeSetOpen() functions.
+ ImGui::SetNextItemSelectionUserData((ImGuiSelectionUserData)(intptr_t)node);
+ ImGui::SetNextItemStorageID((ImGuiID)node->UID);
+ if (ImGui::TreeNodeEx(node->Name, tree_node_flags))
+ {
+ for (ExampleTreeNode* child : node->Childs)
+ DrawNode(child, selection);
+ ImGui::TreePop();
+ }
+ else if (ImGui::IsItemToggledOpen())
+ {
+ TreeCloseAndUnselectChildNodes(node, selection);
+ }
+ }
+
+ static bool TreeNodeGetOpen(ExampleTreeNode* node)
+ {
+ return ImGui::GetStateStorage()->GetBool((ImGuiID)node->UID);
+ }
+
+ static void TreeNodeSetOpen(ExampleTreeNode* node, bool open)
+ {
+ ImGui::GetStateStorage()->SetBool((ImGuiID)node->UID, open);
+ }
+
+ // When closing a node: 1) close and unselect all child nodes, 2) select parent if any child was selected.
+ // FIXME: This is currently handled by user logic but I'm hoping to eventually provide tree node
+ // features to do this automatically, e.g. a ImGuiTreeNodeFlags_AutoCloseChildNodes etc.
+ static int TreeCloseAndUnselectChildNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, int depth = 0)
+ {
+ // Recursive close (the test for depth == 0 is because we call this on a node that was just closed!)
+ int unselected_count = selection->Contains((ImGuiID)node->UID) ? 1 : 0;
+ if (depth == 0 || TreeNodeGetOpen(node))
+ {
+ for (ExampleTreeNode* child : node->Childs)
+ unselected_count += TreeCloseAndUnselectChildNodes(child, selection, depth + 1);
+ TreeNodeSetOpen(node, false);
+ }
+
+ // Select root node if any of its child was selected, otherwise unselect
+ selection->SetItemSelected((ImGuiID)node->UID, (depth == 0 && unselected_count > 0));
+ return unselected_count;
+ }
+
+ // Apply multi-selection requests
+ static void ApplySelectionRequests(ImGuiMultiSelectIO* ms_io, ExampleTreeNode* tree, ImGuiSelectionBasicStorage* selection)
+ {
+ for (ImGuiSelectionRequest& req : ms_io->Requests)
+ {
+ if (req.Type == ImGuiSelectionRequestType_SetAll)
+ {
+ if (req.Selected)
+ TreeSetAllInOpenNodes(tree, selection, req.Selected);
+ else
+ selection->Clear();
+ }
+ else if (req.Type == ImGuiSelectionRequestType_SetRange)
+ {
+ ExampleTreeNode* first_node = (ExampleTreeNode*)(intptr_t)req.RangeFirstItem;
+ ExampleTreeNode* last_node = (ExampleTreeNode*)(intptr_t)req.RangeLastItem;
+ for (ExampleTreeNode* node = first_node; node != NULL; node = TreeGetNextNodeInVisibleOrder(node, last_node))
+ selection->SetItemSelected((ImGuiID)node->UID, req.Selected);
+ }
+ }
+ }
+
+ static void TreeSetAllInOpenNodes(ExampleTreeNode* node, ImGuiSelectionBasicStorage* selection, bool selected)
+ {
+ if (node->Parent != NULL) // Root node isn't visible nor selectable in our scheme
+ selection->SetItemSelected((ImGuiID)node->UID, selected);
+ if (node->Parent == NULL || TreeNodeGetOpen(node))
+ for (ExampleTreeNode* child : node->Childs)
+ TreeSetAllInOpenNodes(child, selection, selected);
+ }
+
+ // Interpolate in *user-visible order* AND only *over opened nodes*.
+ // If you have a sequential mapping tables (e.g. generated after a filter/search pass) this would be simpler.
+ // Here the tricks are that:
+ // - we store/maintain ExampleTreeNode::IndexInParent which allows implementing a linear iterator easily, without searches, without recursion.
+ // this could be replaced by a search in parent, aka 'int index_in_parent = curr_node->Parent->Childs.find_index(curr_node)'
+ // which would only be called when crossing from child to a parent, aka not too much.
+ // - we call SetNextItemStorageID() before our TreeNode() calls with an ID which doesn't relate to UI stack,
+ // making it easier to call TreeNodeGetOpen()/TreeNodeSetOpen() from any location.
+ static ExampleTreeNode* TreeGetNextNodeInVisibleOrder(ExampleTreeNode* curr_node, ExampleTreeNode* last_node)
+ {
+ // Reached last node
+ if (curr_node == last_node)
+ return NULL;
+
+ // Recurse into childs. Query storage to tell if the node is open.
+ if (curr_node->Childs.Size > 0 && TreeNodeGetOpen(curr_node))
+ return curr_node->Childs[0];
+
+ // Next sibling, then into our own parent
+ while (curr_node->Parent != NULL)
+ {
+ if (curr_node->IndexInParent + 1 < curr_node->Parent->Childs.Size)
+ return curr_node->Parent->Childs[curr_node->IndexInParent + 1];
+ curr_node = curr_node->Parent;
+ }
+ return NULL;
+ }
+
+ }; // ExampleTreeFuncs
+
+ static ImGuiSelectionBasicStorage selection;
+ if (demo_data->DemoTree == NULL)
+ demo_data->DemoTree = ExampleTree_CreateDemoTree(); // Create tree once
+ ImGui::Text("Selection size: %d", selection.Size);
+
+ if (ImGui::BeginChild("##Tree", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
+ {
+ ExampleTreeNode* tree = demo_data->DemoTree;
+ ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect2d;
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, selection.Size, -1);
+ ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
+ for (ExampleTreeNode* node : tree->Childs)
+ ExampleTreeFuncs::DrawNode(node, &selection);
+ ms_io = ImGui::EndMultiSelect();
+ ExampleTreeFuncs::ApplySelectionRequests(ms_io, tree, &selection);
+ }
+ ImGui::EndChild();
+
+ ImGui::TreePop();
+ }
+
+ // Advanced demonstration of BeginMultiSelect()
+ // - Showcase clipping.
+ // - Showcase deletion.
+ // - Showcase basic drag and drop.
+ // - Showcase TreeNode variant (note that tree node don't expand in the demo: supporting expanding tree nodes + clipping a separate thing).
+ // - Showcase using inside a table.
+ IMGUI_DEMO_MARKER("Widgets/Selection State/Multi-Select (advanced)");
+ //ImGui::SetNextItemOpen(true, ImGuiCond_Once);
+ if (ImGui::TreeNode("Multi-Select (advanced)"))
+ {
+ // Options
+ enum WidgetType { WidgetType_Selectable, WidgetType_TreeNode };
+ static bool use_clipper = true;
+ static bool use_deletion = true;
+ static bool use_drag_drop = true;
+ static bool show_in_table = false;
+ static bool show_color_button = true;
+ static ImGuiMultiSelectFlags flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_BoxSelect1d;
+ static WidgetType widget_type = WidgetType_Selectable;
+
+ if (ImGui::TreeNode("Options"))
+ {
+ if (ImGui::RadioButton("Selectables", widget_type == WidgetType_Selectable)) { widget_type = WidgetType_Selectable; }
+ ImGui::SameLine();
+ if (ImGui::RadioButton("Tree nodes", widget_type == WidgetType_TreeNode)) { widget_type = WidgetType_TreeNode; }
+ ImGui::SameLine();
+ HelpMarker("TreeNode() is technically supported but... using this correctly is more complicated (you need some sort of linear/random access to your tree, which is suited to advanced trees setups already implementing filters and clipper. We will work toward simplifying and demoing this.\n\nFor now the tree demo is actually a little bit meaningless because it is an empty tree with only root nodes.");
+ ImGui::Checkbox("Enable clipper", &use_clipper);
+ ImGui::Checkbox("Enable deletion", &use_deletion);
+ ImGui::Checkbox("Enable drag & drop", &use_drag_drop);
+ ImGui::Checkbox("Show in a table", &show_in_table);
+ ImGui::Checkbox("Show color button", &show_color_button);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SingleSelect", &flags, ImGuiMultiSelectFlags_SingleSelect);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoSelectAll", &flags, ImGuiMultiSelectFlags_NoSelectAll);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoRangeSelect", &flags, ImGuiMultiSelectFlags_NoRangeSelect);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoSelect", &flags, ImGuiMultiSelectFlags_NoAutoSelect);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClear", &flags, ImGuiMultiSelectFlags_NoAutoClear);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_NoAutoClearOnReselect", &flags, ImGuiMultiSelectFlags_NoAutoClearOnReselect);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect1d", &flags, ImGuiMultiSelectFlags_BoxSelect1d);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelect2d", &flags, ImGuiMultiSelectFlags_BoxSelect2d);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_BoxSelectNoScroll", &flags, ImGuiMultiSelectFlags_BoxSelectNoScroll);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnEscape", &flags, ImGuiMultiSelectFlags_ClearOnEscape);
+ ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ClearOnClickVoid", &flags, ImGuiMultiSelectFlags_ClearOnClickVoid);
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeWindow", &flags, ImGuiMultiSelectFlags_ScopeWindow) && (flags & ImGuiMultiSelectFlags_ScopeWindow))
+ flags &= ~ImGuiMultiSelectFlags_ScopeRect;
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_ScopeRect", &flags, ImGuiMultiSelectFlags_ScopeRect) && (flags & ImGuiMultiSelectFlags_ScopeRect))
+ flags &= ~ImGuiMultiSelectFlags_ScopeWindow;
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClick", &flags, ImGuiMultiSelectFlags_SelectOnClick) && (flags & ImGuiMultiSelectFlags_SelectOnClick))
+ flags &= ~ImGuiMultiSelectFlags_SelectOnClickRelease;
+ if (ImGui::CheckboxFlags("ImGuiMultiSelectFlags_SelectOnClickRelease", &flags, ImGuiMultiSelectFlags_SelectOnClickRelease) && (flags & ImGuiMultiSelectFlags_SelectOnClickRelease))
+ flags &= ~ImGuiMultiSelectFlags_SelectOnClick;
+ ImGui::SameLine(); HelpMarker("Allow dragging an unselected item without altering selection.");
+ ImGui::TreePop();
+ }
+
+ // Initialize default list with 1000 items.
+ // Use default selection.Adapter: Pass index to SetNextItemSelectionUserData(), store index in Selection
+ static ImVector<int> items;
+ static int items_next_id = 0;
+ if (items_next_id == 0) { for (int n = 0; n < 1000; n++) { items.push_back(items_next_id++); } }
+ static ExampleSelectionWithDeletion selection;
+ static bool request_deletion_from_menu = false; // Queue deletion triggered from context menu
+
+ ImGui::Text("Selection size: %d/%d", selection.Size, items.Size);
+
+ const float items_height = (widget_type == WidgetType_TreeNode) ? ImGui::GetTextLineHeight() : ImGui::GetTextLineHeightWithSpacing();
+ ImGui::SetNextWindowContentSize(ImVec2(0.0f, items.Size * items_height));
+ if (ImGui::BeginChild("##Basket", ImVec2(-FLT_MIN, ImGui::GetFontSize() * 20), ImGuiChildFlags_FrameStyle | ImGuiChildFlags_ResizeY))
+ {
+ ImVec2 color_button_sz(ImGui::GetFontSize(), ImGui::GetFontSize());
+ if (widget_type == WidgetType_TreeNode)
+ ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, 0.0f);
+
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(flags, selection.Size, items.Size);
+ selection.ApplyRequests(ms_io);
+
+ const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (selection.Size > 0)) || request_deletion_from_menu;
+ const int item_curr_idx_to_focus = want_delete ? selection.ApplyDeletionPreLoop(ms_io, items.Size) : -1;
+ request_deletion_from_menu = false;
+
+ if (show_in_table)
+ {
+ if (widget_type == WidgetType_TreeNode)
+ ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0.0f, 0.0f));
+ ImGui::BeginTable("##Split", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_NoSavedSettings | ImGuiTableFlags_NoPadOuterX);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.70f);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 0.30f);
+ //ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacingY, 0.0f);
+ }
+
+ ImGuiListClipper clipper;
+ if (use_clipper)
+ {
+ clipper.Begin(items.Size);
+ if (item_curr_idx_to_focus != -1)
+ clipper.IncludeItemByIndex(item_curr_idx_to_focus); // Ensure focused item is not clipped.
+ if (ms_io->RangeSrcItem != -1)
+ clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem); // Ensure RangeSrc item is not clipped.
+ }
+
+ while (!use_clipper || clipper.Step())
+ {
+ const int item_begin = use_clipper ? clipper.DisplayStart : 0;
+ const int item_end = use_clipper ? clipper.DisplayEnd : items.Size;
+ for (int n = item_begin; n < item_end; n++)
+ {
+ if (show_in_table)
+ ImGui::TableNextColumn();
+
+ const int item_id = items[n];
+ const char* item_category = ExampleNames[item_id % IM_ARRAYSIZE(ExampleNames)];
+ char label[64];
+ sprintf(label, "Object %05d: %s", item_id, item_category);
+
+ // IMPORTANT: for deletion refocus to work we need object ID to be stable,
+ // aka not depend on their index in the list. Here we use our persistent item_id
+ // instead of index to build a unique ID that will persist.
+ // (If we used PushID(index) instead, focus wouldn't be restored correctly after deletion).
+ ImGui::PushID(item_id);
+
+ // Emit a color button, to test that Shift+LeftArrow landing on an item that is not part
+ // of the selection scope doesn't erroneously alter our selection.
+ if (show_color_button)
+ {
+ ImU32 dummy_col = (ImU32)((unsigned int)n * 0xC250B74B) | IM_COL32_A_MASK;
+ ImGui::ColorButton("##", ImColor(dummy_col), ImGuiColorEditFlags_NoTooltip, color_button_sz);
+ ImGui::SameLine();
+ }
+
+ // Submit item
+ bool item_is_selected = selection.Contains((ImGuiID)n);
+ bool item_is_open = false;
+ ImGui::SetNextItemSelectionUserData(n);
+ if (widget_type == WidgetType_Selectable)
+ {
+ ImGui::Selectable(label, item_is_selected, ImGuiSelectableFlags_None);
+ }
+ else if (widget_type == WidgetType_TreeNode)
+ {
+ ImGuiTreeNodeFlags tree_node_flags = ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
+ if (item_is_selected)
+ tree_node_flags |= ImGuiTreeNodeFlags_Selected;
+ item_is_open = ImGui::TreeNodeEx(label, tree_node_flags);
+ }
+
+ // Focus (for after deletion)
+ if (item_curr_idx_to_focus == n)
+ ImGui::SetKeyboardFocusHere(-1);
+
+ // Drag and Drop
+ if (use_drag_drop && ImGui::BeginDragDropSource())
+ {
+ // Create payload with full selection OR single unselected item.
+ // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
+ if (ImGui::GetDragDropPayload() == NULL)
+ {
+ ImVector<int> payload_items;
+ void* it = NULL;
+ ImGuiID id = 0;
+ if (!item_is_selected)
+ payload_items.push_back(item_id);
+ else
+ while (selection.GetNextSelectedItem(&it, &id))
+ payload_items.push_back((int)id);
+ ImGui::SetDragDropPayload("MULTISELECT_DEMO_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
+ }
+
+ // Display payload content in tooltip
+ const ImGuiPayload* payload = ImGui::GetDragDropPayload();
+ const int* payload_items = (int*)payload->Data;
+ const int payload_count = (int)payload->DataSize / (int)sizeof(int);
+ if (payload_count == 1)
+ ImGui::Text("Object %05d: %s", payload_items[0], ExampleNames[payload_items[0] % IM_ARRAYSIZE(ExampleNames)]);
+ else
+ ImGui::Text("Dragging %d objects", payload_count);
+
+ ImGui::EndDragDropSource();
+ }
+
+ if (widget_type == WidgetType_TreeNode && item_is_open)
+ ImGui::TreePop();
+
+ // Right-click: context menu
+ if (ImGui::BeginPopupContextItem())
+ {
+ ImGui::BeginDisabled(!use_deletion || selection.Size == 0);
+ sprintf(label, "Delete %d item(s)###DeleteSelected", selection.Size);
+ if (ImGui::Selectable(label))
+ request_deletion_from_menu = true;
+ ImGui::EndDisabled();
+ ImGui::Selectable("Close");
+ ImGui::EndPopup();
+ }
+
+ // Demo content within a table
+ if (show_in_table)
+ {
+ ImGui::TableNextColumn();
+ ImGui::SetNextItemWidth(-FLT_MIN);
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, 0));
+ ImGui::InputText("###NoLabel", (char*)(void*)item_category, strlen(item_category), ImGuiInputTextFlags_ReadOnly);
+ ImGui::PopStyleVar();
+ }
+
+ ImGui::PopID();
+ }
+ if (!use_clipper)
+ break;
+ }
+
+ if (show_in_table)
+ {
+ ImGui::EndTable();
+ if (widget_type == WidgetType_TreeNode)
+ ImGui::PopStyleVar();
+ }
+
+ // Apply multi-select requests
+ ms_io = ImGui::EndMultiSelect();
+ selection.ApplyRequests(ms_io);
+ if (want_delete)
+ selection.ApplyDeletionPostLoop(ms_io, items, item_curr_idx_to_focus);
- IMGUI_DEMO_MARKER("Widgets/Text Filter");
- if (ImGui::TreeNode("Text Filter"))
- {
- // Helper class to easy setup a text filter.
- // You may want to implement a more feature-full filtering scheme in your own application.
- HelpMarker("Not a widget per-se, but ImGuiTextFilter is a helper to perform simple filtering on text strings.");
- static ImGuiTextFilter filter;
- ImGui::Text("Filter usage:\n"
- " \"\" display all lines\n"
- " \"xxx\" display lines containing \"xxx\"\n"
- " \"xxx,yyy\" display lines containing \"xxx\" or \"yyy\"\n"
- " \"-xxx\" hide lines containing \"xxx\"");
- filter.Draw();
- const char* lines[] = { "aaa1.c", "bbb1.c", "ccc1.c", "aaa2.cpp", "bbb2.cpp", "ccc2.cpp", "abc.h", "hello, world" };
- for (int i = 0; i < IM_ARRAYSIZE(lines); i++)
- if (filter.PassFilter(lines[i]))
- ImGui::BulletText("%s", lines[i]);
+ if (widget_type == WidgetType_TreeNode)
+ ImGui::PopStyleVar();
+ }
+ ImGui::EndChild();
+ ImGui::TreePop();
+ }
ImGui::TreePop();
}
}
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowLayout()
+//-----------------------------------------------------------------------------
+
static void ShowDemoWindowLayout()
{
IMGUI_DEMO_MARKER("Layout");
@@ -2875,7 +4001,7 @@ static void ShowDemoWindowLayout()
if (!disable_menu)
window_flags |= ImGuiWindowFlags_MenuBar;
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0f);
- ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Border, window_flags);
+ ImGui::BeginChild("ChildR", ImVec2(0, 260), ImGuiChildFlags_Borders, window_flags);
if (!disable_menu && ImGui::BeginMenuBar())
{
if (ImGui::BeginMenu("Menu"))
@@ -2904,8 +4030,11 @@ static void ShowDemoWindowLayout()
ImGui::SeparatorText("Manual-resize");
{
HelpMarker("Drag bottom border to resize. Double-click bottom border to auto-fit to vertical contents.");
+ //if (ImGui::Button("Set Height to 200"))
+ // ImGui::SetNextWindowSize(ImVec2(-FLT_MIN, 200.0f));
+
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::GetStyleColorVec4(ImGuiCol_FrameBg));
- if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY))
+ if (ImGui::BeginChild("ResizableChild", ImVec2(-FLT_MIN, ImGui::GetTextLineHeightWithSpacing() * 8), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeY))
for (int n = 0; n < 10; n++)
ImGui::Text("Line %04d", n);
ImGui::PopStyleColor();
@@ -2923,7 +4052,7 @@ static void ShowDemoWindowLayout()
ImGui::DragInt("Max Height (in Lines)", &max_height_in_lines, 0.2f);
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 1), ImVec2(FLT_MAX, ImGui::GetTextLineHeightWithSpacing() * max_height_in_lines));
- if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY))
+ if (ImGui::BeginChild("ConstrainedChild", ImVec2(-FLT_MIN, 0.0f), ImGuiChildFlags_Borders | ImGuiChildFlags_AutoResizeY))
for (int n = 0; n < draw_lines; n++)
ImGui::Text("Line %04d", n);
ImGui::EndChild();
@@ -2941,11 +4070,11 @@ static void ShowDemoWindowLayout()
{
static int offset_x = 0;
static bool override_bg_color = true;
- static ImGuiChildFlags child_flags = ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
+ static ImGuiChildFlags child_flags = ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX | ImGuiChildFlags_ResizeY;
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
ImGui::DragInt("Offset X", &offset_x, 1.0f, -1000, 1000);
ImGui::Checkbox("Override ChildBg color", &override_bg_color);
- ImGui::CheckboxFlags("ImGuiChildFlags_Border", &child_flags, ImGuiChildFlags_Border);
+ ImGui::CheckboxFlags("ImGuiChildFlags_Borders", &child_flags, ImGuiChildFlags_Borders);
ImGui::CheckboxFlags("ImGuiChildFlags_AlwaysUseWindowPadding", &child_flags, ImGuiChildFlags_AlwaysUseWindowPadding);
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeX", &child_flags, ImGuiChildFlags_ResizeX);
ImGui::CheckboxFlags("ImGuiChildFlags_ResizeY", &child_flags, ImGuiChildFlags_ResizeY);
@@ -3131,7 +4260,7 @@ static void ShowDemoWindowLayout()
ImGui::Text("Manual wrapping:");
ImGuiStyle& style = ImGui::GetStyle();
int buttons_count = 20;
- float window_visible_x2 = ImGui::GetWindowPos().x + ImGui::GetWindowContentRegionMax().x;
+ float window_visible_x2 = ImGui::GetCursorScreenPos().x + ImGui::GetContentRegionAvail().x;
for (int n = 0; n < buttons_count; n++)
{
ImGui::PushID(n);
@@ -3212,7 +4341,7 @@ static void ShowDemoWindowLayout()
// down by FramePadding.y ahead of time)
ImGui::AlignTextToFramePadding();
ImGui::Text("OK Blahblah"); ImGui::SameLine();
- ImGui::Button("Some framed item"); ImGui::SameLine();
+ ImGui::Button("Some framed item##2"); ImGui::SameLine();
HelpMarker("We call AlignTextToFramePadding() to vertically align the text baseline by +FramePadding.y");
// SmallButton() uses the same vertical padding as Text
@@ -3355,7 +4484,7 @@ static void ShowDemoWindowLayout()
const ImGuiWindowFlags child_flags = enable_extra_decorations ? ImGuiWindowFlags_MenuBar : 0;
const ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
- const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Border, child_flags);
+ const bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(child_w, 200.0f), ImGuiChildFlags_Borders, child_flags);
if (ImGui::BeginMenuBar())
{
ImGui::TextUnformatted("abc");
@@ -3402,7 +4531,7 @@ static void ShowDemoWindowLayout()
float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
ImGuiWindowFlags child_flags = ImGuiWindowFlags_HorizontalScrollbar | (enable_extra_decorations ? ImGuiWindowFlags_AlwaysVerticalScrollbar : 0);
ImGuiID child_id = ImGui::GetID((void*)(intptr_t)i);
- bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Border, child_flags);
+ bool child_is_visible = ImGui::BeginChild(child_id, ImVec2(-100, child_height), ImGuiChildFlags_Borders, child_flags);
if (scroll_to_off)
ImGui::SetScrollX(scroll_to_off_px);
if (scroll_to_pos)
@@ -3444,7 +4573,7 @@ static void ShowDemoWindowLayout()
ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 3.0f);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2.0f, 1.0f));
ImVec2 scrolling_child_size = ImVec2(0, ImGui::GetFrameHeightWithSpacing() * 7 + 30);
- ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Border, ImGuiWindowFlags_HorizontalScrollbar);
+ ImGui::BeginChild("scrolling", scrolling_child_size, ImGuiChildFlags_Borders, ImGuiWindowFlags_HorizontalScrollbar);
for (int line = 0; line < lines; line++)
{
// Display random stuff. For the sake of this trivial demo we are using basic Button() + SameLine()
@@ -3590,7 +4719,7 @@ static void ShowDemoWindowLayout()
}
if (show_child)
{
- ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Border);
+ ImGui::BeginChild("child", ImVec2(0, 0), ImGuiChildFlags_Borders);
ImGui::EndChild();
}
ImGui::End();
@@ -3599,8 +4728,8 @@ static void ShowDemoWindowLayout()
ImGui::TreePop();
}
- IMGUI_DEMO_MARKER("Layout/Clipping");
- if (ImGui::TreeNode("Clipping"))
+ IMGUI_DEMO_MARKER("Layout/Text Clipping");
+ if (ImGui::TreeNode("Text Clipping"))
{
static ImVec2 size(100.0f, 100.0f);
static ImVec2 offset(30.0f, 30.0f);
@@ -3696,6 +4825,10 @@ static void ShowDemoWindowLayout()
}
}
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowPopups()
+//-----------------------------------------------------------------------------
+
static void ShowDemoWindowPopups()
{
IMGUI_DEMO_MARKER("Popups");
@@ -3951,7 +5084,7 @@ static void ShowDemoWindowPopups()
static int item = 1;
static float color[4] = { 0.4f, 0.7f, 0.0f, 0.5f };
ImGui::Combo("Combo", &item, "aaaa\0bbbb\0cccc\0dddd\0eeee\0\0");
- ImGui::ColorEdit4("color", color);
+ ImGui::ColorEdit4("Color", color);
if (ImGui::Button("Add another modal.."))
ImGui::OpenPopup("Stacked 2");
@@ -3963,6 +5096,7 @@ static void ShowDemoWindowPopups()
if (ImGui::BeginPopupModal("Stacked 2", &unused_open))
{
ImGui::Text("Hello from Stacked The Second!");
+ ImGui::ColorEdit4("Color", color); // Allow opening another nested popup
if (ImGui::Button("Close"))
ImGui::CloseCurrentPopup();
ImGui::EndPopup();
@@ -4071,8 +5205,8 @@ const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
static void PushStyleCompact()
{
ImGuiStyle& style = ImGui::GetStyle();
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
+ ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, (float)(int)(style.FramePadding.y * 0.60f));
+ ImGui::PushStyleVarY(ImGuiStyleVar_ItemSpacing, (float)(int)(style.ItemSpacing.y * 0.60f));
}
static void PopStyleCompact()
@@ -4155,6 +5289,10 @@ static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
ImGui::CheckboxFlags("_IsHovered", &flags, ImGuiTableColumnFlags_IsHovered);
}
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowTables()
+//-----------------------------------------------------------------------------
+
static void ShowDemoWindowTables()
{
//ImGui::SetNextItemOpen(true, ImGuiCond_Once);
@@ -4273,7 +5411,7 @@ static void ShowDemoWindowTables()
PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags, ImGuiTableFlags_Borders);
- ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterH");
+ ImGui::SameLine(); HelpMarker("ImGuiTableFlags_Borders\n = ImGuiTableFlags_BordersInnerV\n | ImGuiTableFlags_BordersOuterV\n | ImGuiTableFlags_BordersInnerH\n | ImGuiTableFlags_BordersOuterH");
ImGui::Indent();
ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
@@ -5102,7 +6240,7 @@ static void ShowDemoWindowTables()
for (int row = 0; row < 8; row++)
{
if ((row % 3) == 2)
- ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(style.CellPadding.x, 20.0f));
+ ImGui::PushStyleVarY(ImGuiStyleVar_CellPadding, 20.0f);
ImGui::TableNextRow(ImGuiTableRowFlags_None);
ImGui::TableNextColumn();
ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
@@ -5381,7 +6519,11 @@ static void ShowDemoWindowTables()
// FIXME: It would be nice to actually demonstrate full-featured selection using those checkbox.
static bool column_selected[3] = {};
- // Instead of calling TableHeadersRow() we'll submit custom headers ourselves
+ // Instead of calling TableHeadersRow() we'll submit custom headers ourselves.
+ // (A different approach is also possible:
+ // - Specify ImGuiTableColumnFlags_NoHeaderLabel in some TableSetupColumn() call.
+ // - Call TableHeadersRow() normally. This will submit TableHeader() with no name.
+ // - Then call TableSetColumnIndex() to position yourself in the column and submit your stuff e.g. Checkbox().)
ImGui::TableNextRow(ImGuiTableRowFlags_Headers);
for (int column = 0; column < COLUMNS_COUNT; column++)
{
@@ -5396,6 +6538,7 @@ static void ShowDemoWindowTables()
ImGui::PopID();
}
+ // Submit table contents
for (int row = 0; row < 5; row++)
{
ImGui::TableNextRow();
@@ -5430,6 +6573,7 @@ static void ShowDemoWindowTables()
ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
ImGui::CheckboxFlags("_Resizable", &table_flags, ImGuiTableFlags_Resizable);
+ ImGui::CheckboxFlags("_Sortable", &table_flags, ImGuiTableFlags_Sortable);
ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
@@ -5927,7 +7071,6 @@ static void ShowDemoWindowTables()
// Show data
// FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
- ImGui::PushButtonRepeat(true);
#if 1
// Demonstrate using clipper for large vertical lists
ImGuiListClipper clipper;
@@ -6012,7 +7155,6 @@ static void ShowDemoWindowTables()
ImGui::PopID();
}
}
- ImGui::PopButtonRepeat();
// Store some info to display debug details below
table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
@@ -6122,12 +7264,14 @@ static void ShowDemoWindowColumns()
{
if (h_borders && ImGui::GetColumnIndex() == 0)
ImGui::Separator();
+ ImGui::PushID(i);
ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
ImGui::Text("Avail %.2f", ImGui::GetContentRegionAvail().x);
ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
ImGui::Text("Long text that is likely to clip");
ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
+ ImGui::PopID();
ImGui::NextColumn();
}
ImGui::Columns(1);
@@ -6250,6 +7394,10 @@ static void ShowDemoWindowColumns()
ImGui::TreePop();
}
+//-----------------------------------------------------------------------------
+// [SECTION] ShowDemoWindowInputs()
+//-----------------------------------------------------------------------------
+
static void ShowDemoWindowInputs()
{
IMGUI_DEMO_MARKER("Inputs & Focus");
@@ -6371,7 +7519,7 @@ static void ShowDemoWindowInputs()
ImGui::RadioButton("ImGuiInputFlags_RouteAlways", &route_type, ImGuiInputFlags_RouteAlways);
ImGuiInputFlags flags = route_type | route_options; // Merged flags
if (route_type != ImGuiInputFlags_RouteGlobal)
- route_options &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
+ flags &= ~(ImGuiInputFlags_RouteOverFocused | ImGuiInputFlags_RouteOverActive | ImGuiInputFlags_RouteUnlessBgFocused);
ImGui::SeparatorText("Using SetNextItemShortcut()");
ImGui::Text("Ctrl+S");
@@ -6446,7 +7594,8 @@ static void ShowDemoWindowInputs()
IM_ASSERT(IM_ARRAYSIZE(mouse_cursors_names) == ImGuiMouseCursor_COUNT);
ImGuiMouseCursor current = ImGui::GetMouseCursor();
- ImGui::Text("Current mouse cursor = %d: %s", current, mouse_cursors_names[current]);
+ const char* cursor_name = (current >= ImGuiMouseCursor_Arrow) && (current < ImGuiMouseCursor_COUNT) ? mouse_cursors_names[current] : "N/A";
+ ImGui::Text("Current mouse cursor = %d: %s", current, cursor_name);
ImGui::BeginDisabled(true);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", &io.BackendFlags, ImGuiBackendFlags_HasMouseCursors);
ImGui::EndDisabled();
@@ -6475,10 +7624,10 @@ static void ShowDemoWindowInputs()
ImGui::InputText("1", buf, IM_ARRAYSIZE(buf));
ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
ImGui::InputText("3", buf, IM_ARRAYSIZE(buf));
- ImGui::PushTabStop(false);
+ ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
ImGui::InputText("4 (tab skip)", buf, IM_ARRAYSIZE(buf));
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
- ImGui::PopTabStop();
+ ImGui::PopItemFlag();
ImGui::InputText("5", buf, IM_ARRAYSIZE(buf));
ImGui::TreePop();
}
@@ -6500,12 +7649,12 @@ static void ShowDemoWindowInputs()
ImGui::InputText("2", buf, IM_ARRAYSIZE(buf));
if (ImGui::IsItemActive()) has_focus = 2;
- ImGui::PushTabStop(false);
+ ImGui::PushItemFlag(ImGuiItemFlags_NoTabStop, true);
if (focus_3) ImGui::SetKeyboardFocusHere();
ImGui::InputText("3 (tab skip)", buf, IM_ARRAYSIZE(buf));
if (ImGui::IsItemActive()) has_focus = 3;
ImGui::SameLine(); HelpMarker("Item won't be cycled through when using TAB or Shift+Tab.");
- ImGui::PopTabStop();
+ ImGui::PopItemFlag();
if (has_focus)
ImGui::Text("Item with focus: %d", has_focus);
@@ -6570,6 +7719,17 @@ void ImGui::ShowAboutWindow(bool* p_open)
}
IMGUI_DEMO_MARKER("Tools/About Dear ImGui");
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
+
+ ImGui::TextLinkOpenURL("Homepage", "https://github.com/ocornut/imgui");
+ ImGui::SameLine();
+ ImGui::TextLinkOpenURL("FAQ", "https://github.com/ocornut/imgui/blob/master/docs/FAQ.md");
+ ImGui::SameLine();
+ ImGui::TextLinkOpenURL("Wiki", "https://github.com/ocornut/imgui/wiki");
+ ImGui::SameLine();
+ ImGui::TextLinkOpenURL("Releases", "https://github.com/ocornut/imgui/releases");
+ ImGui::SameLine();
+ ImGui::TextLinkOpenURL("Funding", "https://github.com/ocornut/imgui/wiki/Funding");
+
ImGui::Separator();
ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
@@ -6660,6 +7820,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
#endif
#ifdef __EMSCRIPTEN__
ImGui::Text("define: __EMSCRIPTEN__");
+ ImGui::Text("Emscripten: %d.%d.%d", __EMSCRIPTEN_major__, __EMSCRIPTEN_minor__, __EMSCRIPTEN_tiny__);
#endif
#ifdef IMGUI_HAS_VIEWPORT
ImGui::Text("define: IMGUI_HAS_VIEWPORT");
@@ -6846,6 +8007,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
ImGui::SliderFloat("TabBarBorderSize", &style.TabBarBorderSize, 0.0f, 2.0f, "%.0f");
+ ImGui::SliderFloat("TabBarOverlineSize", &style.TabBarOverlineSize, 0.0f, 2.0f, "%.0f");
+ ImGui::SameLine(); HelpMarker("Overline is only drawn over the selected tab when ImGuiTabBarFlags_DrawSelectedOverline is set.");
ImGui::SeparatorText("Rounding");
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f");
@@ -6865,7 +8028,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
int window_menu_button_position = style.WindowMenuButtonPosition + 1;
if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
- style.WindowMenuButtonPosition = window_menu_button_position - 1;
+ style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1);
ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0");
ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f");
ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
@@ -6893,7 +8056,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
}
ImGui::SeparatorText("Misc");
- ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
+ ImGui::SliderFloat2("DisplayWindowPadding", (float*)&style.DisplayWindowPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to regular windows: amount which we enforce to keep visible when moving near edges of your screen.");
+ ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f"); ImGui::SameLine(); HelpMarker("Apply to every windows, menus, popups, tooltips: amount where we avoid displaying contents. Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
ImGui::EndTabItem();
}
@@ -6935,7 +8099,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
"Right-click to open edit options menu.");
ImGui::SetNextWindowSizeConstraints(ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 10), ImVec2(FLT_MAX, FLT_MAX));
- ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Border, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar | ImGuiWindowFlags_NavFlattened);
+ ImGui::BeginChild("##colors", ImVec2(0, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
ImGui::PushItemWidth(ImGui::GetFontSize() * -12);
for (int i = 0; i < ImGuiCol_COUNT; i++)
{
@@ -7016,10 +8180,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos());
if (show_samples && ImGui::BeginTooltip())
{
- ImGui::TextUnformatted("(R = radius, N = number of segments)");
+ ImGui::TextUnformatted("(R = radius, N = approx number of segments)");
ImGui::Spacing();
ImDrawList* draw_list = ImGui::GetWindowDrawList();
- const float min_widget_width = ImGui::CalcTextSize("N: MMM\nR: MMM").x;
+ const float min_widget_width = ImGui::CalcTextSize("R: MMM\nN: MMM").x;
for (int n = 0; n < 8; n++)
{
const float RAD_MIN = 5.0f;
@@ -7028,6 +8192,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::BeginGroup();
+ // N is not always exact here due to how PathArcTo() function work internally
ImGui::Text("R: %.f\nN: %d", rad, draw_list->_CalcCircleAutoSegmentCount(rad));
const float canvas_width = IM_MAX(min_widget_width, rad * 2.0f);
@@ -7168,7 +8333,7 @@ static void ShowExampleMenuFile()
{
static bool enabled = true;
ImGui::MenuItem("Enabled", "", &enabled);
- ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Border);
+ ImGui::BeginChild("child", ImVec2(0, 60), ImGuiChildFlags_Borders);
for (int i = 0; i < 10; i++)
ImGui::Text("Scrolling Text %d", i);
ImGui::EndChild();
@@ -7335,7 +8500,7 @@ struct ExampleAppConsole
// Reserve enough left-over height for 1 separator + 1 input text
const float footer_height_to_reserve = ImGui::GetStyle().ItemSpacing.y + ImGui::GetFrameHeightWithSpacing();
- if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_None, ImGuiWindowFlags_HorizontalScrollbar | ImGuiWindowFlags_NavFlattened))
+ if (ImGui::BeginChild("ScrollingRegion", ImVec2(0, -footer_height_to_reserve), ImGuiChildFlags_NavFlattened, ImGuiWindowFlags_HorizontalScrollbar))
{
if (ImGui::BeginPopupContextWindow())
{
@@ -7765,7 +8930,7 @@ static void ShowExampleAppLayout(bool* p_open)
// Left
static int selected = 0;
{
- ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeX);
+ ImGui::BeginChild("left pane", ImVec2(150, 0), ImGuiChildFlags_Borders | ImGuiChildFlags_ResizeX);
for (int i = 0; i < 100; i++)
{
// FIXME: Good candidate to use ImGuiSelectableFlags_SelectOnNav
@@ -7811,57 +8976,130 @@ static void ShowExampleAppLayout(bool* p_open)
//-----------------------------------------------------------------------------
// [SECTION] Example App: Property Editor / ShowExampleAppPropertyEditor()
//-----------------------------------------------------------------------------
+// Some of the interactions are a bit lack-luster:
+// - We would want pressing validating or leaving the filter to somehow restore focus.
+// - We may want more advanced filtering (child nodes) and clipper support: both will need extra work.
+// - We would want to customize some keyboard interactions to easily keyboard navigate between the tree and the properties.
+//-----------------------------------------------------------------------------
-static void ShowPlaceholderObject(const char* prefix, int uid)
+struct ExampleAppPropertyEditor
{
- // Use object uid as identifier. Most commonly you could also use the object pointer as a base ID.
- ImGui::PushID(uid);
-
- // Text and Tree nodes are less high than framed widgets, using AlignTextToFramePadding() we add vertical spacing to make the tree lines equal high.
- ImGui::TableNextRow();
- ImGui::TableSetColumnIndex(0);
- ImGui::AlignTextToFramePadding();
- bool node_open = ImGui::TreeNode("Object", "%s_%u", prefix, uid);
- ImGui::TableSetColumnIndex(1);
- ImGui::Text("my sailor is rich");
+ ImGuiTextFilter Filter;
+ ExampleTreeNode* VisibleNode = NULL;
- if (node_open)
+ void Draw(ExampleTreeNode* root_node)
{
- static float placeholder_members[8] = { 0.0f, 0.0f, 1.0f, 3.1416f, 100.0f, 999.0f };
- for (int i = 0; i < 8; i++)
+ // Left side: draw tree
+ // - Currently using a table to benefit from RowBg feature
+ if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
{
- ImGui::PushID(i); // Use field index as identifier.
- if (i < 2)
+ ImGui::SetNextItemWidth(-FLT_MIN);
+ ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
+ ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
+ if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_ARRAYSIZE(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
+ Filter.Build();
+ ImGui::PopItemFlag();
+
+ if (ImGui::BeginTable("##bg", 1, ImGuiTableFlags_RowBg))
{
- ShowPlaceholderObject("Child", 424242);
+ for (ExampleTreeNode* node : root_node->Childs)
+ if (Filter.PassFilter(node->Name)) // Filter root node
+ DrawTreeNode(node);
+ ImGui::EndTable();
}
- else
- {
- // Here we use a TreeNode to highlight on hover (we could use e.g. Selectable as well)
- ImGui::TableNextRow();
- ImGui::TableSetColumnIndex(0);
- ImGui::AlignTextToFramePadding();
- ImGuiTreeNodeFlags flags = ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_Bullet;
- ImGui::TreeNodeEx("Field", flags, "Field_%d", i);
+ }
+ ImGui::EndChild();
- ImGui::TableSetColumnIndex(1);
- ImGui::SetNextItemWidth(-FLT_MIN);
- if (i >= 5)
- ImGui::InputFloat("##value", &placeholder_members[i], 1.0f);
- else
- ImGui::DragFloat("##value", &placeholder_members[i], 0.01f);
- ImGui::NextColumn();
+ // Right side: draw properties
+ ImGui::SameLine();
+
+ ImGui::BeginGroup(); // Lock X position
+ if (ExampleTreeNode* node = VisibleNode)
+ {
+ ImGui::Text("%s", node->Name);
+ ImGui::TextDisabled("UID: 0x%08X", node->UID);
+ ImGui::Separator();
+ if (ImGui::BeginTable("##properties", 2, ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
+ {
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthStretch, 2.0f); // Default twice larger
+ if (node->HasData)
+ {
+ // In a typical application, the structure description would be derived from a data-driven system.
+ // - We try to mimic this with our ExampleMemberInfo structure and the ExampleTreeNodeMemberInfos[] array.
+ // - Limits and some details are hard-coded to simplify the demo.
+ for (const ExampleMemberInfo& field_desc : ExampleTreeNodeMemberInfos)
+ {
+ ImGui::TableNextRow();
+ ImGui::PushID(field_desc.Name);
+ ImGui::TableNextColumn();
+ ImGui::AlignTextToFramePadding();
+ ImGui::TextUnformatted(field_desc.Name);
+ ImGui::TableNextColumn();
+ void* field_ptr = (void*)(((unsigned char*)node) + field_desc.Offset);
+ switch (field_desc.DataType)
+ {
+ case ImGuiDataType_Bool:
+ {
+ IM_ASSERT(field_desc.DataCount == 1);
+ ImGui::Checkbox("##Editor", (bool*)field_ptr);
+ break;
+ }
+ case ImGuiDataType_S32:
+ {
+ int v_min = INT_MIN, v_max = INT_MAX;
+ ImGui::SetNextItemWidth(-FLT_MIN);
+ ImGui::DragScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, 1.0f, &v_min, &v_max);
+ break;
+ }
+ case ImGuiDataType_Float:
+ {
+ float v_min = 0.0f, v_max = 1.0f;
+ ImGui::SetNextItemWidth(-FLT_MIN);
+ ImGui::SliderScalarN("##Editor", field_desc.DataType, field_ptr, field_desc.DataCount, &v_min, &v_max);
+ break;
+ }
+ }
+ ImGui::PopID();
+ }
+ }
+ ImGui::EndTable();
}
- ImGui::PopID();
}
- ImGui::TreePop();
+ ImGui::EndGroup();
}
- ImGui::PopID();
-}
-// Demonstrate create a simple property editor.
-// This demo is a bit lackluster nowadays, would be nice to improve.
-static void ShowExampleAppPropertyEditor(bool* p_open)
+ void DrawTreeNode(ExampleTreeNode* node)
+ {
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn();
+ ImGui::PushID(node->UID);
+ ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
+ tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
+ tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsBackHere; // Left arrow support
+ if (node == VisibleNode)
+ tree_flags |= ImGuiTreeNodeFlags_Selected;
+ if (node->Childs.Size == 0)
+ tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
+ if (node->DataMyBool == false)
+ ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
+ bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
+ if (node->DataMyBool == false)
+ ImGui::PopStyleColor();
+ if (ImGui::IsItemFocused())
+ VisibleNode = node;
+ if (node_open)
+ {
+ for (ExampleTreeNode* child : node->Childs)
+ DrawTreeNode(child);
+ ImGui::TreePop();
+ }
+ ImGui::PopID();
+ }
+};
+
+// Demonstrate creating a simple property editor.
+static void ShowExampleAppPropertyEditor(bool* p_open, ImGuiDemoWindowData* demo_data)
{
ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Example: Property editor", p_open))
@@ -7871,25 +9109,11 @@ static void ShowExampleAppPropertyEditor(bool* p_open)
}
IMGUI_DEMO_MARKER("Examples/Property Editor");
- HelpMarker(
- "This example shows how you may implement a property editor using two columns.\n"
- "All objects/fields data are dummies here.\n");
+ static ExampleAppPropertyEditor property_editor;
+ if (demo_data->DemoTree == NULL)
+ demo_data->DemoTree = ExampleTree_CreateDemoTree();
+ property_editor.Draw(demo_data->DemoTree);
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
- if (ImGui::BeginTable("##split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
- {
- ImGui::TableSetupScrollFreeze(0, 1);
- ImGui::TableSetupColumn("Object");
- ImGui::TableSetupColumn("Contents");
- ImGui::TableHeadersRow();
-
- // Iterate placeholder objects (all the same data)
- for (int obj_i = 0; obj_i < 4; obj_i++)
- ShowPlaceholderObject("Object", obj_i);
-
- ImGui::EndTable();
- }
- ImGui::PopStyleVar();
ImGui::End();
}
@@ -8384,7 +9608,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
// To use a child window instead we could use, e.g:
// ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0)); // Disable padding
// ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(50, 50, 50, 255)); // Set a background color
- // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Border, ImGuiWindowFlags_NoMove);
+ // ImGui::BeginChild("canvas", ImVec2(0.0f, 0.0f), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove);
// ImGui::PopStyleColor();
// ImGui::PopStyleVar();
// [...]
@@ -8863,6 +10087,7 @@ void ShowExampleAppDocuments(bool* p_open)
if (opt_target == Target_Tab)
{
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
+ tab_bar_flags |= ImGuiTabBarFlags_DrawSelectedOverline;
if (ImGui::BeginTabBar("##tabs", tab_bar_flags))
{
if (opt_reorderable)
@@ -9037,6 +10262,404 @@ void ShowExampleAppDocuments(bool* p_open)
ImGui::End();
}
+//-----------------------------------------------------------------------------
+// [SECTION] Example App: Assets Browser / ShowExampleAppAssetsBrowser()
+//-----------------------------------------------------------------------------
+
+//#include "imgui_internal.h" // NavMoveRequestTryWrapping()
+
+struct ExampleAsset
+{
+ ImGuiID ID;
+ int Type;
+
+ ExampleAsset(ImGuiID id, int type) { ID = id; Type = type; }
+
+ static const ImGuiTableSortSpecs* s_current_sort_specs;
+
+ static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, ExampleAsset* items, int items_count)
+ {
+ s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
+ if (items_count > 1)
+ qsort(items, (size_t)items_count, sizeof(items[0]), ExampleAsset::CompareWithSortSpecs);
+ s_current_sort_specs = NULL;
+ }
+
+ // Compare function to be used by qsort()
+ static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
+ {
+ const ExampleAsset* a = (const ExampleAsset*)lhs;
+ const ExampleAsset* b = (const ExampleAsset*)rhs;
+ for (int n = 0; n < s_current_sort_specs->SpecsCount; n++)
+ {
+ const ImGuiTableColumnSortSpecs* sort_spec = &s_current_sort_specs->Specs[n];
+ int delta = 0;
+ if (sort_spec->ColumnIndex == 0)
+ delta = ((int)a->ID - (int)b->ID);
+ else if (sort_spec->ColumnIndex == 1)
+ delta = (a->Type - b->Type);
+ if (delta > 0)
+ return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? +1 : -1;
+ if (delta < 0)
+ return (sort_spec->SortDirection == ImGuiSortDirection_Ascending) ? -1 : +1;
+ }
+ return ((int)a->ID - (int)b->ID);
+ }
+};
+const ImGuiTableSortSpecs* ExampleAsset::s_current_sort_specs = NULL;
+
+struct ExampleAssetsBrowser
+{
+ // Options
+ bool ShowTypeOverlay = true;
+ bool AllowSorting = true;
+ bool AllowDragUnselected = false;
+ bool AllowBoxSelect = true;
+ float IconSize = 32.0f;
+ int IconSpacing = 10;
+ int IconHitSpacing = 4; // Increase hit-spacing if you want to make it possible to clear or box-select from gaps. Some spacing is required to able to amend with Shift+box-select. Value is small in Explorer.
+ bool StretchSpacing = true;
+
+ // State
+ ImVector<ExampleAsset> Items; // Our items
+ ExampleSelectionWithDeletion Selection; // Our selection (ImGuiSelectionBasicStorage + helper funcs to handle deletion)
+ ImGuiID NextItemId = 0; // Unique identifier when creating new items
+ bool RequestDelete = false; // Deferred deletion request
+ bool RequestSort = false; // Deferred sort request
+ float ZoomWheelAccum = 0.0f; // Mouse wheel accumulator to handle smooth wheels better
+
+ // Calculated sizes for layout, output of UpdateLayoutSizes(). Could be locals but our code is simpler this way.
+ ImVec2 LayoutItemSize;
+ ImVec2 LayoutItemStep; // == LayoutItemSize + LayoutItemSpacing
+ float LayoutItemSpacing = 0.0f;
+ float LayoutSelectableSpacing = 0.0f;
+ float LayoutOuterPadding = 0.0f;
+ int LayoutColumnCount = 0;
+ int LayoutLineCount = 0;
+
+ // Functions
+ ExampleAssetsBrowser()
+ {
+ AddItems(10000);
+ }
+ void AddItems(int count)
+ {
+ if (Items.Size == 0)
+ NextItemId = 0;
+ Items.reserve(Items.Size + count);
+ for (int n = 0; n < count; n++, NextItemId++)
+ Items.push_back(ExampleAsset(NextItemId, (NextItemId % 20) < 15 ? 0 : (NextItemId % 20) < 18 ? 1 : 2));
+ RequestSort = true;
+ }
+ void ClearItems()
+ {
+ Items.clear();
+ Selection.Clear();
+ }
+
+ // Logic would be written in the main code BeginChild() and outputing to local variables.
+ // We extracted it into a function so we can call it easily from multiple places.
+ void UpdateLayoutSizes(float avail_width)
+ {
+ // Layout: when not stretching: allow extending into right-most spacing.
+ LayoutItemSpacing = (float)IconSpacing;
+ if (StretchSpacing == false)
+ avail_width += floorf(LayoutItemSpacing * 0.5f);
+
+ // Layout: calculate number of icon per line and number of lines
+ LayoutItemSize = ImVec2(floorf(IconSize), floorf(IconSize));
+ LayoutColumnCount = IM_MAX((int)(avail_width / (LayoutItemSize.x + LayoutItemSpacing)), 1);
+ LayoutLineCount = (Items.Size + LayoutColumnCount - 1) / LayoutColumnCount;
+
+ // Layout: when stretching: allocate remaining space to more spacing. Round before division, so item_spacing may be non-integer.
+ if (StretchSpacing && LayoutColumnCount > 1)
+ LayoutItemSpacing = floorf(avail_width - LayoutItemSize.x * LayoutColumnCount) / LayoutColumnCount;
+
+ LayoutItemStep = ImVec2(LayoutItemSize.x + LayoutItemSpacing, LayoutItemSize.y + LayoutItemSpacing);
+ LayoutSelectableSpacing = IM_MAX(floorf(LayoutItemSpacing) - IconHitSpacing, 0.0f);
+ LayoutOuterPadding = floorf(LayoutItemSpacing * 0.5f);
+ }
+
+ void Draw(const char* title, bool* p_open)
+ {
+ ImGui::SetNextWindowSize(ImVec2(IconSize * 25, IconSize * 15), ImGuiCond_FirstUseEver);
+ if (!ImGui::Begin(title, p_open, ImGuiWindowFlags_MenuBar))
+ {
+ ImGui::End();
+ return;
+ }
+
+ // Menu bar
+ if (ImGui::BeginMenuBar())
+ {
+ if (ImGui::BeginMenu("File"))
+ {
+ if (ImGui::MenuItem("Add 10000 items"))
+ AddItems(10000);
+ if (ImGui::MenuItem("Clear items"))
+ ClearItems();
+ ImGui::Separator();
+ if (ImGui::MenuItem("Close", NULL, false, p_open != NULL))
+ *p_open = false;
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Edit"))
+ {
+ if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
+ RequestDelete = true;
+ ImGui::EndMenu();
+ }
+ if (ImGui::BeginMenu("Options"))
+ {
+ ImGui::PushItemWidth(ImGui::GetFontSize() * 10);
+
+ ImGui::SeparatorText("Contents");
+ ImGui::Checkbox("Show Type Overlay", &ShowTypeOverlay);
+ ImGui::Checkbox("Allow Sorting", &AllowSorting);
+
+ ImGui::SeparatorText("Selection Behavior");
+ ImGui::Checkbox("Allow dragging unselected item", &AllowDragUnselected);
+ ImGui::Checkbox("Allow box-selection", &AllowBoxSelect);
+
+ ImGui::SeparatorText("Layout");
+ ImGui::SliderFloat("Icon Size", &IconSize, 16.0f, 128.0f, "%.0f");
+ ImGui::SameLine(); HelpMarker("Use CTRL+Wheel to zoom");
+ ImGui::SliderInt("Icon Spacing", &IconSpacing, 0, 32);
+ ImGui::SliderInt("Icon Hit Spacing", &IconHitSpacing, 0, 32);
+ ImGui::Checkbox("Stretch Spacing", &StretchSpacing);
+ ImGui::PopItemWidth();
+ ImGui::EndMenu();
+ }
+ ImGui::EndMenuBar();
+ }
+
+ // Show a table with ONLY one header row to showcase the idea/possibility of using this to provide a sorting UI
+ if (AllowSorting)
+ {
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
+ ImGuiTableFlags table_flags_for_sort_specs = ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Borders;
+ if (ImGui::BeginTable("for_sort_specs_only", 2, table_flags_for_sort_specs, ImVec2(0.0f, ImGui::GetFrameHeight())))
+ {
+ ImGui::TableSetupColumn("Index");
+ ImGui::TableSetupColumn("Type");
+ ImGui::TableHeadersRow();
+ if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
+ if (sort_specs->SpecsDirty || RequestSort)
+ {
+ ExampleAsset::SortWithSortSpecs(sort_specs, Items.Data, Items.Size);
+ sort_specs->SpecsDirty = RequestSort = false;
+ }
+ ImGui::EndTable();
+ }
+ ImGui::PopStyleVar();
+ }
+
+ ImGuiIO& io = ImGui::GetIO();
+ ImGui::SetNextWindowContentSize(ImVec2(0.0f, LayoutOuterPadding + LayoutLineCount * (LayoutItemSize.x + LayoutItemSpacing)));
+ if (ImGui::BeginChild("Assets", ImVec2(0.0f, -ImGui::GetTextLineHeightWithSpacing()), ImGuiChildFlags_Borders, ImGuiWindowFlags_NoMove))
+ {
+ ImDrawList* draw_list = ImGui::GetWindowDrawList();
+
+ const float avail_width = ImGui::GetContentRegionAvail().x;
+ UpdateLayoutSizes(avail_width);
+
+ // Calculate and store start position.
+ ImVec2 start_pos = ImGui::GetCursorScreenPos();
+ start_pos = ImVec2(start_pos.x + LayoutOuterPadding, start_pos.y + LayoutOuterPadding);
+ ImGui::SetCursorScreenPos(start_pos);
+
+ // Multi-select
+ ImGuiMultiSelectFlags ms_flags = ImGuiMultiSelectFlags_ClearOnEscape | ImGuiMultiSelectFlags_ClearOnClickVoid;
+
+ // - Enable box-select (in 2D mode, so that changing box-select rectangle X1/X2 boundaries will affect clipped items)
+ if (AllowBoxSelect)
+ ms_flags |= ImGuiMultiSelectFlags_BoxSelect2d;
+
+ // - This feature allows dragging an unselected item without selecting it (rarely used)
+ if (AllowDragUnselected)
+ ms_flags |= ImGuiMultiSelectFlags_SelectOnClickRelease;
+
+ // - Enable keyboard wrapping on X axis
+ // (FIXME-MULTISELECT: We haven't designed/exposed a general nav wrapping api yet, so this flag is provided as a courtesy to avoid doing:
+ // ImGui::NavMoveRequestTryWrapping(ImGui::GetCurrentWindow(), ImGuiNavMoveFlags_WrapX);
+ // When we finish implementing a more general API for this, we will obsolete this flag in favor of the new system)
+ ms_flags |= ImGuiMultiSelectFlags_NavWrapX;
+
+ ImGuiMultiSelectIO* ms_io = ImGui::BeginMultiSelect(ms_flags, Selection.Size, Items.Size);
+
+ // Use custom selection adapter: store ID in selection (recommended)
+ Selection.UserData = this;
+ Selection.AdapterIndexToStorageId = [](ImGuiSelectionBasicStorage* self_, int idx) { ExampleAssetsBrowser* self = (ExampleAssetsBrowser*)self_->UserData; return self->Items[idx].ID; };
+ Selection.ApplyRequests(ms_io);
+
+ const bool want_delete = (ImGui::Shortcut(ImGuiKey_Delete, ImGuiInputFlags_Repeat) && (Selection.Size > 0)) || RequestDelete;
+ const int item_curr_idx_to_focus = want_delete ? Selection.ApplyDeletionPreLoop(ms_io, Items.Size) : -1;
+ RequestDelete = false;
+
+ // Push LayoutSelectableSpacing (which is LayoutItemSpacing minus hit-spacing, if we decide to have hit gaps between items)
+ // Altering style ItemSpacing may seem unnecessary as we position every items using SetCursorScreenPos()...
+ // But it is necessary for two reasons:
+ // - Selectables uses it by default to visually fill the space between two items.
+ // - The vertical spacing would be measured by Clipper to calculate line height if we didn't provide it explicitly (here we do).
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(LayoutSelectableSpacing, LayoutSelectableSpacing));
+
+ // Rendering parameters
+ const ImU32 icon_type_overlay_colors[3] = { 0, IM_COL32(200, 70, 70, 255), IM_COL32(70, 170, 70, 255) };
+ const ImU32 icon_bg_color = ImGui::GetColorU32(ImGuiCol_MenuBarBg);
+ const ImVec2 icon_type_overlay_size = ImVec2(4.0f, 4.0f);
+ const bool display_label = (LayoutItemSize.x >= ImGui::CalcTextSize("999").x);
+
+ const int column_count = LayoutColumnCount;
+ ImGuiListClipper clipper;
+ clipper.Begin(LayoutLineCount, LayoutItemStep.y);
+ if (item_curr_idx_to_focus != -1)
+ clipper.IncludeItemByIndex(item_curr_idx_to_focus / column_count); // Ensure focused item line is not clipped.
+ if (ms_io->RangeSrcItem != -1)
+ clipper.IncludeItemByIndex((int)ms_io->RangeSrcItem / column_count); // Ensure RangeSrc item line is not clipped.
+ while (clipper.Step())
+ {
+ for (int line_idx = clipper.DisplayStart; line_idx < clipper.DisplayEnd; line_idx++)
+ {
+ const int item_min_idx_for_current_line = line_idx * column_count;
+ const int item_max_idx_for_current_line = IM_MIN((line_idx + 1) * column_count, Items.Size);
+ for (int item_idx = item_min_idx_for_current_line; item_idx < item_max_idx_for_current_line; ++item_idx)
+ {
+ ExampleAsset* item_data = &Items[item_idx];
+ ImGui::PushID((int)item_data->ID);
+
+ // Position item
+ ImVec2 pos = ImVec2(start_pos.x + (item_idx % column_count) * LayoutItemStep.x, start_pos.y + line_idx * LayoutItemStep.y);
+ ImGui::SetCursorScreenPos(pos);
+
+ ImGui::SetNextItemSelectionUserData(item_idx);
+ bool item_is_selected = Selection.Contains((ImGuiID)item_data->ID);
+ bool item_is_visible = ImGui::IsRectVisible(LayoutItemSize);
+ ImGui::Selectable("", item_is_selected, ImGuiSelectableFlags_None, LayoutItemSize);
+
+ // Update our selection state immediately (without waiting for EndMultiSelect() requests)
+ // because we use this to alter the color of our text/icon.
+ if (ImGui::IsItemToggledSelection())
+ item_is_selected = !item_is_selected;
+
+ // Focus (for after deletion)
+ if (item_curr_idx_to_focus == item_idx)
+ ImGui::SetKeyboardFocusHere(-1);
+
+ // Drag and drop
+ if (ImGui::BeginDragDropSource())
+ {
+ // Create payload with full selection OR single unselected item.
+ // (the later is only possible when using ImGuiMultiSelectFlags_SelectOnClickRelease)
+ if (ImGui::GetDragDropPayload() == NULL)
+ {
+ ImVector<ImGuiID> payload_items;
+ void* it = NULL;
+ ImGuiID id = 0;
+ if (!item_is_selected)
+ payload_items.push_back(item_data->ID);
+ else
+ while (Selection.GetNextSelectedItem(&it, &id))
+ payload_items.push_back(id);
+ ImGui::SetDragDropPayload("ASSETS_BROWSER_ITEMS", payload_items.Data, (size_t)payload_items.size_in_bytes());
+ }
+
+ // Display payload content in tooltip, by extracting it from the payload data
+ // (we could read from selection, but it is more correct and reusable to read from payload)
+ const ImGuiPayload* payload = ImGui::GetDragDropPayload();
+ const int payload_count = (int)payload->DataSize / (int)sizeof(ImGuiID);
+ ImGui::Text("%d assets", payload_count);
+
+ ImGui::EndDragDropSource();
+ }
+
+ // Render icon (a real app would likely display an image/thumbnail here)
+ // Because we use ImGuiMultiSelectFlags_BoxSelect2d, clipping vertical may occasionally be larger, so we coarse-clip our rendering as well.
+ if (item_is_visible)
+ {
+ ImVec2 box_min(pos.x - 1, pos.y - 1);
+ ImVec2 box_max(box_min.x + LayoutItemSize.x + 2, box_min.y + LayoutItemSize.y + 2); // Dubious
+ draw_list->AddRectFilled(box_min, box_max, icon_bg_color); // Background color
+ if (ShowTypeOverlay && item_data->Type != 0)
+ {
+ ImU32 type_col = icon_type_overlay_colors[item_data->Type % IM_ARRAYSIZE(icon_type_overlay_colors)];
+ draw_list->AddRectFilled(ImVec2(box_max.x - 2 - icon_type_overlay_size.x, box_min.y + 2), ImVec2(box_max.x - 2, box_min.y + 2 + icon_type_overlay_size.y), type_col);
+ }
+ if (display_label)
+ {
+ ImU32 label_col = ImGui::GetColorU32(item_is_selected ? ImGuiCol_Text : ImGuiCol_TextDisabled);
+ char label[32];
+ sprintf(label, "%d", item_data->ID);
+ draw_list->AddText(ImVec2(box_min.x, box_max.y - ImGui::GetFontSize()), label_col, label);
+ }
+ }
+
+ ImGui::PopID();
+ }
+ }
+ }
+ clipper.End();
+ ImGui::PopStyleVar(); // ImGuiStyleVar_ItemSpacing
+
+ // Context menu
+ if (ImGui::BeginPopupContextWindow())
+ {
+ ImGui::Text("Selection: %d items", Selection.Size);
+ ImGui::Separator();
+ if (ImGui::MenuItem("Delete", "Del", false, Selection.Size > 0))
+ RequestDelete = true;
+ ImGui::EndPopup();
+ }
+
+ ms_io = ImGui::EndMultiSelect();
+ Selection.ApplyRequests(ms_io);
+ if (want_delete)
+ Selection.ApplyDeletionPostLoop(ms_io, Items, item_curr_idx_to_focus);
+
+ // Zooming with CTRL+Wheel
+ if (ImGui::IsWindowAppearing())
+ ZoomWheelAccum = 0.0f;
+ if (ImGui::IsWindowHovered() && io.MouseWheel != 0.0f && ImGui::IsKeyDown(ImGuiMod_Ctrl) && ImGui::IsAnyItemActive() == false)
+ {
+ ZoomWheelAccum += io.MouseWheel;
+ if (fabsf(ZoomWheelAccum) >= 1.0f)
+ {
+ // Calculate hovered item index from mouse location
+ // FIXME: Locking aiming on 'hovered_item_idx' (with a cool-down timer) would ensure zoom keeps on it.
+ const float hovered_item_nx = (io.MousePos.x - start_pos.x + LayoutItemSpacing * 0.5f) / LayoutItemStep.x;
+ const float hovered_item_ny = (io.MousePos.y - start_pos.y + LayoutItemSpacing * 0.5f) / LayoutItemStep.y;
+ const int hovered_item_idx = ((int)hovered_item_ny * LayoutColumnCount) + (int)hovered_item_nx;
+ //ImGui::SetTooltip("%f,%f -> item %d", hovered_item_nx, hovered_item_ny, hovered_item_idx); // Move those 4 lines in block above for easy debugging
+
+ // Zoom
+ IconSize *= powf(1.1f, (float)(int)ZoomWheelAccum);
+ IconSize = IM_CLAMP(IconSize, 16.0f, 128.0f);
+ ZoomWheelAccum -= (int)ZoomWheelAccum;
+ UpdateLayoutSizes(avail_width);
+
+ // Manipulate scroll to that we will land at the same Y location of currently hovered item.
+ // - Calculate next frame position of item under mouse
+ // - Set new scroll position to be used in next ImGui::BeginChild() call.
+ float hovered_item_rel_pos_y = ((float)(hovered_item_idx / LayoutColumnCount) + fmodf(hovered_item_ny, 1.0f)) * LayoutItemStep.y;
+ hovered_item_rel_pos_y += ImGui::GetStyle().WindowPadding.y;
+ float mouse_local_y = io.MousePos.y - ImGui::GetWindowPos().y;
+ ImGui::SetScrollY(hovered_item_rel_pos_y - mouse_local_y);
+ }
+ }
+ }
+ ImGui::EndChild();
+
+ ImGui::Text("Selected: %d/%d items", Selection.Size, Items.Size);
+ ImGui::End();
+ }
+};
+
+void ShowExampleAppAssetsBrowser(bool* p_open)
+{
+ IMGUI_DEMO_MARKER("Examples/Assets Browser");
+ static ExampleAssetsBrowser assets_browser;
+ assets_browser.Draw("Example: Assets Browser", p_open);
+}
+
// End of Demo code
#else
diff --git a/backends/imgui/imgui_draw.cpp b/backends/imgui/imgui_draw.cpp
index 393f417df47..acd633ebfb2 100644
--- a/backends/imgui/imgui_draw.cpp
+++ b/backends/imgui/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.90.7 WIP
+// dear imgui, v1.91.3
// (drawing and font code)
/*
@@ -211,11 +211,13 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
- colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
- colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
- colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
- colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
+ colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
+ colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
+ colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
+ colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
@@ -227,6 +229,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_TableBorderLight] = ImVec4(0.23f, 0.23f, 0.25f, 1.00f); // Prefer using Alpha=1.0 here
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.06f);
+ colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
@@ -273,11 +276,13 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
- colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
- colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
- colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
- colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
+ colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
+ colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
+ colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
+ colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_TabDimmedSelectedOverline] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f);
@@ -289,6 +294,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_TableBorderLight] = ImVec4(0.26f, 0.26f, 0.28f, 1.00f); // Prefer using Alpha=1.0 here
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(1.00f, 1.00f, 1.00f, 0.07f);
+ colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f);
colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
@@ -336,11 +342,13 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
- colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
- colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
- colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
- colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
+ colors[ImGuiCol_TabSelected] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
+ colors[ImGuiCol_TabSelectedOverline] = colors[ImGuiCol_HeaderActive];
+ colors[ImGuiCol_TabDimmed] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
+ colors[ImGuiCol_TabDimmedSelected] = ImLerp(colors[ImGuiCol_TabSelected], colors[ImGuiCol_TitleBg], 0.40f);
+ colors[ImGuiCol_TabDimmedSelectedOverline] = ImVec4(0.26f, 0.59f, 1.00f, 1.00f);
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
colors[ImGuiCol_DockingEmptyBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
@@ -352,6 +360,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_TableBorderLight] = ImVec4(0.68f, 0.68f, 0.74f, 1.00f); // Prefer using Alpha=1.0 here
colors[ImGuiCol_TableRowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_TableRowBgAlt] = ImVec4(0.30f, 0.30f, 0.30f, 0.09f);
+ colors[ImGuiCol_TextLink] = colors[ImGuiCol_HeaderActive];
colors[ImGuiCol_TextSelectedBg] = ImVec4(0.26f, 0.59f, 0.98f, 0.35f);
colors[ImGuiCol_DragDropTarget] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_NavHighlight] = colors[ImGuiCol_HeaderHovered];
@@ -523,7 +532,6 @@ void ImDrawList::_OnChangedClipRect()
CmdBuffer.pop_back();
return;
}
-
curr_cmd->ClipRect = _CmdHeader.ClipRect;
}
@@ -546,7 +554,6 @@ void ImDrawList::_OnChangedTextureID()
CmdBuffer.pop_back();
return;
}
-
curr_cmd->TextureId = _CmdHeader.TextureId;
}
@@ -622,6 +629,15 @@ void ImDrawList::PopTextureID()
_OnChangedTextureID();
}
+// This is used by ImGui::PushFont()/PopFont(). It works because we never use _TextureIdStack[] elsewhere than in PushTextureID()/PopTextureID().
+void ImDrawList::_SetTextureID(ImTextureID texture_id)
+{
+ if (_CmdHeader.TextureId == texture_id)
+ return;
+ _CmdHeader.TextureId = texture_id;
+ _OnChangedTextureID();
+}
+
// Reserve space for a number of vertices and indices.
// You must finish filling your reserved data before calling PrimReserve() again, as it may reallocate or
// submit the intermediate results. PrimUnreserve() can be used to release unused allocations.
@@ -2489,13 +2505,14 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
{
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
IM_ASSERT(font_cfg->FontData != NULL && font_cfg->FontDataSize > 0);
- IM_ASSERT(font_cfg->SizePixels > 0.0f);
+ IM_ASSERT(font_cfg->SizePixels > 0.0f && "Is ImFontConfig struct correctly initialized?");
+ IM_ASSERT(font_cfg->OversampleH > 0 && font_cfg->OversampleV > 0 && "Is ImFontConfig struct correctly initialized?");
// Create new font
if (!font_cfg->MergeMode)
Fonts.push_back(IM_NEW(ImFont));
else
- IM_ASSERT(!Fonts.empty() && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
+ IM_ASSERT(Fonts.Size > 0 && "Cannot use MergeMode for the first font"); // When using MergeMode make sure that a font has already been added before. You can use ImGui::GetIO().Fonts->AddFontDefault() to add the default imgui font.
ConfigData.push_back(*font_cfg);
ImFontConfig& new_font_cfg = ConfigData.back();
@@ -2812,8 +2829,9 @@ static bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
for (const ImWchar* src_range = src_tmp.SrcRanges; src_range[0] && src_range[1]; src_range += 2)
{
// Check for valid range. This may also help detect *some* dangling pointers, because a common
- // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent.
- IM_ASSERT(src_range[0] <= src_range[1]);
+ // user error is to setup ImFontConfig::GlyphRanges with a pointer to data that isn't persistent,
+ // or to forget to zero-terminate the glyph range array.
+ IM_ASSERT(src_range[0] <= src_range[1] && "Invalid range: is your glyph range array persistent? it is zero-terminated?");
src_tmp.GlyphsHighest = ImMax(src_tmp.GlyphsHighest, (int)src_range[1]);
}
dst_tmp.SrcCount++;
diff --git a/backends/imgui/imgui_internal.h b/backends/imgui/imgui_internal.h
index a2c59370941..17651d44f4f 100644
--- a/backends/imgui/imgui_internal.h
+++ b/backends/imgui/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.90.7 WIP
+// dear imgui, v1.91.3
// (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@@ -14,19 +14,21 @@ Index of this file:
// [SECTION] Macros
// [SECTION] Generic helpers
// [SECTION] ImDrawList support
-// [SECTION] Widgets support: flags, enums, data structures
// [SECTION] Data types support
+// [SECTION] Widgets support: flags, enums, data structures
// [SECTION] Popup support
// [SECTION] Inputs support
// [SECTION] Clipper support
// [SECTION] Navigation support
// [SECTION] Typing-select support
// [SECTION] Columns support
+// [SECTION] Box-select support
// [SECTION] Multi-select support
// [SECTION] Docking support
// [SECTION] Viewport support
// [SECTION] Settings support
// [SECTION] Localization support
+// [SECTION] Error handling, State recovery support
// [SECTION] Metrics, Debug tools
// [SECTION] Generic context hooks
// [SECTION] ImGuiContext (main imgui context)
@@ -124,6 +126,7 @@ struct ImBitVector; // Store 1-bit per value
struct ImRect; // An axis-aligned rectangle (2 points)
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
struct ImDrawListSharedData; // Data shared between all ImDrawList instances
+struct ImGuiBoxSelectState; // Box-selection state (currently used by multi-selection, could potentially be used by others)
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
struct ImGuiContext; // Main Dear ImGui context
struct ImGuiContextHook; // Hook for extensions like ImGuiTestEngine
@@ -133,14 +136,16 @@ struct ImGuiDockContext; // Docking system context
struct ImGuiDockRequest; // Docking system dock/undock queued request
struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes)
struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session)
+struct ImGuiErrorRecoveryState; // Storage of stack sizes for error handling and recovery
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
struct ImGuiInputTextDeactivateData;// Short term storage to backup text of a deactivating InputText() while another is stealing active id
struct ImGuiLastItemData; // Status storage for last submitted items
struct ImGuiLocEntry; // A localization entry.
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
+struct ImGuiMultiSelectState; // Multi-selection persistent state (for focused selection).
+struct ImGuiMultiSelectTempData; // Multi-selection temporary state (while traversing).
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
-struct ImGuiNavTreeNodeData; // Temporary storage for last TreeNode() being a Left arrow landing candidate.
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
struct ImGuiNextItemData; // Storage for SetNextItem** functions
@@ -148,7 +153,6 @@ struct ImGuiOldColumnData; // Storage data for a single column for lega
struct ImGuiOldColumns; // Storage data for a columns set for legacy Columns() api
struct ImGuiPopupData; // Storage for current popup stack
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
-struct ImGuiStackSizes; // Storage of stack sizes for debugging/asserting
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
struct ImGuiTabBar; // Storage for a tab bar
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
@@ -159,6 +163,7 @@ struct ImGuiTableInstanceData; // Storage for one instance of a same table
struct ImGuiTableTempData; // Temporary storage for one table (one per table in the stack), shared between tables.
struct ImGuiTableSettings; // Storage for a table .ini settings
struct ImGuiTableColumnsSettings; // Storage for a column .ini settings
+struct ImGuiTreeNodeStackData; // Temporary storage for TreeNode().
struct ImGuiTypingSelectState; // Storage for GetTypingSelectRequest()
struct ImGuiTypingSelectRequest; // Storage for GetTypingSelectRequest() (aimed to be public)
struct ImGuiWindow; // Storage for one window
@@ -175,8 +180,7 @@ typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // E
// Flags
typedef int ImGuiActivateFlags; // -> enum ImGuiActivateFlags_ // Flags: for navigation/focus function (will be for ActivateItem() later)
typedef int ImGuiDebugLogFlags; // -> enum ImGuiDebugLogFlags_ // Flags: for ShowDebugLogWindow(), g.DebugLogFlags
-typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow();
-typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag(), g.LastItemData.InFlags
+typedef int ImGuiFocusRequestFlags; // -> enum ImGuiFocusRequestFlags_ // Flags: for FocusWindow()
typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for g.LastItemData.StatusFlags
typedef int ImGuiOldColumnFlags; // -> enum ImGuiOldColumnFlags_ // Flags: for BeginColumns()
typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
@@ -190,8 +194,6 @@ typedef int ImGuiTooltipFlags; // -> enum ImGuiTooltipFlags_ // F
typedef int ImGuiTypingSelectFlags; // -> enum ImGuiTypingSelectFlags_ // Flags: for GetTypingSelectRequest()
typedef int ImGuiWindowRefreshFlags; // -> enum ImGuiWindowRefreshFlags_ // Flags: for SetNextWindowRefreshPolicy()
-typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...);
-
//-----------------------------------------------------------------------------
// [SECTION] Context pointer
// See implementation of this variable in imgui.cpp for comments and details.
@@ -201,24 +203,6 @@ typedef void (*ImGuiErrorLogCallback)(void* user_data, const char* fmt, ...);
extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#endif
-//-------------------------------------------------------------------------
-// [SECTION] STB libraries includes
-//-------------------------------------------------------------------------
-
-namespace ImStb
-{
-
-#undef IMSTB_TEXTEDIT_STRING
-#undef IMSTB_TEXTEDIT_CHARTYPE
-#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState
-#define IMSTB_TEXTEDIT_CHARTYPE ImWchar
-#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f)
-#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
-#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
-#include "imstb_textedit.h"
-
-} // namespace ImStb
-
//-----------------------------------------------------------------------------
// [SECTION] Macros
//-----------------------------------------------------------------------------
@@ -242,6 +226,7 @@ namespace ImStb
#else
#define IMGUI_DEBUG_LOG(...) ((void)0)
#endif
+#define IMGUI_DEBUG_LOG_ERROR(...) do { ImGuiContext& g2 = *GImGui; if (g2.DebugLogFlags & ImGuiDebugLogFlags_EventError) IMGUI_DEBUG_LOG(__VA_ARGS__); else g2.DebugLogSkippedErrors++; } while (0)
#define IMGUI_DEBUG_LOG_ACTIVEID(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventActiveId) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
#define IMGUI_DEBUG_LOG_FOCUS(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventFocus) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
#define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0)
@@ -265,12 +250,6 @@ namespace ImStb
#define IM_ASSERT_PARANOID(_EXPR)
#endif
-// Error handling
-// Down the line in some frameworks/languages we would like to have a way to redirect those to the programmer and recover from more faults.
-#ifndef IM_ASSERT_USER_ERROR
-#define IM_ASSERT_USER_ERROR(_EXP,_MSG) IM_ASSERT((_EXP) && _MSG) // Recoverable User Error
-#endif
-
// Misc Macros
#define IM_PI 3.14159265358979323846f
#ifdef _WIN32
@@ -360,6 +339,7 @@ namespace ImStb
// - Helper: ImPool<>
// - Helper: ImChunkStream<>
// - Helper: ImGuiTextIndex
+// - Helper: ImGuiStorage
//-----------------------------------------------------------------------------
// Helpers: Hashing
@@ -391,11 +371,12 @@ IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end
IMGUI_API void ImStrTrimBlanks(char* str); // Remove leading and trailing blanks from a buffer.
IMGUI_API const char* ImStrSkipBlank(const char* str); // Find first non-blank character.
IMGUI_API int ImStrlenW(const ImWchar* str); // Computer string length (ImWchar string)
-IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line (ImWchar string)
+IMGUI_API const char* ImStrbol(const char* buf_mid_line, const char* buf_begin); // Find beginning-of-line
IM_MSVC_RUNTIME_CHECKS_OFF
static inline char ImToUpper(char c) { return (c >= 'a' && c <= 'z') ? c &= ~32 : c; }
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
+static inline bool ImCharIsXdigitA(char c) { return (c >= '0' && c <= '9') || (c >= 'A' && c <= 'F') || (c >= 'a' && c <= 'f'); }
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helpers: Formatting
@@ -484,7 +465,7 @@ template<typename T> static inline T ImSubClampOverflow(T a, T b, T mn, T mx)
// - Misc maths helpers
static inline ImVec2 ImMin(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x < rhs.x ? lhs.x : rhs.x, lhs.y < rhs.y ? lhs.y : rhs.y); }
static inline ImVec2 ImMax(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x >= rhs.x ? lhs.x : rhs.x, lhs.y >= rhs.y ? lhs.y : rhs.y); }
-static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2& mn, ImVec2 mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }
+static inline ImVec2 ImClamp(const ImVec2& v, const ImVec2&mn, const ImVec2&mx) { return ImVec2((v.x < mn.x) ? mn.x : (v.x > mx.x) ? mx.x : v.x, (v.y < mn.y) ? mn.y : (v.y > mx.y) ? mx.y : v.y); }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, float t) { return ImVec2(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t); }
static inline ImVec2 ImLerp(const ImVec2& a, const ImVec2& b, const ImVec2& t) { return ImVec2(a.x + (b.x - a.x) * t.x, a.y + (b.y - a.y) * t.y); }
static inline ImVec4 ImLerp(const ImVec4& a, const ImVec4& b, float t) { return ImVec4(a.x + (b.x - a.x) * t, a.y + (b.y - a.y) * t, a.z + (b.z - a.z) * t, a.w + (b.w - a.w) * t); }
@@ -500,6 +481,7 @@ static inline int ImModPositive(int a, int b)
static inline float ImDot(const ImVec2& a, const ImVec2& b) { return a.x * b.x + a.y * b.y; }
static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a) { return ImVec2(v.x * cos_a - v.y * sin_a, v.x * sin_a + v.y * cos_a); }
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
+static inline float ImLinearRemapClamp(float s0, float s1, float d0, float d1, float x) { return ImSaturate((x - s0) / (s1 - s0)) * (d1 - d0) + d0; }
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
static inline bool ImIsFloatAboveGuaranteedIntegerPrecision(float f) { return f <= -16777216 || f >= 16777216; }
static inline float ImExponentialMovingAverage(float avg, float sample, int n) { avg -= avg / n; avg += sample / n; return avg; }
@@ -734,7 +716,7 @@ struct ImChunkStream
void swap(ImChunkStream<T>& rhs) { rhs.Buf.swap(Buf); }
};
-// Helper: ImGuiTextIndex<>
+// Helper: ImGuiTextIndex
// Maintain a line index for a text buffer. This is a strong candidate to be moved into the public API.
struct ImGuiTextIndex
{
@@ -748,6 +730,8 @@ struct ImGuiTextIndex
void append(const char* base, int old_size, int new_size);
};
+// Helper: ImGuiStorage
+IMGUI_API ImGuiStoragePair* ImLowerBound(ImGuiStoragePair* in_begin, ImGuiStoragePair* in_end, ImGuiID key);
//-----------------------------------------------------------------------------
// [SECTION] ImDrawList support
//-----------------------------------------------------------------------------
@@ -784,6 +768,7 @@ struct IMGUI_API ImDrawListSharedData
ImVec2 TexUvWhitePixel; // UV of white pixel in the atlas
ImFont* Font; // Current/default font (optional, for simplified AddText overload)
float FontSize; // Current/default font size (optional, for simplified AddText overload)
+ float FontScale; // Current/default font scale (== FontSize / Font->FontSize)
float CurveTessellationTol; // Tessellation tolerance when using PathBezierCurveTo()
float CircleSegmentMaxError; // Number of circle segments to use per pixel of radius for AddCircle() etc
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
@@ -810,33 +795,65 @@ struct ImDrawDataBuilder
ImDrawDataBuilder() { memset(this, 0, sizeof(*this)); }
};
+//-----------------------------------------------------------------------------
+// [SECTION] Data types support
+//-----------------------------------------------------------------------------
+
+struct ImGuiDataVarInfo
+{
+ ImGuiDataType Type;
+ ImU32 Count; // 1+
+ ImU32 Offset; // Offset in parent structure
+ void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
+};
+
+struct ImGuiDataTypeStorage
+{
+ ImU8 Data[8]; // Opaque storage to fit any data up to ImGuiDataType_COUNT
+};
+
+// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
+struct ImGuiDataTypeInfo
+{
+ size_t Size; // Size in bytes
+ const char* Name; // Short descriptive name for the type, for debugging
+ const char* PrintFmt; // Default printf format for the type
+ const char* ScanFmt; // Default scanf format for the type
+};
+
+// Extend ImGuiDataType_
+enum ImGuiDataTypePrivate_
+{
+ ImGuiDataType_String = ImGuiDataType_COUNT + 1,
+ ImGuiDataType_Pointer,
+ ImGuiDataType_ID,
+};
+
//-----------------------------------------------------------------------------
// [SECTION] Widgets support: flags, enums, data structures
//-----------------------------------------------------------------------------
-// Flags used by upcoming items
+// Extend ImGuiItemFlags
// - input: PushItemFlag() manipulates g.CurrentItemFlags, ItemAdd() calls may add extra flags.
// - output: stored in g.LastItemData.InFlags
-// Current window shared by all windows.
-// This is going to be exposed in imgui.h when stabilized enough.
-enum ImGuiItemFlags_
+enum ImGuiItemFlagsPrivate_
{
// Controlled by user
- ImGuiItemFlags_None = 0,
- ImGuiItemFlags_NoTabStop = 1 << 0, // false // Disable keyboard tabbing. This is a "lighter" version of ImGuiItemFlags_NoNav.
- ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
- ImGuiItemFlags_Disabled = 1 << 2, // false // Disable interactions but doesn't affect visuals. See BeginDisabled()/EndDisabled(). See github.com/ocornut/imgui/issues/211
- ImGuiItemFlags_NoNav = 1 << 3, // false // Disable any form of focusing (keyboard/gamepad directional navigation and SetKeyboardFocusHere() calls)
- ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false // Disable item being a candidate for default focus (e.g. used by title bar items)
- ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // Disable MenuItem/Selectable() automatically closing their popup window
- ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
- ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
- ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable()
- ImGuiItemFlags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.
+ ImGuiItemFlags_Disabled = 1 << 10, // false // Disable interactions (DOES NOT affect visuals. DO NOT mix direct use of this with BeginDisabled(). See BeginDisabled()/EndDisabled() for full disable feature, and github #211).
+ ImGuiItemFlags_ReadOnly = 1 << 11, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
+ ImGuiItemFlags_MixedValue = 1 << 12, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
+ ImGuiItemFlags_NoWindowHoverableCheck = 1 << 13, // false // Disable hoverable check in ItemHoverable()
+ ImGuiItemFlags_AllowOverlap = 1 << 14, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.
// Controlled by widget code
- ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
- ImGuiItemFlags_HasSelectionUserData = 1 << 11, // false // Set by SetNextItemSelectionUserData()
+ ImGuiItemFlags_Inputable = 1 << 20, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
+ ImGuiItemFlags_HasSelectionUserData = 1 << 21, // false // Set by SetNextItemSelectionUserData()
+ ImGuiItemFlags_IsMultiSelect = 1 << 22, // false // Set by SetNextItemSelectionUserData()
+
+ ImGuiItemFlags_Default_ = ImGuiItemFlags_AutoClosePopups, // Please don't change, use PushItemFlag() instead.
+
+ // Obsolete
+ //ImGuiItemFlags_SelectableDontClosePopup = !ImGuiItemFlags_AutoClosePopups, // Can't have a redirect as we inverted the behavior
};
// Status flags for an already submitted item
@@ -939,8 +956,9 @@ enum ImGuiSelectableFlagsPrivate_
// Extend ImGuiTreeNodeFlags_
enum ImGuiTreeNodeFlagsPrivate_
{
- ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20,
- ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 21,// (FIXME-WIP) Turn Down arrow into an Up arrow, but reversed trees (#6517)
+ ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 28,// FIXME-WIP: Hard-coded for CollapsingHeader()
+ ImGuiTreeNodeFlags_UpsideDownArrow = 1 << 29,// FIXME-WIP: Turn Down arrow into an Up arrow, but reversed trees (#6517)
+ ImGuiTreeNodeFlags_OpenOnMask_ = ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_OpenOnArrow,
};
enum ImGuiSeparatorFlags_
@@ -1079,20 +1097,31 @@ struct IMGUI_API ImGuiInputTextDeactivatedState
ImGuiInputTextDeactivatedState() { memset(this, 0, sizeof(*this)); }
void ClearFreeMemory() { ID = 0; TextA.clear(); }
};
+
+// Forward declare imstb_textedit.h structure + make its main configuration define accessible
+#undef IMSTB_TEXTEDIT_STRING
+#undef IMSTB_TEXTEDIT_CHARTYPE
+#define IMSTB_TEXTEDIT_STRING ImGuiInputTextState
+#define IMSTB_TEXTEDIT_CHARTYPE char
+#define IMSTB_TEXTEDIT_GETWIDTH_NEWLINE (-1.0f)
+#define IMSTB_TEXTEDIT_UNDOSTATECOUNT 99
+#define IMSTB_TEXTEDIT_UNDOCHARCOUNT 999
+namespace ImStb { struct STB_TexteditState; }
+typedef ImStb::STB_TexteditState ImStbTexteditState;
+
// Internal state of the currently focused/edited text input box
// For a given item ID, access with ImGui::GetInputTextState()
struct IMGUI_API ImGuiInputTextState
{
ImGuiContext* Ctx; // parent UI context (needs to be set explicitly by parent).
+ ImStbTexteditState* Stb; // State for stb_textedit.h
ImGuiID ID; // widget id owning the text state
- int CurLenW, CurLenA; // we need to maintain our buffer length in both UTF-8 and wchar format. UTF-8 length is valid even if TextA is not.
- ImVector<ImWchar> TextW; // edit buffer, we need to persist but can't guarantee the persistence of the user-provided buffer. so we copy into own buffer.
- ImVector<char> TextA; // temporary UTF8 buffer for callbacks and other operations. this is not updated in every code-path! size=capacity.
+ int CurLenA; // UTF-8 length of the string in TextA (in bytes)
+ ImVector<char> TextA; // main UTF8 buffer.
ImVector<char> InitialTextA; // value to revert to when pressing Escape = backup of end-user buffer at the time of focus (in UTF-8, unaltered)
- bool TextAIsValid; // temporary UTF8 buffer is not initially valid before we make the widget active (until then we pull the data from user argument)
+ ImVector<char> CallbackTextBackup; // temporary storage for callback to support automatic reconcile of undo-stack
int BufCapacityA; // end-user buffer capacity
- float ScrollX; // horizontal scrolling/offset
- ImStb::STB_TexteditState Stb; // state for stb_textedit.h
+ ImVec2 Scroll; // horizontal offset (managed manually) + vertical scrolling (pulled from child window's own Scroll.y)
float CursorAnim; // timer for cursor blink, reset on every user action so the cursor reappears immediately
bool CursorFollow; // set when we want scrolling to follow the current cursor position (not always!)
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
@@ -1102,32 +1131,31 @@ struct IMGUI_API ImGuiInputTextState
int ReloadSelectionStart; // POSITIONS ARE IN IMWCHAR units *NOT* UTF-8 this is why this is not exposed yet.
int ReloadSelectionEnd;
- ImGuiInputTextState() { memset(this, 0, sizeof(*this)); }
- void ClearText() { CurLenW = CurLenA = 0; TextW[0] = 0; TextA[0] = 0; CursorClamp(); }
- void ClearFreeMemory() { TextW.clear(); TextA.clear(); InitialTextA.clear(); }
- int GetUndoAvailCount() const { return Stb.undostate.undo_point; }
- int GetRedoAvailCount() const { return IMSTB_TEXTEDIT_UNDOSTATECOUNT - Stb.undostate.redo_point; }
+ ImGuiInputTextState();
+ ~ImGuiInputTextState();
+ void ClearText() { CurLenA = 0; TextA[0] = 0; CursorClamp(); }
+ void ClearFreeMemory() { TextA.clear(); InitialTextA.clear(); }
void OnKeyPressed(int key); // Cannot be inline because we call in code in stb_textedit.h implementation
+ void OnCharPressed(unsigned int c);
// Cursor & Selection
- void CursorAnimReset() { CursorAnim = -0.30f; } // After a user-input the cursor stays on for a while without blinking
- void CursorClamp() { Stb.cursor = ImMin(Stb.cursor, CurLenW); Stb.select_start = ImMin(Stb.select_start, CurLenW); Stb.select_end = ImMin(Stb.select_end, CurLenW); }
- bool HasSelection() const { return Stb.select_start != Stb.select_end; }
- void ClearSelection() { Stb.select_start = Stb.select_end = Stb.cursor; }
- int GetCursorPos() const { return Stb.cursor; }
- int GetSelectionStart() const { return Stb.select_start; }
- int GetSelectionEnd() const { return Stb.select_end; }
- void SelectAll() { Stb.select_start = 0; Stb.cursor = Stb.select_end = CurLenW; Stb.has_preferred_x = 0; }
+ void CursorAnimReset();
+ void CursorClamp();
+ bool HasSelection() const;
+ void ClearSelection();
+ int GetCursorPos() const;
+ int GetSelectionStart() const;
+ int GetSelectionEnd() const;
+ void SelectAll();
// Reload user buf (WIP #2890)
// If you modify underlying user-passed const char* while active you need to call this (InputText V2 may lift this)
// strcpy(my_buf, "hello");
// if (ImGuiInputTextState* state = ImGui::GetInputTextState(id)) // id may be ImGui::GetItemID() is last item
// state->ReloadUserBufAndSelectAll();
- void ReloadUserBufAndSelectAll() { ReloadUserBuf = true; ReloadSelectionStart = 0; ReloadSelectionEnd = INT_MAX; }
- void ReloadUserBufAndKeepSelection() { ReloadUserBuf = true; ReloadSelectionStart = Stb.select_start; ReloadSelectionEnd = Stb.select_end; }
- void ReloadUserBufAndMoveToEnd() { ReloadUserBuf = true; ReloadSelectionStart = ReloadSelectionEnd = INT_MAX; }
-
+ void ReloadUserBufAndSelectAll();
+ void ReloadUserBufAndKeepSelection();
+ void ReloadUserBufAndMoveToEnd();
};
enum ImGuiWindowRefreshFlags_
@@ -1187,29 +1215,30 @@ struct ImGuiNextWindowData
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
};
-// Multi-Selection item index or identifier when using SetNextItemSelectionUserData()/BeginMultiSelect()
-// (Most users are likely to use this store an item INDEX but this may be used to store a POINTER as well.)
-typedef ImS64 ImGuiSelectionUserData;
-
enum ImGuiNextItemDataFlags_
{
ImGuiNextItemDataFlags_None = 0,
ImGuiNextItemDataFlags_HasWidth = 1 << 0,
ImGuiNextItemDataFlags_HasOpen = 1 << 1,
ImGuiNextItemDataFlags_HasShortcut = 1 << 2,
+ ImGuiNextItemDataFlags_HasRefVal = 1 << 3,
+ ImGuiNextItemDataFlags_HasStorageID = 1 << 4,
};
struct ImGuiNextItemData
{
ImGuiNextItemDataFlags Flags;
- ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap.
+ ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap and ImGuiItemFlags_HasSelectionUserData.
// Non-flags members are NOT cleared by ItemAdd() meaning they are still valid during NavProcessItem()
+ ImGuiID FocusScopeId; // Set by SetNextItemSelectionUserData()
ImGuiSelectionUserData SelectionUserData; // Set by SetNextItemSelectionUserData() (note that NULL/0 is a valid value, we use -1 == ImGuiSelectionUserData_Invalid to mark invalid values)
float Width; // Set by SetNextItemWidth()
ImGuiKeyChord Shortcut; // Set by SetNextItemShortcut()
ImGuiInputFlags ShortcutFlags; // Set by SetNextItemShortcut()
bool OpenVal; // Set by SetNextItemOpen()
- ImGuiCond OpenCond : 8;
+ ImU8 OpenCond; // Set by SetNextItemOpen()
+ ImGuiDataTypeStorage RefVal; // Not exposed yet, for ImGuiInputTextFlags_ParseEmptyAsRefVal
+ ImGuiID StorageId; // Set by SetNextItemStorageID()
ImGuiNextItemData() { memset(this, 0, sizeof(*this)); SelectionUserData = -1; }
inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; ItemFlags = ImGuiItemFlags_None; } // Also cleared manually by ItemAdd()!
@@ -1231,19 +1260,24 @@ struct ImGuiLastItemData
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
};
-// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere.
-// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop()
-// Only stored when the node is a potential candidate for landing on a Left arrow jump.
-struct ImGuiNavTreeNodeData
+// Store data emitted by TreeNode() for usage by TreePop()
+// - To implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere: store the minimum amount of data
+// which we can't infer in TreePop(), to perform the equivalent of NavApplyItemToResult().
+// Only stored when the node is a potential candidate for landing on a Left arrow jump.
+struct ImGuiTreeNodeStackData
{
ImGuiID ID;
- ImGuiItemFlags InFlags;
- ImRect NavRect;
+ ImGuiTreeNodeFlags TreeFlags;
+ ImGuiItemFlags InFlags; // Used for nav landing
+ ImRect NavRect; // Used for nav landing
};
-struct IMGUI_API ImGuiStackSizes
+// sizeof() = 20
+struct IMGUI_API ImGuiErrorRecoveryState
{
+ short SizeOfWindowStack;
short SizeOfIDStack;
+ short SizeOfTreeStack;
short SizeOfColorStack;
short SizeOfStyleVarStack;
short SizeOfFontStack;
@@ -1253,17 +1287,16 @@ struct IMGUI_API ImGuiStackSizes
short SizeOfBeginPopupStack;
short SizeOfDisabledStack;
- ImGuiStackSizes() { memset(this, 0, sizeof(*this)); }
- void SetToContextState(ImGuiContext* ctx);
- void CompareWithContextState(ImGuiContext* ctx);
+ ImGuiErrorRecoveryState() { memset(this, 0, sizeof(*this)); }
};
// Data saved for each window pushed into the stack
struct ImGuiWindowStackData
{
- ImGuiWindow* Window;
- ImGuiLastItemData ParentLastItemDataBackup;
- ImGuiStackSizes StackSizesOnBegin; // Store size of various stacks for asserting
+ ImGuiWindow* Window;
+ ImGuiLastItemData ParentLastItemDataBackup;
+ ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting
+ bool DisabledOverrideReenable; // Non-child window override disabled flag
};
struct ImGuiShrinkWidthItem
@@ -1282,40 +1315,6 @@ struct ImGuiPtrOrIndex
ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }
};
-//-----------------------------------------------------------------------------
-// [SECTION] Data types support
-//-----------------------------------------------------------------------------
-
-struct ImGuiDataVarInfo
-{
- ImGuiDataType Type;
- ImU32 Count; // 1+
- ImU32 Offset; // Offset in parent structure
- void* GetVarPtr(void* parent) const { return (void*)((unsigned char*)parent + Offset); }
-};
-
-struct ImGuiDataTypeTempStorage
-{
- ImU8 Data[8]; // Can fit any data up to ImGuiDataType_COUNT
-};
-
-// Type information associated to one ImGuiDataType. Retrieve with DataTypeGetInfo().
-struct ImGuiDataTypeInfo
-{
- size_t Size; // Size in bytes
- const char* Name; // Short descriptive name for the type, for debugging
- const char* PrintFmt; // Default printf format for the type
- const char* ScanFmt; // Default scanf format for the type
-};
-
-// Extend ImGuiDataType_
-enum ImGuiDataTypePrivate_
-{
- ImGuiDataType_String = ImGuiDataType_COUNT + 1,
- ImGuiDataType_Pointer,
- ImGuiDataType_ID,
-};
-
//-----------------------------------------------------------------------------
// [SECTION] Popup support
//-----------------------------------------------------------------------------
@@ -1366,8 +1365,8 @@ typedef ImBitArray<ImGuiKey_NamedKey_COUNT, -ImGuiKey_NamedKey_BEGIN> ImBitAr
#define ImGuiKey_NavKeyboardTweakFast ImGuiMod_Shift
#define ImGuiKey_NavGamepadTweakSlow ImGuiKey_GamepadL1
#define ImGuiKey_NavGamepadTweakFast ImGuiKey_GamepadR1
-#define ImGuiKey_NavGamepadActivate ImGuiKey_GamepadFaceDown
-#define ImGuiKey_NavGamepadCancel ImGuiKey_GamepadFaceRight
+#define ImGuiKey_NavGamepadActivate (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceRight : ImGuiKey_GamepadFaceDown)
+#define ImGuiKey_NavGamepadCancel (g.IO.ConfigNavSwapGamepadButtons ? ImGuiKey_GamepadFaceDown : ImGuiKey_GamepadFaceRight)
#define ImGuiKey_NavGamepadMenu ImGuiKey_GamepadFaceLeft
#define ImGuiKey_NavGamepadInput ImGuiKey_GamepadFaceUp
@@ -1473,26 +1472,26 @@ struct ImGuiKeyOwnerData
enum ImGuiInputFlagsPrivate_
{
// Flags for IsKeyPressed(), IsKeyChordPressed(), IsMouseClicked(), Shortcut()
- // - Repeat mode
- ImGuiInputFlags_RepeatRateDefault = 1 << 1, // Repeat rate: Regular (default)
- ImGuiInputFlags_RepeatRateNavMove = 1 << 2, // Repeat rate: Fast
- ImGuiInputFlags_RepeatRateNavTweak = 1 << 3, // Repeat rate: Faster
+ // - Repeat mode: Repeat rate selection
+ ImGuiInputFlags_RepeatRateDefault = 1 << 1, // Repeat rate: Regular (default)
+ ImGuiInputFlags_RepeatRateNavMove = 1 << 2, // Repeat rate: Fast
+ ImGuiInputFlags_RepeatRateNavTweak = 1 << 3, // Repeat rate: Faster
// - Repeat mode: Specify when repeating key pressed can be interrupted.
// - In theory ImGuiInputFlags_RepeatUntilOtherKeyPress may be a desirable default, but it would break too many behavior so everything is opt-in.
- ImGuiInputFlags_RepeatUntilRelease = 1 << 4, // Stop repeating when released (default for all functions except Shortcut). This only exists to allow overriding Shortcut() default behavior.
- ImGuiInputFlags_RepeatUntilKeyModsChange = 1 << 5, // Stop repeating when released OR if keyboard mods are changed (default for Shortcut)
+ ImGuiInputFlags_RepeatUntilRelease = 1 << 4, // Stop repeating when released (default for all functions except Shortcut). This only exists to allow overriding Shortcut() default behavior.
+ ImGuiInputFlags_RepeatUntilKeyModsChange = 1 << 5, // Stop repeating when released OR if keyboard mods are changed (default for Shortcut)
ImGuiInputFlags_RepeatUntilKeyModsChangeFromNone = 1 << 6, // Stop repeating when released OR if keyboard mods are leaving the None state. Allows going from Mod+Key to Key by releasing Mod.
- ImGuiInputFlags_RepeatUntilOtherKeyPress = 1 << 7, // Stop repeating when released OR if any other keyboard key is pressed during the repeat
+ ImGuiInputFlags_RepeatUntilOtherKeyPress = 1 << 7, // Stop repeating when released OR if any other keyboard key is pressed during the repeat
// Flags for SetKeyOwner(), SetItemKeyOwner()
// - Locking key away from non-input aware code. Locking is useful to make input-owner-aware code steal keys from non-input-owner-aware code. If all code is input-owner-aware locking would never be necessary.
- ImGuiInputFlags_LockThisFrame = 1 << 20, // Further accesses to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared at end of frame.
- ImGuiInputFlags_LockUntilRelease = 1 << 21, // Further accesses to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared when the key is released or at end of each frame if key is released.
+ ImGuiInputFlags_LockThisFrame = 1 << 20, // Further accesses to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared at end of frame.
+ ImGuiInputFlags_LockUntilRelease = 1 << 21, // Further accesses to key data will require EXPLICIT owner ID (ImGuiKeyOwner_Any/0 will NOT accepted for polling). Cleared when the key is released or at end of each frame if key is released.
// - Condition for SetItemKeyOwner()
- ImGuiInputFlags_CondHovered = 1 << 22, // Only set if item is hovered (default to both)
- ImGuiInputFlags_CondActive = 1 << 23, // Only set if item is active (default to both)
- ImGuiInputFlags_CondDefault_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive,
+ ImGuiInputFlags_CondHovered = 1 << 22, // Only set if item is hovered (default to both)
+ ImGuiInputFlags_CondActive = 1 << 23, // Only set if item is active (default to both)
+ ImGuiInputFlags_CondDefault_ = ImGuiInputFlags_CondHovered | ImGuiInputFlags_CondActive,
// [Internal] Mask of which function support which flags
ImGuiInputFlags_RepeatRateMask_ = ImGuiInputFlags_RepeatRateDefault | ImGuiInputFlags_RepeatRateNavMove | ImGuiInputFlags_RepeatRateNavTweak,
@@ -1605,6 +1604,7 @@ enum ImGuiNavLayer
ImGuiNavLayer_COUNT
};
+// Storage for navigation query/results
struct ImGuiNavItemData
{
ImGuiWindow* Window; // Init,Move // Best candidate window (result->ItemWindow->RootWindowForNav == request->Window)
@@ -1615,12 +1615,13 @@ struct ImGuiNavItemData
float DistBox; // Move // Best candidate box distance to current NavId
float DistCenter; // Move // Best candidate center distance to current NavId
float DistAxial; // Move // Best candidate axial distance to current NavId
- ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionData() value.
+ ImGuiSelectionUserData SelectionUserData;//I+Mov // Best candidate SetNextItemSelectionUserData() value. Valid if (InFlags & ImGuiItemFlags_HasSelectionUserData)
ImGuiNavItemData() { Clear(); }
void Clear() { Window = NULL; ID = FocusScopeId = 0; InFlags = 0; SelectionUserData = -1; DistBox = DistCenter = DistAxial = FLT_MAX; }
};
+// Storage for PushFocusScope()
struct ImGuiFocusScopeData
{
ImGuiID ID;
@@ -1720,6 +1721,34 @@ struct ImGuiOldColumns
ImGuiOldColumns() { memset(this, 0, sizeof(*this)); }
};
+//-----------------------------------------------------------------------------
+// [SECTION] Box-select support
+//-----------------------------------------------------------------------------
+
+struct ImGuiBoxSelectState
+{
+ // Active box-selection data (persistent, 1 active at a time)
+ ImGuiID ID;
+ bool IsActive;
+ bool IsStarting;
+ bool IsStartedFromVoid; // Starting click was not from an item.
+ bool IsStartedSetNavIdOnce;
+ bool RequestClear;
+ ImGuiKeyChord KeyMods : 16; // Latched key-mods for box-select logic.
+ ImVec2 StartPosRel; // Start position in window-contents relative space (to support scrolling)
+ ImVec2 EndPosRel; // End position in window-contents relative space
+ ImVec2 ScrollAccum; // Scrolling accumulator (to behave at high-frame spaces)
+ ImGuiWindow* Window;
+
+ // Temporary/Transient data
+ bool UnclipMode; // (Temp/Transient, here in hot area). Set/cleared by the BeginMultiSelect()/EndMultiSelect() owning active box-select.
+ ImRect UnclipRect; // Rectangle where ItemAdd() clipping may be temporarily disabled. Need support by multi-select supporting widgets.
+ ImRect BoxSelectRectPrev; // Selection rectangle in absolute coordinates (derived every frame from BoxSelectStartPosRel and MousePos)
+ ImRect BoxSelectRectCurr;
+
+ ImGuiBoxSelectState() { memset(this, 0, sizeof(*this)); }
+};
+
//-----------------------------------------------------------------------------
// [SECTION] Multi-select support
//-----------------------------------------------------------------------------
@@ -1727,9 +1756,45 @@ struct ImGuiOldColumns
// We always assume that -1 is an invalid value (which works for indices and pointers)
#define ImGuiSelectionUserData_Invalid ((ImGuiSelectionUserData)-1)
-#ifdef IMGUI_HAS_MULTI_SELECT
-// <this is filled in 'range_select' branch>
-#endif // #ifdef IMGUI_HAS_MULTI_SELECT
+// Temporary storage for multi-select
+struct IMGUI_API ImGuiMultiSelectTempData
+{
+ ImGuiMultiSelectIO IO; // MUST BE FIRST FIELD. Requests are set and returned by BeginMultiSelect()/EndMultiSelect() + written to by user during the loop.
+ ImGuiMultiSelectState* Storage;
+ ImGuiID FocusScopeId; // Copied from g.CurrentFocusScopeId (unless another selection scope was pushed manually)
+ ImGuiMultiSelectFlags Flags;
+ ImVec2 ScopeRectMin;
+ ImVec2 BackupCursorMaxPos;
+ ImGuiSelectionUserData LastSubmittedItem; // Copy of last submitted item data, used to merge output ranges.
+ ImGuiID BoxSelectId;
+ ImGuiKeyChord KeyMods;
+ ImS8 LoopRequestSetAll; // -1: no operation, 0: clear all, 1: select all.
+ bool IsEndIO; // Set when switching IO from BeginMultiSelect() to EndMultiSelect() state.
+ bool IsFocused; // Set if currently focusing the selection scope (any item of the selection). May be used if you have custom shortcut associated to selection.
+ bool IsKeyboardSetRange; // Set by BeginMultiSelect() when using Shift+Navigation. Because scrolling may be affected we can't afford a frame of lag with Shift+Navigation.
+ bool NavIdPassedBy;
+ bool RangeSrcPassedBy; // Set by the item that matches RangeSrcItem.
+ bool RangeDstPassedBy; // Set by the item that matches NavJustMovedToId when IsSetRange is set.
+
+ ImGuiMultiSelectTempData() { Clear(); }
+ void Clear() { size_t io_sz = sizeof(IO); ClearIO(); memset((void*)(&IO + 1), 0, sizeof(*this) - io_sz); } // Zero-clear except IO as we preserve IO.Requests[] buffer allocation.
+ void ClearIO() { IO.Requests.resize(0); IO.RangeSrcItem = IO.NavIdItem = ImGuiSelectionUserData_Invalid; IO.NavIdSelected = IO.RangeSrcReset = false; }
+};
+
+// Persistent storage for multi-select (as long as selection is alive)
+struct IMGUI_API ImGuiMultiSelectState
+{
+ ImGuiWindow* Window;
+ ImGuiID ID;
+ int LastFrameActive; // Last used frame-count, for GC.
+ int LastSelectionSize; // Set by BeginMultiSelect() based on optional info provided by user. May be -1 if unknown.
+ ImS8 RangeSelected; // -1 (don't have) or true/false
+ ImS8 NavIdSelected; // -1 (don't have) or true/false
+ ImGuiSelectionUserData RangeSrcItem; //
+ ImGuiSelectionUserData NavIdItem; // SetNextItemSelectionUserData() value for NavId (if part of submitted items)
+
+ ImGuiMultiSelectState() { Window = NULL; ID = 0; LastFrameActive = LastSelectionSize = 0; RangeSelected = NavIdSelected = -1; RangeSrcItem = NavIdItem = ImGuiSelectionUserData_Invalid; }
+};
//-----------------------------------------------------------------------------
// [SECTION] Docking support
@@ -1763,9 +1828,10 @@ enum ImGuiDockNodeFlagsPrivate_
ImGuiDockNodeFlags_NoDocking = ImGuiDockNodeFlags_NoDockingOverMe | ImGuiDockNodeFlags_NoDockingOverOther | ImGuiDockNodeFlags_NoDockingOverEmpty | ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoDockingSplitOther,
// Masks
ImGuiDockNodeFlags_SharedFlagsInheritMask_ = ~0,
- ImGuiDockNodeFlags_NoResizeFlagsMask_ = ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY,
+ ImGuiDockNodeFlags_NoResizeFlagsMask_ = (int)ImGuiDockNodeFlags_NoResize | ImGuiDockNodeFlags_NoResizeX | ImGuiDockNodeFlags_NoResizeY,
+
// When splitting, those local flags are moved to the inheriting child, never duplicated
- ImGuiDockNodeFlags_LocalFlagsTransferMask_ = ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton,
+ ImGuiDockNodeFlags_LocalFlagsTransferMask_ = (int)ImGuiDockNodeFlags_NoDockingSplit | ImGuiDockNodeFlags_NoResizeFlagsMask_ | (int)ImGuiDockNodeFlags_AutoHideTabBar | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton,
ImGuiDockNodeFlags_SavedFlagsMask_ = ImGuiDockNodeFlags_NoResizeFlagsMask_ | ImGuiDockNodeFlags_DockSpace | ImGuiDockNodeFlags_CentralNode | ImGuiDockNodeFlags_NoTabBar | ImGuiDockNodeFlags_HiddenTabBar | ImGuiDockNodeFlags_NoWindowMenuButton | ImGuiDockNodeFlags_NoCloseButton,
};
@@ -1856,11 +1922,13 @@ struct IMGUI_API ImGuiDockNode
enum ImGuiWindowDockStyleCol
{
ImGuiWindowDockStyleCol_Text,
- ImGuiWindowDockStyleCol_Tab,
ImGuiWindowDockStyleCol_TabHovered,
- ImGuiWindowDockStyleCol_TabActive,
- ImGuiWindowDockStyleCol_TabUnfocused,
- ImGuiWindowDockStyleCol_TabUnfocusedActive,
+ ImGuiWindowDockStyleCol_TabFocused,
+ ImGuiWindowDockStyleCol_TabSelected,
+ ImGuiWindowDockStyleCol_TabSelectedOverline,
+ ImGuiWindowDockStyleCol_TabDimmed,
+ ImGuiWindowDockStyleCol_TabDimmedSelected,
+ ImGuiWindowDockStyleCol_TabDimmedSelectedOverline,
ImGuiWindowDockStyleCol_COUNT
};
@@ -1895,6 +1963,7 @@ struct ImGuiViewportP : public ImGuiViewport
int LastFocusedStampCount; // Last stamp number from when a window hosted by this viewport was focused (by comparing this value between two viewport we have an implicit viewport z-order we use as fallback)
ImGuiID LastNameHash;
ImVec2 LastPos;
+ ImVec2 LastSize;
float Alpha; // Window opacity (when dragging dockable windows/viewports we make them transparent)
float LastAlpha;
bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused.
@@ -1906,24 +1975,29 @@ struct ImGuiViewportP : public ImGuiViewport
ImVec2 LastPlatformPos;
ImVec2 LastPlatformSize;
ImVec2 LastRendererSize;
- ImVec2 WorkOffsetMin; // Work Area: Offset from Pos to top-left corner of Work Area. Generally (0,0) or (0,+main_menu_bar_height). Work Area is Full Area but without menu-bars/status-bars (so WorkArea always fit inside Pos/Size!)
- ImVec2 WorkOffsetMax; // Work Area: Offset from Pos+Size to bottom-right corner of Work Area. Generally (0,0) or (0,-status_bar_height).
- ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f.
- ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f.
+
+ // Per-viewport work area
+ // - Insets are >= 0.0f values, distance from viewport corners to work area.
+ // - BeginMainMenuBar() and DockspaceOverViewport() tend to use work area to avoid stepping over existing contents.
+ // - Generally 'safeAreaInsets' in iOS land, 'DisplayCutout' in Android land.
+ ImVec2 WorkInsetMin; // Work Area inset locked for the frame. GetWorkRect() always fits within GetMainRect().
+ ImVec2 WorkInsetMax; // "
+ ImVec2 BuildWorkInsetMin; // Work Area inset accumulator for current frame, to become next frame's WorkInset
+ ImVec2 BuildWorkInsetMax; // "
ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = LastFocusedStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
- ImVec2 CalcWorkRectPos(const ImVec2& off_min) const { return ImVec2(Pos.x + off_min.x, Pos.y + off_min.y); }
- ImVec2 CalcWorkRectSize(const ImVec2& off_min, const ImVec2& off_max) const { return ImVec2(ImMax(0.0f, Size.x - off_min.x + off_max.x), ImMax(0.0f, Size.y - off_min.y + off_max.y)); }
- void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkOffsetMin); WorkSize = CalcWorkRectSize(WorkOffsetMin, WorkOffsetMax); } // Update public fields
+ ImVec2 CalcWorkRectPos(const ImVec2& inset_min) const { return ImVec2(Pos.x + inset_min.x, Pos.y + inset_min.y); }
+ ImVec2 CalcWorkRectSize(const ImVec2& inset_min, const ImVec2& inset_max) const { return ImVec2(ImMax(0.0f, Size.x - inset_min.x - inset_max.x), ImMax(0.0f, Size.y - inset_min.y - inset_max.y)); }
+ void UpdateWorkRect() { WorkPos = CalcWorkRectPos(WorkInsetMin); WorkSize = CalcWorkRectSize(WorkInsetMin, WorkInsetMax); } // Update public fields
// Helpers to retrieve ImRect (we don't need to store BuildWorkRect as every access tend to change it, hence the code asymmetry)
ImRect GetMainRect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
ImRect GetWorkRect() const { return ImRect(WorkPos.x, WorkPos.y, WorkPos.x + WorkSize.x, WorkPos.y + WorkSize.y); }
- ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkOffsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkOffsetMin, BuildWorkOffsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
+ ImRect GetBuildWorkRect() const { ImVec2 pos = CalcWorkRectPos(BuildWorkInsetMin); ImVec2 size = CalcWorkRectSize(BuildWorkInsetMin, BuildWorkInsetMax); return ImRect(pos.x, pos.y, pos.x + size.x, pos.y + size.y); }
};
//-----------------------------------------------------------------------------
@@ -1982,6 +2056,8 @@ enum ImGuiLocKey : int
ImGuiLocKey_WindowingMainMenuBar,
ImGuiLocKey_WindowingPopup,
ImGuiLocKey_WindowingUntitled,
+ ImGuiLocKey_OpenLink_s,
+ ImGuiLocKey_CopyLink,
ImGuiLocKey_DockingHideTabBar,
ImGuiLocKey_DockingHoldShiftToDock,
ImGuiLocKey_DockingDragToUndockOrMoveNode,
@@ -1994,6 +2070,21 @@ struct ImGuiLocEntry
const char* Text;
};
+//-----------------------------------------------------------------------------
+// [SECTION] Error handling, State recovery support
+//-----------------------------------------------------------------------------
+
+// Macros used by Recoverable Error handling
+// - Only dispatch error if _EXPR: evaluate as assert (similar to an assert macro).
+// - The message will always be a string literal, in order to increase likelihood of being display by an assert handler.
+// - See 'Demo->Configuration->Error Handling' and ImGuiIO definitions for details on error handling.
+// - Read https://github.com/ocornut/imgui/wiki/Error-Handling for details on error handling.
+#ifndef IM_ASSERT_USER_ERROR
+#define IM_ASSERT_USER_ERROR(_EXPR,_MSG) do { if (!(_EXPR) && ImGui::ErrorLog(_MSG)) { IM_ASSERT((_EXPR) && _MSG); } } while (0) // Recoverable User Error
+#endif
+
+// The error callback is currently not public, as it is expected that only advanced users will rely on it.
+typedef void (*ImGuiErrorCallback)(ImGuiContext* ctx, void* user_data, const char* msg); // Function signature for g.ErrorCallback
//-----------------------------------------------------------------------------
// [SECTION] Metrics, Debug Tools
@@ -2003,18 +2094,19 @@ enum ImGuiDebugLogFlags_
{
// Event types
ImGuiDebugLogFlags_None = 0,
- ImGuiDebugLogFlags_EventActiveId = 1 << 0,
- ImGuiDebugLogFlags_EventFocus = 1 << 1,
- ImGuiDebugLogFlags_EventPopup = 1 << 2,
- ImGuiDebugLogFlags_EventNav = 1 << 3,
- ImGuiDebugLogFlags_EventClipper = 1 << 4,
- ImGuiDebugLogFlags_EventSelection = 1 << 5,
- ImGuiDebugLogFlags_EventIO = 1 << 6,
- ImGuiDebugLogFlags_EventInputRouting = 1 << 7,
- ImGuiDebugLogFlags_EventDocking = 1 << 8,
- ImGuiDebugLogFlags_EventViewport = 1 << 9,
-
- ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport,
+ ImGuiDebugLogFlags_EventError = 1 << 0, // Error submitted by IM_ASSERT_USER_ERROR()
+ ImGuiDebugLogFlags_EventActiveId = 1 << 1,
+ ImGuiDebugLogFlags_EventFocus = 1 << 2,
+ ImGuiDebugLogFlags_EventPopup = 1 << 3,
+ ImGuiDebugLogFlags_EventNav = 1 << 4,
+ ImGuiDebugLogFlags_EventClipper = 1 << 5,
+ ImGuiDebugLogFlags_EventSelection = 1 << 6,
+ ImGuiDebugLogFlags_EventIO = 1 << 7,
+ ImGuiDebugLogFlags_EventInputRouting = 1 << 8,
+ ImGuiDebugLogFlags_EventDocking = 1 << 9,
+ ImGuiDebugLogFlags_EventViewport = 1 << 10,
+
+ ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport,
ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY
ImGuiDebugLogFlags_OutputToTestEngine = 1 << 21, // Also send output to Test Engine
};
@@ -2112,6 +2204,7 @@ struct ImGuiContext
ImFont* Font; // (Shortcut) == FontStack.empty() ? IO.Font : FontStack.back()
float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
+ float FontScale; // == FontSize / Font->FontSize
float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale
ImDrawListSharedData DrawListSharedData;
double Time;
@@ -2125,6 +2218,7 @@ struct ImGuiContext
bool GcCompactAll; // Request full GC
bool TestEngineHookItems; // Will call test engine hooks: ImGuiTestEngineHook_ItemAdd(), ImGuiTestEngineHook_ItemInfo(), ImGuiTestEngineHook_Log()
void* TestEngine; // Test engine user data
+ char ContextName[16]; // Storage for a context name (to facilitate debugging multi-context setups)
// Inputs
ImVector<ImGuiInputEvent> InputEventsQueue; // Input events which will be trickled/written into IO structure.
@@ -2144,6 +2238,7 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Window being drawn into
ImGuiWindow* HoveredWindow; // Window the mouse is hovering. Will typically catch mouse inputs.
ImGuiWindow* HoveredWindowUnderMovingWindow; // Hovered window ignoring MovingWindow. Only set if MovingWindow is set.
+ ImGuiWindow* HoveredWindowBeforeClear; // Window the mouse is hovering. Filled even with _NoMouse. This is currently useful for multi-context compositors.
ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actual window that is moved is generally MovingWindow->RootWindowDockTree.
ImGuiWindow* WheelingWindow; // Track the window we started mouse-wheeling on. Until a timer elapse or mouse has moved, generally keep scrolling the same window even if during the course of scrolling the mouse ends up hovering a child window.
ImVec2 WheelingWindowRefMousePos;
@@ -2154,13 +2249,16 @@ struct ImGuiContext
ImVec2 WheelingAxisAvg;
// Item/widgets state and tracking information
+ ImGuiID DebugDrawIdConflicts; // Set when we detect multiple items with the same identifier
ImGuiID DebugHookIdInfo; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
ImGuiID HoveredId; // Hovered widget, filled during the frame
ImGuiID HoveredIdPreviousFrame;
- bool HoveredIdAllowOverlap;
- bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
+ int HoveredIdPreviousFrameItemCount; // Count numbers of items using the same ID as last frame's hovered id
float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
+ bool HoveredIdAllowOverlap;
+ bool HoveredIdIsDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
+ bool ItemUnclipByLog; // Disable ItemAdd() clipping, essentially a memory-locality friendly copy of LogEnabled
ImGuiID ActiveId; // Active widget
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
float ActiveIdTimer;
@@ -2193,11 +2291,9 @@ struct ImGuiContext
ImGuiKeyOwnerData KeysOwnerData[ImGuiKey_NamedKey_COUNT];
ImGuiKeyRoutingTable KeysRoutingTable;
ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)
- bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (FIXME: This is a shortcut for not taking ownership of 100+ keys but perhaps best to not have the inconsistency)
+ bool ActiveIdUsingAllKeyboardKeys; // Active widget will want to read all keyboard keys inputs. (this is a shortcut for not taking ownership of 100+ keys, frequently used by drag operations)
ImGuiKeyChord DebugBreakInShortcutRouting; // Set to break in SetShortcutRouting()/Shortcut() calls.
-#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
- ImU32 ActiveIdUsingNavInputMask; // If you used this. Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);'
-#endif
+ //ImU32 ActiveIdUsingNavInputMask; // [OBSOLETE] Since (IMGUI_VERSION_NUM >= 18804) : 'g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);' becomes --> 'SetKeyOwner(ImGuiKey_Escape, g.ActiveId) and/or SetKeyOwner(ImGuiKey_NavGamepadCancel, g.ActiveId);'
// Next window/item data
ImGuiID CurrentFocusScopeId; // Value for currently appending items == g.FocusScopeStack.back(). Not to be mistaken with g.NavFocusScopeId.
@@ -2218,7 +2314,7 @@ struct ImGuiContext
ImVector<ImGuiGroupData> GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin()
ImVector<ImGuiPopupData> OpenPopupStack; // Which popups are open (persistent)
ImVector<ImGuiPopupData> BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
- ImVector<ImGuiNavTreeNodeData> NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted.
+ ImVector<ImGuiTreeNodeStackData>TreeNodeStack; // Stack for TreeNode()
// Viewports
ImVector<ImGuiViewportP*> Viewports; // Active viewports (always 1+, and generally 1 unless multi-viewports are enabled). Each viewports hold their copy of ImDrawData.
@@ -2236,20 +2332,17 @@ struct ImGuiContext
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusedWindow'
ImGuiID NavId; // Focused item for navigation
ImGuiID NavFocusScopeId; // Focused focus scope (e.g. selection code often wants to "clear other items" when landing on an item of the same scope)
- ImVector<ImGuiFocusScopeData> NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain.
+ ImGuiNavLayer NavLayer; // Focused layer (main scrolling layer, or menu/title bar layer)
ImGuiID NavActivateId; // ~~ (g.ActiveId == 0) && (IsKeyPressed(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate)) ? NavId : 0, also set when calling ActivateItem()
ImGuiID NavActivateDownId; // ~~ IsKeyDown(ImGuiKey_Space) || IsKeyDown(ImGuiKey_Enter) || IsKeyDown(ImGuiKey_NavGamepadActivate) ? NavId : 0
ImGuiID NavActivatePressedId; // ~~ IsKeyPressed(ImGuiKey_Space) || IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_NavGamepadActivate) ? NavId : 0 (no repeat)
ImGuiActivateFlags NavActivateFlags;
+ ImVector<ImGuiFocusScopeData> NavFocusRoute; // Reversed copy focus scope stack for NavId (should contains NavFocusScopeId). This essentially follow the window->ParentWindowForFocusRoute chain.
ImGuiID NavHighlightActivatedId;
float NavHighlightActivatedTimer;
- ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
- ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
- ImGuiKeyChord NavJustMovedToKeyMods;
ImGuiID NavNextActivateId; // Set by ActivateItem(), queued until next frame.
ImGuiActivateFlags NavNextActivateFlags;
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS CAN ONLY BE ImGuiInputSource_Keyboard or ImGuiInputSource_Mouse
- ImGuiNavLayer NavLayer; // Layer we are navigating on. For now the system is hard-coded for 0=main contents and 1=menu/title bar, may expose layers later.
ImGuiSelectionUserData NavLastValidSelectionUserData; // Last valid data passed to SetNextItemSelectionUser(), or -1. For current window. Not reset when focusing an item that doesn't have selection data.
bool NavIdIsAlive; // Nav widget has been seen this frame ~~ NavRectRel is valid
bool NavMousePosDirty; // When set we will update mouse position if (io.ConfigFlags & ImGuiConfigFlags_NavEnableSetMousePos) if set (NB: this not enabled by default)
@@ -2280,6 +2373,14 @@ struct ImGuiContext
ImGuiNavItemData NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
ImGuiNavItemData NavTabbingResultFirst; // First tabbing request candidate within NavWindow and flattened hierarchy
+ // Navigation: record of last move request
+ ImGuiID NavJustMovedFromFocusScopeId; // Just navigated from this focus scope id (result of a successfully MoveRequest).
+ ImGuiID NavJustMovedToId; // Just navigated to this id (result of a successfully MoveRequest).
+ ImGuiID NavJustMovedToFocusScopeId; // Just navigated to this focus scope id (result of a successfully MoveRequest).
+ ImGuiKeyChord NavJustMovedToKeyMods;
+ bool NavJustMovedToIsTabbing; // Copy of ImGuiNavMoveFlags_IsTabbing. Maybe we should store whole flags.
More information about the Scummvm-git-logs
mailing list