Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/wolfpld/tracy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBartosz Taudul <wolf@nereid.pl>2022-06-21 23:18:01 +0300
committerBartosz Taudul <wolf@nereid.pl>2022-06-21 23:18:01 +0300
commit56863f5ab7b1b1757c64e7f1a08d63f36ed4ef0d (patch)
tree7e07b66e270e20dbc6011c4200fb36feab064942 /imgui/imgui.cpp
parent771c043c8ed910bde92a6803e8fdc3476c485491 (diff)
Update ImGui to 1.88 + docking.
Diffstat (limited to 'imgui/imgui.cpp')
-rw-r--r--imgui/imgui.cpp1110
1 files changed, 722 insertions, 388 deletions
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index b5fa1bf2..9f33cb17 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.87
+// dear imgui, v1.88
// (main code and documentation)
// Help:
@@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases
-// - Gallery https://github.com/ocornut/imgui/issues/4451 (please post your screenshots/video there!)
+// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues
@@ -84,6 +84,7 @@ CODE
// [SECTION] DOCKING
// [SECTION] PLATFORM DEPENDENT HELPERS
// [SECTION] METRICS/DEBUGGER WINDOW
+// [SECTION] DEBUG LOG WINDOW
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
*/
@@ -102,6 +103,7 @@ CODE
- Easy to hack and improve.
- Minimize setup and maintenance.
- Minimize state storage on user side.
+ - Minimize state synchronization.
- Portable, minimize dependencies, run on target (consoles, phones, etc.).
- Efficient runtime and memory consumption.
@@ -292,6 +294,7 @@ CODE
void void MyImGuiRenderFunction(ImDrawData* draw_data)
{
// TODO: Setup render state: alpha-blending enabled, no face culling, no depth testing, scissor enabled
+ // TODO: Setup texture sampling state: sample with bilinear filtering (NOT point/nearest filtering). Use 'io.Fonts->Flags |= ImFontAtlasFlags_NoBakedLines;' to allow point/nearest filtering.
// TODO: Setup viewport covering draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
// TODO: Setup orthographic projection matrix cover draw_data->DisplayPos to draw_data->DisplayPos + draw_data->DisplaySize
// TODO: Setup shader: vertex { float2 pos, float2 uv, u32 color }, fragment shader sample color from 1 texture, multiply by vertex color.
@@ -386,12 +389,15 @@ CODE
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
(Docking/Viewport Branch)
- - 2021/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
+ - 2022/XX/XX (1.XX) - when multi-viewports are enabled, all positions will be in your natural OS coordinates space. It means that:
- reference to hard-coded positions such as in SetNextWindowPos(ImVec2(0,0)) are probably not what you want anymore.
you may use GetMainViewport()->Pos to offset hard-coded positions, e.g. SetNextWindowPos(GetMainViewport()->Pos)
- 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.
+ - 2022/06/15 (1.88) - renamed IMGUI_DISABLE_METRICS_WINDOW to IMGUI_DISABLE_DEBUG_TOOLS for correctness. kept support for old define (will obsolete).
+ - 2022/05/03 (1.88) - backends: osx: removed ImGui_ImplOSX_HandleEvent() from backend API in favor of backend automatically handling event capture. All ImGui_ImplOSX_HandleEvent() calls should be removed as they are now unnecessary.
+ - 2022/04/05 (1.88) - inputs: renamed ImGuiKeyModFlags to ImGuiModFlags. Kept inline redirection enums (will obsolete). This was never used in public API functions but technically present in imgui.h and ImGuiIO.
- 2022/01/20 (1.87) - inputs: reworded gamepad IO.
- Backend writing to io.NavInputs[] -> backend should call io.AddKeyEvent()/io.AddKeyAnalogEvent() with ImGuiKey_GamepadXXX values.
- 2022/01/19 (1.87) - sliders, drags: removed support for legacy arithmetic operators (+,+-,*,/) when inputing text. This doesn't break any api/code but a feature that used to be accessible by end-users (which seemingly no one used).
@@ -400,10 +406,12 @@ CODE
- Backend writing to io.MouseDown[] -> backend should call io.AddMouseButtonEvent()
- Backend writing to io.MouseWheel -> backend should call io.AddMouseWheelEvent()
- Backend writing to io.MouseHoveredViewport -> backend should call io.AddMouseViewportEvent() [Docking branch w/ multi-viewports only]
+ note: for all calls to IO new functions, the Dear ImGui context should be bound/current.
+ read https://github.com/ocornut/imgui/issues/4921 for details.
- 2022/01/10 (1.87) - inputs: reworked keyboard IO. Removed io.KeyMap[], io.KeysDown[] in favor of calling io.AddKeyEvent(). Removed GetKeyIndex(), now unecessary. All IsKeyXXX() functions now take ImGuiKey values. All features are still functional until IMGUI_DISABLE_OBSOLETE_KEYIO is defined. Read Changelog and Release Notes for details.
- IsKeyPressed(MY_NATIVE_KEY_XXX) -> use IsKeyPressed(ImGuiKey_XXX)
- IsKeyPressed(GetKeyIndex(ImGuiKey_XXX)) -> use IsKeyPressed(ImGuiKey_XXX)
- - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent()
+ - Backend writing to io.KeyMap[],io.KeysDown[] -> backend should call io.AddKeyEvent() (+ call io.SetKeyEventNativeData() if you want legacy user code to stil function with legacy key codes).
- Backend writing to io.KeyCtrl, io.KeyShift.. -> backend should call io.AddKeyEvent() with ImGuiKey_ModXXX values. *IF YOU PULLED CODE BETWEEN 2021/01/10 and 2021/01/27: We used to have a io.AddKeyModsEvent() function which was now replaced by io.AddKeyEvent() with ImGuiKey_ModXXX values.*
- one case won't work with backward compatibility: if your custom backend used ImGuiKey as mock native indices (e.g. "io.KeyMap[ImGuiKey_A] = ImGuiKey_A") because those values are now larger than the legacy KeyDown[] array. Will assert.
- inputs: added ImGuiKey_ModCtrl/ImGuiKey_ModShift/ImGuiKey_ModAlt/ImGuiKey_ModSuper values to submit keyboard modifiers using io.AddKeyEvent(), instead of writing directly to io.KeyCtrl, io.KeyShift, io.KeyAlt, io.KeySuper.
@@ -1079,7 +1087,7 @@ ImGuiStyle::ImGuiStyle()
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
- GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
+ GrabMinSize = 12.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
LogSliderDeadzone = 4.0f; // The size in pixels of the dead-zone around zero on logarithmic sliders that cross zero.
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
@@ -1092,7 +1100,7 @@ ImGuiStyle::ImGuiStyle()
DisplaySafeAreaPadding = ImVec2(3,3); // If you cannot see the edge of your screen (e.g. on a TV) increase the safe area padding. Covers popups/tooltips as well regular windows.
MouseCursorScale = 1.0f; // Scale software rendered mouse cursor (when io.MouseDrawCursor is enabled). May be removed later.
AntiAliasedLines = true; // Enable anti-aliased lines/borders. Disable if you are really tight on CPU/GPU.
- AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering.
+ AntiAliasedLinesUseTex = true; // Enable anti-aliased lines/borders using textures where possible. Require backend to render with bilinear filtering (NOT point/nearest filtering).
AntiAliasedFill = true; // Enable anti-aliased filled shapes (rounded rectangles, circles, etc.).
CurveTessellationTol = 1.25f; // Tessellation tolerance when using PathBezierCurveTo() without a specific number of segments. Decrease for highly tessellated curves (higher quality, more polygons), increase to reduce quality.
CircleTessellationMaxError = 0.30f; // Maximum error (in pixels) allowed when using AddCircle()/AddCircleFilled() or drawing rounded corner rectangles with no explicit segment count specified. Decrease for higher quality but more geometry.
@@ -1200,6 +1208,7 @@ ImGuiIO::ImGuiIO()
for (int i = 0; i < IM_ARRAYSIZE(MouseDownDuration); i++) MouseDownDuration[i] = MouseDownDurationPrev[i] = -1.0f;
for (int i = 0; i < IM_ARRAYSIZE(KeysData); i++) { KeysData[i].DownDuration = KeysData[i].DownDurationPrev = -1.0f; }
for (int i = 0; i < IM_ARRAYSIZE(NavInputsDownDuration); i++) NavInputsDownDuration[i] = -1.0f;
+ AppAcceptingEvents = true;
BackendUsingLegacyKeyArrays = (ImS8)-1;
BackendUsingLegacyNavInputArray = true; // assume using legacy array until proven wrong
}
@@ -1212,11 +1221,11 @@ void ImGuiIO::AddInputCharacter(unsigned int c)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
- if (c == 0)
+ if (c == 0 || !AppAcceptingEvents)
return;
ImGuiInputEvent e;
- e.Type = ImGuiInputEventType_Char;
+ e.Type = ImGuiInputEventType_Text;
e.Source = ImGuiInputSource_Keyboard;
e.Text.Char = c;
g.InputEventsQueue.push_back(e);
@@ -1226,7 +1235,7 @@ void ImGuiIO::AddInputCharacter(unsigned int c)
// we should save the high surrogate.
void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
{
- if (c == 0 && InputQueueSurrogate == 0)
+ if ((c == 0 && InputQueueSurrogate == 0) || !AppAcceptingEvents)
return;
if ((c & 0xFC00) == 0xD800) // High surrogate, must save
@@ -1260,6 +1269,8 @@ void ImGuiIO::AddInputCharacterUTF16(ImWchar16 c)
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
+ if (!AppAcceptingEvents)
+ return;
while (*utf8_chars != 0)
{
unsigned int c = 0;
@@ -1286,7 +1297,7 @@ void ImGuiIO::ClearInputKeys()
KeysData[n].DownDurationPrev = -1.0f;
}
KeyCtrl = KeyShift = KeyAlt = KeySuper = false;
- KeyMods = KeyModsPrev = ImGuiKeyModFlags_None;
+ KeyMods = ImGuiModFlags_None;
for (int n = 0; n < IM_ARRAYSIZE(NavInputsDownDuration); n++)
NavInputsDownDuration[n] = NavInputsDownDurationPrev[n] = -1.0f;
}
@@ -1297,8 +1308,8 @@ void ImGuiIO::ClearInputKeys()
// - float analog_value: 0.0f..1.0f
void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
{
- //if (e->Down) { IMGUI_DEBUG_LOG("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
- if (key == ImGuiKey_None)
+ //if (e->Down) { IMGUI_DEBUG_LOG_IO("AddKeyEvent() Key='%s' %d, NativeKeycode = %d, NativeScancode = %d\n", ImGui::GetKeyName(e->Key), e->Down, e->NativeKeycode, e->NativeScancode); }
+ if (key == ImGuiKey_None || !AppAcceptingEvents)
return;
ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
@@ -1339,6 +1350,8 @@ void ImGuiIO::AddKeyAnalogEvent(ImGuiKey key, bool down, float analog_value)
void ImGuiIO::AddKeyEvent(ImGuiKey key, bool down)
{
+ if (!AppAcceptingEvents)
+ return;
AddKeyAnalogEvent(key, down, down ? 1.0f : 0.0f);
}
@@ -1357,19 +1370,29 @@ void ImGuiIO::SetKeyEventNativeData(ImGuiKey key, int native_keycode, int native
// Build native->imgui map so old user code can still call key functions with native 0..511 values.
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
const int legacy_key = (native_legacy_index != -1) ? native_legacy_index : native_keycode;
- if (ImGui::IsLegacyKey(legacy_key))
- KeyMap[legacy_key] = key;
+ if (!ImGui::IsLegacyKey(legacy_key))
+ return;
+ KeyMap[legacy_key] = key;
+ KeyMap[key] = legacy_key;
#else
IM_UNUSED(key);
IM_UNUSED(native_legacy_index);
#endif
}
+// 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.
+void ImGuiIO::SetAppAcceptingEvents(bool accepting_events)
+{
+ AppAcceptingEvents = accepting_events;
+}
+
// Queue a mouse move event
void ImGuiIO::AddMousePosEvent(float x, float y)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
+ if (!AppAcceptingEvents)
+ return;
ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MousePos;
@@ -1384,6 +1407,8 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
IM_ASSERT(mouse_button >= 0 && mouse_button < ImGuiMouseButton_COUNT);
+ if (!AppAcceptingEvents)
+ return;
ImGuiInputEvent e;
e.Type = ImGuiInputEventType_MouseButton;
@@ -1398,7 +1423,7 @@ void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(&g.IO == this && "Can only add events to current context.");
- if (wheel_x == 0.0f && wheel_y == 0.0f)
+ if ((wheel_x == 0.0f && wheel_y == 0.0f) || !AppAcceptingEvents)
return;
ImGuiInputEvent e;
@@ -1686,8 +1711,12 @@ const char* ImStrSkipBlank(const char* str)
// designed using two-passes worst case, which probably could be improved using the stbsp_vsprintfcb() function.)
#ifdef IMGUI_USE_STB_SPRINTF
#define STB_SPRINTF_IMPLEMENTATION
+#ifdef IMGUI_STB_SPRINTF_FILENAME
+#include IMGUI_STB_SPRINTF_FILENAME
+#else
#include "stb_sprintf.h"
#endif
+#endif
#if defined(_MSC_VER) && !defined(vsnprintf)
#define vsnprintf _vsnprintf
@@ -1727,6 +1756,25 @@ int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args)
}
#endif // #ifdef IMGUI_DISABLE_DEFAULT_FORMAT_FUNCTIONS
+void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end, const char* fmt, ...)
+{
+ ImGuiContext& g = *GImGui;
+ va_list args;
+ va_start(args, fmt);
+ int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
+ *out_buf = g.TempBuffer.Data;
+ if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
+ va_end(args);
+}
+
+void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
+{
+ ImGuiContext& g = *GImGui;
+ int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
+ *out_buf = g.TempBuffer.Data;
+ if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
+}
+
// CRC32 needs a 1KB lookup table (not cache friendly)
// Although the code to generate the table is simple and shorter than the table itself, using a const table allows us to easily:
// - avoid an unnecessary branch/memory tap, - keep the ImHashXXX functions usable by static constructors, - make it thread-safe.
@@ -2288,18 +2336,15 @@ void ImGuiStorage::SetAllInt(int v)
//-----------------------------------------------------------------------------
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
-ImGuiTextFilter::ImGuiTextFilter(const char* default_filter)
+ImGuiTextFilter::ImGuiTextFilter(const char* default_filter) //-V1077
{
+ InputBuf[0] = 0;
+ CountGrep = 0;
if (default_filter)
{
ImStrncpy(InputBuf, default_filter, IM_ARRAYSIZE(InputBuf));
Build();
}
- else
- {
- InputBuf[0] = 0;
- CountGrep = 0;
- }
}
bool ImGuiTextFilter::Draw(const char* label, float width)
@@ -2614,15 +2659,14 @@ void ImGuiListClipper::Begin(int items_count, float items_height)
void ImGuiListClipper::End()
{
- // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
ImGuiContext& g = *GImGui;
- if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
- ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
- ItemsCount = -1;
-
- // Restore temporary buffer and fix back pointers which may be invalidated when nesting
if (ImGuiListClipperData* data = (ImGuiListClipperData*)TempData)
{
+ // In theory here we should assert that we are already at the right position, but it seems saner to just seek at the end and not assert/crash the user.
+ if (ItemsCount >= 0 && ItemsCount < INT_MAX && DisplayStart >= 0)
+ ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
+
+ // Restore temporary buffer and fix back pointers which may be invalidated when nesting
IM_ASSERT(data->ListClipper == this);
data->StepNo = data->Ranges.Size;
if (--g.ClipperTempDataStacked > 0)
@@ -2632,6 +2676,7 @@ void ImGuiListClipper::End()
}
TempData = NULL;
}
+ ItemsCount = -1;
}
void ImGuiListClipper::ForceDisplayRangeByIndices(int item_min, int item_max)
@@ -2648,6 +2693,7 @@ bool ImGuiListClipper::Step()
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
+ IM_ASSERT(data != NULL && "Called ImGuiListClipper::Step() too many times, or before ImGuiListClipper::Begin() ?");
ImGuiTable* table = g.CurrentTable;
if (table && table->IsInsideRow)
@@ -2764,8 +2810,8 @@ bool ImGuiListClipper::Step()
// Advance the cursor to the end of the list and then returns 'false' to end the loop.
if (ItemsCount < INT_MAX)
ImGuiListClipper_SeekCursorForItem(this, ItemsCount);
- ItemsCount = -1;
+ End();
return false;
}
@@ -3249,6 +3295,34 @@ 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);
+ ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
+ for (int n = 0; n < g.Viewports.Size; n++)
+ {
+ // We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor.
+ ImVec2 offset, size, uv[4];
+ if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
+ continue;
+ ImGuiViewportP* viewport = g.Viewports[n];
+ const ImVec2 pos = base_pos - offset;
+ const float scale = base_scale * viewport->DpiScale;
+ if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
+ continue;
+ ImDrawList* draw_list = GetForegroundDrawList(viewport);
+ ImTextureID tex_id = font_atlas->TexID;
+ draw_list->PushTextureID(tex_id);
+ draw_list->AddImage(tex_id, pos + ImVec2(1, 0) * scale, pos + (ImVec2(1, 0) + size) * scale, uv[2], uv[3], col_shadow);
+ draw_list->AddImage(tex_id, pos + ImVec2(2, 0) * scale, pos + (ImVec2(2, 0) + size) * scale, uv[2], uv[3], col_shadow);
+ draw_list->AddImage(tex_id, pos, pos + size * scale, uv[2], uv[3], col_border);
+ draw_list->AddImage(tex_id, pos, pos + size * scale, uv[0], uv[1], col_fill);
+ draw_list->PopTextureID();
+ }
+}
+
+
//-----------------------------------------------------------------------------
// [SECTION] MAIN CODE (most of the code! lots of stuff, needs tidying up!)
//-----------------------------------------------------------------------------
@@ -3294,7 +3368,6 @@ ImGuiID ImGuiWindow::GetID(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
- ImGui::KeepAliveID(id);
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
@@ -3305,7 +3378,6 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
- ImGui::KeepAliveID(id);
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
@@ -3316,37 +3388,6 @@ ImGuiID ImGuiWindow::GetID(int n)
{
ImGuiID seed = IDStack.back();
ImGuiID id = ImHashData(&n, sizeof(n), seed);
- ImGui::KeepAliveID(id);
- ImGuiContext& g = *GImGui;
- if (g.DebugHookIdInfo == id)
- ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
- return id;
-}
-
-ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
-{
- ImGuiID seed = IDStack.back();
- ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
- ImGuiContext& g = *GImGui;
- if (g.DebugHookIdInfo == id)
- ImGui::DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
- return id;
-}
-
-ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
-{
- ImGuiID seed = IDStack.back();
- ImGuiID id = ImHashData(&ptr, sizeof(void*), seed);
- ImGuiContext& g = *GImGui;
- if (g.DebugHookIdInfo == id)
- ImGui::DebugHookIdInfo(id, ImGuiDataType_Pointer, ptr, NULL);
- return id;
-}
-
-ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
-{
- ImGuiID seed = IDStack.back();
- ImGuiID id = ImHashData(&n, sizeof(n), seed);
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
ImGui::DebugHookIdInfo(id, ImGuiDataType_S32, (void*)(intptr_t)n, NULL);
@@ -3359,7 +3400,6 @@ ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
ImGuiID seed = IDStack.back();
ImRect r_rel = ImGui::WindowRectAbsToRel(this, r_abs);
ImGuiID id = ImHashData(&r_rel, sizeof(r_rel), seed);
- ImGui::KeepAliveID(id);
return id;
}
@@ -3409,9 +3449,21 @@ void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
+
+ // While most behaved code would make an effort to not steal active id during window move/drag operations,
+ // we at least need to be resilient to it. Cancelling the move is rather aggressive and users of 'master' branch
+ // may prefer the weird ill-defined half working situation ('docking' did assert), so may need to rework that.
+ if (g.MovingWindow != NULL && g.ActiveId == g.MovingWindow->MoveId)
+ {
+ IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() cancel MovingWindow\n");
+ g.MovingWindow = NULL;
+ }
+
+ // Set active id
g.ActiveIdIsJustActivated = (g.ActiveId != id);
if (g.ActiveIdIsJustActivated)
{
+ IMGUI_DEBUG_LOG_ACTIVEID("SetActiveID() old:0x%08X (window \"%s\") -> new:0x%08X (window \"%s\")\n", g.ActiveId, g.ActiveIdWindow ? g.ActiveIdWindow->Name : "", id, window ? window->Name : "");
g.ActiveIdTimer = 0.0f;
g.ActiveIdHasBeenPressedBefore = false;
g.ActiveIdHasBeenEditedBefore = false;
@@ -3462,6 +3514,8 @@ ImGuiID ImGui::GetHoveredID()
return g.HoveredId ? g.HoveredId : g.HoveredIdPreviousFrame;
}
+// This is called by ItemAdd().
+// Code not using ItemAdd() may need to call this manually otherwise ActiveId will be cleared. In IMGUI_VERSION_NUM < 18717 this was called by GetID().
void ImGui::KeepAliveID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
@@ -3516,7 +3570,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- if (g.NavDisableMouseHover && !g.NavDisableHighlight)
+ if (g.NavDisableMouseHover && !g.NavDisableHighlight && !(flags & ImGuiHoveredFlags_NoNavOverride))
{
if ((g.LastItemData.InFlags & ImGuiItemFlags_Disabled) && !(flags & ImGuiHoveredFlags_AllowWhenDisabled))
return false;
@@ -3579,8 +3633,6 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
return false;
if (!IsMouseHoveringRect(bb.Min, bb.Max))
return false;
- if (g.NavDisableMouseHover)
- return false;
if (!IsWindowContentHoverable(window, ImGuiHoveredFlags_None))
{
g.HoveredIdDisabled = true;
@@ -3616,6 +3668,9 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
IM_DEBUG_BREAK();
}
+ if (g.NavDisableMouseHover)
+ return false;
+
return true;
}
@@ -3733,20 +3788,23 @@ void ImGui::GetAllocatorFunctions(ImGuiMemAllocFunc* p_alloc_func, ImGuiMemFreeF
ImGuiContext* ImGui::CreateContext(ImFontAtlas* shared_font_atlas)
{
+ ImGuiContext* prev_ctx = GetCurrentContext();
ImGuiContext* ctx = IM_NEW(ImGuiContext)(shared_font_atlas);
- if (GImGui == NULL)
- SetCurrentContext(ctx);
- Initialize(ctx);
+ SetCurrentContext(ctx);
+ Initialize();
+ if (prev_ctx != NULL)
+ SetCurrentContext(prev_ctx); // Restore previous context if any, else keep new one.
return ctx;
}
void ImGui::DestroyContext(ImGuiContext* ctx)
{
- if (ctx == NULL)
- ctx = GImGui;
- Shutdown(ctx);
- if (GImGui == ctx)
- SetCurrentContext(NULL);
+ ImGuiContext* prev_ctx = GetCurrentContext();
+ if (ctx == NULL) //-V1051
+ ctx = prev_ctx;
+ SetCurrentContext(ctx);
+ Shutdown();
+ SetCurrentContext((prev_ctx != ctx) ? prev_ctx : NULL);
IM_DELETE(ctx);
}
@@ -3927,13 +3985,12 @@ void ImGui::UpdateMouseMovingWindowNewFrame()
ImGuiWindow* moving_window = g.MovingWindow->RootWindowDockTree;
// When a window stop being submitted while being dragged, it may will its viewport until next Begin()
- const bool window_disappared = (!moving_window->WasActive || moving_window->Viewport == NULL);
+ const bool window_disappared = ((!moving_window->WasActive && !moving_window->Active) || moving_window->Viewport == NULL);
if (g.IO.MouseDown[0] && IsMousePosValid(&g.IO.MousePos) && !window_disappared)
{
ImVec2 pos = g.IO.MousePos - g.ActiveIdClickOffset;
if (moving_window->Pos.x != pos.x || moving_window->Pos.y != pos.y)
{
- MarkIniSettingsDirty(moving_window);
SetWindowPos(moving_window, pos, ImGuiCond_Always);
if (moving_window->ViewportOwned) // Synchronize viewport immediately because some overlays may relies on clipping rectangle before we Begin() into the window.
{
@@ -4031,6 +4088,8 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
}
}
+// This is called during NewFrame()->UpdateViewportsNewFrame() only.
+// Need to keep in sync with SetWindowPos()
static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
{
window->Pos += delta;
@@ -4040,6 +4099,7 @@ static void TranslateWindow(ImGuiWindow* window, const ImVec2& delta)
window->DC.CursorPos += delta;
window->DC.CursorStartPos += delta;
window->DC.CursorMaxPos += delta;
+ window->DC.IdealMaxPos += delta;
}
static void ScaleWindow(ImGuiWindow* window, float scale)
@@ -4061,16 +4121,13 @@ static void ImGui::UpdateKeyboardInputs()
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
- // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
- io.KeyMods = GetMergedKeyModFlags();
-
// Import legacy keys or verify they are not used
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
if (io.BackendUsingLegacyKeyArrays == 0)
{
- // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written too.
- for (int n = 0; n < IM_ARRAYSIZE(io.KeysDown); n++)
- IM_ASSERT(io.KeysDown[n] == false && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
+ // Backend used new io.AddKeyEvent() API: Good! Verify that old arrays are never written to externally.
+ for (int n = 0; n < ImGuiKey_LegacyNativeKey_END; n++)
+ IM_ASSERT((io.KeysDown[n] == false || IsKeyDown(n)) && "Backend needs to either only use io.AddKeyEvent(), either only fill legacy io.KeysDown[] + io.KeyMap[]. Not both!");
}
else
{
@@ -4093,6 +4150,8 @@ static void ImGui::UpdateKeyboardInputs()
const ImGuiKey key = (ImGuiKey)(io.KeyMap[n] != -1 ? io.KeyMap[n] : n);
IM_ASSERT(io.KeyMap[n] == -1 || IsNamedKey(key));
io.KeysData[key].Down = io.KeysDown[n];
+ if (key != n)
+ io.KeysDown[key] = io.KeysDown[n]; // Allow legacy code using io.KeysDown[GetKeyIndex()] with old backends
io.BackendUsingLegacyKeyArrays = 1;
}
if (io.BackendUsingLegacyKeyArrays == 1)
@@ -4105,6 +4164,9 @@ static void ImGui::UpdateKeyboardInputs()
}
#endif
+ // Synchronize io.KeyMods with individual modifiers io.KeyXXX bools
+ io.KeyMods = GetMergedModFlags();
+
// Clear gamepad data if disabled
if ((io.BackendFlags & ImGuiBackendFlags_HasGamepad) == 0)
for (int i = ImGuiKey_Gamepad_BEGIN; i < ImGuiKey_Gamepad_END; i++)
@@ -4116,9 +4178,9 @@ static void ImGui::UpdateKeyboardInputs()
// Update keys
for (int i = 0; i < IM_ARRAYSIZE(io.KeysData); i++)
{
- ImGuiKeyData& key_data = io.KeysData[i];
- key_data.DownDurationPrev = key_data.DownDuration;
- key_data.DownDuration = key_data.Down ? (key_data.DownDuration < 0.0f ? 0.0f : key_data.DownDuration + io.DeltaTime) : -1.0f;
+ ImGuiKeyData* key_data = &io.KeysData[i];
+ key_data->DownDurationPrev = key_data->DownDuration;
+ key_data->DownDuration = key_data->Down ? (key_data->DownDuration < 0.0f ? 0.0f : key_data->DownDuration + io.DeltaTime) : -1.0f;
}
}
@@ -4213,7 +4275,9 @@ void ImGui::UpdateMouseWheel()
}
}
- if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
+ float wheel_x = g.IO.MouseWheelH;
+ float wheel_y = g.IO.MouseWheel;
+ if (wheel_x == 0.0f && wheel_y == 0.0f)
return;
if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel))
@@ -4225,7 +4289,7 @@ void ImGui::UpdateMouseWheel()
// Zoom / Scale window
// FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
- if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
+ if (wheel_y != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
{
StartLockWheelingWindow(window);
const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
@@ -4249,8 +4313,11 @@ void ImGui::UpdateMouseWheel()
// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
// (we avoid doing it on OSX as it the OS input layer handles this already)
const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
- const float wheel_y = swap_axis ? 0.0f : g.IO.MouseWheel;
- const float wheel_x = swap_axis ? g.IO.MouseWheel : g.IO.MouseWheelH;
+ if (swap_axis)
+ {
+ wheel_x = wheel_y;
+ wheel_y = 0.0f;
+ }
// Vertical Mouse Wheel scrolling
if (wheel_y != 0.0f)
@@ -4359,15 +4426,16 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
io.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
}
-ImGuiKeyModFlags ImGui::GetMergedKeyModFlags()
+// [Internal] Do not use directly (can read io.KeyMods instead)
+ImGuiModFlags ImGui::GetMergedModFlags()
{
ImGuiContext& g = *GImGui;
- ImGuiKeyModFlags key_mod_flags = ImGuiKeyModFlags_None;
- if (g.IO.KeyCtrl) { key_mod_flags |= ImGuiKeyModFlags_Ctrl; }
- if (g.IO.KeyShift) { key_mod_flags |= ImGuiKeyModFlags_Shift; }
- if (g.IO.KeyAlt) { key_mod_flags |= ImGuiKeyModFlags_Alt; }
- if (g.IO.KeySuper) { key_mod_flags |= ImGuiKeyModFlags_Super; }
- return key_mod_flags;
+ ImGuiModFlags key_mods = ImGuiModFlags_None;
+ if (g.IO.KeyCtrl) { key_mods |= ImGuiModFlags_Ctrl; }
+ if (g.IO.KeyShift) { key_mods |= ImGuiModFlags_Shift; }
+ if (g.IO.KeyAlt) { key_mods |= ImGuiModFlags_Alt; }
+ if (g.IO.KeySuper) { key_mods |= ImGuiModFlags_Super; }
+ return key_mods;
}
void ImGui::NewFrame()
@@ -4456,9 +4524,16 @@ void ImGui::NewFrame()
g.HoveredIdUsingMouseWheel = false;
g.HoveredIdDisabled = false;
- // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
- if (g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId && g.ActiveId != 0)
+ // Clear ActiveID if the item is not alive anymore.
+ // In 1.87, the common most call to KeepAliveID() was moved from GetID() to ItemAdd().
+ // As a result, custom widget using ButtonBehavior() _without_ ItemAdd() need to call KeepAliveID() themselves.
+ if (g.ActiveId != 0 && g.ActiveIdIsAlive != g.ActiveId && g.ActiveIdPreviousFrame == g.ActiveId)
+ {
+ IMGUI_DEBUG_LOG_ACTIVEID("NewFrame(): ClearActiveID() because it isn't marked alive anymore!\n");
ClearActiveID();
+ }
+
+ // Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
if (g.ActiveId)
g.ActiveIdTimer += g.IO.DeltaTime;
g.LastActiveIdTimer += g.IO.DeltaTime;
@@ -4592,9 +4667,9 @@ void ImGui::NewFrame()
CallContextHooks(&g, ImGuiContextHookType_NewFramePost);
}
-void ImGui::Initialize(ImGuiContext* context)
+void ImGui::Initialize()
{
- ImGuiContext& g = *context;
+ ImGuiContext& g = *GImGui;
IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
// Add .ini handle for ImGuiWindow type
@@ -4607,11 +4682,11 @@ void ImGui::Initialize(ImGuiContext* context)
ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
ini_handler.ApplyAllFn = WindowSettingsHandler_ApplyAll;
ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
- g.SettingsHandlers.push_back(ini_handler);
+ AddSettingsHandler(&ini_handler);
}
// Add .ini handle for ImGuiTable type
- TableSettingsInstallHandler(context);
+ TableSettingsAddSettingsHandler();
// Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
@@ -4620,6 +4695,7 @@ void ImGui::Initialize(ImGuiContext* context)
viewport->PlatformWindowCreated = true;
viewport->Flags = ImGuiViewportFlags_OwnedByApp;
g.Viewports.push_back(viewport);
+ g.TempBuffer.resize(1024 * 3 + 1, 0);
g.PlatformIO.Viewports.push_back(g.Viewports[0]);
#ifdef IMGUI_HAS_DOCK
@@ -4631,10 +4707,10 @@ void ImGui::Initialize(ImGuiContext* context)
}
// This function is merely here to free heap allocations.
-void ImGui::Shutdown(ImGuiContext* context)
+void ImGui::Shutdown()
{
// The fonts atlas can be used prior to calling NewFrame(), so we clear it even if g.Initialized is FALSE (which would happen if we never called NewFrame)
- ImGuiContext& g = *context;
+ ImGuiContext& g = *GImGui;
if (g.IO.Fonts && g.FontAtlasOwnedByContext)
{
g.IO.Fonts->Locked = false;
@@ -4648,18 +4724,10 @@ void ImGui::Shutdown(ImGuiContext* context)
// Save settings (unless we haven't attempted to load them: CreateContext/DestroyContext without a call to NewFrame shouldn't save an empty file)
if (g.SettingsLoaded && g.IO.IniFilename != NULL)
- {
- ImGuiContext* backup_context = GImGui;
- SetCurrentContext(&g);
SaveIniSettingsToDisk(g.IO.IniFilename);
- SetCurrentContext(backup_context);
- }
// Destroy platform windows
- ImGuiContext* backup_context = ImGui::GetCurrentContext();
- SetCurrentContext(context);
DestroyPlatformWindows();
- SetCurrentContext(backup_context);
// Shutdown extensions
DockContextShutdown(&g);
@@ -4712,6 +4780,7 @@ void ImGui::Shutdown(ImGuiContext* context)
g.LogFile = NULL;
}
g.LogBuffer.clear();
+ g.DebugLogBuf.clear();
g.Initialized = false;
}
@@ -5079,7 +5148,6 @@ void ImGui::EndFrame()
// Clear Input data for next frame
g.IO.MouseWheel = g.IO.MouseWheelH = 0.0f;
g.IO.InputQueueCharacters.resize(0);
- g.IO.KeyModsPrev = g.IO.KeyMods; // doing it here is better than in NewFrame() as we'll tolerate backend writing to KeyMods. If we want to firmly disallow it we should detect it.
memset(g.IO.NavInputs, 0, sizeof(g.IO.NavInputs));
CallContextHooks(&g, ImGuiContextHookType_EndFramePost);
@@ -5129,9 +5197,9 @@ void ImGui::Render()
if (first_render_of_frame)
RenderDimmedBackgrounds();
- ImVec2 mouse_cursor_offset, mouse_cursor_size, mouse_cursor_uv[4];
- if (g.IO.MouseDrawCursor && g.MouseCursor != ImGuiMouseCursor_None)
- g.IO.Fonts->GetMouseCursorTexData(g.MouseCursor, &mouse_cursor_offset, &mouse_cursor_size, &mouse_cursor_uv[0], &mouse_cursor_uv[2]);
+ // Draw software mouse cursor if requested by io.MouseDrawCursor flag
+ if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None)
+ RenderMouseCursor(g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
// Setup ImDrawData structures for end-user
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
@@ -5140,15 +5208,6 @@ void ImGui::Render()
ImGuiViewportP* viewport = g.Viewports[n];
viewport->DrawDataBuilder.FlattenIntoSingleLayer();
- // Draw software mouse cursor if requested by io.MouseDrawCursor flag
- // (note we scale cursor by current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor)
- if (mouse_cursor_size.x > 0.0f && mouse_cursor_size.y > 0.0f && first_render_of_frame)
- {
- float scale = g.Style.MouseCursorScale * viewport->DpiScale;
- if (viewport->GetMainRect().Overlaps(ImRect(g.IO.MousePos, g.IO.MousePos + ImVec2(mouse_cursor_size.x + 2, mouse_cursor_size.y + 2) * scale)))
- RenderMouseCursor(GetForegroundDrawList(viewport), g.IO.MousePos, scale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
- }
-
// Add foreground ImDrawList (for each active viewport)
if (viewport->DrawLists[1] != NULL)
AddDrawListToDrawData(&viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
@@ -5422,15 +5481,16 @@ bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size_arg, b
SetNextWindowSize(size);
// 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.
+ const char* temp_window_name;
if (name)
- ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%s_%08X", parent_window->Name, name, id);
+ ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%s_%08X", parent_window->Name, name, id);
else
- ImFormatString(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), "%s/%08X", parent_window->Name, id);
+ ImFormatStringToTempBuffer(&temp_window_name, NULL, "%s/%08X", parent_window->Name, id);
const float backup_border_size = g.Style.ChildBorderSize;
if (!border)
g.Style.ChildBorderSize = 0.0f;
- bool ret = Begin(g.TempBuffer, NULL, flags);
+ bool ret = Begin(temp_window_name, NULL, flags);
g.Style.ChildBorderSize = backup_border_size;
ImGuiWindow* child_window = g.CurrentWindow;
@@ -5615,7 +5675,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImGuiWindowFlags flags)
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
ApplyWindowSettings(window, settings);
}
- window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
+ window->DC.CursorStartPos = window->DC.CursorMaxPos = window->DC.IdealMaxPos = window->Pos; // So first call to CalcWindowContentSizes() doesn't return crazy values
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
{
@@ -5892,6 +5952,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
if (resize_rect.Min.x > resize_rect.Max.x) ImSwap(resize_rect.Min.x, resize_rect.Max.x);
if (resize_rect.Min.y > resize_rect.Max.y) ImSwap(resize_rect.Min.y, resize_rect.Max.y);
ImGuiID resize_grip_id = window->GetID(resize_grip_n); // == GetWindowResizeCornerID()
+ KeepAliveID(resize_grip_id);
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)
@@ -5927,6 +5988,7 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
bool hovered, held;
ImRect border_rect = GetResizeBorderRect(window, border_n, grip_hover_inner_size, WINDOWS_HOVER_PADDING);
ImGuiID border_id = window->GetID(border_n + 4); // == GetWindowResizeBorderID()
+ KeepAliveID(border_id);
ButtonBehavior(border_rect, border_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_NoNavFocus);
//GetForegroundDrawLists(window)->AddRect(border_rect.Min, border_rect.Max, IM_COL32(255, 255, 0, 255));
if ((hovered && g.HoveredIdTimer > WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER) || held)
@@ -5955,9 +6017,9 @@ static bool ImGui::UpdateWindowManualResize(ImGuiWindow* window, const ImVec2& s
{
ImVec2 nav_resize_delta;
if (g.NavInputSource == ImGuiInputSource_Keyboard && g.IO.KeyShift)
- nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiInputReadMode_Down);
+ nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiNavReadMode_Down);
if (g.NavInputSource == ImGuiInputSource_Gamepad)
- nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiInputReadMode_Down);
+ nav_resize_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadDPad, ImGuiNavReadMode_Down);
if (nav_resize_delta.x != 0.0f || nav_resize_delta.y != 0.0f)
{
const float NAV_RESIZE_SPEED = 600.0f;
@@ -5991,8 +6053,8 @@ static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& visibility
{
ImGuiContext& g = *GImGui;
ImVec2 size_for_clamping = window->Size;
- if (g.IO.ConfigWindowsMoveFromTitleBarOnly && !(window->Flags & ImGuiWindowFlags_NoTitleBar))
- size_for_clamping.y = window->TitleBarHeight();
+ if (g.IO.ConfigWindowsMoveFromTitleBarOnly && (!(window->Flags & ImGuiWindowFlags_NoTitleBar) || window->DockNodeAsHost))
+ size_for_clamping.y = ImGui::GetFrameHeight(); // Not using window->TitleBarHeight() as DockNodeAsHost will report 0.0f here.
window->Pos = ImClamp(window->Pos, visibility_rect.Min - size_for_clamping, visibility_rect.Max);
}
@@ -6124,8 +6186,10 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
float unhide_sz_hit = ImFloor(g.FontSize * 0.55f);
ImVec2 p = node->Pos;
ImRect r(p, p + ImVec2(unhide_sz_hit, unhide_sz_hit));
+ ImGuiID unhide_id = window->GetID("#UNHIDE");
+ KeepAliveID(unhide_id);
bool hovered, held;
- if (ButtonBehavior(r, window->GetID("#UNHIDE"), &hovered, &held, ImGuiButtonFlags_FlattenChildren))
+ if (ButtonBehavior(r, unhide_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren))
node->WantHiddenTabBarToggle = true;
else if (held && IsMouseDragging(0))
StartMouseMovingWindowOrNode(window, node, true);
@@ -6263,7 +6327,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
}
if (parent_window && (flags & ImGuiWindowFlags_Popup))
window->RootWindowPopupTree = parent_window->RootWindowPopupTree;
- if (parent_window && !(flags & ImGuiWindowFlags_Modal) && (flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)))
+ 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)
{
@@ -6402,7 +6466,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Parent window is latched only on the first call to Begin() of the frame, so further append-calls can be done from a different window stack
- ImGuiWindow* parent_window_in_stack = window->DockIsActive ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
+ ImGuiWindow* parent_window_in_stack = (window->DockIsActive && window->DockNode->HostWindow) ? window->DockNode->HostWindow : g.CurrentWindowStack.empty() ? NULL : g.CurrentWindowStack.back().Window;
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
@@ -6426,6 +6490,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiPopupData& popup_ref = g.OpenPopupStack[g.BeginPopupStack.Size];
popup_ref.Window = window;
+ popup_ref.ParentNavLayer = parent_window_in_stack->DC.NavLayerCurrent;
g.BeginPopupStack.push_back(popup_ref);
window->PopupId = popup_ref.PopupId;
}
@@ -6960,6 +7025,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.IdealMaxPos = window->DC.CursorStartPos;
window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
+ window->DC.IsSameLine = false;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
window->DC.NavLayersActiveMask = window->DC.NavLayersActiveMaskNext;
@@ -7000,7 +7066,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
window->Viewport->PlatformRequestClose = false;
g.NavWindowingToggleLayer = false; // Assume user mapped PlatformRequestClose on ALT-F4 so we disable ALT for menu toggle. False positive not an issue.
- IMGUI_DEBUG_LOG_VIEWPORT("Window '%s' PlatformRequestClose\n", window->Name);
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' PlatformRequestClose\n", window->Name);
*p_open = false;
}
}
@@ -7267,16 +7333,13 @@ void ImGui::FocusWindow(ImGuiWindow* window)
if (g.NavWindow != window)
{
- g.NavWindow = window;
+ SetNavWindow(window);
if (window && g.NavDisableMouseHover)
g.NavMousePosDirty = true;
g.NavId = window ? window->NavLastIds[0] : 0; // Restore NavId
+ g.NavLayer = ImGuiNavLayer_Main;
g.NavFocusScopeId = 0;
g.NavIdIsAlive = false;
- g.NavLayer = ImGuiNavLayer_Main;
- g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false;
- NavUpdateAnyRequestFlag();
- //IMGUI_DEBUG_LOG("FocusWindow(\"%s\")\n", window ? window->Name : NULL);
}
// Close popups if any
@@ -7646,6 +7709,10 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
const ImVec2 old_pos = window->Pos;
window->Pos = ImFloor(pos);
ImVec2 offset = window->Pos - old_pos;
+ if (offset.x == 0.0f && offset.y == 0.0f)
+ return;
+ MarkIniSettingsDirty(window);
+ // FIXME: share code with TranslateWindow(), need to confirm whether the 3 rect modified by TranslateWindow() are desirable here.
window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
window->DC.IdealMaxPos += offset;
@@ -7680,26 +7747,19 @@ void ImGui::SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond con
window->SetWindowSizeAllowFlags &= ~(ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing);
// Set
- if (size.x > 0.0f)
- {
- window->AutoFitFramesX = 0;
- window->SizeFull.x = IM_FLOOR(size.x);
- }
- else
- {
- window->AutoFitFramesX = 2;
+ ImVec2 old_size = window->SizeFull;
+ window->AutoFitFramesX = (size.x <= 0.0f) ? 2 : 0;
+ window->AutoFitFramesY = (size.y <= 0.0f) ? 2 : 0;
+ if (size.x <= 0.0f)
window->AutoFitOnlyGrows = false;
- }
- if (size.y > 0.0f)
- {
- window->AutoFitFramesY = 0;
- window->SizeFull.y = IM_FLOOR(size.y);
- }
else
- {
- window->AutoFitFramesY = 2;
+ window->SizeFull.x = IM_FLOOR(size.x);
+ if (size.y <= 0.0f)
window->AutoFitOnlyGrows = false;
- }
+ else
+ window->SizeFull.y = IM_FLOOR(size.y);
+ if (old_size.x != window->SizeFull.x || old_size.y != window->SizeFull.y)
+ MarkIniSettingsDirty(window);
}
void ImGui::SetWindowSize(const ImVec2& size, ImGuiCond cond)
@@ -7929,12 +7989,26 @@ void ImGui::PopFocusScope()
g.FocusScopeStack.pop_back();
}
+// Note: this will likely be called ActivateItem() once we rework our Focus/Activation system!
void ImGui::SetKeyboardFocusHere(int offset)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
IM_ASSERT(offset >= -1); // -1 is allowed but not below
- g.NavWindow = window;
+ IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere(%d) in window \"%s\"\n", offset, window->Name);
+
+ // It makes sense in the vast majority of cases to never interrupt a drag and drop.
+ // When we refactor this function into ActivateItem() we may want to make this an option.
+ // MovingWindow is protected from most user inputs using SetActiveIdUsingNavAndKeys(), but
+ // is also automatically dropped in the event g.ActiveId is stolen.
+ if (g.DragDropActive || g.MovingWindow != NULL)
+ {
+ IMGUI_DEBUG_LOG_ACTIVEID("SetKeyboardFocusHere() ignored while DragDropActive!\n");
+ return;
+ }
+
+ SetNavWindow(window);
+
ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
NavMoveRequestSubmit(ImGuiDir_None, offset < 0 ? ImGuiDir_Up : ImGuiDir_Down, ImGuiNavMoveFlags_Tabbing | ImGuiNavMoveFlags_FocusApi, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
if (offset == -1)
@@ -7983,7 +8057,7 @@ void ImGui::PushID(const char* str_id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImGuiID id = window->GetIDNoKeepAlive(str_id);
+ ImGuiID id = window->GetID(str_id);
window->IDStack.push_back(id);
}
@@ -7991,7 +8065,7 @@ void ImGui::PushID(const char* str_id_begin, const char* str_id_end)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImGuiID id = window->GetIDNoKeepAlive(str_id_begin, str_id_end);
+ ImGuiID id = window->GetID(str_id_begin, str_id_end);
window->IDStack.push_back(id);
}
@@ -7999,7 +8073,7 @@ void ImGui::PushID(const void* ptr_id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImGuiID id = window->GetIDNoKeepAlive(ptr_id);
+ ImGuiID id = window->GetID(ptr_id);
window->IDStack.push_back(id);
}
@@ -8007,7 +8081,7 @@ void ImGui::PushID(int int_id)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
- ImGuiID id = window->GetIDNoKeepAlive(int_id);
+ ImGuiID id = window->GetID(int_id);
window->IDStack.push_back(id);
}
@@ -8027,7 +8101,6 @@ void ImGui::PushOverrideID(ImGuiID id)
ImGuiID ImGui::GetIDWithSeed(const char* str, const char* str_end, ImGuiID seed)
{
ImGuiID id = ImHashStr(str, str_end ? (str_end - str) : 0, seed);
- KeepAliveID(id);
ImGuiContext& g = *GImGui;
if (g.DebugHookIdInfo == id)
DebugHookIdInfo(id, ImGuiDataType_String, str, str_end);
@@ -8169,14 +8242,6 @@ const char* ImGui::GetKeyName(ImGuiKey key)
return GKeyNames[key - ImGuiKey_NamedKey_BEGIN];
}
-// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes.
-// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87)
-bool ImGui::IsKeyDown(ImGuiKey key)
-{
- const ImGuiKeyData* key_data = GetKeyData(key);
- return key_data->Down;
-}
-
// t0 = previous time (e.g.: g.Time - g.IO.DeltaTime)
// t1 = current time (e.g.: g.Time)
// An event is triggered at:
@@ -8203,22 +8268,35 @@ int ImGui::GetKeyPressedAmount(ImGuiKey key, float repeat_delay, float repeat_ra
return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, repeat_delay, repeat_rate);
}
+// Note that Dear ImGui doesn't know the meaning/semantic of ImGuiKey from 0..511: they are legacy native keycodes.
+// Consider transitioning from 'IsKeyDown(MY_ENGINE_KEY_A)' (<1.87) to IsKeyDown(ImGuiKey_A) (>= 1.87)
+bool ImGui::IsKeyDown(ImGuiKey key)
+{
+ const ImGuiKeyData* key_data = GetKeyData(key);
+ if (!key_data->Down)
+ return false;
+ return true;
+}
+
bool ImGui::IsKeyPressed(ImGuiKey key, bool repeat)
{
ImGuiContext& g = *GImGui;
const ImGuiKeyData* key_data = GetKeyData(key);
const float t = key_data->DownDuration;
- if (t == 0.0f)
- return true;
- if (repeat && t > g.IO.KeyRepeatDelay)
- return GetKeyPressedAmount(key, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
- return false;
+ if (t < 0.0f)
+ return false;
+ const bool pressed = (t == 0.0f) || (repeat && t > g.IO.KeyRepeatDelay && GetKeyPressedAmount(key, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0);
+ if (!pressed)
+ return false;
+ return true;
}
bool ImGui::IsKeyReleased(ImGuiKey key)
{
const ImGuiKeyData* key_data = GetKeyData(key);
- return key_data->DownDurationPrev >= 0.0f && !key_data->Down;
+ if (key_data->DownDurationPrev < 0.0f || key_data->Down)
+ return false;
+ return true;
}
bool ImGui::IsMouseDown(ImGuiMouseButton button)
@@ -8235,14 +8313,8 @@ bool ImGui::IsMouseClicked(ImGuiMouseButton button, bool repeat)
const float t = g.IO.MouseDownDuration[button];
if (t == 0.0f)
return true;
-
if (repeat && t > g.IO.KeyRepeatDelay)
- {
- // FIXME: 2019/05/03: Our old repeat code was wrong here and led to doubling the repeat rate, which made it an ok rate for repeat on mouse hold.
- int amount = CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate * 0.50f);
- if (amount > 0)
- return true;
- }
+ return CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
return false;
}
@@ -8359,27 +8431,39 @@ void ImGui::SetMouseCursor(ImGuiMouseCursor cursor_type)
g.MouseCursor = cursor_type;
}
-void ImGui::CaptureKeyboardFromApp(bool capture)
+void ImGui::SetNextFrameWantCaptureKeyboard(bool want_capture_keyboard)
{
ImGuiContext& g = *GImGui;
- g.WantCaptureKeyboardNextFrame = capture ? 1 : 0;
+ g.WantCaptureKeyboardNextFrame = want_capture_keyboard ? 1 : 0;
}
-void ImGui::CaptureMouseFromApp(bool capture)
+void ImGui::SetNextFrameWantCaptureMouse(bool want_capture_mouse)
{
ImGuiContext& g = *GImGui;
- g.WantCaptureMouseNextFrame = capture ? 1 : 0;
+ g.WantCaptureMouseNextFrame = want_capture_mouse ? 1 : 0;
}
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
static const char* GetInputSourceName(ImGuiInputSource source)
{
const char* input_source_names[] = { "None", "Mouse", "Keyboard", "Gamepad", "Nav", "Clipboard" };
IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT && source >= 0 && source < ImGuiInputSource_COUNT);
return input_source_names[source];
}
+#endif
+/*static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
+{
+ if (e->Type == ImGuiInputEventType_MousePos) { IMGUI_DEBUG_LOG_IO("%s: MousePos (%.1f %.1f)\n", prefix, e->MousePos.PosX, e->MousePos.PosY); return; }
+ if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("%s: MouseButton %d %s\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up"); return; }
+ if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("%s: MouseWheel (%.1f %.1f)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY); return; }
+ if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("%s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
+ if (e->Type == ImGuiInputEventType_Text) { IMGUI_DEBUG_LOG_IO("%s: Text: %c (U+%08X)\n", prefix, e->Text.Char, e->Text.Char); return; }
+ if (e->Type == ImGuiInputEventType_Focus) { IMGUI_DEBUG_LOG_IO("%s: AppFocused %d\n", prefix, e->AppFocused.Focused); return; }
+}*/
// Process input queue
+// We always call this with the value of 'bool g.IO.ConfigInputTrickleEventQueue'.
// - trickle_fast_inputs = false : process all events, turn into flattened input state (e.g. successive down/up/down/up will be lost)
// - trickle_fast_inputs = true : process as many events as possible (successive down/up/down/up will be trickled over several frames so nothing is lost) (new feature in 1.87)
void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
@@ -8387,7 +8471,12 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
- bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputed = false;
+ // 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);
+
+ bool mouse_moved = false, mouse_wheeled = false, key_changed = false, text_inputted = false;
int mouse_button_changed = 0x00;
ImBitArray<ImGuiKey_KeysData_SIZE> key_changed_mask;
@@ -8403,7 +8492,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
if (io.MousePos.x != event_pos.x || io.MousePos.y != event_pos.y)
{
// Trickling Rule: Stop processing queued events if we already handled a mouse button change
- if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputed))
+ if (trickle_fast_inputs && (mouse_button_changed != 0 || mouse_wheeled || key_changed || text_inputted))
break;
io.MousePos = event_pos;
mouse_moved = true;
@@ -8427,7 +8516,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
if (e->MouseWheel.WheelX != 0.0f || e->MouseWheel.WheelY != 0.0f)
{
// Trickling Rule: Stop processing queued events if we got multiple action on the event
- if (trickle_fast_inputs && (mouse_wheeled || mouse_button_changed != 0))
+ if (trickle_fast_inputs && (mouse_moved || mouse_button_changed != 0))
break;
io.MouseWheelH += e->MouseWheel.WheelX;
io.MouseWheel += e->MouseWheel.WheelY;
@@ -8447,7 +8536,7 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
if (keydata->Down != e->Key.Down || keydata->AnalogValue != e->Key.AnalogValue)
{
// Trickling Rule: Stop processing queued events if we got multiple action on the same button
- if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_changed_mask.TestBit(keydata_index) || text_inputed || mouse_button_changed != 0))
+ if (trickle_fast_inputs && keydata->Down != e->Key.Down && (key_changed_mask.TestBit(keydata_index) || text_inputted || mouse_button_changed != 0))
break;
keydata->Down = e->Key.Down;
keydata->AnalogValue = e->Key.AnalogValue;
@@ -8460,18 +8549,26 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
if (key == ImGuiKey_ModShift) { io.KeyShift = keydata->Down; }
if (key == ImGuiKey_ModAlt) { io.KeyAlt = keydata->Down; }
if (key == ImGuiKey_ModSuper) { io.KeySuper = keydata->Down; }
- io.KeyMods = GetMergedKeyModFlags();
+ io.KeyMods = GetMergedModFlags();
}
+
+ // Allow legacy code using io.KeysDown[GetKeyIndex()] with new backends
+#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
+ io.KeysDown[key] = keydata->Down;
+ if (io.KeyMap[key] != -1)
+ io.KeysDown[io.KeyMap[key]] = keydata->Down;
+#endif
}
}
- else if (e->Type == ImGuiInputEventType_Char)
+ else if (e->Type == ImGuiInputEventType_Text)
{
// Trickling Rule: Stop processing queued events if keys/mouse have been interacted with
- if (trickle_fast_inputs && (key_changed || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
+ if (trickle_fast_inputs && ((key_changed && trickle_interleaved_keys_and_text) || mouse_button_changed != 0 || mouse_moved || mouse_wheeled))
break;
unsigned int c = e->Text.Char;
io.InputQueueCharacters.push_back(c <= IM_UNICODE_CODEPOINT_MAX ? (ImWchar)c : IM_UNICODE_CODEPOINT_INVALID);
- text_inputed = true;
+ if (trickle_interleaved_keys_and_text)
+ text_inputted = true;
}
else if (e->Type == ImGuiInputEventType_Focus)
{
@@ -8486,10 +8583,15 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
}
// Record trail (for domain-specific applications wanting to access a precise trail)
- //if (event_n != 0) IMGUI_DEBUG_LOG("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
+ //if (event_n != 0) IMGUI_DEBUG_LOG_IO("Processed: %d / Remaining: %d\n", event_n, g.InputEventsQueue.Size - event_n);
for (int n = 0; n < event_n; n++)
g.InputEventsTrail.push_back(g.InputEventsQueue[n]);
+ // [DEBUG]
+ /*if (event_n != 0)
+ for (int n = 0; n < g.InputEventsQueue.Size; n++)
+ DebugPrintInputEvent(n < event_n ? "Processed" : "Remaining", &g.InputEventsQueue[n]);*/
+
// Remaining events will be processed on the next frame
if (event_n == g.InputEventsQueue.Size)
g.InputEventsQueue.resize(0);
@@ -8512,9 +8614,12 @@ void ImGui::UpdateInputEvents(bool trickle_fast_inputs)
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
-// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
-// may see different structures than what imgui.cpp sees, which is problematic.
-// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
+// If this triggers you have an issue:
+// - Most commonly: mismatched headers and compiled code version.
+// - Or: mismatched configuration #define, compilation settings, packing pragma etc.
+// The configuration settings mentioned in imconfig.h must be set for all compilation units involved with Dear ImGui,
+// which is way it is required you put them in your imconfig file (and not just before including imgui.h).
+// Otherwise it is possible that different compilation units would see different structure layout
bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
{
bool error = false;
@@ -8548,13 +8653,14 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
IM_ASSERT(g.IO.DisplaySize.x >= 0.0f && g.IO.DisplaySize.y >= 0.0f && "Invalid DisplaySize value!");
IM_ASSERT(g.IO.Fonts->IsBuilt() && "Font Atlas not built! Make sure you called ImGui_ImplXXXX_NewFrame() function for renderer backend, which should call io.Fonts->GetTexDataAsRGBA32() / GetTexDataAsAlpha8()");
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
- IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!");
+ IM_ASSERT(g.Style.CircleTessellationMaxError > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting!"); // Allows us to avoid a few clamps in color computations
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
+ IM_ASSERT(g.Style.ColorButtonPosition == ImGuiDir_Left || g.Style.ColorButtonPosition == ImGuiDir_Right);
#ifndef IMGUI_DISABLE_OBSOLETE_KEYIO
for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_COUNT; n++)
- IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)");
+ IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < ImGuiKey_LegacyNativeKey_END && "io.KeyMap[] contains an out of bound value (need to be 0..511, or -1 for unmapped key)");
// Check: required key mapping (we intentionally do NOT check all keys to not pressure user into setting up everything, but Space is required and was only added in 1.60 WIP)
if ((g.IO.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) && g.IO.BackendUsingLegacyKeyArrays == 1)
@@ -8616,11 +8722,11 @@ static void ImGui::ErrorCheckEndFrameSanityChecks()
// 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.
- const ImGuiKeyModFlags key_mod_flags = GetMergedKeyModFlags();
- IM_ASSERT((key_mod_flags == 0 || g.IO.KeyMods == key_mod_flags) && "Mismatching io.KeyCtrl/io.KeyShift/io.KeyAlt/io.KeySuper vs io.KeyMods");
- IM_UNUSED(key_mod_flags);
+ const ImGuiModFlags key_mods = GetMergedModFlags();
+ 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);
- // Recover from errors
+ // [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
@@ -8660,7 +8766,6 @@ void ImGui::ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, voi
IM_ASSERT(window->IsFallbackWindow);
break;
}
- IM_ASSERT(window == g.CurrentWindow);
if (window->Flags & ImGuiWindowFlags_ChildWindow)
{
if (log_callback) log_callback(user_data, "Recovered from missing EndChild() for '%s'", window->Name);
@@ -8803,7 +8908,7 @@ void ImGuiStackSizes::CompareWithCurrentState()
// - GetWindowContentRegionMin(), GetWindowContentRegionMax()
// - BeginGroup()
// - EndGroup()
-// Also see in imgui_widgets: tab bars, columns.
+// Also see in imgui_widgets: tab bars, and in imgui_tables: tables, columns.
//-----------------------------------------------------------------------------
// Advance cursor given item size for layout.
@@ -8820,14 +8925,16 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
// In theory we should be offsetting the starting position (window->DC.CursorPos), that will be the topic of a larger refactor,
// but since ItemSize() is not yet an API that moves the cursor (to handle e.g. wrapping) enlarging the height has the same effect.
const float offset_to_match_baseline_y = (text_baseline_y >= 0) ? ImMax(0.0f, window->DC.CurrLineTextBaseOffset - text_baseline_y) : 0.0f;
- const float line_height = ImMax(window->DC.CurrLineSize.y, size.y + offset_to_match_baseline_y);
+
+ const float line_y1 = window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y;
+ const float line_height = ImMax(window->DC.CurrLineSize.y, /*ImMax(*/window->DC.CursorPos.y - line_y1/*, 0.0f)*/ + size.y + offset_to_match_baseline_y);
// Always align ourselves on pixel boundaries
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
- window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
+ window->DC.CursorPosPrevLine.y = line_y1;
window->DC.CursorPos.x = IM_FLOOR(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x); // Next line
- window->DC.CursorPos.y = IM_FLOOR(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y); // Next line
+ window->DC.CursorPos.y = IM_FLOOR(line_y1 + line_height + g.Style.ItemSpacing.y); // Next line
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, window->DC.CursorPos.y - g.Style.ItemSpacing.y);
//if (g.IO.KeyAlt) window->DrawList->AddCircle(window->DC.CursorMaxPos, 3.0f, IM_COL32(255,0,0,255), 4); // [DEBUG]
@@ -8836,17 +8943,13 @@ void ImGui::ItemSize(const ImVec2& size, float text_baseline_y)
window->DC.CurrLineSize.y = 0.0f;
window->DC.PrevLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, text_baseline_y);
window->DC.CurrLineTextBaseOffset = 0.0f;
+ window->DC.IsSameLine = false;
// Horizontal layout mode
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
SameLine();
}
-void ImGui::ItemSize(const ImRect& bb, float text_baseline_y)
-{
- ItemSize(bb.GetSize(), text_baseline_y);
-}
-
// Declare item bounding box for clipping and interaction.
// 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.
@@ -8866,6 +8969,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// Directional navigation processing
if (id != 0)
{
+ KeepAliveID(id);
+
// Runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
// (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
@@ -8921,25 +9026,28 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// spacing_w >= 0 : enforce spacing amount
void ImGui::SameLine(float offset_from_start_x, float spacing_w)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
if (window->SkipItems)
return;
- ImGuiContext& g = *GImGui;
if (offset_from_start_x != 0.0f)
{
- if (spacing_w < 0.0f) spacing_w = 0.0f;
+ if (spacing_w < 0.0f)
+ spacing_w = 0.0f;
window->DC.CursorPos.x = window->Pos.x - window->Scroll.x + offset_from_start_x + spacing_w + window->DC.GroupOffset.x + window->DC.ColumnsOffset.x;
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
}
else
{
- if (spacing_w < 0.0f) spacing_w = g.Style.ItemSpacing.x;
+ if (spacing_w < 0.0f)
+ spacing_w = g.Style.ItemSpacing.x;
window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
}
window->DC.CurrLineSize = window->DC.PrevLineSize;
window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
+ window->DC.IsSameLine = true;
}
ImVec2 ImGui::GetCursorScreenPos()
@@ -9084,7 +9192,8 @@ 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)
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
ImVec2 region_max;
if (size.x < 0.0f || size.y < 0.0f)
@@ -9641,7 +9750,9 @@ ImGuiWindow* ImGui::GetTopMostAndVisiblePopupModal()
void ImGui::OpenPopup(const char* str_id, ImGuiPopupFlags popup_flags)
{
ImGuiContext& g = *GImGui;
- OpenPopupEx(g.CurrentWindow->GetID(str_id), popup_flags);
+ ImGuiID id = g.CurrentWindow->GetID(str_id);
+ IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopup(\"%s\" -> 0x%08X\n", str_id, id);
+ OpenPopupEx(id, popup_flags);
}
void ImGui::OpenPopup(ImGuiID id, ImGuiPopupFlags popup_flags)
@@ -9672,7 +9783,7 @@ void ImGui::OpenPopupEx(ImGuiID id, ImGuiPopupFlags popup_flags)
popup_ref.OpenPopupPos = NavCalcPreferredRefPos();
popup_ref.OpenMousePos = IsMousePosValid(&g.IO.MousePos) ? g.IO.MousePos : popup_ref.OpenPopupPos;
- IMGUI_DEBUG_LOG_POPUP("OpenPopupEx(0x%08X)\n", id);
+ IMGUI_DEBUG_LOG_POPUP("[popup] OpenPopupEx(0x%08X)\n", id);
if (g.OpenPopupStack.Size < current_stack_size + 1)
{
g.OpenPopupStack.push_back(popup_ref);
@@ -9742,7 +9853,7 @@ void ImGui::ClosePopupsOverWindow(ImGuiWindow* ref_window, bool restore_focus_to
}
if (popup_count_to_keep < g.OpenPopupStack.Size) // This test is not required but it allows to set a convenient breakpoint on the statement below
{
- IMGUI_DEBUG_LOG_POPUP("ClosePopupsOverWindow(\"%s\") -> ClosePopupToLevel(%d)\n", ref_window->Name, popup_count_to_keep);
+ IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupsOverWindow(\"%s\")\n", ref_window ? ref_window->Name : "<NULL>");
ClosePopupToLevel(popup_count_to_keep, restore_focus_to_window_under_popup);
}
}
@@ -9765,7 +9876,7 @@ void ImGui::ClosePopupsExceptModals()
void ImGui::ClosePopupToLevel(int remaining, bool restore_focus_to_window_under_popup)
{
ImGuiContext& g = *GImGui;
- IMGUI_DEBUG_LOG_POPUP("ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
+ IMGUI_DEBUG_LOG_POPUP("[popup] ClosePopupToLevel(%d), restore_focus_to_window_under_popup=%d\n", remaining, restore_focus_to_window_under_popup);
IM_ASSERT(remaining >= 0 && remaining < g.OpenPopupStack.Size);
// Trim open popup stack
@@ -9810,7 +9921,7 @@ void ImGui::CloseCurrentPopup()
break;
popup_idx--;
}
- IMGUI_DEBUG_LOG_POPUP("CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
+ IMGUI_DEBUG_LOG_POPUP("[popup] CloseCurrentPopup %d -> %d\n", g.BeginPopupStack.Size - 1, popup_idx);
ClosePopupToLevel(popup_idx, true);
// A common pattern is to close a popup when selecting a menu item/selectable that will open another window.
@@ -10126,8 +10237,22 @@ ImVec2 ImGui::FindBestWindowPosForPopup(ImGuiWindow* window)
// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
//-----------------------------------------------------------------------------
-// FIXME-NAV: The existence of SetNavID vs SetFocusID properly needs to be clarified/reworked.
-// In our terminology those should be interchangeable. Those two functions are merely a legacy artifact, so at minimum naming should be clarified.
+// FIXME-NAV: The existence of SetNavID vs SetFocusID vs FocusWindow() needs to be clarified/reworked.
+// In our terminology those should be interchangeable, yet right now this is super confusing.
+// Those two functions are merely a legacy artifact, so at minimum naming should be clarified.
+
+void ImGui::SetNavWindow(ImGuiWindow* window)
+{
+ ImGuiContext& g = *GImGui;
+ if (g.NavWindow != window)
+ {
+ IMGUI_DEBUG_LOG_FOCUS("[focus] SetNavWindow(\"%s\")\n", window ? window->Name : "<NULL>");
+ g.NavWindow = window;
+ }
+ g.NavInitRequest = g.NavMoveSubmitted = g.NavMoveScoringItems = false;
+ NavUpdateAnyRequestFlag();
+}
+
void ImGui::SetNavID(ImGuiID id, ImGuiNavLayer nav_layer, ImGuiID focus_scope_id, const ImRect& rect_rel)
{
ImGuiContext& g = *GImGui;
@@ -10145,12 +10270,12 @@ void ImGui::SetFocusID(ImGuiID id, ImGuiWindow* window)
ImGuiContext& g = *GImGui;
IM_ASSERT(id != 0);
+ if (g.NavWindow != window)
+ SetNavWindow(window);
+
// Assume that SetFocusID() is called in the context where its window->DC.NavLayerCurrent and window->DC.NavFocusScopeIdCurrent are valid.
// Note that window may be != g.CurrentWindow (e.g. SetFocusID call in InputTextEx for multi-line text)
const ImGuiNavLayer nav_layer = window->DC.NavLayerCurrent;
- if (g.NavWindow != window)
- g.NavInitRequest = false;
- g.NavWindow = window;
g.NavId = id;
g.NavLayer = nav_layer;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
@@ -10350,10 +10475,10 @@ static void ImGui::NavProcessItem()
const ImGuiItemFlags item_flags = g.LastItemData.InFlags;
// Process Init Request
- if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent)
+ if (g.NavInitRequest && g.NavLayer == window->DC.NavLayerCurrent && (item_flags & ImGuiItemFlags_Disabled) == 0)
{
// Even if 'ImGuiItemFlags_NoNavDefaultFocus' is on (typically collapse/close button) we record the first ResultId so they can be used as a fallback
- const bool candidate_for_nav_default_focus = (item_flags & (ImGuiItemFlags_NoNavDefaultFocus | ImGuiItemFlags_Disabled)) == 0;
+ const bool candidate_for_nav_default_focus = (item_flags & ImGuiItemFlags_NoNavDefaultFocus) == 0;
if (candidate_for_nav_default_focus || g.NavInitResultId == 0)
{
g.NavInitResultId = id;
@@ -10398,7 +10523,8 @@ static void ImGui::NavProcessItem()
// Update window-relative bounding box of navigated item
if (g.NavId == id)
{
- g.NavWindow = window; // Always refresh g.NavWindow, because some operations such as FocusItem() don't have a window.
+ if (g.NavWindow != window)
+ SetNavWindow(window); // Always refresh g.NavWindow, because some operations such as FocusItem() may not have a window.
g.NavLayer = window->DC.NavLayerCurrent;
g.NavFocusScopeId = window->DC.NavFocusScopeIdCurrent;
g.NavIdIsAlive = true;
@@ -10476,10 +10602,11 @@ void ImGui::NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavM
g.NavMoveScrollFlags = scroll_flags;
g.NavMoveForwardToNextFrame = false;
g.NavMoveKeyMods = g.IO.KeyMods;
- g.NavTabbingCounter = 0;
g.NavMoveResultLocal.Clear();
g.NavMoveResultLocalVisible.Clear();
g.NavMoveResultOther.Clear();
+ g.NavTabbingCounter = 0;
+ g.NavTabbingResultFirst.Clear();
NavUpdateAnyRequestFlag();
}
@@ -10549,7 +10676,12 @@ void ImGui::NavRestoreLayer(ImGuiNavLayer layer)
{
ImGuiContext& g = *GImGui;
if (layer == ImGuiNavLayer_Main)
- g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow);
+ {
+ ImGuiWindow* prev_nav_window = g.NavWindow;
+ g.NavWindow = NavRestoreLastChildNavWindow(g.NavWindow); // FIXME-NAV: Should clear ongoing nav requests?
+ if (prev_nav_window)
+ IMGUI_DEBUG_LOG_FOCUS("[focus] NavRestoreLayer: from \"%s\" to SetNavWindow(\"%s\")\n", prev_nav_window->Name, g.NavWindow->Name);
+ }
ImGuiWindow* window = g.NavWindow;
if (window->NavLastIds[layer] != 0)
{
@@ -10650,29 +10782,29 @@ const char* ImGui::GetNavInputName(ImGuiNavInput n)
return names[n];
}
-float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiInputReadMode mode)
+float ImGui::GetNavInputAmount(ImGuiNavInput n, ImGuiNavReadMode mode)
{
ImGuiContext& g = *GImGui;
- if (mode == ImGuiInputReadMode_Down)
+ if (mode == ImGuiNavReadMode_Down)
return g.IO.NavInputs[n]; // Instant, read analog input (0.0f..1.0f, as provided by user)
const float t = g.IO.NavInputsDownDuration[n];
- if (t < 0.0f && mode == ImGuiInputReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input.
+ if (t < 0.0f && mode == ImGuiNavReadMode_Released) // Return 1.0f when just released, no repeat, ignore analog input.
return (g.IO.NavInputsDownDurationPrev[n] >= 0.0f ? 1.0f : 0.0f);
if (t < 0.0f)
return 0.0f;
- if (mode == ImGuiInputReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
+ if (mode == ImGuiNavReadMode_Pressed) // Return 1.0f when just pressed, no repeat, ignore analog input.
return (t == 0.0f) ? 1.0f : 0.0f;
- if (mode == ImGuiInputReadMode_Repeat)
+ if (mode == ImGuiNavReadMode_Repeat)
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.80f);
- if (mode == ImGuiInputReadMode_RepeatSlow)
+ if (mode == ImGuiNavReadMode_RepeatSlow)
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 1.25f, g.IO.KeyRepeatRate * 2.00f);
- if (mode == ImGuiInputReadMode_RepeatFast)
+ if (mode == ImGuiNavReadMode_RepeatFast)
return (float)CalcTypematicRepeatAmount(t - g.IO.DeltaTime, t, g.IO.KeyRepeatDelay * 0.72f, g.IO.KeyRepeatRate * 0.30f);
return 0.0f;
}
-ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInputReadMode mode, float slow_factor, float fast_factor)
+ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiNavReadMode mode, float slow_factor, float fast_factor)
{
ImVec2 delta(0.0f, 0.0f);
if (dir_sources & ImGuiNavDirSourceFlags_RawKeyboard)
@@ -10696,7 +10828,7 @@ static void ImGui::NavUpdate()
ImGuiIO& io = g.IO;
io.WantSetMousePos = false;
- //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG("NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
+ //if (g.NavScoringDebugCount > 0) IMGUI_DEBUG_LOG_NAV("[nav] NavScoringDebugCount %d for '%s' layer %d (Init:%d, Move:%d)\n", g.NavScoringDebugCount, g.NavWindow ? g.NavWindow->Name : "NULL", g.NavLayer, g.NavInitRequest || g.NavInitResultId != 0, g.NavMoveRequest);
// Update Gamepad->Nav inputs mapping
// Set input source as Gamepad when buttons are pressed (as some features differs when used with Gamepad vs Keyboard)
@@ -10792,8 +10924,8 @@ static void ImGui::NavUpdate()
{
bool activate_down = IsNavInputDown(ImGuiNavInput_Activate);
bool input_down = IsNavInputDown(ImGuiNavInput_Input);
- bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiInputReadMode_Pressed);
- bool input_pressed = input_down && IsNavInputTest(ImGuiNavInput_Input, ImGuiInputReadMode_Pressed);
+ bool activate_pressed = activate_down && IsNavInputTest(ImGuiNavInput_Activate, ImGuiNavReadMode_Pressed);
+ bool input_pressed = input_down && IsNavInputTest(ImGuiNavInput_Input, ImGuiNavReadMode_Pressed);
if (g.ActiveId == 0 && activate_pressed)
{
g.NavActivateId = g.NavId;
@@ -10850,7 +10982,7 @@ static void ImGui::NavUpdate()
// *Normal* Manual scroll with NavScrollXXX keys
// Next movement request will clamp the NavId reference rectangle to the visible area, so navigation will resume within those bounds.
- ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f / 10.0f, 10.0f);
+ ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiNavReadMode_Down, 1.0f / 10.0f, 10.0f);
if (scroll_dir.x != 0.0f && window->ScrollbarX)
SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
if (scroll_dir.y != 0.0f)
@@ -10870,7 +11002,7 @@ static void ImGui::NavUpdate()
{
io.MousePos = io.MousePosPrev = NavCalcPreferredRefPos();
io.WantSetMousePos = true;
- //IMGUI_DEBUG_LOG("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y);
+ //IMGUI_DEBUG_LOG_IO("SetMousePos: (%.1f,%.1f)\n", io.MousePos.x, io.MousePos.y);
}
// [DEBUG]
@@ -10894,7 +11026,7 @@ void ImGui::NavInitRequestApplyResult()
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
// FIXME-NAV: On _NavFlattened windows, g.NavWindow will only be updated during subsequent frame. Not a problem currently.
- IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: result NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
+ IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: ApplyResult: NavID 0x%08X in Layer %d Window \"%s\"\n", g.NavInitResultId, g.NavLayer, g.NavWindow->Name);
SetNavID(g.NavInitResultId, g.NavLayer, 0, g.NavInitResultRectRel);
g.NavIdIsAlive = true; // Mark as alive from previous frame as we got a result
if (g.NavInitRequestFromMove)
@@ -10923,7 +11055,7 @@ void ImGui::NavUpdateCreateMoveRequest()
g.NavMoveScrollFlags = ImGuiScrollFlags_None;
if (window && !g.NavWindowingTarget && !(window->Flags & ImGuiWindowFlags_NoNavInputs))
{
- const ImGuiInputReadMode read_mode = ImGuiInputReadMode_Repeat;
+ const ImGuiNavReadMode read_mode = ImGuiNavReadMode_Repeat;
if (!IsActiveIdUsingNavDir(ImGuiDir_Left) && (IsNavInputTest(ImGuiNavInput_DpadLeft, read_mode) || IsNavInputTest(ImGuiNavInput_KeyLeft_, read_mode))) { g.NavMoveDir = ImGuiDir_Left; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Right) && (IsNavInputTest(ImGuiNavInput_DpadRight, read_mode) || IsNavInputTest(ImGuiNavInput_KeyRight_, read_mode))) { g.NavMoveDir = ImGuiDir_Right; }
if (!IsActiveIdUsingNavDir(ImGuiDir_Up) && (IsNavInputTest(ImGuiNavInput_DpadUp, read_mode) || IsNavInputTest(ImGuiNavInput_KeyUp_, read_mode))) { g.NavMoveDir = ImGuiDir_Up; }
@@ -10964,7 +11096,7 @@ void ImGui::NavUpdateCreateMoveRequest()
// Moving with no reference triggers a init request (will be used as a fallback if the direction fails to find a match)
if (g.NavMoveSubmitted && g.NavId == 0)
{
- IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", g.NavWindow->Name, g.NavLayer);
+ IMGUI_DEBUG_LOG_NAV("[nav] NavInitRequest: from move, window \"%s\", layer=%d\n", window ? window->Name : "<NULL>", g.NavLayer);
g.NavInitRequest = g.NavInitRequestFromMove = true;
g.NavInitResultId = 0;
g.NavDisableHighlight = false;
@@ -10980,7 +11112,7 @@ void ImGui::NavUpdateCreateMoveRequest()
ImRect inner_rect_rel = WindowRectAbsToRel(window, ImRect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1)));
if ((clamp_x || clamp_y) && !inner_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
- IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
+ //IMGUI_DEBUG_LOG_NAV("[nav] NavMoveRequest: clamp NavRectRel for gamepad move\n");
float pad_x = ImMin(inner_rect_rel.GetWidth(), window->CalcFontSize() * 0.5f);
float pad_y = ImMin(inner_rect_rel.GetHeight(), window->CalcFontSize() * 0.5f); // Terrible approximation for the intent of starting navigation from first fully visible item
inner_rect_rel.Min.x = clamp_x ? (inner_rect_rel.Min.x + pad_x) : -FLT_MAX;
@@ -11030,7 +11162,6 @@ void ImGui::NavUpdateCreateTabbingRequest()
ImGuiScrollFlags scroll_flags = window->Appearing ? ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_AlwaysCenterY : ImGuiScrollFlags_KeepVisibleEdgeX | ImGuiScrollFlags_KeepVisibleEdgeY;
ImGuiDir clip_dir = (g.NavTabbingDir < 0) ? ImGuiDir_Up : ImGuiDir_Down;
NavMoveRequestSubmit(ImGuiDir_None, clip_dir, ImGuiNavMoveFlags_Tabbing, scroll_flags); // FIXME-NAV: Once we refactor tabbing, add LegacyApi flag to not activate non-inputable.
- g.NavTabbingResultFirst.Clear();
g.NavTabbingCounter = -1;
}
@@ -11088,7 +11219,11 @@ void ImGui::NavMoveRequestApplyResult()
}
}
- g.NavWindow = result->Window;
+ if (g.NavWindow != result->Window)
+ {
+ IMGUI_DEBUG_LOG_FOCUS("[focus] NavMoveRequest: SetNavWindow(\"%s\")\n", result->Window->Name);
+ g.NavWindow = result->Window;
+ }
if (g.ActiveId != result->ID)
ClearActiveID();
if (g.NavId != result->ID)
@@ -11130,7 +11265,7 @@ void ImGui::NavMoveRequestApplyResult()
static void ImGui::NavUpdateCancelRequest()
{
ImGuiContext& g = *GImGui;
- if (!IsNavInputTest(ImGuiNavInput_Cancel, ImGuiInputReadMode_Pressed))
+ if (!IsNavInputTest(ImGuiNavInput_Cancel, ImGuiNavReadMode_Pressed))
return;
IMGUI_DEBUG_LOG_NAV("[nav] ImGuiNavInput_Cancel\n");
@@ -11156,11 +11291,10 @@ static void ImGui::NavUpdateCancelRequest()
SetNavID(child_window->ChildId, ImGuiNavLayer_Main, 0, WindowRectAbsToRel(parent_window, child_rect));
NavRestoreHighlightAfterMove();
}
- else if (g.OpenPopupStack.Size > 0)
+ else if (g.OpenPopupStack.Size > 0 && !(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
{
// Close open popup/menu
- if (!(g.OpenPopupStack.back().Window->Flags & ImGuiWindowFlags_Modal))
- ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
+ ClosePopupToLevel(g.OpenPopupStack.Size - 1, true);
}
else
{
@@ -11380,7 +11514,7 @@ static void ImGui::NavUpdateWindowing()
}
// Start CTRL+Tab or Square+L/R window selection
- const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiInputReadMode_Pressed);
+ const bool start_windowing_with_gamepad = allow_windowing && !g.NavWindowingTarget && IsNavInputTest(ImGuiNavInput_Menu, ImGuiNavReadMode_Pressed);
const bool start_windowing_with_keyboard = allow_windowing && !g.NavWindowingTarget && io.KeyCtrl && IsKeyPressed(ImGuiKey_Tab);
if (start_windowing_with_gamepad || start_windowing_with_keyboard)
if (ImGuiWindow* window = g.NavWindow ? g.NavWindow : FindWindowNavFocusable(g.WindowsFocusOrder.Size - 1, -INT_MAX, -1))
@@ -11399,7 +11533,7 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingHighlightAlpha = ImMax(g.NavWindowingHighlightAlpha, ImSaturate((g.NavWindowingTimer - NAV_WINDOWING_HIGHLIGHT_DELAY) / 0.05f));
// Select window to focus
- const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiInputReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiInputReadMode_RepeatSlow);
+ const int focus_change_dir = (int)IsNavInputTest(ImGuiNavInput_FocusPrev, ImGuiNavReadMode_RepeatSlow) - (int)IsNavInputTest(ImGuiNavInput_FocusNext, ImGuiNavReadMode_RepeatSlow);
if (focus_change_dir != 0)
{
NavUpdateWindowingHighlightWindow(focus_change_dir);
@@ -11433,7 +11567,7 @@ static void ImGui::NavUpdateWindowing()
// - Testing that only Alt is tested prevents Alt+Shift or AltGR from toggling menu layer.
// - AltGR is normally Alt+Ctrl but we can't reliably detect it (not all backends/systems/layout emit it as Alt+Ctrl). But even on keyboards without AltGR we don't want Alt+Ctrl to open menu anyway.
const bool nav_keyboard_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableKeyboard) != 0;
- if (nav_keyboard_active && io.KeyMods == ImGuiKeyModFlags_Alt && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) == 0)
+ if (nav_keyboard_active && IsKeyPressed(ImGuiKey_ModAlt))
{
g.NavWindowingToggleLayer = true;
g.NavInputSource = ImGuiInputSource_Keyboard;
@@ -11446,13 +11580,12 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingToggleLayer = false;
// Apply layer toggle on release
- // Important: we don't assume that Alt was previously held in order to handle loss of focus when backend calls io.AddFocusEvent(false)
// Important: as before version <18314 we lacked an explicit IO event for focus gain/loss, we also compare mouse validity to detect old backends clearing mouse pos on focus loss.
- if (!(io.KeyMods & ImGuiKeyModFlags_Alt) && (io.KeyModsPrev & ImGuiKeyModFlags_Alt) && g.NavWindowingToggleLayer)
+ if (IsKeyReleased(ImGuiKey_ModAlt) && g.NavWindowingToggleLayer)
if (g.ActiveId == 0 || g.ActiveIdAllowOverlap)
if (IsMousePosValid(&io.MousePos) == IsMousePosValid(&io.MousePosPrev))
apply_toggle_layer = true;
- if (!io.KeyAlt)
+ if (!IsKeyDown(ImGuiKey_ModAlt))
g.NavWindowingToggleLayer = false;
}
@@ -11461,16 +11594,15 @@ static void ImGui::NavUpdateWindowing()
{
ImVec2 move_delta;
if (g.NavInputSource == ImGuiInputSource_Keyboard && !io.KeyShift)
- move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiInputReadMode_Down);
+ move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_RawKeyboard, ImGuiNavReadMode_Down);
if (g.NavInputSource == ImGuiInputSource_Gamepad)
- move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down);
+ move_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiNavReadMode_Down);
if (move_delta.x != 0.0f || move_delta.y != 0.0f)
{
const float NAV_MOVE_SPEED = 800.0f;
const float move_speed = ImFloor(NAV_MOVE_SPEED * io.DeltaTime * ImMin(io.DisplayFramebufferScale.x, io.DisplayFramebufferScale.y)); // FIXME: Doesn't handle variable framerate very well
ImGuiWindow* moving_window = g.NavWindowingTarget->RootWindowDockTree;
SetWindowPos(moving_window, moving_window->Pos + move_delta * move_speed, ImGuiCond_Always);
- MarkIniSettingsDirty(moving_window);
g.NavDisableMouseHover = true;
}
}
@@ -11585,6 +11717,12 @@ void ImGui::NavUpdateWindowingOverlay()
// [SECTION] DRAG AND DROP
//-----------------------------------------------------------------------------
+bool ImGui::IsDragDropActive()
+{
+ ImGuiContext& g = *GImGui;
+ return g.DragDropActive;
+}
+
void ImGui::ClearDragDrop()
{
ImGuiContext& g = *GImGui;
@@ -11654,6 +11792,7 @@ bool ImGui::BeginDragDropSource(ImGuiDragDropFlags flags)
// We don't need to maintain/call ClearActiveID() as releasing the button will early out this function and trigger !ActiveIdIsAlive.
// Rely on keeping other window->LastItemXXX fields intact.
source_id = g.LastItemData.ID = window->GetIDFromRectangle(g.LastItemData.Rect);
+ KeepAliveID(source_id);
bool is_hovered = ItemHoverable(g.LastItemData.Rect, source_id);
if (is_hovered && g.IO.MouseClicked[mouse_button])
{
@@ -11820,7 +11959,10 @@ bool ImGui::BeginDragDropTarget()
const ImRect& display_rect = (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HasDisplayRect) ? g.LastItemData.DisplayRect : g.LastItemData.Rect;
ImGuiID id = g.LastItemData.ID;
if (id == 0)
+ {
id = window->GetIDFromRectangle(display_rect);
+ KeepAliveID(id);
+ }
if (g.DragDropPayload.SourceId == id)
return false;
@@ -12234,6 +12376,20 @@ ImGuiWindowSettings* ImGui::FindOrCreateWindowSettings(const char* name)
return CreateNewWindowSettings(name);
}
+void ImGui::AddSettingsHandler(const ImGuiSettingsHandler* handler)
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(FindSettingsHandler(handler->TypeName) == NULL);
+ g.SettingsHandlers.push_back(*handler);
+}
+
+void ImGui::RemoveSettingsHandler(const char* type_name)
+{
+ ImGuiContext& g = *GImGui;
+ if (ImGuiSettingsHandler* handler = FindSettingsHandler(type_name))
+ g.SettingsHandlers.erase(handler);
+}
+
ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
{
ImGuiContext& g = *GImGui;
@@ -12259,7 +12415,8 @@ void ImGui::LoadIniSettingsFromDisk(const char* ini_filename)
char* file_data = (char*)ImFileLoadToMemory(ini_filename, "rb", &file_data_size);
if (!file_data)
return;
- LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
+ if (file_data_size > 0)
+ LoadIniSettingsFromMemory(file_data, (size_t)file_data_size);
IM_FREE(file_data);
}
@@ -12538,7 +12695,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view
return;
g.CurrentDpiScale = viewport ? viewport->DpiScale : 1.0f;
g.CurrentViewport = viewport;
- //IMGUI_DEBUG_LOG_VIEWPORT("SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
+ //IMGUI_DEBUG_LOG_VIEWPORT("[viewport] SetCurrentViewport changed '%s' 0x%08X\n", current_window ? current_window->Name : NULL, viewport ? viewport->ID : 0);
// Notify platform layer of viewport changes
// FIXME-DPI: This is only currently used for experimenting with handling of multiple DPI
@@ -12546,7 +12703,7 @@ void ImGui::SetCurrentViewport(ImGuiWindow* current_window, ImGuiViewportP* view
g.PlatformIO.Platform_OnChangedViewport(g.CurrentViewport);
}
-static void SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport)
+void ImGui::SetWindowViewport(ImGuiWindow* window, ImGuiViewportP* viewport)
{
// Abandon viewport
if (window->ViewportOwned && window->Viewport->Window == window)
@@ -12884,9 +13041,10 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
ImGuiViewportP* viewport = (ImGuiViewportP*)FindViewportByID(id);
if (viewport)
{
- if (!viewport->PlatformRequestMove)
+ // Always update for main viewport as we are already pulling correct platform pos/size (see #4900)
+ if (!viewport->PlatformRequestMove || viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID)
viewport->Pos = pos;
- if (!viewport->PlatformRequestResize)
+ if (!viewport->PlatformRequestResize || viewport->ID == IMGUI_VIEWPORT_DEFAULT_ID)
viewport->Size = size;
viewport->Flags = flags | (viewport->Flags & ImGuiViewportFlags_Minimized); // Preserve existing flags
}
@@ -12901,7 +13059,7 @@ ImGuiViewportP* ImGui::AddUpdateViewport(ImGuiWindow* window, ImGuiID id, const
viewport->Flags = flags;
UpdateViewportPlatformMonitor(viewport);
g.Viewports.push_back(viewport);
- IMGUI_DEBUG_LOG_VIEWPORT("Add Viewport %08X (%s)\n", id, window->Name);
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Add Viewport %08X '%s'\n", id, window ? window->Name : "<NULL>");
// We normally setup for all viewports in NewFrame() but here need to handle the mid-frame creation of a new viewport.
// We need to extend the fullscreen clip rect so the OverlayDrawList clip is correct for that the first frame
@@ -12943,7 +13101,7 @@ static void ImGui::DestroyViewport(ImGuiViewportP* viewport)
g.MouseLastHoveredViewport = NULL;
// Destroy
- IMGUI_DEBUG_LOG_VIEWPORT("Delete Viewport %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Delete Viewport %08X '%s'\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
DestroyPlatformWindow(viewport); // In most circumstances the platform window will already be destroyed here.
IM_ASSERT(g.PlatformIO.Viewports.contains(viewport) == false);
IM_ASSERT(g.Viewports[viewport->Idx] == viewport);
@@ -13059,7 +13217,7 @@ static void ImGui::WindowSelectViewport(ImGuiWindow* window)
if ((window->Flags & ImGuiWindowFlags_DockNodeHost) && window->Viewport->LastFrameActive < g.FrameCount && will_be_visible)
{
// Steal/transfer ownership
- IMGUI_DEBUG_LOG_VIEWPORT("Window '%s' steal Viewport %08X from Window '%s'\n", window->Name, window->Viewport->ID, window->Viewport->Window->Name);
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Window '%s' steal Viewport %08X from Window '%s'\n", window->Name, window->Viewport->ID, window->Viewport->Window->Name);
window->Viewport->Window = window;
window->Viewport->ID = window->ID;
window->Viewport->LastNameHash = 0;
@@ -13209,7 +13367,7 @@ void ImGui::UpdatePlatformWindows()
bool is_new_platform_window = (viewport->PlatformWindowCreated == false);
if (is_new_platform_window)
{
- IMGUI_DEBUG_LOG_VIEWPORT("Create Platform Window %08X (%s)\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Create Platform Window %08X '%s'\n", viewport->ID, viewport->Window ? viewport->Window->Name : "n/a");
g.PlatformIO.Platform_CreateWindow(viewport);
if (g.PlatformIO.Renderer_CreateWindow != NULL)
g.PlatformIO.Renderer_CreateWindow(viewport);
@@ -13698,8 +13856,9 @@ void ImGui::DockContextClearNodes(ImGuiContext* ctx, ImGuiID root_id, bool clear
// (Different from DockSettingsHandler_ClearAll() + DockSettingsHandler_ApplyAll() because this reuses current settings!)
void ImGui::DockContextRebuildNodes(ImGuiContext* ctx)
{
- IMGUI_DEBUG_LOG_DOCKING("DockContextRebuild()\n");
- ImGuiDockContext* dc = &ctx->DockContext;
+ ImGuiContext& g = *ctx;
+ ImGuiDockContext* dc = &ctx->DockContext;
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextRebuildNodes\n");
SaveIniSettingsToMemory();
ImGuiID root_id = 0; // Rebuild all
DockContextClearNodes(ctx, root_id, false);
@@ -13711,7 +13870,7 @@ void ImGui::DockContextRebuildNodes(ImGuiContext* ctx)
void ImGui::DockContextNewFrameUpdateUndocking(ImGuiContext* ctx)
{
ImGuiContext& g = *ctx;
- ImGuiDockContext* dc = &ctx->DockContext;
+ ImGuiDockContext* dc = &ctx->DockContext;
if (!(g.IO.ConfigFlags & ImGuiConfigFlags_DockingEnable))
{
if (dc->Nodes.Data.Size > 0 || dc->Requests.Size > 0)
@@ -13820,13 +13979,14 @@ ImGuiID ImGui::DockContextGenNodeID(ImGuiContext* ctx)
static ImGuiDockNode* ImGui::DockContextAddNode(ImGuiContext* ctx, ImGuiID id)
{
// Generate an ID for the new node (the exact ID value doesn't matter as long as it is not already used) and add the first window.
+ ImGuiContext& g = *ctx;
if (id == 0)
id = DockContextGenNodeID(ctx);
else
IM_ASSERT(DockContextFindNodeByID(ctx, id) == NULL);
// We don't set node->LastFrameAlive on construction. Nodes are always created at all time to reflect .ini settings!
- IMGUI_DEBUG_LOG_DOCKING("DockContextAddNode 0x%08X\n", id);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextAddNode 0x%08X\n", id);
ImGuiDockNode* node = IM_NEW(ImGuiDockNode)(id);
ctx->DockContext.Nodes.SetVoidPtr(node->ID, node);
return node;
@@ -13837,7 +13997,7 @@ static void ImGui::DockContextRemoveNode(ImGuiContext* ctx, ImGuiDockNode* node,
ImGuiContext& g = *ctx;
ImGuiDockContext* dc = &ctx->DockContext;
- IMGUI_DEBUG_LOG_DOCKING("DockContextRemoveNode 0x%08X\n", node->ID);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextRemoveNode 0x%08X\n", node->ID);
IM_ASSERT(DockContextFindNodeByID(ctx, node->ID) == node);
IM_ASSERT(node->ChildNodes[0] == NULL && node->ChildNodes[1] == NULL);
IM_ASSERT(node->Windows.Size == 0);
@@ -13936,7 +14096,7 @@ static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx)
remove |= (data_root->CountChildWindows == 0);
if (remove)
{
- IMGUI_DEBUG_LOG_DOCKING("DockContextPruneUnusedSettingsNodes: Prune 0x%08X\n", settings->ID);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextPruneUnusedSettingsNodes: Prune 0x%08X\n", settings->ID);
DockSettingsRemoveNodeReferences(&settings->ID, 1);
settings->ID = 0;
}
@@ -14055,9 +14215,9 @@ void ImGui::DockContextProcessDock(ImGuiContext* ctx, ImGuiDockRequest* req)
ImGuiWindow* target_window = req->DockTargetWindow;
ImGuiDockNode* node = req->DockTargetNode;
if (payload_window)
- IMGUI_DEBUG_LOG_DOCKING("DockContextProcessDock node 0x%08X target '%s' dock window '%s', split_dir %d\n", node ? node->ID : 0, target_window ? target_window->Name : "NULL", payload_window ? payload_window->Name : "NULL", req->DockSplitDir);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessDock node 0x%08X target '%s' dock window '%s', split_dir %d\n", node ? node->ID : 0, target_window ? target_window->Name : "NULL", payload_window ? payload_window->Name : "NULL", req->DockSplitDir);
else
- IMGUI_DEBUG_LOG_DOCKING("DockContextProcessDock node 0x%08X, split_dir %d\n", node ? node->ID : 0, req->DockSplitDir);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessDock node 0x%08X, split_dir %d\n", node ? node->ID : 0, req->DockSplitDir);
// Decide which Tab will be selected at the end of the operation
ImGuiID next_selected_id = 0;
@@ -14206,8 +14366,8 @@ static ImVec2 FixLargeWindowsWhenUndocking(const ImVec2& size, ImGuiViewport* re
void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* window, bool clear_persistent_docking_ref)
{
- IMGUI_DEBUG_LOG_DOCKING("DockContextProcessUndockWindow window '%s', clear_persistent_docking_ref = %d\n", window->Name, clear_persistent_docking_ref);
- IM_UNUSED(ctx);
+ ImGuiContext& g = *ctx;
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessUndockWindow window '%s', clear_persistent_docking_ref = %d\n", window->Name, clear_persistent_docking_ref);
if (window->DockNode)
DockNodeRemoveWindow(window->DockNode, window, clear_persistent_docking_ref ? 0 : window->DockId);
else
@@ -14222,7 +14382,8 @@ void ImGui::DockContextProcessUndockWindow(ImGuiContext* ctx, ImGuiWindow* windo
void ImGui::DockContextProcessUndockNode(ImGuiContext* ctx, ImGuiDockNode* node)
{
- IMGUI_DEBUG_LOG_DOCKING("DockContextProcessUndockNode node %08X\n", node->ID);
+ ImGuiContext& g = *ctx;
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockContextProcessUndockNode node %08X\n", node->ID);
IM_ASSERT(node->IsLeafNode());
IM_ASSERT(node->Windows.Size >= 1);
@@ -14366,7 +14527,7 @@ static void ImGui::DockNodeAddWindow(ImGuiDockNode* node, ImGuiWindow* window, b
DockNodeRemoveWindow(window->DockNode, window, 0);
}
IM_ASSERT(window->DockNode == NULL || window->DockNodeAsHost == NULL);
- IMGUI_DEBUG_LOG_DOCKING("DockNodeAddWindow node 0x%08X window '%s'\n", node->ID, window->Name);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeAddWindow node 0x%08X window '%s'\n", node->ID, window->Name);
// If more than 2 windows appeared on the same frame leading to the creation of a new hosting window,
// we'll hide windows until the host window is ready. Hide the 1st window after its been output (so it is not visible for one frame).
@@ -14422,7 +14583,7 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window
//IM_ASSERT(window->RootWindowDockTree == node->HostWindow);
//IM_ASSERT(window->LastFrameActive < g.FrameCount); // We may call this from Begin()
IM_ASSERT(save_dock_id == 0 || save_dock_id == node->ID);
- IMGUI_DEBUG_LOG_DOCKING("DockNodeRemoveWindow node 0x%08X window '%s'\n", node->ID, window->Name);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeRemoveWindow node 0x%08X window '%s'\n", node->ID, window->Name);
window->DockNode = NULL;
window->DockIsActive = window->DockTabWantClose = false;
@@ -14469,7 +14630,7 @@ static void ImGui::DockNodeRemoveWindow(ImGuiDockNode* node, ImGuiWindow* window
if (node->HostWindow->ViewportOwned && node->IsRootNode())
{
// Transfer viewport back to the remaining loose window
- IMGUI_DEBUG_LOG_VIEWPORT("Node %08X transfer Viewport %08X=>%08X for Window '%s'\n", node->ID, node->HostWindow->Viewport->ID, remaining_window->ID, remaining_window->Name);
+ IMGUI_DEBUG_LOG_VIEWPORT("[viewport] Node %08X transfer Viewport %08X=>%08X for Window '%s'\n", node->ID, node->HostWindow->Viewport->ID, remaining_window->ID, remaining_window->Name);
IM_ASSERT(node->HostWindow->Viewport->Window == node->HostWindow);
node->HostWindow->Viewport->Window = remaining_window;
node->HostWindow->Viewport->ID = remaining_window->ID;
@@ -15133,6 +15294,21 @@ void ImGui::DockNodeEndAmendTabBar()
End();
}
+static bool IsDockNodeTitleBarHighlighted(ImGuiDockNode* node, ImGuiDockNode* root_node, ImGuiWindow* host_window)
+{
+ // CTRL+Tab highlight (only highlighting leaf node, not whole hierarchy)
+ ImGuiContext& g = *GImGui;
+ if (g.NavWindowingTarget)
+ return (g.NavWindowingTarget->DockNode == node);
+
+ // FIXME-DOCKING: May want alternative to treat central node void differently? e.g. if (g.NavWindow == host_window)
+ if (g.NavWindow && g.NavWindow->RootWindowForTitleBarHighlight == host_window->RootWindowDockTree && root_node->LastFocusedNodeId == node->ID)
+ for (ImGuiDockNode* parent_node = g.NavWindow->RootWindow->DockNode; parent_node != NULL; parent_node = parent_node->HostWindow ? parent_node->HostWindow->RootWindow->DockNode : NULL)
+ if ((parent_node = ImGui::DockNodeGetRootNode(parent_node)) == root_node)
+ return true;
+ return false;
+}
+
// Submit the tab bar corresponding to a dock node and various housekeeping details.
static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_window)
{
@@ -15148,9 +15324,7 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
// Decide if we should use a focused title bar color
bool is_focused = false;
ImGuiDockNode* root_node = DockNodeGetRootNode(node);
- if (g.NavWindowingTarget)
- is_focused = (g.NavWindowingTarget->DockNode == node);
- else if (g.NavWindow && g.NavWindow->RootWindowForTitleBarHighlight == host_window->RootWindowDockTree && root_node->LastFocusedNodeId == node->ID)
+ if (IsDockNodeTitleBarHighlighted(node, root_node, host_window))
is_focused = true;
// Hidden tab bar will show a triangle on the upper-left (in Begin)
@@ -15247,9 +15421,9 @@ static void ImGui::DockNodeUpdateTabBar(ImGuiDockNode* node, ImGuiWindow* host_w
}
if (tab_bar->Tabs.Size > tabs_unsorted_start)
{
- IMGUI_DEBUG_LOG_DOCKING("In node 0x%08X: %d new appearing tabs:%s\n", node->ID, tab_bar->Tabs.Size - tabs_unsorted_start, (tab_bar->Tabs.Size > tabs_unsorted_start + 1) ? " (will sort)" : "");
+ IMGUI_DEBUG_LOG_DOCKING("[docking] In node 0x%08X: %d new appearing tabs:%s\n", node->ID, tab_bar->Tabs.Size - tabs_unsorted_start, (tab_bar->Tabs.Size > tabs_unsorted_start + 1) ? " (will sort)" : "");
for (int tab_n = tabs_unsorted_start; tab_n < tab_bar->Tabs.Size; tab_n++)
- IMGUI_DEBUG_LOG_DOCKING(" - Tab '%s' Order %d\n", tab_bar->Tabs[tab_n].Window->Name, tab_bar->Tabs[tab_n].Window->DockOrder);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] - Tab '%s' Order %d\n", tab_bar->Tabs[tab_n].Window->Name, tab_bar->Tabs[tab_n].Window->DockOrder);
if (tab_bar->Tabs.Size > tabs_unsorted_start + 1)
ImQsort(tab_bar->Tabs.Data + tabs_unsorted_start, tab_bar->Tabs.Size - tabs_unsorted_start, sizeof(ImGuiTabItem), TabItemComparerByDockOrder);
}
@@ -15598,7 +15772,7 @@ static void ImGui::DockNodePreviewDockSetup(ImGuiWindow* host_window, ImGuiDockN
ImGuiDockNode* root_payload_as_host = root_payload->DockNodeAsHost;
ImGuiDockNode* ref_node_for_rect = (host_node && !host_node->IsVisible) ? DockNodeGetRootNode(host_node) : host_node;
if (ref_node_for_rect)
- IM_ASSERT(ref_node_for_rect->IsVisible);
+ IM_ASSERT(ref_node_for_rect->IsVisible == true);
// Filter, figure out where we are allowed to dock
ImGuiDockNodeFlags src_node_flags = root_payload_as_host ? root_payload_as_host->MergedFlags : root_payload->WindowClass.DockNodeFlagsOverrideSet;
@@ -15850,6 +16024,7 @@ void ImGui::DockNodeTreeSplit(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImGuiDockNode* merge_lead_child)
{
// When called from DockContextProcessUndockNode() it is possible that one of the child is NULL.
+ ImGuiContext& g = *GImGui;
ImGuiDockNode* child_0 = parent_node->ChildNodes[0];
ImGuiDockNode* child_1 = parent_node->ChildNodes[1];
IM_ASSERT(child_0 || child_1);
@@ -15859,7 +16034,7 @@ void ImGui::DockNodeTreeMerge(ImGuiContext* ctx, ImGuiDockNode* parent_node, ImG
IM_ASSERT(parent_node->TabBar == NULL);
IM_ASSERT(parent_node->Windows.Size == 0);
}
- IMGUI_DEBUG_LOG_DOCKING("DockNodeTreeMerge 0x%08X & 0x%08X back into parent 0x%08X\n", child_0 ? child_0->ID : 0, child_1 ? child_1->ID : 0, parent_node->ID);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockNodeTreeMerge: 0x%08X + 0x%08X back into parent 0x%08X\n", child_0 ? child_0->ID : 0, child_1 ? child_1->ID : 0, parent_node->ID);
ImVec2 backup_last_explicit_size = parent_node->SizeRef;
DockNodeMoveChildNodes(parent_node, merge_lead_child);
@@ -16227,12 +16402,12 @@ ImGuiID ImGui::DockSpace(ImGuiID id, const ImVec2& size_arg, ImGuiDockNodeFlags
ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
if (!node)
{
- IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X created\n", id);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockSpace: dockspace node 0x%08X created\n", id);
node = DockContextAddNode(ctx, id);
node->SetLocalFlags(ImGuiDockNodeFlags_CentralNode);
}
if (window_class && window_class->ClassId != node->WindowClass.ClassId)
- IMGUI_DEBUG_LOG_DOCKING("DockSpace: dockspace node 0x%08X: setup WindowClass 0x%08X -> 0x%08X\n", id, node->WindowClass.ClassId, window_class->ClassId);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockSpace: dockspace node 0x%08X: setup WindowClass 0x%08X -> 0x%08X\n", id, node->WindowClass.ClassId, window_class->ClassId);
node->SharedFlags = flags;
node->WindowClass = window_class ? *window_class : ImGuiWindowClass();
@@ -16568,11 +16743,11 @@ void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiID root_id, bool clear_setti
// FIXME-DOCK: We are not exposing nor using split_outer.
ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_ratio_for_node_at_dir, ImGuiID* out_id_at_dir, ImGuiID* out_id_at_opposite_dir)
{
- ImGuiContext* ctx = GImGui;
+ ImGuiContext& g = *GImGui;
IM_ASSERT(split_dir != ImGuiDir_None);
- IMGUI_DEBUG_LOG_DOCKING("DockBuilderSplitNode node 0x%08X, split_dir %d\n", id, split_dir);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockBuilderSplitNode: node 0x%08X, split_dir %d\n", id, split_dir);
- ImGuiDockNode* node = DockContextFindNodeByID(ctx, id);
+ ImGuiDockNode* node = DockContextFindNodeByID(&g, id);
if (node == NULL)
{
IM_ASSERT(node != NULL);
@@ -16589,7 +16764,7 @@ ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_r
req.DockSplitDir = split_dir;
req.DockSplitRatio = ImSaturate((split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? size_ratio_for_node_at_dir : 1.0f - size_ratio_for_node_at_dir);
req.DockSplitOuter = false;
- DockContextProcessDock(ctx, &req);
+ DockContextProcessDock(&g, &req);
ImGuiID id_at_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 0 : 1]->ID;
ImGuiID id_at_opposite_dir = node->ChildNodes[(split_dir == ImGuiDir_Left || split_dir == ImGuiDir_Up) ? 1 : 0]->ID;
@@ -16602,8 +16777,8 @@ ImGuiID ImGui::DockBuilderSplitNode(ImGuiID id, ImGuiDir split_dir, float size_r
static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID dst_node_id_if_known, ImVector<ImGuiID>* out_node_remap_pairs)
{
- ImGuiContext* ctx = GImGui;
- ImGuiDockNode* dst_node = ImGui::DockContextAddNode(ctx, dst_node_id_if_known);
+ ImGuiContext& g = *GImGui;
+ ImGuiDockNode* dst_node = ImGui::DockContextAddNode(&g, dst_node_id_if_known);
dst_node->SharedFlags = src_node->SharedFlags;
dst_node->LocalFlags = src_node->LocalFlags;
dst_node->LocalFlagsInWindows = ImGuiDockNodeFlags_None;
@@ -16623,7 +16798,7 @@ static ImGuiDockNode* DockBuilderCopyNodeRec(ImGuiDockNode* src_node, ImGuiID ds
dst_node->ChildNodes[child_n]->ParentNode = dst_node;
}
- IMGUI_DEBUG_LOG_DOCKING("Fork node %08X -> %08X (%d childs)\n", src_node->ID, dst_node->ID, dst_node->IsSplitNode() ? 2 : 0);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] Fork node %08X -> %08X (%d childs)\n", src_node->ID, dst_node->ID, dst_node->IsSplitNode() ? 2 : 0);
return dst_node;
}
@@ -16678,6 +16853,7 @@ void ImGui::DockBuilderCopyWindowSettings(const char* src_name, const char* dst_
// FIXME: Will probably want to change this signature, in particular how the window remapping pairs are passed.
void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_dockspace_id, ImVector<const char*>* in_window_remap_pairs)
{
+ ImGuiContext& g = *GImGui;
IM_ASSERT(src_dockspace_id != 0);
IM_ASSERT(dst_dockspace_id != 0);
IM_ASSERT(in_window_remap_pairs != NULL);
@@ -16717,14 +16893,14 @@ void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_docks
if (dst_dock_id != 0)
{
// Docked windows gets redocked into the new node hierarchy.
- IMGUI_DEBUG_LOG_DOCKING("Remap live window '%s' 0x%08X -> '%s' 0x%08X\n", src_window_name, src_dock_id, dst_window_name, dst_dock_id);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] Remap live window '%s' 0x%08X -> '%s' 0x%08X\n", src_window_name, src_dock_id, dst_window_name, dst_dock_id);
DockBuilderDockWindow(dst_window_name, dst_dock_id);
}
else
{
// Floating windows gets their settings transferred (regardless of whether the new window already exist or not)
// When this is leading to a Copy and not a Move, we would get two overlapping floating windows. Could we possibly dock them together?
- IMGUI_DEBUG_LOG_DOCKING("Remap window settings '%s' -> '%s'\n", src_window_name, dst_window_name);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] Remap window settings '%s' -> '%s'\n", src_window_name, dst_window_name);
DockBuilderCopyWindowSettings(src_window_name, dst_window_name);
}
}
@@ -16743,7 +16919,7 @@ void ImGui::DockBuilderCopyDockSpace(ImGuiID src_dockspace_id, ImGuiID dst_docks
continue;
// Docked windows gets redocked into the new node hierarchy.
- IMGUI_DEBUG_LOG_DOCKING("Remap window '%s' %08X -> %08X\n", window->Name, src_dock_id, dst_dock_id);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] Remap window '%s' %08X -> %08X\n", window->Name, src_dock_id, dst_dock_id);
DockBuilderDockWindow(window->Name, dst_dock_id);
}
}
@@ -17067,7 +17243,7 @@ void ImGui::BeginDockableDragDropTarget(ImGuiWindow* window)
static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID new_node_id)
{
ImGuiContext& g = *GImGui;
- IMGUI_DEBUG_LOG_DOCKING("DockSettingsRenameNodeReferences: from 0x%08X -> to 0x%08X\n", old_node_id, new_node_id);
+ IMGUI_DEBUG_LOG_DOCKING("[docking] DockSettingsRenameNodeReferences: from 0x%08X -> to 0x%08X\n", old_node_id, new_node_id);
for (int window_n = 0; window_n < g.Windows.Size; window_n++)
{
ImGuiWindow* window = g.Windows[window_n];
@@ -17453,12 +17629,16 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeDat
//-----------------------------------------------------------------------------
// - RenderViewportThumbnail() [Internal]
// - RenderViewportsThumbnails() [Internal]
+// - DebugTextEncoding()
// - MetricsHelpMarker() [Internal]
+// - ShowFontAtlas() [Internal]
// - ShowMetricsWindow()
// - DebugNodeColumns() [Internal]
// - DebugNodeDockNode() [Internal]
// - DebugNodeDrawList() [Internal]
// - DebugNodeDrawCmdShowMeshAndBoundingBox() [Internal]
+// - DebugNodeFont() [Internal]
+// - DebugNodeFontGlyph() [Internal]
// - DebugNodeStorage() [Internal]
// - DebugNodeTabBar() [Internal]
// - DebugNodeViewport() [Internal]
@@ -17468,7 +17648,7 @@ static void SetPlatformImeDataFn_DefaultImpl(ImGuiViewport*, ImGuiPlatformImeDat
// - DebugNodeWindowsListByBeginStackParent() [Internal]
//-----------------------------------------------------------------------------
-#ifndef IMGUI_DISABLE_METRICS_WINDOW
+#ifndef IMGUI_DISABLE_DEBUG_TOOLS
void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP* viewport, const ImRect& bb)
{
@@ -17525,11 +17705,47 @@ static void RenderViewportsThumbnails()
static int IMGUI_CDECL ViewportComparerByFrontMostStampCount(const void* lhs, const void* rhs)
{
- const ImGuiViewportP* a = *(const ImGuiViewportP* const *)lhs;
- const ImGuiViewportP* b = *(const ImGuiViewportP* const *)rhs;
+ const ImGuiViewportP* a = *(const ImGuiViewportP* const*)lhs;
+ const ImGuiViewportP* b = *(const ImGuiViewportP* const*)rhs;
return b->LastFrontMostStampCount - a->LastFrontMostStampCount;
}
+// Helper tool to diagnose between text encoding issues and font loading issues. Pass your UTF-8 string and verify that there are correct.
+void ImGui::DebugTextEncoding(const char* str)
+{
+ Text("Text: \"%s\"", str);
+ if (!BeginTable("list", 4, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit))
+ return;
+ TableSetupColumn("Offset");
+ TableSetupColumn("UTF-8");
+ TableSetupColumn("Glyph");
+ TableSetupColumn("Codepoint");
+ TableHeadersRow();
+ for (const char* p = str; *p != 0; )
+ {
+ unsigned int c;
+ const int c_utf8_len = ImTextCharFromUtf8(&c, p, NULL);
+ TableNextColumn();
+ Text("%d", (int)(p - str));
+ TableNextColumn();
+ for (int byte_index = 0; byte_index < c_utf8_len; byte_index++)
+ {
+ if (byte_index > 0)
+ SameLine();
+ Text("0x%02X", (int)(unsigned char)p[byte_index]);
+ }
+ TableNextColumn();
+ if (GetFont()->FindGlyphNoFallback((ImWchar)c))
+ TextUnformatted(p, p + c_utf8_len);
+ else
+ TextUnformatted((c == IM_UNICODE_CODEPOINT_INVALID) ? "[invalid]" : "[missing]");
+ TableNextColumn();
+ Text("U+%04X", (int)c);
+ p += c_utf8_len;
+ }
+ EndTable();
+}
+
// Avoid naming collision with imgui_demo.cpp's HelpMarker() for unity builds.
static void MetricsHelpMarker(const char* desc)
{
@@ -17544,15 +17760,32 @@ static void MetricsHelpMarker(const char* desc)
}
}
-#ifndef IMGUI_DISABLE_DEMO_WINDOWS
-namespace ImGui { void ShowFontAtlas(ImFontAtlas* atlas); }
-#endif
+// [DEBUG] List fonts in a font atlas and display its texture
+void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
+{
+ for (int i = 0; i < atlas->Fonts.Size; i++)
+ {
+ ImFont* font = atlas->Fonts[i];
+ PushID(font);
+ DebugNodeFont(font);
+ PopID();
+ }
+ if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
+ {
+ ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
+ ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
+ Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
+ TreePop();
+ }
+}
void ImGui::ShowMetricsWindow(bool* p_open)
{
ImGuiContext& g = *GImGui;
ImGuiIO& io = g.IO;
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
+ if (cfg->ShowDebugLog)
+ ShowDebugLogWindow(&cfg->ShowDebugLog);
if (cfg->ShowStackTool)
ShowStackToolWindow(&cfg->ShowStackTool);
@@ -17585,19 +17818,20 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
{
+ ImGuiTableInstanceData* table_instance = TableGetInstanceData(table, table->InstanceCurrent); // Always using last submitted instance
if (rect_type == TRT_OuterRect) { return table->OuterRect; }
else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
else if (rect_type == TRT_BackgroundClipRect) { return table->BgClipRect; }
- else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table->LastOuterHeight); }
+ else if (rect_type == TRT_ColumnsRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->MinX, table->InnerClipRect.Min.y, c->MaxX, table->InnerClipRect.Min.y + table_instance->LastOuterHeight); }
else if (rect_type == TRT_ColumnsWorkRect) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->WorkRect.Min.y, c->WorkMaxX, table->WorkRect.Max.y); }
else if (rect_type == TRT_ColumnsClipRect) { ImGuiTableColumn* c = &table->Columns[n]; return c->ClipRect; }
- else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table->LastFirstRowHeight); } // Note: y1/y2 not always accurate
- else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
- else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table->LastFirstRowHeight); }
- else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
+ else if (rect_type == TRT_ColumnsContentHeadersUsed){ ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersUsed, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); } // Note: y1/y2 not always accurate
+ else if (rect_type == TRT_ColumnsContentHeadersIdeal){ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXHeadersIdeal, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }
+ else if (rect_type == TRT_ColumnsContentFrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y, c->ContentMaxXFrozen, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight); }
+ else if (rect_type == TRT_ColumnsContentUnfrozen) { ImGuiTableColumn* c = &table->Columns[n]; return ImRect(c->WorkMinX, table->InnerClipRect.Min.y + table_instance->LastFirstRowHeight, c->ContentMaxXUnfrozen, table->InnerClipRect.Max.y); }
IM_ASSERT(0);
return ImRect();
}
@@ -17620,8 +17854,32 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Tools
if (TreeNode("Tools"))
{
+ bool show_encoding_viewer = TreeNode("UTF-8 Encoding viewer");
+ SameLine();
+ MetricsHelpMarker("You can also call ImGui::DebugTextEncoding() from your code with a given string to test that your UTF-8 encoding settings are correct.");
+ if (show_encoding_viewer)
+ {
+ static char buf[100] = "";
+ SetNextItemWidth(-FLT_MIN);
+ InputText("##Text", buf, IM_ARRAYSIZE(buf));
+ if (buf[0] != 0)
+ DebugTextEncoding(buf);
+ TreePop();
+ }
+
+ // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
+ if (Checkbox("Show Item Picker", &g.DebugItemPickerActive) && g.DebugItemPickerActive)
+ DebugStartItemPicker();
+ SameLine();
+ MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
+
+ // Stack Tool is your best friend!
+ Checkbox("Show Debug Log", &cfg->ShowDebugLog);
+ SameLine();
+ MetricsHelpMarker("You can also call ImGui::ShowDebugLogWindow() from your code.");
+
// Stack Tool is your best friend!
- Checkbox("Show stack tool", &cfg->ShowStackTool);
+ Checkbox("Show Stack Tool", &cfg->ShowStackTool);
SameLine();
MetricsHelpMarker("You can also call ImGui::ShowStackToolWindow() from your code.");
@@ -17687,12 +17945,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
}
- // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
- if (Button("Item Picker.."))
- DebugStartItemPicker();
- SameLine();
- MetricsHelpMarker("Will call the IM_DEBUG_BREAK() macro to break in debugger.\nWarning: If you don't have a debugger attached, this will probably crash.");
-
TreePop();
}
@@ -17818,14 +18070,19 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
// Details for Fonts
-#ifndef IMGUI_DISABLE_DEMO_WINDOWS
ImFontAtlas* atlas = g.IO.Fonts;
if (TreeNode("Fonts", "Fonts (%d)", atlas->Fonts.Size))
{
ShowFontAtlas(atlas);
TreePop();
}
-#endif
+
+ // Details for InputText
+ if (TreeNode("InputText"))
+ {
+ DebugNodeInputTextState(&g.InputTextState);
+ TreePop();
+ }
// Details for Docking
#ifdef IMGUI_HAS_DOCK
@@ -17936,7 +18193,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Text("ActiveIdWindow: '%s'", g.ActiveIdWindow ? g.ActiveIdWindow->Name : "NULL");
int active_id_using_key_input_count = 0;
- for (int n = 0; n < ImGuiKey_NamedKey_COUNT; n++)
+ for (int n = ImGuiKey_NamedKey_BEGIN; n < ImGuiKey_NamedKey_END; n++)
active_id_using_key_input_count += g.ActiveIdUsingKeyInputMask[n] ? 1 : 0;
Text("ActiveIdUsing: Wheel: %d, NavDirMask: %X, NavInputMask: %X, KeyInputMask: %d key(s)", g.ActiveIdUsingMouseWheel, g.ActiveIdUsingNavDirMask, g.ActiveIdUsingNavInputMask, active_id_using_key_input_count);
Text("HoveredId: 0x%08X (%.2f sec), AllowOverlap: %d", g.HoveredIdPreviousFrame, g.HoveredIdTimer, g.HoveredIdAllowOverlap); // Not displaying g.HoveredId as it is update mid-frame
@@ -18034,25 +18291,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
End();
}
-// [DEBUG] List fonts in a font atlas and display its texture
-void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
-{
- for (int i = 0; i < atlas->Fonts.Size; i++)
- {
- ImFont* font = atlas->Fonts[i];
- PushID(font);
- DebugNodeFont(font);
- PopID();
- }
- if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
- {
- ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
- ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
- Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
- TreePop();
- }
-}
-
// [DEBUG] Display contents of Columns
void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
{
@@ -18100,10 +18338,11 @@ void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label)
const bool is_active = (g.FrameCount - node->LastFrameActive < 2); // Submitted
if (!is_alive) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
bool open;
+ ImGuiTreeNodeFlags tree_node_flags = node->IsFocused ? ImGuiTreeNodeFlags_Selected : ImGuiTreeNodeFlags_None;
if (node->Windows.Size > 0)
- open = TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
+ open = TreeNodeEx((void*)(intptr_t)node->ID, tree_node_flags, "%s 0x%04X%s: %d windows (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", node->Windows.Size, node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
else
- open = TreeNode((void*)(intptr_t)node->ID, "%s 0x%04X%s: %s split (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
+ open = TreeNodeEx((void*)(intptr_t)node->ID, tree_node_flags, "%s 0x%04X%s: %s split (vis: '%s')", label, node->ID, node->IsVisible ? "" : " (hidden)", (node->SplitAxis == ImGuiAxis_X) ? "horizontal" : (node->SplitAxis == ImGuiAxis_Y) ? "vertical" : "n/a", node->VisibleWindow ? node->VisibleWindow->Name : "NULL");
if (!is_alive) { PopStyleColor(); }
if (is_active && IsItemHovered())
if (ImGuiWindow* window = node->HostWindow ? node->HostWindow : node->VisibleWindow)
@@ -18117,10 +18356,10 @@ void ImGui::DebugNodeDockNode(ImGuiDockNode* node, const char* label)
DebugNodeWindow(node->HostWindow, "HostWindow");
DebugNodeWindow(node->VisibleWindow, "VisibleWindow");
BulletText("SelectedTabID: 0x%08X, LastFocusedNodeID: 0x%08X", node->SelectedTabId, node->LastFocusedNodeId);
- BulletText("Misc:%s%s%s%s%s%s",
+ BulletText("Misc:%s%s%s%s%s%s%s",
node->IsDockSpace() ? " IsDockSpace" : "",
node->IsCentralNode() ? " IsCentralNode" : "",
- is_alive ? " IsAlive" : "", is_active ? " IsActive" : "",
+ is_alive ? " IsAlive" : "", is_active ? " IsActive" : "", node->IsFocused ? " IsFocused" : "",
node->WantLockSizeOnce ? " WantLockSizeOnce" : "",
node->HasCentralNodeChild ? " HasCentralNodeChild" : "");
if (TreeNode("flags", "Flags Merged: 0x%04X, Local: 0x%04X, InWindows: 0x%04X, Shared: 0x%04X", node->MergedFlags, node->LocalFlags, node->LocalFlagsInWindows, node->SharedFlags))
@@ -18346,17 +18585,13 @@ void ImGui::DebugNodeFont(ImFont* font)
ImVec2 cell_p2(cell_p1.x + cell_size, cell_p1.y + cell_size);
const ImFontGlyph* glyph = font->FindGlyphNoFallback((ImWchar)(base + n));
draw_list->AddRect(cell_p1, cell_p2, glyph ? IM_COL32(255, 255, 255, 100) : IM_COL32(255, 255, 255, 50));
- if (glyph)
- font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
- if (glyph && IsMouseHoveringRect(cell_p1, cell_p2))
+ if (!glyph)
+ continue;
+ font->RenderChar(draw_list, cell_size, cell_p1, glyph_col, (ImWchar)(base + n));
+ if (IsMouseHoveringRect(cell_p1, cell_p2))
{
BeginTooltip();
- Text("Codepoint: U+%04X", base + n);
- Separator();
- Text("Visible: %d", glyph->Visible);
- Text("AdvanceX: %.1f", glyph->AdvanceX);
- Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
- Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
+ DebugNodeFontGlyph(font, glyph);
EndTooltip();
}
}
@@ -18368,6 +18603,16 @@ void ImGui::DebugNodeFont(ImFont* font)
TreePop();
}
+void ImGui::DebugNodeFontGlyph(ImFont*, const ImFontGlyph* glyph)
+{
+ Text("Codepoint: U+%04X", glyph->Codepoint);
+ Separator();
+ Text("Visible: %d", glyph->Visible);
+ Text("AdvanceX: %.1f", glyph->AdvanceX);
+ Text("Pos: (%.2f,%.2f)->(%.2f,%.2f)", glyph->X0, glyph->Y0, glyph->X1, glyph->Y1);
+ Text("UV: (%.3f,%.3f)->(%.3f,%.3f)", glyph->U0, glyph->V0, glyph->U1, glyph->V1);
+}
+
// [DEBUG] Display contents of ImGuiStorage
void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{
@@ -18561,6 +18806,63 @@ void ImGui::DebugNodeWindowsListByBeginStackParent(ImGuiWindow** windows, int wi
}
//-----------------------------------------------------------------------------
+// [SECTION] DEBUG LOG
+//-----------------------------------------------------------------------------
+
+void ImGui::DebugLog(const char* fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ DebugLogV(fmt, args);
+ va_end(args);
+}
+
+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);
+ g.DebugLogBuf.appendfv(fmt, args);
+ if (g.DebugLogFlags & ImGuiDebugLogFlags_OutputToTTY)
+ IMGUI_DEBUG_PRINTF("%s", g.DebugLogBuf.begin() + old_size);
+}
+
+void ImGui::ShowDebugLogWindow(bool* p_open)
+{
+ ImGuiContext& g = *GImGui;
+ if (!(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize))
+ SetNextWindowSize(ImVec2(0.0f, GetFontSize() * 12.0f), ImGuiCond_FirstUseEver);
+ if (!Begin("Dear ImGui Debug Log", p_open) || GetCurrentWindow()->BeginCount > 1)
+ {
+ End();
+ return;
+ }
+
+ AlignTextToFramePadding();
+ Text("Log events:");
+ SameLine(); CheckboxFlags("All", &g.DebugLogFlags, ImGuiDebugLogFlags_EventMask_);
+ SameLine(); CheckboxFlags("ActiveId", &g.DebugLogFlags, ImGuiDebugLogFlags_EventActiveId);
+ SameLine(); CheckboxFlags("Focus", &g.DebugLogFlags, ImGuiDebugLogFlags_EventFocus);
+ SameLine(); CheckboxFlags("Popup", &g.DebugLogFlags, ImGuiDebugLogFlags_EventPopup);
+ SameLine(); CheckboxFlags("Nav", &g.DebugLogFlags, ImGuiDebugLogFlags_EventNav);
+ SameLine(); CheckboxFlags("Docking", &g.DebugLogFlags, ImGuiDebugLogFlags_EventDocking);
+ SameLine(); CheckboxFlags("Viewport", &g.DebugLogFlags, ImGuiDebugLogFlags_EventViewport);
+
+ if (SmallButton("Clear"))
+ g.DebugLogBuf.clear();
+ SameLine();
+ if (SmallButton("Copy"))
+ SetClipboardText(g.DebugLogBuf.c_str());
+ BeginChild("##log", ImVec2(0.0f, 0.0f), true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_AlwaysHorizontalScrollbar);
+ TextUnformatted(g.DebugLogBuf.begin(), g.DebugLogBuf.end()); // FIXME-OPT: Could use a line index, but TextUnformatted() has a semi-decent fast path for large text.
+ if (GetScrollY() >= GetScrollMaxY())
+ SetScrollHereY(1.0f);
+ EndChild();
+
+ End();
+}
+
+//-----------------------------------------------------------------------------
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//-----------------------------------------------------------------------------
@@ -18654,27 +18956,44 @@ void ImGui::DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* dat
ImGuiStackLevelInfo* info = &tool->Results[tool->StackLevel];
IM_ASSERT(info->ID == id && info->QueryFrameCount > 0);
- int data_len;
switch (data_type)
{
case ImGuiDataType_S32:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%d", (int)(intptr_t)data_id);
break;
case ImGuiDataType_String:
- data_len = data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id);
- ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "\"%.*s\"", data_len, (const char*)data_id);
+ ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "%.*s", data_id_end ? (int)((const char*)data_id_end - (const char*)data_id) : (int)strlen((const char*)data_id), (const char*)data_id);
break;
case ImGuiDataType_Pointer:
ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "(void*)0x%p", data_id);
break;
case ImGuiDataType_ID:
- if (info->Desc[0] == 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
- ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
+ if (info->Desc[0] != 0) // PushOverrideID() is often used to avoid hashing twice, which would lead to 2 calls to DebugHookIdInfo(). We prioritize the first one.
+ return;
+ ImFormatString(info->Desc, IM_ARRAYSIZE(info->Desc), "0x%08X [override]", id);
break;
default:
IM_ASSERT(0);
}
info->QuerySuccess = true;
+ info->DataType = data_type;
+}
+
+static int StackToolFormatLevelInfo(ImGuiStackTool* tool, int n, bool format_for_ui, char* buf, size_t buf_size)
+{
+ ImGuiStackLevelInfo* info = &tool->Results[n];
+ ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? ImGui::FindWindowByID(info->ID) : NULL;
+ if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
+ return ImFormatString(buf, buf_size, format_for_ui ? "\"%s\" [window]" : "%s", window->Name);
+ if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
+ return ImFormatString(buf, buf_size, (format_for_ui && info->DataType == ImGuiDataType_String) ? "\"%s\"" : "%s", info->Desc);
+ if (tool->StackLevel < tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
+ return (*buf = 0);
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ if (const char* label = ImGuiTestEngine_FindItemDebugLabel(GImGui, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
+ return ImFormatString(buf, buf_size, format_for_ui ? "??? \"%s\"" : "%s", label);
+#endif
+ return ImFormatString(buf, buf_size, "???");
}
// Stack Tool: Display UI
@@ -18690,6 +19009,7 @@ void ImGui::ShowStackToolWindow(bool* p_open)
}
// Display hovered/active status
+ ImGuiStackTool* tool = &g.DebugStackTool;
const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
const ImGuiID active_id = g.ActiveId;
#ifdef IMGUI_ENABLE_TEST_ENGINE
@@ -18700,8 +19020,33 @@ void ImGui::ShowStackToolWindow(bool* p_open)
SameLine();
MetricsHelpMarker("Hover an item with the mouse to display elements of the ID Stack leading to the item's final ID.\nEach level of the stack correspond to a PushID() call.\nAll levels of the stack are hashed together to make the final ID of a widget (ID displayed at the bottom level of the stack).\nRead FAQ entry about the ID stack for details.");
+ // CTRL+C to copy path
+ const float time_since_copy = (float)g.Time - tool->CopyToClipboardLastTime;
+ Checkbox("Ctrl+C: copy path to clipboard", &tool->CopyToClipboardOnCtrlC);
+ SameLine();
+ TextColored((time_since_copy >= 0.0f && time_since_copy < 0.75f && ImFmod(time_since_copy, 0.25f) < 0.25f * 0.5f) ? ImVec4(1.f, 1.f, 0.3f, 1.f) : ImVec4(), "*COPIED*");
+ if (tool->CopyToClipboardOnCtrlC && IsKeyDown(ImGuiKey_ModCtrl) && IsKeyPressed(ImGuiKey_C))
+ {
+ tool->CopyToClipboardLastTime = (float)g.Time;
+ char* p = g.TempBuffer.Data;
+ char* p_end = p + g.TempBuffer.Size;
+ for (int stack_n = 0; stack_n < tool->Results.Size && p + 3 < p_end; stack_n++)
+ {
+ *p++ = '/';
+ char level_desc[256];
+ StackToolFormatLevelInfo(tool, stack_n, false, level_desc, IM_ARRAYSIZE(level_desc));
+ for (int n = 0; level_desc[n] && p + 2 < p_end; n++)
+ {
+ if (level_desc[n] == '/')
+ *p++ = '\\';
+ *p++ = level_desc[n];
+ }
+ }
+ *p = '\0';
+ SetClipboardText(g.TempBuffer.Data);
+ }
+
// Display decorated stack
- ImGuiStackTool* tool = &g.DebugStackTool;
tool->LastActiveFrame = g.FrameCount;
if (tool->Results.Size > 0 && BeginTable("##table", 3, ImGuiTableFlags_Borders))
{
@@ -18715,23 +19060,9 @@ void ImGui::ShowStackToolWindow(bool* p_open)
ImGuiStackLevelInfo* info = &tool->Results[n];
TableNextColumn();
Text("0x%08X", (n > 0) ? tool->Results[n - 1].ID : 0);
-
TableNextColumn();
- ImGuiWindow* window = (info->Desc[0] == 0 && n == 0) ? FindWindowByID(info->ID) : NULL;
- if (window) // Source: window name (because the root ID don't call GetID() and so doesn't get hooked)
- Text("\"%s\" [window]", window->Name);
- else if (info->QuerySuccess) // Source: GetID() hooks (prioritize over ItemInfo() because we frequently use patterns like: PushID(str), Button("") where they both have same id)
- TextUnformatted(info->Desc);
- else if (tool->StackLevel >= tool->Results.Size) // Only start using fallback below when all queries are done, so during queries we don't flickering ??? markers.
- {
-#ifdef IMGUI_ENABLE_TEST_ENGINE
- if (const char* label = ImGuiTestEngine_FindItemDebugLabel(&g, info->ID)) // Source: ImGuiTestEngine's ItemInfo()
- Text("??? \"%s\"", label);
- else
-#endif
- TextUnformatted("???");
- }
-
+ StackToolFormatLevelInfo(tool, n, true, g.TempBuffer.Data, g.TempBuffer.Size);
+ TextUnformatted(g.TempBuffer.Data);
TableNextColumn();
Text("0x%08X", info->ID);
if (n == tool->Results.Size - 1)
@@ -18757,12 +19088,15 @@ 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::ShowStackToolWindow(bool*) {}
void ImGui::DebugHookIdInfo(ImGuiID, ImGuiDataType, const void*, const void*) {}
void ImGui::UpdateDebugToolItemPicker() {}
void ImGui::UpdateDebugToolStackQueries() {}
-#endif // #ifndef IMGUI_DISABLE_METRICS_WINDOW
+#endif // #ifndef IMGUI_DISABLE_DEBUG_TOOLS
//-----------------------------------------------------------------------------