Merge branch 'master' into docking

This commit is contained in:
ocornut
2026-06-25 15:48:42 +02:00
7 changed files with 62 additions and 20 deletions

View File

@@ -77,6 +77,14 @@ Other Changes:
- Headers: fixed label being clipped early to reserve space for a sort marker
even when no sort marker is displayed. Auto-fitting a column still accounts
for the possible marker, so that sorting after an auto-fit doesn't clip the label.
- Multi-Select
- Reworked ImGuiMultiSelectFlags_NoAutoSelect as it carried side-effects that
were hardcoded/designed to use multi-selection on checkboxes. (#9391)
Specifically removed those undocumented behaviors from _NoAutoSelect:
- Clicking a selected/checked item always unselect/uncheck.
- Shift+Click inverts targets value and copy to range.
- Shift+Keyboard copy selection source value to range.
Those behaviors are still happening on checkboxes used within multi-selection.
- Fonts:
- Added `IMGUI_DISABLE_DEFAULT_FONT_BITMAP`/`IMGUI_DISABLE_DEFAULT_FONT_VECTOR` to
disable embedding either fonts separately. (#9407)
@@ -90,6 +98,14 @@ Other Changes:
- Nav:
- Fixed context menu activation with gamepad erroneously testing for _NavEnableKeyboard
instead of _NavEnableGamepad. (#9454, #8803, #9270) [@Clownacy]
- TreeNode:
- Fixed nav cursor rendering with rounding even though tree nodes don't have it. (#7589)
- Style:
- Added style.MenuItemRounding, ImGuiStyleVar_MenuItemRounding. (#7589, #9375, #9453)
- Added style.SelectableRounding, ImGuiStyleVar_SelectableRounding. (#7589, #9375, #9453)
The use of this is discouraged because it can easily create problems rendering e.g.
contiguous selection.
- Scale the NavCursor border thickness when using large values with `ScallAllSizes()`.
- DrawList:
- Minor optimization to `AddLine()`, `AddLineH()`, `AddLineV()` functions. (#4091)
- Added `ImDrawListFlags_TextNoPixelSnap` to disable snapping of AddText()

View File

@@ -1561,6 +1561,8 @@ ImGuiStyle::ImGuiStyle()
TreeLinesFlags = ImGuiTreeNodeFlags_DrawLinesNone;
TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
TreeLinesRounding = 0.0f; // Radius of lines connecting child nodes to the vertical line.
MenuItemRounding = 0.0f; // Radius of MenuItem, BeginMenu rounding.
SelectableRounding = 0.0f; // Radius of selectable rounding. MODIFYING THIS IS DISCOURAGED. CONTIGUOUS SELECTIONS WILL NOT LOOK RIGHT. (#7589)
DragDropTargetRounding = 0.0f; // Radius of the drag and drop target frame.
DragDropTargetBorderSize = 2.0f; // Thickness of the drag and drop target border.
DragDropTargetPadding = 3.0f; // Size to expand the drag and drop target from actual target item size.
@@ -1642,6 +1644,8 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor)
TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor);
TreeLinesSize = ImTrunc(TreeLinesSize * scale_factor);
TreeLinesRounding = ImTrunc(TreeLinesRounding * scale_factor);
MenuItemRounding = ImTrunc(MenuItemRounding * scale_factor);
SelectableRounding = ImTrunc(SelectableRounding * scale_factor);
DragDropTargetRounding = ImTrunc(DragDropTargetRounding * scale_factor);
DragDropTargetBorderSize = ImTrunc(DragDropTargetBorderSize * scale_factor);
DragDropTargetPadding = ImTrunc(DragDropTargetPadding * scale_factor);
@@ -3756,6 +3760,8 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] =
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, MenuItemRounding)}, // ImGuiStyleVar_MenuItemRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableRounding)}, // ImGuiStyleVar_SelectableRounding
{ 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, DragDropTargetRounding)}, // ImGuiStyleVar_DragDropTargetRounding
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign
{ 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign
@@ -4100,7 +4106,7 @@ void ImGui::RenderColorComponentMarker(const ImRect& bb, ImU32 col, float roundi
RenderRectFilledInRangeH(window->DrawList, bb, col, bb.Min.x, ImMin(bb.Min.x + g.Style.ColorMarkerSize, bb.Max.x), rounding);
}
void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags)
void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags, float rounding)
{
ImGuiContext& g = *GImGui;
if (id != g.NavId)
@@ -4116,17 +4122,24 @@ void ImGui::RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFl
if (window->DC.NavHideHighlightOneFrame)
return;
float rounding = (flags & ImGuiNavRenderCursorFlags_NoRounding) ? 0.0f : g.Style.FrameRounding;
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
if (rounding < 0.0f && (flags & ImGuiNavRenderCursorFlags_NoRounding))
rounding = 0.0f;
#endif
if (rounding < 0.0f)
rounding = g.Style.FrameRounding;
ImRect display_rect = bb;
display_rect.ClipWith(window->ClipRect);
const float thickness = 2.0f;
const float scale_factor = GetScale(); // FIXME-DPI
const float thickness = (float)(int)ImMax(2.0f, 1.5f * scale_factor);
if (flags & ImGuiNavRenderCursorFlags_Compact)
{
window->DrawList->AddRect(display_rect.Min, display_rect.Max, GetColorU32(ImGuiCol_NavCursor), rounding, thickness);
}
else
{
const float distance = 3.0f + thickness * 0.5f;
const float distance = (float)(int)(3.0f + thickness * 0.5f);
display_rect.Expand(ImVec2(distance, distance));
bool fully_visible = window->ClipRect.Contains(display_rect);
if (!fully_visible)

View File

@@ -1941,6 +1941,8 @@ enum ImGuiStyleVar_
ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign
ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize
ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding
ImGuiStyleVar_MenuItemRounding, // float MenuItemRounding
ImGuiStyleVar_SelectableRounding, // float SelectableRounding
ImGuiStyleVar_DragDropTargetRounding, // float DragDropTargetRounding
ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign
ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign
@@ -2419,6 +2421,8 @@ struct ImGuiStyle
ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes.
float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines.
float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line.
float MenuItemRounding; // Radius of MenuItem, BeginMenu rounding.
float SelectableRounding; // Radius of Selectable rounding. MODIFYING THIS IS DISCOURAGED. CONTIGUOUS SELECTIONS WILL NOT LOOK RIGHT. (#7589)
float DragDropTargetRounding; // Radius of the drag and drop target frame. When <0.0f: use FrameRounding.
float DragDropTargetBorderSize; // Thickness of the drag and drop target border.
float DragDropTargetPadding; // Size to expand the drag and drop target from actual target item size.
@@ -3186,6 +3190,7 @@ enum ImGuiMultiSelectFlags_
ImGuiMultiSelectFlags_NavWrapX = 1 << 16, // [Temporary] Enable navigation wrapping on X axis. Provided as a convenience because we don't have a design for the general Nav API for this yet. When the more general feature be public we may obsolete this flag in favor of new one.
ImGuiMultiSelectFlags_NoSelectOnRightClick = 1 << 17, // Disable default right-click processing, which selects item on mouse down, and is designed for context-menus.
ImGuiMultiSelectFlags_SelectOnMask_ = ImGuiMultiSelectFlags_SelectOnAuto | ImGuiMultiSelectFlags_SelectOnClickAlways | ImGuiMultiSelectFlags_SelectOnClickRelease,
ImGuiMultiSelectFlags_CheckboxMode_ = 1 << 20, // [Internal]
// Obsolete names
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS

View File

@@ -8665,6 +8665,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f");
SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
SliderFloat("MenuItemRounding", &style.MenuItemRounding, 0.0f, 12.0f, "%.0f");
// NB: SelectableRounding is intentionally NOT made visible here. We don't want to encourage people using that.
SeparatorText("Scrollbar");
SliderFloat("ScrollbarSize", &style.ScrollbarSize, 1.0f, 20.0f, "%.0f");

View File

@@ -1750,8 +1750,8 @@ enum ImGuiNavRenderCursorFlags_
ImGuiNavRenderCursorFlags_None = 0,
ImGuiNavRenderCursorFlags_Compact = 1 << 1, // Compact highlight, no padding/distance from focused item
ImGuiNavRenderCursorFlags_AlwaysDraw = 1 << 2, // Draw rectangular highlight if (g.NavId == id) even when g.NavCursorVisible == false, aka even when using the mouse.
ImGuiNavRenderCursorFlags_NoRounding = 1 << 3,
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
ImGuiNavRenderCursorFlags_NoRounding = 1 << 3,
ImGuiNavHighlightFlags_None = ImGuiNavRenderCursorFlags_None, // Renamed in 1.91.4
ImGuiNavHighlightFlags_Compact = ImGuiNavRenderCursorFlags_Compact, // Renamed in 1.91.4
ImGuiNavHighlightFlags_AlwaysDraw = ImGuiNavRenderCursorFlags_AlwaysDraw, // Renamed in 1.91.4
@@ -3929,7 +3929,7 @@ namespace ImGui
// Multi-Select API
IMGUI_API void MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags* p_button_flags);
IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed);
IMGUI_API void MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags = 0);
IMGUI_API void MultiSelectAddSetAll(ImGuiMultiSelectTempData* ms, bool selected);
IMGUI_API void MultiSelectAddSetRange(ImGuiMultiSelectTempData* ms, bool selected, int range_dir, ImGuiSelectionUserData first_item, ImGuiSelectionUserData last_item);
inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; }
@@ -3973,7 +3973,7 @@ namespace ImGui
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
IMGUI_API void RenderColorComponentMarker(const ImRect& bb, ImU32 col, float rounding);
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImDrawList* draw_list, ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, ImDrawFlags flags = 0);
IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None); // Navigation highlight
IMGUI_API void RenderNavCursor(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None, float rounding = -1.0f); // Navigation highlight
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
inline void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavRenderCursorFlags flags = ImGuiNavRenderCursorFlags_None) { RenderNavCursor(bb, id, flags); } // Renamed in 1.91.4
#endif

View File

@@ -1833,7 +1833,7 @@ void ImGui::TableReconcileColumns(ImGuiTable* table)
ImGuiTableReconcileColumnData& reconcile_data = reconcile_requests[dst_idx];
ImGuiTableColumn& dst_column = dst_columns[reconcile_data.ColumnNewIdx];
IM_ASSERT(src_column.IsNeedReconcileSrc && dst_column.IsNeedReconcileDst);
dst_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false;
src_column.IsNeedReconcileSrc = dst_column.IsNeedReconcileDst = false;
reconcile_data.ColumnOldIdx = (ImGuiTableColumnIdx)src_columns.index_from_ptr(&src_column);
reconcile_data.ColumnOldData = src_column;
}
@@ -3395,7 +3395,7 @@ void ImGui::TableHeader(const char* label)
if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
}
RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding);
RenderNavCursor(bb, id, ImGuiNavRenderCursorFlags_Compact, 0.0f);
if (held)
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;

View File

@@ -1281,7 +1281,7 @@ bool ImGui::Checkbox(const char* label, bool* v)
// Range-Selection/Multi-selection support (footer)
if (is_multi_select)
MultiSelectItemFooter(id, &checked, &pressed);
MultiSelectItemFooter(id, &checked, &pressed, ImGuiMultiSelectFlags_CheckboxMode_);
else if (pressed)
checked = !checked;
@@ -7123,9 +7123,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (hovered || selected)
{
const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false, 0.0f);
}
RenderNavCursor(frame_bb, id, nav_render_cursor_flags);
RenderNavCursor(frame_bb, id, nav_render_cursor_flags, 0.0f);
if (span_all_columns && !span_all_columns_label)
TablePopBackgroundChannel();
if (flags & ImGuiTreeNodeFlags_Bullet)
@@ -7505,14 +7505,14 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
{
// Between 1.91.0 and 1.91.4 we made selected Selectable use an arbitrary lerp between _Header and _HeaderHovered. Removed that now. (#8106)
ImU32 col = GetColorU32((held && highlighted) ? ImGuiCol_HeaderActive : highlighted ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
RenderFrame(bb.Min, bb.Max, col, false, style.SelectableRounding);
}
if (g.NavId == id)
{
ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact | ImGuiNavRenderCursorFlags_NoRounding;
ImGuiNavRenderCursorFlags nav_render_cursor_flags = ImGuiNavRenderCursorFlags_Compact;
if (is_multi_select)
nav_render_cursor_flags |= ImGuiNavRenderCursorFlags_AlwaysDraw; // Always show the nav rectangle
RenderNavCursor(bb, id, nav_render_cursor_flags);
RenderNavCursor(bb, id, nav_render_cursor_flags, style.SelectableRounding);
}
}
@@ -8314,7 +8314,7 @@ void ImGui::MultiSelectItemHeader(ImGuiID id, bool* p_selected, ImGuiButtonFlags
// - Altering selection based on Ctrl/Shift modifiers, both for keyboard and mouse.
// - Record current selection state for RangeSrc
// This is all rather complex, best to run and refer to "widgets_multiselect_xxx" tests in imgui_test_suite.
void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed, ImGuiMultiSelectFlags extra_flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -8334,7 +8334,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
ImGuiSelectionUserData item_data = g.NextItemData.SelectionUserData;
ImGuiMultiSelectFlags flags = ms->Flags;
ImGuiMultiSelectFlags flags = ms->Flags | extra_flags;
const bool is_singleselect = (flags & ImGuiMultiSelectFlags_SingleSelect) != 0;
bool is_ctrl = (ms->KeyMods & ImGuiMod_Ctrl) != 0;
bool is_shift = (ms->KeyMods & ImGuiMod_Shift) != 0;
@@ -8488,7 +8488,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
//IM_ASSERT(storage->HasRangeSrc && storage->HasRangeValue);
if (storage->RangeSrcItem == ImGuiSelectionUserData_Invalid)
storage->RangeSrcItem = item_data;
if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0)
if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0)
{
// Shift+Arrow always select
// Ctrl+Shift+Arrow copy source selection state (already stored by BeginMultiSelect() in storage->RangeSelected)
@@ -8508,7 +8508,7 @@ void ImGui::MultiSelectItemFooter(ImGuiID id, bool* p_selected, bool* p_pressed)
else
{
// Ctrl inverts selection, otherwise always select
if ((flags & ImGuiMultiSelectFlags_NoAutoSelect) == 0)
if ((flags & ImGuiMultiSelectFlags_CheckboxMode_) == 0)
selected = is_ctrl ? !selected : true;
else
selected = !selected;
@@ -9362,7 +9362,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
bool menu_is_open = IsPopupOpen(id, ImGuiPopupFlags_None);
@@ -9407,6 +9407,8 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
bool pressed;
const float backup_rounding = style.SelectableRounding;
style.SelectableRounding = style.MenuItemRounding;
const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoAutoClosePopups | (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnClick;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -9442,6 +9444,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
RenderArrow(window->DrawList, ImVec2(text_pos.x + offsets->OffsetMark + extra_w + g.FontSize * 0.30f, text_pos.y), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
popup_pos = ImVec2(pos.x, text_pos.y - style.WindowPadding.y);
}
style.SelectableRounding = backup_rounding;
if (!enabled)
EndDisabled();
@@ -9628,6 +9631,8 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
BeginDisabled();
// We use ImGuiSelectableFlags_NoSetKeyOwner to allow down on one menu item, move, up on another.
const float backup_rounding = style.SelectableRounding;
style.SelectableRounding = style.MenuItemRounding;
const ImGuiSelectableFlags selectable_flags = (ImGuiSelectableFlags)ImGuiSelectableFlags_SelectOnRelease | (ImGuiSelectableFlags)ImGuiSelectableFlags_SetNavIdOnHover;
ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -9671,6 +9676,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
RenderCheckMark(window->DrawList, text_pos + ImVec2(offsets->OffsetMark + stretch_w + g.FontSize * 0.40f, g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text), g.FontSize * 0.866f);
}
}
style.SelectableRounding = backup_rounding;
// Once dragged, release ActiveId + key ownership. This is to allow the idiom of mouse down a menu, dragging elsewhere, up on some other MenuItem(). (#8233, #9394)
// Could move logic into lower-level ImGuiButtonFlags_AutoReleaseActiveId + ImGuiButtonFlags_AutoReleaseKeyOwner? Easier once we get rid of the Selectable() middle-man here.