33#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
34#define _CRT_SECURE_NO_WARNINGS
37#ifndef IMGUI_DEFINE_MATH_OPERATORS
38#define IMGUI_DEFINE_MATH_OPERATORS
43#include "imgui_internal.h"
54#pragma warning (disable: 4127)
55#pragma warning (disable: 4996)
56#if defined(_MSC_VER) && _MSC_VER >= 1922
57#pragma warning (disable: 5054)
59#pragma warning (disable: 26451)
60#pragma warning (disable: 26812)
65#if __has_warning("-Wunknown-warning-option")
66#pragma clang diagnostic ignored "-Wunknown-warning-option"
68#pragma clang diagnostic ignored "-Wunknown-pragmas"
69#pragma clang diagnostic ignored "-Wold-style-cast"
70#pragma clang diagnostic ignored "-Wfloat-equal"
71#pragma clang diagnostic ignored "-Wformat-nonliteral"
72#pragma clang diagnostic ignored "-Wsign-conversion"
73#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
74#pragma clang diagnostic ignored "-Wdouble-promotion"
75#pragma clang diagnostic ignored "-Wenum-enum-conversion"
76#pragma clang diagnostic ignored "-Wdeprecated-enum-enum-conversion"
77#pragma clang diagnostic ignored "-Wimplicit-int-float-conversion"
78#elif defined(__GNUC__)
79#pragma GCC diagnostic ignored "-Wpragmas"
80#pragma GCC diagnostic ignored "-Wformat-nonliteral"
81#pragma GCC diagnostic ignored "-Wclass-memaccess"
82#pragma GCC diagnostic ignored "-Wdeprecated-enum-enum-conversion"
90static const float DRAGDROP_HOLD_TO_OPEN_TIMER = 0.70f;
91static const float DRAG_MOUSE_THRESHOLD_FACTOR = 0.50f;
94static const signed char IM_S8_MIN = -128;
95static const signed char IM_S8_MAX = 127;
96static const unsigned char IM_U8_MIN = 0;
97static const unsigned char IM_U8_MAX = 0xFF;
98static const signed short IM_S16_MIN = -32768;
99static const signed short IM_S16_MAX = 32767;
100static const unsigned short IM_U16_MIN = 0;
101static const unsigned short IM_U16_MAX = 0xFFFF;
102static const ImS32 IM_S32_MIN = INT_MIN;
103static const ImS32 IM_S32_MAX = INT_MAX;
104static const ImU32 IM_U32_MIN = 0;
105static const ImU32 IM_U32_MAX = UINT_MAX;
107static const ImS64 IM_S64_MIN = LLONG_MIN;
108static const ImS64 IM_S64_MAX = LLONG_MAX;
110static const ImS64 IM_S64_MIN = -9223372036854775807LL - 1;
111static const ImS64 IM_S64_MAX = 9223372036854775807LL;
113static const ImU64 IM_U64_MIN = 0;
115static const ImU64 IM_U64_MAX = ULLONG_MAX;
117static const ImU64 IM_U64_MAX = (2ULL * 9223372036854775807LL + 1);
125static bool InputTextFilterCharacter(ImGuiContext* ctx,
unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* user_data, ImGuiInputSource input_source);
126static int InputTextCalcTextLenAndLineCount(
const char* text_begin,
const char** out_text_end);
127static 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);
148void ImGui::TextEx(
const char* text,
const char* text_end, ImGuiTextFlags flags)
150 ImGuiWindow* window = GetCurrentWindow();
151 if (window->SkipItems)
156 if (text == text_end)
157 text = text_end =
"";
160 const char* text_begin = text;
161 if (text_end == NULL)
162 text_end = text + strlen(text);
164 const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
165 const float wrap_pos_x = window->DC.TextWrapPos;
166 const bool wrap_enabled = (wrap_pos_x >= 0.0f);
167 if (text_end - text <= 2000 || wrap_enabled)
170 const float wrap_width = wrap_enabled ? CalcWrapWidthForPos(window->DC.CursorPos, wrap_pos_x) : 0.0f;
171 const ImVec2 text_size = CalcTextSize(text_begin, text_end,
false, wrap_width);
173 ImRect bb(text_pos, text_pos + text_size);
174 ItemSize(text_size, 0.0f);
179 RenderTextWrapped(bb.Min, text_begin, text_end, wrap_width);
188 const char* line = text;
189 const float line_height = GetTextLineHeight();
190 ImVec2 text_size(0, 0);
193 ImVec2 pos = text_pos;
196 int lines_skippable = (int)((window->ClipRect.Min.y - text_pos.y) / line_height);
197 if (lines_skippable > 0)
199 int lines_skipped = 0;
200 while (line < text_end && lines_skipped < lines_skippable)
202 const char* line_end = (
const char*)memchr(line,
'\n', text_end - line);
205 if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
206 text_size.x = ImMax(text_size.x,
CalcTextSize(line, line_end).x);
210 pos.y += lines_skipped * line_height;
217 ImRect line_rect(pos, pos + ImVec2(FLT_MAX, line_height));
218 while (line < text_end)
220 if (IsClippedEx(line_rect, 0))
223 const char* line_end = (
const char*)memchr(line,
'\n', text_end - line);
226 text_size.x = ImMax(text_size.x,
CalcTextSize(line, line_end).x);
227 RenderText(pos, line, line_end,
false);
229 line_rect.Min.y += line_height;
230 line_rect.Max.y += line_height;
231 pos.y += line_height;
235 int lines_skipped = 0;
236 while (line < text_end)
238 const char* line_end = (
const char*)memchr(line,
'\n', text_end - line);
241 if ((flags & ImGuiTextFlags_NoWidthForLargeClippedText) == 0)
242 text_size.x = ImMax(text_size.x,
CalcTextSize(line, line_end).x);
246 pos.y += lines_skipped * line_height;
248 text_size.y = (pos - text_pos).y;
250 ImRect bb(text_pos, text_pos + text_size);
251 ItemSize(text_size, 0.0f);
258 TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
261void ImGui::Text(
const char* fmt, ...)
269void ImGui::TextV(
const char* fmt, va_list args)
271 ImGuiWindow* window = GetCurrentWindow();
272 if (window->SkipItems)
275 const char* text, *text_end;
277 TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
280void ImGui::TextColored(
const ImVec4& col,
const char* fmt, ...)
284 TextColoredV(col, fmt, args);
288void ImGui::TextColoredV(
const ImVec4& col,
const char* fmt, va_list args)
290 PushStyleColor(ImGuiCol_Text, col);
295void ImGui::TextDisabled(
const char* fmt, ...)
299 TextDisabledV(fmt, args);
303void ImGui::TextDisabledV(
const char* fmt, va_list args)
306 PushStyleColor(ImGuiCol_Text,
g.Style.Colors[ImGuiCol_TextDisabled]);
311void ImGui::TextWrapped(
const char* fmt, ...)
315 TextWrappedV(fmt, args);
319void ImGui::TextWrappedV(
const char* fmt, va_list args)
322 const bool need_backup = (
g.CurrentWindow->DC.TextWrapPos < 0.0f);
324 PushTextWrapPos(0.0f);
330void ImGui::LabelText(
const char* label,
const char* fmt, ...)
334 LabelTextV(label, fmt, args);
339void ImGui::LabelTextV(
const char* label,
const char* fmt, va_list args)
341 ImGuiWindow* window = GetCurrentWindow();
342 if (window->SkipItems)
346 const ImGuiStyle& style =
g.Style;
347 const float w = CalcItemWidth();
349 const char* value_text_begin, *value_text_end;
351 const ImVec2 value_size =
CalcTextSize(value_text_begin, value_text_end,
false);
352 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
354 const ImVec2 pos = window->DC.CursorPos;
355 const ImRect value_bb(pos, pos + ImVec2(w, value_size.y + style.FramePadding.y * 2));
356 const ImRect total_bb(pos, pos + ImVec2(w + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), ImMax(value_size.y, label_size.y) + style.FramePadding.y * 2));
357 ItemSize(total_bb, style.FramePadding.y);
358 if (!ItemAdd(total_bb, 0))
362 RenderTextClipped(value_bb.Min + style.FramePadding, value_bb.Max, value_text_begin, value_text_end, &value_size, ImVec2(0.0f, 0.0f));
363 if (label_size.x > 0.0f)
364 RenderText(ImVec2(value_bb.Max.x + style.ItemInnerSpacing.x, value_bb.Min.y + style.FramePadding.y), label);
367void ImGui::BulletText(
const char* fmt, ...)
371 BulletTextV(fmt, args);
376void ImGui::BulletTextV(
const char* fmt, va_list args)
378 ImGuiWindow* window = GetCurrentWindow();
379 if (window->SkipItems)
383 const ImGuiStyle& style =
g.Style;
385 const char* text_begin, *text_end;
387 const ImVec2 label_size =
CalcTextSize(text_begin, text_end,
false);
388 const ImVec2 total_size = ImVec2(
g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x * 2) : 0.0f), label_size.y);
389 ImVec2 pos = window->DC.CursorPos;
390 pos.y += window->DC.CurrLineTextBaseOffset;
391 ItemSize(total_size, 0.0f);
392 const ImRect bb(pos, pos + total_size);
397 ImU32 text_col = GetColorU32(ImGuiCol_Text);
398 RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x +
g.FontSize * 0.5f,
g.FontSize * 0.5f), text_col);
399 RenderText(bb.Min + ImVec2(
g.FontSize + style.FramePadding.x * 2, 0.0f), text_begin, text_end,
false);
483bool ImGui::ButtonBehavior(
const ImRect& bb, ImGuiID
id,
bool* out_hovered,
bool* out_held, ImGuiButtonFlags flags)
486 ImGuiWindow* window = GetCurrentWindow();
489 if ((flags & ImGuiButtonFlags_MouseButtonMask_) == 0)
490 flags |= ImGuiButtonFlags_MouseButtonDefault_;
493 if ((flags & ImGuiButtonFlags_PressedOnMask_) == 0)
494 flags |= ImGuiButtonFlags_PressedOnDefault_;
498 ImGuiItemFlags item_flags = (
g.LastItemData.ID ==
id ?
g.LastItemData.InFlags :
g.CurrentItemFlags);
499 if (flags & ImGuiButtonFlags_AllowOverlap)
500 item_flags |= ImGuiItemFlags_AllowOverlap;
501 if (flags & ImGuiButtonFlags_Repeat)
502 item_flags |= ImGuiItemFlags_ButtonRepeat;
504 ImGuiWindow* backup_hovered_window =
g.HoveredWindow;
505 const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) &&
g.HoveredWindow &&
g.HoveredWindow->RootWindowDockTree == window->RootWindowDockTree;
506 if (flatten_hovered_children)
507 g.HoveredWindow = window;
509#ifdef IMGUI_ENABLE_TEST_ENGINE
511 if (
id != 0 &&
g.LastItemData.ID !=
id)
512 IMGUI_TEST_ENGINE_ITEM_ADD(
id, bb, NULL);
515 bool pressed =
false;
516 bool hovered = ItemHoverable(bb,
id, item_flags);
519 if (
g.DragDropActive && (flags & ImGuiButtonFlags_PressedOnDragDropHold) && !(
g.DragDropSourceFlags & ImGuiDragDropFlags_SourceNoHoldToOpenOthers))
520 if (IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByActiveItem))
524 if (
g.HoveredIdTimer -
g.IO.DeltaTime <= DRAGDROP_HOLD_TO_OPEN_TIMER &&
g.HoveredIdTimer >= DRAGDROP_HOLD_TO_OPEN_TIMER)
527 g.DragDropHoldJustPressedId =
id;
532 if (flatten_hovered_children)
533 g.HoveredWindow = backup_hovered_window;
536 const ImGuiID test_owner_id = (flags & ImGuiButtonFlags_NoTestKeyOwner) ? ImGuiKeyOwner_Any :
id;
542 int mouse_button_clicked = -1;
543 int mouse_button_released = -1;
544 for (
int button = 0; button < 3; button++)
545 if (flags & (ImGuiButtonFlags_MouseButtonLeft << button))
547 if (IsMouseClicked(button, test_owner_id) && mouse_button_clicked == -1) { mouse_button_clicked = button; }
548 if (IsMouseReleased(button, test_owner_id) && mouse_button_released == -1) { mouse_button_released = button; }
552 if (!(flags & ImGuiButtonFlags_NoKeyModifiers) || (!
g.IO.KeyCtrl && !
g.IO.KeyShift && !
g.IO.KeyAlt))
554 if (mouse_button_clicked != -1 &&
g.ActiveId !=
id)
556 if (!(flags & ImGuiButtonFlags_NoSetKeyOwner))
557 SetKeyOwner(MouseButtonToKey(mouse_button_clicked),
id);
558 if (flags & (ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnClickReleaseAnywhere))
560 SetActiveID(
id, window);
561 g.ActiveIdMouseButton = mouse_button_clicked;
562 if (!(flags & ImGuiButtonFlags_NoNavFocus))
563 SetFocusID(
id, window);
566 if ((flags & ImGuiButtonFlags_PressedOnClick) || ((flags & ImGuiButtonFlags_PressedOnDoubleClick) &&
g.IO.MouseClickedCount[mouse_button_clicked] == 2))
569 if (flags & ImGuiButtonFlags_NoHoldingActiveId)
572 SetActiveID(
id, window);
573 if (!(flags & ImGuiButtonFlags_NoNavFocus))
574 SetFocusID(
id, window);
575 g.ActiveIdMouseButton = mouse_button_clicked;
579 if (flags & ImGuiButtonFlags_PressedOnRelease)
581 if (mouse_button_released != -1)
583 const bool has_repeated_at_least_once = (item_flags & ImGuiItemFlags_ButtonRepeat) &&
g.IO.MouseDownDurationPrev[mouse_button_released] >=
g.IO.KeyRepeatDelay;
584 if (!has_repeated_at_least_once)
586 if (!(flags & ImGuiButtonFlags_NoNavFocus))
587 SetFocusID(
id, window);
594 if (
g.ActiveId ==
id && (item_flags & ImGuiItemFlags_ButtonRepeat))
595 if (
g.IO.MouseDownDuration[
g.ActiveIdMouseButton] > 0.0f && IsMouseClicked(
g.ActiveIdMouseButton, test_owner_id, ImGuiInputFlags_Repeat))
600 g.NavDisableHighlight =
true;
605 if (
g.NavId ==
id && !
g.NavDisableHighlight &&
g.NavDisableMouseHover)
606 if (!(flags & ImGuiButtonFlags_NoHoveredOnFocus))
608 if (
g.NavActivateDownId ==
id)
610 bool nav_activated_by_code = (
g.NavActivateId ==
id);
611 bool nav_activated_by_inputs = (
g.NavActivatePressedId ==
id);
612 if (!nav_activated_by_inputs && (item_flags & ImGuiItemFlags_ButtonRepeat))
615 const ImGuiKeyData* key1 = GetKeyData(ImGuiKey_Space);
616 const ImGuiKeyData* key2 = GetKeyData(ImGuiKey_Enter);
617 const ImGuiKeyData* key3 = GetKeyData(ImGuiKey_NavGamepadActivate);
618 const float t1 = ImMax(ImMax(key1->DownDuration, key2->DownDuration), key3->DownDuration);
619 nav_activated_by_inputs = CalcTypematicRepeatAmount(t1 -
g.IO.DeltaTime, t1,
g.IO.KeyRepeatDelay,
g.IO.KeyRepeatRate) > 0;
621 if (nav_activated_by_code || nav_activated_by_inputs)
625 SetActiveID(
id, window);
626 g.ActiveIdSource =
g.NavInputSource;
627 if (!(flags & ImGuiButtonFlags_NoNavFocus) && !(
g.NavActivateFlags & ImGuiActivateFlags_FromShortcut))
628 SetFocusID(
id, window);
629 if (
g.NavActivateFlags & ImGuiActivateFlags_FromShortcut)
630 g.ActiveIdFromShortcut =
true;
636 if (
g.ActiveId ==
id)
638 if (
g.ActiveIdSource == ImGuiInputSource_Mouse)
640 if (
g.ActiveIdIsJustActivated)
641 g.ActiveIdClickOffset =
g.IO.MousePos - bb.Min;
643 const int mouse_button =
g.ActiveIdMouseButton;
644 if (mouse_button == -1)
649 else if (IsMouseDown(mouse_button, test_owner_id))
655 bool release_in = hovered && (flags & ImGuiButtonFlags_PressedOnClickRelease) != 0;
656 bool release_anywhere = (flags & ImGuiButtonFlags_PressedOnClickReleaseAnywhere) != 0;
657 if ((release_in || release_anywhere) && !
g.DragDropActive)
660 bool is_double_click_release = (flags & ImGuiButtonFlags_PressedOnDoubleClick) &&
g.IO.MouseReleased[mouse_button] &&
g.IO.MouseClickedLastCount[mouse_button] == 2;
661 bool is_repeating_already = (item_flags & ImGuiItemFlags_ButtonRepeat) &&
g.IO.MouseDownDurationPrev[mouse_button] >=
g.IO.KeyRepeatDelay;
662 bool is_button_avail_or_owned = TestKeyOwner(MouseButtonToKey(mouse_button), test_owner_id);
663 if (!is_double_click_release && !is_repeating_already && is_button_avail_or_owned)
668 if (!(flags & ImGuiButtonFlags_NoNavFocus))
669 g.NavDisableHighlight =
true;
671 else if (
g.ActiveIdSource == ImGuiInputSource_Keyboard ||
g.ActiveIdSource == ImGuiInputSource_Gamepad)
674 if (
g.NavActivateDownId ==
id)
680 g.ActiveIdHasBeenPressedBefore =
true;
684 if (
g.NavHighlightActivatedId ==
id)
687 if (out_hovered) *out_hovered = hovered;
688 if (out_held) *out_held = held;
693bool ImGui::ButtonEx(
const char* label,
const ImVec2& size_arg, ImGuiButtonFlags flags)
695 ImGuiWindow* window = GetCurrentWindow();
696 if (window->SkipItems)
700 const ImGuiStyle& style =
g.Style;
701 const ImGuiID
id = window->GetID(label);
702 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
704 ImVec2 pos = window->DC.CursorPos;
705 if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset)
706 pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
707 ImVec2
size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
709 const ImRect bb(pos, pos + size);
710 ItemSize(size, style.FramePadding.y);
711 if (!ItemAdd(bb,
id))
715 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, flags);
718 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
719 RenderNavHighlight(bb,
id);
720 RenderFrame(bb.Min, bb.Max, col,
true, style.FrameRounding);
723 LogSetNextTextDecoration(
"[",
"]");
724 RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, NULL, &label_size, style.ButtonTextAlign, &bb);
730 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
734bool ImGui::Button(
const char* label,
const ImVec2& size_arg)
736 return ButtonEx(label, size_arg, ImGuiButtonFlags_None);
740bool ImGui::SmallButton(
const char* label)
743 float backup_padding_y =
g.Style.FramePadding.y;
744 g.Style.FramePadding.y = 0.0f;
745 bool pressed = ButtonEx(label, ImVec2(0, 0), ImGuiButtonFlags_AlignTextBaseLine);
746 g.Style.FramePadding.y = backup_padding_y;
752bool ImGui::InvisibleButton(
const char* str_id,
const ImVec2& size_arg, ImGuiButtonFlags flags)
755 ImGuiWindow* window = GetCurrentWindow();
756 if (window->SkipItems)
760 IM_ASSERT(size_arg.x != 0.0f && size_arg.y != 0.0f);
762 const ImGuiID
id = window->GetID(str_id);
763 ImVec2
size = CalcItemSize(size_arg, 0.0f, 0.0f);
764 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
766 if (!ItemAdd(bb,
id))
770 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, flags);
772 IMGUI_TEST_ENGINE_ITEM_INFO(
id, str_id,
g.LastItemData.StatusFlags);
776bool ImGui::ArrowButtonEx(
const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiButtonFlags flags)
779 ImGuiWindow* window = GetCurrentWindow();
780 if (window->SkipItems)
783 const ImGuiID
id = window->GetID(str_id);
784 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
785 const float default_size = GetFrameHeight();
786 ItemSize(size, (
size.y >= default_size) ?
g.Style.FramePadding.y : -1.0f);
787 if (!ItemAdd(bb,
id))
791 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, flags);
794 const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
795 const ImU32 text_col = GetColorU32(ImGuiCol_Text);
796 RenderNavHighlight(bb,
id);
797 RenderFrame(bb.Min, bb.Max, bg_col,
true,
g.Style.FrameRounding);
798 RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (
size.x -
g.FontSize) * 0.5f), ImMax(0.0f, (
size.y -
g.FontSize) * 0.5f)), text_col, dir);
800 IMGUI_TEST_ENGINE_ITEM_INFO(
id, str_id,
g.LastItemData.StatusFlags);
804bool ImGui::ArrowButton(
const char* str_id, ImGuiDir dir)
806 float sz = GetFrameHeight();
807 return ArrowButtonEx(str_id, dir, ImVec2(sz, sz), ImGuiButtonFlags_None);
811bool ImGui::CloseButton(ImGuiID
id,
const ImVec2& pos)
814 ImGuiWindow* window =
g.CurrentWindow;
818 const ImRect bb(pos, pos + ImVec2(
g.FontSize,
g.FontSize));
819 ImRect bb_interact = bb;
820 const float area_to_visible_ratio = window->OuterRectClipped.GetArea() / bb.GetArea();
821 if (area_to_visible_ratio < 1.5f)
822 bb_interact.Expand(ImTrunc(bb_interact.GetSize() * -0.25f));
826 bool is_clipped = !ItemAdd(bb_interact,
id);
829 bool pressed = ButtonBehavior(bb_interact,
id, &hovered, &held);
835 ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
836 ImVec2 center = bb.GetCenter();
838 window->DrawList->AddCircleFilled(center, ImMax(2.0f,
g.FontSize * 0.5f + 1.0f), col);
840 float cross_extent =
g.FontSize * 0.5f * 0.7071f - 1.0f;
841 ImU32 cross_col = GetColorU32(ImGuiCol_Text);
842 center -= ImVec2(0.5f, 0.5f);
843 window->DrawList->AddLine(center + ImVec2(+cross_extent, +cross_extent), center + ImVec2(-cross_extent, -cross_extent), cross_col, 1.0f);
844 window->DrawList->AddLine(center + ImVec2(+cross_extent, -cross_extent), center + ImVec2(-cross_extent, +cross_extent), cross_col, 1.0f);
850bool ImGui::CollapseButton(ImGuiID
id,
const ImVec2& pos, ImGuiDockNode* dock_node)
853 ImGuiWindow* window =
g.CurrentWindow;
855 ImRect bb(pos, pos + ImVec2(
g.FontSize,
g.FontSize));
856 bool is_clipped = !ItemAdd(bb,
id);
858 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, ImGuiButtonFlags_None);
864 ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
865 ImU32 text_col = GetColorU32(ImGuiCol_Text);
867 window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f),
g.FontSize * 0.5f + 1.0f, bg_col);
870 RenderArrowDockMenu(window->DrawList, bb.Min,
g.FontSize, text_col);
872 RenderArrow(window->DrawList, bb.Min, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
875 if (IsItemActive() && IsMouseDragging(0))
876 StartMouseMovingWindowOrNode(window, dock_node,
true);
881ImGuiID ImGui::GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
883 return window->GetID(axis == ImGuiAxis_X ?
"#SCROLLX" :
"#SCROLLY");
887ImRect ImGui::GetWindowScrollbarRect(ImGuiWindow* window, ImGuiAxis axis)
889 const ImRect outer_rect = window->Rect();
890 const ImRect inner_rect = window->InnerRect;
891 const float border_size = window->WindowBorderSize;
892 const float scrollbar_size = window->ScrollbarSizes[axis ^ 1];
893 IM_ASSERT(scrollbar_size > 0.0f);
894 if (axis == ImGuiAxis_X)
895 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);
897 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);
900void ImGui::Scrollbar(ImGuiAxis axis)
903 ImGuiWindow* window =
g.CurrentWindow;
904 const ImGuiID
id = GetWindowScrollbarID(window, axis);
907 ImRect bb = GetWindowScrollbarRect(window, axis);
908 ImDrawFlags rounding_corners = ImDrawFlags_RoundCornersNone;
909 if (axis == ImGuiAxis_X)
911 rounding_corners |= ImDrawFlags_RoundCornersBottomLeft;
912 if (!window->ScrollbarY)
913 rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
917 if ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar))
918 rounding_corners |= ImDrawFlags_RoundCornersTopRight;
919 if (!window->ScrollbarX)
920 rounding_corners |= ImDrawFlags_RoundCornersBottomRight;
922 float size_avail = window->InnerRect.Max[axis] - window->InnerRect.Min[axis];
923 float size_contents = window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f;
924 ImS64 scroll = (ImS64)window->Scroll[axis];
925 ScrollbarEx(bb,
id, axis, &scroll, (ImS64)size_avail, (ImS64)size_contents, rounding_corners);
926 window->Scroll[axis] = (float)scroll;
935bool ImGui::ScrollbarEx(
const ImRect& bb_frame, ImGuiID
id, ImGuiAxis axis, ImS64* p_scroll_v, ImS64 size_avail_v, ImS64 size_contents_v, ImDrawFlags flags)
938 ImGuiWindow* window =
g.CurrentWindow;
939 if (window->SkipItems)
942 const float bb_frame_width = bb_frame.GetWidth();
943 const float bb_frame_height = bb_frame.GetHeight();
944 if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f)
949 if ((axis == ImGuiAxis_Y) && bb_frame_height <
g.FontSize +
g.Style.FramePadding.y * 2.0f)
950 alpha = ImSaturate((bb_frame_height -
g.FontSize) / (
g.Style.FramePadding.y * 2.0f));
954 const ImGuiStyle& style =
g.Style;
955 const bool allow_interaction = (alpha >= 1.0f);
957 ImRect bb = bb_frame;
958 bb.Expand(ImVec2(-ImClamp(IM_TRUNC((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp(IM_TRUNC((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f)));
961 const float scrollbar_size_v = (axis == ImGuiAxis_X) ? bb.GetWidth() : bb.GetHeight();
965 IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f);
966 const ImS64 win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), (ImS64)1);
967 const float grab_h_pixels = ImClamp(scrollbar_size_v * ((
float)size_avail_v / (
float)win_size_v), style.GrabMinSize, scrollbar_size_v);
968 const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
972 bool hovered =
false;
973 ItemAdd(bb_frame,
id, NULL, ImGuiItemFlags_NoNav);
974 ButtonBehavior(bb,
id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
976 const ImS64 scroll_max = ImMax((ImS64)1, size_contents_v - size_avail_v);
977 float scroll_ratio = ImSaturate((
float)*p_scroll_v / (
float)scroll_max);
978 float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
979 if (held && allow_interaction && grab_h_norm < 1.0f)
981 const float scrollbar_pos_v = bb.Min[axis];
982 const float mouse_pos_v =
g.IO.MousePos[axis];
985 const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
987 bool seek_absolute =
false;
988 if (
g.ActiveIdIsJustActivated)
991 seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm);
993 g.ScrollbarClickDeltaToGrabCenter = 0.0f;
995 g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
1000 const float scroll_v_norm = ImSaturate((clicked_v_norm -
g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm));
1001 *p_scroll_v = (ImS64)(scroll_v_norm * scroll_max);
1004 scroll_ratio = ImSaturate((
float)*p_scroll_v / (
float)scroll_max);
1005 grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
1009 g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
1013 const ImU32 bg_col = GetColorU32(ImGuiCol_ScrollbarBg);
1014 const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha);
1015 window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, bg_col, window->WindowRounding, flags);
1017 if (axis == ImGuiAxis_X)
1018 grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y);
1020 grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels);
1021 window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);
1028void ImGui::Image(ImTextureID user_texture_id,
const ImVec2& image_size,
const ImVec2& uv0,
const ImVec2& uv1,
const ImVec4& tint_col,
const ImVec4& border_col)
1030 ImGuiWindow* window = GetCurrentWindow();
1031 if (window->SkipItems)
1034 const float border_size = (border_col.w > 0.0f) ? 1.0f : 0.0f;
1035 const ImVec2 padding(border_size, border_size);
1036 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + image_size + padding * 2.0f);
1038 if (!ItemAdd(bb, 0))
1042 if (border_size > 0.0f)
1043 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(border_col), 0.0f, ImDrawFlags_None, border_size);
1044 window->DrawList->AddImage(user_texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));
1049bool ImGui::ImageButtonEx(ImGuiID
id, ImTextureID texture_id,
const ImVec2& image_size,
const ImVec2& uv0,
const ImVec2& uv1,
const ImVec4& bg_col,
const ImVec4& tint_col, ImGuiButtonFlags flags)
1052 ImGuiWindow* window = GetCurrentWindow();
1053 if (window->SkipItems)
1056 const ImVec2 padding =
g.Style.FramePadding;
1057 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + image_size + padding * 2.0f);
1059 if (!ItemAdd(bb,
id))
1063 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, flags);
1066 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
1067 RenderNavHighlight(bb,
id);
1068 RenderFrame(bb.Min, bb.Max, col,
true, ImClamp((
float)ImMin(padding.x, padding.y), 0.0f,
g.Style.FrameRounding));
1069 if (bg_col.w > 0.0f)
1070 window->DrawList->AddRectFilled(bb.Min + padding, bb.Max - padding, GetColorU32(bg_col));
1071 window->DrawList->AddImage(texture_id, bb.Min + padding, bb.Max - padding, uv0, uv1, GetColorU32(tint_col));
1077bool ImGui::ImageButton(
const char* str_id, ImTextureID user_texture_id,
const ImVec2& image_size,
const ImVec2& uv0,
const ImVec2& uv1,
const ImVec4& bg_col,
const ImVec4& tint_col)
1080 ImGuiWindow* window =
g.CurrentWindow;
1081 if (window->SkipItems)
1084 return ImageButtonEx(window->GetID(str_id), user_texture_id, image_size, uv0, uv1, bg_col, tint_col);
1087#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1092bool 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)
1095 ImGuiWindow* window =
g.CurrentWindow;
1096 if (window->SkipItems)
1100 PushID((
void*)(intptr_t)user_texture_id);
1101 const ImGuiID
id = window->GetID(
"#image");
1104 if (frame_padding >= 0)
1105 PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2((
float)frame_padding, (
float)frame_padding));
1106 bool ret = ImageButtonEx(
id, user_texture_id, size, uv0, uv1, bg_col, tint_col);
1107 if (frame_padding >= 0)
1113bool ImGui::Checkbox(
const char* label,
bool* v)
1115 ImGuiWindow* window = GetCurrentWindow();
1116 if (window->SkipItems)
1120 const ImGuiStyle& style =
g.Style;
1121 const ImGuiID
id = window->GetID(label);
1122 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
1124 const float square_sz = GetFrameHeight();
1125 const ImVec2 pos = window->DC.CursorPos;
1126 const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
1127 ItemSize(total_bb, style.FramePadding.y);
1128 if (!ItemAdd(total_bb,
id))
1130 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
1135 bool pressed = ButtonBehavior(total_bb,
id, &hovered, &held);
1142 const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
1143 RenderNavHighlight(total_bb,
id);
1144 RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
1145 ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
1146 bool mixed_value = (
g.LastItemData.InFlags & ImGuiItemFlags_MixedValue) != 0;
1151 ImVec2 pad(ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)), ImMax(1.0f, IM_TRUNC(square_sz / 3.6f)));
1152 window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
1156 const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f));
1157 RenderCheckMark(window->DrawList, check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad * 2.0f);
1160 ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
1162 LogRenderedText(&label_pos, mixed_value ?
"[~]" : *v ?
"[x]" :
"[ ]");
1163 if (label_size.x > 0.0f)
1164 RenderText(label_pos, label);
1166 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
1171bool ImGui::CheckboxFlagsT(
const char* label, T* flags, T flags_value)
1173 bool all_on = (*flags & flags_value) == flags_value;
1174 bool any_on = (*flags & flags_value) != 0;
1176 if (!all_on && any_on)
1179 g.NextItemData.ItemFlags |= ImGuiItemFlags_MixedValue;
1180 pressed =
Checkbox(label, &all_on);
1184 pressed =
Checkbox(label, &all_on);
1190 *flags |= flags_value;
1192 *flags &= ~flags_value;
1197bool ImGui::CheckboxFlags(
const char* label,
int* flags,
int flags_value)
1199 return CheckboxFlagsT(label, flags, flags_value);
1202bool ImGui::CheckboxFlags(
const char* label,
unsigned int* flags,
unsigned int flags_value)
1204 return CheckboxFlagsT(label, flags, flags_value);
1207bool ImGui::CheckboxFlags(
const char* label, ImS64* flags, ImS64 flags_value)
1209 return CheckboxFlagsT(label, flags, flags_value);
1212bool ImGui::CheckboxFlags(
const char* label, ImU64* flags, ImU64 flags_value)
1214 return CheckboxFlagsT(label, flags, flags_value);
1217bool ImGui::RadioButton(
const char* label,
bool active)
1219 ImGuiWindow* window = GetCurrentWindow();
1220 if (window->SkipItems)
1224 const ImGuiStyle& style =
g.Style;
1225 const ImGuiID
id = window->GetID(label);
1226 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
1228 const float square_sz = GetFrameHeight();
1229 const ImVec2 pos = window->DC.CursorPos;
1230 const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
1231 const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
1232 ItemSize(total_bb, style.FramePadding.y);
1233 if (!ItemAdd(total_bb,
id))
1236 ImVec2 center = check_bb.GetCenter();
1237 center.x = IM_ROUND(center.x);
1238 center.y = IM_ROUND(center.y);
1239 const float radius = (square_sz - 1.0f) * 0.5f;
1242 bool pressed = ButtonBehavior(total_bb,
id, &hovered, &held);
1246 RenderNavHighlight(total_bb,
id);
1247 const int num_segment = window->DrawList->_CalcCircleAutoSegmentCount(radius);
1248 window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), num_segment);
1251 const float pad = ImMax(1.0f, IM_TRUNC(square_sz / 6.0f));
1252 window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark));
1255 if (style.FrameBorderSize > 0.0f)
1257 window->DrawList->AddCircle(center + ImVec2(1, 1), radius, GetColorU32(ImGuiCol_BorderShadow), num_segment, style.FrameBorderSize);
1258 window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), num_segment, style.FrameBorderSize);
1261 ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
1263 LogRenderedText(&label_pos, active ?
"(x)" :
"( )");
1264 if (label_size.x > 0.0f)
1265 RenderText(label_pos, label);
1267 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
1272bool ImGui::RadioButton(
const char* label,
int* v,
int v_button)
1274 const bool pressed = RadioButton(label, *v == v_button);
1281void ImGui::ProgressBar(
float fraction,
const ImVec2& size_arg,
const char* overlay)
1283 ImGuiWindow* window = GetCurrentWindow();
1284 if (window->SkipItems)
1288 const ImGuiStyle& style =
g.Style;
1290 ImVec2 pos = window->DC.CursorPos;
1291 ImVec2
size = CalcItemSize(size_arg, CalcItemWidth(),
g.FontSize + style.FramePadding.y * 2.0f);
1292 ImRect bb(pos, pos + size);
1293 ItemSize(size, style.FramePadding.y);
1294 if (!ItemAdd(bb, 0))
1298 fraction = ImSaturate(fraction);
1299 RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg),
true, style.FrameRounding);
1300 bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
1301 const ImVec2 fill_br = ImVec2(ImLerp(bb.Min.x, bb.Max.x, fraction), bb.Max.y);
1302 RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0f, fraction, style.FrameRounding);
1305 char overlay_buf[32];
1308 ImFormatString(overlay_buf, IM_ARRAYSIZE(overlay_buf),
"%.0f%%", fraction * 100 + 0.01f);
1309 overlay = overlay_buf;
1313 if (overlay_size.x > 0.0f)
1314 RenderTextClipped(ImVec2(ImClamp(fill_br.x + style.ItemSpacing.x, bb.Min.x, bb.Max.x - overlay_size.x - style.ItemInnerSpacing.x), bb.Min.y), bb.Max, overlay, NULL, &overlay_size, ImVec2(0.0f, 0.5f), &bb);
1319 ImGuiWindow* window = GetCurrentWindow();
1320 if (window->SkipItems)
1324 const ImGuiStyle& style =
g.Style;
1325 const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y,
g.FontSize + style.FramePadding.y * 2),
g.FontSize);
1326 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(
g.FontSize, line_height));
1328 if (!ItemAdd(bb, 0))
1330 SameLine(0, style.FramePadding.x * 2);
1335 ImU32 text_col = GetColorU32(ImGuiCol_Text);
1336 RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x +
g.FontSize * 0.5f, line_height * 0.5f), text_col);
1337 SameLine(0, style.FramePadding.x * 2.0f);
1353void ImGui::Spacing()
1355 ImGuiWindow* window = GetCurrentWindow();
1356 if (window->SkipItems)
1358 ItemSize(ImVec2(0, 0));
1361void ImGui::Dummy(
const ImVec2& size)
1363 ImGuiWindow* window = GetCurrentWindow();
1364 if (window->SkipItems)
1367 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
1372void ImGui::NewLine()
1374 ImGuiWindow* window = GetCurrentWindow();
1375 if (window->SkipItems)
1379 const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
1380 window->DC.LayoutType = ImGuiLayoutType_Vertical;
1381 window->DC.IsSameLine =
false;
1382 if (window->DC.CurrLineSize.y > 0.0f)
1383 ItemSize(ImVec2(0, 0));
1385 ItemSize(ImVec2(0.0f,
g.FontSize));
1386 window->DC.LayoutType = backup_layout_type;
1389void ImGui::AlignTextToFramePadding()
1391 ImGuiWindow* window = GetCurrentWindow();
1392 if (window->SkipItems)
1396 window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y,
g.FontSize +
g.Style.FramePadding.y * 2);
1397 window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset,
g.Style.FramePadding.y);
1403void ImGui::SeparatorEx(ImGuiSeparatorFlags flags,
float thickness)
1405 ImGuiWindow* window = GetCurrentWindow();
1406 if (window->SkipItems)
1410 IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)));
1411 IM_ASSERT(thickness > 0.0f);
1413 if (flags & ImGuiSeparatorFlags_Vertical)
1416 float y1 = window->DC.CursorPos.y;
1417 float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y;
1418 const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness, y2));
1419 ItemSize(ImVec2(thickness, 0.0f));
1420 if (!ItemAdd(bb, 0))
1424 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));
1428 else if (flags & ImGuiSeparatorFlags_Horizontal)
1431 float x1 = window->DC.CursorPos.x;
1432 float x2 = window->WorkRect.Max.x;
1437 ImGuiOldColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL;
1440 x1 = window->Pos.x + window->DC.Indent.x;
1441 x2 = window->Pos.x + window->Size.x;
1442 PushColumnsBackground();
1447 const float thickness_for_layout = (thickness == 1.0f) ? 0.0f : thickness;
1448 const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness));
1449 ItemSize(ImVec2(0.0f, thickness_for_layout));
1454 window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_Separator));
1456 LogRenderedText(&bb.Min,
"--------------------------------\n");
1461 PopColumnsBackground();
1462 columns->LineMinY = window->DC.CursorPos.y;
1467void ImGui::Separator()
1470 ImGuiWindow* window =
g.CurrentWindow;
1471 if (window->SkipItems)
1476 ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
1479 if (window->DC.CurrentColumns)
1480 flags |= ImGuiSeparatorFlags_SpanAllColumns;
1482 SeparatorEx(flags, 1.0f);
1485void ImGui::SeparatorTextEx(ImGuiID
id,
const char* label,
const char* label_end,
float extra_w)
1488 ImGuiWindow* window =
g.CurrentWindow;
1489 ImGuiStyle& style =
g.Style;
1491 const ImVec2 label_size =
CalcTextSize(label, label_end,
false);
1492 const ImVec2 pos = window->DC.CursorPos;
1493 const ImVec2 padding = style.SeparatorTextPadding;
1495 const float separator_thickness = style.SeparatorTextBorderSize;
1496 const ImVec2 min_size(label_size.x + extra_w + padding.x * 2.0f, ImMax(label_size.y + padding.y * 2.0f, separator_thickness));
1497 const ImRect bb(pos, ImVec2(window->WorkRect.Max.x, pos.y + min_size.y));
1498 const float text_baseline_y = ImTrunc((bb.GetHeight() - label_size.y) * style.SeparatorTextAlign.y + 0.99999f);
1499 ItemSize(min_size, text_baseline_y);
1500 if (!ItemAdd(bb,
id))
1503 const float sep1_x1 = pos.x;
1504 const float sep2_x2 = bb.Max.x;
1505 const float seps_y = ImTrunc((bb.Min.y + bb.Max.y) * 0.5f + 0.99999f);
1507 const float label_avail_w = ImMax(0.0f, sep2_x2 - sep1_x1 - padding.x * 2.0f);
1508 const ImVec2 label_pos(pos.x + padding.x + ImMax(0.0f, (label_avail_w - label_size.x - extra_w) * style.SeparatorTextAlign.x), pos.y + text_baseline_y);
1511 window->DC.CursorPosPrevLine.x = label_pos.x + label_size.x;
1513 const ImU32 separator_col = GetColorU32(ImGuiCol_Separator);
1514 if (label_size.x > 0.0f)
1516 const float sep1_x2 = label_pos.x - style.ItemSpacing.x;
1517 const float sep2_x1 = label_pos.x + label_size.x + extra_w + style.ItemSpacing.x;
1518 if (sep1_x2 > sep1_x1 && separator_thickness > 0.0f)
1519 window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep1_x2, seps_y), separator_col, separator_thickness);
1520 if (sep2_x2 > sep2_x1 && separator_thickness > 0.0f)
1521 window->DrawList->AddLine(ImVec2(sep2_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
1523 LogSetNextTextDecoration(
"---", NULL);
1524 RenderTextEllipsis(window->DrawList, label_pos, ImVec2(bb.Max.x, bb.Max.y + style.ItemSpacing.y), bb.Max.x, bb.Max.x, label, label_end, &label_size);
1530 if (separator_thickness > 0.0f)
1531 window->DrawList->AddLine(ImVec2(sep1_x1, seps_y), ImVec2(sep2_x2, seps_y), separator_col, separator_thickness);
1535void ImGui::SeparatorText(
const char* label)
1537 ImGuiWindow* window = GetCurrentWindow();
1538 if (window->SkipItems)
1547 SeparatorTextEx(0, label, FindRenderedTextEnd(label), 0.0f);
1551bool ImGui::SplitterBehavior(
const ImRect& bb, ImGuiID
id, ImGuiAxis axis,
float* size1,
float* size2,
float min_size1,
float min_size2,
float hover_extend,
float hover_visibility_delay, ImU32 bg_col)
1554 ImGuiWindow* window =
g.CurrentWindow;
1556 if (!ItemAdd(bb,
id, NULL, ImGuiItemFlags_NoNav))
1562 ImGuiButtonFlags button_flags = ImGuiButtonFlags_FlattenChildren;
1563#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1564 button_flags |= ImGuiButtonFlags_AllowOverlap;
1568 ImRect bb_interact = bb;
1569 bb_interact.Expand(axis == ImGuiAxis_Y ? ImVec2(0.0f, hover_extend) : ImVec2(hover_extend, 0.0f));
1570 ButtonBehavior(bb_interact,
id, &hovered, &held, button_flags);
1572 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredRect;
1574 if (held || (hovered &&
g.HoveredIdPreviousFrame ==
id &&
g.HoveredIdTimer >= hover_visibility_delay))
1575 SetMouseCursor(axis == ImGuiAxis_Y ? ImGuiMouseCursor_ResizeNS : ImGuiMouseCursor_ResizeEW);
1577 ImRect bb_render = bb;
1580 float mouse_delta = (
g.IO.MousePos -
g.ActiveIdClickOffset - bb_interact.Min)[axis];
1583 float size_1_maximum_delta = ImMax(0.0f, *size1 - min_size1);
1584 float size_2_maximum_delta = ImMax(0.0f, *size2 - min_size2);
1585 if (mouse_delta < -size_1_maximum_delta)
1586 mouse_delta = -size_1_maximum_delta;
1587 if (mouse_delta > size_2_maximum_delta)
1588 mouse_delta = size_2_maximum_delta;
1591 if (mouse_delta != 0.0f)
1593 *size1 = ImMax(*size1 + mouse_delta, min_size1);
1594 *size2 = ImMax(*size2 - mouse_delta, min_size2);
1595 bb_render.Translate((axis == ImGuiAxis_X) ? ImVec2(mouse_delta, 0.0f) : ImVec2(0.0f, mouse_delta));
1601 if (bg_col & IM_COL32_A_MASK)
1602 window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, bg_col, 0.0f);
1603 const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : (hovered &&
g.HoveredIdTimer >= hover_visibility_delay) ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
1604 window->DrawList->AddRectFilled(bb_render.Min, bb_render.Max, col, 0.0f);
1609static int IMGUI_CDECL ShrinkWidthItemComparer(
const void* lhs,
const void* rhs)
1611 const ImGuiShrinkWidthItem* a = (
const ImGuiShrinkWidthItem*)lhs;
1612 const ImGuiShrinkWidthItem* b = (
const ImGuiShrinkWidthItem*)rhs;
1613 if (
int d = (
int)(b->Width - a->Width))
1615 return (b->Index - a->Index);
1620void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items,
int count,
float width_excess)
1624 if (items[0].Width >= 0.0f)
1625 items[0].Width = ImMax(items[0].Width - width_excess, 1.0f);
1628 ImQsort(items, (
size_t)count,
sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
1629 int count_same_width = 1;
1630 while (width_excess > 0.0f && count_same_width < count)
1632 while (count_same_width < count && items[0].Width <= items[count_same_width].Width)
1634 float max_width_to_remove_per_item = (count_same_width <
count && items[count_same_width].Width >= 0.0f) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
1635 if (max_width_to_remove_per_item <= 0.0f)
1637 float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);
1638 for (
int item_n = 0; item_n < count_same_width; item_n++)
1639 items[item_n].Width -= width_to_remove_per_item;
1640 width_excess -= width_to_remove_per_item * count_same_width;
1645 width_excess = 0.0f;
1646 for (
int n = 0; n <
count; n++)
1648 float width_rounded = ImTrunc(items[n].Width);
1649 width_excess += items[n].Width - width_rounded;
1650 items[n].Width = width_rounded;
1652 while (width_excess > 0.0f)
1653 for (
int n = 0; n < count && width_excess > 0.0f; n++)
1655 float width_to_add = ImMin(items[n].InitialWidth - items[n].Width, 1.0f);
1656 items[n].Width += width_to_add;
1657 width_excess -= width_to_add;
1673static float CalcMaxPopupHeightFromItemCount(
int items_count)
1676 if (items_count <= 0)
1678 return (
g.FontSize +
g.Style.ItemSpacing.y) * items_count -
g.Style.ItemSpacing.y + (
g.Style.WindowPadding.y * 2);
1681bool ImGui::BeginCombo(
const char* label,
const char* preview_value, ImGuiComboFlags flags)
1684 ImGuiWindow* window = GetCurrentWindow();
1686 ImGuiNextWindowDataFlags backup_next_window_data_flags =
g.NextWindowData.Flags;
1687 g.NextWindowData.ClearFlags();
1688 if (window->SkipItems)
1691 const ImGuiStyle& style =
g.Style;
1692 const ImGuiID
id = window->GetID(label);
1693 IM_ASSERT((flags & (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview)) != (ImGuiComboFlags_NoArrowButton | ImGuiComboFlags_NoPreview));
1694 if (flags & ImGuiComboFlags_WidthFitPreview)
1695 IM_ASSERT((flags & (ImGuiComboFlags_NoPreview | (ImGuiComboFlags)ImGuiComboFlags_CustomPreview)) == 0);
1697 const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
1698 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
1699 const float preview_width = ((flags & ImGuiComboFlags_WidthFitPreview) && (preview_value != NULL)) ?
CalcTextSize(preview_value, NULL,
true).x : 0.0f;
1700 const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : ((flags & ImGuiComboFlags_WidthFitPreview) ? (arrow_size + preview_width + style.FramePadding.x * 2.0f) : CalcItemWidth());
1701 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
1702 const ImRect total_bb(bb.Min, bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
1703 ItemSize(total_bb, style.FramePadding.y);
1704 if (!ItemAdd(total_bb,
id, &bb))
1709 bool pressed = ButtonBehavior(bb,
id, &hovered, &held);
1710 const ImGuiID popup_id =
ImHashStr(
"##ComboPopup", 0,
id);
1711 bool popup_open = IsPopupOpen(popup_id, ImGuiPopupFlags_None);
1712 if (pressed && !popup_open)
1714 OpenPopupEx(popup_id, ImGuiPopupFlags_None);
1719 const ImU32 frame_col = GetColorU32(hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
1720 const float value_x2 = ImMax(bb.Min.x, bb.Max.x - arrow_size);
1721 RenderNavHighlight(bb,
id);
1722 if (!(flags & ImGuiComboFlags_NoPreview))
1723 window->DrawList->AddRectFilled(bb.Min, ImVec2(value_x2, bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersLeft);
1724 if (!(flags & ImGuiComboFlags_NoArrowButton))
1726 ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
1727 ImU32 text_col = GetColorU32(ImGuiCol_Text);
1728 window->DrawList->AddRectFilled(ImVec2(value_x2, bb.Min.y), bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawFlags_RoundCornersAll : ImDrawFlags_RoundCornersRight);
1729 if (value_x2 + arrow_size - style.FramePadding.x <= bb.Max.x)
1730 RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f);
1732 RenderFrameBorder(bb.Min, bb.Max, style.FrameRounding);
1735 if (flags & ImGuiComboFlags_CustomPreview)
1737 g.ComboPreviewData.PreviewRect = ImRect(bb.Min.x, bb.Min.y, value_x2, bb.Max.y);
1738 IM_ASSERT(preview_value == NULL || preview_value[0] == 0);
1739 preview_value = NULL;
1743 if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
1746 LogSetNextTextDecoration(
"{",
"}");
1747 RenderTextClipped(bb.Min + style.FramePadding, ImVec2(value_x2, bb.Max.y), preview_value, NULL, NULL);
1749 if (label_size.x > 0)
1750 RenderText(ImVec2(bb.Max.x + style.ItemInnerSpacing.x, bb.Min.y + style.FramePadding.y), label);
1755 g.NextWindowData.Flags = backup_next_window_data_flags;
1756 return BeginComboPopup(popup_id, bb, flags);
1759bool ImGui::BeginComboPopup(ImGuiID popup_id,
const ImRect& bb, ImGuiComboFlags flags)
1762 if (!IsPopupOpen(popup_id, ImGuiPopupFlags_None))
1764 g.NextWindowData.ClearFlags();
1769 float w = bb.GetWidth();
1770 if (
g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
1772 g.NextWindowData.SizeConstraintRect.Min.x = ImMax(
g.NextWindowData.SizeConstraintRect.Min.x, w);
1776 if ((flags & ImGuiComboFlags_HeightMask_) == 0)
1777 flags |= ImGuiComboFlags_HeightRegular;
1778 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiComboFlags_HeightMask_));
1779 int popup_max_height_in_items = -1;
1780 if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
1781 else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
1782 else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
1783 ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);
1784 if ((
g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 ||
g.NextWindowData.SizeVal.x <= 0.0f)
1785 constraint_min.x = w;
1786 if ((
g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 ||
g.NextWindowData.SizeVal.y <= 0.0f)
1787 constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
1788 SetNextWindowSizeConstraints(constraint_min, constraint_max);
1793 ImFormatString(name, IM_ARRAYSIZE(name),
"##Combo_%02d",
g.BeginComboDepth);
1798 if (ImGuiWindow* popup_window = FindWindowByName(name))
1799 if (popup_window->WasActive)
1802 ImVec2 size_expected = CalcWindowNextAutoFitSize(popup_window);
1803 popup_window->AutoPosLastDirection = (flags & ImGuiComboFlags_PopupAlignLeft) ? ImGuiDir_Left : ImGuiDir_Down;
1804 ImRect r_outer = GetPopupAllowedExtentRect(popup_window);
1805 ImVec2 pos = FindBestWindowPosForPopupEx(bb.GetBL(), size_expected, &popup_window->AutoPosLastDirection, r_outer, bb, ImGuiPopupPositionPolicy_ComboBox);
1806 SetNextWindowPos(pos);
1810 ImGuiWindowFlags window_flags = ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_Popup | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoMove;
1811 PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(
g.Style.FramePadding.x,
g.Style.WindowPadding.y));
1812 bool ret = Begin(name, NULL, window_flags);
1820 g.BeginComboDepth++;
1824void ImGui::EndCombo()
1828 g.BeginComboDepth--;
1833bool ImGui::BeginComboPreview()
1836 ImGuiWindow* window =
g.CurrentWindow;
1837 ImGuiComboPreviewData* preview_data = &
g.ComboPreviewData;
1839 if (window->SkipItems || !(
g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible))
1841 IM_ASSERT(
g.LastItemData.Rect.Min.x == preview_data->PreviewRect.Min.x &&
g.LastItemData.Rect.Min.y == preview_data->PreviewRect.Min.y);
1842 if (!window->ClipRect.Overlaps(preview_data->PreviewRect))
1846 preview_data->BackupCursorPos = window->DC.CursorPos;
1847 preview_data->BackupCursorMaxPos = window->DC.CursorMaxPos;
1848 preview_data->BackupCursorPosPrevLine = window->DC.CursorPosPrevLine;
1849 preview_data->BackupPrevLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
1850 preview_data->BackupLayout = window->DC.LayoutType;
1851 window->DC.CursorPos = preview_data->PreviewRect.Min +
g.Style.FramePadding;
1852 window->DC.CursorMaxPos = window->DC.CursorPos;
1853 window->DC.LayoutType = ImGuiLayoutType_Horizontal;
1854 window->DC.IsSameLine =
false;
1855 PushClipRect(preview_data->PreviewRect.Min, preview_data->PreviewRect.Max,
true);
1860void ImGui::EndComboPreview()
1863 ImGuiWindow* window =
g.CurrentWindow;
1864 ImGuiComboPreviewData* preview_data = &
g.ComboPreviewData;
1867 ImDrawList* draw_list = window->DrawList;
1868 if (window->DC.CursorMaxPos.x < preview_data->PreviewRect.Max.x && window->DC.CursorMaxPos.y < preview_data->PreviewRect.Max.y)
1869 if (draw_list->CmdBuffer.Size > 1)
1871 draw_list->_CmdHeader.ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ClipRect = draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 2].ClipRect;
1872 draw_list->_TryMergeDrawCmds();
1875 window->DC.CursorPos = preview_data->BackupCursorPos;
1876 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, preview_data->BackupCursorMaxPos);
1877 window->DC.CursorPosPrevLine = preview_data->BackupCursorPosPrevLine;
1878 window->DC.PrevLineTextBaseOffset = preview_data->BackupPrevLineTextBaseOffset;
1879 window->DC.LayoutType = preview_data->BackupLayout;
1880 window->DC.IsSameLine =
false;
1881 preview_data->PreviewRect = ImRect();
1885static const char* Items_ArrayGetter(
void* data,
int idx)
1887 const char*
const* items = (
const char*
const*)data;
1892static const char* Items_SingleStringGetter(
void* data,
int idx)
1894 const char* items_separated_by_zeros = (
const char*)data;
1895 int items_count = 0;
1896 const char* p = items_separated_by_zeros;
1899 if (idx == items_count)
1904 return *p ? p : NULL;
1908bool ImGui::Combo(
const char* label,
int* current_item,
const char* (*getter)(
void* user_data,
int idx),
void* user_data,
int items_count,
int popup_max_height_in_items)
1913 const char* preview_value = NULL;
1914 if (*current_item >= 0 && *current_item < items_count)
1915 preview_value = getter(user_data, *current_item);
1918 if (popup_max_height_in_items != -1 && !(
g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))
1919 SetNextWindowSizeConstraints(ImVec2(0, 0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
1921 if (!BeginCombo(label, preview_value, ImGuiComboFlags_None))
1926 bool value_changed =
false;
1927 for (
int i = 0; i < items_count; i++)
1929 const char* item_text = getter(user_data, i);
1930 if (item_text == NULL)
1931 item_text =
"*Unknown item*";
1934 const bool item_selected = (i == *current_item);
1935 if (Selectable(item_text, item_selected) && *current_item != i)
1937 value_changed =
true;
1941 SetItemDefaultFocus();
1948 MarkItemEdited(
g.LastItemData.ID);
1950 return value_changed;
1954bool ImGui::Combo(
const char* label,
int* current_item,
const char*
const items[],
int items_count,
int height_in_items)
1956 const bool value_changed =
Combo(label, current_item, Items_ArrayGetter, (
void*)items, items_count, height_in_items);
1957 return value_changed;
1961bool ImGui::Combo(
const char* label,
int* current_item,
const char* items_separated_by_zeros,
int height_in_items)
1963 int items_count = 0;
1964 const char* p = items_separated_by_zeros;
1970 bool value_changed =
Combo(label, current_item, Items_SingleStringGetter, (
void*)items_separated_by_zeros, items_count, height_in_items);
1971 return value_changed;
1974#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1976struct ImGuiGetNameFromIndexOldToNewCallbackData {
void* UserData; bool (*OldCallback)(
void*, int,
const char**); };
1977static const char* ImGuiGetNameFromIndexOldToNewCallback(
void* user_data,
int idx)
1979 ImGuiGetNameFromIndexOldToNewCallbackData* data = (ImGuiGetNameFromIndexOldToNewCallbackData*)user_data;
1980 const char* s = NULL;
1981 data->OldCallback(data->UserData, idx, &s);
1985bool ImGui::ListBox(
const char* label,
int* current_item,
bool (*old_getter)(
void*,
int,
const char**),
void* user_data,
int items_count,
int height_in_items)
1987 ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
1988 return ListBox(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, height_in_items);
1990bool ImGui::Combo(
const char* label,
int* current_item,
bool (*old_getter)(
void*,
int,
const char**),
void* user_data,
int items_count,
int popup_max_height_in_items)
1992 ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
1993 return Combo(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, popup_max_height_in_items);
2011static const ImGuiDataTypeInfo GDataTypeInfo[] =
2013 {
sizeof(char),
"S8",
"%d",
"%d" },
2014 {
sizeof(
unsigned char),
"U8",
"%u",
"%u" },
2015 {
sizeof(short),
"S16",
"%d",
"%d" },
2016 {
sizeof(
unsigned short),
"U16",
"%u",
"%u" },
2017 {
sizeof(int),
"S32",
"%d",
"%d" },
2018 {
sizeof(
unsigned int),
"U32",
"%u",
"%u" },
2020 {
sizeof(ImS64),
"S64",
"%I64d",
"%I64d" },
2021 {
sizeof(ImU64),
"U64",
"%I64u",
"%I64u" },
2023 {
sizeof(ImS64),
"S64",
"%lld",
"%lld" },
2024 {
sizeof(ImU64),
"U64",
"%llu",
"%llu" },
2026 {
sizeof(float),
"float",
"%.3f",
"%f" },
2027 {
sizeof(double),
"double",
"%f",
"%lf" },
2031const ImGuiDataTypeInfo* ImGui::DataTypeGetInfo(ImGuiDataType data_type)
2033 IM_ASSERT(data_type >= 0 && data_type < ImGuiDataType_COUNT);
2034 return &GDataTypeInfo[data_type];
2037int ImGui::DataTypeFormatString(
char* buf,
int buf_size, ImGuiDataType data_type,
const void* p_data,
const char* format)
2040 if (data_type == ImGuiDataType_S32 || data_type == ImGuiDataType_U32)
2041 return ImFormatString(buf, buf_size, format, *(
const ImU32*)p_data);
2042 if (data_type == ImGuiDataType_S64 || data_type == ImGuiDataType_U64)
2043 return ImFormatString(buf, buf_size, format, *(
const ImU64*)p_data);
2044 if (data_type == ImGuiDataType_Float)
2045 return ImFormatString(buf, buf_size, format, *(
const float*)p_data);
2046 if (data_type == ImGuiDataType_Double)
2047 return ImFormatString(buf, buf_size, format, *(
const double*)p_data);
2048 if (data_type == ImGuiDataType_S8)
2049 return ImFormatString(buf, buf_size, format, *(
const ImS8*)p_data);
2050 if (data_type == ImGuiDataType_U8)
2051 return ImFormatString(buf, buf_size, format, *(
const ImU8*)p_data);
2052 if (data_type == ImGuiDataType_S16)
2053 return ImFormatString(buf, buf_size, format, *(
const ImS16*)p_data);
2054 if (data_type == ImGuiDataType_U16)
2055 return ImFormatString(buf, buf_size, format, *(
const ImU16*)p_data);
2060void ImGui::DataTypeApplyOp(ImGuiDataType data_type,
int op,
void* output,
const void* arg1,
const void* arg2)
2062 IM_ASSERT(op ==
'+' || op ==
'-');
2065 case ImGuiDataType_S8:
2066 if (op ==
'+') { *(ImS8*)output = ImAddClampOverflow(*(
const ImS8*)arg1, *(
const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); }
2067 if (op ==
'-') { *(ImS8*)output = ImSubClampOverflow(*(
const ImS8*)arg1, *(
const ImS8*)arg2, IM_S8_MIN, IM_S8_MAX); }
2069 case ImGuiDataType_U8:
2070 if (op ==
'+') { *(ImU8*)output = ImAddClampOverflow(*(
const ImU8*)arg1, *(
const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); }
2071 if (op ==
'-') { *(ImU8*)output = ImSubClampOverflow(*(
const ImU8*)arg1, *(
const ImU8*)arg2, IM_U8_MIN, IM_U8_MAX); }
2073 case ImGuiDataType_S16:
2074 if (op ==
'+') { *(ImS16*)output = ImAddClampOverflow(*(
const ImS16*)arg1, *(
const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); }
2075 if (op ==
'-') { *(ImS16*)output = ImSubClampOverflow(*(
const ImS16*)arg1, *(
const ImS16*)arg2, IM_S16_MIN, IM_S16_MAX); }
2077 case ImGuiDataType_U16:
2078 if (op ==
'+') { *(ImU16*)output = ImAddClampOverflow(*(
const ImU16*)arg1, *(
const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); }
2079 if (op ==
'-') { *(ImU16*)output = ImSubClampOverflow(*(
const ImU16*)arg1, *(
const ImU16*)arg2, IM_U16_MIN, IM_U16_MAX); }
2081 case ImGuiDataType_S32:
2082 if (op ==
'+') { *(ImS32*)output = ImAddClampOverflow(*(
const ImS32*)arg1, *(
const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); }
2083 if (op ==
'-') { *(ImS32*)output = ImSubClampOverflow(*(
const ImS32*)arg1, *(
const ImS32*)arg2, IM_S32_MIN, IM_S32_MAX); }
2085 case ImGuiDataType_U32:
2086 if (op ==
'+') { *(ImU32*)output = ImAddClampOverflow(*(
const ImU32*)arg1, *(
const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); }
2087 if (op ==
'-') { *(ImU32*)output = ImSubClampOverflow(*(
const ImU32*)arg1, *(
const ImU32*)arg2, IM_U32_MIN, IM_U32_MAX); }
2089 case ImGuiDataType_S64:
2090 if (op ==
'+') { *(ImS64*)output = ImAddClampOverflow(*(
const ImS64*)arg1, *(
const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); }
2091 if (op ==
'-') { *(ImS64*)output = ImSubClampOverflow(*(
const ImS64*)arg1, *(
const ImS64*)arg2, IM_S64_MIN, IM_S64_MAX); }
2093 case ImGuiDataType_U64:
2094 if (op ==
'+') { *(ImU64*)output = ImAddClampOverflow(*(
const ImU64*)arg1, *(
const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); }
2095 if (op ==
'-') { *(ImU64*)output = ImSubClampOverflow(*(
const ImU64*)arg1, *(
const ImU64*)arg2, IM_U64_MIN, IM_U64_MAX); }
2097 case ImGuiDataType_Float:
2098 if (op ==
'+') { *(
float*)output = *(
const float*)arg1 + *(
const float*)arg2; }
2099 if (op ==
'-') { *(
float*)output = *(
const float*)arg1 - *(
const float*)arg2; }
2101 case ImGuiDataType_Double:
2102 if (op ==
'+') { *(
double*)output = *(
const double*)arg1 + *(
const double*)arg2; }
2103 if (op ==
'-') { *(
double*)output = *(
const double*)arg1 - *(
const double*)arg2; }
2105 case ImGuiDataType_COUNT:
break;
2112bool ImGui::DataTypeApplyFromText(
const char* buf, ImGuiDataType data_type,
void* p_data,
const char* format)
2114 while (ImCharIsBlankA(*buf))
2120 const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);
2121 ImGuiDataTypeTempStorage data_backup;
2122 memcpy(&data_backup, p_data, type_info->Size);
2127 char format_sanitized[32];
2128 if (data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double)
2129 format = type_info->ScanFmt;
2135 if (sscanf(buf, format, type_info->Size >= 4 ? p_data : &v32) < 1)
2137 if (type_info->Size < 4)
2139 if (data_type == ImGuiDataType_S8)
2140 *(ImS8*)p_data = (ImS8)ImClamp(v32, (
int)IM_S8_MIN, (
int)IM_S8_MAX);
2141 else if (data_type == ImGuiDataType_U8)
2142 *(ImU8*)p_data = (ImU8)ImClamp(v32, (
int)IM_U8_MIN, (
int)IM_U8_MAX);
2143 else if (data_type == ImGuiDataType_S16)
2144 *(ImS16*)p_data = (ImS16)ImClamp(v32, (
int)IM_S16_MIN, (
int)IM_S16_MAX);
2145 else if (data_type == ImGuiDataType_U16)
2146 *(ImU16*)p_data = (ImU16)ImClamp(v32, (
int)IM_U16_MIN, (
int)IM_U16_MAX);
2151 return memcmp(&data_backup, p_data, type_info->Size) != 0;
2155static int DataTypeCompareT(
const T* lhs,
const T* rhs)
2157 if (*lhs < *rhs)
return -1;
2158 if (*lhs > *rhs)
return +1;
2162int ImGui::DataTypeCompare(ImGuiDataType data_type,
const void* arg_1,
const void* arg_2)
2166 case ImGuiDataType_S8:
return DataTypeCompareT<ImS8 >((
const ImS8* )arg_1, (
const ImS8* )arg_2);
2167 case ImGuiDataType_U8:
return DataTypeCompareT<ImU8 >((
const ImU8* )arg_1, (
const ImU8* )arg_2);
2168 case ImGuiDataType_S16:
return DataTypeCompareT<ImS16 >((
const ImS16* )arg_1, (
const ImS16* )arg_2);
2169 case ImGuiDataType_U16:
return DataTypeCompareT<ImU16 >((
const ImU16* )arg_1, (
const ImU16* )arg_2);
2170 case ImGuiDataType_S32:
return DataTypeCompareT<ImS32 >((
const ImS32* )arg_1, (
const ImS32* )arg_2);
2171 case ImGuiDataType_U32:
return DataTypeCompareT<ImU32 >((
const ImU32* )arg_1, (
const ImU32* )arg_2);
2172 case ImGuiDataType_S64:
return DataTypeCompareT<ImS64 >((
const ImS64* )arg_1, (
const ImS64* )arg_2);
2173 case ImGuiDataType_U64:
return DataTypeCompareT<ImU64 >((
const ImU64* )arg_1, (
const ImU64* )arg_2);
2174 case ImGuiDataType_Float:
return DataTypeCompareT<float >((
const float* )arg_1, (
const float* )arg_2);
2175 case ImGuiDataType_Double:
return DataTypeCompareT<double>((
const double*)arg_1, (
const double*)arg_2);
2176 case ImGuiDataType_COUNT:
break;
2183static bool DataTypeClampT(T* v,
const T* v_min,
const T* v_max)
2186 if (v_min && *v < *v_min) { *v = *v_min;
return true; }
2187 if (v_max && *v > *v_max) { *v = *v_max;
return true; }
2191bool ImGui::DataTypeClamp(ImGuiDataType data_type,
void* p_data,
const void* p_min,
const void* p_max)
2195 case ImGuiDataType_S8:
return DataTypeClampT<ImS8 >((ImS8* )p_data, (
const ImS8* )p_min, (
const ImS8* )p_max);
2196 case ImGuiDataType_U8:
return DataTypeClampT<ImU8 >((ImU8* )p_data, (
const ImU8* )p_min, (
const ImU8* )p_max);
2197 case ImGuiDataType_S16:
return DataTypeClampT<ImS16 >((ImS16* )p_data, (
const ImS16* )p_min, (
const ImS16* )p_max);
2198 case ImGuiDataType_U16:
return DataTypeClampT<ImU16 >((ImU16* )p_data, (
const ImU16* )p_min, (
const ImU16* )p_max);
2199 case ImGuiDataType_S32:
return DataTypeClampT<ImS32 >((ImS32* )p_data, (
const ImS32* )p_min, (
const ImS32* )p_max);
2200 case ImGuiDataType_U32:
return DataTypeClampT<ImU32 >((ImU32* )p_data, (
const ImU32* )p_min, (
const ImU32* )p_max);
2201 case ImGuiDataType_S64:
return DataTypeClampT<ImS64 >((ImS64* )p_data, (
const ImS64* )p_min, (
const ImS64* )p_max);
2202 case ImGuiDataType_U64:
return DataTypeClampT<ImU64 >((ImU64* )p_data, (
const ImU64* )p_min, (
const ImU64* )p_max);
2203 case ImGuiDataType_Float:
return DataTypeClampT<float >((
float* )p_data, (
const float* )p_min, (
const float* )p_max);
2204 case ImGuiDataType_Double:
return DataTypeClampT<double>((
double*)p_data, (
const double*)p_min, (
const double*)p_max);
2205 case ImGuiDataType_COUNT:
break;
2211static float GetMinimumStepAtDecimalPrecision(
int decimal_precision)
2213 static const float min_steps[10] = { 1.0f, 0.1f, 0.01f, 0.001f, 0.0001f, 0.00001f, 0.000001f, 0.0000001f, 0.00000001f, 0.000000001f };
2214 if (decimal_precision < 0)
2216 return (decimal_precision < IM_ARRAYSIZE(min_steps)) ? min_steps[decimal_precision] : ImPow(10.0f, (
float)-decimal_precision);
2219template<
typename TYPE>
2220TYPE ImGui::RoundScalarWithFormatT(
const char* format, ImGuiDataType data_type, TYPE v)
2222 IM_UNUSED(data_type);
2223 IM_ASSERT(data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double);
2225 if (fmt_start[0] !=
'%' || fmt_start[1] ==
'%')
2229 char fmt_sanitized[32];
2231 fmt_start = fmt_sanitized;
2236 const char* p = v_str;
2239 v = (TYPE)ImAtof(p);
2264template<
typename TYPE,
typename SIGNEDTYPE,
typename FLOATTYPE>
2265bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v,
float v_speed,
const TYPE v_min,
const TYPE v_max,
const char* format, ImGuiSliderFlags flags)
2268 const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
2269 const bool is_clamped = (v_min < v_max);
2270 const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
2271 const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
2274 if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))
2275 v_speed = (
float)((v_max - v_min) *
g.DragSpeedDefaultRatio);
2278 float adjust_delta = 0.0f;
2279 if (
g.ActiveIdSource == ImGuiInputSource_Mouse && IsMousePosValid() && IsMouseDragPastThreshold(0,
g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR))
2281 adjust_delta =
g.IO.MouseDelta[axis];
2283 adjust_delta *= 1.0f / 100.0f;
2285 adjust_delta *= 10.0f;
2287 else if (
g.ActiveIdSource == ImGuiInputSource_Keyboard ||
g.ActiveIdSource == ImGuiInputSource_Gamepad)
2290 const bool tweak_slow = IsKeyDown((
g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);
2291 const bool tweak_fast = IsKeyDown((
g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);
2292 const float tweak_factor = tweak_slow ? 1.0f / 1.0f : tweak_fast ? 10.0f : 1.0f;
2293 adjust_delta = GetNavTweakPressedAmount(axis) * tweak_factor;
2294 v_speed = ImMax(v_speed, GetMinimumStepAtDecimalPrecision(decimal_precision));
2296 adjust_delta *= v_speed;
2299 if (axis == ImGuiAxis_Y)
2300 adjust_delta = -adjust_delta;
2303 if (is_logarithmic && (v_max - v_min < FLT_MAX) && ((v_max - v_min) > 0.000001f))
2304 adjust_delta /= (float)(v_max - v_min);
2308 bool is_just_activated =
g.ActiveIdIsJustActivated;
2309 bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
2310 if (is_just_activated || is_already_past_limits_and_pushing_outward)
2312 g.DragCurrentAccum = 0.0f;
2313 g.DragCurrentAccumDirty =
false;
2315 else if (adjust_delta != 0.0f)
2317 g.DragCurrentAccum += adjust_delta;
2318 g.DragCurrentAccumDirty =
true;
2321 if (!
g.DragCurrentAccumDirty)
2325 FLOATTYPE v_old_ref_for_accum_remainder = (FLOATTYPE)0.0f;
2327 float logarithmic_zero_epsilon = 0.0f;
2328 const float zero_deadzone_halfsize = 0.0f;
2333 logarithmic_zero_epsilon = ImPow(0.1f, (
float)decimal_precision);
2336 float v_old_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2337 float v_new_parametric = v_old_parametric +
g.DragCurrentAccum;
2338 v_cur = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new_parametric, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2339 v_old_ref_for_accum_remainder = v_old_parametric;
2343 v_cur += (SIGNEDTYPE)
g.DragCurrentAccum;
2347 if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))
2348 v_cur = RoundScalarWithFormatT<TYPE>(format, data_type, v_cur);
2351 g.DragCurrentAccumDirty =
false;
2355 float v_new_parametric = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_cur, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2356 g.DragCurrentAccum -= (float)(v_new_parametric - v_old_ref_for_accum_remainder);
2360 g.DragCurrentAccum -= (float)((SIGNEDTYPE)v_cur - (SIGNEDTYPE)*v);
2364 if (v_cur == (TYPE)-0)
2368 if (*v != v_cur && is_clamped)
2370 if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_floating_point))
2372 if (v_cur > v_max || (v_cur < *v && adjust_delta > 0.0f && !is_floating_point))
2383bool ImGui::DragBehavior(ImGuiID
id, ImGuiDataType data_type,
void* p_v,
float v_speed,
const void* p_min,
const void* p_max,
const char* format, ImGuiSliderFlags flags)
2386 IM_ASSERT((flags == 1 || (flags & ImGuiSliderFlags_InvalidMask_) == 0) &&
"Invalid ImGuiSliderFlags flags! Has the 'float power' argument been mistakenly cast to flags? Call function with ImGuiSliderFlags_Logarithmic flags instead.");
2389 if (
g.ActiveId ==
id)
2392 if (
g.ActiveIdSource == ImGuiInputSource_Mouse && !
g.IO.MouseDown[0])
2394 else if ((
g.ActiveIdSource == ImGuiInputSource_Keyboard ||
g.ActiveIdSource == ImGuiInputSource_Gamepad) &&
g.NavActivatePressedId ==
id && !
g.ActiveIdIsJustActivated)
2397 if (
g.ActiveId !=
id)
2399 if ((
g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))
2404 case ImGuiDataType_S8: { ImS32 v32 = (ImS32)*(ImS8*)p_v;
bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(
const ImS8*) p_min : IM_S8_MIN, p_max ? *(const ImS8*)p_max : IM_S8_MAX,
format, flags);
if (r) *(ImS8*)p_v = (ImS8)v32;
return r; }
2405 case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v;
bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(
const ImU8*) p_min : IM_U8_MIN, p_max ? *(const ImU8*)p_max : IM_U8_MAX,
format, flags);
if (r) *(ImU8*)p_v = (ImU8)v32;
return r; }
2406 case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v;
bool r = DragBehaviorT<ImS32, ImS32, float>(ImGuiDataType_S32, &v32, v_speed, p_min ? *(
const ImS16*)p_min : IM_S16_MIN, p_max ? *(const ImS16*)p_max : IM_S16_MAX,
format, flags);
if (r) *(ImS16*)p_v = (ImS16)v32;
return r; }
2407 case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v;
bool r = DragBehaviorT<ImU32, ImS32, float>(ImGuiDataType_U32, &v32, v_speed, p_min ? *(
const ImU16*)p_min : IM_U16_MIN, p_max ? *(const ImU16*)p_max : IM_U16_MAX,
format, flags);
if (r) *(ImU16*)p_v = (ImU16)v32;
return r; }
2408 case ImGuiDataType_S32:
return DragBehaviorT<ImS32, ImS32, float >(data_type, (ImS32*)p_v, v_speed, p_min ? *(
const ImS32* )p_min : IM_S32_MIN, p_max ? *(const ImS32* )p_max : IM_S32_MAX,
format, flags);
2409 case ImGuiDataType_U32:
return DragBehaviorT<ImU32, ImS32, float >(data_type, (ImU32*)p_v, v_speed, p_min ? *(
const ImU32* )p_min : IM_U32_MIN, p_max ? *(const ImU32* )p_max : IM_U32_MAX,
format, flags);
2410 case ImGuiDataType_S64:
return DragBehaviorT<ImS64, ImS64, double>(data_type, (ImS64*)p_v, v_speed, p_min ? *(
const ImS64* )p_min : IM_S64_MIN, p_max ? *(const ImS64* )p_max : IM_S64_MAX,
format, flags);
2411 case ImGuiDataType_U64:
return DragBehaviorT<ImU64, ImS64, double>(data_type, (ImU64*)p_v, v_speed, p_min ? *(
const ImU64* )p_min : IM_U64_MIN, p_max ? *(const ImU64* )p_max : IM_U64_MAX,
format, flags);
2412 case ImGuiDataType_Float:
return DragBehaviorT<float, float, float >(data_type, (
float*)p_v, v_speed, p_min ? *(
const float* )p_min : -FLT_MAX, p_max ? *(const float* )p_max : FLT_MAX,
format, flags);
2413 case ImGuiDataType_Double:
return DragBehaviorT<double,double,double>(data_type, (
double*)p_v, v_speed, p_min ? *(
const double*)p_min : -DBL_MAX, p_max ? *(const double*)p_max : DBL_MAX,
format, flags);
2414 case ImGuiDataType_COUNT:
break;
2422bool 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, ImGuiSliderFlags flags)
2424 ImGuiWindow* window = GetCurrentWindow();
2425 if (window->SkipItems)
2429 const ImGuiStyle& style =
g.Style;
2430 const ImGuiID
id = window->GetID(label);
2431 const float w = CalcItemWidth();
2433 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
2434 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
2435 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
2437 const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
2438 ItemSize(total_bb, style.FramePadding.y);
2439 if (!ItemAdd(total_bb,
id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
2444 format = DataTypeGetInfo(data_type)->PrintFmt;
2446 const bool hovered = ItemHoverable(frame_bb,
id,
g.LastItemData.InFlags);
2447 bool temp_input_is_active = temp_input_allowed && TempInputIsActive(
id);
2448 if (!temp_input_is_active)
2451 const bool clicked = hovered && IsMouseClicked(0,
id);
2452 const bool double_clicked = (hovered &&
g.IO.MouseClickedCount[0] == 2 && TestKeyOwner(ImGuiKey_MouseLeft,
id));
2453 const bool make_active = (clicked || double_clicked ||
g.NavActivateId ==
id);
2454 if (make_active && (clicked || double_clicked))
2455 SetKeyOwner(ImGuiKey_MouseLeft,
id);
2456 if (make_active && temp_input_allowed)
2457 if ((clicked &&
g.IO.KeyCtrl) || double_clicked || (
g.NavActivateId ==
id && (
g.NavActivateFlags & ImGuiActivateFlags_PreferInput)))
2458 temp_input_is_active =
true;
2461 if (
g.IO.ConfigDragClickToInputText && temp_input_allowed && !temp_input_is_active)
2462 if (
g.ActiveId ==
id && hovered &&
g.IO.MouseReleased[0] && !IsMouseDragPastThreshold(0,
g.IO.MouseDragThreshold * DRAG_MOUSE_THRESHOLD_FACTOR))
2464 g.NavActivateId =
id;
2465 g.NavActivateFlags = ImGuiActivateFlags_PreferInput;
2466 temp_input_is_active =
true;
2469 if (make_active && !temp_input_is_active)
2471 SetActiveID(
id, window);
2472 SetFocusID(
id, window);
2473 FocusWindow(window);
2474 g.ActiveIdUsingNavDirMask = (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
2478 if (temp_input_is_active)
2481 const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0 && (p_min == NULL || p_max == NULL || DataTypeCompare(data_type, p_min, p_max) < 0);
2482 return TempInputScalar(frame_bb,
id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
2486 const ImU32 frame_col = GetColorU32(
g.ActiveId ==
id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
2487 RenderNavHighlight(frame_bb,
id);
2488 RenderFrame(frame_bb.Min, frame_bb.Max, frame_col,
true, style.FrameRounding);
2491 const bool value_changed = DragBehavior(
id, data_type, p_data, v_speed, p_min, p_max, format, flags);
2497 const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
2499 LogSetNextTextDecoration(
"{",
"}");
2500 RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
2502 if (label_size.x > 0.0f)
2503 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
2505 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));
2506 return value_changed;
2509bool 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, ImGuiSliderFlags flags)
2511 ImGuiWindow* window = GetCurrentWindow();
2512 if (window->SkipItems)
2516 bool value_changed =
false;
2519 PushMultiItemsWidths(components, CalcItemWidth());
2520 size_t type_size = GDataTypeInfo[data_type].Size;
2521 for (
int i = 0; i < components; i++)
2525 SameLine(0,
g.Style.ItemInnerSpacing.x);
2526 value_changed |= DragScalar(
"", data_type, p_data, v_speed, p_min, p_max, format, flags);
2529 p_data = (
void*)((
char*)p_data + type_size);
2533 const char* label_end = FindRenderedTextEnd(label);
2534 if (label != label_end)
2536 SameLine(0,
g.Style.ItemInnerSpacing.x);
2537 TextEx(label, label_end);
2541 return value_changed;
2544bool ImGui::DragFloat(
const char* label,
float* v,
float v_speed,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
2546 return DragScalar(label, ImGuiDataType_Float, v, v_speed, &v_min, &v_max, format, flags);
2549bool ImGui::DragFloat2(
const char* label,
float v[2],
float v_speed,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
2551 return DragScalarN(label, ImGuiDataType_Float, v, 2, v_speed, &v_min, &v_max, format, flags);
2554bool ImGui::DragFloat3(
const char* label,
float v[3],
float v_speed,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
2556 return DragScalarN(label, ImGuiDataType_Float, v, 3, v_speed, &v_min, &v_max, format, flags);
2559bool ImGui::DragFloat4(
const char* label,
float v[4],
float v_speed,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
2561 return DragScalarN(label, ImGuiDataType_Float, v, 4, v_speed, &v_min, &v_max, format, flags);
2565bool ImGui::DragFloatRange2(
const char* label,
float* v_current_min,
float* v_current_max,
float v_speed,
float v_min,
float v_max,
const char* format,
const char* format_max, ImGuiSliderFlags flags)
2567 ImGuiWindow* window = GetCurrentWindow();
2568 if (window->SkipItems)
2574 PushMultiItemsWidths(2, CalcItemWidth());
2576 float min_min = (v_min >= v_max) ? -FLT_MAX : v_min;
2577 float min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
2578 ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0);
2579 bool value_changed = DragScalar(
"##min", ImGuiDataType_Float, v_current_min, v_speed, &min_min, &min_max, format, min_flags);
2581 SameLine(0,
g.Style.ItemInnerSpacing.x);
2583 float max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
2584 float max_max = (v_min >= v_max) ? FLT_MAX : v_max;
2585 ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0);
2586 value_changed |= DragScalar(
"##max", ImGuiDataType_Float, v_current_max, v_speed, &max_min, &max_max, format_max ? format_max :
format, max_flags);
2588 SameLine(0,
g.Style.ItemInnerSpacing.x);
2590 TextEx(label, FindRenderedTextEnd(label));
2594 return value_changed;
2598bool ImGui::DragInt(
const char* label,
int* v,
float v_speed,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
2600 return DragScalar(label, ImGuiDataType_S32, v, v_speed, &v_min, &v_max, format, flags);
2603bool ImGui::DragInt2(
const char* label,
int v[2],
float v_speed,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
2605 return DragScalarN(label, ImGuiDataType_S32, v, 2, v_speed, &v_min, &v_max, format, flags);
2608bool ImGui::DragInt3(
const char* label,
int v[3],
float v_speed,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
2610 return DragScalarN(label, ImGuiDataType_S32, v, 3, v_speed, &v_min, &v_max, format, flags);
2613bool ImGui::DragInt4(
const char* label,
int v[4],
float v_speed,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
2615 return DragScalarN(label, ImGuiDataType_S32, v, 4, v_speed, &v_min, &v_max, format, flags);
2619bool ImGui::DragIntRange2(
const char* label,
int* v_current_min,
int* v_current_max,
float v_speed,
int v_min,
int v_max,
const char* format,
const char* format_max, ImGuiSliderFlags flags)
2621 ImGuiWindow* window = GetCurrentWindow();
2622 if (window->SkipItems)
2628 PushMultiItemsWidths(2, CalcItemWidth());
2630 int min_min = (v_min >= v_max) ? INT_MIN : v_min;
2631 int min_max = (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max);
2632 ImGuiSliderFlags min_flags = flags | ((min_min == min_max) ? ImGuiSliderFlags_ReadOnly : 0);
2633 bool value_changed = DragInt(
"##min", v_current_min, v_speed, min_min, min_max, format, min_flags);
2635 SameLine(0,
g.Style.ItemInnerSpacing.x);
2637 int max_min = (v_min >= v_max) ? *v_current_min : ImMax(v_min, *v_current_min);
2638 int max_max = (v_min >= v_max) ? INT_MAX : v_max;
2639 ImGuiSliderFlags max_flags = flags | ((max_min == max_max) ? ImGuiSliderFlags_ReadOnly : 0);
2640 value_changed |= DragInt(
"##max", v_current_max, v_speed, max_min, max_max, format_max ? format_max :
format, max_flags);
2642 SameLine(0,
g.Style.ItemInnerSpacing.x);
2644 TextEx(label, FindRenderedTextEnd(label));
2648 return value_changed;
2675template<
typename TYPE,
typename SIGNEDTYPE,
typename FLOATTYPE>
2676float ImGui::ScaleRatioFromValueT(ImGuiDataType data_type, TYPE v, TYPE v_min, TYPE v_max,
bool is_logarithmic,
float logarithmic_zero_epsilon,
float zero_deadzone_halfsize)
2680 IM_UNUSED(data_type);
2682 const TYPE v_clamped = (v_min < v_max) ? ImClamp(v, v_min, v_max) : ImClamp(v, v_max, v_min);
2685 bool flipped = v_max < v_min;
2688 ImSwap(v_min, v_max);
2691 FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
2692 FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;
2695 if ((v_min == 0.0f) && (v_max < 0.0f))
2696 v_min_fudged = -logarithmic_zero_epsilon;
2697 else if ((v_max == 0.0f) && (v_min < 0.0f))
2698 v_max_fudged = -logarithmic_zero_epsilon;
2701 if (v_clamped <= v_min_fudged)
2703 else if (v_clamped >= v_max_fudged)
2705 else if ((v_min * v_max) < 0.0f)
2707 float zero_point_center = (-(float)v_min) / ((float)v_max - (
float)v_min);
2708 float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
2709 float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
2711 result = zero_point_center;
2713 result = (1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(-v_min_fudged / logarithmic_zero_epsilon))) * zero_point_snap_L;
2715 result = zero_point_snap_R + ((float)(ImLog((FLOATTYPE)v_clamped / logarithmic_zero_epsilon) / ImLog(v_max_fudged / logarithmic_zero_epsilon)) * (1.0f - zero_point_snap_R));
2717 else if ((v_min < 0.0f) || (v_max < 0.0f))
2718 result = 1.0f - (float)(ImLog(-(FLOATTYPE)v_clamped / -v_max_fudged) / ImLog(-v_min_fudged / -v_max_fudged));
2720 result = (float)(ImLog((FLOATTYPE)v_clamped / v_min_fudged) / ImLog(v_max_fudged / v_min_fudged));
2722 return flipped ? (1.0f - result) : result;
2727 return (
float)((FLOATTYPE)(SIGNEDTYPE)(v_clamped - v_min) / (FLOATTYPE)(SIGNEDTYPE)(v_max - v_min));
2732template<
typename TYPE,
typename SIGNEDTYPE,
typename FLOATTYPE>
2733TYPE ImGui::ScaleValueFromRatioT(ImGuiDataType data_type,
float t, TYPE v_min, TYPE v_max,
bool is_logarithmic,
float logarithmic_zero_epsilon,
float zero_deadzone_halfsize)
2737 if (
t <= 0.0f || v_min == v_max)
2742 TYPE result = (TYPE)0;
2746 FLOATTYPE v_min_fudged = (ImAbs((FLOATTYPE)v_min) < logarithmic_zero_epsilon) ? ((v_min < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_min;
2747 FLOATTYPE v_max_fudged = (ImAbs((FLOATTYPE)v_max) < logarithmic_zero_epsilon) ? ((v_max < 0.0f) ? -logarithmic_zero_epsilon : logarithmic_zero_epsilon) : (FLOATTYPE)v_max;
2749 const bool flipped = v_max < v_min;
2751 ImSwap(v_min_fudged, v_max_fudged);
2754 if ((v_max == 0.0f) && (v_min < 0.0f))
2755 v_max_fudged = -logarithmic_zero_epsilon;
2757 float t_with_flip = flipped ? (1.0f -
t) :
t;
2759 if ((v_min * v_max) < 0.0f)
2761 float zero_point_center = (-(float)ImMin(v_min, v_max)) / ImAbs((
float)v_max - (float)v_min);
2762 float zero_point_snap_L = zero_point_center - zero_deadzone_halfsize;
2763 float zero_point_snap_R = zero_point_center + zero_deadzone_halfsize;
2764 if (t_with_flip >= zero_point_snap_L && t_with_flip <= zero_point_snap_R)
2765 result = (TYPE)0.0f;
2766 else if (t_with_flip < zero_point_center)
2767 result = (TYPE)-(logarithmic_zero_epsilon * ImPow(-v_min_fudged / logarithmic_zero_epsilon, (FLOATTYPE)(1.0f - (t_with_flip / zero_point_snap_L))));
2769 result = (TYPE)(logarithmic_zero_epsilon * ImPow(v_max_fudged / logarithmic_zero_epsilon, (FLOATTYPE)((t_with_flip - zero_point_snap_R) / (1.0f - zero_point_snap_R))));
2771 else if ((v_min < 0.0f) || (v_max < 0.0f))
2772 result = (TYPE)-(-v_max_fudged * ImPow(-v_min_fudged / -v_max_fudged, (FLOATTYPE)(1.0f - t_with_flip)));
2774 result = (TYPE)(v_min_fudged * ImPow(v_max_fudged / v_min_fudged, (FLOATTYPE)t_with_flip));
2779 const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
2780 if (is_floating_point)
2782 result = ImLerp(v_min, v_max,
t);
2790 FLOATTYPE v_new_off_f = (SIGNEDTYPE)(v_max - v_min) *
t;
2791 result = (TYPE)((SIGNEDTYPE)v_min + (SIGNEDTYPE)(v_new_off_f + (FLOATTYPE)(v_min > v_max ? -0.5 : 0.5)));
2799template<
typename TYPE,
typename SIGNEDTYPE,
typename FLOATTYPE>
2800bool ImGui::SliderBehaviorT(
const ImRect& bb, ImGuiID
id, ImGuiDataType data_type, TYPE* v,
const TYPE v_min,
const TYPE v_max,
const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
2803 const ImGuiStyle& style =
g.Style;
2805 const ImGuiAxis axis = (flags & ImGuiSliderFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
2806 const bool is_logarithmic = (flags & ImGuiSliderFlags_Logarithmic) != 0;
2807 const bool is_floating_point = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
2808 const float v_range_f = (float)(v_min < v_max ? v_max - v_min : v_min - v_max);
2811 const float grab_padding = 2.0f;
2812 const float slider_sz = (bb.Max[axis] - bb.Min[axis]) - grab_padding * 2.0f;
2813 float grab_sz = style.GrabMinSize;
2814 if (!is_floating_point && v_range_f >= 0.0f)
2815 grab_sz = ImMax(slider_sz / (v_range_f + 1), style.GrabMinSize);
2816 grab_sz = ImMin(grab_sz, slider_sz);
2817 const float slider_usable_sz = slider_sz - grab_sz;
2818 const float slider_usable_pos_min = bb.Min[axis] + grab_padding + grab_sz * 0.5f;
2819 const float slider_usable_pos_max = bb.Max[axis] - grab_padding - grab_sz * 0.5f;
2821 float logarithmic_zero_epsilon = 0.0f;
2822 float zero_deadzone_halfsize = 0.0f;
2827 logarithmic_zero_epsilon = ImPow(0.1f, (
float)decimal_precision);
2828 zero_deadzone_halfsize = (style.LogSliderDeadzone * 0.5f) / ImMax(slider_usable_sz, 1.0f);
2832 bool value_changed =
false;
2833 if (
g.ActiveId ==
id)
2835 bool set_new_value =
false;
2836 float clicked_t = 0.0f;
2837 if (
g.ActiveIdSource == ImGuiInputSource_Mouse)
2839 if (!
g.IO.MouseDown[0])
2845 const float mouse_abs_pos =
g.IO.MousePos[axis];
2846 if (
g.ActiveIdIsJustActivated)
2848 float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2849 if (axis == ImGuiAxis_Y)
2850 grab_t = 1.0f - grab_t;
2851 const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
2852 const bool clicked_around_grab = (mouse_abs_pos >= grab_pos - grab_sz * 0.5f - 1.0f) && (mouse_abs_pos <= grab_pos + grab_sz * 0.5f + 1.0f);
2853 g.SliderGrabClickOffset = (clicked_around_grab && is_floating_point) ? mouse_abs_pos - grab_pos : 0.0f;
2855 if (slider_usable_sz > 0.0f)
2856 clicked_t = ImSaturate((mouse_abs_pos -
g.SliderGrabClickOffset - slider_usable_pos_min) / slider_usable_sz);
2857 if (axis == ImGuiAxis_Y)
2858 clicked_t = 1.0f - clicked_t;
2859 set_new_value =
true;
2862 else if (
g.ActiveIdSource == ImGuiInputSource_Keyboard ||
g.ActiveIdSource == ImGuiInputSource_Gamepad)
2864 if (
g.ActiveIdIsJustActivated)
2866 g.SliderCurrentAccum = 0.0f;
2867 g.SliderCurrentAccumDirty =
false;
2870 float input_delta = (axis == ImGuiAxis_X) ? GetNavTweakPressedAmount(axis) : -GetNavTweakPressedAmount(axis);
2871 if (input_delta != 0.0f)
2873 const bool tweak_slow = IsKeyDown((
g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakSlow : ImGuiKey_NavKeyboardTweakSlow);
2874 const bool tweak_fast = IsKeyDown((
g.NavInputSource == ImGuiInputSource_Gamepad) ? ImGuiKey_NavGamepadTweakFast : ImGuiKey_NavKeyboardTweakFast);
2876 if (decimal_precision > 0)
2878 input_delta /= 100.0f;
2880 input_delta /= 10.0f;
2884 if ((v_range_f >= -100.0f && v_range_f <= 100.0f && v_range_f != 0.0f) || tweak_slow)
2885 input_delta = ((input_delta < 0.0f) ? -1.0f : +1.0f) / v_range_f;
2887 input_delta /= 100.0f;
2890 input_delta *= 10.0f;
2892 g.SliderCurrentAccum += input_delta;
2893 g.SliderCurrentAccumDirty =
true;
2896 float delta =
g.SliderCurrentAccum;
2897 if (
g.NavActivatePressedId ==
id && !
g.ActiveIdIsJustActivated)
2901 else if (
g.SliderCurrentAccumDirty)
2903 clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2905 if ((clicked_t >= 1.0f && delta > 0.0f) || (clicked_t <= 0.0f && delta < 0.0f))
2907 set_new_value =
false;
2908 g.SliderCurrentAccum = 0.0f;
2912 set_new_value =
true;
2913 float old_clicked_t = clicked_t;
2914 clicked_t = ImSaturate(clicked_t + delta);
2917 TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2918 if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))
2919 v_new = RoundScalarWithFormatT<TYPE>(format, data_type, v_new);
2920 float new_clicked_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, v_new, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2923 g.SliderCurrentAccum -= ImMin(new_clicked_t - old_clicked_t, delta);
2925 g.SliderCurrentAccum -= ImMax(new_clicked_t - old_clicked_t, delta);
2928 g.SliderCurrentAccumDirty =
false;
2933 if ((
g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) || (flags & ImGuiSliderFlags_ReadOnly))
2934 set_new_value =
false;
2938 TYPE v_new = ScaleValueFromRatioT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, clicked_t, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2941 if (is_floating_point && !(flags & ImGuiSliderFlags_NoRoundToFormat))
2942 v_new = RoundScalarWithFormatT<TYPE>(format, data_type, v_new);
2948 value_changed =
true;
2953 if (slider_sz < 1.0f)
2955 *out_grab_bb = ImRect(bb.Min, bb.Min);
2960 float grab_t = ScaleRatioFromValueT<TYPE, SIGNEDTYPE, FLOATTYPE>(data_type, *v, v_min, v_max, is_logarithmic, logarithmic_zero_epsilon, zero_deadzone_halfsize);
2961 if (axis == ImGuiAxis_Y)
2962 grab_t = 1.0f - grab_t;
2963 const float grab_pos = ImLerp(slider_usable_pos_min, slider_usable_pos_max, grab_t);
2964 if (axis == ImGuiAxis_X)
2965 *out_grab_bb = ImRect(grab_pos - grab_sz * 0.5f, bb.Min.y + grab_padding, grab_pos + grab_sz * 0.5f, bb.Max.y - grab_padding);
2967 *out_grab_bb = ImRect(bb.Min.x + grab_padding, grab_pos - grab_sz * 0.5f, bb.Max.x - grab_padding, grab_pos + grab_sz * 0.5f);
2970 return value_changed;
2976bool ImGui::SliderBehavior(
const ImRect& bb, ImGuiID
id, ImGuiDataType data_type,
void* p_v,
const void* p_min,
const void* p_max,
const char* format, ImGuiSliderFlags flags, ImRect* out_grab_bb)
2979 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.");
2983 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; }
2984 case ImGuiDataType_U8: { ImU32 v32 = (ImU32)*(ImU8*)p_v;
bool r = SliderBehaviorT<ImU32, ImS32, float>(bb,
id, ImGuiDataType_U32, &v32, *(
const ImU8*)p_min, *(
const ImU8*)p_max, format, flags, out_grab_bb);
if (r) *(ImU8*)p_v = (ImU8)v32;
return r; }
2985 case ImGuiDataType_S16: { ImS32 v32 = (ImS32)*(ImS16*)p_v;
bool r = SliderBehaviorT<ImS32, ImS32, float>(bb,
id, ImGuiDataType_S32, &v32, *(
const ImS16*)p_min, *(
const ImS16*)p_max, format, flags, out_grab_bb);
if (r) *(ImS16*)p_v = (ImS16)v32;
return r; }
2986 case ImGuiDataType_U16: { ImU32 v32 = (ImU32)*(ImU16*)p_v;
bool r = SliderBehaviorT<ImU32, ImS32, float>(bb,
id, ImGuiDataType_U32, &v32, *(
const ImU16*)p_min, *(
const ImU16*)p_max, format, flags, out_grab_bb);
if (r) *(ImU16*)p_v = (ImU16)v32;
return r; }
2987 case ImGuiDataType_S32:
2988 IM_ASSERT(*(
const ImS32*)p_min >= IM_S32_MIN / 2 && *(
const ImS32*)p_max <= IM_S32_MAX / 2);
2989 return SliderBehaviorT<ImS32, ImS32, float >(bb,
id, data_type, (ImS32*)p_v, *(
const ImS32*)p_min, *(
const ImS32*)p_max, format, flags, out_grab_bb);
2990 case ImGuiDataType_U32:
2991 IM_ASSERT(*(
const ImU32*)p_max <= IM_U32_MAX / 2);
2992 return SliderBehaviorT<ImU32, ImS32, float >(bb,
id, data_type, (ImU32*)p_v, *(
const ImU32*)p_min, *(
const ImU32*)p_max, format, flags, out_grab_bb);
2993 case ImGuiDataType_S64:
2994 IM_ASSERT(*(
const ImS64*)p_min >= IM_S64_MIN / 2 && *(
const ImS64*)p_max <= IM_S64_MAX / 2);
2995 return SliderBehaviorT<ImS64, ImS64, double>(bb,
id, data_type, (ImS64*)p_v, *(
const ImS64*)p_min, *(
const ImS64*)p_max, format, flags, out_grab_bb);
2996 case ImGuiDataType_U64:
2997 IM_ASSERT(*(
const ImU64*)p_max <= IM_U64_MAX / 2);
2998 return SliderBehaviorT<ImU64, ImS64, double>(bb,
id, data_type, (ImU64*)p_v, *(
const ImU64*)p_min, *(
const ImU64*)p_max, format, flags, out_grab_bb);
2999 case ImGuiDataType_Float:
3000 IM_ASSERT(*(
const float*)p_min >= -FLT_MAX / 2.0f && *(
const float*)p_max <= FLT_MAX / 2.0f);
3001 return SliderBehaviorT<float, float, float >(bb,
id, data_type, (
float*)p_v, *(
const float*)p_min, *(
const float*)p_max, format, flags, out_grab_bb);
3002 case ImGuiDataType_Double:
3003 IM_ASSERT(*(
const double*)p_min >= -DBL_MAX / 2.0f && *(
const double*)p_max <= DBL_MAX / 2.0f);
3004 return SliderBehaviorT<double, double, double>(bb,
id, data_type, (
double*)p_v, *(
const double*)p_min, *(
const double*)p_max, format, flags, out_grab_bb);
3005 case ImGuiDataType_COUNT:
break;
3013bool ImGui::SliderScalar(
const char* label, ImGuiDataType data_type,
void* p_data,
const void* p_min,
const void* p_max,
const char* format, ImGuiSliderFlags flags)
3015 ImGuiWindow* window = GetCurrentWindow();
3016 if (window->SkipItems)
3020 const ImGuiStyle& style =
g.Style;
3021 const ImGuiID
id = window->GetID(label);
3022 const float w = CalcItemWidth();
3024 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
3025 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y * 2.0f));
3026 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
3028 const bool temp_input_allowed = (flags & ImGuiSliderFlags_NoInput) == 0;
3029 ItemSize(total_bb, style.FramePadding.y);
3030 if (!ItemAdd(total_bb,
id, &frame_bb, temp_input_allowed ? ImGuiItemFlags_Inputable : 0))
3035 format = DataTypeGetInfo(data_type)->PrintFmt;
3037 const bool hovered = ItemHoverable(frame_bb,
id,
g.LastItemData.InFlags);
3038 bool temp_input_is_active = temp_input_allowed && TempInputIsActive(
id);
3039 if (!temp_input_is_active)
3042 const bool clicked = hovered && IsMouseClicked(0,
id);
3043 const bool make_active = (clicked ||
g.NavActivateId ==
id);
3044 if (make_active && clicked)
3045 SetKeyOwner(ImGuiKey_MouseLeft,
id);
3046 if (make_active && temp_input_allowed)
3047 if ((clicked &&
g.IO.KeyCtrl) || (
g.NavActivateId ==
id && (
g.NavActivateFlags & ImGuiActivateFlags_PreferInput)))
3048 temp_input_is_active =
true;
3050 if (make_active && !temp_input_is_active)
3052 SetActiveID(
id, window);
3053 SetFocusID(
id, window);
3054 FocusWindow(window);
3055 g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
3059 if (temp_input_is_active)
3062 const bool is_clamp_input = (flags & ImGuiSliderFlags_AlwaysClamp) != 0;
3063 return TempInputScalar(frame_bb,
id, label, data_type, p_data, format, is_clamp_input ? p_min : NULL, is_clamp_input ? p_max : NULL);
3067 const ImU32 frame_col = GetColorU32(
g.ActiveId ==
id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
3068 RenderNavHighlight(frame_bb,
id);
3069 RenderFrame(frame_bb.Min, frame_bb.Max, frame_col,
true,
g.Style.FrameRounding);
3073 const bool value_changed = SliderBehavior(frame_bb,
id, data_type, p_data, p_min, p_max, format, flags, &grab_bb);
3078 if (grab_bb.Max.x > grab_bb.Min.x)
3079 window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(
g.ActiveId ==
id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
3083 const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
3085 LogSetNextTextDecoration(
"{",
"}");
3086 RenderTextClipped(frame_bb.Min, frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.5f));
3088 if (label_size.x > 0.0f)
3089 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
3091 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | (temp_input_allowed ? ImGuiItemStatusFlags_Inputable : 0));
3092 return value_changed;
3096bool ImGui::SliderScalarN(
const char* label, ImGuiDataType data_type,
void* v,
int components,
const void* v_min,
const void* v_max,
const char* format, ImGuiSliderFlags flags)
3098 ImGuiWindow* window = GetCurrentWindow();
3099 if (window->SkipItems)
3103 bool value_changed =
false;
3106 PushMultiItemsWidths(components, CalcItemWidth());
3107 size_t type_size = GDataTypeInfo[data_type].Size;
3108 for (
int i = 0; i < components; i++)
3112 SameLine(0,
g.Style.ItemInnerSpacing.x);
3113 value_changed |= SliderScalar(
"", data_type, v, v_min, v_max, format, flags);
3116 v = (
void*)((
char*)v + type_size);
3120 const char* label_end = FindRenderedTextEnd(label);
3121 if (label != label_end)
3123 SameLine(0,
g.Style.ItemInnerSpacing.x);
3124 TextEx(label, label_end);
3128 return value_changed;
3131bool ImGui::SliderFloat(
const char* label,
float* v,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
3133 return SliderScalar(label, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);
3136bool ImGui::SliderFloat2(
const char* label,
float v[2],
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
3138 return SliderScalarN(label, ImGuiDataType_Float, v, 2, &v_min, &v_max, format, flags);
3141bool ImGui::SliderFloat3(
const char* label,
float v[3],
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
3143 return SliderScalarN(label, ImGuiDataType_Float, v, 3, &v_min, &v_max, format, flags);
3146bool ImGui::SliderFloat4(
const char* label,
float v[4],
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
3148 return SliderScalarN(label, ImGuiDataType_Float, v, 4, &v_min, &v_max, format, flags);
3151bool ImGui::SliderAngle(
const char* label,
float* v_rad,
float v_degrees_min,
float v_degrees_max,
const char* format, ImGuiSliderFlags flags)
3155 float v_deg = (*v_rad) * 360.0f / (2 * IM_PI);
3156 bool value_changed =
SliderFloat(label, &v_deg, v_degrees_min, v_degrees_max, format, flags);
3157 *v_rad = v_deg * (2 * IM_PI) / 360.0f;
3158 return value_changed;
3161bool ImGui::SliderInt(
const char* label,
int* v,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
3163 return SliderScalar(label, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);
3166bool ImGui::SliderInt2(
const char* label,
int v[2],
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
3168 return SliderScalarN(label, ImGuiDataType_S32, v, 2, &v_min, &v_max, format, flags);
3171bool ImGui::SliderInt3(
const char* label,
int v[3],
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
3173 return SliderScalarN(label, ImGuiDataType_S32, v, 3, &v_min, &v_max, format, flags);
3176bool ImGui::SliderInt4(
const char* label,
int v[4],
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
3178 return SliderScalarN(label, ImGuiDataType_S32, v, 4, &v_min, &v_max, format, flags);
3181bool ImGui::VSliderScalar(
const char* label,
const ImVec2& size, ImGuiDataType data_type,
void* p_data,
const void* p_min,
const void* p_max,
const char* format, ImGuiSliderFlags flags)
3183 ImGuiWindow* window = GetCurrentWindow();
3184 if (window->SkipItems)
3188 const ImGuiStyle& style =
g.Style;
3189 const ImGuiID
id = window->GetID(label);
3191 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
3192 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
3193 const ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
3195 ItemSize(bb, style.FramePadding.y);
3196 if (!ItemAdd(frame_bb,
id))
3201 format = DataTypeGetInfo(data_type)->PrintFmt;
3203 const bool hovered = ItemHoverable(frame_bb,
id,
g.LastItemData.InFlags);
3204 const bool clicked = hovered && IsMouseClicked(0,
id);
3205 if (clicked ||
g.NavActivateId ==
id)
3208 SetKeyOwner(ImGuiKey_MouseLeft,
id);
3209 SetActiveID(
id, window);
3210 SetFocusID(
id, window);
3211 FocusWindow(window);
3212 g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
3216 const ImU32 frame_col = GetColorU32(
g.ActiveId ==
id ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg);
3217 RenderNavHighlight(frame_bb,
id);
3218 RenderFrame(frame_bb.Min, frame_bb.Max, frame_col,
true,
g.Style.FrameRounding);
3222 const bool value_changed = SliderBehavior(frame_bb,
id, data_type, p_data, p_min, p_max, format, flags | ImGuiSliderFlags_Vertical, &grab_bb);
3227 if (grab_bb.Max.y > grab_bb.Min.y)
3228 window->DrawList->AddRectFilled(grab_bb.Min, grab_bb.Max, GetColorU32(
g.ActiveId ==
id ? ImGuiCol_SliderGrabActive : ImGuiCol_SliderGrab), style.GrabRounding);
3233 const char* value_buf_end = value_buf + DataTypeFormatString(value_buf, IM_ARRAYSIZE(value_buf), data_type, p_data, format);
3234 RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, value_buf, value_buf_end, NULL, ImVec2(0.5f, 0.0f));
3235 if (label_size.x > 0.0f)
3236 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
3238 return value_changed;
3241bool ImGui::VSliderFloat(
const char* label,
const ImVec2& size,
float* v,
float v_min,
float v_max,
const char* format, ImGuiSliderFlags flags)
3243 return VSliderScalar(label, size, ImGuiDataType_Float, v, &v_min, &v_max, format, flags);
3246bool ImGui::VSliderInt(
const char* label,
const ImVec2& size,
int* v,
int v_min,
int v_max,
const char* format, ImGuiSliderFlags flags)
3248 return VSliderScalar(label, size, ImGuiDataType_S32, v, &v_min, &v_max, format, flags);
3277 while (
char c = fmt[0])
3279 if (c ==
'%' && fmt[1] !=
'%')
3293 const unsigned int ignored_uppercase_mask = (1 << (
'I'-
'A')) | (1 << (
'L'-
'A'));
3294 const unsigned int ignored_lowercase_mask = (1 << (
'h'-
'a')) | (1 << (
'j'-
'a')) | (1 << (
'l'-
'a')) | (1 << (
't'-
'a')) | (1 << (
'w'-
'a')) | (1 << (
'z'-
'a'));
3295 for (
char c; (c = *fmt) != 0; fmt++)
3297 if (c >=
'A' && c <=
'Z' && ((1 << (c -
'A')) & ignored_uppercase_mask) == 0)
3299 if (c >=
'a' && c <=
'z' && ((1 << (c -
'a')) & ignored_lowercase_mask) == 0)
3313 if (fmt_start[0] !=
'%')
3316 if (fmt_end[0] == 0)
3318 ImStrncpy(buf, fmt_start, ImMin((
size_t)(fmt_end - fmt_start) + 1, buf_size));
3328 IM_UNUSED(fmt_out_size);
3329 IM_ASSERT((
size_t)(fmt_end - fmt_in + 1) < fmt_out_size);
3330 while (fmt_in < fmt_end)
3333 if (c !=
'\'' && c !=
'$' && c !=
'_')
3343 const char* fmt_out_begin = fmt_out;
3344 IM_UNUSED(fmt_out_size);
3345 IM_ASSERT((
size_t)(fmt_end - fmt_in + 1) < fmt_out_size);
3346 bool has_type =
false;
3347 while (fmt_in < fmt_end)
3350 if (!has_type && ((c >=
'0' && c <=
'9') || c ==
'.' || c ==
'+' || c ==
'#'))
3352 has_type |= ((c >=
'a' && c <=
'z') || (c >=
'A' && c <=
'Z'));
3353 if (c !=
'\'' && c !=
'$' && c !=
'_')
3357 return fmt_out_begin;
3360template<
typename TYPE>
3361static const char* ImAtoi(
const char* src, TYPE* output)
3364 if (*src ==
'-') { negative = 1; src++; }
3365 if (*src ==
'+') { src++; }
3367 while (*src >=
'0' && *src <=
'9')
3368 v = (v * 10) + (*src++ -
'0');
3369 *output = negative ? -v : v;
3379 return default_precision;
3381 while (*fmt >=
'0' && *fmt <=
'9')
3383 int precision = INT_MAX;
3386 fmt = ImAtoi<int>(fmt + 1, &precision);
3387 if (precision < 0 || precision > 99)
3388 precision = default_precision;
3390 if (*fmt ==
'e' || *fmt ==
'E')
3392 if ((*fmt ==
'g' || *fmt ==
'G') && precision == INT_MAX)
3394 return (precision == INT_MAX) ? default_precision : precision;
3399bool ImGui::TempInputText(
const ImRect& bb, ImGuiID
id,
const char* label,
char* buf,
int buf_size, ImGuiInputTextFlags flags)
3404 const bool init = (
g.TempInputId !=
id);
3408 g.CurrentWindow->DC.CursorPos = bb.Min;
3409 bool value_changed = InputTextEx(label, NULL, buf, buf_size, bb.GetSize(), flags | ImGuiInputTextFlags_MergedItem);
3413 IM_ASSERT(
g.ActiveId ==
id);
3414 g.TempInputId =
g.ActiveId;
3416 return value_changed;
3422bool 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)
3426 const ImGuiDataTypeInfo* type_info = DataTypeGetInfo(data_type);
3431 format = type_info->PrintFmt;
3432 DataTypeFormatString(data_buf, IM_ARRAYSIZE(data_buf), data_type, p_data, format);
3435 ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited;
3437 bool value_changed =
false;
3438 if (TempInputText(bb,
id, label, data_buf, IM_ARRAYSIZE(data_buf), flags))
3441 size_t data_type_size = type_info->Size;
3442 ImGuiDataTypeTempStorage data_backup;
3443 memcpy(&data_backup, p_data, data_type_size);
3446 DataTypeApplyFromText(data_buf, data_type, p_data, format);
3447 if (p_clamp_min || p_clamp_max)
3449 if (p_clamp_min && p_clamp_max && DataTypeCompare(data_type, p_clamp_min, p_clamp_max) > 0)
3450 ImSwap(p_clamp_min, p_clamp_max);
3451 DataTypeClamp(data_type, p_data, p_clamp_min, p_clamp_max);
3455 value_changed = memcmp(&data_backup, p_data, data_type_size) != 0;
3459 return value_changed;
3464bool ImGui::InputScalar(
const char* label, ImGuiDataType data_type,
void* p_data,
const void* p_step,
const void* p_step_fast,
const char* format, ImGuiInputTextFlags flags)
3466 ImGuiWindow* window = GetCurrentWindow();
3467 if (window->SkipItems)
3471 ImGuiStyle& style =
g.Style;
3474 format = DataTypeGetInfo(data_type)->PrintFmt;
3477 DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
3479 flags |= ImGuiInputTextFlags_AutoSelectAll | (ImGuiInputTextFlags)ImGuiInputTextFlags_NoMarkEdited;
3481 bool value_changed =
false;
3484 if (
InputText(label, buf, IM_ARRAYSIZE(buf), flags))
3485 value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
3489 const float button_size = GetFrameHeight();
3493 SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
3494 if (
InputText(
"", buf, IM_ARRAYSIZE(buf), flags))
3495 value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
3496 IMGUI_TEST_ENGINE_ITEM_INFO(
g.LastItemData.ID, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);
3499 const ImVec2 backup_frame_padding = style.FramePadding;
3500 style.FramePadding.x = style.FramePadding.y;
3501 ImGuiButtonFlags button_flags = ImGuiButtonFlags_Repeat | ImGuiButtonFlags_DontClosePopups;
3502 if (flags & ImGuiInputTextFlags_ReadOnly)
3504 SameLine(0, style.ItemInnerSpacing.x);
3505 if (ButtonEx(
"-", ImVec2(button_size, button_size), button_flags))
3507 DataTypeApplyOp(data_type,
'-', p_data, p_data,
g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
3508 value_changed =
true;
3510 SameLine(0, style.ItemInnerSpacing.x);
3511 if (ButtonEx(
"+", ImVec2(button_size, button_size), button_flags))
3513 DataTypeApplyOp(data_type,
'+', p_data, p_data,
g.IO.KeyCtrl && p_step_fast ? p_step_fast : p_step);
3514 value_changed =
true;
3516 if (flags & ImGuiInputTextFlags_ReadOnly)
3519 const char* label_end = FindRenderedTextEnd(label);
3520 if (label != label_end)
3522 SameLine(0, style.ItemInnerSpacing.x);
3523 TextEx(label, label_end);
3525 style.FramePadding = backup_frame_padding;
3531 MarkItemEdited(
g.LastItemData.ID);
3533 return value_changed;
3536bool ImGui::InputScalarN(
const char* label, ImGuiDataType data_type,
void* p_data,
int components,
const void* p_step,
const void* p_step_fast,
const char* format, ImGuiInputTextFlags flags)
3538 ImGuiWindow* window = GetCurrentWindow();
3539 if (window->SkipItems)
3543 bool value_changed =
false;
3546 PushMultiItemsWidths(components, CalcItemWidth());
3547 size_t type_size = GDataTypeInfo[data_type].Size;
3548 for (
int i = 0; i < components; i++)
3552 SameLine(0,
g.Style.ItemInnerSpacing.x);
3553 value_changed |= InputScalar(
"", data_type, p_data, p_step, p_step_fast, format, flags);
3556 p_data = (
void*)((
char*)p_data + type_size);
3560 const char* label_end = FindRenderedTextEnd(label);
3561 if (label != label_end)
3563 SameLine(0.0f,
g.Style.ItemInnerSpacing.x);
3564 TextEx(label, label_end);
3568 return value_changed;
3571bool ImGui::InputFloat(
const char* label,
float* v,
float step,
float step_fast,
const char* format, ImGuiInputTextFlags flags)
3573 return InputScalar(label, ImGuiDataType_Float, (
void*)v, (
void*)(step > 0.0f ? &step : NULL), (void*)(step_fast > 0.0f ? &step_fast : NULL),
format, flags);
3576bool ImGui::InputFloat2(
const char* label,
float v[2],
const char* format, ImGuiInputTextFlags flags)
3578 return InputScalarN(label, ImGuiDataType_Float, v, 2, NULL, NULL, format, flags);
3581bool ImGui::InputFloat3(
const char* label,
float v[3],
const char* format, ImGuiInputTextFlags flags)
3583 return InputScalarN(label, ImGuiDataType_Float, v, 3, NULL, NULL, format, flags);
3586bool ImGui::InputFloat4(
const char* label,
float v[4],
const char* format, ImGuiInputTextFlags flags)
3588 return InputScalarN(label, ImGuiDataType_Float, v, 4, NULL, NULL, format, flags);
3591bool ImGui::InputInt(
const char* label,
int* v,
int step,
int step_fast, ImGuiInputTextFlags flags)
3594 const char*
format = (flags & ImGuiInputTextFlags_CharsHexadecimal) ?
"%08X" :
"%d";
3595 return InputScalar(label, ImGuiDataType_S32, (
void*)v, (
void*)(step > 0 ? &step : NULL), (void*)(step_fast > 0 ? &step_fast : NULL),
format, flags);
3598bool ImGui::InputInt2(
const char* label,
int v[2], ImGuiInputTextFlags flags)
3600 return InputScalarN(label, ImGuiDataType_S32, v, 2, NULL, NULL,
"%d", flags);
3603bool ImGui::InputInt3(
const char* label,
int v[3], ImGuiInputTextFlags flags)
3605 return InputScalarN(label, ImGuiDataType_S32, v, 3, NULL, NULL,
"%d", flags);
3608bool ImGui::InputInt4(
const char* label,
int v[4], ImGuiInputTextFlags flags)
3610 return InputScalarN(label, ImGuiDataType_S32, v, 4, NULL, NULL,
"%d", flags);
3613bool ImGui::InputDouble(
const char* label,
double* v,
double step,
double step_fast,
const char* format, ImGuiInputTextFlags flags)
3615 return InputScalar(label, ImGuiDataType_Double, (
void*)v, (
void*)(step > 0.0 ? &step : NULL), (void*)(step_fast > 0.0 ? &step_fast : NULL),
format, flags);
3631bool ImGui::InputText(
const char* label,
char* buf,
size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* user_data)
3633 IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline));
3634 return InputTextEx(label, NULL, buf, (
int)buf_size, ImVec2(0, 0), flags, callback, user_data);
3637bool ImGui::InputTextMultiline(
const char* label,
char* buf,
size_t buf_size,
const ImVec2& size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* user_data)
3639 return InputTextEx(label, NULL, buf, (
int)buf_size, size, flags | ImGuiInputTextFlags_Multiline, callback, user_data);
3642bool ImGui::InputTextWithHint(
const char* label,
const char* hint,
char* buf,
size_t buf_size, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* user_data)
3644 IM_ASSERT(!(flags & ImGuiInputTextFlags_Multiline));
3645 return InputTextEx(label, hint, buf, (
int)buf_size, ImVec2(0, 0), flags, callback, user_data);
3648static int InputTextCalcTextLenAndLineCount(
const char* text_begin,
const char** out_text_end)
3651 const char* s = text_begin;
3652 while (
char c = *s++)
3656 if (s[0] !=
'\n' && s[0] !=
'\r')
3662static ImVec2 InputTextCalcTextSizeW(ImGuiContext* ctx,
const ImWchar* text_begin,
const ImWchar* text_end,
const ImWchar** remaining, ImVec2* out_offset,
bool stop_on_new_line)
3664 ImGuiContext&
g = *ctx;
3665 ImFont* font =
g.Font;
3666 const float line_height =
g.FontSize;
3667 const float scale = line_height / font->FontSize;
3669 ImVec2 text_size = ImVec2(0, 0);
3670 float line_width = 0.0f;
3672 const ImWchar* s = text_begin;
3673 while (s < text_end)
3675 unsigned int c = (
unsigned int)(*s++);
3678 text_size.x = ImMax(text_size.x, line_width);
3679 text_size.y += line_height;
3681 if (stop_on_new_line)
3688 const float char_width = font->GetCharAdvance((ImWchar)c) *
scale;
3689 line_width += char_width;
3692 if (text_size.x < line_width)
3693 text_size.x = line_width;
3696 *out_offset = ImVec2(line_width, text_size.y + line_height);
3698 if (line_width > 0 || text_size.y == 0.0f)
3699 text_size.y += line_height;
3711static int STB_TEXTEDIT_STRINGLEN(
const ImGuiInputTextState* obj) {
return obj->CurLenW; }
3712static ImWchar STB_TEXTEDIT_GETCHAR(
const ImGuiInputTextState* obj,
int idx) { IM_ASSERT(idx <= obj->CurLenW);
return obj->TextW[idx]; }
3713static float STB_TEXTEDIT_GETWIDTH(ImGuiInputTextState* obj,
int line_start_idx,
int char_idx) { ImWchar c = obj->TextW[line_start_idx + char_idx];
if (c ==
'\n')
return IMSTB_TEXTEDIT_GETWIDTH_NEWLINE; ImGuiContext&
g = *obj->Ctx;
return g.Font->GetCharAdvance(c) * (
g.FontSize /
g.Font->FontSize); }
3714static int STB_TEXTEDIT_KEYTOTEXT(
int key) {
return key >= 0x200000 ? 0 : key; }
3715static ImWchar STB_TEXTEDIT_NEWLINE =
'\n';
3716static void STB_TEXTEDIT_LAYOUTROW(StbTexteditRow* r, ImGuiInputTextState* obj,
int line_start_idx)
3718 const ImWchar* text = obj->TextW.Data;
3719 const ImWchar* text_remaining = NULL;
3720 const ImVec2 size = InputTextCalcTextSizeW(obj->Ctx, text + line_start_idx, text + obj->CurLenW, &text_remaining, NULL,
true);
3723 r->baseline_y_delta = size.y;
3726 r->num_chars = (int)(text_remaining - (text + line_start_idx));
3729static bool is_separator(
unsigned int c)
3731 return c==
',' || c==
';' || c==
'(' || c==
')' || c==
'{' || c==
'}' || c==
'[' || c==
']' || c==
'|' || c==
'\n' || c==
'\r' || c==
'.' || c==
'!';
3734static int is_word_boundary_from_right(ImGuiInputTextState* obj,
int idx)
3737 if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
3740 bool prev_white = ImCharIsBlankW(obj->TextW[idx - 1]);
3741 bool prev_separ = is_separator(obj->TextW[idx - 1]);
3742 bool curr_white = ImCharIsBlankW(obj->TextW[idx]);
3743 bool curr_separ = is_separator(obj->TextW[idx]);
3744 return ((prev_white || prev_separ) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
3746static int is_word_boundary_from_left(ImGuiInputTextState* obj,
int idx)
3748 if ((obj->Flags & ImGuiInputTextFlags_Password) || idx <= 0)
3751 bool prev_white = ImCharIsBlankW(obj->TextW[idx]);
3752 bool prev_separ = is_separator(obj->TextW[idx]);
3753 bool curr_white = ImCharIsBlankW(obj->TextW[idx - 1]);
3754 bool curr_separ = is_separator(obj->TextW[idx - 1]);
3755 return ((prev_white) && !(curr_separ || curr_white)) || (curr_separ && !prev_separ);
3757static 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; }
3758static 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; }
3759static 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; }
3760static int STB_TEXTEDIT_MOVEWORDRIGHT_IMPL(ImGuiInputTextState* obj,
int idx) { ImGuiContext&
g = *obj->Ctx;
if (
g.IO.ConfigMacOSXBehaviors)
return STB_TEXTEDIT_MOVEWORDRIGHT_MAC(obj, idx);
else return STB_TEXTEDIT_MOVEWORDRIGHT_WIN(obj, idx); }
3761#define STB_TEXTEDIT_MOVEWORDLEFT STB_TEXTEDIT_MOVEWORDLEFT_IMPL
3762#define STB_TEXTEDIT_MOVEWORDRIGHT STB_TEXTEDIT_MOVEWORDRIGHT_IMPL
3764static void STB_TEXTEDIT_DELETECHARS(ImGuiInputTextState* obj,
int pos,
int n)
3766 ImWchar* dst = obj->TextW.Data + pos;
3774 const ImWchar* src = obj->TextW.Data + pos + n;
3775 while (ImWchar c = *src++)
3780static bool STB_TEXTEDIT_INSERTCHARS(ImGuiInputTextState* obj,
int pos,
const ImWchar* new_text,
int new_text_len)
3782 const bool is_resizable = (obj->Flags & ImGuiInputTextFlags_CallbackResize) != 0;
3783 const int text_len = obj->CurLenW;
3784 IM_ASSERT(pos <= text_len);
3787 if (!is_resizable && (new_text_len_utf8 + obj->CurLenA + 1 > obj->BufCapacityA))
3791 if (new_text_len + text_len + 1 > obj->TextW.Size)
3795 IM_ASSERT(text_len < obj->TextW.Size);
3796 obj->TextW.resize(text_len + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1);
3799 ImWchar* text = obj->TextW.Data;
3800 if (pos != text_len)
3801 memmove(text + pos + new_text_len, text + pos, (
size_t)(text_len - pos) *
sizeof(ImWchar));
3802 memcpy(text + pos, new_text, (
size_t)new_text_len *
sizeof(ImWchar));
3805 obj->CurLenW += new_text_len;
3806 obj->CurLenA += new_text_len_utf8;
3807 obj->TextW[obj->CurLenW] =
'\0';
3813#define STB_TEXTEDIT_K_LEFT 0x200000
3814#define STB_TEXTEDIT_K_RIGHT 0x200001
3815#define STB_TEXTEDIT_K_UP 0x200002
3816#define STB_TEXTEDIT_K_DOWN 0x200003
3817#define STB_TEXTEDIT_K_LINESTART 0x200004
3818#define STB_TEXTEDIT_K_LINEEND 0x200005
3819#define STB_TEXTEDIT_K_TEXTSTART 0x200006
3820#define STB_TEXTEDIT_K_TEXTEND 0x200007
3821#define STB_TEXTEDIT_K_DELETE 0x200008
3822#define STB_TEXTEDIT_K_BACKSPACE 0x200009
3823#define STB_TEXTEDIT_K_UNDO 0x20000A
3824#define STB_TEXTEDIT_K_REDO 0x20000B
3825#define STB_TEXTEDIT_K_WORDLEFT 0x20000C
3826#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D
3827#define STB_TEXTEDIT_K_PGUP 0x20000E
3828#define STB_TEXTEDIT_K_PGDOWN 0x20000F
3829#define STB_TEXTEDIT_K_SHIFT 0x400000
3831#define IMSTB_TEXTEDIT_IMPLEMENTATION
3832#define IMSTB_TEXTEDIT_memmove memmove
3833#include "imstb_textedit.h"
3837static void stb_textedit_replace(ImGuiInputTextState* str, STB_TexteditState* state,
const IMSTB_TEXTEDIT_CHARTYPE* text,
int text_len)
3839 stb_text_makeundo_replace(str, state, 0, str->CurLenW, text_len);
3840 ImStb::STB_TEXTEDIT_DELETECHARS(str, 0, str->CurLenW);
3841 state->cursor = state->select_start = state->select_end = 0;
3844 if (ImStb::STB_TEXTEDIT_INSERTCHARS(str, 0, text, text_len))
3846 state->cursor = state->select_start = state->select_end = text_len;
3847 state->has_preferred_x = 0;
3855void ImGuiInputTextState::OnKeyPressed(
int key)
3857 stb_textedit_key(
this, &Stb, key);
3858 CursorFollow =
true;
3862ImGuiInputTextCallbackData::ImGuiInputTextCallbackData()
3864 memset(
this, 0,
sizeof(*
this));
3870void ImGuiInputTextCallbackData::DeleteChars(
int pos,
int bytes_count)
3872 IM_ASSERT(pos + bytes_count <= BufTextLen);
3873 char* dst = Buf + pos;
3874 const char* src = Buf + pos + bytes_count;
3875 while (
char c = *src++)
3879 if (CursorPos >= pos + bytes_count)
3880 CursorPos -= bytes_count;
3881 else if (CursorPos >= pos)
3883 SelectionStart = SelectionEnd = CursorPos;
3885 BufTextLen -= bytes_count;
3888void ImGuiInputTextCallbackData::InsertChars(
int pos,
const char* new_text,
const char* new_text_end)
3891 if (new_text == new_text_end)
3894 const bool is_resizable = (Flags & ImGuiInputTextFlags_CallbackResize) != 0;
3895 const int new_text_len = new_text_end ? (int)(new_text_end - new_text) : (int)strlen(new_text);
3896 if (new_text_len + BufTextLen >= BufSize)
3902 ImGuiContext&
g = *Ctx;
3903 ImGuiInputTextState* edit_state = &
g.InputTextState;
3904 IM_ASSERT(edit_state->ID != 0 &&
g.ActiveId == edit_state->ID);
3905 IM_ASSERT(Buf == edit_state->TextA.Data);
3906 int new_buf_size = BufTextLen + ImClamp(new_text_len * 4, 32, ImMax(256, new_text_len)) + 1;
3907 edit_state->TextA.reserve(new_buf_size + 1);
3908 Buf = edit_state->TextA.Data;
3909 BufSize = edit_state->BufCapacityA = new_buf_size;
3912 if (BufTextLen != pos)
3913 memmove(Buf + pos + new_text_len, Buf + pos, (
size_t)(BufTextLen - pos));
3914 memcpy(Buf + pos, new_text, (
size_t)new_text_len *
sizeof(
char));
3915 Buf[BufTextLen + new_text_len] =
'\0';
3917 if (CursorPos >= pos)
3918 CursorPos += new_text_len;
3919 SelectionStart = SelectionEnd = CursorPos;
3921 BufTextLen += new_text_len;
3925static bool InputTextFilterCharacter(ImGuiContext* ctx,
unsigned int* p_char, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* user_data, ImGuiInputSource input_source)
3927 IM_ASSERT(input_source == ImGuiInputSource_Keyboard || input_source == ImGuiInputSource_Clipboard);
3928 unsigned int c = *p_char;
3931 bool apply_named_filters =
true;
3935 pass |= (c ==
'\n') && (flags & ImGuiInputTextFlags_Multiline) != 0;
3936 pass |= (c ==
'\t') && (flags & ImGuiInputTextFlags_AllowTabInput) != 0;
3939 apply_named_filters =
false;
3942 if (input_source != ImGuiInputSource_Clipboard)
3949 if (c >= 0xE000 && c <= 0xF8FF)
3954 if (c > IM_UNICODE_CODEPOINT_MAX)
3958 if (apply_named_filters && (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase | ImGuiInputTextFlags_CharsNoBlank | ImGuiInputTextFlags_CharsScientific)))
3966 ImGuiContext&
g = *ctx;
3967 const unsigned c_decimal_point = (
unsigned int)
g.IO.PlatformLocaleDecimalPoint;
3968 if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific))
3969 if (c ==
'.' || c ==
',')
3970 c = c_decimal_point;
3975 if (flags & (ImGuiInputTextFlags_CharsDecimal | ImGuiInputTextFlags_CharsScientific | ImGuiInputTextFlags_CharsHexadecimal))
3976 if (c >= 0xFF01 && c <= 0xFF5E)
3977 c = c - 0xFF01 + 0x21;
3980 if (flags & ImGuiInputTextFlags_CharsDecimal)
3981 if (!(c >=
'0' && c <=
'9') && (c != c_decimal_point) && (c !=
'-') && (c !=
'+') && (c !=
'*') && (c !=
'/'))
3985 if (flags & ImGuiInputTextFlags_CharsScientific)
3986 if (!(c >=
'0' && c <=
'9') && (c != c_decimal_point) && (c !=
'-') && (c !=
'+') && (c !=
'*') && (c !=
'/') && (c !=
'e') && (c !=
'E'))
3990 if (flags & ImGuiInputTextFlags_CharsHexadecimal)
3991 if (!(c >=
'0' && c <=
'9') && !(c >=
'a' && c <=
'f') && !(c >=
'A' && c <=
'F'))
3995 if (flags & ImGuiInputTextFlags_CharsUppercase)
3996 if (c >=
'a' && c <=
'z')
3997 c += (
unsigned int)(
'A' -
'a');
3999 if (flags & ImGuiInputTextFlags_CharsNoBlank)
4000 if (ImCharIsBlankW(c))
4007 if (flags & ImGuiInputTextFlags_CallbackCharFilter)
4010 ImGuiInputTextCallbackData callback_data;
4011 callback_data.Ctx = &
g;
4012 callback_data.EventFlag = ImGuiInputTextFlags_CallbackCharFilter;
4013 callback_data.EventChar = (ImWchar)c;
4014 callback_data.Flags = flags;
4015 callback_data.UserData = user_data;
4016 if (callback(&callback_data) != 0)
4018 *p_char = callback_data.EventChar;
4019 if (!callback_data.EventChar)
4029static void InputTextReconcileUndoStateAfterUserCallback(ImGuiInputTextState* state,
const char* new_buf_a,
int new_length_a)
4032 const ImWchar* old_buf = state->TextW.Data;
4033 const int old_length = state->CurLenW;
4035 g.TempBuffer.reserve_discard((new_length + 1) *
sizeof(ImWchar));
4036 ImWchar* new_buf = (ImWchar*)(
void*)
g.TempBuffer.Data;
4037 ImTextStrFromUtf8(new_buf, new_length + 1, new_buf_a, new_buf_a + new_length_a);
4039 const int shorter_length = ImMin(old_length, new_length);
4041 for (first_diff = 0; first_diff < shorter_length; first_diff++)
4042 if (old_buf[first_diff] != new_buf[first_diff])
4044 if (first_diff == old_length && first_diff == new_length)
4047 int old_last_diff = old_length - 1;
4048 int new_last_diff = new_length - 1;
4049 for (; old_last_diff >= first_diff && new_last_diff >= first_diff; old_last_diff--, new_last_diff--)
4050 if (old_buf[old_last_diff] != new_buf[new_last_diff])
4053 const int insert_len = new_last_diff - first_diff + 1;
4054 const int delete_len = old_last_diff - first_diff + 1;
4055 if (insert_len > 0 || delete_len > 0)
4056 if (IMSTB_TEXTEDIT_CHARTYPE* p = stb_text_createundo(&state->Stb.undostate, first_diff, delete_len, insert_len))
4057 for (
int i = 0; i < delete_len; i++)
4058 p[i] = ImStb::STB_TEXTEDIT_GETCHAR(state, first_diff + i);
4065void ImGui::InputTextDeactivateHook(ImGuiID
id)
4068 ImGuiInputTextState* state = &
g.InputTextState;
4069 if (
id == 0 || state->ID !=
id)
4071 g.InputTextDeactivatedState.ID = state->ID;
4072 if (state->Flags & ImGuiInputTextFlags_ReadOnly)
4074 g.InputTextDeactivatedState.TextA.resize(0);
4078 IM_ASSERT(state->TextA.Data != 0);
4079 g.InputTextDeactivatedState.TextA.resize(state->CurLenA + 1);
4080 memcpy(
g.InputTextDeactivatedState.TextA.Data, state->TextA.Data, state->CurLenA + 1);
4092bool ImGui::InputTextEx(
const char* label,
const char* hint,
char* buf,
int buf_size,
const ImVec2& size_arg, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback,
void* callback_user_data)
4094 ImGuiWindow* window = GetCurrentWindow();
4095 if (window->SkipItems)
4098 IM_ASSERT(buf != NULL && buf_size >= 0);
4099 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackHistory) && (flags & ImGuiInputTextFlags_Multiline)));
4100 IM_ASSERT(!((flags & ImGuiInputTextFlags_CallbackCompletion) && (flags & ImGuiInputTextFlags_AllowTabInput)));
4104 const ImGuiStyle& style =
g.Style;
4106 const bool RENDER_SELECTION_WHEN_INACTIVE =
false;
4107 const bool is_multiline = (flags & ImGuiInputTextFlags_Multiline) != 0;
4111 const ImGuiID
id = window->GetID(label);
4112 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
4113 const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ?
g.FontSize * 8.0f : label_size.y) + style.FramePadding.y * 2.0f);
4114 const ImVec2 total_size = ImVec2(frame_size.x + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), frame_size.y);
4116 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
4117 const ImRect total_bb(frame_bb.Min, frame_bb.Min + total_size);
4119 ImGuiWindow* draw_window = window;
4120 ImVec2 inner_size = frame_size;
4121 ImGuiLastItemData item_data_backup;
4124 ImVec2 backup_pos = window->DC.CursorPos;
4125 ItemSize(total_bb, style.FramePadding.y);
4126 if (!ItemAdd(total_bb,
id, &frame_bb, ImGuiItemFlags_Inputable))
4131 item_data_backup =
g.LastItemData;
4132 window->DC.CursorPos = backup_pos;
4135 if (
g.NavActivateId ==
id && (
g.NavActivateFlags & ImGuiActivateFlags_FromTabbing) && (flags & ImGuiInputTextFlags_AllowTabInput))
4136 g.NavActivateId = 0;
4139 const ImGuiID backup_activate_id =
g.NavActivateId;
4140 if (
g.ActiveId ==
id)
4141 g.NavActivateId = 0;
4144 PushStyleColor(ImGuiCol_ChildBg, style.Colors[ImGuiCol_FrameBg]);
4145 PushStyleVar(ImGuiStyleVar_ChildRounding, style.FrameRounding);
4146 PushStyleVar(ImGuiStyleVar_ChildBorderSize, style.FrameBorderSize);
4147 PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0, 0));
4148 bool child_visible = BeginChildEx(label,
id, frame_bb.GetSize(),
true, ImGuiWindowFlags_NoMove);
4149 g.NavActivateId = backup_activate_id;
4158 draw_window =
g.CurrentWindow;
4159 draw_window->DC.NavLayersActiveMaskNext |= (1 << draw_window->DC.NavLayerCurrent);
4160 draw_window->DC.CursorPos += style.FramePadding;
4161 inner_size.x -= draw_window->ScrollbarSizes.x;
4166 ItemSize(total_bb, style.FramePadding.y);
4167 if (!(flags & ImGuiInputTextFlags_MergedItem))
4168 if (!ItemAdd(total_bb,
id, &frame_bb, ImGuiItemFlags_Inputable))
4171 const bool hovered = ItemHoverable(frame_bb,
id,
g.LastItemData.InFlags);
4173 g.MouseCursor = ImGuiMouseCursor_TextInput;
4176 ImGuiInputTextState* state = GetInputTextState(
id);
4178 if (
g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly)
4179 flags |= ImGuiInputTextFlags_ReadOnly;
4180 const bool is_readonly = (flags & ImGuiInputTextFlags_ReadOnly) != 0;
4181 const bool is_password = (flags & ImGuiInputTextFlags_Password) != 0;
4182 const bool is_undoable = (flags & ImGuiInputTextFlags_NoUndoRedo) == 0;
4183 const bool is_resizable = (flags & ImGuiInputTextFlags_CallbackResize) != 0;
4185 IM_ASSERT(callback != NULL);
4187 const bool input_requested_by_nav = (
g.ActiveId !=
id) && ((
g.NavActivateId ==
id) && ((
g.NavActivateFlags & ImGuiActivateFlags_PreferInput) || (
g.NavInputSource == ImGuiInputSource_Keyboard)));
4189 const bool user_clicked = hovered && io.MouseClicked[0];
4190 const bool user_scroll_finish = is_multiline && state != NULL &&
g.ActiveId == 0 &&
g.ActiveIdPreviousFrame == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
4191 const bool user_scroll_active = is_multiline && state != NULL &&
g.ActiveId == GetWindowScrollbarID(draw_window, ImGuiAxis_Y);
4192 bool clear_active_id =
false;
4193 bool select_all =
false;
4195 float scroll_y = is_multiline ? draw_window->Scroll.y : FLT_MAX;
4197 const bool init_reload_from_user_buf = (state != NULL && state->ReloadUserBuf);
4198 const bool init_changed_specs = (state != NULL && state->Stb.single_line != !is_multiline);
4199 const bool init_make_active = (user_clicked || user_scroll_finish || input_requested_by_nav);
4200 const bool init_state = (init_make_active || user_scroll_active);
4201 if ((init_state &&
g.ActiveId !=
id) || init_changed_specs || init_reload_from_user_buf)
4204 state = &
g.InputTextState;
4205 state->CursorAnimReset();
4206 state->ReloadUserBuf =
false;
4209 InputTextDeactivateHook(state->ID);
4212 const int buf_len = (int)strlen(buf);
4213 if (!init_reload_from_user_buf)
4216 state->InitialTextA.resize(buf_len + 1);
4217 memcpy(state->InitialTextA.Data, buf, buf_len + 1);
4222 bool recycle_state = (state->ID ==
id && !init_changed_specs && !init_reload_from_user_buf);
4223 if (recycle_state && (state->CurLenA != buf_len || (state->TextAIsValid && strncmp(state->TextA.Data, buf, buf_len) != 0)))
4224 recycle_state =
false;
4227 const char* buf_end = NULL;
4229 state->TextW.resize(buf_size + 1);
4230 state->TextA.resize(0);
4231 state->TextAIsValid =
false;
4232 state->CurLenW =
ImTextStrFromUtf8(state->TextW.Data, buf_size, buf, NULL, &buf_end);
4233 state->CurLenA = (int)(buf_end - buf);
4239 state->CursorClamp();
4243 state->ScrollX = 0.0f;
4244 stb_textedit_initialize_state(&state->Stb, !is_multiline);
4247 if (init_reload_from_user_buf)
4249 state->Stb.select_start = state->ReloadSelectionStart;
4250 state->Stb.cursor = state->Stb.select_end = state->ReloadSelectionEnd;
4251 state->CursorClamp();
4253 else if (!is_multiline)
4255 if (flags & ImGuiInputTextFlags_AutoSelectAll)
4257 if (input_requested_by_nav && (!recycle_state || !(
g.NavActivateFlags & ImGuiActivateFlags_TryToPreserveState)))
4259 if (user_clicked && io.KeyCtrl)
4263 if (flags & ImGuiInputTextFlags_AlwaysOverwrite)
4264 state->Stb.insert_mode = 1;
4267 const bool is_osx = io.ConfigMacOSXBehaviors;
4268 if (
g.ActiveId !=
id && init_make_active)
4270 IM_ASSERT(state && state->ID ==
id);
4271 SetActiveID(
id, window);
4272 SetFocusID(
id, window);
4273 FocusWindow(window);
4275 if (
g.ActiveId ==
id)
4279 SetKeyOwner(ImGuiKey_MouseLeft,
id);
4280 g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Left) | (1 << ImGuiDir_Right);
4281 if (is_multiline || (flags & ImGuiInputTextFlags_CallbackHistory))
4282 g.ActiveIdUsingNavDirMask |= (1 << ImGuiDir_Up) | (1 << ImGuiDir_Down);
4283 SetKeyOwner(ImGuiKey_Enter,
id);
4284 SetKeyOwner(ImGuiKey_KeypadEnter,
id);
4285 SetKeyOwner(ImGuiKey_Home,
id);
4286 SetKeyOwner(ImGuiKey_End,
id);
4289 SetKeyOwner(ImGuiKey_PageUp,
id);
4290 SetKeyOwner(ImGuiKey_PageDown,
id);
4293 SetKeyOwner(ImGuiMod_Alt,
id);
4297 if (
g.ActiveId ==
id && state == NULL)
4301 if (
g.ActiveId ==
id && io.MouseClicked[0] && !init_state && !init_make_active)
4302 clear_active_id =
true;
4305 bool render_cursor = (
g.ActiveId ==
id) || (state && user_scroll_active);
4306 bool render_selection = state && (state->HasSelection() || select_all) && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
4307 bool value_changed =
false;
4308 bool validated =
false;
4312 if (is_readonly && state != NULL && (render_cursor || render_selection))
4314 const char* buf_end = NULL;
4315 state->TextW.resize(buf_size + 1);
4316 state->CurLenW =
ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, buf, NULL, &buf_end);
4317 state->CurLenA = (int)(buf_end - buf);
4318 state->CursorClamp();
4319 render_selection &= state->HasSelection();
4323 const bool buf_display_from_state = (render_cursor || render_selection ||
g.ActiveId ==
id) && !is_readonly && state && state->TextAIsValid;
4324 const bool is_displaying_hint = (hint != NULL && (buf_display_from_state ? state->TextA.Data : buf)[0] == 0);
4327 if (is_password && !is_displaying_hint)
4329 const ImFontGlyph* glyph =
g.Font->FindGlyph(
'*');
4330 ImFont* password_font = &
g.InputTextPasswordFont;
4331 password_font->FontSize =
g.Font->FontSize;
4332 password_font->Scale =
g.Font->Scale;
4333 password_font->Ascent =
g.Font->Ascent;
4334 password_font->Descent =
g.Font->Descent;
4335 password_font->ContainerAtlas =
g.Font->ContainerAtlas;
4336 password_font->FallbackGlyph = glyph;
4337 password_font->FallbackAdvanceX = glyph->AdvanceX;
4338 IM_ASSERT(password_font->Glyphs.empty() && password_font->IndexAdvanceX.empty() && password_font->IndexLookup.empty());
4339 PushFont(password_font);
4343 int backup_current_text_length = 0;
4344 if (
g.ActiveId ==
id)
4346 IM_ASSERT(state != NULL);
4347 backup_current_text_length = state->CurLenA;
4348 state->Edited =
false;
4349 state->BufCapacityA = buf_size;
4350 state->Flags = flags;
4354 g.ActiveIdAllowOverlap = !io.MouseDown[0];
4357 const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
4358 const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (
g.FontSize * 0.5f));
4363 state->SelectedAllMouseLock =
true;
4365 else if (hovered && io.MouseClickedCount[0] >= 2 && !io.KeyShift)
4367 stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
4368 const int multiclick_count = (io.MouseClickedCount[0] - 2);
4369 if ((multiclick_count % 2) == 0)
4374 const bool is_bol = (state->Stb.cursor == 0) || ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor - 1) ==
'\n';
4375 if (STB_TEXT_HAS_SELECTION(&state->Stb) || !is_bol)
4378 if (!STB_TEXT_HAS_SELECTION(&state->Stb))
4379 ImStb::stb_textedit_prep_selection_at_cursor(&state->Stb);
4380 state->Stb.cursor = ImStb::STB_TEXTEDIT_MOVEWORDRIGHT_MAC(state, state->Stb.cursor);
4381 state->Stb.select_end = state->Stb.cursor;
4382 ImStb::stb_textedit_clamp(state, &state->Stb);
4387 const bool is_eol = ImStb::STB_TEXTEDIT_GETCHAR(state, state->Stb.cursor) ==
'\n';
4391 if (!is_eol && is_multiline)
4393 ImSwap(state->Stb.select_start, state->Stb.select_end);
4394 state->Stb.cursor = state->Stb.select_end;
4396 state->CursorFollow =
false;
4398 state->CursorAnimReset();
4400 else if (io.MouseClicked[0] && !state->SelectedAllMouseLock)
4405 stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
4407 stb_textedit_click(state, &state->Stb, mouse_x, mouse_y);
4408 state->CursorAnimReset();
4411 else if (io.MouseDown[0] && !state->SelectedAllMouseLock && (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f))
4413 stb_textedit_drag(state, &state->Stb, mouse_x, mouse_y);
4414 state->CursorAnimReset();
4415 state->CursorFollow =
true;
4417 if (state->SelectedAllMouseLock && !io.MouseDown[0])
4418 state->SelectedAllMouseLock =
false;
4422 if ((flags & ImGuiInputTextFlags_AllowTabInput) && !is_readonly)
4424 if (Shortcut(ImGuiKey_Tab,
id, ImGuiInputFlags_Repeat))
4426 unsigned int c =
'\t';
4427 if (InputTextFilterCharacter(&
g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
4428 state->OnKeyPressed((
int)c);
4440 const bool ignore_char_inputs = (io.KeyCtrl && !io.KeyAlt) || (is_osx && io.KeySuper);
4441 if (io.InputQueueCharacters.Size > 0)
4443 if (!ignore_char_inputs && !is_readonly && !input_requested_by_nav)
4444 for (
int n = 0; n < io.InputQueueCharacters.Size; n++)
4447 unsigned int c = (
unsigned int)io.InputQueueCharacters[n];
4450 if (InputTextFilterCharacter(&
g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
4451 state->OnKeyPressed((
int)c);
4455 io.InputQueueCharacters.resize(0);
4460 bool revert_edit =
false;
4461 if (
g.ActiveId ==
id && !
g.ActiveIdIsJustActivated && !clear_active_id)
4463 IM_ASSERT(state != NULL);
4465 const int row_count_per_page = ImMax((
int)((inner_size.y - style.FramePadding.y) /
g.FontSize), 1);
4466 state->Stb.row_count_per_page = row_count_per_page;
4469 const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl;
4470 const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt;
4474 const ImGuiInputFlags f_repeat = ImGuiInputFlags_Repeat;
4475 const bool is_cut = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_X,
id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Delete,
id, f_repeat)) && !is_readonly && !is_password && (!is_multiline || state->HasSelection());
4476 const bool is_copy = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_C,
id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_Insert,
id)) && !is_password && (!is_multiline || state->HasSelection());
4477 const bool is_paste = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_V,
id, f_repeat) || Shortcut(ImGuiMod_Shift | ImGuiKey_Insert,
id, f_repeat)) && !is_readonly;
4478 const bool is_undo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Z,
id, f_repeat)) && !is_readonly && is_undoable;
4479 const bool is_redo = (Shortcut(ImGuiMod_Shortcut | ImGuiKey_Y,
id, f_repeat) || (is_osx && Shortcut(ImGuiMod_Shortcut | ImGuiMod_Shift | ImGuiKey_Z,
id, f_repeat))) && !is_readonly && is_undoable;
4480 const bool is_select_all = Shortcut(ImGuiMod_Shortcut | ImGuiKey_A,
id);
4483 const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
4484 const bool is_enter_pressed = IsKeyPressed(ImGuiKey_Enter,
true) || IsKeyPressed(ImGuiKey_KeypadEnter,
true);
4485 const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate,
false) || IsKeyPressed(ImGuiKey_NavGamepadInput,
false));
4486 const bool is_cancel = Shortcut(ImGuiKey_Escape,
id, f_repeat) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel,
id, f_repeat));
4491 else if (IsKeyPressed(ImGuiKey_UpArrow) && is_multiline) {
if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y -
g.FontSize, 0.0f));
else state->OnKeyPressed((is_startend_key_down ?
STB_TEXTEDIT_K_TEXTSTART :
STB_TEXTEDIT_K_UP) | k_mask); }
4492 else if (IsKeyPressed(ImGuiKey_DownArrow) && is_multiline) {
if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y +
g.FontSize, GetScrollMaxY()));
else state->OnKeyPressed((is_startend_key_down ?
STB_TEXTEDIT_K_TEXTEND :
STB_TEXTEDIT_K_DOWN) | k_mask); }
4493 else if (IsKeyPressed(ImGuiKey_PageUp) && is_multiline) { state->OnKeyPressed(
STB_TEXTEDIT_K_PGUP | k_mask); scroll_y -= row_count_per_page *
g.FontSize; }
4494 else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(
STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page *
g.FontSize; }
4497 else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut)
4499 if (!state->HasSelection())
4502 if (is_wordmove_key_down)
4507 else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly)
4509 if (!state->HasSelection())
4511 if (is_wordmove_key_down)
4513 else if (is_osx && io.KeySuper && !io.KeyAlt && !io.KeyCtrl)
4518 else if (is_enter_pressed || is_gamepad_validate)
4521 bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
4522 if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
4525 if (io.ConfigInputTextEnterKeepActive && !is_multiline)
4528 clear_active_id =
true;
4530 else if (!is_readonly)
4532 unsigned int c =
'\n';
4533 if (InputTextFilterCharacter(&
g, &c, flags, callback, callback_user_data, ImGuiInputSource_Keyboard))
4534 state->OnKeyPressed((
int)c);
4539 if (flags & ImGuiInputTextFlags_EscapeClearsAll)
4547 render_cursor = render_selection =
false;
4548 clear_active_id =
true;
4553 clear_active_id = revert_edit =
true;
4554 render_cursor = render_selection =
false;
4557 else if (is_undo || is_redo)
4560 state->ClearSelection();
4562 else if (is_select_all)
4565 state->CursorFollow =
true;
4567 else if (is_cut || is_copy)
4570 if (io.SetClipboardTextFn)
4572 const int ib = state->HasSelection() ? ImMin(state->Stb.select_start, state->Stb.select_end) : 0;
4573 const int ie = state->HasSelection() ? ImMax(state->Stb.select_start, state->Stb.select_end) : state->CurLenW;
4575 char* clipboard_data = (
char*)IM_ALLOC(clipboard_data_len *
sizeof(
char));
4576 ImTextStrToUtf8(clipboard_data, clipboard_data_len, state->TextW.Data + ib, state->TextW.Data + ie);
4577 SetClipboardText(clipboard_data);
4578 MemFree(clipboard_data);
4582 if (!state->HasSelection())
4584 state->CursorFollow =
true;
4585 stb_textedit_cut(state, &state->Stb);
4590 if (
const char* clipboard = GetClipboardText())
4593 const int clipboard_len = (int)strlen(clipboard);
4594 ImWchar* clipboard_filtered = (ImWchar*)IM_ALLOC((clipboard_len + 1) *
sizeof(ImWchar));
4595 int clipboard_filtered_len = 0;
4596 for (
const char* s = clipboard; *s != 0; )
4600 if (!InputTextFilterCharacter(&
g, &c, flags, callback, callback_user_data, ImGuiInputSource_Clipboard))
4602 clipboard_filtered[clipboard_filtered_len++] = (ImWchar)c;
4604 clipboard_filtered[clipboard_filtered_len] = 0;
4605 if (clipboard_filtered_len > 0)
4607 stb_textedit_paste(state, &state->Stb, clipboard_filtered, clipboard_filtered_len);
4608 state->CursorFollow =
true;
4610 MemFree(clipboard_filtered);
4615 render_selection |= state->HasSelection() && (RENDER_SELECTION_WHEN_INACTIVE || render_cursor);
4619 const char* apply_new_text = NULL;
4620 int apply_new_text_length = 0;
4621 if (
g.ActiveId ==
id)
4623 IM_ASSERT(state != NULL);
4624 if (revert_edit && !is_readonly)
4626 if (flags & ImGuiInputTextFlags_EscapeClearsAll)
4629 IM_ASSERT(buf[0] != 0);
4630 apply_new_text =
"";
4631 apply_new_text_length = 0;
4632 value_changed =
true;
4633 IMSTB_TEXTEDIT_CHARTYPE empty_string;
4634 stb_textedit_replace(state, &state->Stb, &empty_string, 0);
4636 else if (strcmp(buf, state->InitialTextA.Data) != 0)
4640 apply_new_text = state->InitialTextA.Data;
4641 apply_new_text_length = state->InitialTextA.Size - 1;
4642 value_changed =
true;
4643 ImVector<ImWchar> w_text;
4644 if (apply_new_text_length > 0)
4647 ImTextStrFromUtf8(w_text.Data, w_text.Size, apply_new_text, apply_new_text + apply_new_text_length);
4649 stb_textedit_replace(state, &state->Stb, w_text.Data, (apply_new_text_length > 0) ? (w_text.Size - 1) : 0);
4656 state->TextAIsValid =
true;
4657 state->TextA.resize(state->TextW.Size * 4 + 1);
4658 ImTextStrToUtf8(state->TextA.Data, state->TextA.Size, state->TextW.Data, NULL);
4667 const bool apply_edit_back_to_user_buffer = !revert_edit || (validated && (flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0);
4668 if (apply_edit_back_to_user_buffer)
4676 if ((flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_CallbackHistory | ImGuiInputTextFlags_CallbackEdit | ImGuiInputTextFlags_CallbackAlways)) != 0)
4678 IM_ASSERT(callback != NULL);
4681 ImGuiInputTextFlags event_flag = 0;
4682 ImGuiKey event_key = ImGuiKey_None;
4683 if ((flags & ImGuiInputTextFlags_CallbackCompletion) != 0 && Shortcut(ImGuiKey_Tab,
id))
4685 event_flag = ImGuiInputTextFlags_CallbackCompletion;
4686 event_key = ImGuiKey_Tab;
4688 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_UpArrow))
4690 event_flag = ImGuiInputTextFlags_CallbackHistory;
4691 event_key = ImGuiKey_UpArrow;
4693 else if ((flags & ImGuiInputTextFlags_CallbackHistory) != 0 && IsKeyPressed(ImGuiKey_DownArrow))
4695 event_flag = ImGuiInputTextFlags_CallbackHistory;
4696 event_key = ImGuiKey_DownArrow;
4698 else if ((flags & ImGuiInputTextFlags_CallbackEdit) && state->Edited)
4700 event_flag = ImGuiInputTextFlags_CallbackEdit;
4702 else if (flags & ImGuiInputTextFlags_CallbackAlways)
4704 event_flag = ImGuiInputTextFlags_CallbackAlways;
4709 ImGuiInputTextCallbackData callback_data;
4710 callback_data.Ctx = &
g;
4711 callback_data.EventFlag = event_flag;
4712 callback_data.Flags = flags;
4713 callback_data.UserData = callback_user_data;
4715 char* callback_buf = is_readonly ? buf : state->TextA.Data;
4716 callback_data.EventKey = event_key;
4717 callback_data.Buf = callback_buf;
4718 callback_data.BufTextLen = state->CurLenA;
4719 callback_data.BufSize = state->BufCapacityA;
4720 callback_data.BufDirty =
false;
4723 ImWchar* text = state->TextW.Data;
4725 const int utf8_selection_start = callback_data.SelectionStart =
ImTextCountUtf8BytesFromStr(text, text + state->Stb.select_start);
4729 callback(&callback_data);
4732 callback_buf = is_readonly ? buf : state->TextA.Data;
4733 IM_ASSERT(callback_data.Buf == callback_buf);
4734 IM_ASSERT(callback_data.BufSize == state->BufCapacityA);
4735 IM_ASSERT(callback_data.Flags == flags);
4736 const bool buf_dirty = callback_data.BufDirty;
4737 if (callback_data.CursorPos != utf8_cursor_pos || buf_dirty) { state->Stb.cursor =
ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.CursorPos); state->CursorFollow =
true; }
4738 if (callback_data.SelectionStart != utf8_selection_start || buf_dirty) { state->Stb.select_start = (callback_data.SelectionStart == callback_data.CursorPos) ? state->Stb.cursor :
ImTextCountCharsFromUtf8(callback_data.Buf, callback_data.Buf + callback_data.SelectionStart); }
4739 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); }
4742 IM_ASSERT(!is_readonly);
4743 IM_ASSERT(callback_data.BufTextLen == (
int)strlen(callback_data.Buf));
4744 InputTextReconcileUndoStateAfterUserCallback(state, callback_data.Buf, callback_data.BufTextLen);
4745 if (callback_data.BufTextLen > backup_current_text_length && is_resizable)
4746 state->TextW.resize(state->TextW.Size + (callback_data.BufTextLen - backup_current_text_length));
4747 state->CurLenW =
ImTextStrFromUtf8(state->TextW.Data, state->TextW.Size, callback_data.Buf, NULL);
4748 state->CurLenA = callback_data.BufTextLen;
4749 state->CursorAnimReset();
4755 if (!is_readonly && strcmp(state->TextA.Data, buf) != 0)
4757 apply_new_text = state->TextA.Data;
4758 apply_new_text_length = state->CurLenA;
4759 value_changed =
true;
4765 if (
g.InputTextDeactivatedState.ID ==
id)
4767 if (
g.ActiveId !=
id && IsItemDeactivatedAfterEdit() && !is_readonly && strcmp(
g.InputTextDeactivatedState.TextA.Data, buf) != 0)
4769 apply_new_text =
g.InputTextDeactivatedState.TextA.Data;
4770 apply_new_text_length =
g.InputTextDeactivatedState.TextA.Size - 1;
4771 value_changed =
true;
4774 g.InputTextDeactivatedState.ID = 0;
4778 if (apply_new_text != NULL)
4783 IM_ASSERT(apply_new_text_length >= 0);
4786 ImGuiInputTextCallbackData callback_data;
4787 callback_data.Ctx = &
g;
4788 callback_data.EventFlag = ImGuiInputTextFlags_CallbackResize;
4789 callback_data.Flags = flags;
4790 callback_data.Buf = buf;
4791 callback_data.BufTextLen = apply_new_text_length;
4792 callback_data.BufSize = ImMax(buf_size, apply_new_text_length + 1);
4793 callback_data.UserData = callback_user_data;
4794 callback(&callback_data);
4795 buf = callback_data.Buf;
4796 buf_size = callback_data.BufSize;
4797 apply_new_text_length = ImMin(callback_data.BufTextLen, buf_size - 1);
4798 IM_ASSERT(apply_new_text_length <= buf_size);
4803 ImStrncpy(buf, apply_new_text, ImMin(apply_new_text_length + 1, buf_size));
4808 if (
g.ActiveId ==
id && clear_active_id)
4810 else if (
g.ActiveId ==
id)
4811 g.WantTextInputNextFrame = 1;
4816 RenderNavHighlight(frame_bb,
id);
4817 RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg),
true, style.FrameRounding);
4820 const ImVec4 clip_rect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + inner_size.x, frame_bb.Min.y + inner_size.y);
4821 ImVec2 draw_pos = is_multiline ? draw_window->DC.CursorPos : frame_bb.Min + style.FramePadding;
4822 ImVec2 text_size(0.0f, 0.0f);
4827 const int buf_display_max_length = 2 * 1024 * 1024;
4828 const char* buf_display = buf_display_from_state ? state->TextA.Data : buf;
4829 const char* buf_display_end = NULL;
4830 if (is_displaying_hint)
4833 buf_display_end = hint + strlen(hint);
4838 if (render_cursor || render_selection)
4840 IM_ASSERT(state != NULL);
4841 if (!is_displaying_hint)
4842 buf_display_end = buf_display + state->CurLenA;
4851 const ImWchar* text_begin = state->TextW.Data;
4852 ImVec2 cursor_offset, select_start_offset;
4856 const ImWchar* searches_input_ptr[2] = { NULL, NULL };
4857 int searches_result_line_no[2] = { -1000, -1000 };
4858 int searches_remaining = 0;
4861 searches_input_ptr[0] = text_begin + state->Stb.cursor;
4862 searches_result_line_no[0] = -1;
4863 searches_remaining++;
4865 if (render_selection)
4867 searches_input_ptr[1] = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
4868 searches_result_line_no[1] = -1;
4869 searches_remaining++;
4874 searches_remaining += is_multiline ? 1 : 0;
4877 for (
const ImWchar* s = text_begin; *s != 0; s++)
4881 if (searches_result_line_no[0] == -1 && s >= searches_input_ptr[0]) { searches_result_line_no[0] = line_count;
if (--searches_remaining <= 0)
break; }
4882 if (searches_result_line_no[1] == -1 && s >= searches_input_ptr[1]) { searches_result_line_no[1] = line_count;
if (--searches_remaining <= 0)
break; }
4885 if (searches_result_line_no[0] == -1)
4886 searches_result_line_no[0] = line_count;
4887 if (searches_result_line_no[1] == -1)
4888 searches_result_line_no[1] = line_count;
4891 cursor_offset.x = InputTextCalcTextSizeW(&
g,
ImStrbolW(searches_input_ptr[0], text_begin), searches_input_ptr[0]).x;
4892 cursor_offset.y = searches_result_line_no[0] *
g.FontSize;
4893 if (searches_result_line_no[1] >= 0)
4895 select_start_offset.x = InputTextCalcTextSizeW(&
g,
ImStrbolW(searches_input_ptr[1], text_begin), searches_input_ptr[1]).x;
4896 select_start_offset.y = searches_result_line_no[1] *
g.FontSize;
4901 text_size = ImVec2(inner_size.x, line_count *
g.FontSize);
4905 if (render_cursor && state->CursorFollow)
4908 if (!(flags & ImGuiInputTextFlags_NoHorizontalScroll))
4910 const float scroll_increment_x = inner_size.x * 0.25f;
4911 const float visible_width = inner_size.x - style.FramePadding.x;
4912 if (cursor_offset.x < state->ScrollX)
4913 state->ScrollX = IM_TRUNC(ImMax(0.0f, cursor_offset.x - scroll_increment_x));
4914 else if (cursor_offset.x - visible_width >= state->ScrollX)
4915 state->ScrollX = IM_TRUNC(cursor_offset.x - visible_width + scroll_increment_x);
4919 state->ScrollX = 0.0f;
4926 if (cursor_offset.y -
g.FontSize < scroll_y)
4927 scroll_y = ImMax(0.0f, cursor_offset.y -
g.FontSize);
4928 else if (cursor_offset.y - (inner_size.y - style.FramePadding.y * 2.0f) >= scroll_y)
4929 scroll_y = cursor_offset.y - inner_size.y + style.FramePadding.y * 2.0f;
4930 const float scroll_max_y = ImMax((text_size.y + style.FramePadding.y * 2.0f) - inner_size.y, 0.0f);
4931 scroll_y = ImClamp(scroll_y, 0.0f, scroll_max_y);
4932 draw_pos.y += (draw_window->Scroll.y - scroll_y);
4933 draw_window->Scroll.y = scroll_y;
4936 state->CursorFollow =
false;
4940 const ImVec2 draw_scroll = ImVec2(state->ScrollX, 0.0f);
4941 if (render_selection)
4943 const ImWchar* text_selected_begin = text_begin + ImMin(state->Stb.select_start, state->Stb.select_end);
4944 const ImWchar* text_selected_end = text_begin + ImMax(state->Stb.select_start, state->Stb.select_end);
4946 ImU32 bg_color = GetColorU32(ImGuiCol_TextSelectedBg, render_cursor ? 1.0f : 0.6f);
4947 float bg_offy_up = is_multiline ? 0.0f : -1.0f;
4948 float bg_offy_dn = is_multiline ? 0.0f : 2.0f;
4949 ImVec2 rect_pos = draw_pos + select_start_offset - draw_scroll;
4950 for (
const ImWchar* p = text_selected_begin; p < text_selected_end; )
4952 if (rect_pos.y > clip_rect.w +
g.FontSize)
4954 if (rect_pos.y < clip_rect.y)
4958 while (p < text_selected_end)
4964 ImVec2 rect_size = InputTextCalcTextSizeW(&
g, p, text_selected_end, &p, NULL,
true);
4965 if (rect_size.x <= 0.0f) rect_size.x = IM_TRUNC(
g.Font->GetCharAdvance((ImWchar)
' ') * 0.50f);
4966 ImRect rect(rect_pos + ImVec2(0.0f, bg_offy_up -
g.FontSize), rect_pos + ImVec2(rect_size.x, bg_offy_dn));
4967 rect.ClipWith(clip_rect);
4968 if (rect.Overlaps(clip_rect))
4969 draw_window->DrawList->AddRectFilled(rect.Min, rect.Max, bg_color);
4971 rect_pos.x = draw_pos.x - draw_scroll.x;
4972 rect_pos.y +=
g.FontSize;
4977 if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
4979 ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
4980 draw_window->DrawList->AddText(
g.Font,
g.FontSize, draw_pos - draw_scroll, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);
4986 state->CursorAnim += io.DeltaTime;
4987 bool cursor_is_visible = (!
g.IO.ConfigInputTextCursorBlink) || (state->CursorAnim <= 0.0f) || ImFmod(state->CursorAnim, 1.20f) <= 0.80f;
4988 ImVec2 cursor_screen_pos = ImTrunc(draw_pos + cursor_offset - draw_scroll);
4989 ImRect cursor_screen_rect(cursor_screen_pos.x, cursor_screen_pos.y -
g.FontSize + 0.5f, cursor_screen_pos.x + 1.0f, cursor_screen_pos.y - 1.5f);
4990 if (cursor_is_visible && cursor_screen_rect.Overlaps(clip_rect))
4991 draw_window->DrawList->AddLine(cursor_screen_rect.Min, cursor_screen_rect.GetBL(), GetColorU32(ImGuiCol_Text));
4996 g.PlatformImeData.WantVisible =
true;
4997 g.PlatformImeData.InputPos = ImVec2(cursor_screen_pos.x - 1.0f, cursor_screen_pos.y -
g.FontSize);
4998 g.PlatformImeData.InputLineHeight =
g.FontSize;
4999 g.PlatformImeViewport = window->Viewport->ID;
5007 text_size = ImVec2(inner_size.x, InputTextCalcTextLenAndLineCount(buf_display, &buf_display_end) *
g.FontSize);
5008 else if (!is_displaying_hint &&
g.ActiveId ==
id)
5009 buf_display_end = buf_display + state->CurLenA;
5010 else if (!is_displaying_hint)
5011 buf_display_end = buf_display + strlen(buf_display);
5013 if (is_multiline || (buf_display_end - buf_display) < buf_display_max_length)
5015 ImU32 col = GetColorU32(is_displaying_hint ? ImGuiCol_TextDisabled : ImGuiCol_Text);
5016 draw_window->DrawList->AddText(
g.Font,
g.FontSize, draw_pos, col, buf_display, buf_display_end, 0.0f, is_multiline ? NULL : &clip_rect);
5020 if (is_password && !is_displaying_hint)
5026 Dummy(ImVec2(text_size.x, text_size.y + style.FramePadding.y));
5027 g.NextItemData.ItemFlags |= ImGuiItemFlags_Inputable | ImGuiItemFlags_NoTabStop;
5029 item_data_backup.StatusFlags |= (
g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredWindow);
5034 if (
g.LastItemData.ID == 0)
5036 g.LastItemData.ID =
id;
5037 g.LastItemData.InFlags = item_data_backup.InFlags;
5038 g.LastItemData.StatusFlags = item_data_backup.StatusFlags;
5043 if (
g.LogEnabled && (!is_password || is_displaying_hint))
5045 LogSetNextTextDecoration(
"{",
"}");
5046 LogRenderedText(&draw_pos, buf_display, buf_display_end);
5049 if (label_size.x > 0)
5050 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
5052 if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
5055 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Inputable);
5056 if ((flags & ImGuiInputTextFlags_EnterReturnsTrue) != 0)
5059 return value_changed;
5062void ImGui::DebugNodeInputTextState(ImGuiInputTextState* state)
5064#ifndef IMGUI_DISABLE_DEBUG_TOOLS
5066 ImStb::STB_TexteditState* stb_state = &state->Stb;
5067 ImStb::StbUndoState* undo_state = &stb_state->undostate;
5068 Text(
"ID: 0x%08X, ActiveID: 0x%08X", state->ID,
g.ActiveId);
5069 DebugLocateItemOnHover(state->ID);
5070 Text(
"CurLenW: %d, CurLenA: %d, Cursor: %d, Selection: %d..%d", state->CurLenW, state->CurLenA, stb_state->cursor, stb_state->select_start, stb_state->select_end);
5071 Text(
"has_preferred_x: %d (%.2f)", stb_state->has_preferred_x, stb_state->preferred_x);
5072 Text(
"undo_point: %d, redo_point: %d, undo_char_point: %d, redo_char_point: %d", undo_state->undo_point, undo_state->redo_point, undo_state->undo_char_point, undo_state->redo_char_point);
5073 if (BeginChild(
"undopoints", ImVec2(0.0f, GetTextLineHeight() * 10), ImGuiChildFlags_Border | ImGuiChildFlags_ResizeY))
5075 PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(0, 0));
5076 for (
int n = 0; n < IMSTB_TEXTEDIT_UNDOSTATECOUNT; n++)
5078 ImStb::StbUndoRecord* undo_rec = &undo_state->undo_rec[n];
5079 const char undo_rec_type = (n < undo_state->undo_point) ?
'u' : (n >= undo_state->redo_point) ?
'r' :
' ';
5080 if (undo_rec_type ==
' ')
5083 if (undo_rec_type !=
' ' && undo_rec->char_storage != -1)
5084 ImTextStrToUtf8(buf, IM_ARRAYSIZE(buf), undo_state->undo_char + undo_rec->char_storage, undo_state->undo_char + undo_rec->char_storage + undo_rec->insert_length);
5085 Text(
"%c [%02d] where %03d, insert %03d, delete %03d, char_storage %03d \"%s\"",
5086 undo_rec_type, n, undo_rec->where, undo_rec->insert_length, undo_rec->delete_length, undo_rec->char_storage, buf);
5087 if (undo_rec_type ==
' ')
5113bool ImGui::ColorEdit3(
const char* label,
float col[3], ImGuiColorEditFlags flags)
5115 return ColorEdit4(label, col, flags | ImGuiColorEditFlags_NoAlpha);
5118static void ColorEditRestoreH(
const float* col,
float* H)
5121 IM_ASSERT(
g.ColorEditCurrentID != 0);
5122 if (
g.ColorEditSavedID !=
g.ColorEditCurrentID ||
g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))
5124 *
H =
g.ColorEditSavedHue;
5129static void ColorEditRestoreHS(
const float* col,
float* H,
float*
S,
float* V)
5132 IM_ASSERT(
g.ColorEditCurrentID != 0);
5133 if (
g.ColorEditSavedID !=
g.ColorEditCurrentID ||
g.ColorEditSavedColor != ImGui::ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0)))
5138 if (*
S == 0.0f || (*H == 0.0f &&
g.ColorEditSavedHue == 1))
5139 *
H =
g.ColorEditSavedHue;
5143 *
S =
g.ColorEditSavedSat;
5149bool ImGui::ColorEdit4(
const char* label,
float col[4], ImGuiColorEditFlags flags)
5151 ImGuiWindow* window = GetCurrentWindow();
5152 if (window->SkipItems)
5156 const ImGuiStyle& style =
g.Style;
5157 const float square_sz = GetFrameHeight();
5158 const char* label_display_end = FindRenderedTextEnd(label);
5159 float w_full = CalcItemWidth();
5160 g.NextItemData.ClearFlags();
5164 const bool set_current_color_edit_id = (
g.ColorEditCurrentID == 0);
5165 if (set_current_color_edit_id)
5166 g.ColorEditCurrentID = window->IDStack.back();
5169 const ImGuiColorEditFlags flags_untouched = flags;
5170 if (flags & ImGuiColorEditFlags_NoInputs)
5171 flags = (flags & (~ImGuiColorEditFlags_DisplayMask_)) | ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_NoOptions;
5174 if (!(flags & ImGuiColorEditFlags_NoOptions))
5175 ColorEditOptionsPopup(col, flags);
5178 if (!(flags & ImGuiColorEditFlags_DisplayMask_))
5179 flags |= (
g.ColorEditOptions & ImGuiColorEditFlags_DisplayMask_);
5180 if (!(flags & ImGuiColorEditFlags_DataTypeMask_))
5181 flags |= (
g.ColorEditOptions & ImGuiColorEditFlags_DataTypeMask_);
5182 if (!(flags & ImGuiColorEditFlags_PickerMask_))
5183 flags |= (
g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_);
5184 if (!(flags & ImGuiColorEditFlags_InputMask_))
5185 flags |= (
g.ColorEditOptions & ImGuiColorEditFlags_InputMask_);
5186 flags |= (
g.ColorEditOptions & ~(ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_));
5187 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_));
5188 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));
5190 const bool alpha = (flags & ImGuiColorEditFlags_NoAlpha) == 0;
5191 const bool hdr = (flags & ImGuiColorEditFlags_HDR) != 0;
5192 const int components = alpha ? 4 : 3;
5193 const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
5194 const float w_inputs = ImMax(w_full - w_button, 1.0f);
5195 w_full = w_inputs + w_button;
5198 float f[4] = { col[0], col[1], col[2], alpha ? col[3] : 1.0f };
5199 if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB))
5200 ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
5201 else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV))
5204 ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
5205 ColorEditRestoreHS(col, &f[0], &f[1], &f[2]);
5207 int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) };
5209 bool value_changed =
false;
5210 bool value_changed_as_float =
false;
5212 const ImVec2 pos = window->DC.CursorPos;
5213 const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f;
5214 window->DC.CursorPos.x = pos.x + inputs_offset_x;
5216 if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
5219 const float w_items = w_inputs - style.ItemInnerSpacing.x * (components - 1);
5221 const bool hide_prefix = (IM_TRUNC(w_items / components) <=
CalcTextSize((flags & ImGuiColorEditFlags_Float) ?
"M:0.000" :
"M:000").x);
5222 static const char* ids[4] = {
"##X",
"##Y",
"##Z",
"##W" };
5223 static const char* fmt_table_int[3][4] =
5225 {
"%3d",
"%3d",
"%3d",
"%3d" },
5226 {
"R:%3d",
"G:%3d",
"B:%3d",
"A:%3d" },
5227 {
"H:%3d",
"S:%3d",
"V:%3d",
"A:%3d" }
5229 static const char* fmt_table_float[3][4] =
5231 {
"%0.3f",
"%0.3f",
"%0.3f",
"%0.3f" },
5232 {
"R:%0.3f",
"G:%0.3f",
"B:%0.3f",
"A:%0.3f" },
5233 {
"H:%0.3f",
"S:%0.3f",
"V:%0.3f",
"A:%0.3f" }
5235 const int fmt_idx = hide_prefix ? 0 : (flags & ImGuiColorEditFlags_DisplayHSV) ? 2 : 1;
5237 float prev_split = 0.0f;
5238 for (
int n = 0; n < components; n++)
5241 SameLine(0, style.ItemInnerSpacing.x);
5242 float next_split = IM_TRUNC(w_items * (n + 1) / components);
5243 SetNextItemWidth(ImMax(next_split - prev_split, 1.0f));
5244 prev_split = next_split;
5247 if (flags & ImGuiColorEditFlags_Float)
5249 value_changed |= DragFloat(ids[n], &f[n], 1.0f / 255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
5250 value_changed_as_float |= value_changed;
5254 value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
5256 if (!(flags & ImGuiColorEditFlags_NoOptions))
5257 OpenPopupOnItemClick(
"context", ImGuiPopupFlags_MouseButtonRight);
5260 else if ((flags & ImGuiColorEditFlags_DisplayHex) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
5265 ImFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255), ImClamp(i[3], 0, 255));
5267 ImFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", ImClamp(i[0], 0, 255), ImClamp(i[1], 0, 255), ImClamp(i[2], 0, 255));
5268 SetNextItemWidth(w_inputs);
5269 if (
InputText(
"##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsUppercase))
5271 value_changed =
true;
5273 while (*p ==
'#' || ImCharIsBlankA(*p))
5275 i[0] = i[1] = i[2] = 0;
5279 r = sscanf(p,
"%02X%02X%02X%02X", (
unsigned int*)&i[0], (
unsigned int*)&i[1], (
unsigned int*)&i[2], (
unsigned int*)&i[3]);
5281 r = sscanf(p,
"%02X%02X%02X", (
unsigned int*)&i[0], (
unsigned int*)&i[1], (
unsigned int*)&i[2]);
5284 if (!(flags & ImGuiColorEditFlags_NoOptions))
5285 OpenPopupOnItemClick(
"context", ImGuiPopupFlags_MouseButtonRight);
5288 ImGuiWindow* picker_active_window = NULL;
5289 if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
5291 const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x;
5292 window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y);
5294 const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
5295 if (ColorButton(
"##ColorButton", col_v4, flags))
5297 if (!(flags & ImGuiColorEditFlags_NoPicker))
5300 g.ColorPickerRef = col_v4;
5301 OpenPopup(
"picker");
5302 SetNextWindowPos(
g.LastItemData.Rect.GetBL() + ImVec2(0.0f, style.ItemSpacing.y));
5305 if (!(flags & ImGuiColorEditFlags_NoOptions))
5306 OpenPopupOnItemClick(
"context", ImGuiPopupFlags_MouseButtonRight);
5308 if (BeginPopup(
"picker"))
5310 if (
g.CurrentWindow->BeginCount == 1)
5312 picker_active_window =
g.CurrentWindow;
5313 if (label != label_display_end)
5315 TextEx(label, label_display_end);
5318 ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_PickerMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
5319 ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayMask_ | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
5320 SetNextItemWidth(square_sz * 12.0f);
5321 value_changed |= ColorPicker4(
"##picker", col, picker_flags, &
g.ColorPickerRef.x);
5327 if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
5331 SameLine(0.0f, style.ItemInnerSpacing.x);
5332 window->DC.CursorPos.x = pos.x + ((flags & ImGuiColorEditFlags_NoInputs) ? w_button : w_full + style.ItemInnerSpacing.x);
5333 TextEx(label, label_display_end);
5337 if (value_changed && picker_active_window == NULL)
5339 if (!value_changed_as_float)
5340 for (
int n = 0; n < 4; n++)
5341 f[n] = i[n] / 255.0f;
5342 if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB))
5344 g.ColorEditSavedHue = f[0];
5345 g.ColorEditSavedSat = f[1];
5346 ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
5347 g.ColorEditSavedID =
g.ColorEditCurrentID;
5348 g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(f[0], f[1], f[2], 0));
5350 if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV))
5351 ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
5360 if (set_current_color_edit_id)
5361 g.ColorEditCurrentID = 0;
5367 if ((
g.LastItemData.StatusFlags & ImGuiItemStatusFlags_HoveredRect) && !(
g.LastItemData.InFlags & ImGuiItemFlags_ReadOnly) && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropTarget())
5369 bool accepted_drag_drop =
false;
5370 if (
const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F))
5372 memcpy((
float*)col, payload->Data,
sizeof(
float) * 3);
5373 value_changed = accepted_drag_drop =
true;
5375 if (
const ImGuiPayload* payload = AcceptDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F))
5377 memcpy((
float*)col, payload->Data,
sizeof(
float) * components);
5378 value_changed = accepted_drag_drop =
true;
5382 if (accepted_drag_drop && (flags & ImGuiColorEditFlags_InputHSV))
5383 ColorConvertRGBtoHSV(col[0], col[1], col[2], col[0], col[1], col[2]);
5384 EndDragDropTarget();
5388 if (picker_active_window &&
g.ActiveId != 0 &&
g.ActiveIdWindow == picker_active_window)
5389 g.LastItemData.ID =
g.ActiveId;
5391 if (value_changed &&
g.LastItemData.ID != 0)
5392 MarkItemEdited(
g.LastItemData.ID);
5394 return value_changed;
5397bool ImGui::ColorPicker3(
const char* label,
float col[3], ImGuiColorEditFlags flags)
5399 float col4[4] = { col[0], col[1], col[2], 1.0f };
5400 if (!ColorPicker4(label, col4, flags | ImGuiColorEditFlags_NoAlpha))
5402 col[0] = col4[0]; col[1] = col4[1]; col[2] = col4[2];
5407static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz,
float bar_w,
float alpha)
5409 ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha);
5410 ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8));
5411 ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8));
5412 ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8));
5413 ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8));
5420bool ImGui::ColorPicker4(
const char* label,
float col[4], ImGuiColorEditFlags flags,
const float* ref_col)
5423 ImGuiWindow* window = GetCurrentWindow();
5424 if (window->SkipItems)
5427 ImDrawList* draw_list = window->DrawList;
5428 ImGuiStyle& style =
g.Style;
5431 const float width = CalcItemWidth();
5432 const bool is_readonly = ((
g.NextItemData.ItemFlags |
g.CurrentItemFlags) & ImGuiItemFlags_ReadOnly) != 0;
5433 g.NextItemData.ClearFlags();
5436 const bool set_current_color_edit_id = (
g.ColorEditCurrentID == 0);
5437 if (set_current_color_edit_id)
5438 g.ColorEditCurrentID = window->IDStack.back();
5441 if (!(flags & ImGuiColorEditFlags_NoSidePreview))
5442 flags |= ImGuiColorEditFlags_NoSmallPreview;
5445 if (!(flags & ImGuiColorEditFlags_NoOptions))
5446 ColorPickerOptionsPopup(col, flags);
5449 if (!(flags & ImGuiColorEditFlags_PickerMask_))
5450 flags |= ((
g.ColorEditOptions & ImGuiColorEditFlags_PickerMask_) ?
g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_PickerMask_;
5451 if (!(flags & ImGuiColorEditFlags_InputMask_))
5452 flags |= ((
g.ColorEditOptions & ImGuiColorEditFlags_InputMask_) ?
g.ColorEditOptions : ImGuiColorEditFlags_DefaultOptions_) & ImGuiColorEditFlags_InputMask_;
5453 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_));
5454 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));
5455 if (!(flags & ImGuiColorEditFlags_NoOptions))
5456 flags |= (
g.ColorEditOptions & ImGuiColorEditFlags_AlphaBar);
5459 int components = (flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4;
5460 bool alpha_bar = (flags & ImGuiColorEditFlags_AlphaBar) && !(flags & ImGuiColorEditFlags_NoAlpha);
5461 ImVec2 picker_pos = window->DC.CursorPos;
5462 float square_sz = GetFrameHeight();
5463 float bars_width = square_sz;
5464 float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x));
5465 float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
5466 float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
5467 float bars_triangles_half_sz = IM_TRUNC(bars_width * 0.20f);
5469 float backup_initial_col[4];
5470 memcpy(backup_initial_col, col, components *
sizeof(
float));
5472 float wheel_thickness = sv_picker_size * 0.08f;
5473 float wheel_r_outer = sv_picker_size * 0.50f;
5474 float wheel_r_inner = wheel_r_outer - wheel_thickness;
5475 ImVec2 wheel_center(picker_pos.x + (sv_picker_size + bars_width)*0.5f, picker_pos.y + sv_picker_size * 0.5f);
5478 float triangle_r = wheel_r_inner - (int)(sv_picker_size * 0.027f);
5479 ImVec2 triangle_pa = ImVec2(triangle_r, 0.0f);
5480 ImVec2 triangle_pb = ImVec2(triangle_r * -0.5f, triangle_r * -0.866025f);
5481 ImVec2 triangle_pc = ImVec2(triangle_r * -0.5f, triangle_r * +0.866025f);
5483 float H = col[0],
S = col[1], V = col[2];
5484 float R = col[0], G = col[1],
B = col[2];
5485 if (flags & ImGuiColorEditFlags_InputRGB)
5488 ColorConvertRGBtoHSV(R, G, B, H,
S, V);
5489 ColorEditRestoreHS(col, &H, &
S, &V);
5491 else if (flags & ImGuiColorEditFlags_InputHSV)
5493 ColorConvertHSVtoRGB(H,
S, V, R, G, B);
5496 bool value_changed =
false, value_changed_h =
false, value_changed_sv =
false;
5498 PushItemFlag(ImGuiItemFlags_NoNav,
true);
5499 if (flags & ImGuiColorEditFlags_PickerHueWheel)
5502 InvisibleButton(
"hsv", ImVec2(sv_picker_size + style.ItemInnerSpacing.x + bars_width, sv_picker_size));
5503 if (IsItemActive() && !is_readonly)
5505 ImVec2 initial_off =
g.IO.MouseClickedPos[0] - wheel_center;
5506 ImVec2 current_off =
g.IO.MousePos - wheel_center;
5507 float initial_dist2 = ImLengthSqr(initial_off);
5508 if (initial_dist2 >= (wheel_r_inner - 1) * (wheel_r_inner - 1) && initial_dist2 <= (wheel_r_outer + 1) * (wheel_r_outer + 1))
5511 H = ImAtan2(current_off.y, current_off.x) / IM_PI * 0.5f;
5514 value_changed = value_changed_h =
true;
5516 float cos_hue_angle = ImCos(-H * 2.0f * IM_PI);
5517 float sin_hue_angle = ImSin(-H * 2.0f * IM_PI);
5518 if (
ImTriangleContainsPoint(triangle_pa, triangle_pb, triangle_pc, ImRotate(initial_off, cos_hue_angle, sin_hue_angle)))
5521 ImVec2 current_off_unrotated = ImRotate(current_off, cos_hue_angle, sin_hue_angle);
5523 current_off_unrotated =
ImTriangleClosestPoint(triangle_pa, triangle_pb, triangle_pc, current_off_unrotated);
5526 V = ImClamp(1.0f - vv, 0.0001f, 1.0f);
5527 S = ImClamp(uu / V, 0.0001f, 1.0f);
5528 value_changed = value_changed_sv =
true;
5531 if (!(flags & ImGuiColorEditFlags_NoOptions))
5532 OpenPopupOnItemClick(
"context", ImGuiPopupFlags_MouseButtonRight);
5534 else if (flags & ImGuiColorEditFlags_PickerHueBar)
5537 InvisibleButton(
"sv", ImVec2(sv_picker_size, sv_picker_size));
5538 if (IsItemActive() && !is_readonly)
5540 S = ImSaturate((io.MousePos.x - picker_pos.x) / (sv_picker_size - 1));
5541 V = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
5542 ColorEditRestoreH(col, &H);
5543 value_changed = value_changed_sv =
true;
5545 if (!(flags & ImGuiColorEditFlags_NoOptions))
5546 OpenPopupOnItemClick(
"context", ImGuiPopupFlags_MouseButtonRight);
5549 SetCursorScreenPos(ImVec2(bar0_pos_x, picker_pos.y));
5550 InvisibleButton(
"hue", ImVec2(bars_width, sv_picker_size));
5551 if (IsItemActive() && !is_readonly)
5553 H = ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
5554 value_changed = value_changed_h =
true;
5561 SetCursorScreenPos(ImVec2(bar1_pos_x, picker_pos.y));
5562 InvisibleButton(
"alpha", ImVec2(bars_width, sv_picker_size));
5565 col[3] = 1.0f - ImSaturate((io.MousePos.y - picker_pos.y) / (sv_picker_size - 1));
5566 value_changed =
true;
5571 if (!(flags & ImGuiColorEditFlags_NoSidePreview))
5573 SameLine(0, style.ItemInnerSpacing.x);
5577 if (!(flags & ImGuiColorEditFlags_NoLabel))
5579 const char* label_display_end = FindRenderedTextEnd(label);
5580 if (label != label_display_end)
5582 if ((flags & ImGuiColorEditFlags_NoSidePreview))
5583 SameLine(0, style.ItemInnerSpacing.x);
5584 TextEx(label, label_display_end);
5588 if (!(flags & ImGuiColorEditFlags_NoSidePreview))
5590 PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus,
true);
5591 ImVec4 col_v4(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
5592 if ((flags & ImGuiColorEditFlags_NoLabel))
5595 ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf | ImGuiColorEditFlags_NoTooltip;
5596 ColorButton(
"##current", col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2));
5597 if (ref_col != NULL)
5600 ImVec4 ref_col_v4(ref_col[0], ref_col[1], ref_col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : ref_col[3]);
5601 if (ColorButton(
"##original", ref_col_v4, (flags & sub_flags_to_forward), ImVec2(square_sz * 3, square_sz * 2)))
5603 memcpy(col, ref_col, components *
sizeof(
float));
5604 value_changed =
true;
5612 if (value_changed_h || value_changed_sv)
5614 if (flags & ImGuiColorEditFlags_InputRGB)
5616 ColorConvertHSVtoRGB(H,
S, V, col[0], col[1], col[2]);
5617 g.ColorEditSavedHue =
H;
5618 g.ColorEditSavedSat =
S;
5619 g.ColorEditSavedID =
g.ColorEditCurrentID;
5620 g.ColorEditSavedColor = ColorConvertFloat4ToU32(ImVec4(col[0], col[1], col[2], 0));
5622 else if (flags & ImGuiColorEditFlags_InputHSV)
5631 bool value_changed_fix_hue_wrap =
false;
5632 if ((flags & ImGuiColorEditFlags_NoInputs) == 0)
5634 PushItemWidth((alpha_bar ? bar1_pos_x : bar0_pos_x) + bars_width - picker_pos.x);
5635 ImGuiColorEditFlags sub_flags_to_forward = ImGuiColorEditFlags_DataTypeMask_ | ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoTooltip | ImGuiColorEditFlags_NoSmallPreview | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf;
5636 ImGuiColorEditFlags sub_flags = (flags & sub_flags_to_forward) | ImGuiColorEditFlags_NoPicker;
5637 if (flags & ImGuiColorEditFlags_DisplayRGB || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)
5638 if (ColorEdit4(
"##rgb", col, sub_flags | ImGuiColorEditFlags_DisplayRGB))
5642 value_changed_fix_hue_wrap = (
g.ActiveId != 0 && !
g.ActiveIdAllowOverlap);
5643 value_changed =
true;
5645 if (flags & ImGuiColorEditFlags_DisplayHSV || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)
5646 value_changed |= ColorEdit4(
"##hsv", col, sub_flags | ImGuiColorEditFlags_DisplayHSV);
5647 if (flags & ImGuiColorEditFlags_DisplayHex || (flags & ImGuiColorEditFlags_DisplayMask_) == 0)
5648 value_changed |= ColorEdit4(
"##hex", col, sub_flags | ImGuiColorEditFlags_DisplayHex);
5653 if (value_changed_fix_hue_wrap && (flags & ImGuiColorEditFlags_InputRGB))
5655 float new_H, new_S, new_V;
5656 ColorConvertRGBtoHSV(col[0], col[1], col[2], new_H, new_S, new_V);
5657 if (new_H <= 0 && H > 0)
5659 if (new_V <= 0 && V != new_V)
5660 ColorConvertHSVtoRGB(H,
S, new_V <= 0 ? V * 0.5f : new_V, col[0], col[1], col[2]);
5661 else if (new_S <= 0)
5662 ColorConvertHSVtoRGB(H, new_S <= 0 ?
S * 0.5f : new_S, new_V, col[0], col[1], col[2]);
5668 if (flags & ImGuiColorEditFlags_InputRGB)
5673 ColorConvertRGBtoHSV(R, G, B, H,
S, V);
5674 ColorEditRestoreHS(col, &H, &
S, &V);
5676 else if (flags & ImGuiColorEditFlags_InputHSV)
5681 ColorConvertHSVtoRGB(H,
S, V, R, G, B);
5685 const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha);
5686 const ImU32 col_black = IM_COL32(0,0,0,style_alpha8);
5687 const ImU32 col_white = IM_COL32(255,255,255,style_alpha8);
5688 const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8);
5689 const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) };
5691 ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
5692 ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
5693 ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha));
5695 ImVec2 sv_cursor_pos;
5697 if (flags & ImGuiColorEditFlags_PickerHueWheel)
5700 const float aeps = 0.5f / wheel_r_outer;
5701 const int segment_per_arc = ImMax(4, (
int)wheel_r_outer / 12);
5702 for (
int n = 0; n < 6; n++)
5704 const float a0 = (n) /6.0f * 2.0f * IM_PI - aeps;
5705 const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
5706 const int vert_start_idx = draw_list->VtxBuffer.Size;
5707 draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
5708 draw_list->PathStroke(col_white, 0, wheel_thickness);
5709 const int vert_end_idx = draw_list->VtxBuffer.Size;
5712 ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner);
5713 ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner);
5714 ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n + 1]);
5718 float cos_hue_angle = ImCos(H * 2.0f * IM_PI);
5719 float sin_hue_angle = ImSin(H * 2.0f * IM_PI);
5720 ImVec2 hue_cursor_pos(wheel_center.x + cos_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f, wheel_center.y + sin_hue_angle * (wheel_r_inner + wheel_r_outer) * 0.5f);
5721 float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
5722 int hue_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(hue_cursor_rad);
5723 draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
5724 draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad + 1, col_midgrey, hue_cursor_segments);
5725 draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments);
5728 ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
5729 ImVec2 trb = wheel_center + ImRotate(triangle_pb, cos_hue_angle, sin_hue_angle);
5730 ImVec2 trc = wheel_center + ImRotate(triangle_pc, cos_hue_angle, sin_hue_angle);
5731 ImVec2 uv_white = GetFontTexUvWhitePixel();
5732 draw_list->PrimReserve(3, 3);
5733 draw_list->PrimVtx(tra, uv_white, hue_color32);
5734 draw_list->PrimVtx(trb, uv_white, col_black);
5735 draw_list->PrimVtx(trc, uv_white, col_white);
5736 draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);
5737 sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(
S)), trb, ImSaturate(1 - V));
5739 else if (flags & ImGuiColorEditFlags_PickerHueBar)
5742 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white);
5743 draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black);
5744 RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);
5745 sv_cursor_pos.x = ImClamp(IM_ROUND(picker_pos.x + ImSaturate(
S) * sv_picker_size), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2);
5746 sv_cursor_pos.y = ImClamp(IM_ROUND(picker_pos.y + ImSaturate(1 - V) * sv_picker_size), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
5749 for (
int i = 0; i < 6; ++i)
5750 draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]);
5751 float bar0_line_y = IM_ROUND(picker_pos.y + H * sv_picker_size);
5752 RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
5753 RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
5757 float sv_cursor_rad = value_changed_sv ? wheel_thickness * 0.55f : wheel_thickness * 0.40f;
5758 int sv_cursor_segments = draw_list->_CalcCircleAutoSegmentCount(sv_cursor_rad);
5759 draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, sv_cursor_segments);
5760 draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad + 1, col_midgrey, sv_cursor_segments);
5761 draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, sv_cursor_segments);
5766 float alpha = ImSaturate(col[3]);
5767 ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
5768 RenderColorRectWithAlphaCheckerboard(draw_list, bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
5769 draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK);
5770 float bar1_line_y = IM_ROUND(picker_pos.y + (1.0f - alpha) * sv_picker_size);
5771 RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
5772 RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
5777 if (value_changed && memcmp(backup_initial_col, col, components *
sizeof(
float)) == 0)
5778 value_changed =
false;
5779 if (value_changed &&
g.LastItemData.ID != 0)
5780 MarkItemEdited(
g.LastItemData.ID);
5782 if (set_current_color_edit_id)
5783 g.ColorEditCurrentID = 0;
5786 return value_changed;
5793bool ImGui::ColorButton(
const char* desc_id,
const ImVec4& col, ImGuiColorEditFlags flags,
const ImVec2& size_arg)
5795 ImGuiWindow* window = GetCurrentWindow();
5796 if (window->SkipItems)
5800 const ImGuiID
id = window->GetID(desc_id);
5801 const float default_size = GetFrameHeight();
5802 const ImVec2
size(size_arg.x == 0.0f ? default_size : size_arg.x, size_arg.y == 0.0f ? default_size : size_arg.y);
5803 const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + size);
5804 ItemSize(bb, (
size.y >= default_size) ?
g.Style.FramePadding.y : 0.0f);
5805 if (!ItemAdd(bb,
id))
5809 bool pressed = ButtonBehavior(bb,
id, &hovered, &held);
5811 if (flags & ImGuiColorEditFlags_NoAlpha)
5812 flags &= ~(ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf);
5814 ImVec4 col_rgb = col;
5815 if (flags & ImGuiColorEditFlags_InputHSV)
5816 ColorConvertHSVtoRGB(col_rgb.x, col_rgb.y, col_rgb.z, col_rgb.x, col_rgb.y, col_rgb.z);
5818 ImVec4 col_rgb_without_alpha(col_rgb.x, col_rgb.y, col_rgb.z, 1.0f);
5819 float grid_step = ImMin(
size.x,
size.y) / 2.99f;
5820 float rounding = ImMin(
g.Style.FrameRounding, grid_step * 0.5f);
5821 ImRect bb_inner = bb;
5823 if ((flags & ImGuiColorEditFlags_NoBorder) == 0)
5826 bb_inner.Expand(off);
5828 if ((flags & ImGuiColorEditFlags_AlphaPreviewHalf) && col_rgb.w < 1.0f)
5830 float mid_x = IM_ROUND((bb_inner.Min.x + bb_inner.Max.x) * 0.5f);
5831 RenderColorRectWithAlphaCheckerboard(window->DrawList, ImVec2(bb_inner.Min.x + grid_step, bb_inner.Min.y), bb_inner.Max, GetColorU32(col_rgb), grid_step, ImVec2(-grid_step + off, off), rounding, ImDrawFlags_RoundCornersRight);
5832 window->DrawList->AddRectFilled(bb_inner.Min, ImVec2(mid_x, bb_inner.Max.y), GetColorU32(col_rgb_without_alpha), rounding, ImDrawFlags_RoundCornersLeft);
5837 ImVec4 col_source = (flags & ImGuiColorEditFlags_AlphaPreview) ? col_rgb : col_rgb_without_alpha;
5838 if (col_source.w < 1.0f)
5839 RenderColorRectWithAlphaCheckerboard(window->DrawList, bb_inner.Min, bb_inner.Max, GetColorU32(col_source), grid_step, ImVec2(off, off), rounding);
5841 window->DrawList->AddRectFilled(bb_inner.Min, bb_inner.Max, GetColorU32(col_source), rounding);
5843 RenderNavHighlight(bb,
id);
5844 if ((flags & ImGuiColorEditFlags_NoBorder) == 0)
5846 if (
g.Style.FrameBorderSize > 0.0f)
5847 RenderFrameBorder(bb.Min, bb.Max, rounding);
5849 window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), rounding);
5854 if (
g.ActiveId ==
id && !(flags & ImGuiColorEditFlags_NoDragDrop) && BeginDragDropSource())
5856 if (flags & ImGuiColorEditFlags_NoAlpha)
5857 SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_3F, &col_rgb,
sizeof(
float) * 3, ImGuiCond_Once);
5859 SetDragDropPayload(IMGUI_PAYLOAD_TYPE_COLOR_4F, &col_rgb,
sizeof(
float) * 4, ImGuiCond_Once);
5860 ColorButton(desc_id, col, flags);
5863 EndDragDropSource();
5867 if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered && IsItemHovered(ImGuiHoveredFlags_ForTooltip))
5868 ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
5874void ImGui::SetColorEditOptions(ImGuiColorEditFlags flags)
5877 if ((flags & ImGuiColorEditFlags_DisplayMask_) == 0)
5878 flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DisplayMask_;
5879 if ((flags & ImGuiColorEditFlags_DataTypeMask_) == 0)
5880 flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_DataTypeMask_;
5881 if ((flags & ImGuiColorEditFlags_PickerMask_) == 0)
5882 flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_PickerMask_;
5883 if ((flags & ImGuiColorEditFlags_InputMask_) == 0)
5884 flags |= ImGuiColorEditFlags_DefaultOptions_ & ImGuiColorEditFlags_InputMask_;
5885 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DisplayMask_));
5886 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_DataTypeMask_));
5887 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_PickerMask_));
5888 IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiColorEditFlags_InputMask_));
5889 g.ColorEditOptions = flags;
5893void ImGui::ColorTooltip(
const char* text,
const float* col, ImGuiColorEditFlags flags)
5897 if (!BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None))
5899 const char* text_end = text ? FindRenderedTextEnd(text, NULL) : text;
5900 if (text_end > text)
5902 TextEx(text, text_end);
5906 ImVec2 sz(
g.FontSize * 3 +
g.Style.FramePadding.y * 2,
g.FontSize * 3 +
g.Style.FramePadding.y * 2);
5907 ImVec4 cf(col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
5908 int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
5909 ColorButton(
"##preview", cf, (flags & (ImGuiColorEditFlags_InputMask_ | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf)) | ImGuiColorEditFlags_NoTooltip, sz);
5911 if ((flags & ImGuiColorEditFlags_InputRGB) || !(flags & ImGuiColorEditFlags_InputMask_))
5913 if (flags & ImGuiColorEditFlags_NoAlpha)
5914 Text(
"#%02X%02X%02X\nR: %d, G: %d, B: %d\n(%.3f, %.3f, %.3f)", cr, cg, cb, cr, cg, cb, col[0], col[1], col[2]);
5916 Text(
"#%02X%02X%02X%02X\nR:%d, G:%d, B:%d, A:%d\n(%.3f, %.3f, %.3f, %.3f)", cr, cg, cb, ca, cr, cg, cb, ca, col[0], col[1], col[2], col[3]);
5918 else if (flags & ImGuiColorEditFlags_InputHSV)
5920 if (flags & ImGuiColorEditFlags_NoAlpha)
5921 Text(
"H: %.3f, S: %.3f, V: %.3f", col[0], col[1], col[2]);
5923 Text(
"H: %.3f, S: %.3f, V: %.3f, A: %.3f", col[0], col[1], col[2], col[3]);
5928void ImGui::ColorEditOptionsPopup(
const float* col, ImGuiColorEditFlags flags)
5930 bool allow_opt_inputs = !(flags & ImGuiColorEditFlags_DisplayMask_);
5931 bool allow_opt_datatype = !(flags & ImGuiColorEditFlags_DataTypeMask_);
5932 if ((!allow_opt_inputs && !allow_opt_datatype) || !BeginPopup(
"context"))
5936 ImGuiColorEditFlags opts =
g.ColorEditOptions;
5937 if (allow_opt_inputs)
5939 if (RadioButton(
"RGB", (opts & ImGuiColorEditFlags_DisplayRGB) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayRGB;
5940 if (RadioButton(
"HSV", (opts & ImGuiColorEditFlags_DisplayHSV) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHSV;
5941 if (RadioButton(
"Hex", (opts & ImGuiColorEditFlags_DisplayHex) != 0)) opts = (opts & ~ImGuiColorEditFlags_DisplayMask_) | ImGuiColorEditFlags_DisplayHex;
5943 if (allow_opt_datatype)
5945 if (allow_opt_inputs) Separator();
5946 if (RadioButton(
"0..255", (opts & ImGuiColorEditFlags_Uint8) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Uint8;
5947 if (RadioButton(
"0.00..1.00", (opts & ImGuiColorEditFlags_Float) != 0)) opts = (opts & ~ImGuiColorEditFlags_DataTypeMask_) | ImGuiColorEditFlags_Float;
5950 if (allow_opt_inputs || allow_opt_datatype)
5952 if (Button(
"Copy as..", ImVec2(-1, 0)))
5954 if (BeginPopup(
"Copy"))
5956 int cr = IM_F32_TO_INT8_SAT(col[0]), cg = IM_F32_TO_INT8_SAT(col[1]), cb = IM_F32_TO_INT8_SAT(col[2]), ca = (flags & ImGuiColorEditFlags_NoAlpha) ? 255 : IM_F32_TO_INT8_SAT(col[3]);
5958 ImFormatString(buf, IM_ARRAYSIZE(buf),
"(%.3ff, %.3ff, %.3ff, %.3ff)", col[0], col[1], col[2], (flags & ImGuiColorEditFlags_NoAlpha) ? 1.0f : col[3]);
5959 if (Selectable(buf))
5960 SetClipboardText(buf);
5961 ImFormatString(buf, IM_ARRAYSIZE(buf),
"(%d,%d,%d,%d)", cr, cg, cb, ca);
5962 if (Selectable(buf))
5963 SetClipboardText(buf);
5964 ImFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X", cr, cg, cb);
5965 if (Selectable(buf))
5966 SetClipboardText(buf);
5967 if (!(flags & ImGuiColorEditFlags_NoAlpha))
5969 ImFormatString(buf, IM_ARRAYSIZE(buf),
"#%02X%02X%02X%02X", cr, cg, cb, ca);
5970 if (Selectable(buf))
5971 SetClipboardText(buf);
5976 g.ColorEditOptions = opts;
5981void ImGui::ColorPickerOptionsPopup(
const float* ref_col, ImGuiColorEditFlags flags)
5983 bool allow_opt_picker = !(flags & ImGuiColorEditFlags_PickerMask_);
5984 bool allow_opt_alpha_bar = !(flags & ImGuiColorEditFlags_NoAlpha) && !(flags & ImGuiColorEditFlags_AlphaBar);
5985 if ((!allow_opt_picker && !allow_opt_alpha_bar) || !BeginPopup(
"context"))
5989 if (allow_opt_picker)
5991 ImVec2 picker_size(
g.FontSize * 8, ImMax(
g.FontSize * 8 - (GetFrameHeight() +
g.Style.ItemInnerSpacing.x), 1.0f));
5992 PushItemWidth(picker_size.x);
5993 for (
int picker_type = 0; picker_type < 2; picker_type++)
5996 if (picker_type > 0) Separator();
5997 PushID(picker_type);
5998 ImGuiColorEditFlags picker_flags = ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_NoOptions | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_NoSidePreview | (flags & ImGuiColorEditFlags_NoAlpha);
5999 if (picker_type == 0) picker_flags |= ImGuiColorEditFlags_PickerHueBar;
6000 if (picker_type == 1) picker_flags |= ImGuiColorEditFlags_PickerHueWheel;
6001 ImVec2 backup_pos = GetCursorScreenPos();
6002 if (Selectable(
"##selectable",
false, 0, picker_size))
6003 g.ColorEditOptions = (
g.ColorEditOptions & ~ImGuiColorEditFlags_PickerMask_) | (picker_flags & ImGuiColorEditFlags_PickerMask_);
6004 SetCursorScreenPos(backup_pos);
6005 ImVec4 previewing_ref_col;
6006 memcpy(&previewing_ref_col, ref_col,
sizeof(
float) * ((picker_flags & ImGuiColorEditFlags_NoAlpha) ? 3 : 4));
6007 ColorPicker4(
"##previewing_picker", &previewing_ref_col.x, picker_flags);
6012 if (allow_opt_alpha_bar)
6014 if (allow_opt_picker) Separator();
6015 CheckboxFlags(
"Alpha Bar", &
g.ColorEditOptions, ImGuiColorEditFlags_AlphaBar);
6036bool ImGui::TreeNode(
const char* str_id,
const char* fmt, ...)
6039 va_start(args, fmt);
6040 bool is_open = TreeNodeExV(str_id, 0, fmt, args);
6045bool ImGui::TreeNode(
const void* ptr_id,
const char* fmt, ...)
6048 va_start(args, fmt);
6049 bool is_open = TreeNodeExV(ptr_id, 0, fmt, args);
6054bool ImGui::TreeNode(
const char* label)
6056 ImGuiWindow* window = GetCurrentWindow();
6057 if (window->SkipItems)
6059 return TreeNodeBehavior(window->GetID(label), 0, label, NULL);
6062bool ImGui::TreeNodeV(
const char* str_id,
const char* fmt, va_list args)
6064 return TreeNodeExV(str_id, 0, fmt, args);
6067bool ImGui::TreeNodeV(
const void* ptr_id,
const char* fmt, va_list args)
6069 return TreeNodeExV(ptr_id, 0, fmt, args);
6072bool ImGui::TreeNodeEx(
const char* label, ImGuiTreeNodeFlags flags)
6074 ImGuiWindow* window = GetCurrentWindow();
6075 if (window->SkipItems)
6078 return TreeNodeBehavior(window->GetID(label), flags, label, NULL);
6081bool ImGui::TreeNodeEx(
const char* str_id, ImGuiTreeNodeFlags flags,
const char* fmt, ...)
6084 va_start(args, fmt);
6085 bool is_open = TreeNodeExV(str_id, flags, fmt, args);
6090bool ImGui::TreeNodeEx(
const void* ptr_id, ImGuiTreeNodeFlags flags,
const char* fmt, ...)
6093 va_start(args, fmt);
6094 bool is_open = TreeNodeExV(ptr_id, flags, fmt, args);
6099bool ImGui::TreeNodeExV(
const char* str_id, ImGuiTreeNodeFlags flags,
const char* fmt, va_list args)
6101 ImGuiWindow* window = GetCurrentWindow();
6102 if (window->SkipItems)
6105 const char* label, *label_end;
6107 return TreeNodeBehavior(window->GetID(str_id), flags, label, label_end);
6110bool ImGui::TreeNodeExV(
const void* ptr_id, ImGuiTreeNodeFlags flags,
const char* fmt, va_list args)
6112 ImGuiWindow* window = GetCurrentWindow();
6113 if (window->SkipItems)
6116 const char* label, *label_end;
6118 return TreeNodeBehavior(window->GetID(ptr_id), flags, label, label_end);
6121void ImGui::TreeNodeSetOpen(ImGuiID
id,
bool open)
6124 ImGuiStorage* storage =
g.CurrentWindow->DC.StateStorage;
6125 storage->SetInt(
id, open ? 1 : 0);
6128bool ImGui::TreeNodeUpdateNextOpen(ImGuiID
id, ImGuiTreeNodeFlags flags)
6130 if (flags & ImGuiTreeNodeFlags_Leaf)
6135 ImGuiWindow* window =
g.CurrentWindow;
6136 ImGuiStorage* storage = window->DC.StateStorage;
6139 if (
g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen)
6141 if (
g.NextItemData.OpenCond & ImGuiCond_Always)
6143 is_open =
g.NextItemData.OpenVal;
6144 TreeNodeSetOpen(
id, is_open);
6149 const int stored_value = storage->GetInt(
id, -1);
6150 if (stored_value == -1)
6152 is_open =
g.NextItemData.OpenVal;
6153 TreeNodeSetOpen(
id, is_open);
6157 is_open = stored_value != 0;
6163 is_open = storage->GetInt(
id, (flags & ImGuiTreeNodeFlags_DefaultOpen) ? 1 : 0) != 0;
6168 if (
g.LogEnabled && !(flags & ImGuiTreeNodeFlags_NoAutoOpenOnLog) && (window->DC.TreeDepth -
g.LogDepthRef) <
g.LogDepthToExpand)
6174bool ImGui::TreeNodeBehavior(ImGuiID
id, ImGuiTreeNodeFlags flags,
const char* label,
const char* label_end)
6176 ImGuiWindow* window = GetCurrentWindow();
6177 if (window->SkipItems)
6181 const ImGuiStyle& style =
g.Style;
6182 const bool display_frame = (flags & ImGuiTreeNodeFlags_Framed) != 0;
6183 const ImVec2 padding = (display_frame || (flags & ImGuiTreeNodeFlags_FramePadding)) ? style.FramePadding : ImVec2(style.FramePadding.x, ImMin(window->DC.CurrLineTextBaseOffset, style.FramePadding.y));
6186 label_end = FindRenderedTextEnd(label);
6187 const ImVec2 label_size =
CalcTextSize(label, label_end,
false);
6190 const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y,
g.FontSize + style.FramePadding.y * 2), label_size.y + padding.y * 2);
6191 const bool span_all_columns = (flags & ImGuiTreeNodeFlags_SpanAllColumns) != 0 && (
g.CurrentTable != NULL);
6193 frame_bb.Min.x = span_all_columns ? window->ParentWorkRect.Min.x : (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
6194 frame_bb.Min.y = window->DC.CursorPos.y;
6195 frame_bb.Max.x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
6196 frame_bb.Max.y = window->DC.CursorPos.y + frame_height;
6201 frame_bb.Min.x -= IM_TRUNC(window->WindowPadding.x * 0.5f - 1.0f);
6202 frame_bb.Max.x += IM_TRUNC(window->WindowPadding.x * 0.5f);
6205 const float text_offset_x =
g.FontSize + (display_frame ? padding.x * 3 : padding.x * 2);
6206 const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset);
6207 const float text_width =
g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x * 2 : 0.0f);
6208 ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);
6209 ItemSize(ImVec2(text_width, frame_height), padding.y);
6212 ImRect interact_bb = frame_bb;
6213 if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_SpanAllColumns)) == 0)
6214 interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
6217 const float backup_clip_rect_min_x = window->ClipRect.Min.x;
6218 const float backup_clip_rect_max_x = window->ClipRect.Max.x;
6219 if (span_all_columns)
6221 window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
6222 window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
6226 bool is_open = TreeNodeUpdateNextOpen(
id, flags);
6227 bool item_add = ItemAdd(interact_bb,
id);
6228 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
6229 g.LastItemData.DisplayRect = frame_bb;
6231 if (span_all_columns)
6233 window->ClipRect.Min.x = backup_clip_rect_min_x;
6234 window->ClipRect.Max.x = backup_clip_rect_max_x;
6242 if (is_open && !
g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6243 if (
g.NavMoveDir == ImGuiDir_Left &&
g.NavWindow == window && NavMoveRequestButNoResultYet())
6245 g.NavTreeNodeStack.resize(
g.NavTreeNodeStack.Size + 1);
6246 ImGuiNavTreeNodeData* nav_tree_node_data = &
g.NavTreeNodeStack.back();
6247 nav_tree_node_data->ID =
id;
6248 nav_tree_node_data->InFlags =
g.LastItemData.InFlags;
6249 nav_tree_node_data->NavRect =
g.LastItemData.NavRect;
6250 window->DC.TreeJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
6253 const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
6256 if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6257 TreePushOverrideID(
id);
6258 IMGUI_TEST_ENGINE_ITEM_INFO(
g.LastItemData.ID, label,
g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
6262 if (span_all_columns)
6264 TablePushBackgroundChannel();
6265 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasClipRect;
6266 g.LastItemData.ClipRect = window->ClipRect;
6269 ImGuiButtonFlags button_flags = ImGuiTreeNodeFlags_None;
6270 if ((flags & ImGuiTreeNodeFlags_AllowOverlap) || (
g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap))
6271 button_flags |= ImGuiButtonFlags_AllowOverlap;
6273 button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
6278 const float arrow_hit_x1 = (text_pos.x - text_offset_x) - style.TouchExtraPadding.x;
6279 const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (
g.FontSize + padding.x * 2.0f) + style.TouchExtraPadding.x;
6280 const bool is_mouse_x_over_arrow = (
g.IO.MousePos.x >= arrow_hit_x1 &&
g.IO.MousePos.x < arrow_hit_x2);
6281 if (window !=
g.HoveredWindow || !is_mouse_x_over_arrow)
6282 button_flags |= ImGuiButtonFlags_NoKeyModifiers;
6293 if (is_mouse_x_over_arrow)
6294 button_flags |= ImGuiButtonFlags_PressedOnClick;
6295 else if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
6296 button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick;
6298 button_flags |= ImGuiButtonFlags_PressedOnClickRelease;
6300 bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0;
6301 const bool was_selected = selected;
6304 bool pressed = ButtonBehavior(interact_bb,
id, &hovered, &held, button_flags);
6305 bool toggled =
false;
6308 if (pressed &&
g.DragDropHoldJustPressedId !=
id)
6310 if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (
g.NavActivateId ==
id))
6312 if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
6313 toggled |= is_mouse_x_over_arrow && !
g.NavDisableMouseHover;
6314 if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) &&
g.IO.MouseClickedCount[0] == 2)
6317 else if (pressed &&
g.DragDropHoldJustPressedId ==
id)
6319 IM_ASSERT(button_flags & ImGuiButtonFlags_PressedOnDragDropHold);
6324 if (
g.NavId ==
id &&
g.NavMoveDir == ImGuiDir_Left && is_open)
6327 NavClearPreferredPosForAxis(ImGuiAxis_X);
6328 NavMoveRequestCancel();
6330 if (
g.NavId ==
id &&
g.NavMoveDir == ImGuiDir_Right && !is_open)
6333 NavClearPreferredPosForAxis(ImGuiAxis_X);
6334 NavMoveRequestCancel();
6340 window->DC.StateStorage->SetInt(
id, is_open);
6341 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
6346 if (selected != was_selected)
6347 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
6350 const ImU32 text_col = GetColorU32(ImGuiCol_Text);
6351 ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_Compact;
6355 const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
6356 RenderFrame(frame_bb.Min, frame_bb.Max, bg_col,
true, style.FrameRounding);
6357 RenderNavHighlight(frame_bb,
id, nav_highlight_flags);
6358 if (flags & ImGuiTreeNodeFlags_Bullet)
6359 RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y +
g.FontSize * 0.5f), text_col);
6361 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);
6363 text_pos.x -= text_offset_x -padding.x;
6364 if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)
6365 frame_bb.Max.x -=
g.FontSize + style.FramePadding.x;
6368 LogSetNextTextDecoration(
"###",
"###");
6373 if (hovered || selected)
6375 const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
6376 RenderFrame(frame_bb.Min, frame_bb.Max, bg_col,
false);
6378 RenderNavHighlight(frame_bb,
id, nav_highlight_flags);
6379 if (flags & ImGuiTreeNodeFlags_Bullet)
6380 RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y +
g.FontSize * 0.5f), text_col);
6382 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);
6384 LogSetNextTextDecoration(
">", NULL);
6387 if (span_all_columns)
6388 TablePopBackgroundChannel();
6392 RenderTextClipped(text_pos, frame_bb.Max, label, label_end, &label_size);
6394 RenderText(text_pos, label, label_end,
false);
6396 if (is_open && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
6397 TreePushOverrideID(
id);
6398 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | (is_leaf ? 0 : ImGuiItemStatusFlags_Openable) | (is_open ? ImGuiItemStatusFlags_Opened : 0));
6402void ImGui::TreePush(
const char* str_id)
6404 ImGuiWindow* window = GetCurrentWindow();
6406 window->DC.TreeDepth++;
6410void ImGui::TreePush(
const void* ptr_id)
6412 ImGuiWindow* window = GetCurrentWindow();
6414 window->DC.TreeDepth++;
6418void ImGui::TreePushOverrideID(ImGuiID
id)
6421 ImGuiWindow* window =
g.CurrentWindow;
6423 window->DC.TreeDepth++;
6427void ImGui::TreePop()
6430 ImGuiWindow* window =
g.CurrentWindow;
6433 window->DC.TreeDepth--;
6434 ImU32 tree_depth_mask = (1 << window->DC.TreeDepth);
6437 if (window->DC.TreeJumpToParentOnPopMask & tree_depth_mask)
6439 ImGuiNavTreeNodeData* nav_tree_node_data = &
g.NavTreeNodeStack.back();
6440 IM_ASSERT(nav_tree_node_data->ID == window->IDStack.back());
6441 if (
g.NavIdIsAlive &&
g.NavMoveDir == ImGuiDir_Left &&
g.NavWindow == window && NavMoveRequestButNoResultYet())
6442 NavMoveRequestResolveWithPastTreeNode(&
g.NavMoveResultLocal, nav_tree_node_data);
6443 g.NavTreeNodeStack.pop_back();
6445 window->DC.TreeJumpToParentOnPopMask &= tree_depth_mask - 1;
6447 IM_ASSERT(window->IDStack.Size > 1);
6452float ImGui::GetTreeNodeToLabelSpacing()
6455 return g.FontSize + (
g.Style.FramePadding.x * 2.0f);
6459void ImGui::SetNextItemOpen(
bool is_open, ImGuiCond cond)
6462 if (
g.CurrentWindow->SkipItems)
6464 g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen;
6465 g.NextItemData.OpenVal = is_open;
6466 g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always;
6471bool ImGui::CollapsingHeader(
const char* label, ImGuiTreeNodeFlags flags)
6473 ImGuiWindow* window = GetCurrentWindow();
6474 if (window->SkipItems)
6477 return TreeNodeBehavior(window->GetID(label), flags | ImGuiTreeNodeFlags_CollapsingHeader, label);
6484bool ImGui::CollapsingHeader(
const char* label,
bool* p_visible, ImGuiTreeNodeFlags flags)
6486 ImGuiWindow* window = GetCurrentWindow();
6487 if (window->SkipItems)
6490 if (p_visible && !*p_visible)
6493 ImGuiID
id = window->GetID(label);
6494 flags |= ImGuiTreeNodeFlags_CollapsingHeader;
6496 flags |= ImGuiTreeNodeFlags_AllowOverlap | (ImGuiTreeNodeFlags)ImGuiTreeNodeFlags_ClipLabelForTrailingButton;
6497 bool is_open = TreeNodeBehavior(
id, flags, label);
6498 if (p_visible != NULL)
6504 ImGuiLastItemData last_item_backup =
g.LastItemData;
6505 float button_size =
g.FontSize;
6506 float button_x = ImMax(
g.LastItemData.Rect.Min.x,
g.LastItemData.Rect.Max.x -
g.Style.FramePadding.x - button_size);
6507 float button_y =
g.LastItemData.Rect.Min.y +
g.Style.FramePadding.y;
6508 ImGuiID close_button_id = GetIDWithSeed(
"#CLOSE", NULL,
id);
6509 if (CloseButton(close_button_id, ImVec2(button_x, button_y)))
6511 g.LastItemData = last_item_backup;
6527bool ImGui::Selectable(
const char* label,
bool selected, ImGuiSelectableFlags flags,
const ImVec2& size_arg)
6529 ImGuiWindow* window = GetCurrentWindow();
6530 if (window->SkipItems)
6534 const ImGuiStyle& style =
g.Style;
6537 ImGuiID
id = window->GetID(label);
6539 ImVec2
size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
6540 ImVec2 pos = window->DC.CursorPos;
6541 pos.y += window->DC.CurrLineTextBaseOffset;
6542 ItemSize(size, 0.0f);
6546 const bool span_all_columns = (flags & ImGuiSelectableFlags_SpanAllColumns) != 0;
6547 const float min_x = span_all_columns ? window->ParentWorkRect.Min.x : pos.x;
6548 const float max_x = span_all_columns ? window->ParentWorkRect.Max.x : window->WorkRect.Max.x;
6549 if (size_arg.x == 0.0f || (flags & ImGuiSelectableFlags_SpanAvailWidth))
6550 size.x = ImMax(label_size.x, max_x - min_x);
6553 const ImVec2 text_min = pos;
6554 const ImVec2 text_max(min_x +
size.x, pos.y +
size.y);
6557 ImRect bb(min_x, pos.y, text_max.x, text_max.y);
6558 if ((flags & ImGuiSelectableFlags_NoPadWithHalfSpacing) == 0)
6560 const float spacing_x = span_all_columns ? 0.0f : style.ItemSpacing.x;
6561 const float spacing_y = style.ItemSpacing.y;
6562 const float spacing_L = IM_TRUNC(spacing_x * 0.50f);
6563 const float spacing_U = IM_TRUNC(spacing_y * 0.50f);
6564 bb.Min.x -= spacing_L;
6565 bb.Min.y -= spacing_U;
6566 bb.Max.x += (spacing_x - spacing_L);
6567 bb.Max.y += (spacing_y - spacing_U);
6572 const float backup_clip_rect_min_x = window->ClipRect.Min.x;
6573 const float backup_clip_rect_max_x = window->ClipRect.Max.x;
6574 if (span_all_columns)
6576 window->ClipRect.Min.x = window->ParentWorkRect.Min.x;
6577 window->ClipRect.Max.x = window->ParentWorkRect.Max.x;
6580 const bool disabled_item = (flags & ImGuiSelectableFlags_Disabled) != 0;
6581 const bool item_add = ItemAdd(bb,
id, NULL, disabled_item ? ImGuiItemFlags_Disabled : ImGuiItemFlags_None);
6582 if (span_all_columns)
6584 window->ClipRect.Min.x = backup_clip_rect_min_x;
6585 window->ClipRect.Max.x = backup_clip_rect_max_x;
6591 const bool disabled_global = (
g.CurrentItemFlags & ImGuiItemFlags_Disabled) != 0;
6592 if (disabled_item && !disabled_global)
6597 if (span_all_columns)
6600 TablePushBackgroundChannel();
6601 else if (window->DC.CurrentColumns)
6602 PushColumnsBackground();
6603 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HasClipRect;
6604 g.LastItemData.ClipRect = window->ClipRect;
6608 ImGuiButtonFlags button_flags = 0;
6609 if (flags & ImGuiSelectableFlags_NoHoldingActiveID) { button_flags |= ImGuiButtonFlags_NoHoldingActiveId; }
6610 if (flags & ImGuiSelectableFlags_NoSetKeyOwner) { button_flags |= ImGuiButtonFlags_NoSetKeyOwner; }
6611 if (flags & ImGuiSelectableFlags_SelectOnClick) { button_flags |= ImGuiButtonFlags_PressedOnClick; }
6612 if (flags & ImGuiSelectableFlags_SelectOnRelease) { button_flags |= ImGuiButtonFlags_PressedOnRelease; }
6613 if (flags & ImGuiSelectableFlags_AllowDoubleClick) { button_flags |= ImGuiButtonFlags_PressedOnClickRelease | ImGuiButtonFlags_PressedOnDoubleClick; }
6614 if ((flags & ImGuiSelectableFlags_AllowOverlap) || (
g.LastItemData.InFlags & ImGuiItemFlags_AllowOverlap)) { button_flags |= ImGuiButtonFlags_AllowOverlap; }
6616 const bool was_selected = selected;
6618 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, button_flags);
6627 if ((flags & ImGuiSelectableFlags_SelectOnNav) &&
g.NavJustMovedToId != 0 &&
g.NavJustMovedToFocusScopeId ==
g.CurrentFocusScopeId)
6628 if (
g.NavJustMovedToId ==
id)
6629 selected = pressed =
true;
6632 if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover)))
6634 if (!
g.NavDisableMouseHover &&
g.NavWindow == window &&
g.NavLayer == window->DC.NavLayerCurrent)
6636 SetNavID(
id, window->DC.NavLayerCurrent,
g.CurrentFocusScopeId, WindowRectAbsToRel(window, bb));
6637 g.NavDisableHighlight =
true;
6644 if (selected != was_selected)
6645 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
6648 if (hovered || selected)
6650 const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
6651 RenderFrame(bb.Min, bb.Max, col,
false, 0.0f);
6654 RenderNavHighlight(bb,
id, ImGuiNavHighlightFlags_Compact | ImGuiNavHighlightFlags_NoRounding);
6656 if (span_all_columns)
6659 TablePopBackgroundChannel();
6660 else if (window->DC.CurrentColumns)
6661 PopColumnsBackground();
6664 RenderTextClipped(text_min, text_max, label, NULL, &label_size, style.SelectableTextAlign, &bb);
6667 if (pressed && (window->Flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiSelectableFlags_DontClosePopups) && !(
g.LastItemData.InFlags & ImGuiItemFlags_SelectableDontClosePopup))
6668 CloseCurrentPopup();
6670 if (disabled_item && !disabled_global)
6673 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
6677bool ImGui::Selectable(
const char* label,
bool* p_selected, ImGuiSelectableFlags flags,
const ImVec2& size_arg)
6679 if (Selectable(label, *p_selected, flags, size_arg))
6681 *p_selected = !*p_selected;
6699ImGuiTypingSelectRequest* ImGui::GetTypingSelectRequest(ImGuiTypingSelectFlags flags)
6702 ImGuiTypingSelectState* data = &
g.TypingSelectState;
6703 ImGuiTypingSelectRequest* out_request = &data->Request;
6706 const float TYPING_SELECT_RESET_TIMER = 1.80f;
6707 const int TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK = 4;
6708 if (data->SearchBuffer[0] != 0)
6710 bool clear_buffer =
false;
6711 clear_buffer |= (
g.NavFocusScopeId != data->FocusScope);
6712 clear_buffer |= (data->LastRequestTime + TYPING_SELECT_RESET_TIMER <
g.Time);
6713 clear_buffer |=
g.NavAnyRequest;
6714 clear_buffer |=
g.ActiveId != 0 &&
g.NavActivateId == 0;
6715 clear_buffer |= IsKeyPressed(ImGuiKey_Escape) || IsKeyPressed(ImGuiKey_Enter);
6716 clear_buffer |= IsKeyPressed(ImGuiKey_Backspace) && (flags & ImGuiTypingSelectFlags_AllowBackspace) == 0;
6723 const int buffer_max_len = IM_ARRAYSIZE(data->SearchBuffer) - 1;
6724 int buffer_len = (int)strlen(data->SearchBuffer);
6725 bool select_request =
false;
6726 for (ImWchar w :
g.IO.InputQueueCharacters)
6729 if (w < 32 || (buffer_len == 0 && ImCharIsBlankW(w)) || (buffer_len + w_len > buffer_max_len))
6733 if (data->SingleCharModeLock && w_len == out_request->SingleCharSize && memcmp(w_buf, data->SearchBuffer, w_len) == 0)
6735 select_request =
true;
6738 if (data->SingleCharModeLock)
6743 memcpy(data->SearchBuffer + buffer_len, w_buf, w_len + 1);
6744 buffer_len += w_len;
6745 select_request =
true;
6747 g.IO.InputQueueCharacters.resize(0);
6750 if ((flags & ImGuiTypingSelectFlags_AllowBackspace) && IsKeyPressed(ImGuiKey_Backspace, 0, ImGuiInputFlags_Repeat))
6754 buffer_len = (int)(p - data->SearchBuffer);
6758 if (buffer_len == 0)
6762 data->FocusScope =
g.NavFocusScopeId;
6763 data->LastRequestFrame =
g.FrameCount;
6764 data->LastRequestTime = (float)
g.Time;
6766 out_request->Flags = flags;
6767 out_request->SearchBufferLen = buffer_len;
6768 out_request->SearchBuffer = data->SearchBuffer;
6769 out_request->SelectRequest = (data->LastRequestFrame ==
g.FrameCount);
6770 out_request->SingleCharMode =
false;
6771 out_request->SingleCharSize = 0;
6777 if (flags & ImGuiTypingSelectFlags_AllowSingleCharMode)
6779 const char* buf_begin = out_request->SearchBuffer;
6780 const char* buf_end = out_request->SearchBuffer + out_request->SearchBufferLen;
6782 const char* p = buf_begin + c0_len;
6783 for (; p < buf_end; p += c0_len)
6784 if (memcmp(buf_begin, p, (
size_t)c0_len) != 0)
6786 const int single_char_count = (p == buf_end) ? (out_request->SearchBufferLen / c0_len) : 0;
6787 out_request->SingleCharMode = (single_char_count > 0 || data->SingleCharModeLock);
6788 out_request->SingleCharSize = (ImS8)c0_len;
6789 data->SingleCharModeLock |= (single_char_count >= TYPING_SELECT_SINGLE_CHAR_COUNT_FOR_LOCK);
6795static int ImStrimatchlen(
const char* s1,
const char* s1_end,
const char* s2)
6798 while (s1 < s1_end && ImToUpper(*s1++) == ImToUpper(*s2++))
6809int ImGui::TypingSelectFindMatch(ImGuiTypingSelectRequest* req,
int items_count,
const char* (*get_item_name_func)(
void*,
int),
void* user_data,
int nav_item_idx)
6811 if (req == NULL || req->SelectRequest ==
false)
6814 if (req->SingleCharMode && (req->Flags & ImGuiTypingSelectFlags_AllowSingleCharMode))
6815 idx = TypingSelectFindNextSingleCharMatch(req, items_count, get_item_name_func, user_data, nav_item_idx);
6817 idx = TypingSelectFindBestLeadingMatch(req, items_count, get_item_name_func, user_data);
6819 NavRestoreHighlightAfterMove();
6824int ImGui::TypingSelectFindNextSingleCharMatch(ImGuiTypingSelectRequest* req,
int items_count,
const char* (*get_item_name_func)(
void*,
int),
void* user_data,
int nav_item_idx)
6830 int first_match_idx = -1;
6831 bool return_next_match =
false;
6832 for (
int idx = 0; idx < items_count; idx++)
6834 const char* item_name = get_item_name_func(user_data, idx);
6835 if (ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SingleCharSize, item_name) < req->SingleCharSize)
6837 if (return_next_match)
6839 if (first_match_idx == -1 && nav_item_idx == -1)
6841 if (first_match_idx == -1)
6842 first_match_idx = idx;
6843 if (nav_item_idx == idx)
6844 return_next_match =
true;
6846 return first_match_idx;
6849int ImGui::TypingSelectFindBestLeadingMatch(ImGuiTypingSelectRequest* req,
int items_count,
const char* (*get_item_name_func)(
void*,
int),
void* user_data)
6851 int longest_match_idx = -1;
6852 int longest_match_len = 0;
6853 for (
int idx = 0; idx < items_count; idx++)
6855 const char* item_name = get_item_name_func(user_data, idx);
6856 const int match_len = ImStrimatchlen(req->SearchBuffer, req->SearchBuffer + req->SearchBufferLen, item_name);
6857 if (match_len <= longest_match_len)
6859 longest_match_idx = idx;
6860 longest_match_len = match_len;
6861 if (match_len == req->SearchBufferLen)
6864 return longest_match_idx;
6867void ImGui::DebugNodeTypingSelectState(ImGuiTypingSelectState* data)
6869#ifndef IMGUI_DISABLE_DEBUG_TOOLS
6870 Text(
"SearchBuffer = \"%s\"", data->SearchBuffer);
6871 Text(
"SingleCharMode = %d, Size = %d, Lock = %d", data->Request.SingleCharMode, data->Request.SingleCharSize, data->SingleCharModeLock);
6872 Text(
"LastRequest = time: %.2f, frame: %d", data->LastRequestTime, data->LastRequestFrame);
6883void ImGui::SetNextItemSelectionUserData(ImGuiSelectionUserData selection_user_data)
6888 g.NextItemData.ItemFlags |= ImGuiItemFlags_HasSelectionUserData;
6889 g.NextItemData.SelectionUserData = selection_user_data;
6904bool ImGui::BeginListBox(
const char* label,
const ImVec2& size_arg)
6907 ImGuiWindow* window = GetCurrentWindow();
6908 if (window->SkipItems)
6911 const ImGuiStyle& style =
g.Style;
6912 const ImGuiID
id = GetID(label);
6913 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
6917 ImVec2
size = ImTrunc(CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.25f + style.FramePadding.y * 2.0f));
6918 ImVec2 frame_size = ImVec2(
size.x, ImMax(
size.y, label_size.y));
6919 ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
6920 ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
6921 g.NextItemData.ClearFlags();
6923 if (!IsRectVisible(bb.Min, bb.Max))
6925 ItemSize(bb.GetSize(), style.FramePadding.y);
6926 ItemAdd(bb, 0, &frame_bb);
6927 g.NextWindowData.ClearFlags();
6933 if (label_size.x > 0.0f)
6935 ImVec2 label_pos = ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y);
6936 RenderText(label_pos, label);
6937 window->DC.CursorMaxPos = ImMax(window->DC.CursorMaxPos, label_pos + label_size);
6940 BeginChild(
id, frame_bb.GetSize(), ImGuiChildFlags_FrameStyle);
6944void ImGui::EndListBox()
6947 ImGuiWindow* window =
g.CurrentWindow;
6948 IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) &&
"Mismatched BeginListBox/EndListBox calls. Did you test the return value of BeginListBox?");
6955bool ImGui::ListBox(
const char* label,
int* current_item,
const char*
const items[],
int items_count,
int height_items)
6957 const bool value_changed =
ListBox(label, current_item, Items_ArrayGetter, (
void*)items, items_count, height_items);
6958 return value_changed;
6963bool ImGui::ListBox(
const char* label,
int* current_item,
const char* (*getter)(
void* user_data,
int idx),
void* user_data,
int items_count,
int height_in_items)
6968 if (height_in_items < 0)
6969 height_in_items = ImMin(items_count, 7);
6970 float height_in_items_f = height_in_items + 0.25f;
6971 ImVec2
size(0.0f, ImTrunc(GetTextLineHeightWithSpacing() * height_in_items_f +
g.Style.FramePadding.y * 2.0f));
6973 if (!BeginListBox(label, size))
6978 bool value_changed =
false;
6979 ImGuiListClipper clipper;
6980 clipper.Begin(items_count, GetTextLineHeightWithSpacing());
6981 while (clipper.Step())
6982 for (
int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++)
6984 const char* item_text = getter(user_data, i);
6985 if (item_text == NULL)
6986 item_text =
"*Unknown item*";
6989 const bool item_selected = (i == *current_item);
6990 if (Selectable(item_text, item_selected))
6993 value_changed =
true;
6996 SetItemDefaultFocus();
7002 MarkItemEdited(
g.LastItemData.ID);
7004 return value_changed;
7020int ImGui::PlotEx(ImGuiPlotType plot_type,
const char* label,
float (*values_getter)(
void* data,
int idx),
void* data,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max,
const ImVec2& size_arg)
7023 ImGuiWindow* window = GetCurrentWindow();
7024 if (window->SkipItems)
7027 const ImGuiStyle& style =
g.Style;
7028 const ImGuiID
id = window->GetID(label);
7030 const ImVec2 label_size =
CalcTextSize(label, NULL,
true);
7031 const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
7033 const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
7034 const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
7035 const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0));
7036 ItemSize(total_bb, style.FramePadding.y);
7037 if (!ItemAdd(total_bb, 0, &frame_bb))
7039 const bool hovered = ItemHoverable(frame_bb,
id,
g.LastItemData.InFlags);
7042 if (scale_min == FLT_MAX || scale_max == FLT_MAX)
7044 float v_min = FLT_MAX;
7045 float v_max = -FLT_MAX;
7046 for (
int i = 0; i < values_count; i++)
7048 const float v = values_getter(data, i);
7051 v_min = ImMin(v_min, v);
7052 v_max = ImMax(v_max, v);
7054 if (scale_min == FLT_MAX)
7056 if (scale_max == FLT_MAX)
7060 RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg),
true, style.FrameRounding);
7062 const int values_count_min = (plot_type == ImGuiPlotType_Lines) ? 2 : 1;
7063 int idx_hovered = -1;
7064 if (values_count >= values_count_min)
7066 int res_w = ImMin((
int)frame_size.x, values_count) + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7067 int item_count = values_count + ((plot_type == ImGuiPlotType_Lines) ? -1 : 0);
7070 if (hovered && inner_bb.Contains(
g.IO.MousePos))
7072 const float t = ImClamp((
g.IO.MousePos.x - inner_bb.Min.x) / (inner_bb.Max.x - inner_bb.Min.x), 0.0f, 0.9999f);
7073 const int v_idx = (int)(
t * item_count);
7074 IM_ASSERT(v_idx >= 0 && v_idx < values_count);
7076 const float v0 = values_getter(data, (v_idx + values_offset) % values_count);
7077 const float v1 = values_getter(data, (v_idx + 1 + values_offset) % values_count);
7078 if (plot_type == ImGuiPlotType_Lines)
7079 SetTooltip(
"%d: %8.4g\n%d: %8.4g", v_idx, v0, v_idx + 1, v1);
7080 else if (plot_type == ImGuiPlotType_Histogram)
7081 SetTooltip(
"%d: %8.4g", v_idx, v0);
7082 idx_hovered = v_idx;
7085 const float t_step = 1.0f / (float)res_w;
7086 const float inv_scale = (scale_min == scale_max) ? 0.0f : (1.0f / (scale_max - scale_min));
7088 float v0 = values_getter(data, (0 + values_offset) % values_count);
7090 ImVec2 tp0 = ImVec2( t0, 1.0f - ImSaturate((v0 - scale_min) * inv_scale) );
7091 float histogram_zero_line_t = (scale_min * scale_max < 0.0f) ? (1 + scale_min * inv_scale) : (scale_min < 0.0f ? 0.0f : 1.0f);
7093 const ImU32 col_base = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLines : ImGuiCol_PlotHistogram);
7094 const ImU32 col_hovered = GetColorU32((plot_type == ImGuiPlotType_Lines) ? ImGuiCol_PlotLinesHovered : ImGuiCol_PlotHistogramHovered);
7096 for (
int n = 0; n < res_w; n++)
7098 const float t1 = t0 + t_step;
7099 const int v1_idx = (int)(t0 * item_count + 0.5f);
7100 IM_ASSERT(v1_idx >= 0 && v1_idx < values_count);
7101 const float v1 = values_getter(data, (v1_idx + values_offset + 1) % values_count);
7102 const ImVec2 tp1 = ImVec2( t1, 1.0f - ImSaturate((v1 - scale_min) * inv_scale) );
7105 ImVec2 pos0 = ImLerp(inner_bb.Min, inner_bb.Max, tp0);
7106 ImVec2 pos1 = ImLerp(inner_bb.Min, inner_bb.Max, (plot_type == ImGuiPlotType_Lines) ? tp1 : ImVec2(tp1.x, histogram_zero_line_t));
7107 if (plot_type == ImGuiPlotType_Lines)
7109 window->DrawList->AddLine(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);
7111 else if (plot_type == ImGuiPlotType_Histogram)
7113 if (pos1.x >= pos0.x + 2.0f)
7115 window->DrawList->AddRectFilled(pos0, pos1, idx_hovered == v1_idx ? col_hovered : col_base);
7125 RenderTextClipped(ImVec2(frame_bb.Min.x, frame_bb.Min.y + style.FramePadding.y), frame_bb.Max, overlay_text, NULL, NULL, ImVec2(0.5f, 0.0f));
7127 if (label_size.x > 0.0f)
7128 RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, inner_bb.Min.y), label);
7143static float Plot_ArrayGetter(
void* data,
int idx)
7146 const float v = *(
const float*)(
const void*)((
const unsigned char*)plot_data->
Values + (
size_t)idx * plot_data->
Stride);
7150void ImGui::PlotLines(
const char* label,
const float* values,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max, ImVec2 graph_size,
int stride)
7153 PlotEx(ImGuiPlotType_Lines, label, &Plot_ArrayGetter, (
void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7156void ImGui::PlotLines(
const char* label,
float (*values_getter)(
void* data,
int idx),
void* data,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max, ImVec2 graph_size)
7158 PlotEx(ImGuiPlotType_Lines, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7161void ImGui::PlotHistogram(
const char* label,
const float* values,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max, ImVec2 graph_size,
int stride)
7164 PlotEx(ImGuiPlotType_Histogram, label, &Plot_ArrayGetter, (
void*)&data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7167void ImGui::PlotHistogram(
const char* label,
float (*values_getter)(
void* data,
int idx),
void* data,
int values_count,
int values_offset,
const char* overlay_text,
float scale_min,
float scale_max, ImVec2 graph_size)
7169 PlotEx(ImGuiPlotType_Histogram, label, values_getter, data, values_count, values_offset, overlay_text, scale_min, scale_max, graph_size);
7179void ImGui::Value(
const char* prefix,
bool b)
7181 Text(
"%s: %s", prefix, (b ?
"true" :
"false"));
7184void ImGui::Value(
const char* prefix,
int v)
7186 Text(
"%s: %d", prefix, v);
7189void ImGui::Value(
const char* prefix,
unsigned int v)
7191 Text(
"%s: %d", prefix, v);
7194void ImGui::Value(
const char* prefix,
float v,
const char* float_format)
7200 Text(fmt, prefix, v);
7204 Text(
"%s: %.3f", prefix, v);
7223void ImGuiMenuColumns::Update(
float spacing,
bool window_reappearing)
7225 if (window_reappearing)
7226 memset(Widths, 0,
sizeof(Widths));
7227 Spacing = (ImU16)spacing;
7228 CalcNextTotalWidth(
true);
7229 memset(Widths, 0,
sizeof(Widths));
7230 TotalWidth = NextTotalWidth;
7234void ImGuiMenuColumns::CalcNextTotalWidth(
bool update_offsets)
7237 bool want_spacing =
false;
7238 for (
int i = 0; i < IM_ARRAYSIZE(Widths); i++)
7240 ImU16 width = Widths[i];
7241 if (want_spacing && width > 0)
7243 want_spacing |= (width > 0);
7246 if (i == 1) { OffsetLabel = offset; }
7247 if (i == 2) { OffsetShortcut = offset; }
7248 if (i == 3) { OffsetMark = offset; }
7252 NextTotalWidth = offset;
7255float ImGuiMenuColumns::DeclColumns(
float w_icon,
float w_label,
float w_shortcut,
float w_mark)
7257 Widths[0] = ImMax(Widths[0], (ImU16)w_icon);
7258 Widths[1] = ImMax(Widths[1], (ImU16)w_label);
7259 Widths[2] = ImMax(Widths[2], (ImU16)w_shortcut);
7260 Widths[3] = ImMax(Widths[3], (ImU16)w_mark);
7261 CalcNextTotalWidth(
false);
7262 return (
float)ImMax(TotalWidth, NextTotalWidth);
7269bool ImGui::BeginMenuBar()
7271 ImGuiWindow* window = GetCurrentWindow();
7272 if (window->SkipItems)
7274 if (!(window->Flags & ImGuiWindowFlags_MenuBar))
7277 IM_ASSERT(!window->DC.MenuBarAppending);
7279 PushID(
"##menubar");
7283 ImRect bar_rect = window->MenuBarRect();
7284 ImRect clip_rect(IM_ROUND(bar_rect.Min.x + window->WindowBorderSize), IM_ROUND(bar_rect.Min.y + window->WindowBorderSize), IM_ROUND(ImMax(bar_rect.Min.x, bar_rect.Max.x - ImMax(window->WindowRounding, window->WindowBorderSize))), IM_ROUND(bar_rect.Max.y));
7285 clip_rect.ClipWith(window->OuterRectClipped);
7286 PushClipRect(clip_rect.Min, clip_rect.Max,
false);
7289 window->DC.CursorPos = window->DC.CursorMaxPos = ImVec2(bar_rect.Min.x + window->DC.MenuBarOffset.x, bar_rect.Min.y + window->DC.MenuBarOffset.y);
7290 window->DC.LayoutType = ImGuiLayoutType_Horizontal;
7291 window->DC.IsSameLine =
false;
7292 window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
7293 window->DC.MenuBarAppending =
true;
7294 AlignTextToFramePadding();
7298void ImGui::EndMenuBar()
7300 ImGuiWindow* window = GetCurrentWindow();
7301 if (window->SkipItems)
7306 if (NavMoveRequestButNoResultYet() && (
g.NavMoveDir == ImGuiDir_Left ||
g.NavMoveDir == ImGuiDir_Right) && (
g.NavWindow->Flags & ImGuiWindowFlags_ChildMenu))
7309 ImGuiWindow* nav_earliest_child =
g.NavWindow;
7310 while (nav_earliest_child->ParentWindow && (nav_earliest_child->ParentWindow->Flags & ImGuiWindowFlags_ChildMenu))
7311 nav_earliest_child = nav_earliest_child->ParentWindow;
7312 if (nav_earliest_child->ParentWindow == window && nav_earliest_child->DC.ParentLayoutType == ImGuiLayoutType_Horizontal && (
g.NavMoveFlags & ImGuiNavMoveFlags_Forwarded) == 0)
7316 const ImGuiNavLayer layer = ImGuiNavLayer_Menu;
7317 IM_ASSERT(window->DC.NavLayersActiveMaskNext & (1 << layer));
7318 FocusWindow(window);
7319 SetNavID(window->NavLastIds[layer], layer, 0, window->NavRectRel[layer]);
7320 g.NavDisableHighlight =
true;
7321 g.NavDisableMouseHover =
g.NavMousePosDirty =
true;
7322 NavMoveRequestForward(
g.NavMoveDir,
g.NavMoveClipDir,
g.NavMoveFlags,
g.NavMoveScrollFlags);
7326 IM_MSVC_WARNING_SUPPRESS(6011);
7327 IM_ASSERT(window->Flags & ImGuiWindowFlags_MenuBar);
7328 IM_ASSERT(window->DC.MenuBarAppending);
7331 window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->Pos.x;
7334 ImGuiGroupData& group_data =
g.GroupStack.back();
7335 group_data.EmitItem =
false;
7336 ImVec2 restore_cursor_max_pos = group_data.BackupCursorMaxPos;
7337 window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, window->DC.CursorMaxPos.x - window->Scroll.x);
7339 window->DC.LayoutType = ImGuiLayoutType_Vertical;
7340 window->DC.IsSameLine =
false;
7341 window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
7342 window->DC.MenuBarAppending =
false;
7343 window->DC.CursorMaxPos = restore_cursor_max_pos;
7349bool ImGui::BeginViewportSideBar(
const char* name, ImGuiViewport* viewport_p, ImGuiDir dir,
float axis_size, ImGuiWindowFlags window_flags)
7351 IM_ASSERT(dir != ImGuiDir_None);
7353 ImGuiWindow* bar_window = FindWindowByName(name);
7354 ImGuiViewportP* viewport = (ImGuiViewportP*)(
void*)(viewport_p ? viewport_p : GetMainViewport());
7355 if (bar_window == NULL || bar_window->BeginCount == 0)
7358 ImRect avail_rect = viewport->GetBuildWorkRect();
7359 ImGuiAxis axis = (dir == ImGuiDir_Up || dir == ImGuiDir_Down) ? ImGuiAxis_Y : ImGuiAxis_X;
7360 ImVec2 pos = avail_rect.Min;
7361 if (dir == ImGuiDir_Right || dir == ImGuiDir_Down)
7362 pos[axis] = avail_rect.Max[axis] - axis_size;
7363 ImVec2
size = avail_rect.GetSize();
7364 size[axis] = axis_size;
7365 SetNextWindowPos(pos);
7366 SetNextWindowSize(size);
7369 if (dir == ImGuiDir_Up || dir == ImGuiDir_Left)
7370 viewport->BuildWorkOffsetMin[axis] += axis_size;
7371 else if (dir == ImGuiDir_Down || dir == ImGuiDir_Right)
7372 viewport->BuildWorkOffsetMax[axis] -= axis_size;
7375 window_flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoDocking;
7376 SetNextWindowViewport(viewport->ID);
7377 PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
7378 PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0, 0));
7379 bool is_open = Begin(name, NULL, window_flags);
7385bool ImGui::BeginMainMenuBar()
7388 ImGuiViewportP* viewport = (ImGuiViewportP*)(
void*)GetMainViewport();
7391 SetCurrentViewport(NULL, viewport);
7396 g.NextWindowData.MenuBarOffsetMinVal = ImVec2(
g.Style.DisplaySafeAreaPadding.x, ImMax(
g.Style.DisplaySafeAreaPadding.y -
g.Style.FramePadding.y, 0.0f));
7397 ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
7398 float height = GetFrameHeight();
7399 bool is_open = BeginViewportSideBar(
"##MainMenuBar", viewport, ImGuiDir_Up, height, window_flags);
7400 g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
7409void ImGui::EndMainMenuBar()
7416 if (
g.CurrentWindow ==
g.NavWindow &&
g.NavLayer == ImGuiNavLayer_Main && !
g.NavAnyRequest)
7417 FocusTopMostWindowUnderOne(
g.NavWindow, NULL, NULL, ImGuiFocusRequestFlags_UnlessBelowModal | ImGuiFocusRequestFlags_RestoreFocusedChild);
7422static bool IsRootOfOpenMenuSet()
7425 ImGuiWindow* window =
g.CurrentWindow;
7426 if ((
g.OpenPopupStack.Size <=
g.BeginPopupStack.Size) || (window->Flags & ImGuiWindowFlags_ChildMenu))
7440 const ImGuiPopupData* upper_popup = &
g.OpenPopupStack[
g.BeginPopupStack.Size];
7441 if (window->DC.NavLayerCurrent != upper_popup->ParentNavLayer)
7443 return upper_popup->Window && (upper_popup->Window->Flags & ImGuiWindowFlags_ChildMenu) && ImGui::IsWindowChildOf(upper_popup->Window, window,
true,
false);
7446bool ImGui::BeginMenuEx(
const char* label,
const char* icon,
bool enabled)
7448 ImGuiWindow* window = GetCurrentWindow();
7449 if (window->SkipItems)
7453 const ImGuiStyle& style =
g.Style;
7454 const ImGuiID
id = window->GetID(label);
7455 bool menu_is_open = IsPopupOpen(
id, ImGuiPopupFlags_None);
7459 ImGuiWindowFlags window_flags = ImGuiWindowFlags_ChildMenu | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoNavFocus;
7460 if (window->Flags & ImGuiWindowFlags_ChildMenu)
7461 window_flags |= ImGuiWindowFlags_ChildWindow;
7466 if (
g.MenusIdSubmittedThisFrame.contains(
id))
7469 menu_is_open = BeginPopupEx(
id, window_flags);
7471 g.NextWindowData.ClearFlags();
7472 return menu_is_open;
7476 g.MenusIdSubmittedThisFrame.push_back(
id);
7482 const bool menuset_is_open = IsRootOfOpenMenuSet();
7483 if (menuset_is_open)
7484 PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck,
true);
7489 ImVec2 popup_pos, pos = window->DC.CursorPos;
7493 const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
7497 const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SelectOnClick | ImGuiSelectableFlags_DontClosePopups;
7498 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
7503 popup_pos = ImVec2(pos.x - 1.0f - IM_TRUNC(style.ItemSpacing.x * 0.5f), pos.y - style.FramePadding.y + window->MenuBarHeight());
7504 window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
7505 PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
7506 float w = label_size.x;
7507 ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
7508 pressed = Selectable(
"", menu_is_open, selectable_flags, ImVec2(w, label_size.y));
7509 RenderText(text_pos, label);
7511 window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f));
7518 popup_pos = ImVec2(pos.x, pos.y - style.WindowPadding.y);
7519 float icon_w = (icon && icon[0]) ?
CalcTextSize(icon, NULL).x : 0.0f;
7520 float checkmark_w = IM_TRUNC(
g.FontSize * 1.20f);
7521 float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w);
7522 float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
7523 ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
7524 pressed = Selectable(
"", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
7525 RenderText(text_pos, label);
7527 RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
7528 RenderArrow(window->DrawList, pos + ImVec2(offsets->OffsetMark + extra_w +
g.FontSize * 0.30f, 0.0f), GetColorU32(ImGuiCol_Text), ImGuiDir_Right);
7533 const bool hovered = (
g.HoveredId ==
id) && enabled && !
g.NavDisableMouseHover;
7534 if (menuset_is_open)
7537 bool want_open =
false;
7538 bool want_open_nav_init =
false;
7539 bool want_close =
false;
7540 if (window->DC.LayoutType == ImGuiLayoutType_Vertical)
7544 bool moving_toward_child_menu =
false;
7545 ImGuiPopupData* child_popup = (
g.BeginPopupStack.Size <
g.OpenPopupStack.Size) ? &
g.OpenPopupStack[
g.BeginPopupStack.Size] : NULL;
7546 ImGuiWindow* child_menu_window = (child_popup && child_popup->Window && child_popup->Window->ParentWindow == window) ? child_popup->Window : NULL;
7547 if (
g.HoveredWindow == window && child_menu_window != NULL)
7549 const float ref_unit =
g.FontSize;
7550 const float child_dir = (window->Pos.x < child_menu_window->Pos.x) ? 1.0f : -1.0f;
7551 const ImRect next_window_rect = child_menu_window->Rect();
7552 ImVec2 ta = (
g.IO.MousePos -
g.IO.MouseDelta);
7553 ImVec2 tb = (child_dir > 0.0f) ? next_window_rect.GetTL() : next_window_rect.GetTR();
7554 ImVec2 tc = (child_dir > 0.0f) ? next_window_rect.GetBL() : next_window_rect.GetBR();
7555 const float pad_farmost_h = ImClamp(ImFabs(ta.x - tb.x) * 0.30f, ref_unit * 0.5f, ref_unit * 2.5f);
7556 ta.x += child_dir * -0.5f;
7557 tb.x += child_dir * ref_unit;
7558 tc.x += child_dir * ref_unit;
7559 tb.y = ta.y + ImMax((tb.y - pad_farmost_h) - ta.y, -ref_unit * 8.0f);
7560 tc.y = ta.y + ImMin((tc.y + pad_farmost_h) - ta.y, +ref_unit * 8.0f);
7568 if (menu_is_open && !hovered &&
g.HoveredWindow == window && !moving_toward_child_menu && !
g.NavDisableMouseHover &&
g.ActiveId == 0)
7573 if (!menu_is_open && pressed)
7575 else if (!menu_is_open && hovered && !moving_toward_child_menu)
7577 else if (!menu_is_open && hovered &&
g.HoveredIdTimer >= 0.30f &&
g.MouseStationaryTimer >= 0.30f)
7579 if (
g.NavId ==
id &&
g.NavMoveDir == ImGuiDir_Right)
7581 want_open = want_open_nav_init =
true;
7582 NavMoveRequestCancel();
7583 NavRestoreHighlightAfterMove();
7589 if (menu_is_open && pressed && menuset_is_open)
7592 want_open = menu_is_open =
false;
7594 else if (pressed || (hovered && menuset_is_open && !menu_is_open))
7598 else if (
g.NavId ==
id &&
g.NavMoveDir == ImGuiDir_Down)
7601 NavMoveRequestCancel();
7607 if (want_close && IsPopupOpen(
id, ImGuiPopupFlags_None))
7608 ClosePopupToLevel(
g.BeginPopupStack.Size,
true);
7610 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Openable | (menu_is_open ? ImGuiItemStatusFlags_Opened : 0));
7613 if (want_open && !menu_is_open &&
g.OpenPopupStack.Size >
g.BeginPopupStack.Size)
7620 menu_is_open =
true;
7621 OpenPopup(label, ImGuiPopupFlags_NoReopen);
7626 ImGuiLastItemData last_item_in_parent =
g.LastItemData;
7627 SetNextWindowPos(popup_pos, ImGuiCond_Always);
7628 PushStyleVar(ImGuiStyleVar_ChildRounding, style.PopupRounding);
7629 menu_is_open = BeginPopupEx(
id, window_flags);
7635 if (want_open && want_open_nav_init && !
g.NavInitRequest)
7637 FocusWindow(
g.CurrentWindow, ImGuiFocusRequestFlags_UnlessBelowModal);
7638 NavInitWindow(
g.CurrentWindow,
false);
7643 g.LastItemData = last_item_in_parent;
7644 if (
g.HoveredWindow == window)
7645 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
7650 g.NextWindowData.ClearFlags();
7653 return menu_is_open;
7656bool ImGui::BeginMenu(
const char* label,
bool enabled)
7658 return BeginMenuEx(label, NULL, enabled);
7661void ImGui::EndMenu()
7665 ImGuiWindow* window =
g.CurrentWindow;
7666 IM_ASSERT(window->Flags & ImGuiWindowFlags_Popup);
7667 ImGuiWindow* parent_window = window->ParentWindow;
7668 if (window->BeginCount == window->BeginCountPreviousFrame)
7669 if (
g.NavMoveDir == ImGuiDir_Left && NavMoveRequestButNoResultYet())
7670 if (
g.NavWindow && (
g.NavWindow->RootWindowForNav == window) && parent_window->DC.LayoutType == ImGuiLayoutType_Vertical)
7672 ClosePopupToLevel(
g.BeginPopupStack.Size - 1,
true);
7673 NavMoveRequestCancel();
7679bool ImGui::MenuItemEx(
const char* label,
const char* icon,
const char* shortcut,
bool selected,
bool enabled)
7681 ImGuiWindow* window = GetCurrentWindow();
7682 if (window->SkipItems)
7686 ImGuiStyle& style =
g.Style;
7687 ImVec2 pos = window->DC.CursorPos;
7691 const bool menuset_is_open = IsRootOfOpenMenuSet();
7692 if (menuset_is_open)
7693 PushItemFlag(ImGuiItemFlags_NoWindowHoverableCheck,
true);
7703 const ImGuiSelectableFlags selectable_flags = ImGuiSelectableFlags_SelectOnRelease | ImGuiSelectableFlags_NoSetKeyOwner | ImGuiSelectableFlags_SetNavIdOnHover;
7704 const ImGuiMenuColumns* offsets = &window->DC.MenuColumns;
7705 if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
7709 float w = label_size.x;
7710 window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * 0.5f);
7711 ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
7712 PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
7713 pressed = Selectable(
"", selected, selectable_flags, ImVec2(w, 0.0f));
7715 if (
g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
7716 RenderText(text_pos, label);
7717 window->DC.CursorPos.x += IM_TRUNC(style.ItemSpacing.x * (-1.0f + 0.5f));
7724 float icon_w = (icon && icon[0]) ?
CalcTextSize(icon, NULL).x : 0.0f;
7725 float shortcut_w = (shortcut && shortcut[0]) ?
CalcTextSize(shortcut, NULL).x : 0.0f;
7726 float checkmark_w = IM_TRUNC(
g.FontSize * 1.20f);
7727 float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w);
7728 float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
7729 pressed = Selectable(
"",
false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
7730 if (
g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
7732 RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
7734 RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
7735 if (shortcut_w > 0.0f)
7737 PushStyleColor(ImGuiCol_Text, style.Colors[ImGuiCol_TextDisabled]);
7738 RenderText(pos + ImVec2(offsets->OffsetShortcut + stretch_w, 0.0f), shortcut, NULL,
false);
7742 RenderCheckMark(window->DrawList, pos + ImVec2(offsets->OffsetMark + stretch_w +
g.FontSize * 0.40f,
g.FontSize * 0.134f * 0.5f), GetColorU32(ImGuiCol_Text),
g.FontSize * 0.866f);
7745 IMGUI_TEST_ENGINE_ITEM_INFO(
g.LastItemData.ID, label,
g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (selected ? ImGuiItemStatusFlags_Checked : 0));
7749 if (menuset_is_open)
7755bool ImGui::MenuItem(
const char* label,
const char* shortcut,
bool selected,
bool enabled)
7757 return MenuItemEx(label, NULL, shortcut, selected, enabled);
7760bool ImGui::MenuItem(
const char* label,
const char* shortcut,
bool* p_selected,
bool enabled)
7762 if (MenuItemEx(label, NULL, shortcut, p_selected ? *p_selected : false, enabled))
7765 *p_selected = !*p_selected;
7809 static void TabBarLayout(ImGuiTabBar* tab_bar);
7810 static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar,
const char* label, ImGuiWindow* docked_window);
7811 static float TabBarCalcMaxTabWidth();
7812 static float TabBarScrollClamp(ImGuiTabBar* tab_bar,
float scrolling);
7813 static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id,
ImGuiTabBarSection* sections);
7814 static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);
7815 static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);
7818ImGuiTabBar::ImGuiTabBar()
7820 memset(
this, 0,
sizeof(*
this));
7821 CurrFrameVisible = PrevFrameVisible = -1;
7822 LastTabItemIdx = -1;
7825static inline int TabItemGetSectionIdx(
const ImGuiTabItem* tab)
7827 return (tab->Flags & ImGuiTabItemFlags_Leading) ? 0 : (tab->Flags & ImGuiTabItemFlags_Trailing) ? 2 : 1;
7830static int IMGUI_CDECL TabItemComparerBySection(
const void* lhs,
const void* rhs)
7832 const ImGuiTabItem* a = (
const ImGuiTabItem*)lhs;
7833 const ImGuiTabItem* b = (
const ImGuiTabItem*)rhs;
7834 const int a_section = TabItemGetSectionIdx(a);
7835 const int b_section = TabItemGetSectionIdx(b);
7836 if (a_section != b_section)
7837 return a_section - b_section;
7838 return (
int)(a->IndexDuringLayout - b->IndexDuringLayout);
7841static int IMGUI_CDECL TabItemComparerByBeginOrder(
const void* lhs,
const void* rhs)
7843 const ImGuiTabItem* a = (
const ImGuiTabItem*)lhs;
7844 const ImGuiTabItem* b = (
const ImGuiTabItem*)rhs;
7845 return (
int)(a->BeginOrder - b->BeginOrder);
7848static ImGuiTabBar* GetTabBarFromTabBarRef(
const ImGuiPtrOrIndex& ref)
7851 return ref.Ptr ? (ImGuiTabBar*)ref.Ptr :
g.TabBars.GetByIndex(ref.Index);
7854static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
7857 if (
g.TabBars.Contains(tab_bar))
7858 return ImGuiPtrOrIndex(
g.TabBars.GetIndex(tab_bar));
7859 return ImGuiPtrOrIndex(tab_bar);
7862bool ImGui::BeginTabBar(
const char* str_id, ImGuiTabBarFlags flags)
7865 ImGuiWindow* window =
g.CurrentWindow;
7866 if (window->SkipItems)
7869 ImGuiID
id = window->GetID(str_id);
7870 ImGuiTabBar* tab_bar =
g.TabBars.GetOrAddByKey(
id);
7871 ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y +
g.FontSize +
g.Style.FramePadding.y * 2);
7873 tab_bar->SeparatorMinX = tab_bar->BarRect.Min.x - IM_TRUNC(window->WindowPadding.x * 0.5f);
7874 tab_bar->SeparatorMaxX = tab_bar->BarRect.Max.x + IM_TRUNC(window->WindowPadding.x * 0.5f);
7875 return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused);
7878bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar,
const ImRect& tab_bar_bb, ImGuiTabBarFlags flags)
7881 ImGuiWindow* window =
g.CurrentWindow;
7882 if (window->SkipItems)
7885 IM_ASSERT(tab_bar->ID != 0);
7886 if ((flags & ImGuiTabBarFlags_DockNode) == 0)
7887 PushOverrideID(tab_bar->ID);
7890 g.CurrentTabBarStack.push_back(GetTabBarRefFromTabBar(tab_bar));
7891 g.CurrentTabBar = tab_bar;
7894 tab_bar->BackupCursorPos = window->DC.CursorPos;
7895 if (tab_bar->CurrFrameVisible ==
g.FrameCount)
7897 window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY);
7898 tab_bar->BeginCount++;
7903 if ((flags & ImGuiTabBarFlags_Reorderable) != (tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (tab_bar->TabsAddedNew && !(flags & ImGuiTabBarFlags_Reorderable)))
7904 if ((flags & ImGuiTabBarFlags_DockNode) == 0)
7905 ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size,
sizeof(ImGuiTabItem), TabItemComparerByBeginOrder);
7906 tab_bar->TabsAddedNew =
false;
7909 if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
7910 flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
7912 tab_bar->Flags = flags;
7913 tab_bar->BarRect = tab_bar_bb;
7914 tab_bar->WantLayout =
true;
7915 tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible;
7916 tab_bar->CurrFrameVisible =
g.FrameCount;
7917 tab_bar->PrevTabsContentsHeight = tab_bar->CurrTabsContentsHeight;
7918 tab_bar->CurrTabsContentsHeight = 0.0f;
7919 tab_bar->ItemSpacingY =
g.Style.ItemSpacing.y;
7920 tab_bar->FramePadding =
g.Style.FramePadding;
7921 tab_bar->TabsActiveCount = 0;
7922 tab_bar->LastTabItemIdx = -1;
7923 tab_bar->BeginCount = 1;
7926 window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.y + tab_bar->ItemSpacingY);
7930 const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);
7931 if (
g.Style.TabBarBorderSize > 0.0f)
7933 const float y = tab_bar->BarRect.Max.y;
7934 window->DrawList->AddRectFilled(ImVec2(tab_bar->SeparatorMinX, y -
g.Style.TabBarBorderSize), ImVec2(tab_bar->SeparatorMaxX, y), col);
7939void ImGui::EndTabBar()
7942 ImGuiWindow* window =
g.CurrentWindow;
7943 if (window->SkipItems)
7946 ImGuiTabBar* tab_bar =
g.CurrentTabBar;
7947 if (tab_bar == NULL)
7949 IM_ASSERT_USER_ERROR(tab_bar != NULL,
"Mismatched BeginTabBar()/EndTabBar()!");
7954 if (tab_bar->WantLayout)
7955 TabBarLayout(tab_bar);
7958 const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 <
g.FrameCount);
7959 if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing)
7961 tab_bar->CurrTabsContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, tab_bar->CurrTabsContentsHeight);
7962 window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->CurrTabsContentsHeight;
7966 window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->PrevTabsContentsHeight;
7968 if (tab_bar->BeginCount > 1)
7969 window->DC.CursorPos = tab_bar->BackupCursorPos;
7971 tab_bar->LastTabItemIdx = -1;
7972 if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
7975 g.CurrentTabBarStack.pop_back();
7976 g.CurrentTabBar =
g.CurrentTabBarStack.empty() ? NULL : GetTabBarFromTabBarRef(
g.CurrentTabBarStack.back());
7980static float TabBarCalcScrollableWidth(ImGuiTabBar* tab_bar,
ImGuiTabBarSection* sections)
7982 return tab_bar->BarRect.GetWidth() - sections[0].
Width - sections[2].
Width - sections[1].
Spacing;
7987static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
7990 tab_bar->WantLayout =
false;
7995 bool need_sort_by_section =
false;
7997 for (
int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)
7999 ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];
8000 if (tab->LastFrameVisible < tab_bar->PrevFrameVisible || tab->WantClose)
8003 if (tab_bar->VisibleTabId == tab->ID) { tab_bar->VisibleTabId = 0; }
8004 if (tab_bar->SelectedTabId == tab->ID) { tab_bar->SelectedTabId = 0; }
8005 if (tab_bar->NextSelectedTabId == tab->ID) { tab_bar->NextSelectedTabId = 0; }
8008 if (tab_dst_n != tab_src_n)
8009 tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n];
8011 tab = &tab_bar->Tabs[tab_dst_n];
8012 tab->IndexDuringLayout = (ImS16)tab_dst_n;
8015 int curr_tab_section_n = TabItemGetSectionIdx(tab);
8018 ImGuiTabItem* prev_tab = &tab_bar->Tabs[tab_dst_n - 1];
8019 int prev_tab_section_n = TabItemGetSectionIdx(prev_tab);
8020 if (curr_tab_section_n == 0 && prev_tab_section_n != 0)
8021 need_sort_by_section =
true;
8022 if (prev_tab_section_n == 2 && curr_tab_section_n != 2)
8023 need_sort_by_section =
true;
8026 sections[curr_tab_section_n].
TabCount++;
8029 if (tab_bar->Tabs.Size != tab_dst_n)
8030 tab_bar->Tabs.resize(tab_dst_n);
8032 if (need_sort_by_section)
8033 ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size,
sizeof(ImGuiTabItem), TabItemComparerBySection);
8040 ImGuiID scroll_to_tab_id = 0;
8041 if (tab_bar->NextSelectedTabId)
8043 tab_bar->SelectedTabId = tab_bar->NextSelectedTabId;
8044 tab_bar->NextSelectedTabId = 0;
8045 scroll_to_tab_id = tab_bar->SelectedTabId;
8049 if (tab_bar->ReorderRequestTabId != 0)
8051 if (TabBarProcessReorder(tab_bar))
8052 if (tab_bar->ReorderRequestTabId == tab_bar->SelectedTabId)
8053 scroll_to_tab_id = tab_bar->ReorderRequestTabId;
8054 tab_bar->ReorderRequestTabId = 0;
8058 const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0;
8059 if (tab_list_popup_button)
8060 if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar))
8061 scroll_to_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
8066 g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);
8069 ImGuiTabItem* most_recently_selected_tab = NULL;
8070 int curr_section_n = -1;
8071 bool found_selected_tab_id =
false;
8072 for (
int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
8074 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
8075 IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible);
8077 if ((most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected) && !(tab->Flags & ImGuiTabItemFlags_Button))
8078 most_recently_selected_tab = tab;
8079 if (tab->ID == tab_bar->SelectedTabId)
8080 found_selected_tab_id =
true;
8081 if (scroll_to_tab_id == 0 &&
g.NavJustMovedToId == tab->ID)
8082 scroll_to_tab_id = tab->ID;
8087 const char* tab_name = TabBarGetTabName(tab_bar, tab);
8088 const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
8089 tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;
8091 int section_n = TabItemGetSectionIdx(tab);
8093 section->
Width += tab->ContentWidth + (section_n == curr_section_n ?
g.Style.ItemInnerSpacing.x : 0.0f);
8094 curr_section_n = section_n;
8097 IM_MSVC_WARNING_SUPPRESS(6385);
8098 ImGuiShrinkWidthItem* shrink_width_item = &
g.ShrinkWidthBuffer[shrink_buffer_indexes[section_n]++];
8099 shrink_width_item->Index = tab_n;
8100 shrink_width_item->Width = shrink_width_item->InitialWidth = tab->ContentWidth;
8101 tab->Width = ImMax(tab->ContentWidth, 1.0f);
8105 tab_bar->WidthAllTabsIdeal = 0.0f;
8106 for (
int section_n = 0; section_n < 3; section_n++)
8107 tab_bar->WidthAllTabsIdeal += sections[section_n].Width + sections[section_n].Spacing;
8111 if ((tab_bar->WidthAllTabsIdeal > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll))
8112 if (ImGuiTabItem* scroll_and_select_tab = TabBarScrollingButtons(tab_bar))
8114 scroll_to_tab_id = scroll_and_select_tab->ID;
8115 if ((scroll_and_select_tab->Flags & ImGuiTabItemFlags_Button) == 0)
8116 tab_bar->SelectedTabId = scroll_to_tab_id;
8120 float section_0_w = sections[0].
Width + sections[0].
Spacing;
8121 float section_1_w = sections[1].
Width + sections[1].
Spacing;
8122 float section_2_w = sections[2].
Width + sections[2].
Spacing;
8123 bool central_section_is_visible = (section_0_w + section_2_w) < tab_bar->BarRect.GetWidth();
8125 if (central_section_is_visible)
8126 width_excess = ImMax(section_1_w - (tab_bar->BarRect.GetWidth() - section_0_w - section_2_w), 0.0f);
8128 width_excess = (section_0_w + section_2_w) - tab_bar->BarRect.GetWidth();
8131 if (width_excess >= 1.0f && ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown) || !central_section_is_visible))
8133 int shrink_data_count = (central_section_is_visible ? sections[1].
TabCount : sections[0].
TabCount + sections[2].
TabCount);
8134 int shrink_data_offset = (central_section_is_visible ? sections[0].
TabCount + sections[2].
TabCount : 0);
8135 ShrinkWidths(
g.ShrinkWidthBuffer.Data + shrink_data_offset, shrink_data_count, width_excess);
8138 for (
int tab_n = shrink_data_offset; tab_n < shrink_data_offset + shrink_data_count; tab_n++)
8140 ImGuiTabItem* tab = &tab_bar->Tabs[
g.ShrinkWidthBuffer[tab_n].Index];
8141 float shrinked_width = IM_TRUNC(
g.ShrinkWidthBuffer[tab_n].Width);
8142 if (shrinked_width < 0.0f)
8145 shrinked_width = ImMax(1.0f, shrinked_width);
8146 int section_n = TabItemGetSectionIdx(tab);
8147 sections[section_n].
Width -= (tab->Width - shrinked_width);
8148 tab->Width = shrinked_width;
8153 int section_tab_index = 0;
8154 float tab_offset = 0.0f;
8155 tab_bar->WidthAllTabs = 0.0f;
8156 for (
int section_n = 0; section_n < 3; section_n++)
8160 tab_offset = ImMin(ImMax(0.0f, tab_bar->BarRect.GetWidth() - section->
Width), tab_offset);
8162 for (
int tab_n = 0; tab_n < section->
TabCount; tab_n++)
8164 ImGuiTabItem* tab = &tab_bar->Tabs[section_tab_index + tab_n];
8165 tab->Offset = tab_offset;
8166 tab->NameOffset = -1;
8167 tab_offset += tab->Width + (tab_n < section->
TabCount - 1 ?
g.Style.ItemInnerSpacing.x : 0.0f);
8169 tab_bar->WidthAllTabs += ImMax(section->
Width + section->
Spacing, 0.0f);
8170 tab_offset += section->
Spacing;
8171 section_tab_index += section->
TabCount;
8175 tab_bar->TabsNames.Buf.resize(0);
8178 if (found_selected_tab_id ==
false)
8179 tab_bar->SelectedTabId = 0;
8180 if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL)
8181 scroll_to_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID;
8184 tab_bar->VisibleTabId = tab_bar->SelectedTabId;
8185 tab_bar->VisibleTabWasSubmitted =
false;
8188 if (
g.NavWindowingTarget != NULL &&
g.NavWindowingTarget->DockNode &&
g.NavWindowingTarget->DockNode->TabBar == tab_bar)
8189 tab_bar->VisibleTabId = scroll_to_tab_id =
g.NavWindowingTarget->TabId;
8192 if (scroll_to_tab_id != 0)
8193 TabBarScrollToTab(tab_bar, scroll_to_tab_id, sections);
8194 else if ((tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll) && IsMouseHoveringRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max,
true) && IsWindowContentHoverable(
g.CurrentWindow))
8196 const float wheel =
g.IO.MouseWheelRequestAxisSwap ?
g.IO.MouseWheel :
g.IO.MouseWheelH;
8197 const ImGuiKey wheel_key =
g.IO.MouseWheelRequestAxisSwap ? ImGuiKey_MouseWheelY : ImGuiKey_MouseWheelX;
8198 if (TestKeyOwner(wheel_key, tab_bar->ID) && wheel != 0.0f)
8200 const float scroll_step = wheel * TabBarCalcScrollableWidth(tab_bar, sections) / 3.0f;
8201 tab_bar->ScrollingTargetDistToVisibility = 0.0f;
8202 tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget - scroll_step);
8204 SetKeyOwner(wheel_key, tab_bar->ID);
8208 tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);
8209 tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);
8210 if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
8214 tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, 70.0f *
g.FontSize);
8215 tab_bar->ScrollingSpeed = ImMax(tab_bar->ScrollingSpeed, ImFabs(tab_bar->ScrollingTarget - tab_bar->ScrollingAnim) / 0.3f);
8216 const bool teleport = (tab_bar->PrevFrameVisible + 1 <
g.FrameCount) || (tab_bar->ScrollingTargetDistToVisibility > 10.0f *
g.FontSize);
8217 tab_bar->ScrollingAnim = teleport ? tab_bar->ScrollingTarget : ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget,
g.IO.DeltaTime * tab_bar->ScrollingSpeed);
8221 tab_bar->ScrollingSpeed = 0.0f;
8223 tab_bar->ScrollingRectMinX = tab_bar->BarRect.Min.x + sections[0].
Width + sections[0].
Spacing;
8224 tab_bar->ScrollingRectMaxX = tab_bar->BarRect.Max.x - sections[2].
Width - sections[1].
Spacing;
8227 ImGuiWindow* window =
g.CurrentWindow;
8228 window->DC.CursorPos = tab_bar->BarRect.Min;
8229 ItemSize(ImVec2(tab_bar->WidthAllTabs, tab_bar->BarRect.GetHeight()), tab_bar->FramePadding.y);
8230 window->DC.IdealMaxPos.x = ImMax(window->DC.IdealMaxPos.x, tab_bar->BarRect.Min.x + tab_bar->WidthAllTabsIdeal);
8234static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar,
const char* label, ImGuiWindow* docked_window)
8236 if (docked_window != NULL)
8239 IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
8240 ImGuiID
id = docked_window->TabId;
8246 ImGuiWindow* window =
GImGui->CurrentWindow;
8247 return window->GetID(label);
8251static float ImGui::TabBarCalcMaxTabWidth()
8254 return g.FontSize * 20.0f;
8257ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
8260 for (
int n = 0; n < tab_bar->Tabs.Size; n++)
8261 if (tab_bar->Tabs[n].ID == tab_id)
8262 return &tab_bar->Tabs[n];
8267ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar,
int order)
8269 if (order < 0 || order >= tab_bar->Tabs.Size)
8271 return &tab_bar->Tabs[order];
8275ImGuiTabItem* ImGui::TabBarFindMostRecentlySelectedTabForActiveWindow(ImGuiTabBar* tab_bar)
8277 ImGuiTabItem* most_recently_selected_tab = NULL;
8278 for (
int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
8280 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
8281 if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected)
8282 if (tab->Window && tab->Window->WasActive)
8283 most_recently_selected_tab = tab;
8285 return most_recently_selected_tab;
8288ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
8290 if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)
8292 return &tab_bar->Tabs[tab_bar->LastTabItemIdx];
8295const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
8298 return tab->Window->Name;
8299 if (tab->NameOffset == -1)
8301 IM_ASSERT(tab->NameOffset < tab_bar->TabsNames.Buf.Size);
8302 return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
8307void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiTabItemFlags tab_flags, ImGuiWindow* window)
8310 IM_ASSERT(TabBarFindTabByID(tab_bar, window->TabId) == NULL);
8311 IM_ASSERT(
g.CurrentTabBar != tab_bar);
8313 if (!window->HasCloseButton)
8314 tab_flags |= ImGuiTabItemFlags_NoCloseButton;
8316 ImGuiTabItem new_tab;
8317 new_tab.ID = window->TabId;
8318 new_tab.Flags = tab_flags;
8319 new_tab.LastFrameVisible = tab_bar->CurrFrameVisible;
8320 if (new_tab.LastFrameVisible == -1)
8321 new_tab.LastFrameVisible =
g.FrameCount - 1;
8322 new_tab.Window = window;
8323 tab_bar->Tabs.push_back(new_tab);
8327void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
8329 if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
8330 tab_bar->Tabs.erase(tab);
8331 if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; }
8332 if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; }
8333 if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; }
8337void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
8339 if (tab->Flags & ImGuiTabItemFlags_Button)
8342 if ((tab->Flags & (ImGuiTabItemFlags_UnsavedDocument | ImGuiTabItemFlags_NoAssumedClosure)) == 0)
8346 tab->WantClose =
true;
8347 if (tab_bar->VisibleTabId == tab->ID)
8349 tab->LastFrameVisible = -1;
8350 tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0;
8356 if (tab_bar->VisibleTabId != tab->ID)
8357 TabBarQueueFocus(tab_bar, tab);
8361static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar,
float scrolling)
8363 scrolling = ImMin(scrolling, tab_bar->WidthAllTabs - tab_bar->BarRect.GetWidth());
8364 return ImMax(scrolling, 0.0f);
8368static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id,
ImGuiTabBarSection* sections)
8370 ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id);
8373 if (tab->Flags & ImGuiTabItemFlags_SectionMask_)
8377 float margin =
g.FontSize * 1.0f;
8378 int order = TabBarGetTabOrder(tab_bar, tab);
8381 float scrollable_width = TabBarCalcScrollableWidth(tab_bar, sections);
8384 float tab_x1 = tab->Offset - sections[0].
Width + (order > sections[0].
TabCount - 1 ? -margin : 0.0f);
8385 float tab_x2 = tab->Offset - sections[0].
Width + tab->Width + (order + 1 < tab_bar->Tabs.Size - sections[2].
TabCount ? margin : 1.0f);
8386 tab_bar->ScrollingTargetDistToVisibility = 0.0f;
8387 if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= scrollable_width))
8390 tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f);
8391 tab_bar->ScrollingTarget = tab_x1;
8393 else if (tab_bar->ScrollingTarget < tab_x2 - scrollable_width)
8396 tab_bar->ScrollingTargetDistToVisibility = ImMax((tab_x1 - scrollable_width) - tab_bar->ScrollingAnim, 0.0f);
8397 tab_bar->ScrollingTarget = tab_x2 - scrollable_width;
8401void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
8403 tab_bar->NextSelectedTabId = tab->ID;
8406void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab,
int offset)
8408 IM_ASSERT(offset != 0);
8409 IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
8410 tab_bar->ReorderRequestTabId = tab->ID;
8411 tab_bar->ReorderRequestOffset = (ImS16)offset;
8414void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos)
8417 IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
8418 if ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) == 0)
8421 const bool is_central_section = (src_tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;
8422 const float bar_offset = tab_bar->BarRect.Min.x - (is_central_section ? tab_bar->ScrollingTarget : 0);
8425 const int dir = (bar_offset + src_tab->Offset) > mouse_pos.x ? -1 : +1;
8426 const int src_idx = tab_bar->Tabs.index_from_ptr(src_tab);
8427 int dst_idx = src_idx;
8428 for (
int i = src_idx; i >= 0 && i < tab_bar->Tabs.Size; i += dir)
8431 const ImGuiTabItem* dst_tab = &tab_bar->Tabs[i];
8432 if (dst_tab->Flags & ImGuiTabItemFlags_NoReorder)
8434 if ((dst_tab->Flags & ImGuiTabItemFlags_SectionMask_) != (src_tab->Flags & ImGuiTabItemFlags_SectionMask_))
8439 const float x1 = bar_offset + dst_tab->Offset -
g.Style.ItemInnerSpacing.x;
8440 const float x2 = bar_offset + dst_tab->Offset + dst_tab->Width +
g.Style.ItemInnerSpacing.x;
8442 if ((dir < 0 && mouse_pos.x > x1) || (dir > 0 && mouse_pos.x < x2))
8446 if (dst_idx != src_idx)
8447 TabBarQueueReorder(tab_bar, src_tab, dst_idx - src_idx);
8450bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
8452 ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId);
8453 if (tab1 == NULL || (tab1->Flags & ImGuiTabItemFlags_NoReorder))
8457 int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset;
8458 if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
8463 ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
8464 if (tab2->Flags & ImGuiTabItemFlags_NoReorder)
8466 if ((tab1->Flags & ImGuiTabItemFlags_SectionMask_) != (tab2->Flags & ImGuiTabItemFlags_SectionMask_))
8469 ImGuiTabItem item_tmp = *tab1;
8470 ImGuiTabItem* src_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 + 1 : tab2;
8471 ImGuiTabItem* dst_tab = (tab_bar->ReorderRequestOffset > 0) ? tab1 : tab2 + 1;
8472 const int move_count = (tab_bar->ReorderRequestOffset > 0) ? tab_bar->ReorderRequestOffset : -tab_bar->ReorderRequestOffset;
8473 memmove(dst_tab, src_tab, move_count *
sizeof(ImGuiTabItem));
8476 if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
8477 MarkIniSettingsDirty();
8481static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
8484 ImGuiWindow* window =
g.CurrentWindow;
8486 const ImVec2 arrow_button_size(
g.FontSize - 2.0f,
g.FontSize +
g.Style.FramePadding.y * 2.0f);
8487 const float scrolling_buttons_width = arrow_button_size.x * 2.0f;
8489 const ImVec2 backup_cursor_pos = window->DC.CursorPos;
8493 ImVec4 arrow_col =
g.Style.Colors[ImGuiCol_Text];
8494 arrow_col.w *= 0.5f;
8496 PushStyleColor(ImGuiCol_Text, arrow_col);
8497 PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
8498 const float backup_repeat_delay =
g.IO.KeyRepeatDelay;
8499 const float backup_repeat_rate =
g.IO.KeyRepeatRate;
8500 g.IO.KeyRepeatDelay = 0.250f;
8501 g.IO.KeyRepeatRate = 0.200f;
8502 float x = ImMax(tab_bar->BarRect.Min.x, tab_bar->BarRect.Max.x - scrolling_buttons_width);
8503 window->DC.CursorPos = ImVec2(x, tab_bar->BarRect.Min.y);
8504 if (ArrowButtonEx(
"##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
8506 window->DC.CursorPos = ImVec2(x + arrow_button_size.x, tab_bar->BarRect.Min.y);
8507 if (ArrowButtonEx(
"##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
8510 g.IO.KeyRepeatRate = backup_repeat_rate;
8511 g.IO.KeyRepeatDelay = backup_repeat_delay;
8513 ImGuiTabItem* tab_to_scroll_to = NULL;
8514 if (select_dir != 0)
8515 if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
8517 int selected_order = TabBarGetTabOrder(tab_bar, tab_item);
8518 int target_order = selected_order + select_dir;
8521 while (tab_to_scroll_to == NULL)
8524 tab_to_scroll_to = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order];
8528 if (tab_to_scroll_to->Flags & ImGuiTabItemFlags_Button)
8530 target_order += select_dir;
8531 selected_order += select_dir;
8532 tab_to_scroll_to = (target_order < 0 || target_order >= tab_bar->Tabs.Size) ? tab_to_scroll_to : NULL;
8536 window->DC.CursorPos = backup_cursor_pos;
8537 tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f;
8539 return tab_to_scroll_to;
8542static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
8545 ImGuiWindow* window =
g.CurrentWindow;
8548 const float tab_list_popup_button_width =
g.FontSize +
g.Style.FramePadding.y;
8549 const ImVec2 backup_cursor_pos = window->DC.CursorPos;
8550 window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x -
g.Style.FramePadding.y, tab_bar->BarRect.Min.y);
8551 tab_bar->BarRect.Min.x += tab_list_popup_button_width;
8553 ImVec4 arrow_col =
g.Style.Colors[ImGuiCol_Text];
8554 arrow_col.w *= 0.5f;
8555 PushStyleColor(ImGuiCol_Text, arrow_col);
8556 PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
8557 bool open = BeginCombo(
"##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_HeightLargest);
8560 ImGuiTabItem* tab_to_select = NULL;
8563 for (
int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
8565 ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
8566 if (tab->Flags & ImGuiTabItemFlags_Button)
8569 const char* tab_name = TabBarGetTabName(tab_bar, tab);
8570 if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))
8571 tab_to_select = tab;
8576 window->DC.CursorPos = backup_cursor_pos;
8577 return tab_to_select;
8593bool ImGui::BeginTabItem(
const char* label,
bool* p_open, ImGuiTabItemFlags flags)
8596 ImGuiWindow* window =
g.CurrentWindow;
8597 if (window->SkipItems)
8600 ImGuiTabBar* tab_bar =
g.CurrentTabBar;
8601 if (tab_bar == NULL)
8603 IM_ASSERT_USER_ERROR(tab_bar,
"Needs to be called between BeginTabBar() and EndTabBar()!");
8606 IM_ASSERT((flags & ImGuiTabItemFlags_Button) == 0);
8608 bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
8609 if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
8611 ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
8612 PushOverrideID(tab->ID);
8617void ImGui::EndTabItem()
8620 ImGuiWindow* window =
g.CurrentWindow;
8621 if (window->SkipItems)
8624 ImGuiTabBar* tab_bar =
g.CurrentTabBar;
8625 if (tab_bar == NULL)
8627 IM_ASSERT_USER_ERROR(tab_bar != NULL,
"Needs to be called between BeginTabBar() and EndTabBar()!");
8630 IM_ASSERT(tab_bar->LastTabItemIdx >= 0);
8631 ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
8632 if (!(tab->Flags & ImGuiTabItemFlags_NoPushId))
8636bool ImGui::TabItemButton(
const char* label, ImGuiTabItemFlags flags)
8639 ImGuiWindow* window =
g.CurrentWindow;
8640 if (window->SkipItems)
8643 ImGuiTabBar* tab_bar =
g.CurrentTabBar;
8644 if (tab_bar == NULL)
8646 IM_ASSERT_USER_ERROR(tab_bar != NULL,
"Needs to be called between BeginTabBar() and EndTabBar()!");
8649 return TabItemEx(tab_bar, label, NULL, flags | ImGuiTabItemFlags_Button | ImGuiTabItemFlags_NoReorder, NULL);
8652bool ImGui::TabItemEx(ImGuiTabBar* tab_bar,
const char* label,
bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
8656 if (tab_bar->WantLayout)
8658 ImGuiNextItemData backup_next_item_data =
g.NextItemData;
8659 TabBarLayout(tab_bar);
8660 g.NextItemData = backup_next_item_data;
8662 ImGuiWindow* window =
g.CurrentWindow;
8663 if (window->SkipItems)
8666 const ImGuiStyle& style =
g.Style;
8667 const ImGuiID
id = TabBarCalcTabID(tab_bar, label, docked_window);
8671 IMGUI_TEST_ENGINE_ITEM_INFO(
id, label,
g.LastItemData.StatusFlags);
8672 if (p_open && !*p_open)
8674 ItemAdd(ImRect(),
id, NULL, ImGuiItemFlags_NoNav);
8678 IM_ASSERT(!p_open || !(flags & ImGuiTabItemFlags_Button));
8679 IM_ASSERT((flags & (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing)) != (ImGuiTabItemFlags_Leading | ImGuiTabItemFlags_Trailing));
8682 if (flags & ImGuiTabItemFlags_NoCloseButton)
8684 else if (p_open == NULL)
8685 flags |= ImGuiTabItemFlags_NoCloseButton;
8688 ImGuiTabItem* tab = TabBarFindTabByID(tab_bar,
id);
8689 bool tab_is_new =
false;
8692 tab_bar->Tabs.push_back(ImGuiTabItem());
8693 tab = &tab_bar->Tabs.back();
8695 tab_bar->TabsAddedNew = tab_is_new =
true;
8697 tab_bar->LastTabItemIdx = (ImS16)tab_bar->Tabs.index_from_ptr(tab);
8700 ImVec2
size = TabItemCalcSize(label, (p_open != NULL) || (flags & ImGuiTabItemFlags_UnsavedDocument));
8701 tab->RequestedWidth = -1.0f;
8702 if (
g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
8703 size.x = tab->RequestedWidth =
g.NextItemData.Width;
8705 tab->Width = ImMax(1.0f,
size.x);
8706 tab->ContentWidth =
size.x;
8707 tab->BeginOrder = tab_bar->TabsActiveCount++;
8709 const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 <
g.FrameCount);
8710 const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;
8711 const bool tab_appearing = (tab->LastFrameVisible + 1 <
g.FrameCount);
8712 const bool tab_just_unsaved = (flags & ImGuiTabItemFlags_UnsavedDocument) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
8713 const bool is_tab_button = (flags & ImGuiTabItemFlags_Button) != 0;
8714 tab->LastFrameVisible =
g.FrameCount;
8716 tab->Window = docked_window;
8720 if (docked_window != NULL)
8722 IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_DockNode);
8723 tab->NameOffset = -1;
8727 tab->NameOffset = (ImS32)tab_bar->TabsNames.size();
8728 tab_bar->TabsNames.append(label, label + strlen(label) + 1);
8734 if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
8735 if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
8736 TabBarQueueFocus(tab_bar, tab);
8737 if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId !=
id))
8738 TabBarQueueFocus(tab_bar, tab);
8743 bool tab_contents_visible = (tab_bar->VisibleTabId ==
id);
8744 if (tab_contents_visible)
8745 tab_bar->VisibleTabWasSubmitted =
true;
8748 if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL)
8749 if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs))
8750 tab_contents_visible =
true;
8754 if (tab_appearing && (!tab_bar_appearing || tab_is_new))
8756 ItemAdd(ImRect(),
id, NULL, ImGuiItemFlags_NoNav);
8759 return tab_contents_visible;
8762 if (tab_bar->SelectedTabId ==
id)
8763 tab->LastFrameSelected =
g.FrameCount;
8766 const ImVec2 backup_main_cursor_pos = window->DC.CursorPos;
8769 const bool is_central_section = (tab->Flags & ImGuiTabItemFlags_SectionMask_) == 0;
8770 size.x = tab->Width;
8771 if (is_central_section)
8772 window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(IM_TRUNC(tab->Offset - tab_bar->ScrollingAnim), 0.0f);
8774 window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2(tab->Offset, 0.0f);
8775 ImVec2 pos = window->DC.CursorPos;
8776 ImRect bb(pos, pos + size);
8779 const bool want_clip_rect = is_central_section && (bb.Min.x < tab_bar->ScrollingRectMinX || bb.Max.x > tab_bar->ScrollingRectMaxX);
8781 PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->ScrollingRectMinX), bb.Min.y - 1), ImVec2(tab_bar->ScrollingRectMaxX, bb.Max.y),
true);
8783 ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;
8784 ItemSize(bb.GetSize(), style.FramePadding.y);
8785 window->DC.CursorMaxPos = backup_cursor_max_pos;
8787 if (!ItemAdd(bb,
id))
8791 window->DC.CursorPos = backup_main_cursor_pos;
8792 return tab_contents_visible;
8796 ImGuiButtonFlags button_flags = ((is_tab_button ? ImGuiButtonFlags_PressedOnClickRelease : ImGuiButtonFlags_PressedOnClick) | ImGuiButtonFlags_AllowOverlap);
8797 if (
g.DragDropActive && !
g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW))
8798 button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
8800 bool pressed = ButtonBehavior(bb,
id, &hovered, &held, button_flags);
8801 if (pressed && !is_tab_button)
8802 TabBarQueueFocus(tab_bar, tab);
8806 if (held && docked_window &&
g.ActiveId ==
id &&
g.ActiveIdIsJustActivated)
8807 g.ActiveIdWindow = docked_window;
8810 ImGuiDockNode* node = docked_window ? docked_window->DockNode : NULL;
8811 const bool single_floating_window_node = node && node->IsFloatingNode() && (node->Windows.Size == 1);
8812 if (held && single_floating_window_node && IsMouseDragging(0, 0.0f))
8815 StartMouseMovingWindow(docked_window);
8817 else if (held && !tab_appearing && IsMouseDragging(0))
8821 float drag_distance_from_edge_x = 0.0f;
8822 if (!
g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (docked_window != NULL)))
8825 if (
g.IO.MouseDelta.x < 0.0f &&
g.IO.MousePos.x < bb.Min.x)
8828 drag_distance_from_edge_x = bb.Min.x -
g.IO.MousePos.x;
8829 TabBarQueueReorderFromMousePos(tab_bar, tab,
g.IO.MousePos);
8831 else if (
g.IO.MouseDelta.x > 0.0f &&
g.IO.MousePos.x > bb.Max.x)
8834 drag_distance_from_edge_x =
g.IO.MousePos.x - bb.Max.x;
8835 TabBarQueueReorderFromMousePos(tab_bar, tab,
g.IO.MousePos);
8840 const bool can_undock = docked_window != NULL && !(docked_window->Flags & ImGuiWindowFlags_NoMove) && !(node->MergedFlags & ImGuiDockNodeFlags_NoUndocking);
8844 bool undocking_tab = (
g.DragDropActive &&
g.DragDropPayload.SourceId ==
id);
8847 float threshold_base =
g.FontSize;
8848 float threshold_x = (threshold_base * 2.2f);
8849 float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(
g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
8852 float distance_from_edge_y = ImMax(bb.Min.y -
g.IO.MousePos.y,
g.IO.MousePos.y - bb.Max.y);
8853 if (distance_from_edge_y >= threshold_y)
8854 undocking_tab =
true;
8855 if (drag_distance_from_edge_x > threshold_x)
8856 if ((drag_dir < 0 && TabBarGetTabOrder(tab_bar, tab) == 0) || (drag_dir > 0 && TabBarGetTabOrder(tab_bar, tab) == tab_bar->Tabs.Size - 1))
8857 undocking_tab =
true;
8864 DockContextQueueUndockWindow(&
g, docked_window);
8865 g.MovingWindow = docked_window;
8866 SetActiveID(
g.MovingWindow->MoveId,
g.MovingWindow);
8867 g.ActiveIdClickOffset -=
g.MovingWindow->Pos - bb.Min;
8868 g.ActiveIdNoClearOnFocusLoss =
true;
8869 SetActiveIdUsingAllKeyboardKeys();
8875 if (hovered &&
g.HoveredIdNotActiveTimer > TOOLTIP_DELAY && bb.GetWidth() < tab->ContentWidth)
8878 bb.Max.x = bb.Min.x + IM_TRUNC(ImLerp(bb.GetWidth(), tab->ContentWidth, ImSaturate((
g.HoveredIdNotActiveTimer - 0.40f) * 6.0f)));
8879 display_draw_list = GetForegroundDrawList(window);
8880 TabItemBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive));
8885 ImDrawList* display_draw_list = window->DrawList;
8886 const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused));
8887 TabItemBackground(display_draw_list, bb, flags, tab_col);
8888 RenderNavHighlight(bb,
id);
8891 const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
8892 if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)
8893 TabBarQueueFocus(tab_bar, tab);
8895 if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
8896 flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
8899 const ImGuiID close_button_id = p_open ? GetIDWithSeed(
"#CLOSE", NULL, docked_window ? docked_window->ID :
id) : 0;
8902 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);
8903 if (just_closed && p_open != NULL)
8906 TabBarCloseTab(tab_bar, tab);
8911 if (docked_window && (hovered ||
g.HoveredId == close_button_id))
8912 g.LastItemData.StatusFlags |= ImGuiItemStatusFlags_HoveredWindow;
8917 window->DC.CursorPos = backup_main_cursor_pos;
8924 if (text_clipped &&
g.HoveredId ==
id && !held)
8925 if (!(tab_bar->Flags & ImGuiTabBarFlags_NoTooltip) && !(tab->Flags & ImGuiTabItemFlags_NoTooltip))
8926 SetItemTooltip(
"%.*s", (
int)(FindRenderedTextEnd(label) - label), label);
8928 IM_ASSERT(!is_tab_button || !(tab_bar->SelectedTabId == tab->ID && is_tab_button));
8931 return tab_contents_visible;
8937void ImGui::SetTabItemClosed(
const char* label)
8940 bool is_within_manual_tab_bar =
g.CurrentTabBar && !(
g.CurrentTabBar->Flags & ImGuiTabBarFlags_DockNode);
8941 if (is_within_manual_tab_bar)
8943 ImGuiTabBar* tab_bar =
g.CurrentTabBar;
8944 ImGuiID tab_id = TabBarCalcTabID(tab_bar, label, NULL);
8945 if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
8946 tab->WantClose =
true;
8948 else if (ImGuiWindow* window = FindWindowByName(label))
8950 if (window->DockIsActive)
8951 if (ImGuiDockNode* node = window->DockNode)
8953 ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label, window);
8954 TabBarRemoveTab(node->TabBar, tab_id);
8955 window->DockTabWantClose =
true;
8960ImVec2 ImGui::TabItemCalcSize(
const char* label,
bool has_close_button_or_unsaved_marker)
8964 ImVec2
size = ImVec2(label_size.x +
g.Style.FramePadding.x, label_size.y +
g.Style.FramePadding.y * 2.0f);
8965 if (has_close_button_or_unsaved_marker)
8966 size.x +=
g.Style.FramePadding.x + (
g.Style.ItemInnerSpacing.x +
g.FontSize);
8968 size.x +=
g.Style.FramePadding.x + 1.0f;
8969 return ImVec2(ImMin(
size.x, TabBarCalcMaxTabWidth()),
size.y);
8972ImVec2 ImGui::TabItemCalcSize(ImGuiWindow* window)
8974 return TabItemCalcSize(window->Name, window->HasCloseButton || (window->Flags & ImGuiWindowFlags_UnsavedDocument));
8977void ImGui::TabItemBackground(ImDrawList* draw_list,
const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)
8981 const float width = bb.GetWidth();
8983 IM_ASSERT(width > 0.0f);
8984 const float rounding = ImMax(0.0f, ImMin((flags & ImGuiTabItemFlags_Button) ?
g.Style.FrameRounding :
g.Style.TabRounding, width * 0.5f - 1.0f));
8985 const float y1 = bb.Min.y + 1.0f;
8986 const float y2 = bb.Max.y -
g.Style.TabBarBorderSize;
8987 draw_list->PathLineTo(ImVec2(bb.Min.x, y2));
8988 draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9);
8989 draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);
8990 draw_list->PathLineTo(ImVec2(bb.Max.x, y2));
8991 draw_list->PathFillConvex(col);
8992 if (
g.Style.TabBorderSize > 0.0f)
8994 draw_list->PathLineTo(ImVec2(bb.Min.x + 0.5f, y2));
8995 draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding + 0.5f, y1 + rounding + 0.5f), rounding, 6, 9);
8996 draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding - 0.5f, y1 + rounding + 0.5f), rounding, 9, 12);
8997 draw_list->PathLineTo(ImVec2(bb.Max.x - 0.5f, y2));
8998 draw_list->PathStroke(GetColorU32(ImGuiCol_Border), 0,
g.Style.TabBorderSize);
9004void ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list,
const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding,
const char* label, ImGuiID tab_id, ImGuiID close_button_id,
bool is_contents_visible,
bool* out_just_closed,
bool* out_text_clipped)
9009 if (out_just_closed)
9010 *out_just_closed =
false;
9011 if (out_text_clipped)
9012 *out_text_clipped =
false;
9014 if (bb.GetWidth() <= 1.0f)
9020 const float backup_alpha =
g.Style.Alpha;
9021 if (!is_contents_visible)
9022 g.Style.Alpha *= 0.7f;
9026 ImRect text_pixel_clip_bb(bb.Min.x + frame_padding.x, bb.Min.y + frame_padding.y, bb.Max.x - frame_padding.x, bb.Max.y);
9027 ImRect text_ellipsis_clip_bb = text_pixel_clip_bb;
9030 if (out_text_clipped)
9032 *out_text_clipped = (text_ellipsis_clip_bb.Min.x + label_size.x) > text_pixel_clip_bb.Max.x;
9036 const float button_sz =
g.FontSize;
9037 const ImVec2 button_pos(ImMax(bb.Min.x, bb.Max.x - frame_padding.x - button_sz), bb.Min.y + frame_padding.y);
9044 bool close_button_pressed =
false;
9045 bool close_button_visible =
false;
9046 if (close_button_id != 0)
9047 if (is_contents_visible || bb.GetWidth() >= ImMax(button_sz,
g.Style.TabMinWidthForCloseButton))
9048 if (
g.HoveredId == tab_id ||
g.HoveredId == close_button_id ||
g.ActiveId == tab_id ||
g.ActiveId == close_button_id)
9049 close_button_visible =
true;
9050 bool unsaved_marker_visible = (flags & ImGuiTabItemFlags_UnsavedDocument) != 0 && (button_pos.x + button_sz <= bb.Max.x);
9052 if (close_button_visible)
9054 ImGuiLastItemData last_item_backup =
g.LastItemData;
9055 if (CloseButton(close_button_id, button_pos))
9056 close_button_pressed =
true;
9057 g.LastItemData = last_item_backup;
9060 if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
9061 close_button_pressed =
true;
9063 else if (unsaved_marker_visible)
9065 const ImRect bullet_bb(button_pos, button_pos + ImVec2(button_sz, button_sz));
9066 RenderBullet(draw_list, bullet_bb.GetCenter(), GetColorU32(ImGuiCol_Text));
9072 float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f;
9073 if (close_button_visible || unsaved_marker_visible)
9075 text_pixel_clip_bb.Max.x -= close_button_visible ? (button_sz) : (button_sz * 0.80f);
9076 text_ellipsis_clip_bb.Max.x -= unsaved_marker_visible ? (button_sz * 0.80f) : 0.0f;
9077 ellipsis_max_x = text_pixel_clip_bb.Max.x;
9079 RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size);
9082 if (!is_contents_visible)
9083 g.Style.Alpha = backup_alpha;
9086 if (out_just_closed)
9087 *out_just_closed = close_button_pressed;
const ImWchar * ImStrbolW(const ImWchar *buf_mid_line, const ImWchar *buf_begin)
void ImTriangleBarycentricCoords(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p, float &out_u, float &out_v, float &out_w)
int ImTextStrToUtf8(char *out_buf, int out_buf_size, const ImWchar *in_text, const ImWchar *in_text_end)
int ImFormatString(char *buf, size_t buf_size, const char *fmt,...)
void ImStrTrimBlanks(char *buf)
void ImFormatStringToTempBufferV(const char **out_buf, const char **out_buf_end, const char *fmt, va_list args)
const char * ImTextCharToUtf8(char out_buf[5], unsigned int c)
bool ImTriangleContainsPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
int ImTextCountUtf8BytesFromStr(const ImWchar *in_text, const ImWchar *in_text_end)
ImGuiID ImHashStr(const char *data_p, size_t data_size, ImGuiID seed)
const char * ImTextFindPreviousUtf8Codepoint(const char *in_text_start, const char *in_text_curr)
IM_MSVC_RUNTIME_CHECKS_OFF int ImTextCharFromUtf8(unsigned int *out_char, const char *in_text, const char *in_text_end)
int ImTextCountCharsFromUtf8(const char *in_text, const char *in_text_end)
int ImTextCountUtf8BytesFromChar(const char *in_text, const char *in_text_end)
int ImTextStrFromUtf8(ImWchar *buf, int buf_size, const char *in_text, const char *in_text_end, const char **in_text_remaining)
void ImStrncpy(char *dst, const char *src, size_t count)
ImVec2 ImTriangleClosestPoint(const ImVec2 &a, const ImVec2 &b, const ImVec2 &c, const ImVec2 &p)
auto CalcTextSize(std::string_view str)
void TextUnformatted(const std::string &str)
ALWAYS_INLINE unsigned count(const uint8_t *pIn, const uint8_t *pMatch, const uint8_t *pInLimit)
constexpr mat4 scale(const vec3 &xyz)
void Combo(const char *label, const char *preview_value, ImGuiComboFlags flags, std::invocable<> auto next)
void ListBox(const char *label, const ImVec2 &size, std::invocable<> auto next)
void Indent(float indent_w, std::invocable<> auto next)
void format(SectorAccessibleDisk &disk, MSXBootSectorType bootType)
Format the given disk (= a single partition).
bool Checkbox(const HotKey &hotKey, BooleanSetting &setting)
bool SliderFloat(FloatSetting &setting, const char *format, ImGuiSliderFlags flags)
bool InputText(Setting &setting)
size_t size(std::string_view utf8)
ImGuiPlotArrayGetterData(const float *values, int stride)