update Dear ImGui to 1.89.9

this is part of an upgrade process to the latest version of Dear ImGui
it will take a while as I am stepping through individual versions due
to the heavy modifications we've made for Furnace
This commit is contained in:
tildearrow 2025-08-09 20:45:33 -05:00
parent 0d1acc41bf
commit b3d60e512c
19 changed files with 596 additions and 409 deletions

View file

@ -6,7 +6,8 @@
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues: // Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows)..
// [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually. // [ ] Renderer: The renderer is suboptimal as we need to convert vertices manually.
// [ ] Platform: Missing gamepad support. // [ ] Platform: Missing gamepad support.

View file

@ -6,7 +6,8 @@
// [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy ALLEGRO_KEY_* values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// [X] Platform: Clipboard support (from Allegro 5.1.12) // [X] Platform: Clipboard support (from Allegro 5.1.12)
// [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. // [X] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'.
// Issues: // Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows)..
// [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually. // [ ] Renderer: The renderer is suboptimal as we need to unindex our buffers and convert vertices manually.
// [ ] Platform: Missing gamepad support. // [ ] Platform: Missing gamepad support.

View file

@ -8,6 +8,7 @@
// [ ] Platform: Clipboard support. // [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
// Important: // Important:
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)

View file

@ -8,6 +8,7 @@
// [ ] Platform: Clipboard support. // [ ] Platform: Clipboard support.
// [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'. // [ ] Platform: Gamepad support. Enable with 'io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad'.
// [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android. // [ ] Platform: Mouse cursor shape and visibility. Disable with 'io.ConfigFlags |= ImGuiConfigFlags_NoMouseCursorChange'. FIXME: Check if this is even possible with Android.
// [ ] Platform: Multi-viewport support (multiple windows). Not meaningful on Android.
// Important: // Important:
// - Consider using SDL or GLFW backend on Android, which will be more full-featured than this. // - Consider using SDL or GLFW backend on Android, which will be more full-featured than this.
// - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446) // - FIXME: On-screen keyboard currently needs to be enabled by the application (see examples/ and issue #3446)

View file

@ -7,7 +7,7 @@
// Implemented features: // Implemented features:
// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Issues: // Missing features:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing horizontal mouse wheel support.
// [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing mouse cursor shape/visibility support.

View file

@ -7,7 +7,7 @@
// Implemented features: // Implemented features:
// [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set] // [X] Platform: Partial keyboard support. Since 1.87 we are using the io.AddKeyEvent() function. Pass ImGuiKey values to all key functions e.g. ImGui::IsKeyPressed(ImGuiKey_Space). [Legacy GLUT values will also be supported unless IMGUI_DISABLE_OBSOLETE_KEYIO is set]
// Issues: // Missing features:
// [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I // [ ] Platform: GLUT is unable to distinguish e.g. Backspace from CTRL+H or TAB from CTRL+I
// [ ] Platform: Missing horizontal mouse wheel support. // [ ] Platform: Missing horizontal mouse wheel support.
// [ ] Platform: Missing mouse cursor shape/visibility support. // [ ] Platform: Missing mouse cursor shape/visibility support.

View file

@ -557,6 +557,11 @@ bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere
return ImGui_ImplSDL2_Init(window, renderer, nullptr); return ImGui_ImplSDL2_Init(window, renderer, nullptr);
} }
bool ImGui_ImplSDL2_InitForOther(SDL_Window* window)
{
return ImGui_ImplSDL2_Init(window, nullptr, nullptr);
}
void ImGui_ImplSDL2_Shutdown() void ImGui_ImplSDL2_Shutdown()
{ {
ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData(); ImGui_ImplSDL2_Data* bd = ImGui_ImplSDL2_GetBackendData();

View file

@ -31,6 +31,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL2_InitForOther(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL2_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame(); IMGUI_IMPL_API void ImGui_ImplSDL2_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event); IMGUI_IMPL_API bool ImGui_ImplSDL2_ProcessEvent(const SDL_Event* event);

View file

@ -473,6 +473,11 @@ bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* rendere
return ImGui_ImplSDL3_Init(window, renderer, nullptr); return ImGui_ImplSDL3_Init(window, renderer, nullptr);
} }
bool ImGui_ImplSDL3_InitForOther(SDL_Window* window)
{
return ImGui_ImplSDL3_Init(window, nullptr, nullptr);
}
void ImGui_ImplSDL3_Shutdown() void ImGui_ImplSDL3_Shutdown()
{ {
ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData(); ImGui_ImplSDL3_Data* bd = ImGui_ImplSDL3_GetBackendData();

View file

@ -32,6 +32,7 @@ IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForVulkan(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForD3D(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForMetal(SDL_Window* window);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer); IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForSDLRenderer(SDL_Window* window, SDL_Renderer* renderer);
IMGUI_IMPL_API bool ImGui_ImplSDL3_InitForOther(SDL_Window* window);
IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown(); IMGUI_IMPL_API void ImGui_ImplSDL3_Shutdown();
IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame(); IMGUI_IMPL_API void ImGui_ImplSDL3_NewFrame();
IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event); IMGUI_IMPL_API bool ImGui_ImplSDL3_ProcessEvent(const SDL_Event* event);

View file

@ -5,6 +5,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows). Not meaningful on the web.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

View file

@ -5,6 +5,8 @@
// Implemented features: // Implemented features:
// [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID! // [X] Renderer: User texture binding. Use 'WGPUTextureView' as ImTextureID. Read the FAQ about ImTextureID!
// [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices. // [X] Renderer: Large meshes support (64k+ vertices) with 16-bit indices.
// Missing features:
// [ ] Renderer: Multi-viewport support (multiple windows). Not meaningful on the web.
// You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this. // You can use unmodified imgui_impl_* files in your project. See examples/ folder for examples of using this.
// Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need. // Prefer including the entire imgui/ repository into your project (either as a copy or as a submodule), and only build the backends you need.

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (main code and documentation) // (main code and documentation)
// Help: // Help:
@ -433,6 +433,7 @@ CODE
- likewise io.MousePos and GetMousePos() will use OS coordinates. - 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. If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
- 2023/08/25 (1.89.9) - Clipper: Renamed IncludeRangeByIndices() (also called ForceDisplayRangeByIndices() before 1.89.6) to IncludeItemsByIndex(). Kept inline redirection function. Sorry!
- 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878) - 2023/07/12 (1.89.8) - ImDrawData: CmdLists now owned, changed from ImDrawList** to ImVector<ImDrawList*>. Majority of users shouldn't be affected, but you cannot compare to NULL nor reassign manually anymore. Instead use AddDrawList(). (#6406, #4879, #1878)
- 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15). - 2023/06/28 (1.89.7) - overlapping items: obsoleted 'SetItemAllowOverlap()' (called after item) in favor of calling 'SetNextItemAllowOverlap()' (called before item). 'SetItemAllowOverlap()' didn't and couldn't work reliably since 1.89 (2022-11-15).
- 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete). - 2023/06/28 (1.89.7) - overlapping items: renamed 'ImGuiTreeNodeFlags_AllowItemOverlap' to 'ImGuiTreeNodeFlags_AllowOverlap', 'ImGuiSelectableFlags_AllowItemOverlap' to 'ImGuiSelectableFlags_AllowOverlap'. Kept redirecting enums (will obsolete).
@ -1191,7 +1192,7 @@ ImGuiStyle::ImGuiStyle()
FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested. FrameBorderSize = 0.0f; // Thickness of border around frames. Generally set to 0.0f or 1.0f. Other values not well tested.
ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines ItemSpacing = ImVec2(8,4); // Horizontal and vertical spacing between widgets/lines
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label) ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
CellPadding = ImVec2(4,2); // Padding within a table cell CellPadding = ImVec2(4,2); // Padding within a table cell. CellPadding.y may be altered between different rows.
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
@ -1338,6 +1339,7 @@ ImGuiIO::ImGuiIO()
// Note: Initialize() will setup default clipboard/ime handlers. // Note: Initialize() will setup default clipboard/ime handlers.
BackendPlatformName = BackendRendererName = NULL; BackendPlatformName = BackendRendererName = NULL;
BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL; BackendPlatformUserData = BackendRendererUserData = BackendLanguageUserData = NULL;
PlatformLocaleDecimalPoint = '.';
// Input (NB: we already have memset zero the entire structure!) // Input (NB: we already have memset zero the entire structure!)
MousePos = ImVec2(-FLT_MAX, -FLT_MAX); MousePos = ImVec2(-FLT_MAX, -FLT_MAX);
@ -1583,7 +1585,7 @@ void ImGuiIO::AddMousePosEvent(float x, float y)
e.EventId = g.InputEventsNextEventId++; e.EventId = g.InputEventsNextEventId++;
e.MousePos.PosX = pos.x; e.MousePos.PosX = pos.x;
e.MousePos.PosY = pos.y; e.MousePos.PosY = pos.y;
e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; e.MousePos.MouseSource = g.InputEventsNextMouseSource;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
@ -1607,7 +1609,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
e.EventId = g.InputEventsNextEventId++; e.EventId = g.InputEventsNextEventId++;
e.MouseButton.Button = mouse_button; e.MouseButton.Button = mouse_button;
e.MouseButton.Down = down; e.MouseButton.Down = down;
e.MouseWheel.MouseSource = g.InputEventsNextMouseSource; e.MouseButton.MouseSource = g.InputEventsNextMouseSource;
g.InputEventsQueue.push_back(e); g.InputEventsQueue.push_back(e);
} }
@ -2622,16 +2624,15 @@ void ImGuiTextFilter::Build()
input_range.split(',', &Filters); input_range.split(',', &Filters);
CountGrep = 0; CountGrep = 0;
for (int i = 0; i != Filters.Size; i++) for (ImGuiTextRange& f : Filters)
{ {
ImGuiTextRange& f = Filters[i];
while (f.b < f.e && ImCharIsBlankA(f.b[0])) while (f.b < f.e && ImCharIsBlankA(f.b[0]))
f.b++; f.b++;
while (f.e > f.b && ImCharIsBlankA(f.e[-1])) while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
f.e--; f.e--;
if (f.empty()) if (f.empty())
continue; continue;
if (Filters[i].b[0] != '-') if (f.b[0] != '-')
CountGrep += 1; CountGrep += 1;
} }
} }
@ -2644,9 +2645,8 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
if (text == NULL) if (text == NULL)
text = ""; text = "";
for (int i = 0; i != Filters.Size; i++) for (const ImGuiTextRange& f : Filters)
{ {
const ImGuiTextRange& f = Filters[i];
if (f.empty()) if (f.empty())
continue; continue;
if (f.b[0] == '-') if (f.b[0] == '-')
@ -2934,7 +2934,7 @@ void ImGuiListClipper::End()
ItemsCount = -1; ItemsCount = -1;
} }
void ImGuiListClipper::IncludeRangeByIndices(int item_begin, int item_end) void ImGuiListClipper::IncludeItemsByIndex(int item_begin, int item_end)
{ {
ImGuiListClipperData* data = (ImGuiListClipperData*)TempData; ImGuiListClipperData* data = (ImGuiListClipperData*)TempData;
IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet. IM_ASSERT(DisplayStart < 0); // Only allowed after Begin() and if there has not been a specified range yet.
@ -3035,26 +3035,28 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
// - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping. // - Very important: when a starting position is after our maximum item, we set Min to (ItemsCount - 1). This allows us to handle most forms of wrapping.
// - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list, // - Due to how Selectable extra padding they tend to be "unaligned" with exact unit in the item list,
// which with the flooring/ceiling tend to lead to 2 items instead of one being submitted. // which with the flooring/ceiling tend to lead to 2 items instead of one being submitted.
for (int i = 0; i < data->Ranges.Size; i++) for (ImGuiListClipperRange& range : data->Ranges)
if (data->Ranges[i].PosToIndexConvert) if (range.PosToIndexConvert)
{ {
int m1 = (int)(((double)data->Ranges[i].Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight); int m1 = (int)(((double)range.Min - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight);
int m2 = (int)((((double)data->Ranges[i].Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f); int m2 = (int)((((double)range.Max - window->DC.CursorPos.y - data->LossynessOffset) / clipper->ItemsHeight) + 0.999999f);
data->Ranges[i].Min = ImClamp(already_submitted + m1 + data->Ranges[i].PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1); range.Min = ImClamp(already_submitted + m1 + range.PosToIndexOffsetMin, already_submitted, clipper->ItemsCount - 1);
data->Ranges[i].Max = ImClamp(already_submitted + m2 + data->Ranges[i].PosToIndexOffsetMax, data->Ranges[i].Min + 1, clipper->ItemsCount); range.Max = ImClamp(already_submitted + m2 + range.PosToIndexOffsetMax, range.Min + 1, clipper->ItemsCount);
data->Ranges[i].PosToIndexConvert = false; range.PosToIndexConvert = false;
} }
ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo); ImGuiListClipper_SortAndFuseRanges(data->Ranges, data->StepNo);
} }
// Step 0+ (if item height is given in advance) or 1+: Display the next range in line. // Step 0+ (if item height is given in advance) or 1+: Display the next range in line.
if (data->StepNo < data->Ranges.Size) while (data->StepNo < data->Ranges.Size)
{ {
clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted); clipper->DisplayStart = ImMax(data->Ranges[data->StepNo].Min, already_submitted);
clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount); clipper->DisplayEnd = ImMin(data->Ranges[data->StepNo].Max, clipper->ItemsCount);
if (clipper->DisplayStart > already_submitted) //-V1051 if (clipper->DisplayStart > already_submitted) //-V1051
ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart); ImGuiListClipper_SeekCursorForItem(clipper, clipper->DisplayStart);
data->StepNo++; data->StepNo++;
if (clipper->DisplayStart == clipper->DisplayEnd && data->StepNo < data->Ranges.Size)
continue;
return true; return true;
} }
@ -3646,13 +3648,12 @@ void ImGui::RenderMouseCursor(ImVec2 base_pos, float base_scale, ImGuiMouseCurso
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT); IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas; ImFontAtlas* font_atlas = g.DrawListSharedData.Font->ContainerAtlas;
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
// We scale cursor with current viewport/monitor, however Windows 10 for its own hardware cursor seems to be using a different scale factor. // 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]; ImVec2 offset, size, uv[4];
if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2])) if (!font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
continue; continue;
ImGuiViewportP* viewport = g.Viewports[n];
const ImVec2 pos = base_pos - offset; const ImVec2 pos = base_pos - offset;
const float scale = base_scale * viewport->DpiScale; const float scale = base_scale * viewport->DpiScale;
if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale))) if (!viewport->GetMainRect().Overlaps(ImRect(pos, pos + ImVec2(size.x + 2, size.y + 2) * scale)))
@ -3737,6 +3738,7 @@ static const ImGuiLocEntry GLocalizationEntriesEnUS[] =
{ ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" },
{ ImGuiLocKey_WindowingUntitled, "(Untitled)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" },
{ ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" }, { ImGuiLocKey_DockingHideTabBar, "Hide tab bar###HideTabBar" },
{ ImGuiLocKey_DockingHoldShiftToDock, "Hold SHIFT to enable Docking window."},
}; };
void ImGui::Initialize() void ImGui::Initialize()
@ -3834,6 +3836,7 @@ void ImGui::Shutdown()
g.FontStack.clear(); g.FontStack.clear();
g.OpenPopupStack.clear(); g.OpenPopupStack.clear();
g.BeginPopupStack.clear(); g.BeginPopupStack.clear();
g.NavTreeNodeStack.clear();
g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL; g.CurrentViewport = g.MouseViewport = g.MouseLastHoveredViewport = NULL;
g.Viewports.clear_delete(); g.Viewports.clear_delete();
@ -3886,9 +3889,9 @@ void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
IM_ASSERT(hook_id != 0); IM_ASSERT(hook_id != 0);
for (int n = 0; n < g.Hooks.Size; n++) for (ImGuiContextHook& hook : g.Hooks)
if (g.Hooks[n].HookId == hook_id) if (hook.HookId == hook_id)
g.Hooks[n].Type = ImGuiContextHookType_PendingRemoval_; hook.Type = ImGuiContextHookType_PendingRemoval_;
} }
// Call context hooks (used by e.g. test engine) // Call context hooks (used by e.g. test engine)
@ -3896,9 +3899,9 @@ void ImGui::RemoveContextHook(ImGuiContext* ctx, ImGuiID hook_id)
void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type) void ImGui::CallContextHooks(ImGuiContext* ctx, ImGuiContextHookType hook_type)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
for (int n = 0; n < g.Hooks.Size; n++) for (ImGuiContextHook& hook : g.Hooks)
if (g.Hooks[n].Type == hook_type) if (hook.Type == hook_type)
g.Hooks[n].Callback(&g, &g.Hooks[n]); hook.Callback(&g, &hook);
} }
@ -4142,6 +4145,8 @@ void ImGui::MarkItemEdited(ImGuiID id)
// This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit(). // This marking is solely to be able to provide info for IsItemDeactivatedAfterEdit().
// ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data. // ActiveId might have been released by the time we call this (as in the typical press/release button behavior) but still need to fill the data.
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (g.LockMarkEdited > 0)
return;
if (g.ActiveId == id || g.ActiveId == 0) if (g.ActiveId == id || g.ActiveId == 0)
{ {
g.ActiveIdHasBeenEditedThisFrame = true; g.ActiveIdHasBeenEditedThisFrame = true;
@ -4267,7 +4272,7 @@ bool ImGui::IsItemHovered(ImGuiHoveredFlags flags)
return false; return false;
// Test if using AllowOverlap and overlapped // Test if using AllowOverlap and overlapped
if ((g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap) && id != 0) if ((g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap) && id != 0)
if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0) if ((flags & ImGuiHoveredFlags_AllowWhenOverlappedByItem) == 0)
if (g.HoveredIdPreviousFrame != g.LastItemData.ID) if (g.HoveredIdPreviousFrame != g.LastItemData.ID)
return false; return false;
@ -4335,7 +4340,7 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id, ImGuiItemFlags item_flag
// AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. // AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match.
// This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test. // This allows using patterns where a later submitted widget overlaps a previous one. Generally perceived as a front-to-back hit-test.
if (item_flags & ImGuiItemflags_AllowOverlap) if (item_flags & ImGuiItemFlags_AllowOverlap)
{ {
g.HoveredIdAllowOverlap = true; g.HoveredIdAllowOverlap = true;
if (g.HoveredIdPreviousFrame != id) if (g.HoveredIdPreviousFrame != id)
@ -4484,33 +4489,33 @@ int ImGui::GetFrameCount()
return GImGui->FrameCount; return GImGui->FrameCount;
} }
static ImDrawList* GetViewportDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name) static ImDrawList* GetViewportBgFgDrawList(ImGuiViewportP* viewport, size_t drawlist_no, const char* drawlist_name)
{ {
// Create the draw list on demand, because they are not frequently used for all viewports // Create the draw list on demand, because they are not frequently used for all viewports
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->DrawLists)); IM_ASSERT(drawlist_no < IM_ARRAYSIZE(viewport->BgFgDrawLists));
ImDrawList* draw_list = viewport->DrawLists[drawlist_no]; ImDrawList* draw_list = viewport->BgFgDrawLists[drawlist_no];
if (draw_list == NULL) if (draw_list == NULL)
{ {
draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData); draw_list = IM_NEW(ImDrawList)(&g.DrawListSharedData);
draw_list->_OwnerName = drawlist_name; draw_list->_OwnerName = drawlist_name;
viewport->DrawLists[drawlist_no] = draw_list; viewport->BgFgDrawLists[drawlist_no] = draw_list;
} }
// Our ImDrawList system requires that there is always a command // Our ImDrawList system requires that there is always a command
if (viewport->DrawListsLastFrame[drawlist_no] != g.FrameCount) if (viewport->BgFgDrawListsLastFrame[drawlist_no] != g.FrameCount)
{ {
draw_list->_ResetForNewFrame(); draw_list->_ResetForNewFrame();
draw_list->PushTextureID(g.IO.Fonts->TexID); draw_list->PushTextureID(g.IO.Fonts->TexID);
draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false); draw_list->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size, false);
viewport->DrawListsLastFrame[drawlist_no] = g.FrameCount; viewport->BgFgDrawListsLastFrame[drawlist_no] = g.FrameCount;
} }
return draw_list; return draw_list;
} }
ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport) ImDrawList* ImGui::GetBackgroundDrawList(ImGuiViewport* viewport)
{ {
return GetViewportDrawList((ImGuiViewportP*)viewport, 0, "##Background"); return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 0, "##Background");
} }
ImDrawList* ImGui::GetBackgroundDrawList() ImDrawList* ImGui::GetBackgroundDrawList()
@ -4521,7 +4526,7 @@ ImDrawList* ImGui::GetBackgroundDrawList()
ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport) ImDrawList* ImGui::GetForegroundDrawList(ImGuiViewport* viewport)
{ {
return GetViewportDrawList((ImGuiViewportP*)viewport, 1, "##Foreground"); return GetViewportBgFgDrawList((ImGuiViewportP*)viewport, 1, "##Foreground");
} }
ImDrawList* ImGui::GetForegroundDrawList() ImDrawList* ImGui::GetForegroundDrawList()
@ -4863,8 +4868,8 @@ void ImGui::NewFrame()
SetCurrentFont(GetDefaultFont()); SetCurrentFont(GetDefaultFont());
IM_ASSERT(g.Font->IsLoaded()); IM_ASSERT(g.Font->IsLoaded());
ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); ImRect virtual_space(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
virtual_space.Add(g.Viewports[n]->GetMainRect()); virtual_space.Add(viewport->GetMainRect());
g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4(); g.DrawListSharedData.ClipRectFullscreen = virtual_space.ToVec4();
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol; g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError); g.DrawListSharedData.SetCircleTessellationMaxError(g.Style.CircleTessellationMaxError);
@ -4879,11 +4884,10 @@ void ImGui::NewFrame()
g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset; g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
// Mark rendering data as invalid to prevent user who may have a handle on it to use it. // Mark rendering data as invalid to prevent user who may have a handle on it to use it.
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
ImGuiViewportP* viewport = g.Viewports[n];
viewport->DrawData = NULL; viewport->DrawData = NULL;
viewport->DrawDataP.Clear(); viewport->DrawDataP.Valid = false;
} }
// Drag and drop keep the source ID alive so even if the source disappear our state is consistent // Drag and drop keep the source ID alive so even if the source disappear our state is consistent
@ -5037,9 +5041,8 @@ void ImGui::NewFrame()
// Mark all windows as not visible and compact unused memory. // Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size); IM_ASSERT(g.WindowsFocusOrder.Size <= g.Windows.Size);
const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer; const float memory_compact_start_time = (g.GcCompactAll || g.IO.ConfigMemoryCompactTimer < 0.0f) ? FLT_MAX : (float)g.Time - g.IO.ConfigMemoryCompactTimer;
for (int i = 0; i != g.Windows.Size; i++) for (ImGuiWindow* window : g.Windows)
{ {
ImGuiWindow* window = g.Windows[i];
window->WasActive = window->Active; window->WasActive = window->Active;
window->Active = false; window->Active = false;
window->WriteAccessed = false; window->WriteAccessed = false;
@ -5055,9 +5058,9 @@ void ImGui::NewFrame()
for (int i = 0; i < g.TablesLastTimeActive.Size; i++) for (int i = 0; i < g.TablesLastTimeActive.Size; i++)
if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time) if (g.TablesLastTimeActive[i] >= 0.0f && g.TablesLastTimeActive[i] < memory_compact_start_time)
TableGcCompactTransientBuffers(g.Tables.GetByIndex(i)); TableGcCompactTransientBuffers(g.Tables.GetByIndex(i));
for (int i = 0; i < g.TablesTempData.Size; i++) for (ImGuiTableTempData& table_temp_data : g.TablesTempData)
if (g.TablesTempData[i].LastTimeActive >= 0.0f && g.TablesTempData[i].LastTimeActive < memory_compact_start_time) if (table_temp_data.LastTimeActive >= 0.0f && table_temp_data.LastTimeActive < memory_compact_start_time)
TableGcCompactTransientBuffers(&g.TablesTempData[i]); TableGcCompactTransientBuffers(&table_temp_data);
if (g.GcCompactAll) if (g.GcCompactAll)
GcCompactTransientMiscBuffers(); GcCompactTransientMiscBuffers();
g.GcCompactAll = false; g.GcCompactAll = false;
@ -5140,15 +5143,12 @@ static void AddWindowToDrawData(ImGuiWindow* window, int layer)
ImGuiViewportP* viewport = window->Viewport; ImGuiViewportP* viewport = window->Viewport;
IM_ASSERT(viewport != NULL); IM_ASSERT(viewport != NULL);
g.IO.MetricsRenderWindows++; g.IO.MetricsRenderWindows++;
if (window->Flags & ImGuiWindowFlags_DockNodeHost) if (window->DrawList->_Splitter._Count > 1)
window->DrawList->ChannelsMerge(); window->DrawList->ChannelsMerge(); // Merge if user forgot to merge back. Also required in Docking branch for ImGuiWindowFlags_DockNodeHost windows.
ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList); ImGui::AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[layer], window->DrawList);
for (int i = 0; i < window->DC.ChildWindows.Size; i++) for (ImGuiWindow* child : window->DC.ChildWindows)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active if (IsWindowActiveAndVisible(child)) // Clipped children may have been marked not active
AddWindowToDrawData(child, layer); AddWindowToDrawData(child, layer);
}
} }
static inline int GetWindowDisplayLayer(ImGuiWindow* window) static inline int GetWindowDisplayLayer(ImGuiWindow* window)
@ -5245,10 +5245,10 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
// Draw behind window by moving the draw command at the FRONT of the draw list // Draw behind window by moving the draw command at the FRONT of the draw list
{ {
// We've already called AddWindowToDrawData() which called DrawList->ChannelsMerge() on DockNodeHost windows, // Draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
// and draw list have been trimmed already, hence the explicit recreation of a draw command if missing.
// FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order. // FIXME: This is creating complication, might be simpler if we could inject a drawlist in drawdata at a given position and not attempt to manipulate ImDrawCmd order.
ImDrawList* draw_list = window->RootWindowDockTree->DrawList; ImDrawList* draw_list = window->RootWindowDockTree->DrawList;
draw_list->ChannelsMerge();
if (draw_list->CmdBuffer.Size == 0) if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd(); draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that) draw_list->PushClipRect(viewport_rect.Min - ImVec2(1, 1), viewport_rect.Max + ImVec2(1, 1), false); // FIXME: Need to stricty ensure ImDrawCmd are not merged (ElemCount==6 checks below will verify that)
@ -5265,6 +5265,7 @@ static void ImGui::RenderDimmedBackgroundBehindWindow(ImGuiWindow* window, ImU32
if (window->RootWindow->DockIsActive) if (window->RootWindow->DockIsActive)
{ {
ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindowDockTree)->DrawList; ImDrawList* draw_list = FindFrontMostVisibleChildWindow(window->RootWindowDockTree)->DrawList;
draw_list->ChannelsMerge();
if (draw_list->CmdBuffer.Size == 0) if (draw_list->CmdBuffer.Size == 0)
draw_list->AddDrawCmd(); draw_list->AddDrawCmd();
draw_list->PushClipRect(viewport_rect.Min, viewport_rect.Max, false); draw_list->PushClipRect(viewport_rect.Min, viewport_rect.Max, false);
@ -5290,6 +5291,8 @@ ImGuiWindow* ImGui::FindBottomMostVisibleWindowWithinBeginStack(ImGuiWindow* par
return bottom_most_visible_window; return bottom_most_visible_window;
} }
// Important: AddWindowToDrawData() has not been called yet, meaning DockNodeHost windows needs a DrawList->ChannelsMerge() before usage.
// We call ChannelsMerge() lazily here at it is faster that doing a full iteration of g.Windows[] prior to calling RenderDimmedBackgrounds().
static void ImGui::RenderDimmedBackgrounds() static void ImGui::RenderDimmedBackgrounds()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -5326,6 +5329,7 @@ static void ImGui::RenderDimmedBackgrounds()
bb.Expand(distance); bb.Expand(distance);
if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y) if (bb.GetWidth() >= viewport->Size.x && bb.GetHeight() >= viewport->Size.y)
bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward bb.Expand(-distance - 1.0f); // If a window fits the entire viewport, adjust its highlight inward
window->DrawList->ChannelsMerge();
if (window->DrawList->CmdBuffer.Size == 0) if (window->DrawList->CmdBuffer.Size == 0)
window->DrawList->AddDrawCmd(); window->DrawList->AddDrawCmd();
window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size); window->DrawList->PushClipRect(viewport->Pos, viewport->Pos + viewport->Size);
@ -5434,9 +5438,8 @@ void ImGui::EndFrame()
// We cannot do that on FocusWindow() because children may not exist yet // We cannot do that on FocusWindow() because children may not exist yet
g.WindowsTempSortBuffer.resize(0); g.WindowsTempSortBuffer.resize(0);
g.WindowsTempSortBuffer.reserve(g.Windows.Size); g.WindowsTempSortBuffer.reserve(g.Windows.Size);
for (int i = 0; i != g.Windows.Size; i++) for (ImGuiWindow* window : g.Windows)
{ {
ImGuiWindow* window = g.Windows[i];
if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it if (window->Active && (window->Flags & ImGuiWindowFlags_ChildWindow)) // if a child is active its parent will add it
continue; continue;
AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window); AddWindowToSortBuffer(&g.WindowsTempSortBuffer, window);
@ -5468,28 +5471,30 @@ void ImGui::Render()
if (g.FrameCountEnded != g.FrameCount) if (g.FrameCountEnded != g.FrameCount)
EndFrame(); EndFrame();
const bool first_render_of_frame = (g.FrameCountRendered != g.FrameCount); if (g.FrameCountRendered == g.FrameCount)
return;
g.FrameCountRendered = g.FrameCount; g.FrameCountRendered = g.FrameCount;
g.IO.MetricsRenderWindows = 0;
g.IO.MetricsRenderWindows = 0;
CallContextHooks(&g, ImGuiContextHookType_RenderPre); CallContextHooks(&g, ImGuiContextHookType_RenderPre);
// Add background ImDrawList (for each active viewport) // Add background ImDrawList (for each active viewport)
for (int n = 0; n != g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
ImGuiViewportP* viewport = g.Viewports[n];
InitViewportDrawData(viewport); InitViewportDrawData(viewport);
if (viewport->DrawLists[0] != NULL) if (viewport->BgFgDrawLists[0] != NULL)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport)); AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetBackgroundDrawList(viewport));
} }
// Draw modal/window whitening backgrounds
RenderDimmedBackgrounds();
// Add ImDrawList to render // Add ImDrawList to render
ImGuiWindow* windows_to_render_top_most[2]; ImGuiWindow* windows_to_render_top_most[2];
windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindowDockTree : NULL; windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindowDockTree : NULL;
windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL); windows_to_render_top_most[1] = (g.NavWindowingTarget ? g.NavWindowingListWindow : NULL);
for (int n = 0; n != g.Windows.Size; n++) for (ImGuiWindow* window : g.Windows)
{ {
ImGuiWindow* window = g.Windows[n];
IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'" IM_MSVC_WARNING_SUPPRESS(6011); // Static Analysis false positive "warning C6011: Dereferencing NULL pointer 'window'"
if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1]) if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window); AddRootWindowToDrawData(window);
@ -5498,30 +5503,25 @@ void ImGui::Render()
if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
AddRootWindowToDrawData(windows_to_render_top_most[n]); AddRootWindowToDrawData(windows_to_render_top_most[n]);
// Draw modal/window whitening backgrounds
if (first_render_of_frame)
RenderDimmedBackgrounds();
// Draw software mouse cursor if requested by io.MouseDrawCursor flag // Draw software mouse cursor if requested by io.MouseDrawCursor flag
if (g.IO.MouseDrawCursor && first_render_of_frame && g.MouseCursor != ImGuiMouseCursor_None) if (g.IO.MouseDrawCursor && 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)); 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 // Setup ImDrawData structures for end-user
g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0; g.IO.MetricsRenderVertices = g.IO.MetricsRenderIndices = 0;
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
ImGuiViewportP* viewport = g.Viewports[n];
FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder); FlattenDrawDataIntoSingleLayer(&viewport->DrawDataBuilder);
// Add foreground ImDrawList (for each active viewport) // Add foreground ImDrawList (for each active viewport)
if (viewport->DrawLists[1] != NULL) if (viewport->BgFgDrawLists[1] != NULL)
AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport)); AddDrawListToDrawDataEx(&viewport->DrawDataP, viewport->DrawDataBuilder.Layers[0], GetForegroundDrawList(viewport));
// We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch). // We call _PopUnusedDrawCmd() last thing, as RenderDimmedBackgrounds() rely on a valid command being there (especially in docking branch).
ImDrawData* draw_data = &viewport->DrawDataP; ImDrawData* draw_data = &viewport->DrawDataP;
IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount); IM_ASSERT(draw_data->CmdLists.Size == draw_data->CmdListsCount);
for (int draw_list_n = 0; draw_list_n < draw_data->CmdLists.Size; draw_list_n++) for (ImDrawList* draw_list : draw_data->CmdLists)
draw_data->CmdLists[draw_list_n]->_PopUnusedDrawCmd(); draw_list->_PopUnusedDrawCmd();
g.IO.MetricsRenderVertices += draw_data->TotalVtxCount; g.IO.MetricsRenderVertices += draw_data->TotalVtxCount;
g.IO.MetricsRenderIndices += draw_data->TotalIdxCount; g.IO.MetricsRenderIndices += draw_data->TotalIdxCount;
@ -5727,7 +5727,7 @@ bool ImGui::IsItemEdited()
void ImGui::SetNextItemAllowOverlap() void ImGui::SetNextItemAllowOverlap()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.NextItemData.ItemFlags |= ImGuiItemflags_AllowOverlap; g.NextItemData.ItemFlags |= ImGuiItemFlags_AllowOverlap;
} }
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
@ -6600,18 +6600,18 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
ImVec2 collapse_button_pos; ImVec2 collapse_button_pos;
if (has_close_button) if (has_close_button)
{ {
pad_r += button_sz; close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); pad_r += button_sz + style.ItemInnerSpacing.x;
} }
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right) if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
{ {
pad_r += button_sz; collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - button_sz, title_bar_rect.Min.y + style.FramePadding.y);
collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y); pad_r += button_sz + style.ItemInnerSpacing.x;
} }
if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left) if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
{ {
collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y); collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y + style.FramePadding.y);
pad_l += button_sz; pad_l += button_sz + style.ItemInnerSpacing.x;
} }
// Collapse button (submitting first so it gets priority when choosing a navigation init fallback) // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
@ -6705,9 +6705,9 @@ ImGuiWindow* ImGui::FindBlockingModal(ImGuiWindow* window)
return NULL; return NULL;
// Find a modal that has common parent with specified window. Specified window should be positioned behind that modal. // Find a modal that has common parent with specified window. Specified window should be positioned behind that modal.
for (int i = 0; i < g.OpenPopupStack.Size; i++) for (ImGuiPopupData& popup_data : g.OpenPopupStack)
{ {
ImGuiWindow* popup_window = g.OpenPopupStack.Data[i].Window; ImGuiWindow* popup_window = popup_data.Window;
if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal)) if (popup_window == NULL || !(popup_window->Flags & ImGuiWindowFlags_Modal))
continue; continue;
if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows. if (!popup_window->Active && !popup_window->WasActive) // Check WasActive, because this code may run before popup renders on current frame, also check Active to handle newly created windows.
@ -7532,9 +7532,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags, const
{ {
// Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source. // Docking: Dragging a dockable window (or any of its child) turns it into a drag and drop source.
// We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it. // We need to do this _before_ we overwrite window->DC.LastItemId below because BeginDockableDragDropSource() also overwrites it.
if ((g.MovingWindow == window) && (g.IO.ConfigDockingWithShift == g.IO.KeyShift)) if (g.MovingWindow == window && (window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0)
if ((window->RootWindowDockTree->Flags & ImGuiWindowFlags_NoDocking) == 0) BeginDockableDragDropSource(window);
BeginDockableDragDropSource(window);
// Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead. // Docking: Any dockable window can act as a target. For dock node hosts we call BeginDockableDragDropTarget() in DockNodeUpdate() instead.
if (g.DragDropActive && !(flags & ImGuiWindowFlags_NoDocking)) if (g.DragDropActive && !(flags & ImGuiWindowFlags_NoDocking))
@ -9727,8 +9726,8 @@ static const char* GetMouseSourceName(ImGuiMouseSource source)
static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e) static void DebugPrintInputEvent(const char* prefix, const ImGuiInputEvent* e)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MousePos) { if (e->MousePos.PosX == -FLT_MAX && e->MousePos.PosY == -FLT_MAX) IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (-FLT_MAX, -FLT_MAX)\n", prefix); else IMGUI_DEBUG_LOG_IO("[io] %s: MousePos (%.1f, %.1f) (%s)\n", prefix, e->MousePos.PosX, e->MousePos.PosY, GetMouseSourceName(e->MousePos.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseWheel.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MouseButton) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseButton %d %s (%s)\n", prefix, e->MouseButton.Button, e->MouseButton.Down ? "Down" : "Up", GetMouseSourceName(e->MouseButton.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; } if (e->Type == ImGuiInputEventType_MouseWheel) { IMGUI_DEBUG_LOG_IO("[io] %s: MouseWheel (%.3f, %.3f) (%s)\n", prefix, e->MouseWheel.WheelX, e->MouseWheel.WheelY, GetMouseSourceName(e->MouseWheel.MouseSource)); return; }
if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; } if (e->Type == ImGuiInputEventType_MouseViewport){IMGUI_DEBUG_LOG_IO("[io] %s: MouseViewport (0x%08X)\n", prefix, e->MouseViewport.HoveredViewportID); return; }
if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; } if (e->Type == ImGuiInputEventType_Key) { IMGUI_DEBUG_LOG_IO("[io] %s: Key \"%s\" %s\n", prefix, ImGui::GetKeyName(e->Key.Key), e->Key.Down ? "Down" : "Up"); return; }
@ -10474,7 +10473,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg, ImGu
// Gets back to previous line and continue with horizontal layout // Gets back to previous line and continue with horizontal layout
// offset_from_start_x == 0 : follow right after previous item // offset_from_start_x == 0 : follow right after previous item
// offset_from_start_x != 0 : align to specified x position (relative to window/group left) // offset_from_start_x != 0 : align to specified x position (relative to window/group left)
// spacing_w < 0 : use default spacing if pos_x == 0, no spacing if pos_x != 0 // spacing_w < 0 : use default spacing if offset_from_start_x == 0, no spacing if offset_from_start_x != 0
// spacing_w >= 0 : enforce spacing amount // spacing_w >= 0 : enforce spacing amount
void ImGui::SameLine(float offset_from_start_x, float spacing_w) void ImGui::SameLine(float offset_from_start_x, float spacing_w)
{ {
@ -10508,9 +10507,6 @@ ImVec2 ImGui::GetCursorScreenPos()
return window->DC.CursorPos; return window->DC.CursorPos;
} }
// 2022/08/05: Setting cursor position also extend boundaries (via modifying CursorMaxPos) used to compute window size, group size etc.
// I believe this was is a judicious choice but it's probably being relied upon (it has been the case since 1.31 and 1.50)
// It would be sane if we requested user to use SetCursorPos() + Dummy(ImVec2(0,0)) to extend CursorMaxPos...
void ImGui::SetCursorScreenPos(const ImVec2& pos) void ImGui::SetCursorScreenPos(const ImVec2& pos)
{ {
ImGuiWindow* window = GetCurrentWindow(); ImGuiWindow* window = GetCurrentWindow();
@ -12131,6 +12127,19 @@ void ImGui::NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result)
NavUpdateAnyRequestFlag(); NavUpdateAnyRequestFlag();
} }
// Called by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere
void ImGui::NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data)
{
ImGuiContext& g = *GImGui;
g.NavMoveScoringItems = false;
g.LastItemData.ID = tree_node_data->ID;
g.LastItemData.InFlags = tree_node_data->InFlags;
g.LastItemData.NavRect = tree_node_data->NavRect;
NavApplyItemToResult(result); // Result this instead of implementing a NavApplyPastTreeNodeToResult()
NavClearPreferredPosForAxis(ImGuiAxis_Y);
NavUpdateAnyRequestFlag();
}
void ImGui::NavMoveRequestCancel() void ImGui::NavMoveRequestCancel()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -12627,7 +12636,7 @@ void ImGui::NavUpdateCreateMoveRequest()
scoring_rect.TranslateY(scoring_rect_offset_y); scoring_rect.TranslateY(scoring_rect_offset_y);
if (g.NavMoveSubmitted) if (g.NavMoveSubmitted)
NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags); NavBiasScoringRect(scoring_rect, window->RootWindowForNav->NavPreferredScoringPosRel[g.NavLayer], g.NavMoveDir, g.NavMoveFlags);
IM_ASSERT(!scoring_rect.IsInverted()); // Ensure if we have a finite, non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem(). IM_ASSERT(!scoring_rect.IsInverted()); // Ensure we have a non-inverted bounding box here will allow us to remove extraneous ImFabs() calls in NavScoreItem().
//GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG] //GetForegroundDrawList()->AddRect(scoring_rect.Min, scoring_rect.Max, IM_COL32(255,200,0,255)); // [DEBUG]
//if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG] //if (!g.NavScoringNoClipRect.IsInverted()) { GetForegroundDrawList()->AddRect(g.NavScoringNoClipRect.Min, g.NavScoringNoClipRect.Max, IM_COL32(255, 200, 0, 255)); } // [DEBUG]
} }
@ -13903,9 +13912,9 @@ ImGuiSettingsHandler* ImGui::FindSettingsHandler(const char* type_name)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
const ImGuiID type_hash = ImHashStr(type_name); const ImGuiID type_hash = ImHashStr(type_name);
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (g.SettingsHandlers[handler_n].TypeHash == type_hash) if (handler.TypeHash == type_hash)
return &g.SettingsHandlers[handler_n]; return &handler;
return NULL; return NULL;
} }
@ -13914,9 +13923,9 @@ void ImGui::ClearIniSettings()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.SettingsIniData.clear(); g.SettingsIniData.clear();
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (g.SettingsHandlers[handler_n].ClearAllFn) if (handler.ClearAllFn != NULL)
g.SettingsHandlers[handler_n].ClearAllFn(&g, &g.SettingsHandlers[handler_n]); handler.ClearAllFn(&g, &handler);
} }
bool ImGui::LoadIniSettingsFromDisk(const char* ini_filename, bool redundancy) bool ImGui::LoadIniSettingsFromDisk(const char* ini_filename, bool redundancy)
@ -13987,9 +13996,9 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
// Call pre-read handlers // Call pre-read handlers
// Some types will clear their data (e.g. dock information) some types will allow merge/override (window) // Some types will clear their data (e.g. dock information) some types will allow merge/override (window)
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (g.SettingsHandlers[handler_n].ReadInitFn) if (handler.ReadInitFn != NULL)
g.SettingsHandlers[handler_n].ReadInitFn(&g, &g.SettingsHandlers[handler_n]); handler.ReadInitFn(&g, &handler);
void* entry_data = NULL; void* entry_data = NULL;
ImGuiSettingsHandler* entry_handler = NULL; ImGuiSettingsHandler* entry_handler = NULL;
@ -14033,9 +14042,9 @@ void ImGui::LoadIniSettingsFromMemory(const char* ini_data, size_t ini_size)
memcpy(buf, ini_data, ini_size); memcpy(buf, ini_data, ini_size);
// Call post-read handlers // Call post-read handlers
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
if (g.SettingsHandlers[handler_n].ApplyAllFn) if (handler.ApplyAllFn != NULL)
g.SettingsHandlers[handler_n].ApplyAllFn(&g, &g.SettingsHandlers[handler_n]); handler.ApplyAllFn(&g, &handler);
} }
bool ImGui::SaveIniSettingsToDisk(const char* ini_filename, bool redundancy) bool ImGui::SaveIniSettingsToDisk(const char* ini_filename, bool redundancy)
@ -14086,11 +14095,8 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
g.SettingsDirtyTimer = 0.0f; g.SettingsDirtyTimer = 0.0f;
g.SettingsIniData.Buf.resize(0); g.SettingsIniData.Buf.resize(0);
g.SettingsIniData.Buf.push_back(0); g.SettingsIniData.Buf.push_back(0);
for (int handler_n = 0; handler_n < g.SettingsHandlers.Size; handler_n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
{ handler.WriteAllFn(&g, &handler, &g.SettingsIniData);
ImGuiSettingsHandler* handler = &g.SettingsHandlers[handler_n];
handler->WriteAllFn(&g, handler, &g.SettingsIniData);
}
if (out_size) if (out_size)
*out_size = (size_t)g.SettingsIniData.size(); *out_size = (size_t)g.SettingsIniData.size();
return g.SettingsIniData.c_str(); return g.SettingsIniData.c_str();
@ -14159,8 +14165,8 @@ void ImGui::ClearWindowSettings(const char* name)
static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*) static void WindowSettingsHandler_ClearAll(ImGuiContext* ctx, ImGuiSettingsHandler*)
{ {
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
for (int i = 0; i != g.Windows.Size; i++) for (ImGuiWindow* window : g.Windows)
g.Windows[i]->SettingsOffset = -1; window->SettingsOffset = -1;
g.SettingsWindows.clear(); g.SettingsWindows.clear();
} }
@ -14211,9 +14217,8 @@ static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
// Gather data from windows that were active during this session // Gather data from windows that were active during this session
// (if a window wasn't opened in this session we preserve its settings) // (if a window wasn't opened in this session we preserve its settings)
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
for (int i = 0; i != g.Windows.Size; i++) for (ImGuiWindow* window : g.Windows)
{ {
ImGuiWindow* window = g.Windows[i];
if (window->Flags & ImGuiWindowFlags_NoSavedSettings) if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
continue; continue;
@ -17372,14 +17377,13 @@ static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* o
r.Max.x -= style.WindowBorderSize; r.Max.x -= style.WindowBorderSize;
float button_sz = g.FontSize; float button_sz = g.FontSize;
ImVec2 window_menu_button_pos = r.Min;
r.Min.x += style.FramePadding.x; r.Min.x += style.FramePadding.x;
r.Max.x -= style.FramePadding.x; r.Max.x -= style.FramePadding.x;
ImVec2 window_menu_button_pos = ImVec2(r.Min.x, r.Min.y + style.FramePadding.y);
if (node->HasCloseButton) if (node->HasCloseButton)
{ {
r.Max.x -= button_sz; if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
if (out_close_button_pos) *out_close_button_pos = ImVec2(r.Max.x - style.FramePadding.x, r.Min.y); r.Max.x -= button_sz + style.ItemInnerSpacing.x;
} }
if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Left) if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Left)
{ {
@ -17387,8 +17391,8 @@ static void ImGui::DockNodeCalcTabBarLayout(const ImGuiDockNode* node, ImRect* o
} }
else if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Right) else if (node->HasWindowMenuButton && style.WindowMenuButtonPosition == ImGuiDir_Right)
{ {
r.Max.x -= button_sz + style.FramePadding.x; window_menu_button_pos = ImVec2(r.Max.x - button_sz, r.Min.y + style.FramePadding.y);
window_menu_button_pos = ImVec2(r.Max.x, r.Min.y); r.Max.x -= button_sz + style.ItemInnerSpacing.x;
} }
if (out_tab_bar_rect) { *out_tab_bar_rect = r; } if (out_tab_bar_rect) { *out_tab_bar_rect = r; }
if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; } if (out_window_menu_button_pos) { *out_window_menu_button_pos = window_menu_button_pos; }
@ -18879,6 +18883,17 @@ void ImGui::BeginDockableDragDropSource(ImGuiWindow* window)
IM_ASSERT(g.MovingWindow == window); IM_ASSERT(g.MovingWindow == window);
IM_ASSERT(g.CurrentWindow == window); IM_ASSERT(g.CurrentWindow == window);
// 0: Hold SHIFT to disable docking, 1: Hold SHIFT to enable docking.
if (g.IO.ConfigDockingWithShift != g.IO.KeyShift)
{
// When ConfigDockingWithShift is set, display a tooltip to increase UI affordance.
// We cannot set for HoveredWindowUnderMovingWindow != NULL here, as it is only valid/useful when drag and drop is already active
// (because of the 'is_mouse_dragging_with_an_expected_destination' logic in UpdateViewportsNewFrame() function)
if (g.IO.ConfigDockingWithShift && g.MouseStationaryTimer >= 1.0f && g.ActiveId >= 1.0f)
SetTooltip("%s", LocalizeGetMsg(ImGuiLocKey_DockingHoldShiftToDock));
return;
}
g.LastItemData.ID = window->MoveId; g.LastItemData.ID = window->MoveId;
window = window->RootWindowDockTree; window = window->RootWindowDockTree;
IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0); IM_ASSERT((window->Flags & ImGuiWindowFlags_NoDocking) == 0);
@ -19404,10 +19419,9 @@ void ImGui::DebugRenderViewportThumbnail(ImDrawList* draw_list, ImGuiViewportP*
ImVec2 scale = bb.GetSize() / viewport->Size; ImVec2 scale = bb.GetSize() / viewport->Size;
ImVec2 off = bb.Min - viewport->Pos * scale; ImVec2 off = bb.Min - viewport->Pos * scale;
float alpha_mul = (viewport->Flags & ImGuiViewportFlags_IsMinimized) ? 0.30f : 1.00f; float alpha_mul = (viewport->Flags & ImGuiViewportFlags_IsMinimized) ? 0.30f : 1.00f;
window->DrawList->AddRectFilled(bb.Min, bb.Max, ImGui::GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f)); window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Border, alpha_mul * 0.40f));
for (int i = 0; i != g.Windows.Size; i++) for (ImGuiWindow* thumb_window : g.Windows)
{ {
ImGuiWindow* thumb_window = g.Windows[i];
if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow)) if (!thumb_window->WasActive || (thumb_window->Flags & ImGuiWindowFlags_ChildWindow))
continue; continue;
if (thumb_window->Viewport != viewport) if (thumb_window->Viewport != viewport)
@ -19436,13 +19450,12 @@ static void RenderViewportsThumbnails()
// We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports. // We don't display full monitor bounds (we could, but it often looks awkward), instead we display just enough to cover all of our viewports.
float SCALE = 1.0f / 8.0f; float SCALE = 1.0f / 8.0f;
ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX); ImRect bb_full(FLT_MAX, FLT_MAX, -FLT_MAX, -FLT_MAX);
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
bb_full.Add(g.Viewports[n]->GetMainRect()); bb_full.Add(viewport->GetMainRect());
ImVec2 p = window->DC.CursorPos; ImVec2 p = window->DC.CursorPos;
ImVec2 off = p - bb_full.Min * SCALE; ImVec2 off = p - bb_full.Min * SCALE;
for (int n = 0; n < g.Viewports.Size; n++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
ImGuiViewportP* viewport = g.Viewports[n];
ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE); ImRect viewport_draw_bb(off + (viewport->Pos) * SCALE, off + (viewport->Pos + viewport->Size) * SCALE);
ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb); ImGui::DebugRenderViewportThumbnail(window->DrawList, viewport, viewport_draw_bb);
} }
@ -19557,9 +19570,8 @@ static void MetricsHelpMarker(const char* desc)
// [DEBUG] List fonts in a font atlas and display its texture // [DEBUG] List fonts in a font atlas and display its texture
void ImGui::ShowFontAtlas(ImFontAtlas* atlas) void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
{ {
for (int i = 0; i < atlas->Fonts.Size; i++) for (ImFont* font : atlas->Fonts)
{ {
ImFont* font = atlas->Fonts[i];
PushID(font); PushID(font);
DebugNodeFont(font); DebugNodeFont(font);
PopID(); PopID();
@ -19760,9 +19772,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship! // Here we display windows in their submitted order/hierarchy, however note that the Begin stack doesn't constitute a Parent<>Child relationship!
ImVector<ImGuiWindow*>& temp_buffer = g.WindowsTempSortBuffer; ImVector<ImGuiWindow*>& temp_buffer = g.WindowsTempSortBuffer;
temp_buffer.resize(0); temp_buffer.resize(0);
for (int i = 0; i < g.Windows.Size; i++) for (ImGuiWindow* window : g.Windows)
if (g.Windows[i]->LastFrameActive + 1 >= g.FrameCount) if (window->LastFrameActive + 1 >= g.FrameCount)
temp_buffer.push_back(g.Windows[i]); temp_buffer.push_back(window);
struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } }; struct Func { static int IMGUI_CDECL WindowComparerByBeginOrder(const void* lhs, const void* rhs) { return ((int)(*(const ImGuiWindow* const *)lhs)->BeginOrderWithinContext - (*(const ImGuiWindow* const*)rhs)->BeginOrderWithinContext); } };
ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder); ImQsort(temp_buffer.Data, (size_t)temp_buffer.Size, sizeof(ImGuiWindow*), Func::WindowComparerByBeginOrder);
DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL); DebugNodeWindowsListByBeginStackParent(temp_buffer.Data, temp_buffer.Size, NULL);
@ -19774,22 +19786,21 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// DrawLists // DrawLists
int drawlist_count = 0; int drawlist_count = 0;
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) for (ImGuiViewportP* viewport : g.Viewports)
drawlist_count += g.Viewports[viewport_i]->DrawDataP.CmdLists.Size; drawlist_count += viewport->DrawDataP.CmdLists.Size;
if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count)) if (TreeNode("DrawLists", "DrawLists (%d)", drawlist_count))
{ {
Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh); Checkbox("Show ImDrawCmd mesh when hovering", &cfg->ShowDrawCmdMesh);
Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes); Checkbox("Show ImDrawCmd bounding boxes when hovering", &cfg->ShowDrawCmdBoundingBoxes);
for (int viewport_i = 0; viewport_i < g.Viewports.Size; viewport_i++) for (ImGuiViewportP* viewport : g.Viewports)
{ {
ImGuiViewportP* viewport = g.Viewports[viewport_i];
bool viewport_has_drawlist = false; bool viewport_has_drawlist = false;
for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
{ {
if (!viewport_has_drawlist) if (!viewport_has_drawlist)
Text("Active DrawLists in Viewport #%d, ID: 0x%08X", viewport->Idx, viewport->ID); Text("Active DrawLists in Viewport #%d, ID: 0x%08X", viewport->Idx, viewport->ID);
viewport_has_drawlist = true; viewport_has_drawlist = true;
DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
} }
} }
TreePop(); TreePop();
@ -19833,22 +19844,21 @@ void ImGui::ShowMetricsWindow(bool* p_open)
viewport->Window ? viewport->Window->Name : "N/A"); viewport->Window ? viewport->Window->Name : "N/A");
TreePop(); TreePop();
} }
for (int i = 0; i < g.Viewports.Size; i++) for (ImGuiViewportP* viewport : g.Viewports)
DebugNodeViewport(g.Viewports[i]); DebugNodeViewport(viewport);
TreePop(); TreePop();
} }
// Details for Popups // Details for Popups
if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size)) if (TreeNode("Popups", "Popups (%d)", g.OpenPopupStack.Size))
{ {
for (int i = 0; i < g.OpenPopupStack.Size; i++) for (const ImGuiPopupData& popup_data : g.OpenPopupStack)
{ {
// As it's difficult to interact with tree nodes while popups are open, we display everything inline. // As it's difficult to interact with tree nodes while popups are open, we display everything inline.
const ImGuiPopupData* popup_data = &g.OpenPopupStack[i]; ImGuiWindow* window = popup_data.Window;
ImGuiWindow* window = popup_data->Window;
BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'", BulletText("PopupID: %08x, Window: '%s' (%s%s), BackupNavWindow '%s', ParentWindow '%s'",
popup_data->PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "", popup_data.PopupId, window ? window->Name : "NULL", window && (window->Flags & ImGuiWindowFlags_ChildWindow) ? "Child;" : "", window && (window->Flags & ImGuiWindowFlags_ChildMenu) ? "Menu;" : "",
popup_data->BackupNavWindow ? popup_data->BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL"); popup_data.BackupNavWindow ? popup_data.BackupNavWindow->Name : "NULL", window && window->ParentWindow ? window->ParentWindow->Name : "NULL");
} }
TreePop(); TreePop();
} }
@ -19929,8 +19939,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer); Text("SettingsDirtyTimer %.2f", g.SettingsDirtyTimer);
if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size)) if (TreeNode("SettingsHandlers", "Settings handlers: (%d)", g.SettingsHandlers.Size))
{ {
for (int n = 0; n < g.SettingsHandlers.Size; n++) for (ImGuiSettingsHandler& handler : g.SettingsHandlers)
BulletText("\"%s\"", g.SettingsHandlers[n].TypeName); BulletText("\"%s\"", handler.TypeName);
TreePop(); TreePop();
} }
if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size())) if (TreeNode("SettingsWindows", "Settings packed data: Windows: %d bytes", g.SettingsWindows.size()))
@ -20119,9 +20129,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Overlay: Display windows Rectangles and Begin Order // Overlay: Display windows Rectangles and Begin Order
if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder) if (cfg->ShowWindowsRects || cfg->ShowWindowsBeginOrder)
{ {
for (int n = 0; n < g.Windows.Size; n++) for (ImGuiWindow* window : g.Windows)
{ {
ImGuiWindow* window = g.Windows[n];
if (!window->WasActive) if (!window->WasActive)
continue; continue;
ImDrawList* draw_list = GetForegroundDrawList(window); ImDrawList* draw_list = GetForegroundDrawList(window);
@ -20197,8 +20206,8 @@ void ImGui::DebugNodeColumns(ImGuiOldColumns* columns)
if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags)) if (!TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
return; return;
BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX); BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
for (int column_n = 0; column_n < columns->Columns.Size; column_n++) for (ImGuiOldColumnData& column : columns->Columns)
BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm)); BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", (int)columns->Columns.index_from_ptr(&column), column.OffsetNorm, GetColumnOffsetFromNorm(columns, column.OffsetNorm));
TreePop(); TreePop();
} }
@ -20519,11 +20528,8 @@ void ImGui::DebugNodeStorage(ImGuiStorage* storage, const char* label)
{ {
if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes())) if (!TreeNode(label, "%s: %d entries, %d bytes", label, storage->Data.Size, storage->Data.size_in_bytes()))
return; return;
for (int n = 0; n < storage->Data.Size; n++) for (const ImGuiStorage::ImGuiStoragePair& p : storage->Data)
{
const ImGuiStorage::ImGuiStoragePair& p = storage->Data[n];
BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer. BulletText("Key 0x%08X Value { i: %d }", p.key, p.val_i); // Important: we currently don't store a type, real value may not be integer.
}
TreePop(); TreePop();
} }
@ -20594,8 +20600,8 @@ void ImGui::DebugNodeViewport(ImGuiViewportP* viewport)
(flags & ImGuiViewportFlags_NoAutoMerge) ? " NoAutoMerge" : "", (flags & ImGuiViewportFlags_NoAutoMerge) ? " NoAutoMerge" : "",
(flags & ImGuiViewportFlags_TopMost) ? " TopMost" : "", (flags & ImGuiViewportFlags_TopMost) ? " TopMost" : "",
(flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : ""); (flags & ImGuiViewportFlags_CanHostOtherWindows) ? " CanHostOtherWindows" : "");
for (int draw_list_i = 0; draw_list_i < viewport->DrawDataP.CmdLists.Size; draw_list_i++) for (ImDrawList* draw_list : viewport->DrawDataP.CmdLists)
DebugNodeDrawList(NULL, viewport, viewport->DrawDataP.CmdLists[draw_list_i], "DrawList"); DebugNodeDrawList(NULL, viewport, draw_list, "DrawList");
TreePop(); TreePop();
} }
} }
@ -20660,8 +20666,8 @@ void ImGui::DebugNodeWindow(ImGuiWindow* window, const char* label)
if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); } if (window->DC.ChildWindows.Size > 0) { DebugNodeWindowsList(&window->DC.ChildWindows, "ChildWindows"); }
if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size)) if (window->ColumnsStorage.Size > 0 && TreeNode("Columns", "Columns sets (%d)", window->ColumnsStorage.Size))
{ {
for (int n = 0; n < window->ColumnsStorage.Size; n++) for (ImGuiOldColumns& columns : window->ColumnsStorage)
DebugNodeColumns(&window->ColumnsStorage[n]); DebugNodeColumns(&columns);
TreePop(); TreePop();
} }
DebugNodeStorage(&window->StateStorage, "Storage"); DebugNodeStorage(&window->StateStorage, "Storage");
@ -20798,6 +20804,38 @@ void ImGui::ShowDebugLogWindow(bool* p_open)
// [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL) // [SECTION] OTHER DEBUG TOOLS (ITEM PICKER, STACK TOOL)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Draw a small cross at current CursorPos in current window's DrawList
void ImGui::DebugDrawCursorPos(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImVec2 pos = window->DC.CursorPos;
window->DrawList->AddLine(ImVec2(pos.x, pos.y - 3.0f), ImVec2(pos.x, pos.y + 4.0f), col, 1.0f);
window->DrawList->AddLine(ImVec2(pos.x - 3.0f, pos.y), ImVec2(pos.x + 4.0f, pos.y), col, 1.0f);
}
// Draw a 10px wide rectangle around CurposPos.x using Line Y1/Y2 in current window's DrawList
void ImGui::DebugDrawLineExtents(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
float curr_x = window->DC.CursorPos.x;
float line_y1 = (window->DC.IsSameLine ? window->DC.CursorPosPrevLine.y : window->DC.CursorPos.y);
float line_y2 = line_y1 + (window->DC.IsSameLine ? window->DC.PrevLineSize.y : window->DC.CurrLineSize.y);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y1), ImVec2(curr_x + 5.0f, line_y1), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 0.5f, line_y1), ImVec2(curr_x - 0.5f, line_y2), col, 1.0f);
window->DrawList->AddLine(ImVec2(curr_x - 5.0f, line_y2), ImVec2(curr_x + 5.0f, line_y2), col, 1.0f);
}
// Draw last item rect in ForegroundDrawList (so it is always visible)
void ImGui::DebugDrawItemRect(ImU32 col)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col);
}
// [DEBUG] Locate item position/rectangle given an ID.
static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green static const ImU32 DEBUG_LOCATE_ITEM_COLOR = IM_COL32(0, 255, 0, 255); // Green
void ImGui::DebugLocateItem(ImGuiID target_id) void ImGui::DebugLocateItem(ImGuiID target_id)

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (headers) // (headers)
// Help: // Help:
@ -25,8 +25,8 @@
// Library Version // Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.89.8" #define IMGUI_VERSION "1.89.9"
#define IMGUI_VERSION_NUM 18980 #define IMGUI_VERSION_NUM 18990
#define IMGUI_HAS_TABLE #define IMGUI_HAS_TABLE
#define IMGUI_HAS_VIEWPORT // Viewport WIP branch #define IMGUI_HAS_VIEWPORT // Viewport WIP branch
#define IMGUI_HAS_DOCK // Docking WIP branch #define IMGUI_HAS_DOCK // Docking WIP branch
@ -361,8 +361,8 @@ namespace ImGui
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ! IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport. IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport.
IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (useful if you want to do your own drawing via the DrawList API) IMGUI_API ImVec2 GetWindowPos(); // get current window position in screen space (note: it is unlikely you need to use this. Consider using current layout pos instead, GetScreenCursorPos())
IMGUI_API ImVec2 GetWindowSize(); // get current window size IMGUI_API ImVec2 GetWindowSize(); // get current window size (note: it is unlikely you need to use this. Consider using GetScreenCursorPos() and e.g. GetContentRegionAvail() instead)
IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x) IMGUI_API float GetWindowWidth(); // get current window width (shortcut for GetWindowSize().x)
IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y) IMGUI_API float GetWindowHeight(); // get current window height (shortcut for GetWindowSize().y)
IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window. IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window.
@ -1103,7 +1103,7 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node ImGuiTreeNodeFlags_OpenOnDoubleClick = 1 << 6, // Need double-click to open node
ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open. ImGuiTreeNodeFlags_OpenOnArrow = 1 << 7, // Only open when clicking on the arrow part. If ImGuiTreeNodeFlags_OpenOnDoubleClick is also set, single-click arrow or double-click all box to open.
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes). ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes).
ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow. IMPORTANT: node can still be marked open/close if you don't set the _Leaf flag!
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding(). ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default. ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area). ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area).
@ -1999,7 +1999,7 @@ struct ImGuiStyle
float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly). float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines. ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines.
ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label). ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
ImVec2 CellPadding; // Padding within a table cell ImVec2 CellPadding; // Padding within a table cell. CellPadding.y may be altered between different rows.
ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much! ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2). float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1). float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
@ -2166,6 +2166,9 @@ struct ImGuiIO
void* _UnusedPadding; // Unused field to keep data structure the same size. void* _UnusedPadding; // Unused field to keep data structure the same size.
#endif #endif
// Optional: Platform locale
ImWchar PlatformLocaleDecimalPoint; // '.' // [Experimental] Configure decimal point e.g. '.' or ',' useful for some languages (e.g. German), generally pulled from *localeconv()->decimal_point
//------------------------------------------------------------------ //------------------------------------------------------------------
// Input - Call before calling NewFrame() // Input - Call before calling NewFrame()
//------------------------------------------------------------------ //------------------------------------------------------------------
@ -2551,12 +2554,14 @@ struct ImGuiListClipper
IMGUI_API void End(); // Automatically called on the last call of Step() that returns false. IMGUI_API void End(); // Automatically called on the last call of Step() that returns false.
IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items. IMGUI_API bool Step(); // Call until it returns false. The DisplayStart/DisplayEnd fields will be set and you can process/draw those items.
// Call IncludeRangeByIndices() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility. // Call IncludeItemByIndex() or IncludeItemsByIndex() *BEFORE* first call to Step() if you need a range of items to not be clipped, regardless of their visibility.
// (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range). // (Due to alignment / padding of certain items it is possible that an extra item may be included on either end of the display range).
IMGUI_API void IncludeRangeByIndices(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped. inline void IncludeItemByIndex(int item_index) { IncludeItemsByIndex(item_index, item_index + 1); }
IMGUI_API void IncludeItemsByIndex(int item_begin, int item_end); // item_end is exclusive e.g. use (42, 42+1) to make item 42 never clipped.
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeRangeByIndices(item_begin, item_end); } // [renamed in 1.89.6] inline void IncludeRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.9]
inline void ForceDisplayRangeByIndices(int item_begin, int item_end) { IncludeItemsByIndex(item_begin, item_end); } // [renamed in 1.89.6]
//inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79] //inline ImGuiListClipper(int items_count, float items_height = -1.0f) { memset(this, 0, sizeof(*this)); ItemsCount = -1; Begin(items_count, items_height); } // [removed in 1.79]
#endif #endif
}; };
@ -2859,7 +2864,7 @@ struct ImDrawList
// Advanced: Channels // Advanced: Channels
// - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives) // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit FG primitives before BG primitives)
// - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end) // - Use to minimize draw calls (e.g. if going back-and-forth between multiple clipping rectangles, prefer to append into separate channels then merge at the end)
// - FIXME-OBSOLETE: This API shouldn't have been in ImDrawList in the first place! // - This API shouldn't have been in ImDrawList in the first place!
// Prefer using your own persistent instance of ImDrawListSplitter as you can stack them. // Prefer using your own persistent instance of ImDrawListSplitter as you can stack them.
// Using the ImDrawList::ChannelsXXXX you cannot stack a split over another. // Using the ImDrawList::ChannelsXXXX you cannot stack a split over another.
inline void ChannelsSplit(int count) { _Splitter.Split(this, count); } inline void ChannelsSplit(int count) { _Splitter.Split(this, count); }

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (demo code) // (demo code)
// Help: // Help:
@ -10,9 +10,9 @@
// Read imgui.cpp for more details, documentation and comments. // Read imgui.cpp for more details, documentation and comments.
// Get the latest version at https://github.com/ocornut/imgui // Get the latest version at https://github.com/ocornut/imgui
// ------------------------------------------------- //---------------------------------------------------
// PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT! // PLEASE DO NOT REMOVE THIS FILE FROM YOUR PROJECT!
// ------------------------------------------------- //---------------------------------------------------
// Message to the person tempted to delete this file when integrating Dear ImGui into their codebase: // Message to the person tempted to delete this file when integrating Dear ImGui into their codebase:
// Think again! It is the most useful reference code that you and other coders will want to refer to and call. // Think again! It is the most useful reference code that you and other coders will want to refer to and call.
// Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app! // Have the ImGui::ShowDemoWindow() function wired in an always-available debug menu of your game/app!
@ -26,14 +26,23 @@
// Thank you, // Thank you,
// -Your beloved friend, imgui_demo.cpp (which you won't delete) // -Your beloved friend, imgui_demo.cpp (which you won't delete)
// Message to beginner C/C++ programmers about the meaning of the 'static' keyword: //--------------------------------------------
// In this demo code, we frequently use 'static' variables inside functions. A static variable persists across calls, // ABOUT THE MEANING OF THE 'static' KEYWORD:
// so it is essentially like a global variable but declared inside the scope of the function. We do this as a way to //--------------------------------------------
// gather code and data in the same place, to make the demo source code faster to read, faster to write, and smaller // In this demo code, we frequently use 'static' variables inside functions.
// in size. It also happens to be a convenient way of storing simple UI related information as long as your function // A static variable persists across calls. It is essentially a global variable but declared inside the scope of the function.
// doesn't need to be reentrant or used in multiple threads. This might be a pattern you will want to use in your code, // Think of "static int n = 0;" as "global int n = 0;" !
// but most of the real data you would be editing is likely going to be stored outside your functions. // We do this IN THE DEMO because we want:
// - to gather code and data in the same place.
// - to make the demo source code faster to read, faster to change, smaller in size.
// - it is also a convenient way of storing simple UI related information as long as your function
// doesn't need to be reentrant or used in multiple threads.
// This might be a pattern you will want to use in your code, but most of the data you would be working
// with in a complex codebase is likely going to be stored outside your functions.
//-----------------------------------------
// ABOUT THE CODING STYLE OF OUR DEMO CODE
//-----------------------------------------
// The Demo code in this file is designed to be easy to copy-and-paste into your application! // The Demo code in this file is designed to be easy to copy-and-paste into your application!
// Because of this: // Because of this:
// - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace. // - We never omit the ImGui:: prefix when calling functions, even though most code here is in the same namespace.
@ -95,6 +104,9 @@ Index of this file:
#include <stdio.h> // vsnprintf, sscanf, printf #include <stdio.h> // vsnprintf, sscanf, printf
#include <stdlib.h> // NULL, malloc, free, atoi #include <stdlib.h> // NULL, malloc, free, atoi
#include <stdint.h> // intptr_t #include <stdint.h> // intptr_t
#if !defined(_MSC_VER) || _MSC_VER >= 1800
#include <inttypes.h> // PRId64/PRIu64, not avail in some MinGW headers.
#endif
// Visual Studio warnings // Visual Studio warnings
#ifdef _MSC_VER #ifdef _MSC_VER
@ -143,14 +155,13 @@ Index of this file:
#define vsnprintf _vsnprintf #define vsnprintf _vsnprintf
#endif #endif
// Format specifiers, printing 64-bit hasn't been decently standardized... // Format specifiers for 64-bit values (hasn't been decently standardized before VS2013)
// In a real application you should be using PRId64 and PRIu64 from <inttypes.h> (non-windows) and on Windows define them yourself. #if !defined(PRId64) && defined(_MSC_VER)
#ifdef _MSC_VER #define PRId64 "I64d"
#define IM_PRId64 "I64d" #define PRIu64 "I64u"
#define IM_PRIu64 "I64u" #elif !defined(PRId64)
#else #define PRId64 "lld"
#define IM_PRId64 "lld" #define PRIu64 "llu"
#define IM_PRIu64 "llu"
#endif #endif
// Helpers macros // Helpers macros
@ -177,20 +188,20 @@ Index of this file:
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS) #if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
// Forward Declarations // Forward Declarations
static void ShowExampleAppDockSpace(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppMainMenuBar(); static void ShowExampleAppMainMenuBar();
static void ShowExampleAppConsole(bool* p_open); static void ShowExampleAppConsole(bool* p_open);
static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleAppDockSpace(bool* p_open);
static void ShowExampleAppDocuments(bool* p_open);
static void ShowExampleAppLog(bool* p_open); static void ShowExampleAppLog(bool* p_open);
static void ShowExampleAppLayout(bool* p_open); static void ShowExampleAppLayout(bool* p_open);
static void ShowExampleAppPropertyEditor(bool* p_open); static void ShowExampleAppPropertyEditor(bool* p_open);
static void ShowExampleAppLongText(bool* p_open); static void ShowExampleAppSimpleOverlay(bool* p_open);
static void ShowExampleAppAutoResize(bool* p_open); static void ShowExampleAppAutoResize(bool* p_open);
static void ShowExampleAppConstrainedResize(bool* p_open); static void ShowExampleAppConstrainedResize(bool* p_open);
static void ShowExampleAppSimpleOverlay(bool* p_open);
static void ShowExampleAppFullscreen(bool* p_open); static void ShowExampleAppFullscreen(bool* p_open);
static void ShowExampleAppLongText(bool* p_open);
static void ShowExampleAppWindowTitles(bool* p_open); static void ShowExampleAppWindowTitles(bool* p_open);
static void ShowExampleAppCustomRendering(bool* p_open);
static void ShowExampleMenuFile(); static void ShowExampleMenuFile();
// We split the contents of the big ShowDemoWindow() function into smaller functions // We split the contents of the big ShowDemoWindow() function into smaller functions
@ -256,61 +267,61 @@ void* GImGuiDemoMarkerCallbackUserData = NULL;
void ImGui::ShowDemoWindow(bool* p_open) void ImGui::ShowDemoWindow(bool* p_open)
{ {
// Exceptionally add an extra assert here for people confused about initial Dear ImGui setup // Exceptionally add an extra assert here for people confused about initial Dear ImGui setup
// Most functions would normally just crash if the context is missing. // Most functions would normally just assert/crash if the context is missing.
IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing dear imgui context. Refer to examples app!"); IM_ASSERT(ImGui::GetCurrentContext() != NULL && "Missing Dear ImGui context. Refer to examples app!");
// Examples Apps (accessible from the "Examples" menu) // Examples Apps (accessible from the "Examples" menu)
static bool show_app_main_menu_bar = false; static bool show_app_main_menu_bar = false;
static bool show_app_console = false;
static bool show_app_custom_rendering = false;
static bool show_app_dockspace = false; static bool show_app_dockspace = false;
static bool show_app_documents = false; static bool show_app_documents = false;
static bool show_app_console = false;
static bool show_app_log = false; static bool show_app_log = false;
static bool show_app_layout = false; static bool show_app_layout = false;
static bool show_app_property_editor = false; static bool show_app_property_editor = false;
static bool show_app_long_text = false; static bool show_app_simple_overlay = false;
static bool show_app_auto_resize = false; static bool show_app_auto_resize = false;
static bool show_app_constrained_resize = false; static bool show_app_constrained_resize = false;
static bool show_app_simple_overlay = false;
static bool show_app_fullscreen = false; static bool show_app_fullscreen = false;
static bool show_app_long_text = false;
static bool show_app_window_titles = false; static bool show_app_window_titles = false;
static bool show_app_custom_rendering = false;
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar(); if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function) if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() nodes needs to be submitted early (read comments near the DockSpace function)
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace() if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
if (show_app_console) ShowExampleAppConsole(&show_app_console); if (show_app_console) ShowExampleAppConsole(&show_app_console);
if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
if (show_app_log) ShowExampleAppLog(&show_app_log); if (show_app_log) ShowExampleAppLog(&show_app_log);
if (show_app_layout) ShowExampleAppLayout(&show_app_layout); if (show_app_layout) ShowExampleAppLayout(&show_app_layout);
if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor); if (show_app_property_editor) ShowExampleAppPropertyEditor(&show_app_property_editor);
if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text); if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize); if (show_app_auto_resize) ShowExampleAppAutoResize(&show_app_auto_resize);
if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize); if (show_app_constrained_resize) ShowExampleAppConstrainedResize(&show_app_constrained_resize);
if (show_app_simple_overlay) ShowExampleAppSimpleOverlay(&show_app_simple_overlay);
if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen); if (show_app_fullscreen) ShowExampleAppFullscreen(&show_app_fullscreen);
if (show_app_long_text) ShowExampleAppLongText(&show_app_long_text);
if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles); if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
// Dear ImGui Tools/Apps (accessible from the "Tools" menu) // Dear ImGui Tools (accessible from the "Tools" menu)
static bool show_app_metrics = false; static bool show_tool_metrics = false;
static bool show_app_debug_log = false; static bool show_tool_debug_log = false;
static bool show_app_stack_tool = false; static bool show_tool_stack_tool = false;
static bool show_app_about = false; static bool show_tool_style_editor = false;
static bool show_app_style_editor = false; static bool show_tool_about = false;
if (show_app_metrics) if (show_tool_metrics)
ImGui::ShowMetricsWindow(&show_app_metrics); ImGui::ShowMetricsWindow(&show_tool_metrics);
if (show_app_debug_log) if (show_tool_debug_log)
ImGui::ShowDebugLogWindow(&show_app_debug_log); ImGui::ShowDebugLogWindow(&show_tool_debug_log);
if (show_app_stack_tool) if (show_tool_stack_tool)
ImGui::ShowStackToolWindow(&show_app_stack_tool); ImGui::ShowStackToolWindow(&show_tool_stack_tool);
if (show_app_about) if (show_tool_style_editor)
ImGui::ShowAboutWindow(&show_app_about);
if (show_app_style_editor)
{ {
ImGui::Begin("Dear ImGui Style Editor", &show_app_style_editor); ImGui::Begin("Dear ImGui Style Editor", &show_tool_style_editor);
ImGui::ShowStyleEditor(); ImGui::ShowStyleEditor();
ImGui::End(); ImGui::End();
} }
if (show_tool_about)
ImGui::ShowAboutWindow(&show_tool_about);
// Demonstrate the various window flags. Typically you would just use the default! // Demonstrate the various window flags. Typically you would just use the default!
static bool no_titlebar = false; static bool no_titlebar = false;
@ -373,19 +384,24 @@ void ImGui::ShowDemoWindow(bool* p_open)
{ {
IMGUI_DEMO_MARKER("Menu/Examples"); IMGUI_DEMO_MARKER("Menu/Examples");
ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar); ImGui::MenuItem("Main menu bar", NULL, &show_app_main_menu_bar);
ImGui::SeparatorText("Mini apps");
ImGui::MenuItem("Console", NULL, &show_app_console); ImGui::MenuItem("Console", NULL, &show_app_console);
ImGui::MenuItem("Log", NULL, &show_app_log);
ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering); ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace); ImGui::MenuItem("Dockspace", NULL, &show_app_dockspace);
ImGui::MenuItem("Documents", NULL, &show_app_documents); ImGui::MenuItem("Documents", NULL, &show_app_documents);
ImGui::MenuItem("Log", NULL, &show_app_log);
ImGui::MenuItem("Property editor", NULL, &show_app_property_editor);
ImGui::MenuItem("Simple layout", NULL, &show_app_layout);
ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
ImGui::SeparatorText("Concepts");
ImGui::MenuItem("Auto-resizing window", NULL, &show_app_auto_resize);
ImGui::MenuItem("Constrained-resizing window", NULL, &show_app_constrained_resize);
ImGui::MenuItem("Fullscreen window", NULL, &show_app_fullscreen);
ImGui::MenuItem("Long text display", NULL, &show_app_long_text);
ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
ImGui::EndMenu(); ImGui::EndMenu();
} }
//if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar! //if (ImGui::MenuItem("MenuItem")) {} // You can also use MenuItem() inside a menu bar!
@ -397,11 +413,11 @@ void ImGui::ShowDemoWindow(bool* p_open)
#else #else
const bool has_debug_tools = false; const bool has_debug_tools = false;
#endif #endif
ImGui::MenuItem("Metrics/Debugger", NULL, &show_app_metrics, has_debug_tools); ImGui::MenuItem("Metrics/Debugger", NULL, &show_tool_metrics, has_debug_tools);
ImGui::MenuItem("Debug Log", NULL, &show_app_debug_log, has_debug_tools); ImGui::MenuItem("Debug Log", NULL, &show_tool_debug_log, has_debug_tools);
ImGui::MenuItem("Stack Tool", NULL, &show_app_stack_tool, has_debug_tools); ImGui::MenuItem("Stack Tool", NULL, &show_tool_stack_tool, has_debug_tools);
ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor); ImGui::MenuItem("Style Editor", NULL, &show_tool_style_editor);
ImGui::MenuItem("About Dear ImGui", NULL, &show_app_about); ImGui::MenuItem("About Dear ImGui", NULL, &show_tool_about);
ImGui::EndMenu(); ImGui::EndMenu();
} }
ImGui::EndMenuBar(); ImGui::EndMenuBar();
@ -2203,12 +2219,12 @@ static void ShowDemoWindowWidgets()
ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u"); ImGui::SliderScalar("slider u32 low", ImGuiDataType_U32, &u32_v, &u32_zero, &u32_fifty,"%u");
ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u"); ImGui::SliderScalar("slider u32 high", ImGuiDataType_U32, &u32_v, &u32_hi_a, &u32_hi_b, "%u");
ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u"); ImGui::SliderScalar("slider u32 full", ImGuiDataType_U32, &u32_v, &u32_min, &u32_max, "%u");
ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" IM_PRId64); ImGui::SliderScalar("slider s64 low", ImGuiDataType_S64, &s64_v, &s64_zero, &s64_fifty,"%" PRId64);
ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" IM_PRId64); ImGui::SliderScalar("slider s64 high", ImGuiDataType_S64, &s64_v, &s64_hi_a, &s64_hi_b, "%" PRId64);
ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" IM_PRId64); ImGui::SliderScalar("slider s64 full", ImGuiDataType_S64, &s64_v, &s64_min, &s64_max, "%" PRId64);
ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" IM_PRIu64 " ms"); ImGui::SliderScalar("slider u64 low", ImGuiDataType_U64, &u64_v, &u64_zero, &u64_fifty,"%" PRIu64 " ms");
ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" IM_PRIu64 " ms"); ImGui::SliderScalar("slider u64 high", ImGuiDataType_U64, &u64_v, &u64_hi_a, &u64_hi_b, "%" PRIu64 " ms");
ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" IM_PRIu64 " ms"); ImGui::SliderScalar("slider u64 full", ImGuiDataType_U64, &u64_v, &u64_min, &u64_max, "%" PRIu64 " ms");
ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one); ImGui::SliderScalar("slider float low", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one);
ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic); ImGui::SliderScalar("slider float low log", ImGuiDataType_Float, &f32_v, &f32_zero, &f32_one, "%.10f", ImGuiSliderFlags_Logarithmic);
ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e"); ImGui::SliderScalar("slider float high", ImGuiDataType_Float, &f32_v, &f32_lo_a, &f32_hi_a, "%e");
@ -2221,8 +2237,8 @@ static void ShowDemoWindowWidgets()
ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u"); ImGui::SliderScalar("slider u8 reverse", ImGuiDataType_U8, &u8_v, &u8_max, &u8_min, "%u");
ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d"); ImGui::SliderScalar("slider s32 reverse", ImGuiDataType_S32, &s32_v, &s32_fifty, &s32_zero, "%d");
ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u"); ImGui::SliderScalar("slider u32 reverse", ImGuiDataType_U32, &u32_v, &u32_fifty, &u32_zero, "%u");
ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" IM_PRId64); ImGui::SliderScalar("slider s64 reverse", ImGuiDataType_S64, &s64_v, &s64_fifty, &s64_zero, "%" PRId64);
ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" IM_PRIu64 " ms"); ImGui::SliderScalar("slider u64 reverse", ImGuiDataType_U64, &u64_v, &u64_fifty, &u64_zero, "%" PRIu64 " ms");
IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs"); IMGUI_DEMO_MARKER("Widgets/Data Types/Inputs");
static bool inputs_step = true; static bool inputs_step = true;
@ -3843,6 +3859,14 @@ struct MyItem
// very often by the sorting algorithm it would be a little wasteful. // very often by the sorting algorithm it would be a little wasteful.
static const ImGuiTableSortSpecs* s_current_sort_specs; static const ImGuiTableSortSpecs* s_current_sort_specs;
static void SortWithSortSpecs(ImGuiTableSortSpecs* sort_specs, MyItem* items, int items_count)
{
s_current_sort_specs = sort_specs; // Store in variable accessible by the sort function.
if (items_count > 1)
qsort(items, (size_t)items_count, sizeof(items[0]), MyItem::CompareWithSortSpecs);
s_current_sort_specs = NULL;
}
// Compare function to be used by qsort() // Compare function to be used by qsort()
static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs) static int IMGUI_CDECL CompareWithSortSpecs(const void* lhs, const void* rhs)
{ {
@ -4838,9 +4862,9 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNode("Row height")) if (ImGui::TreeNode("Row height"))
{ {
HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row."); HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would require a unique clipping rectangle per row.");
if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV)) if (ImGui::BeginTable("table_row_height", 1, ImGuiTableFlags_Borders))
{ {
for (int row = 0; row < 10; row++) for (int row = 0; row < 8; row++)
{ {
float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row); float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height); ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
@ -4849,6 +4873,45 @@ static void ShowDemoWindowTables()
} }
ImGui::EndTable(); ImGui::EndTable();
} }
HelpMarker("Showcase using SameLine(0,0) to share Current Line Height between cells.\n\nPlease note that Tables Row Height is not the same thing as Current Line Height, as a table cell may contains multiple lines.");
if (ImGui::BeginTable("table_share_lineheight", 2, ImGuiTableFlags_Borders))
{
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::ColorButton("##1", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
ImGui::TableNextColumn();
ImGui::Text("Line 1");
ImGui::Text("Line 2");
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::ColorButton("##2", ImVec4(0.13f, 0.26f, 0.40f, 1.0f), ImGuiColorEditFlags_None, ImVec2(40, 40));
ImGui::TableNextColumn();
ImGui::SameLine(0.0f, 0.0f); // Reuse line height from previous column
ImGui::Text("Line 1, with SameLine(0,0)");
ImGui::Text("Line 2");
ImGui::EndTable();
}
HelpMarker("Showcase altering CellPadding.y between rows. Note that CellPadding.x is locked for the entire table.");
if (ImGui::BeginTable("table_changing_cellpadding_y", 1, ImGuiTableFlags_Borders))
{
ImGuiStyle& style = ImGui::GetStyle();
for (int row = 0; row < 8; row++)
{
if ((row % 3) == 2)
ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(style.CellPadding.x, 20.0f));
ImGui::TableNextRow(ImGuiTableRowFlags_None);
ImGui::TableNextColumn();
ImGui::Text("CellPadding.y = %.2f", style.CellPadding.y);
if ((row % 3) == 2)
ImGui::PopStyleVar();;
}
ImGui::EndTable();
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -5340,14 +5403,11 @@ static void ShowDemoWindowTables()
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
// Sort our data if sort specs have been changed! // Sort our data if sort specs have been changed!
if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) if (ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs())
if (sorts_specs->SpecsDirty) if (sort_specs->SpecsDirty)
{ {
MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
if (items.Size > 1) sort_specs->SpecsDirty = false;
qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs);
MyItem::s_current_sort_specs = NULL;
sorts_specs->SpecsDirty = false;
} }
// Demonstrate using clipper for large vertical lists // Demonstrate using clipper for large vertical lists
@ -5555,15 +5615,13 @@ static void ShowDemoWindowTables()
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows); ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
// Sort our data if sort specs have been changed! // Sort our data if sort specs have been changed!
ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs(); ImGuiTableSortSpecs* sort_specs = ImGui::TableGetSortSpecs();
if (sorts_specs && sorts_specs->SpecsDirty) if (sort_specs && sort_specs->SpecsDirty)
items_need_sort = true; items_need_sort = true;
if (sorts_specs && items_need_sort && items.Size > 1) if (sort_specs && items_need_sort && items.Size > 1)
{ {
MyItem::s_current_sort_specs = sorts_specs; // Store in variable accessible by the sort function. MyItem::SortWithSortSpecs(sort_specs, items.Data, items.Size);
qsort(&items[0], (size_t)items.Size, sizeof(items[0]), MyItem::CompareWithSortSpecs); sort_specs->SpecsDirty = false;
MyItem::s_current_sort_specs = NULL;
sorts_specs->SpecsDirty = false;
} }
items_need_sort = false; items_need_sort = false;
@ -6292,9 +6350,8 @@ void ImGui::ShowFontSelector(const char* label)
ImFont* font_current = ImGui::GetFont(); ImFont* font_current = ImGui::GetFont();
if (ImGui::BeginCombo(label, font_current->GetDebugName())) if (ImGui::BeginCombo(label, font_current->GetDebugName()))
{ {
for (int n = 0; n < io.Fonts->Fonts.Size; n++) for (ImFont* font : io.Fonts->Fonts)
{ {
ImFont* font = io.Fonts->Fonts[n];
ImGui::PushID((void*)font); ImGui::PushID((void*)font);
if (ImGui::Selectable(font->GetDebugName(), font == font_current)) if (ImGui::Selectable(font->GetDebugName(), font == font_current))
io.FontDefault = font; io.FontDefault = font;
@ -6905,9 +6962,8 @@ struct ExampleAppConsole
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(4, 1)); // Tighten spacing
if (copy_to_clipboard) if (copy_to_clipboard)
ImGui::LogToClipboard(); ImGui::LogToClipboard();
for (int i = 0; i < Items.Size; i++) for (const char* item : Items)
{ {
const char* item = Items[i];
if (!Filter.PassFilter(item)) if (!Filter.PassFilter(item))
continue; continue;
@ -7396,6 +7452,7 @@ static void ShowPlaceholderObject(const char* prefix, int uid)
} }
// Demonstrate create a simple property editor. // Demonstrate create a simple property editor.
// This demo is a bit lackluster nowadays, would be nice to improve.
static void ShowExampleAppPropertyEditor(bool* p_open) static void ShowExampleAppPropertyEditor(bool* p_open)
{ {
ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(430, 450), ImGuiCond_FirstUseEver);
@ -7404,23 +7461,24 @@ static void ShowExampleAppPropertyEditor(bool* p_open)
ImGui::End(); ImGui::End();
return; return;
} }
IMGUI_DEMO_MARKER("Examples/Property Editor");
IMGUI_DEMO_MARKER("Examples/Property Editor");
HelpMarker( HelpMarker(
"This example shows how you may implement a property editor using two columns.\n" "This example shows how you may implement a property editor using two columns.\n"
"All objects/fields data are dummies here.\n" "All objects/fields data are dummies here.\n");
"Remember that in many simple cases, you can use ImGui::SameLine(xxx) to position\n"
"your cursor horizontally instead of using the Columns() API.");
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2)); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 2));
if (ImGui::BeginTable("split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable)) if (ImGui::BeginTable("##split", 2, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY))
{ {
ImGui::TableSetupScrollFreeze(0, 1);
ImGui::TableSetupColumn("Object");
ImGui::TableSetupColumn("Contents");
ImGui::TableHeadersRow();
// Iterate placeholder objects (all the same data) // Iterate placeholder objects (all the same data)
for (int obj_i = 0; obj_i < 4; obj_i++) for (int obj_i = 0; obj_i < 4; obj_i++)
{
ShowPlaceholderObject("Object", obj_i); ShowPlaceholderObject("Object", obj_i);
//ImGui::Separator();
}
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::PopStyleVar(); ImGui::PopStyleVar();
@ -7967,6 +8025,43 @@ static void ShowExampleAppCustomRendering(bool* p_open)
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
// Demonstrate out-of-order rendering via channels splitting
// We use functions in ImDrawList as each draw list contains a convenience splitter,
// but you can also instantiate your own ImDrawListSplitter if you need to nest them.
if (ImGui::BeginTabItem("Draw Channels"))
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
{
ImGui::Text("Blue shape is drawn first: appears in back");
ImGui::Text("Red shape is drawn after: appears in front");
ImVec2 p0 = ImGui::GetCursorScreenPos();
draw_list->AddRectFilled(ImVec2(p0.x, p0.y), ImVec2(p0.x + 50, p0.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
draw_list->AddRectFilled(ImVec2(p0.x + 25, p0.y + 25), ImVec2(p0.x + 75, p0.y + 75), IM_COL32(255, 0, 0, 255)); // Red
ImGui::Dummy(ImVec2(75, 75));
}
ImGui::Separator();
{
ImGui::Text("Blue shape is drawn first, into channel 1: appears in front");
ImGui::Text("Red shape is drawn after, into channel 0: appears in back");
ImVec2 p1 = ImGui::GetCursorScreenPos();
// Create 2 channels and draw a Blue shape THEN a Red shape.
// You can create any number of channels. Tables API use 1 channel per column in order to better batch draw calls.
draw_list->ChannelsSplit(2);
draw_list->ChannelsSetCurrent(1);
draw_list->AddRectFilled(ImVec2(p1.x, p1.y), ImVec2(p1.x + 50, p1.y + 50), IM_COL32(0, 0, 255, 255)); // Blue
draw_list->ChannelsSetCurrent(0);
draw_list->AddRectFilled(ImVec2(p1.x + 25, p1.y + 25), ImVec2(p1.x + 75, p1.y + 75), IM_COL32(255, 0, 0, 255)); // Red
// Flatten/reorder channels. Red shape is in channel 0 and it appears below the Blue shape in channel 1.
// This works by copying draw indices only (vertices are not copied).
draw_list->ChannelsMerge();
ImGui::Dummy(ImVec2(75, 75));
ImGui::Text("After reordering, contents of channel 0 appears below channel 1.");
}
ImGui::EndTabItem();
}
ImGui::EndTabBar(); ImGui::EndTabBar();
} }
@ -8185,12 +8280,11 @@ struct ExampleAppDocuments
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag. // Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app) static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
{ {
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
{ {
MyDocument* doc = &app.Documents[doc_n]; if (!doc.Open && doc.OpenPrev)
if (!doc->Open && doc->OpenPrev) ImGui::SetTabItemClosed(doc.Name);
ImGui::SetTabItemClosed(doc->Name); doc.OpenPrev = doc.Open;
doc->OpenPrev = doc->Open;
} }
} }
@ -8229,23 +8323,19 @@ void ShowExampleAppDocuments(bool* p_open)
if (ImGui::BeginMenu("File")) if (ImGui::BeginMenu("File"))
{ {
int open_count = 0; int open_count = 0;
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
open_count += app.Documents[doc_n].Open ? 1 : 0; open_count += doc.Open ? 1 : 0;
if (ImGui::BeginMenu("Open", open_count < app.Documents.Size)) if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
{ {
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
{ if (!doc.Open && ImGui::MenuItem(doc.Name))
MyDocument* doc = &app.Documents[doc_n]; doc.DoOpen();
if (!doc->Open)
if (ImGui::MenuItem(doc->Name))
doc->DoOpen();
}
ImGui::EndMenu(); ImGui::EndMenu();
} }
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0)) if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
app.Documents[doc_n].DoQueueClose(); doc.DoQueueClose();
if (ImGui::MenuItem("Exit", "Ctrl+F4") && p_open) if (ImGui::MenuItem("Exit", "Ctrl+F4") && p_open)
*p_open = false; *p_open = false;
ImGui::EndMenu(); ImGui::EndMenu();
@ -8256,13 +8346,13 @@ void ShowExampleAppDocuments(bool* p_open)
// [Debug] List documents with one checkbox for each // [Debug] List documents with one checkbox for each
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
{ {
MyDocument* doc = &app.Documents[doc_n]; MyDocument& doc = app.Documents[doc_n];
if (doc_n > 0) if (doc_n > 0)
ImGui::SameLine(); ImGui::SameLine();
ImGui::PushID(doc); ImGui::PushID(&doc);
if (ImGui::Checkbox(doc->Name, &doc->Open)) if (ImGui::Checkbox(doc.Name, &doc.Open))
if (!doc->Open) if (!doc.Open)
doc->DoForceClose(); doc.DoForceClose();
ImGui::PopID(); ImGui::PopID();
} }
ImGui::PushItemWidth(ImGui::GetFontSize() * 12); ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
@ -8298,26 +8388,25 @@ void ShowExampleAppDocuments(bool* p_open)
//if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway.. //if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
// Submit Tabs // Submit Tabs
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
{ {
MyDocument* doc = &app.Documents[doc_n]; if (!doc.Open)
if (!doc->Open)
continue; continue;
ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0); ImGuiTabItemFlags tab_flags = (doc.Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags); bool visible = ImGui::BeginTabItem(doc.Name, &doc.Open, tab_flags);
// Cancel attempt to close when unsaved add to save queue so we can display a popup. // Cancel attempt to close when unsaved add to save queue so we can display a popup.
if (!doc->Open && doc->Dirty) if (!doc.Open && doc.Dirty)
{ {
doc->Open = true; doc.Open = true;
doc->DoQueueClose(); doc.DoQueueClose();
} }
MyDocument::DisplayContextMenu(doc); MyDocument::DisplayContextMenu(&doc);
if (visible) if (visible)
{ {
MyDocument::DisplayContents(doc); MyDocument::DisplayContents(&doc);
ImGui::EndTabItem(); ImGui::EndTabItem();
} }
} }
@ -8378,15 +8467,12 @@ void ShowExampleAppDocuments(bool* p_open)
if (close_queue.empty()) if (close_queue.empty())
{ {
// Close queue is locked once we started a popup // Close queue is locked once we started a popup
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++) for (MyDocument& doc : app.Documents)
{ if (doc.WantClose)
MyDocument* doc = &app.Documents[doc_n];
if (doc->WantClose)
{ {
doc->WantClose = false; doc.WantClose = false;
close_queue.push_back(doc); close_queue.push_back(&doc);
} }
}
} }
// Display closing confirmation UI // Display closing confirmation UI

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (drawing and font code) // (drawing and font code)
/* /*
@ -567,7 +567,7 @@ int ImDrawList::_CalcCircleAutoSegmentCount(float radius) const
{ {
// Automatic segment count // Automatic segment count
const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy const int radius_idx = (int)(radius + 0.999999f); // ceil to never reduce accuracy
if (radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts)) if (radius_idx >= 0 && radius_idx < IM_ARRAYSIZE(_Data->CircleSegmentCounts))
return _Data->CircleSegmentCounts[radius_idx]; // Use cached value return _Data->CircleSegmentCounts[radius_idx]; // Use cached value
else else
return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError); return IM_DRAWLIST_CIRCLE_AUTO_SEGMENT_CALC(radius, _Data->CircleSegmentMaxError);
@ -1355,10 +1355,12 @@ static inline ImDrawFlags FixRectCornerFlags(ImDrawFlags flags)
void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags) void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawFlags flags)
{ {
flags = FixRectCornerFlags(flags); if (rounding >= 0.5f)
rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f ) - 1.0f); {
rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f ) - 1.0f); flags = FixRectCornerFlags(flags);
rounding = ImMin(rounding, ImFabs(b.x - a.x) * (((flags & ImDrawFlags_RoundCornersTop) == ImDrawFlags_RoundCornersTop) || ((flags & ImDrawFlags_RoundCornersBottom) == ImDrawFlags_RoundCornersBottom) ? 0.5f : 1.0f) - 1.0f);
rounding = ImMin(rounding, ImFabs(b.y - a.y) * (((flags & ImDrawFlags_RoundCornersLeft) == ImDrawFlags_RoundCornersLeft) || ((flags & ImDrawFlags_RoundCornersRight) == ImDrawFlags_RoundCornersRight) ? 0.5f : 1.0f) - 1.0f);
}
if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone) if (rounding < 0.5f || (flags & ImDrawFlags_RoundCornersMask_) == ImDrawFlags_RoundCornersNone)
{ {
PathLineTo(a); PathLineTo(a);
@ -1992,15 +1994,9 @@ void ImDrawData::DeIndexAllBuffers()
// or if there is a difference between your window resolution and framebuffer resolution. // or if there is a difference between your window resolution and framebuffer resolution.
void ImDrawData::ScaleClipRects(const ImVec2& fb_scale) void ImDrawData::ScaleClipRects(const ImVec2& fb_scale)
{ {
for (int i = 0; i < CmdListsCount; i++) for (ImDrawList* draw_list : CmdLists)
{ for (ImDrawCmd& cmd : draw_list->CmdBuffer)
ImDrawList* cmd_list = CmdLists[i]; cmd.ClipRect = ImVec4(cmd.ClipRect.x * fb_scale.x, cmd.ClipRect.y * fb_scale.y, cmd.ClipRect.z * fb_scale.x, cmd.ClipRect.w * fb_scale.y);
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
ImDrawCmd* cmd = &cmd_list->CmdBuffer[cmd_i];
cmd->ClipRect = ImVec4(cmd->ClipRect.x * fb_scale.x, cmd->ClipRect.y * fb_scale.y, cmd->ClipRect.z * fb_scale.x, cmd->ClipRect.w * fb_scale.y);
}
}
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -2141,19 +2137,19 @@ ImFontAtlas::~ImFontAtlas()
void ImFontAtlas::ClearInputData() void ImFontAtlas::ClearInputData()
{ {
IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!"); IM_ASSERT(!Locked && "Cannot modify a locked ImFontAtlas between NewFrame() and EndFrame/Render()!");
for (int i = 0; i < ConfigData.Size; i++) for (ImFontConfig& font_cfg : ConfigData)
if (ConfigData[i].FontData && ConfigData[i].FontDataOwnedByAtlas) if (font_cfg.FontData && font_cfg.FontDataOwnedByAtlas)
{ {
IM_FREE(ConfigData[i].FontData); IM_FREE(font_cfg.FontData);
ConfigData[i].FontData = NULL; font_cfg.FontData = NULL;
} }
// When clearing this we lose access to the font name and other information used to build the font. // When clearing this we lose access to the font name and other information used to build the font.
for (int i = 0; i < Fonts.Size; i++) for (ImFont* font : Fonts)
if (Fonts[i]->ConfigData >= ConfigData.Data && Fonts[i]->ConfigData < ConfigData.Data + ConfigData.Size) if (font->ConfigData >= ConfigData.Data && font->ConfigData < ConfigData.Data + ConfigData.Size)
{ {
Fonts[i]->ConfigData = NULL; font->ConfigData = NULL;
Fonts[i]->ConfigDataCount = 0; font->ConfigDataCount = 0;
} }
ConfigData.clear(); ConfigData.clear();
CustomRects.clear(); CustomRects.clear();
@ -2967,9 +2963,9 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
} }
// Build all fonts lookup tables // Build all fonts lookup tables
for (int i = 0; i < atlas->Fonts.Size; i++) for (ImFont* font : atlas->Fonts)
if (atlas->Fonts[i]->DirtyLookupTables) if (font->DirtyLookupTables)
atlas->Fonts[i]->BuildLookupTable(); font->BuildLookupTable();
atlas->TexReady = true; atlas->TexReady = true;
} }

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (internal structures/api) // (internal structures/api)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility. // You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
@ -139,6 +139,7 @@ struct ImGuiLastItemData; // Status storage for last submitted items
struct ImGuiLocEntry; // A localization entry. struct ImGuiLocEntry; // A localization entry.
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result struct ImGuiNavItemData; // Result of a gamepad/keyboard directional navigation move query result
struct ImGuiNavTreeNodeData; // Temporary storage for last TreeNode() being a Left arrow landing candidate.
struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions struct ImGuiMetricsConfig; // Storage for ShowMetricsWindow() and DebugNodeXXX() functions
struct ImGuiNextWindowData; // Storage for SetNextWindow** functions struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
struct ImGuiNextItemData; // Storage for SetNextItem** functions struct ImGuiNextItemData; // Storage for SetNextItem** functions
@ -810,7 +811,7 @@ enum ImGuiItemFlags_
ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets) ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed. ImGuiItemFlags_ReadOnly = 1 << 7, // false // [ALPHA] Allow hovering interactions but underlying value is not changed.
ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable() ImGuiItemFlags_NoWindowHoverableCheck = 1 << 8, // false // Disable hoverable check in ItemHoverable()
ImGuiItemflags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame. ImGuiItemFlags_AllowOverlap = 1 << 9, // false // Allow being overlapped by another widget. Not-hovered to Hovered transition deferred by a frame.
// Controlled by widget code // Controlled by widget code
ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature. ImGuiItemFlags_Inputable = 1 << 10, // false // [WIP] Auto-activate input mode when tab focused. Currently only used and supported by a few items before it becomes a generic feature.
@ -896,7 +897,7 @@ enum ImGuiComboFlagsPrivate_
enum ImGuiSliderFlagsPrivate_ enum ImGuiSliderFlagsPrivate_
{ {
ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically? ImGuiSliderFlags_Vertical = 1 << 20, // Should this slider be orientated vertically?
ImGuiSliderFlags_ReadOnly = 1 << 21, ImGuiSliderFlags_ReadOnly = 1 << 21, // Consider using g.NextItemData.ItemFlags |= ImGuiItemFlags_ReadOnly instead.
}; };
// Extend ImGuiSelectableFlags_ // Extend ImGuiSelectableFlags_
@ -1203,7 +1204,7 @@ enum ImGuiNextItemDataFlags_
struct ImGuiNextItemData struct ImGuiNextItemData
{ {
ImGuiNextItemDataFlags Flags; ImGuiNextItemDataFlags Flags;
ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemflags_AllowOverlap. ImGuiItemFlags ItemFlags; // Currently only tested/used for ImGuiItemFlags_AllowOverlap.
float Width; // Set by SetNextItemWidth() float Width; // Set by SetNextItemWidth()
ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging) ImGuiID FocusScopeId; // Set by SetNextItemMultiSelectData() (!= 0 signify value has been set, so it's an alternate version of HasSelectionData, we don't use Flags for this because they are cleared too early. This is mostly used for debugging)
ImGuiCond OpenCond; ImGuiCond OpenCond;
@ -1226,6 +1227,16 @@ struct ImGuiLastItemData
ImGuiLastItemData() { memset(this, 0, sizeof(*this)); } ImGuiLastItemData() { memset(this, 0, sizeof(*this)); }
}; };
// Store data emitted by TreeNode() for usage by TreePop() to implement ImGuiTreeNodeFlags_NavLeftJumpsBackHere.
// This is the minimum amount of data that we need to perform the equivalent of NavApplyItemToResult() and which we can't infer in TreePop()
// Only stored when the node is a potential candidate for landing on a Left arrow jump.
struct ImGuiNavTreeNodeData
{
ImGuiID ID;
ImGuiItemFlags InFlags;
ImRect NavRect;
};
struct IMGUI_API ImGuiStackSizes struct IMGUI_API ImGuiStackSizes
{ {
short SizeOfIDStack; short SizeOfIDStack;
@ -1775,8 +1786,8 @@ struct ImGuiViewportP : public ImGuiViewport
float LastAlpha; float LastAlpha;
bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused. bool LastFocusedHadNavWindow;// Instead of maintaining a LastFocusedWindow (which may harder to correctly maintain), we merely store weither NavWindow != NULL last time the viewport was focused.
short PlatformMonitor; short PlatformMonitor;
int DrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used int BgFgDrawListsLastFrame[2]; // Last frame number the background (0) and foreground (1) draw lists were used
ImDrawList* DrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays. ImDrawList* BgFgDrawLists[2]; // Convenience background (0) and foreground (1) draw lists. We use them to draw software mouser cursor when io.MouseDrawCursor is set and to draw most debug overlays.
ImDrawData DrawDataP; ImDrawData DrawDataP;
ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData ImDrawDataBuilder DrawDataBuilder; // Temporary data while building final ImDrawData
ImVec2 LastPlatformPos; ImVec2 LastPlatformPos;
@ -1787,8 +1798,8 @@ struct ImGuiViewportP : public ImGuiViewport
ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f. ImVec2 BuildWorkOffsetMin; // Work Area: Offset being built during current frame. Generally >= 0.0f.
ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f. ImVec2 BuildWorkOffsetMax; // Work Area: Offset being built during current frame. Generally <= 0.0f.
ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = DrawListsLastFrame[0] = DrawListsLastFrame[1] = LastFocusedStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; DrawLists[0] = DrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); } ImGuiViewportP() { Window = NULL; Idx = -1; LastFrameActive = BgFgDrawListsLastFrame[0] = BgFgDrawListsLastFrame[1] = LastFocusedStampCount = -1; LastNameHash = 0; Alpha = LastAlpha = 1.0f; LastFocusedHadNavWindow = false; PlatformMonitor = -1; BgFgDrawLists[0] = BgFgDrawLists[1] = NULL; LastPlatformPos = LastPlatformSize = LastRendererSize = ImVec2(FLT_MAX, FLT_MAX); }
~ImGuiViewportP() { if (DrawLists[0]) IM_DELETE(DrawLists[0]); if (DrawLists[1]) IM_DELETE(DrawLists[1]); } ~ImGuiViewportP() { if (BgFgDrawLists[0]) IM_DELETE(BgFgDrawLists[0]); if (BgFgDrawLists[1]) IM_DELETE(BgFgDrawLists[1]); }
void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; } void ClearRequestFlags() { PlatformRequestClose = PlatformRequestMove = PlatformRequestResize = false; }
// Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect) // Calculate work rect pos/size given a set of offset (we have 1 pair of offset for rect locked from last frame data, and 1 pair for currently building rect)
@ -1858,6 +1869,7 @@ enum ImGuiLocKey : int
ImGuiLocKey_WindowingPopup, ImGuiLocKey_WindowingPopup,
ImGuiLocKey_WindowingUntitled, ImGuiLocKey_WindowingUntitled,
ImGuiLocKey_DockingHideTabBar, ImGuiLocKey_DockingHideTabBar,
ImGuiLocKey_DockingHoldShiftToDock,
ImGuiLocKey_COUNT ImGuiLocKey_COUNT
}; };
@ -2057,6 +2069,8 @@ struct ImGuiContext
ImVector<ImGuiGroupData>GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin() ImVector<ImGuiGroupData>GroupStack; // Stack for BeginGroup()/EndGroup() - not inherited by Begin()
ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent) ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent)
ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame) ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
ImVector<ImGuiNavTreeNodeData> NavTreeNodeStack; // Stack for TreeNode() when a NavLeft requested is emitted.
int BeginMenuCount; int BeginMenuCount;
// Viewports // Viewports
@ -2207,6 +2221,7 @@ struct ImGuiContext
float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage? float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled() float DisabledAlphaBackup; // Backup for style.Alpha for BeginDisabled()
short DisabledStackSize; short DisabledStackSize;
short LockMarkEdited;
short TooltipOverrideCount; short TooltipOverrideCount;
ImVector<char> ClipboardHandlerData; // If no custom clipboard handler is defined ImVector<char> ClipboardHandlerData; // If no custom clipboard handler is defined
ImVector<ImGuiID> MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once ImVector<ImGuiID> MenusIdSubmittedThisFrame; // A list of menu IDs that were rendered at least once
@ -2215,7 +2230,6 @@ struct ImGuiContext
ImGuiPlatformImeData PlatformImeData; // Data updated by current frame ImGuiPlatformImeData PlatformImeData; // Data updated by current frame
ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn ImGuiPlatformImeData PlatformImeDataPrev; // Previous frame data (when changing we will call io.SetPlatformImeDataFn
ImGuiID PlatformImeViewport; ImGuiID PlatformImeViewport;
char PlatformLocaleDecimalPoint; // '.' or *localeconv()->decimal_point
// Extensions // Extensions
// FIXME: We could provide an API to register one slot in an array held in ImGuiContext? // FIXME: We could provide an API to register one slot in an array held in ImGuiContext?
@ -2418,12 +2432,12 @@ struct ImGuiContext
ScrollbarClickDeltaToGrabCenter = 0.0f; ScrollbarClickDeltaToGrabCenter = 0.0f;
DisabledAlphaBackup = 0.0f; DisabledAlphaBackup = 0.0f;
DisabledStackSize = 0; DisabledStackSize = 0;
LockMarkEdited = 0;
TooltipOverrideCount = 0; TooltipOverrideCount = 0;
PlatformImeData.InputPos = ImVec2(0.0f, 0.0f); PlatformImeData.InputPos = ImVec2(0.0f, 0.0f);
PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission PlatformImeDataPrev.InputPos = ImVec2(-1.0f, -1.0f); // Different to ensure initial submission
PlatformImeViewport = 0; PlatformImeViewport = 0;
PlatformLocaleDecimalPoint = '.';
DockNodeWindowMenuHandler = NULL; DockNodeWindowMenuHandler = NULL;
@ -2862,6 +2876,7 @@ struct IMGUI_API ImGuiTable
float RowPosY1; float RowPosY1;
float RowPosY2; float RowPosY2;
float RowMinHeight; // Height submitted to TableNextRow() float RowMinHeight; // Height submitted to TableNextRow()
float RowCellPaddingY; // Top and bottom padding. Reloaded during row change.
float RowTextBaseline; float RowTextBaseline;
float RowIndentOffsetX; float RowIndentOffsetX;
ImGuiTableRowFlags RowFlags : 16; // Current row flags, see ImGuiTableRowFlags_ ImGuiTableRowFlags RowFlags : 16; // Current row flags, see ImGuiTableRowFlags_
@ -2875,9 +2890,8 @@ struct IMGUI_API ImGuiTable
float HostIndentX; float HostIndentX;
float MinColumnWidth; float MinColumnWidth;
float OuterPaddingX; float OuterPaddingX;
float CellPaddingX; // Padding from each borders float CellPaddingX; // Padding from each borders. Locked in BeginTable()/Layout.
float CellPaddingY; float CellSpacingX1; // Spacing between non-bordered cells. Locked in BeginTable()/Layout.
float CellSpacingX1; // Spacing between non-bordered cells
float CellSpacingX2; float CellSpacingX2;
float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details. float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
float ColumnsGivenWidth; // Sum of current column width float ColumnsGivenWidth; // Sum of current column width
@ -3193,6 +3207,7 @@ namespace ImGui
IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestSubmit(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags); IMGUI_API void NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, ImGuiNavMoveFlags move_flags, ImGuiScrollFlags scroll_flags);
IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result); IMGUI_API void NavMoveRequestResolveWithLastItem(ImGuiNavItemData* result);
IMGUI_API void NavMoveRequestResolveWithPastTreeNode(ImGuiNavItemData* result, ImGuiNavTreeNodeData* tree_node_data);
IMGUI_API void NavMoveRequestCancel(); IMGUI_API void NavMoveRequestCancel();
IMGUI_API void NavMoveRequestApplyResult(); IMGUI_API void NavMoveRequestApplyResult();
IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags); IMGUI_API void NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags move_flags);
@ -3559,10 +3574,12 @@ namespace ImGui
IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); IMGUI_API void ErrorCheckEndFrameRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL); IMGUI_API void ErrorCheckEndWindowRecover(ImGuiErrorLogCallback log_callback, void* user_data = NULL);
IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries(); IMGUI_API void ErrorCheckUsingSetCursorPosToExtendParentBoundaries();
IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255));
IMGUI_API void DebugDrawLineExtents(ImU32 col = IM_COL32(255, 0, 0, 255));
IMGUI_API void DebugDrawItemRect(ImU32 col = IM_COL32(255, 0, 0, 255));
IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time! IMGUI_API void DebugLocateItem(ImGuiID target_id); // Call sparingly: only 1 at the same time!
IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time! IMGUI_API void DebugLocateItemOnHover(ImGuiID target_id); // Only call on reaction to a mouse Hover: because only 1 at the same time!
IMGUI_API void DebugLocateItemResolveWithLastItem(); IMGUI_API void DebugLocateItemResolveWithLastItem();
inline void DebugDrawItemRect(ImU32 col = IM_COL32(255,0,0,255)) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; GetForegroundDrawList(window)->AddRect(g.LastItemData.Rect.Min, g.LastItemData.Rect.Max, col); }
inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; } inline void DebugStartItemPicker() { ImGuiContext& g = *GImGui; g.DebugItemPickerActive = true; }
IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas); IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);
IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end); IMGUI_API void DebugHookIdInfo(ImGuiID id, ImGuiDataType data_type, const void* data_id, const void* data_id_end);

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (tables and columns code) // (tables and columns code)
/* /*
@ -82,7 +82,7 @@ Index of this file:
// Y with ScrollX/ScrollY disabled: we output table directly in current window // Y with ScrollX/ScrollY disabled: we output table directly in current window
// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll. // - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless _NoHostExtendY is set). Not meaningful if parent window can vertically scroll.
// - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set) // - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless _NoHostExtendY is set)
// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtenY is set) // - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless _NoHostExtendY is set)
// Y with ScrollX/ScrollY enabled: using a child window for scrolling // Y with ScrollX/ScrollY enabled: using a child window for scrolling
// - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll. // - outer_size.y < 0.0f -> Bottom-align. Not meaningful if parent window can vertically scroll.
// - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window. // - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window.
@ -455,7 +455,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border; table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border;
table->CellSpacingX2 = inner_spacing_explicit; table->CellSpacingX2 = inner_spacing_explicit;
table->CellPaddingX = inner_padding_explicit; table->CellPaddingX = inner_padding_explicit;
table->CellPaddingY = g.Style.CellPadding.y;
const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; const float outer_padding_for_border = (flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f; const float outer_padding_explicit = pad_outer_x ? g.Style.CellPadding.x : 0.0f;
@ -472,6 +471,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow
table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow() table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()
table->RowCellPaddingY = 0.0f;
table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any
table->FreezeColumnsRequest = table->FreezeColumnsCount = 0; table->FreezeColumnsRequest = table->FreezeColumnsCount = 0;
table->IsUnfrozenRows = true; table->IsUnfrozenRows = true;
@ -1748,19 +1748,20 @@ void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height)
table->LastRowFlags = table->RowFlags; table->LastRowFlags = table->RowFlags;
table->RowFlags = row_flags; table->RowFlags = row_flags;
table->RowCellPaddingY = g.Style.CellPadding.y;
table->RowMinHeight = row_min_height; table->RowMinHeight = row_min_height;
TableBeginRow(table); TableBeginRow(table);
// We honor min_row_height requested by user, but cannot guarantee per-row maximum height, // We honor min_row_height requested by user, but cannot guarantee per-row maximum height,
// because that would essentially require a unique clipping rectangle per-cell. // because that would essentially require a unique clipping rectangle per-cell.
table->RowPosY2 += table->CellPaddingY * 2.0f; table->RowPosY2 += table->RowCellPaddingY * 2.0f;
table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height); table->RowPosY2 = ImMax(table->RowPosY2, table->RowPosY1 + row_min_height);
// Disable output until user calls TableNextColumn() // Disable output until user calls TableNextColumn()
table->InnerWindow->SkipItems = true; table->InnerWindow->SkipItems = true;
} }
// [Internal] Called by TableNextRow() // [Internal] Only called by TableNextRow()
void ImGui::TableBeginRow(ImGuiTable* table) void ImGui::TableBeginRow(ImGuiTable* table)
{ {
ImGuiWindow* window = table->InnerWindow; ImGuiWindow* window = table->InnerWindow;
@ -1781,8 +1782,10 @@ void ImGui::TableBeginRow(ImGuiTable* table)
table->RowPosY1 = table->RowPosY2 = next_y1; table->RowPosY1 = table->RowPosY2 = next_y1;
table->RowTextBaseline = 0.0f; table->RowTextBaseline = 0.0f;
table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent table->RowIndentOffsetX = window->DC.Indent.x - table->HostIndentX; // Lock indent
window->DC.PrevLineTextBaseOffset = 0.0f; window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x, window->DC.CursorPos.y + table->RowCellPaddingY); // This allows users to call SameLine() to share LineSize between columns.
window->DC.PrevLineSize = window->DC.CurrLineSize = ImVec2(0.0f, 0.0f); // This allows users to call SameLine() to share LineSize between columns, and to call it from first column too.
window->DC.IsSameLine = window->DC.IsSetPos = false; window->DC.IsSameLine = window->DC.IsSetPos = false;
window->DC.CursorMaxPos.y = next_y1; window->DC.CursorMaxPos.y = next_y1;
@ -2016,9 +2019,10 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
start_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row. start_x += table->RowIndentOffsetX; // ~~ += window.DC.Indent.x - table->HostIndentX, except we locked it for the row.
window->DC.CursorPos.x = start_x; window->DC.CursorPos.x = start_x;
window->DC.CursorPos.y = table->RowPosY1 + table->CellPaddingY; window->DC.CursorPos.y = table->RowPosY1 + table->RowCellPaddingY;
window->DC.CursorMaxPos.x = window->DC.CursorPos.x; window->DC.CursorMaxPos.x = window->DC.CursorPos.x;
window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT
window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x; // PrevLine.y is preserved. This allows users to call SameLine() to share LineSize between columns.
window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; window->DC.CurrLineTextBaseOffset = table->RowTextBaseline;
window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent; window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent;
@ -2073,7 +2077,7 @@ void ImGui::TableEndCell(ImGuiTable* table)
p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen; p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen;
*p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x); *p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x);
if (column->IsEnabled) if (column->IsEnabled)
table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY); table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->RowCellPaddingY);
column->ItemWidth = window->DC.ItemWidth; column->ItemWidth = window->DC.ItemWidth;
// Propagate text baseline for the entire row // Propagate text baseline for the entire row
@ -2675,8 +2679,9 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set) // Return NULL if no sort specs (most often when ImGuiTableFlags_Sortable is not set)
// You can sort your data again when 'SpecsChanged == true'. It will be true with sorting specs have changed since // When 'sort_specs->SpecsDirty == true' you should sort your data. It will be true when sorting specs have
// last call, or the first time. // changed since last call, or the first time. Make sure to set 'SpecsDirty = false' after sorting,
// else you may wastefully sort your data every frame!
// Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()! // Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable()!
ImGuiTableSortSpecs* ImGui::TableGetSortSpecs() ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
{ {
@ -2954,7 +2959,7 @@ void ImGui::TableHeader(const char* label)
// If we already got a row height, there's use that. // If we already got a row height, there's use that.
// FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect? // FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect?
ImRect cell_r = TableGetCellBgRect(table, column_n); ImRect cell_r = TableGetCellBgRect(table, column_n);
float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f); float label_height = ImMax(label_size.y, table->RowMinHeight - table->RowCellPaddingY * 2.0f);
// Calculate ideal size for sort order arrow // Calculate ideal size for sort order arrow
float w_arrow = 0.0f; float w_arrow = 0.0f;

View file

@ -1,4 +1,4 @@
// dear imgui, v1.89.8 // dear imgui, v1.89.9
// (widgets code) // (widgets code)
/* /*
@ -120,7 +120,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// For InputTextEx() // For InputTextEx()
static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source); static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source);
static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end); static int InputTextCalcTextLenAndLineCount(const char* text_begin, const char** out_text_end);
static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, const bool stop_on_new_line = false, const float wrap_width = 0.0f, const bool keep_trailing_blanks = false); static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, const bool stop_on_new_line = false, const float wrap_width = 0.0f, const bool keep_trailing_blanks = false);
static ImVec2 FindCharPosition(const ImWchar* text_begin, const ImWchar* char_position, const ImWchar* text_end, const float wrap_width); static ImVec2 FindCharPosition(const ImWchar* text_begin, const ImWchar* char_position, const ImWchar* text_end, const float wrap_width);
@ -675,7 +675,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
// Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that. // Note that _both_ ButtonFlags and ItemFlags are valid sources, so copy one into the item_flags and only check that.
ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags); ImGuiItemFlags item_flags = (g.LastItemData.ID == id ? g.LastItemData.InFlags : g.CurrentItemFlags);
if (flags & ImGuiButtonFlags_AllowOverlap) if (flags & ImGuiButtonFlags_AllowOverlap)
item_flags |= ImGuiItemflags_AllowOverlap; item_flags |= ImGuiItemFlags_AllowOverlap;
if (flags & ImGuiButtonFlags_Repeat) if (flags & ImGuiButtonFlags_Repeat)
item_flags |= ImGuiItemFlags_ButtonRepeat; item_flags |= ImGuiItemFlags_ButtonRepeat;
@ -990,14 +990,14 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)
// Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825) // Tweak 1: Shrink hit-testing area if button covers an abnormally large proportion of the visible region. That's in order to facilitate moving the window away. (#3825)
// This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible? // This may better be applied as a general hit-rect reduction mechanism for all widgets to ensure the area to move window is always accessible?
const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));
ImRect bb_interact = bb; ImRect bb_interact = bb;
const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea(); const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();
if (area_to_visible_ratio < 1.5f) if (area_to_visible_ratio < 1.5f)
bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f)); bb_interact.Expand(ImFloor(bb_interact.GetSize() * -0.25f));
// Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window. // Tweak 2: We intentionally allow interaction when clipped so that a mechanical Alt,Right,Activate sequence can always close a window.
// (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible). // (this isn't the common behavior of buttons, but it doesn't affect the user because navigation tends to keep items visible in scrolling layer).
bool is_clipped = !ItemAdd(bb_interact, id); bool is_clipped = !ItemAdd(bb_interact, id);
bool hovered, held; bool hovered, held;
@ -1027,22 +1027,24 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow; ImGuiWindow* window = g.CurrentWindow;
ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f); ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));
ItemAdd(bb, id); bool is_clipped = !ItemAdd(bb, id);
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None); bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
if (is_clipped)
return pressed;
// Render // Render
//bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed); //bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button); ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
ImU32 text_col = GetColorU32(ImGuiCol_Text); ImU32 text_col = GetColorU32(ImGuiCol_Text);
if (hovered || held) if (hovered || held)
window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, bg_col); window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, bg_col);
if (dock_node) if (dock_node)
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, text_col); RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col);
else else
RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f); RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
// Switch to moving the window after mouse is moved beyond the initial drag threshold // Switch to moving the window after mouse is moved beyond the initial drag threshold
if (IsItemActive() && IsMouseDragging(0)) if (IsItemActive() && IsMouseDragging(0))
@ -2967,14 +2969,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X; const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0; const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double); const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
const SIGNEDTYPE v_range = (v_min < v_max ? v_max - v_min : v_min - v_max); const float v_range_f = (float)(v_min < v_max ? v_max - v_min : v_min - v_max); // We don't need high precision for what we do with it.
// Calculate bounds // Calculate bounds
const float grab_padding = 2.0f; // FIXME: Should be part of style. const float grab_padding = 2.0f; // FIXME: Should be part of style.
const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f; const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;
float grab_sz = style.GrabMinSize; float grab_sz = style.GrabMinSize;
if (!is_floating_point && v_range >= 0) // v_range < 0 may happen on integer overflows if (!is_floating_point && v_range_f >= 0.0f) // v_range_f < 0 may happen on integer overflows
grab_sz = ImMax((float)(slider_sz / (v_range + 1)), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit grab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize); // For integer sliders: if possible have the grab size represent 1 unit
grab_sz = ImMin(grab_sz, slider_sz); grab_sz = ImMin(grab_sz, slider_sz);
const float slider_usable_sz = slider_sz - grab_sz; const float slider_usable_sz = slider_sz - grab_sz;
const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f; const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;
@ -3043,8 +3045,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
} }
else else
{ {
if ((v_range >= -100.0f && v_range <= 100.0f) || tweak_slow) if ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow)
input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f; // Gamepad/keyboard tweak speeds in integer steps
else else
input_delta /= 100.0f; input_delta /= 100.0f;
} }
@ -3091,6 +3093,10 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
} }
} }
if (set_new_value)
if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))
set_new_value = false;
if (set_new_value) if (set_new_value)
{ {
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize); TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
@ -3136,11 +3142,6 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type
// Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert. // Read imgui.cpp "API BREAKING CHANGES" section for 1.78 if you hit this assert.
IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead."); IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) && "Invalid ImGuiSliderFlags flag! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
// Those are the things we can do easily outside the SliderBehaviorT<> template, saves code generation.
ImGuiContext& g = *GImGui;
if ((g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))
return false;
switch (data_type) switch (data_type)
{ {
case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; } case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v; bool r = SliderBehaviorT<ImS32, ImS32, float>(bb, id, ImGuiDataType_S32, &v32, *(const ImS8*)p_min, *(const ImS8*)p_max, format, flags, out_grab_bb); if (r) *(ImS8*)p_v = (ImS8)v32; return r; }
@ -4352,7 +4353,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
} }
// Return false to discard a character. // Return false to discard a character.
static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source) static bool InputTextFilterCharacter(ImGuiContext* ctx, unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data, ImGuiInputSource input_source)
{ {
IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard); IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard);
unsigned int c = *p_char; unsigned int c = *p_char;
@ -4391,10 +4392,13 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
// The standard mandate that programs starts in the "C" locale where the decimal point is '.'. // The standard mandate that programs starts in the "C" locale where the decimal point is '.'.
// We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point. // We don't really intend to provide widespread support for it, but out of empathy for people stuck with using odd API, we support the bare minimum aka overriding the decimal point.
// Change the default decimal_point with: // Change the default decimal_point with:
// ImGui::GetCurrentContext()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point; // ImGui::GetIO()->PlatformLocaleDecimalPoint = *localeconv()->decimal_point;
// Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions. // Users of non-default decimal point (in particular ',') may be affected by word-selection logic (is_word_boundary_from_right/is_word_boundary_from_left) functions.
ImGuiContext& g = *GImGui; ImGuiContext& g = *ctx;
const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint; const unsigned c_decimal_point = (unsigned int)g.IO.PlatformLocaleDecimalPoint;
if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific))
if (c == '.' || c == ',')
c = c_decimal_point;
// Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block) // Full-width -> half-width conversion for numeric fields (https://en.wikipedia.org/wiki/Halfwidth_and_Fullwidth_Forms_(Unicode_block)
// While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may // While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may
@ -4847,7 +4851,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly) if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly)
{ {
unsigned int c = '\t'; // Insert TAB unsigned int c = '\t'; // Insert TAB
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
state->OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
@ -4863,7 +4867,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
unsigned int c = (unsigned int)io.InputQueueCharacters[n]; unsigned int c = (unsigned int)io.InputQueueCharacters[n];
if (c == '\t') // Skip Tab, see above. if (c == '\t') // Skip Tab, see above.
continue; continue;
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
state->OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
@ -4946,7 +4950,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
else if (!is_readonly) else if (!is_readonly)
{ {
unsigned int c = '\n'; // Insert new line unsigned int c = '\n'; // Insert new line
if (InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard)) if (InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
state->OnKeyPressed((int)c); state->OnKeyPressed((int)c);
} }
} }
@ -5013,7 +5017,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{ {
unsigned int c; unsigned int c;
s += ImTextCharFromUtf8(&c, s, NULL); s += ImTextCharFromUtf8(&c, s, NULL);
if (!InputTextFilterCharacter(&c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard)) if (!InputTextFilterCharacter(&g, &c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard))
continue; continue;
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c; clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
} }
@ -6342,6 +6346,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)
if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context")) if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.LockMarkEdited++;
ImGuiColorEditFlags opts = g.ColorEditOptions; ImGuiColorEditFlags opts = g.ColorEditOptions;
if (allow_opt_inputs) if (allow_opt_inputs)
{ {
@ -6384,6 +6389,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)
g.ColorEditOptions = opts; g.ColorEditOptions = opts;
EndPopup(); EndPopup();
g.LockMarkEdited--;
} }
void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags) void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags)
@ -6393,6 +6399,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context")) if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context"))
return; return;
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.LockMarkEdited++;
if (allow_opt_picker) if (allow_opt_picker)
{ {
ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function ImVec2 picker_size(g.FontSize * 8, ImMax(g.FontSize * 8 - (GetFrameHeight() + g.Style.ItemInnerSpacing.x), 1.0f)); // FIXME: Picker size copied from main picker function
@ -6422,6 +6429,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar); CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
} }
EndPopup(); EndPopup();
g.LockMarkEdited--;
} }
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
@ -6618,18 +6626,29 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0) if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)
interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f; interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
// Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child. // Compute open and multi-select states before ItemAdd() as it clear NextItem data.
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
bool is_open = TreeNodeUpdateNextOpen(id, flags); bool is_open = TreeNodeUpdateNextOpen(id, flags);
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
bool item_add = ItemAdd(interact_bb, id); bool item_add = ItemAdd(interact_bb, id);
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect; g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
g.LastItemData.DisplayRect = frame_bb; g.LastItemData.DisplayRect = frame_bb;
// If a NavLeft request is happening and ImGuiTreeNodeFlags_NavLeftJumpsBackHere enabled:
// Store data for the current depth to allow returning to this node from any child item.
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// It will become tempting to enable ImGuiTreeNodeFlags_NavLeftJumpsBackHere by default or move it to ImGuiStyle.
// Currently only supports 32 level deep and we are fine with (1 << Depth) overflowing into a zero, easy to increase.
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
{
g.NavTreeNodeStack.resize(g.NavTreeNodeStack.Size + 1);
ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
nav_tree_node_data->ID = id;
nav_tree_node_data->InFlags = g.LastItemData.InFlags;
nav_tree_node_data->NavRect = g.LastItemData.NavRect;
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
}
const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
if (!item_add) if (!item_add)
{ {
if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen)) if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
@ -6639,7 +6658,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
} }
ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None; ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;
if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap))
button_flags |= ImGuiButtonFlags_AllowOverlap; button_flags |= ImGuiButtonFlags_AllowOverlap;
if (!is_leaf) if (!is_leaf)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
@ -6799,12 +6818,14 @@ void ImGui::TreePop()
ImU32 tree_depth_mask = (1 << window->DC.TreeDepth); ImU32 tree_depth_mask = (1 << window->DC.TreeDepth);
// Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled) // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet()) if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request
if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)) {
{ ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect()); IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());
NavMoveRequestCancel(); if (g.NavIdIsAlive && g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
} NavMoveRequestResolveWithPastTreeNode(&g.NavMoveResultLocal, nav_tree_node_data);
g.NavTreeNodeStack.pop_back();
}
window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1; window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1;
IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much. IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
@ -6866,8 +6887,8 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
ImGuiLastItemData last_item_backup = g.LastItemData; ImGuiLastItemData last_item_backup = g.LastItemData;
float button_size = g.FontSize; float button_size = g.FontSize;
float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x * 2.0f - button_size); float button_x = ImMax(g.LastItemData.Rect.Min.x, g.LastItemData.Rect.Max.x - g.Style.FramePadding.x - button_size);
float button_y = g.LastItemData.Rect.Min.y; float button_y = g.LastItemData.Rect.Min.y + g.Style.FramePadding.y;
ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id); ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id);
if (CloseButton(close_button_id, ImVec2(button_x, button_y))) if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
*p_visible = false; *p_visible = false;
@ -6979,7 +7000,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; } if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }
if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; } if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; } if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }
if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemflags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; } if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
const bool was_selected = selected; const bool was_selected = selected;
bool hovered, held; bool hovered, held;
@ -7018,7 +7039,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : (hovered && !(g.IO.ConfigFlags&ImGuiConfigFlags_NoHoverColors)) ? ImGuiCol_HeaderHovered : ImGuiCol_Header); const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : (hovered && !(g.IO.ConfigFlags&ImGuiConfigFlags_NoHoverColors)) ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(bb.Min, bb.Max, col, false, 0.0f); RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
} }
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding); if (g.NavId == id)
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
if (span_all_columns && window->DC.CurrentColumns) if (span_all_columns && window->DC.CurrentColumns)
PopColumnsBackground(); PopColumnsBackground();
@ -9185,7 +9207,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
} }
const float button_sz = g.FontSize; const float button_sz = g.FontSize;
const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x * 2.0f - button_sz), bb.Min.y); const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y);
// Close Button & Unsaved Marker // Close Button & Unsaved Marker
// We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap() // We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap()
@ -9203,10 +9225,8 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (close_button_visible) if (close_button_visible)
{ {
ImGuiLastItemData last_item_backup = g.LastItemData; ImGuiLastItemData last_item_backup = g.LastItemData;
PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
if (CloseButton(close_button_id, button_pos)) if (CloseButton(close_button_id, button_pos))
close_button_pressed = true; close_button_pressed = true;
PopStyleVar();
g.LastItemData = last_item_backup; g.LastItemData = last_item_backup;
// Close with middle mouse button // Close with middle mouse button