Merge branch 'master' into docking

This commit is contained in:
ocornut
2026-09-09 21:25:09 +02:00
5 changed files with 96 additions and 41 deletions

View File

@@ -4018,6 +4018,7 @@ void ImGui::RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end
// Effectively as this is called from widget doing their own coarse clipping it's not very valuable presently. Next time function will take
// better advantage of the render function taking size into account for coarse clipping.
void ImGui::RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_display_end, const ImVec2* text_size_if_known, const ImVec2& align, const ImRect* clip_rect)
// DOES NOT CALL LogRenderedText(), unlike RenderTextClipped!!!
{
// Perform CPU side clipping for single clipped element to avoid using scissor state
ImVec2 pos = pos_min;

14
imgui.h
View File

@@ -30,7 +30,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
#define IMGUI_VERSION "1.93.0 WIP"
#define IMGUI_VERSION_NUM 19296
#define IMGUI_VERSION_NUM 19297
#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_VIEWPORT // In 'docking' WIP branch.
@@ -1305,7 +1305,6 @@ enum ImGuiItemFlags_
ImGuiItemFlags_AutoClosePopups = 1 << 4, // true // MenuItem()/Selectable() automatically close their parent popup window.
ImGuiItemFlags_AllowDuplicateId = 1 << 5, // false // Allow submitting an item with the same identifier as an item already submitted this frame without triggering a warning tooltip if io.ConfigDebugHighlightIdConflicts is set.
ImGuiItemFlags_Disabled = 1 << 6, // false // [Internal] Disable interactions. DOES NOT affect visuals. This is used by BeginDisabled()/EndDisabled() and only provided here so you can read back via GetItemFlags().
ImGuiItemFlags_MixedValue = 1 << 9, // false // [BETA] Represent a mixed/indeterminate value. Replace value label with "-" and apply edits on validation. Only supported by some widgets: Checkbox, RadioButton, Sliders and Drags.
//---------------------------------------------------------------------------------
// LiveEdit refers to applying edits to backing variables _while_ typing a value using the keyboard.
@@ -1319,6 +1318,17 @@ enum ImGuiItemFlags_
ImGuiItemFlags_LiveEditOnInputText = 1 << 7, // true // InputText: apply keyboard edits to backing value while typing. Otherwise, edits are applied when validating, tabbing out or losing focus.
ImGuiItemFlags_LiveEditOnInputScalar = 1 << 8, // false // DragXXX, SliderXXX, InputScalar: apply keyboard edits to backing value while typing. Otherwise, edits are applied when validating, tabbing out or losing focus.
ImGuiItemFlags_LiveEditOnInput = ImGuiItemFlags_LiveEditOnInputText | ImGuiItemFlags_LiveEditOnInputScalar,
//---------------------------------------------------------------------------------
// [BETA] MixedValue mode used to represent a mixed/indeterminate state, typically for multi-selection.
// - Replace value display with "-" or a custom label.
// - Enter key validation apply an edit and return true even if value hasn't changed (in order to apply to all).
// - Supported by selected widgets: Checkbox, RadioButton, Sliders, Drags, Inputs, Combo.
// - Note: InputText-side Undo cannot be reliably combined with MixedValue + LiveEdit On:
// - Both the initial edit and subsequent undo/revert will typically make your app code write to all backing objects.
// - If you use MixedMode and the simplest solution is to ensure LiveEdit is off but widgets where this applies.
//---------------------------------------------------------------------------------
ImGuiItemFlags_MixedValue = 1 << 9, // false // [BETA] Represent a mixed/indeterminate value. Replace value label with "-" and apply edits on validation.
};
// Flags for ImGui::InputText()

View File

@@ -2133,13 +2133,16 @@ static void DemoWindowWidgetsMixedValues()
// This is designed for advanced property editors which are generally reusable and data-driven.
HelpMarker("Using ImGuiItemFlags_MixedValue.");
static bool use_liveedit = false;
static float items[3] = { 12.0f, 0.0f, 0.0f };
float* item_ref = &items[0];
ImGui::Checkbox("ImGuiItemFlags_LiveEditOnInput", &use_liveedit);
ImGui::SeparatorText("Scalar/Text Widgets");
const bool is_mixed = memcmp(&items[0], &items[1], sizeof(float)) != 0 || memcmp(&items[0], &items[2], sizeof(float)) != 0;
// Demonstrate Drags, Sliders, Inputs
ImGui::PushItemFlag(ImGuiItemFlags_LiveEditOnInput, use_liveedit);
ImGui::PushItemFlag(ImGuiItemFlags_MixedValue, is_mixed);
bool edited = false;
edited |= ImGui::DragFloat("DragFloat", item_ref);
@@ -2155,6 +2158,7 @@ static void DemoWindowWidgetsMixedValues()
ImGui::InputFloat("item 0 (ref)", &items[0]);
ImGui::InputFloat("item 1", &items[1]);
ImGui::InputFloat("item 2", &items[2]);
ImGui::PopItemFlag();
// Demonstrate Checkbox(), RadioButton(), Combo(), ColorEdit4()
ImGui::SeparatorText("Others Widgets");

View File

@@ -194,6 +194,7 @@ struct ImGuiWindow; // Storage for one window
struct ImGuiWindowDockStyle; // Storage for window-style data which needs to be stored for docking purpose
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame, in practice we currently keep it for each window)
struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
struct ImGuiWindowStackData; // Storage for each window pushed into the stack
// Enumerations
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
@@ -943,6 +944,8 @@ struct ImFontStackData
// [SECTION] Style support
//-----------------------------------------------------------------------------
#define ImGuiCol_TextMixedValue ImGuiCol_TextDisabled
struct ImGuiStyleVarInfo
{
ImU32 Count : 8; // 1+
@@ -1039,7 +1042,7 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HasShortcut = 1 << 10, // g.LastItemData.Shortcut valid. Set by SetNextItemShortcut() -> ItemAdd().
//ImGuiItemStatusFlags_FocusedByTabbing = 1 << 8, // Removed IN 1.90.1 (Dec 2023). The trigger is part of g.NavActivateId. See commit 54c1bdeceb.
ImGuiItemStatusFlags_EditedInternal = 1 << 11, // Similar to ImGuiItemStatusFlags_Edited but bypassing ImGuiItemFlags_NoMarkEdited.
// Additional status + semantic for ImGuiTestEngine
#ifdef IMGUI_ENABLE_TEST_ENGINE
ImGuiItemStatusFlags_Openable = 1 << 20, // Item is an openable (e.g. TreeNode)
@@ -1093,12 +1096,6 @@ enum ImGuiButtonFlagsPrivate_
//ImGuiButtonFlags_NoKeyModifiers = ImGuiButtonFlags_NoKeyModsAllowed, // Renamed in 1.91.4
};
// Extend ImGuiComboFlags_
enum ImGuiComboFlagsPrivate_
{
ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview()
};
// Extend ImGuiSliderFlags_
enum ImGuiSliderFlagsPrivate_
{
@@ -1193,6 +1190,10 @@ enum ImGuiPlotType
ImGuiPlotType_Histogram,
};
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//ImGuiComboFlags_CustomPreview = 1 << 20, // enable BeginComboPreview() // [Obsoleted in 1.93.0] Unnecessary: can now use BeginComboPreview() without a flag.
#endif
// Storage data for BeginComboPreview()/EndComboPreview()
struct IMGUI_API ImGuiComboPreviewData
{
@@ -1201,7 +1202,10 @@ struct IMGUI_API ImGuiComboPreviewData
ImVec2 BackupCursorMaxPos;
ImVec2 BackupCursorPosPrevLine;
float BackupPrevLineTextBaseOffset;
ImGuiLayoutType BackupLayout;
float BackupWorkRectMaxX;
float BackupContentRectMaxX;
ImGuiLayoutType BackupLayout : 8;
int WithinPreview : 2;
ImGuiComboPreviewData() { memset((void*)this, 0, sizeof(*this)); }
};
@@ -1290,6 +1294,7 @@ struct IMGUI_API ImGuiInputTextState
bool SelectedAllMouseLock; // after a double-click to select all, we ignore further mouse drags to update selection
bool EditedBefore; // edited since activated
bool EditedThisFrame; // edited this frame
bool ValidatedThisFrame;
bool WantReloadUserBuf; // force a reload of user buf so it may be modified externally. may be automatic in future version.
ImS8 LastMoveDirectionLR; // ImGuiDir_Left or ImGuiDir_Right. track last movement direction so when cursor cross over a word-wrapping boundaries we can display it on either line depending on last move.s
int ReloadSelectionStart;
@@ -1475,7 +1480,7 @@ struct IMGUI_API ImGuiErrorRecoveryState
ImGuiErrorRecoveryState() { memset((void*)this, 0, sizeof(*this)); }
};
// Data saved for each window pushed into the stack
// Storage for each window pushed into the stack.
struct ImGuiWindowStackData
{
ImGuiWindow* Window;
@@ -1483,6 +1488,7 @@ struct ImGuiWindowStackData
ImGuiErrorRecoveryState StackSizesInBegin; // Store size of various stacks for asserting
bool DisabledOverrideReenable; // Non-child window override disabled flag
float DisabledOverrideReenableAlphaBackup;
ImRect ParentLastComboPreviewRect;
};
struct ImGuiShrinkWidthItem
@@ -2501,7 +2507,7 @@ struct ImGuiContext
ImVec2 WheelingAxisAvg;
// Item/widgets state and tracking information
const char* MixedValueLabel; // Value replacement when displaying a mixed value. Default to "-" (Unreal uses "Multiple values", Unity uses "---"). May be interpreted as a format: must not contain single %.
const char* MixedValueLabel; // Value replacement when displaying a mixed value. Default to "-" (Unreal uses "Multiple values", Unity uses "---"). May be interpreted as a format: must not contain single %. Set to NULL to display original value.
ImGuiID DebugDrawIdConflictsId; // Set when we detect multiple items with the same identifier
ImGuiID DebugHookIdInfoId; // Will call core hooks: DebugHookIdInfo() from GetID functions, used by ID Stack Tool [next HoveredId/ActiveId to not pull in an extra cache-line]
ImGuiID HoveredId; // Hovered widget, filled during the frame
@@ -3772,7 +3778,7 @@ namespace ImGui
// Combos
IMGUI_API bool BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags flags);
IMGUI_API bool BeginComboPreview();
IMGUI_API bool BeginComboPreview(); // Submit preview contents a combo. Call this after EndCombo() to display contents that's more than just a text label.
IMGUI_API void EndComboPreview();
// Keyboard/Gamepad Navigation

View File

@@ -1958,7 +1958,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
const ImGuiID id = window->GetID(label);
IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)); // Can't use both flags together
if (flags & ImGuiComboFlags_WidthFitPreview)
IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0);
IM_ASSERT((flags & ImGuiComboFlags_NoPreview) == 0);
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
const char* label_end = FindRenderedTextEnd(label);
@@ -1998,13 +1998,8 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
}
RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding);
// Custom preview
if (flags & ImGuiComboFlags_CustomPreview)
{
g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);
IM_ASSERT(preview_value == NULL || preview_value[0] == 0);
preview_value = NULL;
}
// Store geometry for BeginComboPreview() - only necessary when visible.
g.ComboPreviewData.PreviewRect = (flags & ImGuiComboFlags_NoPreview) ? ImRect() : ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);
// Render preview and label
if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
@@ -2086,6 +2081,7 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
return false;
}
g.BeginComboDepth++;
g.CurrentWindowStack.back().ParentLastComboPreviewRect = g.ComboPreviewData.PreviewRect;
return true;
}
@@ -2093,6 +2089,7 @@ void ImGui::EndCombo()
{
ImGuiContext& g = *GImGui;
g.BeginComboDepth--;
g.ComboPreviewData.PreviewRect = g.CurrentWindowStack.back().ParentLastComboPreviewRect;
char name[16];
ImFormatString(name, IM_COUNTOF(name), "##Combo_%02d", g.BeginComboDepth); // FIXME: Move those to helpers?
if (strcmp(g.CurrentWindow->Name, name) != 0)
@@ -2100,19 +2097,26 @@ void ImGui::EndCombo()
EndPopup();
}
// Call directly after the BeginCombo/EndCombo block. The preview is designed to only host non-interactive elements
// (Experimental, see GitHub issues: #1658, #4168)
// Submit preview contents for BeginCombo()/EndCombo(), to display contents that's more than just a text label.
// - [BETA] See GitHub issues: #1658, #4168.
// - Make sure you call this after EndCombo().
// - The preview is designed to only host non-interactive elements.
// - Not compatible with ImGuiComboFlags_WidthFitPreview.
// - 2026-09-08 (1.93.0): removed ImGuiComboFlags_CustomPreview. You can use BeginComboPreview()/EndComboPreview() without an extra flag.
bool ImGui::BeginComboPreview()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiComboPreviewData* preview_data = &g.ComboPreviewData;
if (window->SkipItems || !(g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible))
return false;
IM_ASSERT(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y); // Didn't call after BeginCombo/EndCombo block or forgot to pass ImGuiComboFlags_CustomPreview flag?
if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional)
ImGuiComboPreviewData* preview_data = &g.ComboPreviewData;
if (!window->ClipRect.Overlaps(preview_data->PreviewRect) || preview_data->PreviewRect.GetWidth() <= 0.0f) // Narrower test (optional) + handle _NoPreview
return false;
IM_ASSERT_USER_ERROR_RETV(g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x && g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y, false,
"Call BeginComboPreview() after BeginCombo(), not after EndCombo()!"); // Calling after EndCombo() works only if you don't nest combos.
IM_ASSERT_USER_ERROR_RETV(preview_data->WithinPreview == false, false,
"Cannot recurse BeginComboPreview(): call EndComboPreview() before opening another combo.");
// FIXME: This could be contained in a PushWorkRect() api
preview_data->BackupCursorPos = window->DC.CursorPos;
@@ -2120,6 +2124,10 @@ bool ImGui::BeginComboPreview()
preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine;
preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
preview_data->BackupLayout = window->DC.LayoutType;
preview_data->WithinPreview = true;
preview_data->BackupWorkRectMaxX = window->WorkRect.Max.x;
preview_data->BackupContentRectMaxX = window->ContentRegionRect.Max.x;
window->WorkRect.Max.x = window->ContentRegionRect.Max.x = preview_data->PreviewRect.Max.x - g.Style.FramePadding.x;
window->DC.CursorPos = preview_data->PreviewRect.Min + g.Style.FramePadding;
window->DC.CursorMaxPos = window->DC.CursorPos;
window->DC.LayoutType = ImGuiLayoutType_Horizontal;
@@ -2145,12 +2153,14 @@ void ImGui::EndComboPreview()
}
PopClipRect();
window->DC.CursorPos = preview_data->BackupCursorPos;
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos);
window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos); // No need to do the same with IdealMaxPos
window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine;
window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset;
window->WorkRect.Max.x = preview_data->BackupWorkRectMaxX;
window->ContentRegionRect.Max.x = preview_data->BackupContentRectMaxX;
window->DC.LayoutType = preview_data->BackupLayout;
window->DC.IsSameLine = false;
preview_data->PreviewRect = ImRect();
preview_data->WithinPreview = false;
}
// Getter for the old Combo() API: const char*[]
@@ -2824,12 +2834,16 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
MarkItemEdited(id);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
const char* format_for_display = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) ? g.MixedValueLabel : format;
const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0;
char value_buf[64];
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format_for_display);
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format);
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
if (is_mixed)
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]);
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (is_mixed)
PopStyleColor();
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
@@ -3432,12 +3446,16 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(g.ActiveId == id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
const char* format_for_display = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) ? g.MixedValueLabel : format;
const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0;
char value_buf[64];
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format_for_display);
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format);
if (g.LogEnabled)
LogSetNextTextDecoration("{", "}");
if (is_mixed)
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]);
RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
if (is_mixed)
PopStyleColor();
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
@@ -3587,10 +3605,15 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
// Display value using user-provided display format so user can add prefix/suffix/decorations to the value.
// For the vertical slider we allow centered text to overlap the frame padding
const char* format_for_display = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) ? g.MixedValueLabel : format;
const bool is_mixed = (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue) != 0;
char value_buf[64];
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, format_for_display);
const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_COUNTOF(value_buf), data_type, p_data, (is_mixed && g.MixedValueLabel != NULL) ? g.MixedValueLabel : format);
if (is_mixed)
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]);
RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));
if (is_mixed)
PopStyleColor();
if (label_size.x > 0.0f)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
@@ -3827,7 +3850,11 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
// Only mark as edited if new value is different
g.LastItemData.ItemFlags &= ~ImGuiItemFlags_NoMarkEdited;
bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0 || (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue);
bool value_changed = memcmp(&data_backup, p_data, data_type_size) != 0;
if (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue)
if (ImGuiInputTextState* state = GetInputTextState(g.LastItemData.ID))
value_changed |= (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputScalar) ? (state->EditedThisFrame | state->ValidatedThisFrame) : state->ValidatedThisFrame;
if (value_changed)
MarkItemEdited(id);
return value_changed;
@@ -3905,7 +3932,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
}
}
if (g.LastItemData.ItemFlags & ImGuiItemFlags_MixedValue)
value_changed |= ret;
if (ImGuiInputTextState* state = GetInputTextState(g.LastItemData.ID))
value_changed |= (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputScalar) ? (state->EditedThisFrame | state->ValidatedThisFrame) : state->ValidatedThisFrame;
// Step buttons
if (has_step_buttons)
@@ -5045,6 +5073,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (state != NULL && state->ID == id)
{
state->Flags = flags;
state->EditedThisFrame = state->ValidatedThisFrame = false;
//state->LastFrameActive = g.FrameCount;
// Word-wrapping: attempt to keep cursor in view while resizing frame/parent (FIXME-WORDWRAP: would be better to preserve same relative offset)
@@ -5060,7 +5089,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (g.ActiveId == id)
{
IM_ASSERT(state != NULL);
state->EditedThisFrame = false;
state->BufCapacity = buf_size;
state->WrapWidth = wrap_width;
@@ -5463,7 +5491,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (g.LastItemData.ItemFlags & ImGuiItemFlags_LiveEditOnInputText)
{
// Apply when modified
if (strcmp(state->TextSrc, buf) != 0 || (is_mixed && validated))
if (strcmp(state->TextSrc, buf) != 0 || (is_mixed && (state->EditedThisFrame || validated)))
{
apply_new_text = state->TextSrc;
apply_new_text_length = state->TextLen;
@@ -5567,7 +5595,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (is_password && !is_displaying_hint)
PushPasswordFont();
}
if (is_mixed && g.ActiveId != id && apply_new_text == NULL)
const bool is_displaying_mixed = is_mixed && g.ActiveId != id && apply_new_text == NULL;
if (is_displaying_mixed && g.MixedValueLabel != NULL)
{
buf_display = g.MixedValueLabel;
buf_display_end = buf_display + strlen(g.MixedValueLabel);
@@ -5616,7 +5645,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
ImVec2 draw_scroll;
// Render text. We currently only render selection when the widget is active or while scrolling.
const ImU32 text_col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
const ImU32 text_col = GetColorU32(is_displaying_mixed ? ImGuiCol_TextMixedValue : is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
if (render_cursor || render_selection)
{
// Render text (with cursor and selection)
@@ -5789,6 +5818,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label, label_end, false);
if (state && validated)
state->ValidatedThisFrame = true;
if (value_changed)
MarkItemEdited(id);
@@ -6590,7 +6621,10 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (is_mixed)
{
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding);
RenderTextClipped(ImVec2(bb.Min.x, bb.Min.y + g.Style.FramePadding.y), bb.Max, g.MixedValueLabel, NULL, NULL, ImVec2(0.5f, 0.0f));
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextMixedValue]);
if (g.MixedValueLabel != NULL)
RenderTextClipped(ImVec2(bb.Min.x, bb.Min.y + g.Style.FramePadding.y), bb.Max, g.MixedValueLabel, NULL, NULL, ImVec2(0.5f, 0.0f));
PopStyleColor();
}
else if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f)
{