mirror of
https://github.com/wolfpld/tracy.git
synced 2025-03-20 07:40:02 +08:00
Update imgui to f87e891f.
This commit is contained in:
+217
-205
@@ -1,4 +1,4 @@
|
||||
// dear imgui, v1.88
|
||||
// dear imgui, v1.89 WIP
|
||||
// (widgets code)
|
||||
|
||||
/*
|
||||
@@ -611,7 +611,15 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
|
||||
if (g.NavActivateDownId == id)
|
||||
{
|
||||
bool nav_activated_by_code = (g.NavActivateId == id);
|
||||
bool nav_activated_by_inputs = IsNavInputTest(ImGuiNavInput_Activate, (flags & ImGuiButtonFlags_Repeat) ? ImGuiNavReadMode_Repeat : ImGuiNavReadMode_Pressed);
|
||||
bool nav_activated_by_inputs = (g.NavActivatePressedId == id);
|
||||
if (!nav_activated_by_inputs && (flags & ImGuiButtonFlags_Repeat))
|
||||
{
|
||||
// Avoid pressing both keys from triggering double amount of repeat events
|
||||
const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space);
|
||||
const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_NavGamepadActivate);
|
||||
const float t1 = ImMax(key1->DownDuration, key2->DownDuration);
|
||||
nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 - g.IO.DeltaTime, t1, g.IO.KeyRepeatDelay, g.IO.KeyRepeatRate) > 0;
|
||||
}
|
||||
if (nav_activated_by_code || nav_activated_by_inputs)
|
||||
{
|
||||
// Set active id so it can be queried by user via IsItemActive(), equivalent of holding the mouse button.
|
||||
@@ -1036,14 +1044,15 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2&
|
||||
|
||||
// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390)
|
||||
// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API.
|
||||
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec2& padding, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = GetCurrentWindow();
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2);
|
||||
const ImVec2 padding = g.Style.FramePadding;
|
||||
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size + padding * 2.0f);
|
||||
ItemSize(bb);
|
||||
if (!ItemAdd(bb, id))
|
||||
return false;
|
||||
@@ -1062,9 +1071,21 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size
|
||||
return pressed;
|
||||
}
|
||||
|
||||
// frame_padding < 0: uses FramePadding from style (default)
|
||||
// frame_padding = 0: no framing
|
||||
// frame_padding > 0: set framing size
|
||||
bool ImGui::ImageButton(const char* str_id, ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
return ImageButtonEx(window->GetID(str_id), user_texture_id, size, uv0, uv1, bg_col, tint_col);
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
// Legacy API obsoleted in 1.89. Two differences with new ImageButton()
|
||||
// - new ImageButton() requires an explicit 'const char* str_id' Old ImageButton() used opaque imTextureId (created issue with: multiple buttons with same image, transient texture id values, opaque computation of ID)
|
||||
// - new ImageButton() always use style.FramePadding Old ImageButton() had an override argument.
|
||||
// If you need to change padding with new ImageButton() you can use PushStyleVar(ImGuiStyleVar_FramePadding, value), consistent with other Button functions.
|
||||
bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, int frame_padding, const ImVec4& bg_col, const ImVec4& tint_col)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
@@ -1077,9 +1098,14 @@ bool ImGui::ImageButton(ImTextureID user_texture_id, const ImVec2& size, const I
|
||||
const ImGuiID id = window->GetID("#image");
|
||||
PopID();
|
||||
|
||||
const ImVec2 padding = (frame_padding >= 0) ? ImVec2((float)frame_padding, (float)frame_padding) : g.Style.FramePadding;
|
||||
return ImageButtonEx(id, user_texture_id, size, uv0, uv1, padding, bg_col, tint_col);
|
||||
if (frame_padding >= 0)
|
||||
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((float)frame_padding, (float)frame_padding));
|
||||
bool ret = ImageButtonEx(id, user_texture_id, size, uv0, uv1, bg_col, tint_col);
|
||||
if (frame_padding >= 0)
|
||||
PopStyleVar();
|
||||
return ret;
|
||||
}
|
||||
#endif // #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
bool ImGui::Checkbox(const char* label, bool* v)
|
||||
{
|
||||
@@ -1558,12 +1584,12 @@ void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_exc
|
||||
items[n].Width = width_rounded;
|
||||
}
|
||||
while (width_excess > 0.0f)
|
||||
for (int n = 0; n < count; n++)
|
||||
if (items[n].Width + 1.0f <= items[n].InitialWidth)
|
||||
{
|
||||
items[n].Width += 1.0f;
|
||||
width_excess -= 1.0f;
|
||||
}
|
||||
for (int n = 0; n < count && width_excess > 0.0f; n++)
|
||||
{
|
||||
float width_to_add = ImMin(items[n].InitialWidth - items[n].Width, 1.0f);
|
||||
items[n].Width += width_to_add;
|
||||
width_excess -= width_to_add;
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -1877,11 +1903,11 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Data Type and Data Formatting Helpers [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
// - PatchFormatStringFloatToInt()
|
||||
// - DataTypeGetInfo()
|
||||
// - DataTypeFormatString()
|
||||
// - DataTypeApplyOp()
|
||||
// - DataTypeApplyOpFromText()
|
||||
// - DataTypeCompare()
|
||||
// - DataTypeClamp()
|
||||
// - GetMinimumStepAtDecimalPrecision
|
||||
// - RoundScalarWithFormat<>()
|
||||
@@ -1907,30 +1933,6 @@ static const ImGuiDataTypeInfo GDataTypeInfo[] =
|
||||
};
|
||||
IM_STATIC_ASSERT(IM_ARRAYSIZE(GDataTypeInfo) == ImGuiDataType_COUNT);
|
||||
|
||||
// FIXME-LEGACY: Prior to 1.61 our DragInt() function internally used floats and because of this the compile-time default value for format was "%.0f".
|
||||
// Even though we changed the compile-time default, we expect users to have carried %f around, which would break the display of DragInt() calls.
|
||||
// To honor backward compatibility we are rewriting the format string, unless IMGUI_DISABLE_OBSOLETE_FUNCTIONS is enabled. What could possibly go wrong?!
|
||||
static const char* PatchFormatStringFloatToInt(const char* fmt)
|
||||
{
|
||||
if (fmt[0] == '%' && fmt[1] == '.' && fmt[2] == '0' && fmt[3] == 'f' && fmt[4] == 0) // Fast legacy path for "%.0f" which is expected to be the most common case.
|
||||
return "%d";
|
||||
const char* fmt_start = ImParseFormatFindStart(fmt); // Find % (if any, and ignore %%)
|
||||
const char* fmt_end = ImParseFormatFindEnd(fmt_start); // Find end of format specifier, which itself is an exercise of confidence/recklessness (because snprintf is dependent on libc or user).
|
||||
if (fmt_end > fmt_start && fmt_end[-1] == 'f')
|
||||
{
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
if (fmt_start == fmt && fmt_end[0] == 0)
|
||||
return "%d";
|
||||
const char* tmp_format;
|
||||
ImFormatStringToTempBuffer(&tmp_format, NULL, "%.*s%%d%s", (int)(fmt_start - fmt), fmt, fmt_end); // Honor leading and trailing decorations, but lose alignment/precision.
|
||||
return tmp_format;
|
||||
#else
|
||||
IM_ASSERT(0 && "DragInt(): Invalid format string!"); // Old versions used a default parameter of "%.0f", please replace with e.g. "%d"
|
||||
#endif
|
||||
}
|
||||
return fmt;
|
||||
}
|
||||
|
||||
const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type)
|
||||
{
|
||||
IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
|
||||
@@ -2189,7 +2191,10 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav)
|
||||
{
|
||||
const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0;
|
||||
adjust_delta = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiNavReadMode_RepeatFast, 1.0f / 10.0f, 10.0f)[axis];
|
||||
const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);
|
||||
const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);
|
||||
const float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f;
|
||||
adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor;
|
||||
v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));
|
||||
}
|
||||
adjust_delta *= v_speed;
|
||||
@@ -2287,6 +2292,7 @@ bool ImGui::DragBehavior(ImGuiID id, ImGuiDataType data_type, void* p_v, float v
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.ActiveId == id)
|
||||
{
|
||||
// Those are the things we can do easily outside the DragBehaviorT<> template, saves code generation.
|
||||
if (g.ActiveIdSource == ImGuiInputSource_Mouse && !g.IO.MouseDown[0])
|
||||
ClearActiveID();
|
||||
else if (g.ActiveIdSource == ImGuiInputSource_Nav && g.NavActivatePressedId == id && !g.ActiveIdIsJustActivated)
|
||||
@@ -2340,8 +2346,6 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data,
|
||||
// Default format string when passing NULL
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.)
|
||||
format = PatchFormatStringFloatToInt(format);
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
@@ -2547,35 +2551,6 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details.
|
||||
bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* p_data, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
|
||||
{
|
||||
ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None;
|
||||
if (power != 1.0f)
|
||||
{
|
||||
IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
|
||||
IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
|
||||
drag_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
|
||||
}
|
||||
return DragScalar(label, data_type, p_data, v_speed, p_min, p_max, format, drag_flags);
|
||||
}
|
||||
|
||||
bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* p_data, int components, float v_speed, const void* p_min, const void* p_max, const char* format, float power)
|
||||
{
|
||||
ImGuiSliderFlags drag_flags = ImGuiSliderFlags_None;
|
||||
if (power != 1.0f)
|
||||
{
|
||||
IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
|
||||
IM_ASSERT(p_min != NULL && p_max != NULL); // When using a power curve the drag needs to have known bounds
|
||||
drag_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
|
||||
}
|
||||
return DragScalarN(label, data_type, p_data, components, v_speed, p_min, p_max, format, drag_flags);
|
||||
}
|
||||
|
||||
#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: SliderScalar, SliderFloat, SliderInt, etc.
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -2795,25 +2770,26 @@ bool ImGui::SliderBehaviorT(const ImRect& bb, ImGuiID id, ImGuiDataType data_typ
|
||||
g.SliderCurrentAccumDirty = false;
|
||||
}
|
||||
|
||||
const ImVec2 input_delta2 = GetNavInputAmount2d(ImGuiNavDirSourceFlags_Keyboard | ImGuiNavDirSourceFlags_PadDPad, ImGuiNavReadMode_RepeatFast, 0.0f, 0.0f);
|
||||
float input_delta = (axis == ImGuiAxis_X) ? input_delta2.x : -input_delta2.y;
|
||||
float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis);
|
||||
if (input_delta != 0.0f)
|
||||
{
|
||||
const bool tweak_slow = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);
|
||||
const bool tweak_fast = IsKeyDown((g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);
|
||||
const int decimal_precision = is_floating_point ? ImParseFormatPrecision(format, 3) : 0;
|
||||
if (decimal_precision > 0)
|
||||
{
|
||||
input_delta /= 100.0f; // Gamepad/keyboard tweak speeds in % of slider bounds
|
||||
if (IsNavInputDown(ImGuiNavInput_TweakSlow))
|
||||
if (tweak_slow)
|
||||
input_delta /= 10.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((v_range >= -100.0f && v_range <= 100.0f) || IsNavInputDown(ImGuiNavInput_TweakSlow))
|
||||
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
|
||||
else
|
||||
input_delta /= 100.0f;
|
||||
}
|
||||
if (IsNavInputDown(ImGuiNavInput_TweakFast))
|
||||
if (tweak_fast)
|
||||
input_delta *= 10.0f;
|
||||
|
||||
g.SliderCurrentAccum += input_delta;
|
||||
@@ -2901,6 +2877,7 @@ 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;
|
||||
@@ -2960,8 +2937,6 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_dat
|
||||
// Default format string when passing NULL
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.)
|
||||
format = PatchFormatStringFloatToInt(format);
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
bool temp_input_is_active = temp_input_allowed && TempInputIsActive(id);
|
||||
@@ -3127,8 +3102,6 @@ bool ImGui::VSliderScalar(const char* label, const ImVec2& size, ImGuiDataType d
|
||||
// Default format string when passing NULL
|
||||
if (format == NULL)
|
||||
format = DataTypeGetInfo(data_type)->PrintFmt;
|
||||
else if (data_type == ImGuiDataType_S32 && strcmp(format, "%d") != 0) // (FIXME-LEGACY: Patch old "%.0f" format string to use "%d", read function more details.)
|
||||
format = PatchFormatStringFloatToInt(format);
|
||||
|
||||
const bool hovered = ItemHoverable(frame_bb, id);
|
||||
if ((hovered && g.IO.MouseClicked[0]) || g.NavActivateId == id || g.NavActivateInputId == id)
|
||||
@@ -3175,33 +3148,6 @@ bool ImGui::VSliderInt(const char* label, const ImVec2& size, int* v, int v_min,
|
||||
return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
// Obsolete versions with power parameter. See https://github.com/ocornut/imgui/issues/3361 for details.
|
||||
bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* p_data, const void* p_min, const void* p_max, const char* format, float power)
|
||||
{
|
||||
ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
|
||||
if (power != 1.0f)
|
||||
{
|
||||
IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
|
||||
slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
|
||||
}
|
||||
return SliderScalar(label, data_type, p_data, p_min, p_max, format, slider_flags);
|
||||
}
|
||||
|
||||
bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, int components, const void* v_min, const void* v_max, const char* format, float power)
|
||||
{
|
||||
ImGuiSliderFlags slider_flags = ImGuiSliderFlags_None;
|
||||
if (power != 1.0f)
|
||||
{
|
||||
IM_ASSERT(power == 1.0f && "Call function with ImGuiSliderFlags_Logarithmic flags instead of using the old 'float power' function!");
|
||||
slider_flags |= ImGuiSliderFlags_Logarithmic; // Fallback for non-asserting paths
|
||||
}
|
||||
return SliderScalarN(label, data_type, v, components, v_min, v_max, format, slider_flags);
|
||||
}
|
||||
|
||||
#endif // IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: InputScalar, InputFloat, InputInt, etc.
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -3449,6 +3395,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* p_data
|
||||
SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
|
||||
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
|
||||
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(g.LastItemData.ID, label, g.LastItemData.StatusFlags);
|
||||
|
||||
// Step buttons
|
||||
const ImVec2 backup_frame_padding = style.FramePadding;
|
||||
@@ -3603,7 +3550,7 @@ bool ImGui::InputTextMultiline(const char* label, char* buf, size_t buf_size, co
|
||||
|
||||
bool ImGui::InputTextWithHint(const char* label, const char* hint, char* buf, size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data)
|
||||
{
|
||||
IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline()
|
||||
IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline)); // call InputTextMultiline() or InputTextEx() manually if you need multi-line + hint.
|
||||
return InputTextEx(label, hint, buf, (int)buf_size, ImVec2(0, 0), flags, callback, user_data);
|
||||
}
|
||||
|
||||
@@ -3694,13 +3641,10 @@ static int is_word_boundary_from_right(ImGuiInputTextState* obj, int idx)
|
||||
static int is_word_boundary_from_left(ImGuiInputTextState* obj, int idx) { if (obj->Flags & ImGuiInputTextFlags_Password) return 0; return idx > 0 ? (!is_separator(obj->TextW[idx - 1]) && is_separator(obj->TextW[idx])) : 1; }
|
||||
static int STB_TEXTEDIT_MOVEWORDLEFT_IMPL(ImGuiInputTextState* obj, int idx) { idx--; while (idx >= 0 && !is_word_boundary_from_right(obj, idx)) idx--; return idx < 0 ? 0 : idx; }
|
||||
static int STB_TEXTEDIT_MOVEWORDRIGHT_MAC(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_left(obj, idx)) idx++; return idx > len ? len : idx; }
|
||||
#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
|
||||
#ifdef __APPLE__ // FIXME: Move setting to IO structure
|
||||
#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_MAC
|
||||
#else
|
||||
static int STB_TEXTEDIT_MOVEWORDRIGHT_WIN(ImGuiInputTextState* obj, int idx) { idx++; int len = obj->CurLenW; while (idx < len && !is_word_boundary_from_right(obj, idx)) idx++; return idx > len ? len : idx; }
|
||||
#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_WIN
|
||||
#endif
|
||||
static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj, int idx) { if (ImGui::GetIO().ConfigMacOSXBehaviors) return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx); else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
|
||||
#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL // They need to be #define for stb_textedit.h
|
||||
#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
|
||||
|
||||
static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj, int pos, int n)
|
||||
{
|
||||
@@ -3778,11 +3722,12 @@ static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* st
|
||||
{
|
||||
stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len);
|
||||
ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW);
|
||||
state->cursor = state->select_start = state->select_end = 0;
|
||||
if (text_len <= 0)
|
||||
return;
|
||||
if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len))
|
||||
{
|
||||
state->cursor = text_len;
|
||||
state->cursor = state->select_start = state->select_end = text_len;
|
||||
state->has_preferred_x = 0;
|
||||
return;
|
||||
}
|
||||
@@ -3901,6 +3846,13 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
|
||||
ImGuiContext& g = *GImGui;
|
||||
const unsigned c_decimal_point = (unsigned int)g.PlatformLocaleDecimalPoint;
|
||||
|
||||
// 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
|
||||
// scratch their head as to why it works in numerical fields vs in generic text fields it would require support in the font.
|
||||
if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal))
|
||||
if (c >= 0xFF01 && c <= 0xFF5E)
|
||||
c = c - 0xFF01 + 0x21;
|
||||
|
||||
// Allow 0-9 . - + * /
|
||||
if (flags & ImGuiInputTextFlags_CharsDecimal)
|
||||
if (!(c >= '0' && c <= '9') && (c != c_decimal_point) && (c != '-') && (c != '+') && (c != '*') && (c != '/'))
|
||||
@@ -3919,11 +3871,13 @@ static bool InputTextFilterCharacter(unsigned int* p_char, ImGuiInputTextFlags f
|
||||
// Turn a-z into A-Z
|
||||
if (flags & ImGuiInputTextFlags_CharsUppercase)
|
||||
if (c >= 'a' && c <= 'z')
|
||||
*p_char = (c += (unsigned int)('A' - 'a'));
|
||||
c += (unsigned int)('A' - 'a');
|
||||
|
||||
if (flags & ImGuiInputTextFlags_CharsNoBlank)
|
||||
if (ImCharIsBlankW(c))
|
||||
return false;
|
||||
|
||||
*p_char = c;
|
||||
}
|
||||
|
||||
// Custom callback filter
|
||||
@@ -4149,11 +4103,11 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
FocusWindow(window);
|
||||
|
||||
// Declare our inputs
|
||||
IM_ASSERT(ImGuiNavInput_COUNT < 32);
|
||||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
|
||||
if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))
|
||||
g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
|
||||
g.ActiveIdUsingNavInputMask |= (1 << ImGuiNavInput_Cancel);
|
||||
SetActiveIdUsingKey(ImGuiKey_Escape);
|
||||
SetActiveIdUsingKey(ImGuiKey_NavGamepadCancel);
|
||||
SetActiveIdUsingKey(ImGuiKey_Home);
|
||||
SetActiveIdUsingKey(ImGuiKey_End);
|
||||
if (is_multiline)
|
||||
@@ -4176,10 +4130,10 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
clear_active_id = true;
|
||||
|
||||
// Lock the decision of whether we are going to take the path displaying the cursor or selection
|
||||
const bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active);
|
||||
bool render_cursor = (g.ActiveId == id) || (state && user_scroll_active);
|
||||
bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
|
||||
bool value_changed = false;
|
||||
bool enter_pressed = false;
|
||||
bool validated = false;
|
||||
|
||||
// When read-only we always use the live data passed to the function
|
||||
// FIXME-OPT: Because our selection/cursor code currently needs the wide text we need to convert it when active, which is not ideal :(
|
||||
@@ -4275,10 +4229,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
else if (io.MouseClicked[0] && !state->SelectedAllMouseLock)
|
||||
{
|
||||
// FIXME: unselect on late click could be done release?
|
||||
if (hovered)
|
||||
{
|
||||
stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
|
||||
if (io.KeyShift)
|
||||
stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
|
||||
else
|
||||
stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
|
||||
state->CursorAnimReset();
|
||||
}
|
||||
}
|
||||
@@ -4291,7 +4247,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (state->SelectedAllMouseLock && !io.MouseDown[0])
|
||||
state->SelectedAllMouseLock = false;
|
||||
|
||||
// We except backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336)
|
||||
// We expect backends to emit a Tab key but some also emit a Tab character which we ignore (#2467, #1336)
|
||||
// (For Tab and Enter: Win32/SFML/Allegro are sending both keys and chars, GLFW and SDL are only sending keys. For Space they all send all threes)
|
||||
const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
|
||||
if ((flags & ImGuiInputTextFlags_AllowTabInput) && IsKeyPressed(ImGuiKey_Tab) && !ignore_char_inputs && !io.KeyShift && !is_readonly)
|
||||
@@ -4322,7 +4278,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
|
||||
// Process other shortcuts/key-presses
|
||||
bool cancel_edit = false;
|
||||
bool revert_edit = false;
|
||||
if (g.ActiveId == id && !g.ActiveIdIsJustActivated && !clear_active_id)
|
||||
{
|
||||
IM_ASSERT(state != NULL);
|
||||
@@ -4332,23 +4288,25 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
|
||||
const bool is_osx = io.ConfigMacOSXBehaviors;
|
||||
const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiModFlags_Super | ImGuiModFlags_Shift));
|
||||
const bool is_osx_shift_shortcut = is_osx && (io.KeyMods == (ImGuiMod_Super | ImGuiMod_Shift));
|
||||
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
|
||||
const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
|
||||
const bool is_ctrl_key_only = (io.KeyMods == ImGuiModFlags_Ctrl);
|
||||
const bool is_shift_key_only = (io.KeyMods == ImGuiModFlags_Shift);
|
||||
const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiModFlags_Super) : (io.KeyMods == ImGuiModFlags_Ctrl);
|
||||
const bool is_ctrl_key_only = (io.KeyMods == ImGuiMod_Ctrl);
|
||||
const bool is_shift_key_only = (io.KeyMods == ImGuiMod_Shift);
|
||||
const bool is_shortcut_key = g.IO.ConfigMacOSXBehaviors ? (io.KeyMods == ImGuiMod_Super) : (io.KeyMods == ImGuiMod_Ctrl);
|
||||
|
||||
const bool is_cut = ((is_shortcut_key && IsKeyPressed(ImGuiKey_X)) || (is_shift_key_only && IsKeyPressed(ImGuiKey_Delete))) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_copy = ((is_shortcut_key && IsKeyPressed(ImGuiKey_C)) || (is_ctrl_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_password && (!is_multiline || state->HasSelection());
|
||||
const bool is_paste = ((is_shortcut_key && IsKeyPressed(ImGuiKey_V)) || (is_shift_key_only && IsKeyPressed(ImGuiKey_Insert))) && !is_readonly;
|
||||
const bool is_undo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Z)) && !is_readonly && is_undoable);
|
||||
const bool is_redo = ((is_shortcut_key && IsKeyPressed(ImGuiKey_Y)) || (is_osx_shift_shortcut && IsKeyPressed(ImGuiKey_Z))) && !is_readonly && is_undoable;
|
||||
const bool is_select_all = is_shortcut_key && IsKeyPressed(ImGuiKey_A);
|
||||
|
||||
// We allow validate/cancel with Nav source (gamepad) to makes it easier to undo an accidental NavInput press with no keyboard wired, but otherwise it isn't very useful.
|
||||
const bool is_validate_enter = IsKeyPressed(ImGuiKey_Enter) || IsKeyPressed(ImGuiKey_KeypadEnter);
|
||||
const bool is_validate_nav = (IsNavInputTest(ImGuiNavInput_Activate, ImGuiNavReadMode_Pressed) && !IsKeyPressed(ImGuiKey_Space)) || IsNavInputTest(ImGuiNavInput_Input, ImGuiNavReadMode_Pressed);
|
||||
const bool is_cancel = IsKeyPressed(ImGuiKey_Escape) || IsNavInputTest(ImGuiNavInput_Cancel, ImGuiNavReadMode_Pressed);
|
||||
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
||||
const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter, true) || IsKeyPressed(ImGuiKey_KeypadEnter, true);
|
||||
const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));
|
||||
const bool is_cancel = IsKeyPressed(ImGuiKey_Escape, false) || (nav_gamepad_active && IsKeyPressed(ImGuiKey_NavGamepadCancel, false));
|
||||
|
||||
if (IsKeyPressed(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
|
||||
else if (IsKeyPressed(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
|
||||
@@ -4370,12 +4328,17 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
|
||||
}
|
||||
else if (is_validate_enter)
|
||||
else if (is_enter_pressed || is_gamepad_validate)
|
||||
{
|
||||
// Determine if we turn Enter into a \n character
|
||||
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
|
||||
if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
|
||||
if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
|
||||
{
|
||||
enter_pressed = clear_active_id = true;
|
||||
validated = true;
|
||||
if (io.ConfigInputTextEnterKeepActive && !is_multiline)
|
||||
state->SelectAll(); // No need to scroll
|
||||
else
|
||||
clear_active_id = true;
|
||||
}
|
||||
else if (!is_readonly)
|
||||
{
|
||||
@@ -4384,21 +4347,32 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
state->OnKeyPressed((int)c);
|
||||
}
|
||||
}
|
||||
else if (is_validate_nav)
|
||||
{
|
||||
IM_ASSERT(!is_validate_enter);
|
||||
enter_pressed = clear_active_id = true;
|
||||
}
|
||||
else if (is_cancel)
|
||||
{
|
||||
clear_active_id = cancel_edit = true;
|
||||
if (flags & ImGuiInputTextFlags_EscapeClearsAll)
|
||||
{
|
||||
if (state->CurLenA > 0)
|
||||
{
|
||||
revert_edit = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
render_cursor = render_selection = false;
|
||||
clear_active_id = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
clear_active_id = revert_edit = true;
|
||||
render_cursor = render_selection = false;
|
||||
}
|
||||
}
|
||||
else if (is_undo || is_redo)
|
||||
{
|
||||
state->OnKeyPressed(is_undo ? STB_TEXTEDIT_K_UNDO : STB_TEXTEDIT_K_REDO);
|
||||
state->ClearSelection();
|
||||
}
|
||||
else if (is_shortcut_key && IsKeyPressed(ImGuiKey_A))
|
||||
else if (is_select_all)
|
||||
{
|
||||
state->SelectAll();
|
||||
state->CursorFollow = true;
|
||||
@@ -4462,11 +4436,19 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (g.ActiveId == id)
|
||||
{
|
||||
IM_ASSERT(state != NULL);
|
||||
if (cancel_edit)
|
||||
if (revert_edit && !is_readonly)
|
||||
{
|
||||
// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
|
||||
if (!is_readonly && strcmp(buf, state->InitialTextA.Data) != 0)
|
||||
if (flags & ImGuiInputTextFlags_EscapeClearsAll)
|
||||
{
|
||||
// Clear input
|
||||
apply_new_text = "";
|
||||
apply_new_text_length = 0;
|
||||
STB_TEXTEDIT_CHARTYPE empty_string;
|
||||
stb_textedit_replace(state, &state->Stb, &empty_string, 0);
|
||||
}
|
||||
else if (strcmp(buf, state->InitialTextA.Data) != 0)
|
||||
{
|
||||
// Restore initial value. Only return true if restoring to the initial value changes the current buffer contents.
|
||||
// Push records into the undo stack so we can CTRL+Z the revert operation itself
|
||||
apply_new_text = state->InitialTextA.Data;
|
||||
apply_new_text_length = state->InitialTextA.Size - 1;
|
||||
@@ -4491,7 +4473,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
// 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).
|
||||
const bool apply_edit_back_to_user_buffer = !cancel_edit || (enter_pressed && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
|
||||
const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
|
||||
if (apply_edit_back_to_user_buffer)
|
||||
{
|
||||
// Apply new value immediately - copy modified buffer back
|
||||
@@ -4566,6 +4548,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
if (callback_data.SelectionEnd != utf8_selection_end || buf_dirty) { state->Stb.select_end = (callback_data.SelectionEnd == callback_data.SelectionStart) ? state->Stb.select_start : ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionEnd); }
|
||||
if (buf_dirty)
|
||||
{
|
||||
IM_ASSERT((flags & ImGuiInputTextFlags_ReadOnly) == 0);
|
||||
IM_ASSERT(callback_data.BufTextLen == (int)strlen(callback_data.Buf)); // You need to maintain BufTextLen if you change the text!
|
||||
InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen); // FIXME: Move the rest of this block inside function and rename to InputTextReconcileStateAfterUserCallback() ?
|
||||
if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
|
||||
@@ -4584,9 +4567,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
apply_new_text_length = state->CurLenA;
|
||||
}
|
||||
}
|
||||
|
||||
// Clear temporary user storage
|
||||
state->Flags = ImGuiInputTextFlags_None;
|
||||
}
|
||||
|
||||
// Copy result to user buffer. This can currently only happen when (g.ActiveId == id)
|
||||
@@ -4868,7 +4848,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
|
||||
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
|
||||
if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
|
||||
return enter_pressed;
|
||||
return validated;
|
||||
else
|
||||
return value_changed;
|
||||
}
|
||||
@@ -5109,16 +5089,19 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
|
||||
if (BeginPopup("picker"))
|
||||
{
|
||||
picker_active_window = g.CurrentWindow;
|
||||
if (label != label_display_end)
|
||||
if (g.CurrentWindow->BeginCount == 1)
|
||||
{
|
||||
TextEx(label, label_display_end);
|
||||
Spacing();
|
||||
picker_active_window = g.CurrentWindow;
|
||||
if (label != label_display_end)
|
||||
{
|
||||
TextEx(label, label_display_end);
|
||||
Spacing();
|
||||
}
|
||||
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
|
||||
ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
|
||||
SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
|
||||
value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
|
||||
}
|
||||
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
|
||||
ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
|
||||
SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
|
||||
value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
|
||||
EndPopup();
|
||||
}
|
||||
}
|
||||
@@ -5162,7 +5145,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
bool accepted_drag_drop = false;
|
||||
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
|
||||
{
|
||||
memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512
|
||||
memcpy((float*)col, payload->Data, sizeof(float) * 3); // Preserve alpha if any //-V512 //-V1086
|
||||
value_changed = accepted_drag_drop = true;
|
||||
}
|
||||
if (const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
|
||||
@@ -5181,7 +5164,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
|
||||
if (picker_active_window && g.ActiveId != 0 && g.ActiveIdWindow == picker_active_window)
|
||||
g.LastItemData.ID = g.ActiveId;
|
||||
|
||||
if (value_changed)
|
||||
if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId
|
||||
MarkItemEdited(g.LastItemData.ID);
|
||||
|
||||
return value_changed;
|
||||
@@ -5569,7 +5552,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
|
||||
|
||||
if (value_changed && memcmp(backup_initial_col, col, components * sizeof(float)) == 0)
|
||||
value_changed = false;
|
||||
if (value_changed)
|
||||
if (value_changed && g.LastItemData.ID != 0) // In case of ID collision, the second EndGroup() won't catch g.ActiveId
|
||||
MarkItemEdited(g.LastItemData.ID);
|
||||
|
||||
PopID();
|
||||
@@ -5904,7 +5887,14 @@ bool ImGui::TreeNodeExV(const void* ptr_id, ImGuiTreeNodeFlags flags, const char
|
||||
return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end);
|
||||
}
|
||||
|
||||
bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
||||
void ImGui::TreeNodeSetOpen(ImGuiID id, bool open)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiStorage* storage = g.CurrentWindow->DC.StateStorage;
|
||||
storage->SetInt(id, open ? 1 : 0);
|
||||
}
|
||||
|
||||
bool ImGui::TreeNodeUpdateNextOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
||||
{
|
||||
if (flags & ImGuiTreeNodeFlags_Leaf)
|
||||
return true;
|
||||
@@ -5920,7 +5910,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
||||
if (g.NextItemData.OpenCond & ImGuiCond_Always)
|
||||
{
|
||||
is_open = g.NextItemData.OpenVal;
|
||||
storage->SetInt(id, is_open);
|
||||
TreeNodeSetOpen(id, is_open);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5929,7 +5919,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
|
||||
if (stored_value == -1)
|
||||
{
|
||||
is_open = g.NextItemData.OpenVal;
|
||||
storage->SetInt(id, is_open);
|
||||
TreeNodeSetOpen(id, is_open);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -5995,7 +5985,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
|
||||
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
|
||||
// This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
|
||||
const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
|
||||
bool is_open = TreeNodeBehaviorIsOpen(id, flags);
|
||||
bool is_open = TreeNodeUpdateNextOpen(id, flags);
|
||||
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
|
||||
window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
|
||||
|
||||
@@ -7010,10 +7000,10 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
|
||||
// Odd hack to allow hovering across menus of a same menu-set (otherwise we wouldn't be able to hover parent without always being a Child window)
|
||||
// This is only done for items for the menu set and not the full parent window.
|
||||
const bool menuset_is_open = IsRootOfOpenMenuSet();
|
||||
ImGuiWindow* backed_nav_window = g.NavWindow;
|
||||
if (menuset_is_open)
|
||||
g.NavWindow = window;
|
||||
PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true);
|
||||
|
||||
// The reference position stored in popup_pos will be used by Begin() to find a suitable position for the child menu,
|
||||
// However the final position is going to be different! It is chosen by FindBestWindowPosForPopup().
|
||||
@@ -7062,7 +7052,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
|
||||
const bool hovered = (g.HoveredId == id) && enabled && !g.NavDisableMouseHover;
|
||||
if (menuset_is_open)
|
||||
g.NavWindow = backed_nav_window;
|
||||
PopItemFlag();
|
||||
|
||||
bool want_open = false;
|
||||
bool want_close = false;
|
||||
@@ -7071,26 +7061,30 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
// Close menu when not hovering it anymore unless we are moving roughly in the direction of the menu
|
||||
// Implement http://bjk5.com/post/44698559168/breaking-down-amazons-mega-dropdown to avoid using timers, so menus feels more reactive.
|
||||
bool moving_toward_child_menu = false;
|
||||
ImGuiWindow* child_menu_window = (g.BeginPopupStack.Size < g.OpenPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].SourceWindow == window) ? g.OpenPopupStack[g.BeginPopupStack.Size].Window : NULL;
|
||||
if (g.HoveredWindow == window && child_menu_window != NULL && !(window->Flags & ImGuiWindowFlags_MenuBar))
|
||||
ImGuiPopupData* child_popup = (g.BeginPopupStack.Size < g.OpenPopupStack.Size) ? &g.OpenPopupStack[g.BeginPopupStack.Size] : NULL; // Popup candidate (testing below)
|
||||
ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL;
|
||||
if (g.HoveredWindow == window && child_menu_window != NULL)
|
||||
{
|
||||
float ref_unit = g.FontSize; // FIXME-DPI
|
||||
float child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f;
|
||||
ImRect next_window_rect = child_menu_window->Rect();
|
||||
ImVec2 ta = (g.IO.MousePos - g.IO.MouseDelta);
|
||||
ImVec2 tb = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetTL() : next_window_rect.GetTR();
|
||||
ImVec2 tc = (window->Pos.x < child_menu_window->Pos.x) ? next_window_rect.GetBL() : next_window_rect.GetBR();
|
||||
ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR();
|
||||
ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR();
|
||||
float extra = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f); // add a bit of extra slack.
|
||||
ta.x += (window->Pos.x < child_menu_window->Pos.x) ? -0.5f : +0.5f; // to avoid numerical issues (FIXME: ??)
|
||||
ta.x += child_dir * -0.5f;
|
||||
tb.x += child_dir * ref_unit;
|
||||
tc.x += child_dir * ref_unit;
|
||||
tb.y = ta.y + ImMax((tb.y - extra) - ta.y, -ref_unit * 8.0f); // triangle has maximum height to limit the slope and the bias toward large sub-menus
|
||||
tc.y = ta.y + ImMin((tc.y + extra) - ta.y, +ref_unit * 8.0f);
|
||||
moving_toward_child_menu = ImTriangleContainsPoint(ta, tb, tc, g.IO.MousePos);
|
||||
//GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_other_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]
|
||||
//GetForegroundDrawList()->AddTriangleFilled(ta, tb, tc, moving_toward_child_menu ? IM_COL32(0,128,0,128) : IM_COL32(128,0,0,128)); // [DEBUG]
|
||||
}
|
||||
|
||||
// The 'HovereWindow == window' check creates an inconsistency (e.g. moving away from menu slowly tends to hit same window, whereas moving away fast does not)
|
||||
// But we also need to not close the top-menu menu when moving over void. Perhaps we should extend the triangle check to a larger polygon.
|
||||
// (Remember to test this on BeginPopup("A")->BeginMenu("B") sequence which behaves slightly differently as B isn't a Child of A and hovering isn't shared.)
|
||||
if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu)
|
||||
if (menu_is_open && !hovered && g.HoveredWindow == window && !moving_toward_child_menu && !g.NavDisableMouseHover)
|
||||
want_close = true;
|
||||
|
||||
// Open
|
||||
@@ -7144,10 +7138,19 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
|
||||
|
||||
if (menu_is_open)
|
||||
{
|
||||
SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: this is super misleading! The value will serve as reference for FindBestWindowPosForPopup(), not actual pos.
|
||||
ImGuiLastItemData last_item_in_parent = g.LastItemData;
|
||||
SetNextWindowPos(popup_pos, ImGuiCond_Always); // Note: misleading: the value will serve as reference for FindBestWindowPosForPopup(), not actual pos.
|
||||
PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding); // First level will use _PopupRounding, subsequent will use _ChildRounding
|
||||
menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
menu_is_open = BeginPopupEx(id, flags); // menu_is_open can be 'false' when the popup is completely clipped (e.g. zero size display)
|
||||
PopStyleVar();
|
||||
if (menu_is_open)
|
||||
{
|
||||
// Restore LastItemData so IsItemXXXX functions can work after BeginMenu()/EndMenu()
|
||||
// (This fixes using IsItemClicked() and IsItemHovered(), but IsItemHovered() also relies on its support for ImGuiItemFlags_NoWindowHoverableCheck)
|
||||
g.LastItemData = last_item_in_parent;
|
||||
if (g.HoveredWindow == window)
|
||||
g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -7164,17 +7167,18 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
|
||||
|
||||
void ImGui::EndMenu()
|
||||
{
|
||||
// Nav: When a left move request _within our child menu_ failed, close ourselves (the _parent_ menu).
|
||||
// A menu doesn't close itself because EndMenuBar() wants the catch the last Left<>Right inputs.
|
||||
// However, it means that with the current code, a BeginMenu() from outside another menu or a menu-bar won't be closable with the Left direction.
|
||||
// Nav: When a left move request our menu failed, close ourselves.
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet() && window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
||||
if (g.NavWindow && (g.NavWindow->RootWindowForNav->Flags & ImGuiWindowFlags_Popup) && g.NavWindow->RootWindowForNav->ParentWindow == window)
|
||||
{
|
||||
ClosePopupToLevel(g.BeginPopupStack.Size, true);
|
||||
NavMoveRequestCancel();
|
||||
}
|
||||
IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup); // Mismatched BeginMenu()/EndMenu() calls
|
||||
ImGuiWindow* parent_window = window->ParentWindow; // Should always be != NULL is we passed assert.
|
||||
if (window->BeginCount == window->BeginCountPreviousFrame)
|
||||
if (g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet())
|
||||
if (g.NavWindow && (g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical)
|
||||
{
|
||||
ClosePopupToLevel(g.BeginPopupStack.Size - 1, true);
|
||||
NavMoveRequestCancel();
|
||||
}
|
||||
|
||||
EndPopup();
|
||||
}
|
||||
@@ -7190,10 +7194,10 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
|
||||
// See BeginMenuEx() for comments about this.
|
||||
const bool menuset_is_open = IsRootOfOpenMenuSet();
|
||||
ImGuiWindow* backed_nav_window = g.NavWindow;
|
||||
if (menuset_is_open)
|
||||
g.NavWindow = window;
|
||||
PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck, true);
|
||||
|
||||
// We've been using the equivalent of ImGuiSelectableFlags_SetNavIdOnHover on all Selectable() since early Nav system days (commit 43ee5d73),
|
||||
// but I am unsure whether this should be kept at all. For now moved it to be an opt-in feature used by menus only.
|
||||
@@ -7245,7 +7249,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
|
||||
EndDisabled();
|
||||
PopID();
|
||||
if (menuset_is_open)
|
||||
g.NavWindow = backed_nav_window;
|
||||
PopItemFlag();
|
||||
|
||||
return pressed;
|
||||
}
|
||||
@@ -7572,8 +7576,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
|
||||
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
|
||||
const char* tab_name = tab_bar->GetTabName(tab);
|
||||
const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
|
||||
tab->ContentWidth = (tab->RequestedWidth > 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button).x;
|
||||
const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
|
||||
tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;
|
||||
|
||||
int section_n = TabItemGetSectionIdx(tab);
|
||||
ImGuiTabBarSection* section = §ions[section_n];
|
||||
@@ -7585,9 +7589,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
ImGuiShrinkWidthItem* shrink_width_item = &g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++];
|
||||
shrink_width_item->Index = tab_n;
|
||||
shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth;
|
||||
|
||||
IM_ASSERT(tab->ContentWidth > 0.0f);
|
||||
tab->Width = tab->ContentWidth;
|
||||
tab->Width = ImMax(tab->ContentWidth, 1.0f);
|
||||
}
|
||||
|
||||
// Compute total ideal width (used for e.g. auto-resizing a window)
|
||||
@@ -7617,7 +7619,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth(); // Excess used to shrink leading/trailing section
|
||||
|
||||
// With ImGuiTabBarFlags_FittingPolicyScroll policy, we will only shrink leading/trailing if the central section is not visible anymore
|
||||
if (width_excess > 0.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||
if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
|
||||
{
|
||||
int shrink_data_count = (central_section_is_visible ? sections[1].TabCount : sections[0].TabCount + sections[2].TabCount);
|
||||
int shrink_data_offset = (central_section_is_visible ? sections[0].TabCount + sections[2].TabCount : 0);
|
||||
@@ -7631,6 +7633,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
if (shrinked_width < 0.0f)
|
||||
continue;
|
||||
|
||||
shrinked_width = ImMax(1.0f, shrinked_width);
|
||||
int section_n = TabItemGetSectionIdx(tab);
|
||||
sections[section_n].Width -= (tab->Width - shrinked_width);
|
||||
tab->Width = shrinked_width;
|
||||
@@ -7674,7 +7677,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
|
||||
// CTRL+TAB can override visible tab temporarily
|
||||
if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar)
|
||||
tab_bar->VisibleTabId = scroll_to_tab_id = g.NavWindowingTarget->ID;
|
||||
tab_bar->VisibleTabId = scroll_to_tab_id = g.NavWindowingTarget->TabId;
|
||||
|
||||
// Update scrolling
|
||||
if (scroll_to_tab_id != 0)
|
||||
@@ -7785,7 +7788,9 @@ void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
|
||||
// Called on manual closure attempt
|
||||
void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
{
|
||||
IM_ASSERT(!(tab->Flags & ImGuiTabItemFlags_Button));
|
||||
if (tab->Flags & ImGuiTabItemFlags_Button)
|
||||
return; // A button appended with TabItemButton().
|
||||
|
||||
if (!(tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
{
|
||||
// This will remove a frame of lag for selecting another tab on closure.
|
||||
@@ -8140,18 +8145,19 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab);
|
||||
|
||||
// Calculate tab contents size
|
||||
ImVec2 size = TabItemCalcSize(label, p_open != NULL);
|
||||
ImVec2 size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument));
|
||||
tab->RequestedWidth = -1.0f;
|
||||
if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
|
||||
size.x = tab->RequestedWidth = g.NextItemData.Width;
|
||||
if (tab_is_new)
|
||||
tab->Width = size.x;
|
||||
tab->Width = ImMax(1.0f, size.x);
|
||||
tab->ContentWidth = size.x;
|
||||
tab->BeginOrder = tab_bar->TabsActiveCount++;
|
||||
|
||||
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
|
||||
const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;
|
||||
const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);
|
||||
const bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
|
||||
const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;
|
||||
tab->LastFrameVisible = g.FrameCount;
|
||||
tab->Flags = flags;
|
||||
@@ -8312,7 +8318,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
SetActiveID(g.MovingWindow->MoveId, g.MovingWindow);
|
||||
g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
|
||||
g.ActiveIdNoClearOnFocusLoss = true;
|
||||
SetActiveIdUsingNavAndKeys();
|
||||
SetActiveIdUsingAllKeyboardKeys();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8346,7 +8352,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
const ImGuiID close_button_id = p_open ? GetIDWithSeed("#CLOSE", NULL, docked_window ? docked_window->ID : id) : 0;
|
||||
bool just_closed;
|
||||
bool text_clipped;
|
||||
TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
|
||||
TabItemLabelAndCloseButton(display_draw_list, bb, tab_just_unsaved ? (flags & ~ImGuiTabItemFlags_UnsavedDocument) : flags, tab_bar->FramePadding, label, id, close_button_id, tab_contents_visible, &just_closed, &text_clipped);
|
||||
if (just_closed && p_open != NULL)
|
||||
{
|
||||
*p_open = false;
|
||||
@@ -8368,9 +8374,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
|
||||
// (We test IsItemHovered() to discard e.g. when another item is active or drag and drop over the tab bar, which g.HoveredId ignores)
|
||||
// FIXME: This is a mess.
|
||||
// FIXME: We may want disabled tab to still display the tooltip?
|
||||
if (text_clipped && g.HoveredId == id && !held && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay && IsItemHovered())
|
||||
if (text_clipped && g.HoveredId == id && !held)
|
||||
if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
|
||||
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
if (IsItemHovered(ImGuiHoveredFlags_DelayNormal))
|
||||
SetTooltip("%.*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)
|
||||
@@ -8404,18 +8411,23 @@ void ImGui::SetTabItemClosed(const char* label)
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button)
|
||||
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f);
|
||||
if (has_close_button)
|
||||
if (has_close_button_or_unsaved_marker)
|
||||
size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle.
|
||||
else
|
||||
size.x += g.Style.FramePadding.x + 1.0f;
|
||||
return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y);
|
||||
}
|
||||
|
||||
ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window)
|
||||
{
|
||||
return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
|
||||
}
|
||||
|
||||
void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)
|
||||
{
|
||||
// While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it.
|
||||
|
||||
Reference in New Issue
Block a user