Merge branch 'master' into docking
build / Build - Windows (push) Has been cancelled
build / Build - Linux (push) Has been cancelled
build / Build - MacOS (push) Has been cancelled
build / Build - iOS (push) Has been cancelled
build / Build - Emscripten (push) Has been cancelled
build / Build - Android (push) Has been cancelled
build / Test - Windows (push) Has been cancelled
build / Test - Linux (push) Has been cancelled

# Conflicts:
#	backends/imgui_impl_metal.mm
#	imgui.cpp
This commit is contained in:
ocornut
2026-04-08 21:40:40 +02:00
10 changed files with 124 additions and 63 deletions
+2 -2
View File
@@ -18,6 +18,7 @@
// CHANGELOG // CHANGELOG
// (minor and older changes stripped away, please see git history for details) // (minor and older changes stripped away, please see git history for details)
// 2026-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface. // 2026-XX-XX: Metal: Added support for multiple windows via the ImGuiPlatformIO interface.
// 2026-04-03: Metal: avoid redundant vertex buffer bind in SetupRenderState. (#9343)
// 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310) // 2026-03-19: Fixed issue in ImGui_ImplMetal_RenderDrawData() if ImTextureID_Invalid is defined to be != 0, which became the default since 2026-03-12. (#9295, #9310)
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown. // 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
// 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture(). // 2025-06-11: Added support for ImGuiBackendFlags_RendererHasTextures, for dynamic font atlas. Removed ImGui_ImplMetal_CreateFontsTexture() and ImGui_ImplMetal_DestroyFontsTexture().
@@ -227,8 +228,7 @@ static void ImGui_ImplMetal_SetupRenderState(ImDrawData* draw_data, id<MTLComman
[commandEncoder setRenderPipelineState:renderPipelineState]; [commandEncoder setRenderPipelineState:renderPipelineState];
[commandEncoder setVertexBuffer:vertexBuffer.buffer offset:0 atIndex:0]; [commandEncoder setVertexBuffer:vertexBuffer.buffer offset:vertexBufferOffset atIndex:0];
[commandEncoder setVertexBufferOffset:vertexBufferOffset atIndex:0];
} }
// Metal Render function. // Metal Render function.
+32
View File
@@ -35,6 +35,38 @@ HOW TO UPDATE?
and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users. and API updates have been a little more frequent lately. They are documented below and in imgui.cpp and should not affect all users.
- Please report any issue! - Please report any issue!
-----------------------------------------------------------------------
VERSION 1.92.8 WIP (In Progress)
-----------------------------------------------------------------------
Breaking Changes:
Other Changes:
- InputText:
- InputTextMultiline: fixed an issue processing deactivation logic when an active
multi-line edit is clipped due to being out of view.
- Fixed a crash when toggling ReadOnly while active. (#9354)
- Tables:
- Fixed issues reporting ideal size to parent window/container: (#9352, #7651)
- When both scrollbars are visible but only one of ScrollX/ScrollY was explicitly requested.
- When vertical scrollbar was not at the top, the computation was often incorrect.
- Windows:
- Fixed a single-axis auto-resizing feedback loop issue with nested containers
and varying scrollbar visibility. (#9352)
- Detect and report error when calling End() instead of EndPopup() on a popup. (#9351)
- Fonts:
- imgui_freetype: add FreeType headers & compiled version in 'About Dear ImGui' details.
- Clipper:
- Improved error reporting when misusing the clipper inside a table (prioritize
reporting the common clipper error over a table sanity check assert). (#9350)
- Tweaked assert triggering when first item height measurement fails, and made it
a better recoverable error. (#9350)
- Backends:
- Metal: avoid redundant vertex buffer bind in SetupRenderState, which leads
to validation issue. (#9343) [@Hunam6]
----------------------------------------------------------------------- -----------------------------------------------------------------------
VERSION 1.92.7 (Released 2026-04-02) VERSION 1.92.7 (Released 2026-04-02)
----------------------------------------------------------------------- -----------------------------------------------------------------------
+26 -15
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (main code and documentation) // (main code and documentation)
// Help: // Help:
@@ -3454,9 +3454,6 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
if (clipper->ItemsHeight <= 0.0f) if (clipper->ItemsHeight <= 0.0f)
{ {
IM_ASSERT(data->StepNo == 1); IM_ASSERT(data->StepNo == 1);
if (table)
IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision((float)clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y); bool affected_by_floating_point_precision = ImIsFloatAboveGuaranteedIntegerPrecision((float)clipper->StartPosY) || ImIsFloatAboveGuaranteedIntegerPrecision(window->DC.CursorPos.y);
if (affected_by_floating_point_precision) if (affected_by_floating_point_precision)
{ {
@@ -3470,7 +3467,14 @@ static bool ImGuiListClipper_StepInternal(ImGuiListClipper* clipper)
} }
if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode. if (clipper->ItemsHeight == 0.0f && clipper->ItemsCount == INT_MAX) // Accept that no item have been submitted if in indeterminate mode.
return false; return false;
IM_ASSERT(clipper->ItemsHeight > 0.0f && "Unable to calculate item height! First item hasn't moved the cursor vertically!"); if (clipper->ItemsHeight <= 0.0f)
{
IM_ASSERT_USER_ERROR(clipper->ItemsHeight > 0.0f, "ImGuiListClipper: Failed to calculate item height! First item hasn't been submitted by user code, or has not moved the cursor vertically!");
return false;
}
if (table)
IM_ASSERT(table->RowPosY1 == clipper->StartPosY && table->RowPosY2 == window->DC.CursorPos.y);
calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards. calc_clipping = true; // If item height had to be calculated, calculate clipping afterwards.
} }
@@ -4229,7 +4233,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)(); IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
if (shared_font_atlas == NULL) if (shared_font_atlas == NULL)
IO.Fonts->OwnerContext = this; IO.Fonts->OwnerContext = this;
WithinEndChildID = 0; WithinEndChildID = WithinEndPopupID = 0;
TestEngine = NULL; TestEngine = NULL;
InputEventsNextMouseSource = ImGuiMouseSource_Mouse; InputEventsNextMouseSource = ImGuiMouseSource_Mouse;
@@ -7050,8 +7054,8 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y; const float decoration_h_without_scrollbars = window->DecoOuterSizeY1 + window->DecoOuterSizeY2 - window->ScrollbarSizes.y;
ImVec2 size_pad = window->WindowPadding * 2.0f; ImVec2 size_pad = window->WindowPadding * 2.0f;
ImVec2 size_desired; ImVec2 size_desired;
size_desired[ImGuiAxis_X] = (axis_mask & 1) ? size_contents.x + size_pad.x + decoration_w_without_scrollbars : window->Size.x; size_desired.x = (axis_mask & 1) ? size_contents.x + size_pad.x + decoration_w_without_scrollbars : window->Size.x;
size_desired[ImGuiAxis_Y] = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y; size_desired.y = (axis_mask & 2) ? size_contents.y + size_pad.y + decoration_h_without_scrollbars : window->Size.y;
// Determine maximum window size // Determine maximum window size
// Child windows are laid within their parent (unless they are also popups/menus) and thus have no restriction // Child windows are laid within their parent (unless they are also popups/menus) and thus have no restriction
@@ -7078,8 +7082,10 @@ static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_cont
// When the window cannot fit all contents (either because of constraints, either because screen is too small), // When the window cannot fit all contents (either because of constraints, either because screen is too small),
// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding. // we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit); ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - decoration_w_without_scrollbars < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar); float size_contents_for_scrollbar_x = (axis_mask & 1) ? size_contents.x : window->ContentSize.x; // See #9352. In theory this should use same logic as `window->ScrollbarY = ...` codepath in Begin(). Needs some plumbling.
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - decoration_h_without_scrollbars < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar); float size_contents_for_scrollbar_y = (axis_mask & 2) ? size_contents.y : window->ContentSize.y;
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x < size_contents_for_scrollbar_x + size_pad.x + decoration_w_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y < size_contents_for_scrollbar_y + size_pad.y + decoration_h_without_scrollbars && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
if (will_have_scrollbar_x) if (will_have_scrollbar_x)
size_auto_fit.y += style.ScrollbarSize; size_auto_fit.y += style.ScrollbarSize;
if (will_have_scrollbar_y) if (will_have_scrollbar_y)
@@ -8357,12 +8363,12 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2)); ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - (window->DecoOuterSizeY1 + window->DecoOuterSizeY2));
ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame; ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + scrollbar_sizes_from_last_frame;
ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f; ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x; float size_for_scrollbars_x = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y; float size_for_scrollbars_y = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
bool scrollbar_x_prev = window->ScrollbarX; bool scrollbar_x_prev = window->ScrollbarX;
//bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons? //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar)); window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_for_scrollbars_y) && !(flags & ImGuiWindowFlags_NoScrollbar));
window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar)); window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_for_scrollbars_x - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
// Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488) // Track when ScrollbarX visibility keeps toggling, which is a sign of a feedback loop, and stabilize by enforcing visibility (#3285, #8488)
// (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause. // (Feedback loops of this sort can manifest in various situations, but combining horizontal + vertical scrollbar + using a clipper with varying width items is one frequent cause.
@@ -8377,7 +8383,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ScrollbarXStabilizeEnabled = scrollbar_x_stabilize; window->ScrollbarXStabilizeEnabled = scrollbar_x_stabilize;
if (window->ScrollbarX && !window->ScrollbarY) if (window->ScrollbarX && !window->ScrollbarY)
window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar); window->ScrollbarY = (needed_size_from_last_frame.y > size_for_scrollbars_y - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f); window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
// Amend the partially filled window->DecorationXXX values. // Amend the partially filled window->DecorationXXX values.
@@ -8770,6 +8776,8 @@ void ImGui::End()
ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back(); ImGuiWindowStackData& window_stack_data = g.CurrentWindowStack.back();
// Error checking: verify that user doesn't directly call End() on a child window. // Error checking: verify that user doesn't directly call End() on a child window.
if (window->Flags & ImGuiWindowFlags_Popup)
IM_ASSERT_USER_ERROR(g.WithinEndPopupID == window->ID, "Must call EndPopup() and not End()!");
if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive) if ((window->Flags & ImGuiWindowFlags_ChildWindow) && !(window->Flags & ImGuiWindowFlags_DockNodeHost) && !window->DockIsActive)
IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!"); IM_ASSERT_USER_ERROR(g.WithinEndChildID == window->ID, "Must call EndChild() and not End()!");
@@ -13174,10 +13182,13 @@ void ImGui::EndPopup()
NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY); NavMoveRequestTryWrapping(window, ImGuiNavMoveFlags_LoopY);
// Child-popups don't need to be laid out // Child-popups don't need to be laid out
const ImGuiID backup_within_end_popup_id = g.WithinEndPopupID;
const ImGuiID backup_within_end_child_id = g.WithinEndChildID; const ImGuiID backup_within_end_child_id = g.WithinEndChildID;
g.WithinEndPopupID = window->ID;
if (window->Flags & ImGuiWindowFlags_ChildWindow) if (window->Flags & ImGuiWindowFlags_ChildWindow)
g.WithinEndChildID = window->ID; g.WithinEndChildID = window->ID;
End(); End();
g.WithinEndPopupID = backup_within_end_popup_id;
g.WithinEndChildID = backup_within_end_child_id; g.WithinEndChildID = backup_within_end_child_id;
} }
+3 -3
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (headers) // (headers)
// Help: // Help:
@@ -29,8 +29,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.92.7" #define IMGUI_VERSION "1.92.8 WIP"
#define IMGUI_VERSION_NUM 19270 #define IMGUI_VERSION_NUM 19271
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
+1 -1
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (demo code) // (demo code)
// Help: // Help:
+1 -1
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (drawing and font code) // (drawing and font code)
/* /*
+2 -1
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (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.
@@ -2410,6 +2410,7 @@ struct ImGuiContext
float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale float CurrentDpiScale; // Current window/viewport DpiScale == CurrentViewport->DpiScale
ImDrawListSharedData DrawListSharedData; ImDrawListSharedData DrawListSharedData;
ImGuiID WithinEndChildID; // Set within EndChild() ImGuiID WithinEndChildID; // Set within EndChild()
ImGuiID WithinEndPopupID; // Set within EndPopup()
void* TestEngine; // Test engine user data void* TestEngine; // Test engine user data
// Inputs // Inputs
+16 -14
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (tables and columns code) // (tables and columns code)
/* /*
@@ -1436,12 +1436,12 @@ void ImGui::EndTable()
if (table->Flags & ImGuiTableFlags_ScrollX) if (table->Flags & ImGuiTableFlags_ScrollX)
{ {
const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f; const float outer_padding_for_border = (table->Flags & ImGuiTableFlags_BordersOuterV) ? TABLE_BORDER_SIZE : 0.0f;
float max_pos_x = table->InnerWindow->DC.CursorMaxPos.x; float max_pos_x = inner_window->DC.CursorMaxPos.x;
if (table->RightMostEnabledColumn != -1) if (table->RightMostEnabledColumn != -1)
max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border); max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].WorkMaxX + table->CellPaddingX + table->OuterPaddingX - outer_padding_for_border);
if (table->ResizedColumn != -1) if (table->ResizedColumn != -1)
max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2); max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2);
table->InnerWindow->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth; inner_window->DC.CursorMaxPos.x = max_pos_x + table->TempData->AngledHeadersExtraWidth;
} }
// Pop clipping rect // Pop clipping rect
@@ -1550,7 +1550,7 @@ void ImGui::EndTable()
} }
else else
{ {
table->InnerWindow->DC.TreeDepth--; inner_window->DC.TreeDepth--;
ItemSize(table->OuterRect.GetSize()); ItemSize(table->OuterRect.GetSize());
ItemAdd(table->OuterRect, 0); ItemAdd(table->OuterRect, 0);
} }
@@ -1565,13 +1565,12 @@ void ImGui::EndTable()
} }
else if (temp_data->UserOuterSize.x <= 0.0f) else if (temp_data->UserOuterSize.x <= 0.0f)
{ {
// Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block // Some references for this: #7651 + tests "table_reported_size", "table_reported_size_outer" equivalent Y block, #9352
// - Checking for ImGuiTableFlags_ScrollX/ScrollY flag makes us a frame ahead when disabling those flags. // - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback? See broken test in 'table_reported_size_outer'
// - FIXME-TABLE: Would make sense to pre-compute expected scrollbar visibility/sizes to generally save a frame of feedback. const float outer_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth;
const float inner_content_max_x = table->OuterRect.Min.x + table->ColumnsAutoFitWidth; // Slightly misleading name but used for code symmetry with inner_content_max_y const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((inner_window != outer_window) ? inner_window->ScrollbarSizes.x : 0.0f);
const float decoration_size = table->TempData->AngledHeadersExtraWidth + ((table->Flags & ImGuiTableFlags_ScrollY) ? inner_window->ScrollbarSizes.x : 0.0f); outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, outer_content_max_x + decoration_size - temp_data->UserOuterSize.x);
outer_window->DC.IdealMaxPos.x = ImMax(outer_window->DC.IdealMaxPos.x, inner_content_max_x + decoration_size - temp_data->UserOuterSize.x); outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, outer_content_max_x + decoration_size));
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos.x, ImMin(table->OuterRect.Max.x, inner_content_max_x + decoration_size));
} }
else else
{ {
@@ -1579,9 +1578,12 @@ void ImGui::EndTable()
} }
if (temp_data->UserOuterSize.y <= 0.0f) if (temp_data->UserOuterSize.y <= 0.0f)
{ {
const float decoration_size = (table->Flags & ImGuiTableFlags_ScrollX) ? inner_window->ScrollbarSizes.y : 0.0f; // (same comment as above)
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, inner_content_max_y + decoration_size - temp_data->UserOuterSize.y); const float outer_content_size_y = (inner_window == outer_window) ? (inner_content_max_y - table->InnerRect.Min.y) : (inner_content_max_y - inner_window->DC.CursorStartPos.y);
outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, inner_content_max_y + decoration_size)); const float outer_content_max_y = table->OuterRect.Min.y + outer_content_size_y;
const float decoration_size = (inner_window != outer_window ? inner_window->ScrollbarSizes.y : 0.0f);
outer_window->DC.IdealMaxPos.y = ImMax(outer_window->DC.IdealMaxPos.y, outer_content_max_y + decoration_size - temp_data->UserOuterSize.y);
outer_window->DC.CursorMaxPos.y = ImMax(backup_outer_max_pos.y, ImMin(table->OuterRect.Max.y, outer_content_max_y + decoration_size));
} }
else else
{ {
+19 -14
View File
@@ -1,4 +1,4 @@
// dear imgui, v1.92.7 // dear imgui, v1.92.8 WIP
// (widgets code) // (widgets code)
/* /*
@@ -4716,7 +4716,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
{ {
ImVec2 backup_pos = window->DC.CursorPos; ImVec2 backup_pos = window->DC.CursorPos;
ItemSize(total_bb, style.FramePadding.y); ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable)) bool no_clip = (g.InputTextDeactivatedState.ID == id) || (g.ActiveId == id) || (id == g.NavActivateId); // Mimic some of ItemAdd() logic + add InputTextDeactivatedState.ID check.
if (!ItemAdd(total_bb, id, &frame_bb, ImGuiItemFlags_Inputable) && !no_clip)
{ {
EndGroup(); EndGroup();
return false; return false;
@@ -4742,7 +4743,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
g.NavActivateId = backup_activate_id; g.NavActivateId = backup_activate_id;
PopStyleVar(3); PopStyleVar(3);
PopStyleColor(); PopStyleColor();
if (!child_visible) if (!child_visible && !no_clip)
{ {
EndChild(); EndChild();
EndGroup(); EndGroup();
@@ -4806,7 +4807,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX; float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;
const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf); const bool init_reload_from_user_buf = (state != NULL && state->WantReloadUserBuf);
const bool init_changed_specs = (state != NULL && state->Stb->single_line != !is_multiline); // state != NULL means its our state. const bool init_changed_specs_multiline = (state != NULL && (state->Stb->single_line != !is_multiline)); // state != NULL means its our state.
const bool init_changed_specs_readonly = (state != NULL && ((state->Flags ^ flags) & ImGuiInputTextFlags_ReadOnly)); // state != NULL means its our state.
const bool init_make_active = (input_requested_by_user || input_requested_by_nav || input_requested_by_reactivate || user_scroll_finish); const bool init_make_active = (input_requested_by_user || input_requested_by_nav || input_requested_by_reactivate || user_scroll_finish);
if (init_reload_from_user_buf) if (init_reload_from_user_buf)
{ {
@@ -4820,7 +4822,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb->select_start = state->ReloadSelectionStart; state->Stb->select_start = state->ReloadSelectionStart;
state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; // will be clamped to bounds below state->Stb->cursor = state->Stb->select_end = state->ReloadSelectionEnd; // will be clamped to bounds below
} }
else if ((init_make_active && g.ActiveId != id) || init_changed_specs) else if ((init_make_active && g.ActiveId != id) || init_changed_specs_multiline || init_changed_specs_readonly)
{ {
// Access state even if we don't own it yet. // Access state even if we don't own it yet.
state = &g.InputTextState; state = &g.InputTextState;
@@ -4841,8 +4843,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
// Preserve cursor position and undo/redo stack if we come back to same widget // Preserve cursor position and undo/redo stack if we come back to same widget
// FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate? // FIXME: Since we reworked this on 2022/06, may want to differentiate recycle_cursor vs recycle_undostate?
bool recycle_state = (state->ID == id && !init_changed_specs); bool recycle_state = (state->ID == id && !init_changed_specs_multiline);
if (recycle_state && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0))) if (recycle_state && !init_changed_specs_readonly && (state->TextLen != buf_len || (state->TextA.Data == NULL || strncmp(state->TextA.Data, buf, buf_len) != 0)))
recycle_state = false; recycle_state = false;
// Start edition // Start edition
@@ -4951,13 +4953,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_password && !is_displaying_hint) if (is_password && !is_displaying_hint)
PushPasswordFont(); PushPasswordFont();
// Word-wrapping: attempt to keep cursor in view while resizing frame/parent if (state != NULL && state->ID == id)
// FIXME-WORDWRAP: It would be better to preserve same relative offset.
if (is_wordwrap && state != NULL && state->ID == id && state->WrapWidth != wrap_width)
{ {
state->CursorCenterY = true; state->Flags = flags;
state->WrapWidth = wrap_width;
render_cursor = true; // Word-wrapping: attempt to keep cursor in view while resizing frame/parent (FIXME-WORDWRAP: would be better to preserve same relative offset)
if (is_wordwrap && state->WrapWidth != wrap_width)
{
state->CursorCenterY = true;
state->WrapWidth = wrap_width;
render_cursor = true;
}
} }
// Process mouse inputs and character inputs // Process mouse inputs and character inputs
@@ -4966,7 +4972,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
IM_ASSERT(state != NULL); IM_ASSERT(state != NULL);
state->EditedThisFrame = false; state->EditedThisFrame = false;
state->BufCapacity = buf_size; state->BufCapacity = buf_size;
state->Flags = flags;
state->WrapWidth = wrap_width; state->WrapWidth = wrap_width;
// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget. // Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
+22 -12
View File
@@ -95,6 +95,10 @@ static void* (*GImGuiFreeTypeAllocFunc)(size_t size, void* user_data) = ImGuiFre
static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc; static void (*GImGuiFreeTypeFreeFunc)(void* ptr, void* user_data) = ImGuiFreeTypeDefaultFreeFunc;
static void* GImGuiFreeTypeAllocatorUserData = nullptr; static void* GImGuiFreeTypeAllocatorUserData = nullptr;
// Load struct
static ImFontLoader GImGuiFreeTypeLoader;
static char GImGuiFreeTypeLoaderName[48] = "FreeType";
// Lunasvg support // Lunasvg support
#ifdef IMGUI_ENABLE_FREETYPE_LUNASVG #ifdef IMGUI_ENABLE_FREETYPE_LUNASVG
static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state); static FT_Error ImGuiLunasvgPortInit(FT_Pointer* state);
@@ -146,6 +150,7 @@ struct ImGui_ImplFreeType_Data
{ {
FT_Library Library; FT_Library Library;
FT_MemoryRec_ MemoryManager; FT_MemoryRec_ MemoryManager;
char BackendName[48];
ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); } ImGui_ImplFreeType_Data() { memset((void*)this, 0, sizeof(*this)); }
}; };
@@ -359,6 +364,11 @@ static bool ImGui_ImplFreeType_LoaderInit(ImFontAtlas* atlas)
return false; return false;
} }
// Update ImFontLoader::Name field with linked version
FT_Int ver_linked_major, ver_linked_minor, ver_linked_patch;
FT_Library_Version(bd->Library, &ver_linked_major, &ver_linked_minor, &ver_linked_patch);
snprintf(GImGuiFreeTypeLoaderName, sizeof(GImGuiFreeTypeLoaderName), "FreeType (%d.%d.%d; %d.%d.%d)", FREETYPE_MAJOR, FREETYPE_MINOR, FREETYPE_PATCH, ver_linked_major, ver_linked_minor, ver_linked_patch);
// If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator. // If you don't call FT_Add_Default_Modules() the rest of code may work, but FreeType won't use our custom allocator.
FT_Add_Default_Modules(bd->Library); FT_Add_Default_Modules(bd->Library);
@@ -569,18 +579,18 @@ static bool ImGui_ImplFreetype_FontSrcContainsGlyph(ImFontAtlas* atlas, ImFontCo
const ImFontLoader* ImGuiFreeType::GetFontLoader() const ImFontLoader* ImGuiFreeType::GetFontLoader()
{ {
static ImFontLoader loader; ImFontLoader* loader = &GImGuiFreeTypeLoader;
loader.Name = "FreeType"; loader->Name = GImGuiFreeTypeLoaderName; // Initially "FreeType" then updated during the call to ImGui_ImplFreeType_LoaderInit()
loader.LoaderInit = ImGui_ImplFreeType_LoaderInit; loader->LoaderInit = ImGui_ImplFreeType_LoaderInit;
loader.LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown; loader->LoaderShutdown = ImGui_ImplFreeType_LoaderShutdown;
loader.FontSrcInit = ImGui_ImplFreeType_FontSrcInit; loader->FontSrcInit = ImGui_ImplFreeType_FontSrcInit;
loader.FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy; loader->FontSrcDestroy = ImGui_ImplFreeType_FontSrcDestroy;
loader.FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph; loader->FontSrcContainsGlyph = ImGui_ImplFreetype_FontSrcContainsGlyph;
loader.FontBakedInit = ImGui_ImplFreeType_FontBakedInit; loader->FontBakedInit = ImGui_ImplFreeType_FontBakedInit;
loader.FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy; loader->FontBakedDestroy = ImGui_ImplFreeType_FontBakedDestroy;
loader.FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph; loader->FontBakedLoadGlyph = ImGui_ImplFreeType_FontBakedLoadGlyph;
loader.FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData); loader->FontBakedSrcLoaderDataSize = sizeof(ImGui_ImplFreeType_FontSrcBakedData);
return &loader; return loader;
} }
void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data) void ImGuiFreeType::SetAllocatorFunctions(void* (*alloc_func)(size_t sz, void* user_data), void (*free_func)(void* ptr, void* user_data), void* user_data)