mirror of
https://github.com/wolfpld/tracy.git
synced 2025-03-20 07:40:02 +08:00
Update ImGui to 1.89.9 + docking.
This commit is contained in:
+171
-149
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.89.5
|
||||
// dear imgui, v1.89.9
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -41,11 +41,7 @@ Index of this file:
|
||||
#include "imgui_internal.h"
|
||||
|
||||
// System includes
|
||||
#if defined(_MSC_VER) && _MSC_VER <= 1500 // MSVC 2008 or earlier
|
||||
#include <stddef.h> // intptr_t
|
||||
#else
|
||||
#include <stdint.h> // intptr_t
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// Warnings
|
||||
@@ -124,7 +120,7 @@ static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
// 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 ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx, const ImWchar* text_begin, const ImWchar* text_end, const ImWchar** remaining = NULL, ImVec2* out_offset = NULL, bool stop_on_new_line = false);
|
||||
|
||||
@@ -492,6 +488,14 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0)
|
||||
flags |= ImGuiButtonFlags_PressedOnDefault_;
|
||||
|
||||
// Default behavior inherited from item flags
|
||||
// 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);
|
||||
if (flags & ImGuiButtonFlags_AllowOverlap)
|
||||
item_flags |= ImGuiItemFlags_AllowOverlap;
|
||||
if (flags & ImGuiButtonFlags_Repeat)
|
||||
item_flags |= ImGuiItemFlags_ButtonRepeat;
|
||||
|
||||
ImGuiWindow* backup_hovered_window = g.HoveredWindow;
|
||||
const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredWindow && g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree;
|
||||
if (flatten_hovered_children)
|
||||
@@ -504,11 +508,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
#endif
|
||||
|
||||
bool pressed = false;
|
||||
bool hovered = ItemHoverable(bb, id);
|
||||
|
||||
// Drag source doesn't report as hovered
|
||||
if (hovered && g.DragDropActive && g.DragDropPayload.SourceId == id && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoDisableHover))
|
||||
hovered = false;
|
||||
bool hovered = ItemHoverable(bb, id, item_flags);
|
||||
|
||||
// Special mode for Drag and Drop where holding button pressed for a long time while dragging another item triggers the button
|
||||
if (g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
|
||||
@@ -527,10 +527,6 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
if (flatten_hovered_children)
|
||||
g.HoveredWindow = backup_hovered_window;
|
||||
|
||||
// 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.
|
||||
if (hovered && (flags & ImGuiButtonFlags_AllowItemOverlap) && (g.HoveredIdPreviousFrame != id && g.HoveredIdPreviousFrame != 0))
|
||||
hovered = false;
|
||||
|
||||
// Mouse handling
|
||||
const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any : id;
|
||||
if (hovered)
|
||||
@@ -579,7 +575,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
{
|
||||
if (mouse_button_released != -1)
|
||||
{
|
||||
const bool has_repeated_at_least_once = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior
|
||||
const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button_released] >= g.IO.KeyRepeatDelay; // Repeat mode trumps on release behavior
|
||||
if (!has_repeated_at_least_once)
|
||||
pressed = true;
|
||||
if (!(flags & ImGuiButtonFlags_NoNavFocus))
|
||||
@@ -590,7 +586,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
|
||||
// 'Repeat' mode acts when held regardless of _PressedOn flags (see table above).
|
||||
// Relies on repeat logic of IsMouseClicked() but we may as well do it ourselves if we end up exposing finer RepeatDelay/RepeatRate settings.
|
||||
if (g.ActiveId == id && (flags & ImGuiButtonFlags_Repeat))
|
||||
if (g.ActiveId == id && (item_flags & ImGuiItemFlags_ButtonRepeat))
|
||||
if (g.IO.MouseDownDuration[g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat))
|
||||
pressed = true;
|
||||
}
|
||||
@@ -608,7 +604,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
{
|
||||
bool nav_activated_by_code = (g.NavActivateId == id);
|
||||
bool nav_activated_by_inputs = (g.NavActivatePressedId == id);
|
||||
if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat))
|
||||
if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat))
|
||||
{
|
||||
// Avoid pressing multiple keys from triggering excessive amount of repeat events
|
||||
const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space);
|
||||
@@ -655,7 +651,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
{
|
||||
// Report as pressed when releasing the mouse (this is the most common path)
|
||||
bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) && g.IO.MouseReleased[mouse_button] && g.IO.MouseClickedLastCount[mouse_button] == 2;
|
||||
bool is_repeating_already = (flags & ImGuiButtonFlags_Repeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps <on release>
|
||||
bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) && g.IO.MouseDownDurationPrev[mouse_button] >= g.IO.KeyRepeatDelay; // Repeat mode trumps <on release>
|
||||
bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id);
|
||||
if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned)
|
||||
pressed = true;
|
||||
@@ -702,9 +698,6 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
|
||||
if (!ItemAdd(bb, id))
|
||||
return false;
|
||||
|
||||
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
|
||||
flags |= ImGuiButtonFlags_Repeat;
|
||||
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
|
||||
|
||||
@@ -781,9 +774,6 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu
|
||||
if (!ItemAdd(bb, id))
|
||||
return false;
|
||||
|
||||
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
|
||||
flags |= ImGuiButtonFlags_Repeat;
|
||||
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
|
||||
|
||||
@@ -812,14 +802,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)
|
||||
// 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;
|
||||
const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();
|
||||
if (area_to_visible_ratio < 1.5f)
|
||||
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.
|
||||
// (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 hovered, held;
|
||||
@@ -849,22 +839,24 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos, ImGuiDockNode* dock_no
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f);
|
||||
ItemAdd(bb, id);
|
||||
ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize));
|
||||
bool is_clipped = !ItemAdd(bb, id);
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
|
||||
if (is_clipped)
|
||||
return pressed;
|
||||
|
||||
// Render
|
||||
//bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
|
||||
ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
ImU32 text_col = GetColorU32(ImGuiCol_Text);
|
||||
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)
|
||||
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, text_col);
|
||||
RenderArrowDockMenu(window->DrawList, bb.Min, g.FontSize, text_col);
|
||||
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
|
||||
if (IsItemActive() && IsMouseDragging(0))
|
||||
@@ -887,9 +879,9 @@ ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
|
||||
const float scrollbar_size = window->ScrollbarSizes[axis ^ 1]; // (ScrollbarSizes.x = width of Y scrollbar; ScrollbarSizes.y = height of X scrollbar)
|
||||
IM_ASSERT(scrollbar_size > 0.0f);
|
||||
if (axis == ImGuiAxis_X)
|
||||
return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x, outer_rect.Max.y);
|
||||
return ImRect(inner_rect.Min.x, ImMax(outer_rect.Min.y, outer_rect.Max.y - border_size - scrollbar_size), inner_rect.Max.x - border_size, outer_rect.Max.y - border_size);
|
||||
else
|
||||
return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x, inner_rect.Max.y);
|
||||
return ImRect(ImMax(outer_rect.Min.x, outer_rect.Max.x - border_size - scrollbar_size), inner_rect.Min.y, outer_rect.Max.x - border_size, inner_rect.Max.y - border_size);
|
||||
}
|
||||
|
||||
void ImGui::Scrollbar(ImGuiAxis axis)
|
||||
@@ -1174,10 +1166,8 @@ bool ImGui::CheckboxFlagsT(const char* label, T* flags, T flags_value)
|
||||
if (!all_on && any_on)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiItemFlags backup_item_flags = g.CurrentItemFlags;
|
||||
g.CurrentItemFlags |= ImGuiItemFlags_MixedValue;
|
||||
g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue;
|
||||
pressed = Checkbox(label, &all_on);
|
||||
g.CurrentItemFlags = backup_item_flags;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1398,8 +1388,9 @@ void ImGui::AlignTextToFramePadding()
|
||||
}
|
||||
|
||||
// Horizontal/vertical separating line
|
||||
// FIXME: Surprisingly, this seemingly simple widget is adjacent to MANY different legacy/tricky layout issues.
|
||||
void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
|
||||
// FIXME: Surprisingly, this seemingly trivial widget is a victim of many different legacy/tricky layout issues.
|
||||
// Note how thickness == 1.0f is handled specifically as not moving CursorPos by 'thickness', but other values are.
|
||||
void ImGui::SeparatorEx(ImGuiSeparatorFlags flags, float thickness)
|
||||
{
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
@@ -1407,8 +1398,8 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected
|
||||
IM_ASSERT(thickness > 0.0f);
|
||||
|
||||
const float thickness = 1.0f; // Cannot use g.Style.SeparatorTextSize yet for various reasons.
|
||||
if (flags & ImGuiSeparatorFlags_Vertical)
|
||||
{
|
||||
// Vertical separator, for menu bars (use current line height).
|
||||
@@ -1442,6 +1433,8 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
|
||||
x2 = table->Columns[table->CurrentColumn].MaxX;
|
||||
}
|
||||
|
||||
// Before Tables API happened, we relied on Separator() to span all columns of a Columns() set.
|
||||
// We currently don't need to provide the same feature for tables because tables naturally have border features.
|
||||
ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL;
|
||||
if (columns)
|
||||
PushColumnsBackground();
|
||||
@@ -1451,8 +1444,8 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
|
||||
const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness; // FIXME: See 1.70/1.71 Separator() change: makes legacy 1-px separator not affect layout yet. Should change.
|
||||
const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness));
|
||||
ItemSize(ImVec2(0.0f, thickness_for_layout));
|
||||
const bool item_visible = ItemAdd(bb, 0);
|
||||
if (item_visible)
|
||||
|
||||
if (ItemAdd(bb, 0))
|
||||
{
|
||||
// Draw
|
||||
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));
|
||||
@@ -1475,10 +1468,11 @@ void ImGui::Separator()
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
// Those flags should eventually be overridable by the user
|
||||
// Those flags should eventually be configurable by the user
|
||||
// FIXME: We cannot g.Style.SeparatorTextBorderSize for thickness as it relates to SeparatorText() which is a decorated separator, not defaulting to 1.0f.
|
||||
ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
|
||||
flags |= ImGuiSeparatorFlags_SpanAllColumns; // NB: this only applies to legacy Columns() api as they relied on Separator() a lot.
|
||||
SeparatorEx(flags);
|
||||
SeparatorEx(flags, 1.0f);
|
||||
}
|
||||
|
||||
void ImGui::SeparatorTextEx(ImGuiID id, const char* label, const char* label_end, float extra_w)
|
||||
@@ -1538,8 +1532,8 @@ void ImGui::SeparatorText(const char* label)
|
||||
return;
|
||||
|
||||
// The SeparatorText() vs SeparatorTextEx() distinction is designed to be considerate that we may want:
|
||||
// - allow headers to be draggable items (would require a stable ID + a noticeable highlight)
|
||||
// - this high-level entry point to allow formatting? (may require ID separate from formatted string)
|
||||
// - allow separator-text to be draggable items (would require a stable ID + a noticeable highlight)
|
||||
// - this high-level entry point to allow formatting? (which in turns may require ID separate from formatted string)
|
||||
// - because of this we probably can't turn 'const char* label' into 'const char* fmt, ...'
|
||||
// Otherwise, we can decide that users wanting to drag this would layout a dedicated drag-item,
|
||||
// and then we can turn this into a format function.
|
||||
@@ -1555,14 +1549,20 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
|
||||
if (!ItemAdd(bb, id, NULL, ImGuiItemFlags_NoNav))
|
||||
return false;
|
||||
|
||||
// FIXME: AFAIK the only leftover reason for passing ImGuiButtonFlags_AllowOverlap here is
|
||||
// to allow caller of SplitterBehavior() to call SetItemAllowOverlap() after the item.
|
||||
// Nowadays we would instead want to use SetNextItemAllowOverlap() before the item.
|
||||
ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren;
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
button_flags |= ImGuiButtonFlags_AllowOverlap;
|
||||
#endif
|
||||
|
||||
bool hovered, held;
|
||||
ImRect bb_interact = bb;
|
||||
bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
|
||||
ButtonBehavior(bb_interact, id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
|
||||
ButtonBehavior(bb_interact, id, &hovered, &held, button_flags);
|
||||
if (hovered)
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect; // for IsItemHovered(), because bb_interact is larger than bb
|
||||
if (g.ActiveId != id)
|
||||
SetItemAllowOverlap();
|
||||
|
||||
if (held || (hovered && g.HoveredIdPreviousFrame == id && g.HoveredIdTimer >= hover_visibility_delay))
|
||||
SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW);
|
||||
@@ -1831,7 +1831,7 @@ bool ImGui::BeginComboPreview()
|
||||
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.Contains(preview_data->PreviewRect)) // Narrower test (optional)
|
||||
if (!window->ClipRect.Overlaps(preview_data->PreviewRect)) // Narrower test (optional)
|
||||
return false;
|
||||
|
||||
// FIXME: This could be contained in a PushWorkRect() api
|
||||
@@ -1930,7 +1930,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
|
||||
const char* item_text;
|
||||
if (!items_getter(data, i, &item_text))
|
||||
item_text = "*Unknown item*";
|
||||
if (Selectable(item_text, item_selected))
|
||||
if (Selectable(item_text, item_selected) && *current_item != i)
|
||||
{
|
||||
value_changed = true;
|
||||
*current_item = i;
|
||||
@@ -2096,7 +2096,8 @@ bool ImGui::DataTypeApplyFromText(const char* buf, ImGuiDataType data_type, void
|
||||
memcpy(&data_backup, p_data, type_info->Size);
|
||||
|
||||
// Sanitize format
|
||||
// For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
|
||||
// - For float/double we have to ignore format with precision (e.g. "%.2f") because sscanf doesn't take them in, so force them into %f and %lf
|
||||
// - In theory could treat empty format as using default, but this would only cover rare/bizarre case of using InputScalar() + integer + format string without %.
|
||||
char format_sanitized[32];
|
||||
if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
|
||||
format = type_info->ScanFmt;
|
||||
@@ -2416,7 +2417,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
@@ -2779,14 +2780,14 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
||||
const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
|
||||
const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
|
||||
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
|
||||
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;
|
||||
float grab_sz = style.GrabMinSize;
|
||||
if (!is_floating_point && v_range >= 0) // v_range < 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
|
||||
if (!is_floating_point && v_range_f >= 0.0f) // v_range_f < 0 may happen on integer overflows
|
||||
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);
|
||||
const float slider_usable_sz = slider_sz - grab_sz;
|
||||
const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;
|
||||
@@ -2855,8 +2856,8 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((v_range >= -100.0f && v_range <= 100.0f) || tweak_slow)
|
||||
input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / (float)v_range; // Gamepad/keyboard tweak speeds in integer steps
|
||||
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) / v_range_f; // Gamepad/keyboard tweak speeds in integer steps
|
||||
else
|
||||
input_delta /= 100.0f;
|
||||
}
|
||||
@@ -2903,6 +2904,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)
|
||||
{
|
||||
TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
|
||||
@@ -2948,11 +2953,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.
|
||||
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)
|
||||
{
|
||||
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; }
|
||||
@@ -3009,7 +3009,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
if (!temp_input_is_active)
|
||||
{
|
||||
@@ -3176,7 +3176,7 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
|
||||
const bool clicked = hovered && IsMouseClicked(0, id);
|
||||
if (clicked || g.NavActivateId == id)
|
||||
{
|
||||
@@ -3279,7 +3279,7 @@ const char* ImParseFormatFindEnd(const char* fmt)
|
||||
}
|
||||
|
||||
// Extract the format out of a format string with leading or trailing decorations
|
||||
// fmt = "blah blah" -> return fmt
|
||||
// fmt = "blah blah" -> return ""
|
||||
// fmt = "%.3f" -> return fmt
|
||||
// fmt = "hello %.3f" -> return fmt + 6
|
||||
// fmt = "%.3f hello" -> return buf written with "%.3f"
|
||||
@@ -3287,7 +3287,7 @@ const char* ImParseFormatTrimDecorations(const char* fmt, char* buf, size_t buf_
|
||||
{
|
||||
const char* fmt_start = ImParseFormatFindStart(fmt);
|
||||
if (fmt_start[0] != '%')
|
||||
return fmt;
|
||||
return "";
|
||||
const char* fmt_end = ImParseFormatFindEnd(fmt_start);
|
||||
if (fmt_end[0] == 0) // If we only have leading decoration, we don't need to copy the data.
|
||||
return fmt_start;
|
||||
@@ -3405,9 +3405,14 @@ static inline ImGuiInputTextFlags InputScalar_DefaultCharsFilter(ImGuiDataType d
|
||||
// However this may not be ideal for all uses, as some user code may break on out of bound values.
|
||||
bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImGuiDataType data_type, void* p_data, const char* format, const void* p_clamp_min, const void* p_clamp_max)
|
||||
{
|
||||
// FIXME: May need to clarify display behavior if format doesn't contain %.
|
||||
// "%d" -> "%d" / "There are %d items" -> "%d" / "items" -> "%d" (fallback). Also see #6405
|
||||
const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);
|
||||
char fmt_buf[32];
|
||||
char data_buf[32];
|
||||
format = ImParseFormatTrimDecorations(format, fmt_buf, IM_ARRAYSIZE(fmt_buf));
|
||||
if (format[0] == 0)
|
||||
format = type_info->PrintFmt;
|
||||
DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format);
|
||||
ImStrTrimBlanks(data_buf);
|
||||
|
||||
@@ -3418,7 +3423,7 @@ bool ImGui::TempInputScalar(const ImRect& bb, ImGuiID id, const char* label, ImG
|
||||
if (TempInputText(bb, id, label, data_buf, IM_ARRAYSIZE(data_buf), flags))
|
||||
{
|
||||
// Backup old value
|
||||
size_t data_type_size = DataTypeGetInfo(data_type)->Size;
|
||||
size_t data_type_size = type_info->Size;
|
||||
ImGuiDataTypeTempStorage data_backup;
|
||||
memcpy(&data_backup, p_data, data_type_size);
|
||||
|
||||
@@ -3814,6 +3819,7 @@ static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj, int pos, const Im
|
||||
#define STB_TEXTEDIT_K_SHIFT 0x400000
|
||||
|
||||
#define STB_TEXTEDIT_IMPLEMENTATION
|
||||
#define STB_TEXTEDIT_memmove memmove
|
||||
#include "imstb_textedit.h"
|
||||
|
||||
// stb_textedit internally allows for a single undo record to do addition and deletion, but somehow, calling
|
||||
@@ -3871,6 +3877,10 @@ void ImGuiInputTextCallbackData::DeleteChars(int pos, int bytes_count)
|
||||
|
||||
void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, const char* new_text_end)
|
||||
{
|
||||
// Accept null ranges
|
||||
if (new_text == new_text_end)
|
||||
return;
|
||||
|
||||
const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
|
||||
const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
|
||||
if (new_text_len + BufTextLen >= BufSize)
|
||||
@@ -3902,7 +3912,7 @@ void ImGuiInputTextCallbackData::InsertChars(int pos, const char* new_text, cons
|
||||
}
|
||||
|
||||
// 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);
|
||||
unsigned int c = *p_char;
|
||||
@@ -3941,10 +3951,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 '.'.
|
||||
// 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:
|
||||
// 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.
|
||||
ImGuiContext& g = *GImGui;
|
||||
const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint;
|
||||
ImGuiContext& g = *ctx;
|
||||
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)
|
||||
// While this is mostly convenient, this has the side-effect for uninformed users accidentally inputting full-width characters that they may
|
||||
@@ -4046,8 +4059,16 @@ void ImGui::InputTextDeactivateHook(ImGuiID id)
|
||||
if (id == 0 || state->ID != id)
|
||||
return;
|
||||
g.InputTextDeactivatedState.ID = state->ID;
|
||||
g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1);
|
||||
memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data ? state->TextA.Data : "", state->CurLenA + 1);
|
||||
if (state->Flags & ImGuiInputTextFlags_ReadOnly)
|
||||
{
|
||||
g.InputTextDeactivatedState.TextA.resize(0); // In theory this data won't be used, but clear to be neat.
|
||||
}
|
||||
else
|
||||
{
|
||||
IM_ASSERT(state->TextA.Data != 0);
|
||||
g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1);
|
||||
memcpy(g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Edit a string of text
|
||||
@@ -4137,7 +4158,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
return false;
|
||||
item_status_flags = g.LastItemData.StatusFlags;
|
||||
}
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
|
||||
if (hovered)
|
||||
g.MouseCursor = ImGuiMouseCursor_TextInput;
|
||||
|
||||
@@ -4302,7 +4323,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
// Although we are active we don't prevent mouse from hovering other elements unless we are interacting right now with the widget.
|
||||
// Down the line we should have a cleaner library-wide concept of Selected vs Active.
|
||||
g.ActiveIdAllowOverlap = !io.MouseDown[0];
|
||||
g.WantTextInputNextFrame = 1;
|
||||
|
||||
// Edit in progress
|
||||
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
|
||||
@@ -4373,7 +4393,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if ((flags & ImGuiInputTextFlags_AllowTabInput) && Shortcut(ImGuiKey_Tab, id) && !is_readonly)
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -4389,7 +4409,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
unsigned int c = (unsigned int)io.InputQueueCharacters[n];
|
||||
if (c == '\t') // Skip Tab, see above.
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -4472,7 +4492,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
else if (!is_readonly)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -4480,7 +4500,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
{
|
||||
if (flags & ImGuiInputTextFlags_EscapeClearsAll)
|
||||
{
|
||||
if (state->CurLenA > 0)
|
||||
if (buf[0] != 0)
|
||||
{
|
||||
revert_edit = true;
|
||||
}
|
||||
@@ -4539,7 +4559,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
{
|
||||
unsigned int c;
|
||||
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;
|
||||
clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
|
||||
}
|
||||
@@ -4568,8 +4588,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (flags & ImGuiInputTextFlags_EscapeClearsAll)
|
||||
{
|
||||
// Clear input
|
||||
IM_ASSERT(buf[0] != 0);
|
||||
apply_new_text = "";
|
||||
apply_new_text_length = 0;
|
||||
value_changed = true;
|
||||
STB_TEXTEDIT_CHARTYPE empty_string;
|
||||
stb_textedit_replace(state, &state->Stb, &empty_string, 0);
|
||||
}
|
||||
@@ -4598,9 +4620,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL);
|
||||
}
|
||||
|
||||
// When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.
|
||||
// When using 'ImGuiInputTextFlags_EnterReturnsTrue' as a special case we reapply the live buffer back to the input buffer
|
||||
// before clearing ActiveId, even though strictly speaking it wasn't modified on this frame.
|
||||
// If we didn't do that, code like InputInt() with ImGuiInputTextFlags_EnterReturnsTrue would fail.
|
||||
// This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize).
|
||||
// This also allows the user to use InputText() with ImGuiInputTextFlags_EnterReturnsTrue without maintaining any user-side storage
|
||||
// (please note that if you use this property along ImGuiInputTextFlags_CallbackResize you can end up with your temporary string object
|
||||
// unnecessarily allocating once a frame, either store your string data, either if you don't then don't use ImGuiInputTextFlags_CallbackResize).
|
||||
const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
|
||||
if (apply_edit_back_to_user_buffer)
|
||||
{
|
||||
@@ -4701,11 +4726,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
// Handle reapplying final data on deactivation (see InputTextDeactivateHook() for details)
|
||||
if (g.InputTextDeactivatedState.ID == id)
|
||||
{
|
||||
if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly)
|
||||
if (g.ActiveId != id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0)
|
||||
{
|
||||
apply_new_text = g.InputTextDeactivatedState.TextA.Data;
|
||||
apply_new_text_length = g.InputTextDeactivatedState.TextA.Size - 1;
|
||||
value_changed |= (strcmp(g.InputTextDeactivatedState.TextA.Data, buf) != 0);
|
||||
value_changed = true;
|
||||
//IMGUI_DEBUG_LOG("InputText(): apply Deactivated data for 0x%08X: \"%.*s\".\n", id, apply_new_text_length, apply_new_text);
|
||||
}
|
||||
g.InputTextDeactivatedState.ID = 0;
|
||||
@@ -4741,8 +4766,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
|
||||
// Release active ID at the end of the function (so e.g. pressing Return still does a final application of the value)
|
||||
if (clear_active_id && g.ActiveId == id)
|
||||
// Otherwise request text input ahead for next frame.
|
||||
if (g.ActiveId == id && clear_active_id)
|
||||
ClearActiveID();
|
||||
else if (g.ActiveId == id)
|
||||
g.WantTextInputNextFrame = 1;
|
||||
|
||||
// Render frame
|
||||
if (!is_multiline)
|
||||
@@ -4958,11 +4986,9 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
{
|
||||
// For focus requests to work on our multiline we need to ensure our child ItemAdd() call specifies the ImGuiItemFlags_Inputable (ref issue #4761)...
|
||||
Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y));
|
||||
ImGuiItemFlags backup_item_flags = g.CurrentItemFlags;
|
||||
g.CurrentItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;
|
||||
g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;
|
||||
EndChild();
|
||||
item_data_backup.StatusFlags |= (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow);
|
||||
g.CurrentItemFlags = backup_item_flags;
|
||||
|
||||
// ...and then we need to undo the group overriding last item data, which gets a bit messy as EndGroup() tries to forward scrollbar being active...
|
||||
// FIXME: This quite messy/tricky, should attempt to get rid of the child window.
|
||||
@@ -5796,7 +5822,7 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
|
||||
}
|
||||
|
||||
// Tooltip
|
||||
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
|
||||
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip))
|
||||
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
|
||||
|
||||
return pressed;
|
||||
@@ -5826,7 +5852,7 @@ void ImGui::ColorTooltip(const char* text, const float* col, ImGuiColorEditFlags
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
|
||||
if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePreviousTooltip, ImGuiWindowFlags_None))
|
||||
if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
|
||||
return;
|
||||
const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
|
||||
if (text_end > text)
|
||||
@@ -5864,6 +5890,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)
|
||||
if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup("context"))
|
||||
return;
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.LockMarkEdited++;
|
||||
ImGuiColorEditFlags opts = g.ColorEditOptions;
|
||||
if (allow_opt_inputs)
|
||||
{
|
||||
@@ -5906,6 +5933,7 @@ void ImGui::ColorEditOptionsPopup(const float* col, ImGuiColorEditFlags flags)
|
||||
|
||||
g.ColorEditOptions = opts;
|
||||
EndPopup();
|
||||
g.LockMarkEdited--;
|
||||
}
|
||||
|
||||
void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags)
|
||||
@@ -5915,6 +5943,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
|
||||
if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup("context"))
|
||||
return;
|
||||
ImGuiContext& g = *GImGui;
|
||||
g.LockMarkEdited++;
|
||||
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
|
||||
@@ -5944,6 +5973,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
|
||||
CheckboxFlags("Alpha Bar", &g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
|
||||
}
|
||||
EndPopup();
|
||||
g.LockMarkEdited--;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -6140,18 +6170,29 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)
|
||||
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.
|
||||
// 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;
|
||||
// Compute open and multi-select states before ItemAdd() as it clear NextItem data.
|
||||
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);
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
|
||||
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 (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
|
||||
@@ -6161,8 +6202,8 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
}
|
||||
|
||||
ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;
|
||||
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
|
||||
button_flags |= ImGuiButtonFlags_AllowItemOverlap;
|
||||
if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap))
|
||||
button_flags |= ImGuiButtonFlags_AllowOverlap;
|
||||
if (!is_leaf)
|
||||
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
|
||||
|
||||
@@ -6218,11 +6259,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Left && is_open)
|
||||
{
|
||||
toggled = true;
|
||||
NavClearPreferredPosForAxis(ImGuiAxis_X);
|
||||
NavMoveRequestCancel();
|
||||
}
|
||||
if (g.NavId == id && g.NavMoveDir == ImGuiDir_Right && !is_open) // If there's something upcoming on the line we may want to give it the priority?
|
||||
{
|
||||
toggled = true;
|
||||
NavClearPreferredPosForAxis(ImGuiAxis_X);
|
||||
NavMoveRequestCancel();
|
||||
}
|
||||
|
||||
@@ -6233,8 +6276,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
|
||||
}
|
||||
}
|
||||
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
|
||||
SetItemAllowOverlap();
|
||||
|
||||
// In this branch, TreeNodeBehavior() cannot toggle the selection so this will never trigger.
|
||||
if (selected != was_selected) //-V547
|
||||
@@ -6252,9 +6293,9 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
if (flags & ImGuiTreeNodeFlags_Bullet)
|
||||
RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col);
|
||||
else if (!is_leaf)
|
||||
RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
|
||||
RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 1.0f);
|
||||
else // Leaf without bullet, left-adjusted text
|
||||
text_pos.x -= text_offset_x;
|
||||
text_pos.x -= text_offset_x -padding.x;
|
||||
if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)
|
||||
frame_bb.Max.x -= g.FontSize + style.FramePadding.x;
|
||||
|
||||
@@ -6274,7 +6315,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
if (flags & ImGuiTreeNodeFlags_Bullet)
|
||||
RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col);
|
||||
else if (!is_leaf)
|
||||
RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
|
||||
RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ((flags & ImGuiTreeNodeFlags_UpsideDownArrow) ? ImGuiDir_Up : ImGuiDir_Down) : ImGuiDir_Right, 0.70f);
|
||||
if (g.LogEnabled)
|
||||
LogSetNextTextDecoration(">", NULL);
|
||||
RenderText(text_pos, label, label_end, false);
|
||||
@@ -6321,12 +6362,14 @@ void ImGui::TreePop()
|
||||
ImU32 tree_depth_mask = (1 << window->DC.TreeDepth);
|
||||
|
||||
// Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)
|
||||
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
|
||||
if (g.NavIdIsAlive && (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask))
|
||||
{
|
||||
SetNavID(window->IDStack.back(), g.NavLayer, 0, ImRect());
|
||||
NavMoveRequestCancel();
|
||||
}
|
||||
if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask) // Only set during request
|
||||
{
|
||||
ImGuiNavTreeNodeData* nav_tree_node_data = &g.NavTreeNodeStack.back();
|
||||
IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());
|
||||
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;
|
||||
|
||||
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.
|
||||
@@ -6378,7 +6421,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
|
||||
ImGuiID id = window->GetID(label);
|
||||
flags |= ImGuiTreeNodeFlags_CollapsingHeader;
|
||||
if (p_visible)
|
||||
flags |= ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton;
|
||||
flags |= ImGuiTreeNodeFlags_AllowOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton;
|
||||
bool is_open = TreeNodeBehavior(id, flags, label);
|
||||
if (p_visible != NULL)
|
||||
{
|
||||
@@ -6388,8 +6431,8 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiLastItemData last_item_backup = g.LastItemData;
|
||||
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_y = g.LastItemData.Rect.Min.y;
|
||||
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 + g.Style.FramePadding.y;
|
||||
ImGuiID close_button_id = GetIDWithSeed("#CLOSE", NULL, id);
|
||||
if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
|
||||
*p_visible = false;
|
||||
@@ -6407,7 +6450,7 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFl
|
||||
|
||||
// Tip: pass a non-visible label (e.g. "##hello") then you can use the space to draw other text or image.
|
||||
// But you need to make sure the ID is unique, e.g. enclose calls in PushID/PopID or use ##unique_id.
|
||||
// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowItemOverlap are also frequently used flags.
|
||||
// With this scheme, ImGuiSelectableFlags_SpanAllColumns and ImGuiSelectableFlags_AllowOverlap are also frequently used flags.
|
||||
// FIXME: Selectable() with (size.x == 0.0f) and (SelectableTextAlign.x > 0.0f) followed by SameLine() is currently not supported.
|
||||
bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags flags, const ImVec2& size_arg)
|
||||
{
|
||||
@@ -6491,7 +6534,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }
|
||||
if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
|
||||
if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }
|
||||
if (flags & ImGuiSelectableFlags_AllowItemOverlap) { button_flags |= ImGuiButtonFlags_AllowItemOverlap; }
|
||||
if ((flags & ImGuiSelectableFlags_AllowOverlap) || (g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
|
||||
|
||||
const bool was_selected = selected;
|
||||
bool hovered, held;
|
||||
@@ -6520,9 +6563,6 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
if (pressed)
|
||||
MarkItemEdited(id);
|
||||
|
||||
if (flags & ImGuiSelectableFlags_AllowItemOverlap)
|
||||
SetItemAllowOverlap();
|
||||
|
||||
// In this branch, Selectable() cannot toggle the selection so this will never trigger.
|
||||
if (selected != was_selected) //-V547
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
|
||||
@@ -6533,7 +6573,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
|
||||
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
|
||||
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)
|
||||
PopColumnsBackground();
|
||||
@@ -6612,20 +6653,6 @@ bool ImGui::BeginListBox(const char* label, const ImVec2& size_arg)
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// OBSOLETED in 1.81 (from February 2021)
|
||||
bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_items)
|
||||
{
|
||||
// If height_in_items == -1, default height is maximum 7.
|
||||
ImGuiContext& g = *GImGui;
|
||||
float height_in_items_f = (height_in_items < 0 ? ImMin(items_count, 7) : height_in_items) + 0.25f;
|
||||
ImVec2 size;
|
||||
size.x = 0.0f;
|
||||
size.y = GetTextLineHeightWithSpacing() * height_in_items_f + g.Style.FramePadding.y * 2.0f;
|
||||
return BeginListBox(label, size);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ImGui::EndListBox()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -6721,7 +6748,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
|
||||
ItemSize(total_bb, style.FramePadding.y);
|
||||
if (!ItemAdd(total_bb, 0, &frame_bb))
|
||||
return -1;
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
const bool hovered = ItemHoverable(frame_bb, id, g.LastItemData.InFlags);
|
||||
|
||||
// Determine scale from values if not specified
|
||||
if (scale_min == FLT_MAX || scale_max == FLT_MAX)
|
||||
@@ -7093,7 +7120,7 @@ void ImGui::EndMainMenuBar()
|
||||
// FIXME: With this strategy we won't be able to restore a NULL focus.
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.CurrentWindow == g.NavWindow && g.NavLayer == ImGuiNavLayer_Main && !g.NavAnyRequest)
|
||||
FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL);
|
||||
FocusTopMostWindowUnderOne(g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild);
|
||||
|
||||
End();
|
||||
}
|
||||
@@ -7107,9 +7134,9 @@ static bool IsRootOfOpenMenuSet()
|
||||
|
||||
// Initially we used 'upper_popup->OpenParentId == window->IDStack.back()' to differentiate multiple menu sets from each others
|
||||
// (e.g. inside menu bar vs loose menu items) based on parent ID.
|
||||
// This would however prevent the use of e.g. PuhsID() user code submitting menus.
|
||||
// This would however prevent the use of e.g. PushID() user code submitting menus.
|
||||
// Previously this worked between popup and a first child menu because the first child menu always had the _ChildWindow flag,
|
||||
// making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.
|
||||
// making hovering on parent popup possible while first child menu was focused - but this was generally a bug with other side effects.
|
||||
// Instead we don't treat Popup specifically (in order to consistently support menu features in them), maybe the first child menu of a Popup
|
||||
// doesn't have the _ChildWindow flag, and we rely on this IsRootOfOpenMenuSet() check to allow hovering between root window/popup and first child menu.
|
||||
// In the end, lack of ID check made it so we could no longer differentiate between separate menu sets. To compensate for that, we at least check parent window nav layer.
|
||||
@@ -7117,7 +7144,9 @@ static bool IsRootOfOpenMenuSet()
|
||||
// open on hover, but that should be a lesser problem, because if such menus are close in proximity in window content then it won't feel weird and if they are far apart
|
||||
// it likely won't be a problem anyone runs into.
|
||||
const ImGuiPopupData* upper_popup = &g.OpenPopupStack[g.BeginPopupStack.Size];
|
||||
return (window->DC.NavLayerCurrent == upper_popup->ParentNavLayer && upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu));
|
||||
if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)
|
||||
return false;
|
||||
return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window, true, false);
|
||||
}
|
||||
|
||||
bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
@@ -8461,7 +8490,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
}
|
||||
|
||||
// Click to Select a tab
|
||||
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowItemOverlap);
|
||||
ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
|
||||
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW)) // FIXME: May be an opt-in property of the payload to disable this
|
||||
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
|
||||
bool hovered, held;
|
||||
@@ -8474,10 +8503,6 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
if (held && docked_window && g.ActiveId == id && g.ActiveIdIsJustActivated)
|
||||
g.ActiveIdWindow = docked_window;
|
||||
|
||||
// Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered)
|
||||
if (g.ActiveId != id)
|
||||
SetItemAllowOverlap();
|
||||
|
||||
// Drag and drop a single floating window node moves it
|
||||
ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL;
|
||||
const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1);
|
||||
@@ -8594,8 +8619,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
// FIXME: We may want disabled tab to still display the tooltip?
|
||||
if (text_clipped && g.HoveredId == id && !held)
|
||||
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
|
||||
if (IsItemHovered(ImGuiHoveredFlags_DelayNormal))
|
||||
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
SetItemTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
|
||||
IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button)); // TabItemButton should not be selected
|
||||
if (is_tab_button)
|
||||
@@ -8706,7 +8730,7 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
}
|
||||
|
||||
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
|
||||
// We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap()
|
||||
@@ -8724,10 +8748,8 @@ void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
|
||||
if (close_button_visible)
|
||||
{
|
||||
ImGuiLastItemData last_item_backup = g.LastItemData;
|
||||
PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
|
||||
if (CloseButton(close_button_id, button_pos))
|
||||
close_button_pressed = true;
|
||||
PopStyleVar();
|
||||
g.LastItemData = last_item_backup;
|
||||
|
||||
// Close with middle mouse button
|
||||
|
||||
Reference in New Issue
Block a user