Updated ImGui.

This commit is contained in:
Бранимир Караџић 2023-02-02 19:00:28 -08:00
parent 94ce7aa6a9
commit a7ef647e98
7 changed files with 288 additions and 212 deletions

View File

@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases
// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!)
// - Gallery https://github.com/ocornut/imgui/issues/5886 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues
@ -1469,7 +1469,7 @@ void ImGuiIO::AddMouseButtonEvent(int mouse_button, bool down)
g.InputEventsQueue.push_back(e);
}
// Queue a mouse wheel event (most mouse/API will only have a Y component)
// Queue a mouse wheel event (some mouse/API may only have a Y component)
void ImGuiIO::AddMouseWheelEvent(float wheel_x, float wheel_y)
{
ImGuiContext& g = *GImGui;
@ -1807,18 +1807,36 @@ void ImFormatStringToTempBuffer(const char** out_buf, const char** out_buf_end,
ImGuiContext& g = *GImGui;
va_list args;
va_start(args, fmt);
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
{
const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
*out_buf = buf;
if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
}
else
{
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
}
va_end(args);
}
void ImFormatStringToTempBufferV(const char** out_buf, const char** out_buf_end, const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
{
const char* buf = va_arg(args, const char*); // Skip formatting when using "%s"
*out_buf = buf;
if (out_buf_end) { *out_buf_end = buf + strlen(buf); }
}
else
{
int buf_len = ImFormatStringV(g.TempBuffer.Data, g.TempBuffer.Size, fmt, args);
*out_buf = g.TempBuffer.Data;
if (out_buf_end) { *out_buf_end = g.TempBuffer.Data + buf_len; }
}
}
// CRC32 needs a 1KB lookup table (not cache friendly)
@ -1905,7 +1923,7 @@ ImFileHandle ImFileOpen(const char* filename, const char* mode)
// Previously we used ImTextCountCharsFromUtf8/ImTextStrFromUtf8 here but we now need to support ImWchar16 and ImWchar32!
const int filename_wsize = ::MultiByteToWideChar(CP_UTF8, 0, filename, -1, NULL, 0);
const int mode_wsize = ::MultiByteToWideChar(CP_UTF8, 0, mode, -1, NULL, 0);
ImVector<ImWchar> buf;
ImVector<wchar_t> buf;
buf.resize(filename_wsize + mode_wsize);
::MultiByteToWideChar(CP_UTF8, 0, filename, -1, (wchar_t*)&buf[0], filename_wsize);
::MultiByteToWideChar(CP_UTF8, 0, mode, -1, (wchar_t*)&buf[filename_wsize], mode_wsize);
@ -5812,12 +5830,15 @@ void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar
{
for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
{
const ImU32 col = resize_grip_col[resize_grip_n];
if ((col & IM_COL32_A_MASK) == 0)
continue;
const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
window->DrawList->PathFillConvex(col);
}
}
@ -8469,7 +8490,8 @@ void ImGui::UpdateMouseWheel()
// Mouse wheel scrolling
// As a standard behavior holding SHIFT while using Vertical Mouse Wheel triggers Horizontal scroll instead
// (we avoid doing it on OSX as it the OS input layer handles this already)
// - We avoid doing it on OSX as it the OS input layer handles this already.
// - However this means when running on OSX over Emcripten, Shift+WheelY will incur two swappings (1 in OS, 1 here), cancelling the feature.
const bool swap_axis = g.IO.KeyShift && !g.IO.ConfigMacOSXBehaviors;
if (swap_axis)
{
@ -8851,6 +8873,13 @@ static void ImGui::ErrorCheckNewFrameSanityChecks()
// #define IM_ASSERT(EXPR) do { if (SomeCode(EXPR)) SomeMoreCode(); } while (0) // Correct!
if (true) IM_ASSERT(1); else IM_ASSERT(0);
// Emscripten backends are often imprecise in their submission of DeltaTime. (#6114, #3644)
// Ideally the Emscripten app/backend should aim to fix or smooth this value and avoid feeding zero, but we tolerate it.
#ifdef __EMSCRIPTEN__
if (g.IO.DeltaTime <= 0.0f && g.FrameCount > 0)
g.IO.DeltaTime = 0.00001f;
#endif
// Check user data
// (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
IM_ASSERT(g.Initialized);
@ -13142,10 +13171,13 @@ void ImGui::ShowFontAtlas(ImFontAtlas* atlas)
DebugNodeFont(font);
PopID();
}
if (TreeNode("Atlas texture", "Atlas texture (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
if (TreeNode("Font Atlas", "Font Atlas (%dx%d pixels)", atlas->TexWidth, atlas->TexHeight))
{
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f);
ImGuiContext& g = *GImGui;
ImGuiMetricsConfig* cfg = &g.DebugMetricsConfig;
Checkbox("Tint with Text Color", &cfg->ShowAtlasTintedWithTextColor); // Using text color ensure visibility of core atlas data, but will alter custom colored icons
ImVec4 tint_col = cfg->ShowAtlasTintedWithTextColor ? GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
ImVec4 border_col = GetStyleColorVec4(ImGuiCol_Border);
Image(atlas->TexID, ImVec2((float)atlas->TexWidth, (float)atlas->TexHeight), ImVec2(0.0f, 0.0f), ImVec2(1.0f, 1.0f), tint_col, border_col);
TreePop();
}
@ -13937,7 +13969,7 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
p += ImFormatString(p, buf_end - p, "%s'%s'",
tab_n > 0 ? ", " : "", (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???");
tab_n > 0 ? ", " : "", (tab->NameOffset != -1) ? TabBarGetTabName(tab_bar, tab) : "???");
}
p += ImFormatString(p, buf_end - p, (tab_bar->Tabs.Size > 3) ? " ... }" : " } ");
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
@ -13954,12 +13986,12 @@ void ImGui::DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label)
{
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
const ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
PushID(tab);
if (SmallButton("<")) { TabBarQueueReorder(tab_bar, tab, -1); } SameLine(0, 2);
if (SmallButton(">")) { TabBarQueueReorder(tab_bar, tab, +1); } SameLine();
Text("%02d%c Tab 0x%08X '%s' Offset: %.2f, Width: %.2f/%.2f",
tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? tab_bar->GetTabName(tab) : "???", tab->Offset, tab->Width, tab->ContentWidth);
tab_n, (tab->ID == tab_bar->SelectedTabId) ? '*' : ' ', tab->ID, (tab->NameOffset != -1) ? TabBarGetTabName(tab_bar, tab) : "???", tab->Offset, tab->Width, tab->ContentWidth);
PopID();
}
TreePop();

View File

@ -11,7 +11,7 @@
// - FAQ http://dearimgui.org/faq
// - Homepage & latest https://github.com/ocornut/imgui
// - Releases & changelog https://github.com/ocornut/imgui/releases
// - Gallery https://github.com/ocornut/imgui/issues/5243 (please post your screenshots/video there!)
// - Gallery https://github.com/ocornut/imgui/issues/5886 (please post your screenshots/video there!)
// - Wiki https://github.com/ocornut/imgui/wiki (lots of good stuff there)
// - Glossary https://github.com/ocornut/imgui/wiki/Glossary
// - Issues & support https://github.com/ocornut/imgui/issues
@ -23,7 +23,7 @@
// Library Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM > 12345')
#define IMGUI_VERSION "1.89.3 WIP"
#define IMGUI_VERSION_NUM 18921
#define IMGUI_VERSION_NUM 18926
#define IMGUI_HAS_TABLE
/*
@ -1968,7 +1968,7 @@ struct ImGuiIO
IMGUI_API void AddKeyAnalogEvent(ImGuiKey key, bool down, float v); // Queue a new key down/up event for analog values (e.g. ImGuiKey_Gamepad_ values). Dead-zones should be handled by the backend.
IMGUI_API void AddMousePosEvent(float x, float y); // Queue a mouse position update. Use -FLT_MAX,-FLT_MAX to signify no mouse (e.g. app not focused and not hovered)
IMGUI_API void AddMouseButtonEvent(int button, bool down); // Queue a mouse button change
IMGUI_API void AddMouseWheelEvent(float wh_x, float wh_y); // Queue a mouse wheel update
IMGUI_API void AddMouseWheelEvent(float wheel_x, float wheel_y); // Queue a mouse wheel update. wheel_y<0: scroll down, wheel_y>0: scroll up, wheel_x<0: scroll right, wheel_x>0: scroll left.
IMGUI_API void AddFocusEvent(bool focused); // Queue a gain/loss of focus for the application (generally based on OS/platform focus of your window)
IMGUI_API void AddInputCharacter(unsigned int c); // Queue a new character input
IMGUI_API void AddInputCharacterUTF16(ImWchar16 c); // Queue a new character input from a UTF-16 character, it can be a surrogate
@ -2018,8 +2018,8 @@ struct ImGuiIO
// (reading from those variables is fair game, as they are extremely unlikely to be moving anywhere)
ImVec2 MousePos; // Mouse position, in pixels. Set to ImVec2(-FLT_MAX, -FLT_MAX) if mouse is unavailable (on another screen, etc.)
bool MouseDown[5]; // Mouse buttons: 0=left, 1=right, 2=middle + extras (ImGuiMouseButton_COUNT == 5). Dear ImGui mostly uses left and right buttons. Other buttons allow us to track if the mouse is being used by your application + available to user as a convenience via IsMouse** API.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text.
float MouseWheelH; // Mouse wheel Horizontal. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
float MouseWheel; // Mouse wheel Vertical: 1 unit scrolls about 5 lines text. >0 scrolls Up, <0 scrolls Down. Hold SHIFT to turn vertical scroll into horizontal scroll.
float MouseWheelH; // Mouse wheel Horizontal. >0 scrolls Left, <0 scrolls Right. Most users don't have a mouse with a horizontal wheel, may not be filled by all backends.
bool KeyCtrl; // Keyboard modifier down: Control
bool KeyShift; // Keyboard modifier down: Shift
bool KeyAlt; // Keyboard modifier down: Alt

View File

@ -457,6 +457,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Checkbox("io.ConfigWindowsResizeFromEdges", &io.ConfigWindowsResizeFromEdges);
ImGui::SameLine(); HelpMarker("Enable resizing of windows from their edges and from the lower-left corner.\nThis requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback.");
ImGui::Checkbox("io.ConfigWindowsMoveFromTitleBarOnly", &io.ConfigWindowsMoveFromTitleBarOnly);
ImGui::Checkbox("io.ConfigMacOSXBehaviors", &io.ConfigMacOSXBehaviors);
ImGui::Checkbox("io.MouseDrawCursor", &io.MouseDrawCursor);
ImGui::SameLine(); HelpMarker("Instruct Dear ImGui to render a mouse cursor itself. Note that a mouse cursor rendered via your application GPU rendering path will feel more laggy than hardware cursor, but will be more in sync with your other visuals.\n\nSome desktop applications may use both kinds of cursors (e.g. enable software cursor only when resizing/dragging something).");
ImGui::Text("Also see Style->Rendering for rendering options.");
@ -610,20 +611,41 @@ static void ShowDemoWindowWidgets()
ImGui::SameLine();
ImGui::Text("%d", counter);
ImGui::Separator();
ImGui::LabelText("label", "Value");
{
// Using the _simplified_ one-liner Combo() api here
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
static int item_current = 0;
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
// Tooltips
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
//ImGui::AlignTextToFramePadding();
ImGui::Text("Tooltips:");
ImGui::SameLine();
ImGui::SmallButton("Button");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::SmallButton("Fancy");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::EndTooltip();
}
ImGui::SameLine();
ImGui::SmallButton("Delayed");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // With a delay
ImGui::SetTooltip("I am a tooltip with a delay.");
ImGui::SameLine();
HelpMarker(
"Tooltip are created by using the IsItemHovered() function over any kind of item.");
}
ImGui::LabelText("label", "Value");
{
// To wire InputText() with std::string or any other custom string type,
// see the "Text Input > Resize Callback" section of this demo, and the misc/cpp/imgui_stdlib.h file.
@ -722,6 +744,17 @@ static void ShowDemoWindowWidgets()
ImGui::ColorEdit4("color 2", col2);
}
{
// Using the _simplified_ one-liner Combo() api here
// See "Combo" section for examples of how to use the more flexible BeginCombo()/EndCombo() api.
IMGUI_DEMO_MARKER("Widgets/Basic/Combo");
const char* items[] = { "AAAA", "BBBB", "CCCC", "DDDD", "EEEE", "FFFF", "GGGG", "HHHH", "IIIIIII", "JJJJ", "KKKKKKK" };
static int item_current = 0;
ImGui::Combo("combo", &item_current, items, IM_ARRAYSIZE(items));
ImGui::SameLine(); HelpMarker(
"Using the simplified one-liner Combo API here.\nRefer to the \"Combo\" section below for an explanation of how to use the more flexible and general BeginCombo/EndCombo API.");
}
{
// Using the _simplified_ one-liner ListBox() api here
// See "List boxes" section for examples of how to use the more flexible BeginListBox()/EndListBox() api.
@ -733,40 +766,6 @@ static void ShowDemoWindowWidgets()
"Using the simplified one-liner ListBox API here.\nRefer to the \"List boxes\" section below for an explanation of how to use the more flexible and general BeginListBox/EndListBox API.");
}
{
// Tooltips
IMGUI_DEMO_MARKER("Widgets/Basic/Tooltips");
ImGui::AlignTextToFramePadding();
ImGui::Text("Tooltips:");
ImGui::SameLine();
ImGui::Button("Button");
if (ImGui::IsItemHovered())
ImGui::SetTooltip("I am a tooltip");
ImGui::SameLine();
ImGui::Button("Fancy");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::Text("I am a fancy tooltip");
static float arr[] = { 0.6f, 0.1f, 1.0f, 0.5f, 0.92f, 0.1f, 0.2f };
ImGui::PlotLines("Curve", arr, IM_ARRAYSIZE(arr));
ImGui::Text("Sin(time) = %f", sinf((float)ImGui::GetTime()));
ImGui::EndTooltip();
}
ImGui::SameLine();
ImGui::Button("Delayed");
if (ImGui::IsItemHovered(ImGuiHoveredFlags_DelayNormal)) // Delay best used on items that highlight on hover, so this not a great example!
ImGui::SetTooltip("I am a tooltip with a delay.");
ImGui::SameLine();
HelpMarker(
"Tooltip are created by using the IsItemHovered() function over any kind of item.");
}
ImGui::TreePop();
}
@ -1026,12 +1025,14 @@ static void ShowDemoWindowWidgets()
float my_tex_w = (float)io.Fonts->TexWidth;
float my_tex_h = (float)io.Fonts->TexHeight;
{
static bool use_text_color_for_tint = false;
ImGui::Checkbox("Use Text Color for Tint", &use_text_color_for_tint);
ImGui::Text("%.0fx%.0f", my_tex_w, my_tex_h);
ImVec2 pos = ImGui::GetCursorScreenPos();
ImVec2 uv_min = ImVec2(0.0f, 0.0f); // Top-left
ImVec2 uv_max = ImVec2(1.0f, 1.0f); // Lower-right
ImVec4 tint_col = ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
ImVec4 border_col = ImVec4(1.0f, 1.0f, 1.0f, 0.5f); // 50% opaque white
ImVec4 tint_col = use_text_color_for_tint ? ImGui::GetStyleColorVec4(ImGuiCol_Text) : ImVec4(1.0f, 1.0f, 1.0f, 1.0f); // No tint
ImVec4 border_col = ImGui::GetStyleColorVec4(ImGuiCol_Border);
ImGui::Image(my_tex_id, ImVec2(my_tex_w, my_tex_h), uv_min, uv_max, tint_col, border_col);
if (ImGui::IsItemHovered())
{
@ -5993,6 +5994,9 @@ void ImGui::ShowAboutWindow(bool* p_open)
#endif
#ifdef __clang_version__
ImGui::Text("define: __clang_version__=%s", __clang_version__);
#endif
#ifdef __EMSCRIPTEN__
ImGui::Text("define: __EMSCRIPTEN__");
#endif
ImGui::Separator();
ImGui::Text("io.BackendPlatformName: %s", io.BackendPlatformName ? io.BackendPlatformName : "NULL");
@ -6165,7 +6169,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("ScrollbarRounding", &style.ScrollbarRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
@ -6180,6 +6183,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::Text("Safe Area Padding");
ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
ImGui::SliderFloat2("DisplaySafeAreaPadding", (float*)&style.DisplaySafeAreaPadding, 0.0f, 30.0f, "%.0f");
ImGui::SliderFloat("LogSliderDeadzone", &style.LogSliderDeadzone, 0.0f, 12.0f, "%.0f");
ImGui::EndTabItem();
}

View File

@ -706,7 +706,7 @@ void ImDrawList::PrimQuadUV(const ImVec2& a, const ImVec2& b, const ImVec2& c, c
// We avoid using the ImVec2 math operators here to reduce cost to a minimum for debug/non-inlined builds.
void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32 col, ImDrawFlags flags, float thickness)
{
if (points_count < 2)
if (points_count < 2 || (col & IM_COL32_A_MASK) == 0)
return;
const bool closed = (flags & ImDrawFlags_Closed) != 0;
@ -964,7 +964,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
// - Filled shapes must always use clockwise winding order. The anti-aliasing fringe depends on it. Counter-clockwise shapes will have "inward" anti-aliasing.
void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_count, ImU32 col)
{
if (points_count < 3)
if (points_count < 3 || (col & IM_COL32_A_MASK) == 0)
return;
const ImVec2 uv = _Data->TexUvWhitePixel;
@ -3573,18 +3573,17 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
while (y + line_height < clip_rect.y && s < text_end)
{
const char* line_end = (const char*)memchr(s, '\n', text_end - s);
const char* line_next = line_end ? line_end + 1 : text_end;
if (word_wrap_enabled)
{
// FIXME-OPT: This is not optimal as do first do a search for \n before calling CalcWordWrapPositionA().
// If the specs for CalcWordWrapPositionA() were reworked to optionally return on \n we could combine both.
// However it is still better than nothing performing the fast-forward!
s = CalcWordWrapPositionA(scale, s, line_next, wrap_width);
s = CalcWordWrapPositionA(scale, s, line_end ? line_end : text_end, wrap_width);
s = CalcWordWrapNextLineStartA(s, text_end);
}
else
{
s = line_next;
s = line_end ? line_end + 1 : text_end;
}
y += line_height;
}
@ -3611,10 +3610,9 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
const int idx_count_max = (int)(text_end - s) * 6;
const int idx_expected_size = draw_list->IdxBuffer.Size + idx_count_max;
draw_list->PrimReserve(idx_count_max, vtx_count_max);
ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
unsigned int vtx_current_idx = draw_list->_VtxCurrentIdx;
ImDrawVert* vtx_write = draw_list->_VtxWritePtr;
ImDrawIdx* idx_write = draw_list->_IdxWritePtr;
unsigned int vtx_index = draw_list->_VtxCurrentIdx;
const ImU32 col_untinted = col | ~IM_COL32_A_MASK;
const char* word_wrap_eol = NULL;
@ -3713,14 +3711,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
// We are NOT calling PrimRectUV() here because non-inlined causes too much overhead in a debug builds. Inlined here:
{
idx_write[0] = (ImDrawIdx)(vtx_current_idx); idx_write[1] = (ImDrawIdx)(vtx_current_idx+1); idx_write[2] = (ImDrawIdx)(vtx_current_idx+2);
idx_write[3] = (ImDrawIdx)(vtx_current_idx); idx_write[4] = (ImDrawIdx)(vtx_current_idx+2); idx_write[5] = (ImDrawIdx)(vtx_current_idx+3);
vtx_write[0].pos.x = x1; vtx_write[0].pos.y = y1; vtx_write[0].col = glyph_col; vtx_write[0].uv.x = u1; vtx_write[0].uv.y = v1;
vtx_write[1].pos.x = x2; vtx_write[1].pos.y = y1; vtx_write[1].col = glyph_col; vtx_write[1].uv.x = u2; vtx_write[1].uv.y = v1;
vtx_write[2].pos.x = x2; vtx_write[2].pos.y = y2; vtx_write[2].col = glyph_col; vtx_write[2].uv.x = u2; vtx_write[2].uv.y = v2;
vtx_write[3].pos.x = x1; vtx_write[3].pos.y = y2; vtx_write[3].col = glyph_col; vtx_write[3].uv.x = u1; vtx_write[3].uv.y = v2;
idx_write[0] = (ImDrawIdx)(vtx_index); idx_write[1] = (ImDrawIdx)(vtx_index + 1); idx_write[2] = (ImDrawIdx)(vtx_index + 2);
idx_write[3] = (ImDrawIdx)(vtx_index); idx_write[4] = (ImDrawIdx)(vtx_index + 2); idx_write[5] = (ImDrawIdx)(vtx_index + 3);
vtx_write += 4;
vtx_current_idx += 4;
vtx_index += 4;
idx_write += 6;
}
}
@ -3734,7 +3732,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, const ImVec2& pos, Im
draw_list->CmdBuffer[draw_list->CmdBuffer.Size - 1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
draw_list->_VtxWritePtr = vtx_write;
draw_list->_IdxWritePtr = idx_write;
draw_list->_VtxCurrentIdx = vtx_current_idx;
draw_list->_VtxCurrentIdx = vtx_index;
}
//-----------------------------------------------------------------------------

View File

@ -1,10 +1,12 @@
// dear imgui, v1.89.3 WIP
// (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
// Set:
// #define IMGUI_DEFINE_MATH_OPERATORS
// To implement maths operators for ImVec2 (disabled by default to not collide with using IM_VEC2_CLASS_EXTRA along with your own math types+operators)
// You may use this file to debug, understand or extend Dear ImGui features but we don't provide any guarantee of forward compatibility.
// To implement maths operators for ImVec2 (disabled by default to not conflict with using IM_VEC2_CLASS_EXTRA with your own math types+operators), use:
/*
#define IMGUI_DEFINE_MATH_OPERATORS
#include "imgui_internal.h"
*/
/*
@ -548,9 +550,12 @@ struct IMGUI_API ImRect
bool IsInverted() const { return Min.x > Max.x || Min.y > Max.y; }
ImVec4 ToVec4() const { return ImVec4(Min.x, Min.y, Max.x, Max.y); }
};
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helper: ImBitArray
#define IM_BITARRAY_TESTBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] & ((ImU32)1 << ((_N) & 31))) != 0) // Macro version of ImBitArrayTestBit(): ensure args have side-effect or are costly!
#define IM_BITARRAY_CLEARBIT(_ARRAY, _N) ((_ARRAY[(_N) >> 5] &= ~((ImU32)1 << ((_N) & 31)))) // Macro version of ImBitArrayClearBit(): ensure args have side-effect or are costly!
inline size_t ImBitArrayGetStorageSizeInBytes(int bitcount) { return (size_t)((bitcount + 31) >> 5) << 2; }
inline void ImBitArrayClearAllBits(ImU32* arr, int bitcount){ memset(arr, 0, ImBitArrayGetStorageSizeInBytes(bitcount)); }
inline bool ImBitArrayTestBit(const ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); return (arr[n >> 5] & mask) != 0; }
inline void ImBitArrayClearBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] &= ~mask; }
inline void ImBitArraySetBit(ImU32* arr, int n) { ImU32 mask = (ImU32)1 << (n & 31); arr[n >> 5] |= mask; }
@ -567,6 +572,8 @@ inline void ImBitArraySetBitRange(ImU32* arr, int n, int n2) // Works on ran
}
}
typedef ImU32* ImBitArrayPtr; // Name for use in structs
// Helper: ImBitArray class (wrapper over ImBitArray functions)
// Store 1-bit per value.
template<int BITCOUNT, int OFFSET = 0>
@ -576,11 +583,11 @@ struct ImBitArray
ImBitArray() { ClearAllBits(); }
void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); }
void SetAllBits() { memset(Storage, 255, sizeof(Storage)); }
bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }
void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); }
void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); }
void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2)
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); }
bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return IM_BITARRAY_TESTBIT(Storage, n); }
};
// Helper: ImBitVector
@ -590,10 +597,11 @@ struct IMGUI_API ImBitVector
ImVector<ImU32> Storage;
void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); }
void Clear() { Storage.clear(); }
bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); }
bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return IM_BITARRAY_TESTBIT(Storage.Data, n); }
void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); }
void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); }
};
IM_MSVC_RUNTIME_CHECKS_RESTORE
// Helper: ImSpan<>
// Pointing to a span of data we don't own.
@ -1663,23 +1671,16 @@ enum ImGuiDebugLogFlags_
struct ImGuiMetricsConfig
{
bool ShowDebugLog;
bool ShowStackTool;
bool ShowWindowsRects;
bool ShowWindowsBeginOrder;
bool ShowTablesRects;
bool ShowDrawCmdMesh;
bool ShowDrawCmdBoundingBoxes;
int ShowWindowsRectsType;
int ShowTablesRectsType;
ImGuiMetricsConfig()
{
ShowDebugLog = ShowStackTool = ShowWindowsRects = ShowWindowsBeginOrder = ShowTablesRects = false;
ShowDrawCmdMesh = true;
ShowDrawCmdBoundingBoxes = true;
ShowWindowsRectsType = ShowTablesRectsType = -1;
}
bool ShowDebugLog = false;
bool ShowStackTool = false;
bool ShowWindowsRects = false;
bool ShowWindowsBeginOrder = false;
bool ShowTablesRects = false;
bool ShowDrawCmdMesh = true;
bool ShowDrawCmdBoundingBoxes = true;
bool ShowAtlasTintedWithTextColor = false;
int ShowWindowsRectsType = -1;
int ShowTablesRectsType = -1;
};
struct ImGuiStackLevelInfo
@ -2384,7 +2385,7 @@ struct ImGuiTabItem
float RequestedWidth; // Width optionally requested by caller, -1.0f is unused
ImS32 NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames
ImS16 BeginOrder; // BeginTabItem() order, used to re-order tabs after toggling ImGuiTabBarFlags_Reorderable
ImS16 IndexDuringLayout; // Index only used during TabBarLayout()
ImS16 IndexDuringLayout; // Index only used during TabBarLayout(). Tabs gets reordered so 'Tabs[n].IndexDuringLayout == n' but may mismatch during additions.
bool WantClose; // Marked as closed by SetTabItemClosed()
ImGuiTabItem() { memset(this, 0, sizeof(*this)); LastFrameVisible = LastFrameSelected = -1; RequestedWidth = -1.0f; NameOffset = -1; BeginOrder = IndexDuringLayout = -1; }
@ -2426,12 +2427,6 @@ struct IMGUI_API ImGuiTabBar
ImGuiTextBuffer TabsNames; // For non-docking tab bar we re-append names in a contiguous buffer.
ImGuiTabBar();
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); }
const char* GetTabName(const ImGuiTabItem* tab) const
{
IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size);
return TabsNames.Buf.Data + tab->NameOffset;
}
};
//-----------------------------------------------------------------------------
@ -2439,12 +2434,11 @@ struct IMGUI_API ImGuiTabBar
//-----------------------------------------------------------------------------
#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color.
#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64.
#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels()
#define IMGUI_TABLE_MAX_COLUMNS 512 // May be further lifted
// Our current column maximum is 64 but we may raise that in the future.
typedef ImS8 ImGuiTableColumnIdx;
typedef ImU8 ImGuiTableDrawChannelIdx;
typedef ImS16 ImGuiTableColumnIdx;
typedef ImU16 ImGuiTableDrawChannelIdx;
// [Internal] sizeof() ~ 104
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
@ -2535,10 +2529,9 @@ struct IMGUI_API ImGuiTable
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items)
ImBitArrayPtr EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
ImBitArrayPtr EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
ImBitArrayPtr VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect)
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
int SettingsOffset; // Offset in g.SettingsTables
int LastFrameActive;
@ -3034,12 +3027,18 @@ namespace ImGui
IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);
// Tab Bars
inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; }
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API ImGuiTabItem* TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order);
IMGUI_API ImGuiTabItem* TabBarGetCurrentTab(ImGuiTabBar* tab_bar);
inline int TabBarGetTabOrder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab) { return tab_bar->Tabs.index_from_ptr(tab); }
IMGUI_API const char* TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset);
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, ImVec2 mouse_pos);
IMGUI_API void TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
IMGUI_API void TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset);
IMGUI_API void TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, ImVec2 mouse_pos);
IMGUI_API bool TabBarProcessReorder(ImGuiTabBar* tab_bar);
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window);
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button_or_unsaved_marker);
@ -3074,7 +3073,7 @@ namespace ImGui
IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0, 0), ImGuiButtonFlags flags = 0);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags = 0);
IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col);
IMGUI_API bool ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags = 0);
IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value);
IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value);
@ -3130,7 +3129,7 @@ namespace ImGui
IMGUI_API void ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags flags);
// Plot
IMGUI_API int 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, ImVec2 frame_size);
IMGUI_API int 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);
// Shade functions (write over already created vertices)
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);

View File

@ -315,7 +315,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
return false;
// Sanity checks
IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!");
IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS);
if (flags & ImGuiTableFlags_ScrollX)
IM_ASSERT(inner_width >= 0.0f);
@ -581,16 +581,22 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)
{
// Allocate single buffer for our arrays
ImSpanAllocator<3> span_allocator;
const int columns_bit_array_size = (int)ImBitArrayGetStorageSizeInBytes(columns_count);
ImSpanAllocator<6> span_allocator;
span_allocator.Reserve(0, columns_count * sizeof(ImGuiTableColumn));
span_allocator.Reserve(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.Reserve(2, columns_count * sizeof(ImGuiTableCellData), 4);
for (int n = 3; n < 6; n++)
span_allocator.Reserve(n, columns_bit_array_size);
table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());
memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());
span_allocator.SetArenaBasePtr(table->RawData);
span_allocator.GetSpan(0, &table->Columns);
span_allocator.GetSpan(1, &table->DisplayOrderToIndex);
span_allocator.GetSpan(2, &table->RowCellData);
table->EnabledMaskByDisplayOrder = (ImU32*)span_allocator.GetSpanPtrBegin(3);
table->EnabledMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(4);
table->VisibleMaskByIndex = (ImU32*)span_allocator.GetSpanPtrBegin(5);
}
// Apply queued resizing/reordering/hiding requests
@ -729,8 +735,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
table->IsDefaultDisplayOrder = true;
table->ColumnsEnabledCount = 0;
table->EnabledMaskByIndex = 0x00;
table->EnabledMaskByDisplayOrder = 0x00;
ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount);
ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount);
table->LeftMostEnabledColumn = -1;
table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
@ -795,8 +801,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
else
table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n;
column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
table->EnabledMaskByIndex |= (ImU64)1 << column_n;
table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder;
ImBitArraySetBit(table->EnabledMaskByIndex, column_n);
ImBitArraySetBit(table->EnabledMaskByDisplayOrder, column->DisplayOrder);
prev_visible_column_idx = column_n;
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
@ -844,7 +850,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
@ -860,7 +866,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
if (column->AutoFitQueue != 0x00)
column->WidthRequest = width_auto;
else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)))
else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && column->IsRequestOutput)
column->WidthRequest = width_auto;
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
@ -908,7 +914,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
@ -935,7 +941,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
{
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue;
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))
@ -966,8 +972,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
ImRect host_clip_rect = table->InnerClipRect;
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
table->VisibleMaskByIndex = 0x00;
table->RequestOutputMaskByIndex = 0x00;
ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount);
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
const int column_n = table->DisplayOrderToIndex[order_n];
@ -984,7 +989,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Clear status flags
column->Flags &= ~ImGuiTableColumnFlags_StatusMask_;
if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0)
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
{
// Hidden column: clear a few fields and we are done with it for the remainder of the function.
// We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper.
@ -1037,12 +1042,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y);
const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY;
if (is_visible)
table->VisibleMaskByIndex |= ((ImU64)1 << column_n);
ImBitArraySetBit(table->VisibleMaskByIndex, column_n);
// Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output.
column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0;
if (column->IsRequestOutput)
table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n);
// Mark column as SkipItems (ignoring all items/layout)
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
@ -1169,7 +1172,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue;
const int column_n = table->DisplayOrderToIndex[order_n];
@ -1305,7 +1308,7 @@ void ImGui::EndTable()
float auto_fit_width_for_stretched = 0.0f;
float auto_fit_width_for_stretched_min = 0.0f;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
if (IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n))
{
ImGuiTableColumn* column = &table->Columns[column_n];
float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column);
@ -1651,7 +1654,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n
return;
if (column_n == -1)
column_n = table->CurrentColumn;
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))
return;
if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
table->RowCellDataCurrent++;
@ -1926,7 +1929,7 @@ bool ImGui::TableSetColumnIndex(int column_n)
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
return table->Columns[column_n].IsRequestOutput;
}
// [Public] Append into the next column, wrap and create a new row when already on last column
@ -1951,8 +1954,7 @@ bool ImGui::TableNextColumn()
// Return whether the column is visible. User may choose to skip submitting items based on this return value,
// however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
int column_n = table->CurrentColumn;
return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
return table->Columns[table->CurrentColumn].IsRequestOutput;
}
@ -2292,7 +2294,7 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
const int freeze_row_multiplier = (table->FreezeRowsCount > 0) ? 2 : 1;
const int channels_for_row = (table->Flags & ImGuiTableFlags_NoClip) ? 1 : table->ColumnsEnabledCount;
const int channels_for_bg = 1 + 1 * freeze_row_multiplier;
const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || table->VisibleMaskByIndex != table->EnabledMaskByIndex) ? +1 : 0;
const int channels_for_dummy = (table->ColumnsEnabledCount < table->ColumnsCount || (memcmp(table->VisibleMaskByIndex, table->EnabledMaskByIndex, ImBitArrayGetStorageSizeInBytes(table->ColumnsCount)) != 0)) ? +1 : 0;
const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;
table->DrawSplitter->Split(table->InnerWindow->DrawList, channels_total);
table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1);
@ -2366,19 +2368,26 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
// Track which groups we are going to attempt to merge, and which channels goes into each group.
struct MergeGroup
{
ImRect ClipRect;
int ChannelsCount;
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> ChannelsMask;
MergeGroup() { ChannelsCount = 0; }
ImRect ClipRect;
int ChannelsCount;
ImBitArrayPtr ChannelsMask;
};
int merge_group_mask = 0x00;
MergeGroup merge_groups[4];
MergeGroup merge_groups[4] = {};
// Use a reusable temp buffer for the merge masks as they are dynamically sized.
const int max_draw_channels = (4 + table->ColumnsCount * 2);
const int size_for_masks_bitarrays_one = (int)ImBitArrayGetStorageSizeInBytes(max_draw_channels);
g.TempBuffer.reserve(size_for_masks_bitarrays_one * 5);
memset(g.TempBuffer.Data, 0, size_for_masks_bitarrays_one * 5);
for (int n = 0; n < IM_ARRAYSIZE(merge_groups); n++)
merge_groups[n].ChannelsMask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * n));
ImBitArrayPtr remaining_mask = (ImBitArrayPtr)(void*)(g.TempBuffer.Data + (size_for_masks_bitarrays_one * 4));
// 1. Scan channels and take note of those which can be merged
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
if (!IM_BITARRAY_TESTBIT(table->VisibleMaskByIndex, column_n))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
@ -2410,11 +2419,11 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
}
const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2);
IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS);
IM_ASSERT(channel_no < max_draw_channels);
MergeGroup* merge_group = &merge_groups[merge_group_n];
if (merge_group->ChannelsCount == 0)
merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX);
merge_group->ChannelsMask.SetBit(channel_no);
ImBitArraySetBit(merge_group->ChannelsMask, channel_no);
merge_group->ChannelsCount++;
merge_group->ClipRect.Add(src_channel->_CmdBuffer[0].ClipRect);
merge_group_mask |= (1 << merge_group_n);
@ -2450,9 +2459,8 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
const int LEADING_DRAW_CHANNELS = 2;
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask; // We need 132-bit of storage
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count);
remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
ImBitArraySetBitRange(remaining_mask, LEADING_DRAW_CHANNELS, splitter->_Count);
ImBitArrayClearBit(remaining_mask, table->Bg2DrawChannelUnfrozen);
IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS);
//ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect;
@ -2485,14 +2493,14 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200));
#endif
remaining_count -= merge_group->ChannelsCount;
for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++)
remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n];
for (int n = 0; n < (size_for_masks_bitarrays_one >> 2); n++)
remaining_mask[n] &= ~merge_group->ChannelsMask[n];
for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++)
{
// Copy + overwrite new clip rect
if (!merge_group->ChannelsMask.TestBit(n))
if (!IM_BITARRAY_TESTBIT(merge_group->ChannelsMask, n))
continue;
merge_group->ChannelsMask.ClearBit(n);
IM_BITARRAY_CLEARBIT(merge_group->ChannelsMask, n);
merge_channels_count--;
ImDrawChannel* channel = &splitter->_Channels[n];
@ -2510,7 +2518,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
// Append unmergeable channels that we didn't reorder at the end of the list
for (int n = 0; n < splitter->_Count && remaining_count != 0; n++)
{
if (!remaining_mask.TestBit(n))
if (!IM_BITARRAY_TESTBIT(remaining_mask, n))
continue;
ImDrawChannel* channel = &splitter->_Channels[n];
memcpy(dst_tmp++, channel, sizeof(ImDrawChannel));
@ -2542,7 +2550,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
{
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n))
continue;
const int column_n = table->DisplayOrderToIndex[order_n];

View File

@ -274,7 +274,6 @@ void ImGui::TextV(const char* fmt, va_list args)
if (window->SkipItems)
return;
// FIXME-OPT: Handle the %s shortcut?
const char* text, *text_end;
ImFormatStringToTempBufferV(&text, &text_end, fmt, args);
TextEx(text, text_end, ImGuiTextFlags_NoWidthForLargeClippedText);
@ -291,10 +290,7 @@ void ImGui::TextColored(const ImVec4& col, const char* fmt, ...)
void ImGui::TextColoredV(const ImVec4& col, const char* fmt, va_list args)
{
PushStyleColor(ImGuiCol_Text, col);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args);
TextV(fmt, args);
PopStyleColor();
}
@ -310,10 +306,7 @@ void ImGui::TextDisabledV(const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args);
TextV(fmt, args);
PopStyleColor();
}
@ -328,13 +321,10 @@ void ImGui::TextWrapped(const char* fmt, ...)
void ImGui::TextWrappedV(const char* fmt, va_list args)
{
ImGuiContext& g = *GImGui;
bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
const bool need_backup = (g.CurrentWindow->DC.TextWrapPos < 0.0f); // Keep existing wrap position if one is already set
if (need_backup)
PushTextWrapPos(0.0f);
if (fmt[0] == '%' && fmt[1] == 's' && fmt[2] == 0)
TextEx(va_arg(args, const char*), NULL, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
else
TextV(fmt, args);
TextV(fmt, args);
if (need_backup)
PopTextWrapPos();
}
@ -1042,7 +1032,7 @@ void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2&
// ImageButton() is flawed as 'id' is always derived from 'texture_id' (see #2464 #1390)
// We provide this internal helper to write your own variant while we figure out how to redesign the public ImageButton() API.
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col)
bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& bg_col, const ImVec4& tint_col, ImGuiButtonFlags flags)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
@ -1056,7 +1046,7 @@ bool ImGui::ImageButtonEx(ImGuiID id, ImTextureID texture_id, const ImVec2& size
return false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@ -1705,7 +1695,12 @@ bool ImGui::BeginComboPopup(ImGuiID popup_id, const ImRect& bb, ImGuiComboFlags
if (flags & ImGuiComboFlags_HeightRegular) popup_max_height_in_items = 8;
else if (flags & ImGuiComboFlags_HeightSmall) popup_max_height_in_items = 4;
else if (flags & ImGuiComboFlags_HeightLarge) popup_max_height_in_items = 20;
SetNextWindowSizeConstraints(ImVec2(w, 0.0f), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
ImVec2 constraint_min(0.0f, 0.0f), constraint_max(FLT_MAX, FLT_MAX);
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.x <= 0.0f) // Don't apply constraints if user specified a size
constraint_min.x = w;
if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) == 0 || g.NextWindowData.SizeVal.y <= 0.0f)
constraint_max.y = CalcMaxPopupHeightFromItemCount(popup_max_height_in_items);
SetNextWindowSizeConstraints(constraint_min, constraint_max);
}
// This is essentially a specialized version of BeginPopupEx()
@ -4111,6 +4106,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb.insert_mode = 1; // stb field name is indeed incorrect (see #2863)
}
const bool is_osx = io.ConfigMacOSXBehaviors;
if (g.ActiveId != id && init_make_active)
{
IM_ASSERT(state && state->ID == id);
@ -4133,6 +4129,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
SetKeyOwner(ImGuiKey_PageUp, id);
SetKeyOwner(ImGuiKey_PageDown, id);
}
if (is_osx)
SetKeyOwner(ImGuiMod_Alt, id);
if (flags & (ImGuiInputTextFlags_CallbackCompletion | ImGuiInputTextFlags_AllowTabInput)) // Disable keyboard tabbing out as we will use the \t character.
SetKeyOwner(ImGuiKey_Tab, id);
}
@ -4202,7 +4200,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
const float mouse_x = (io.MousePos.x - frame_bb.Min.x - style.FramePadding.x) + state->ScrollX;
const float mouse_y = (is_multiline ? (io.MousePos.y - draw_window->DC.CursorPos.y) : (g.FontSize * 0.5f));
const bool is_osx = io.ConfigMacOSXBehaviors;
if (select_all)
{
state->SelectAll();
@ -4303,7 +4300,6 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
state->Stb.row_count_per_page = row_count_per_page;
const int k_mask = (io.KeyShift ? STB_TEXTEDIT_K_SHIFT : 0);
const bool is_osx = io.ConfigMacOSXBehaviors;
const bool is_wordmove_key_down = is_osx ? io.KeyAlt : io.KeyCtrl; // OS X style: Text editing cursor movement using Alt instead of Ctrl
const bool is_startend_key_down = is_osx && io.KeySuper && !io.KeyCtrl && !io.KeyAlt; // OS X style: Line/Text Start and End using Cmd+Arrows instead of Home/End
@ -4332,7 +4328,16 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
else if (IsKeyPressed(ImGuiKey_PageDown) && is_multiline) { state->OnKeyPressed(STB_TEXTEDIT_K_PGDOWN | k_mask); scroll_y += row_count_per_page * g.FontSize; }
else if (IsKeyPressed(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
else if (IsKeyPressed(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
else if (IsKeyPressed(ImGuiKey_Delete) && !is_readonly && !is_cut)
{
if (!state->HasSelection())
{
// OSX doesn't seem to have Super+Delete to delete until end-of-line, so we don't emulate that (as opposed to Super+Backspace)
if (is_wordmove_key_down)
state->OnKeyPressed(STB_TEXTEDIT_K_WORDRIGHT | STB_TEXTEDIT_K_SHIFT);
}
state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask);
}
else if (IsKeyPressed(ImGuiKey_Backspace) && !is_readonly)
{
if (!state->HasSelection())
@ -6561,7 +6566,7 @@ bool ImGui::ListBox(const char* label, int* current_item, bool (*items_getter)(v
// - others https://github.com/ocornut/imgui/wiki/Useful-Extensions
//-------------------------------------------------------------------------
int 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, ImVec2 frame_size)
int 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)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
@ -6572,10 +6577,7 @@ int ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_get
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (frame_size.x == 0.0f)
frame_size.x = CalcItemWidth();
if (frame_size.y == 0.0f)
frame_size.y = label_size.y + (style.FramePadding.y * 2);
const ImVec2 frame_size = CalcItemSize(size_arg, CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0f);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding);
@ -7040,7 +7042,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x * 2.0f, style.ItemSpacing.y));
float w = label_size.x;
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, 0.0f));
pressed = Selectable("", menu_is_open, selectable_flags, ImVec2(w, label_size.y));
RenderText(text_pos, label);
PopStyleVar();
window->DC.CursorPos.x += IM_FLOOR(style.ItemSpacing.x * (-1.0f + 0.5f)); // -1 spacing to compensate the spacing added when Selectable() did a SameLine(). It would also work to call SameLine() ourselves after the PopStyleVar().
@ -7056,7 +7058,7 @@ bool ImGui::BeginMenuEx(const char* label, const char* icon, bool enabled)
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, 0.0f, checkmark_w); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
ImVec2 text_pos(window->DC.CursorPos.x + offsets->OffsetLabel, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f));
pressed = Selectable("", menu_is_open, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
RenderText(text_pos, label);
if (icon_w > 0.0f)
RenderText(pos + ImVec2(offsets->OffsetIcon, 0.0f), icon);
@ -7248,7 +7250,7 @@ bool ImGui::MenuItemEx(const char* label, const char* icon, const char* shortcut
float checkmark_w = IM_FLOOR(g.FontSize * 1.20f);
float min_w = window->DC.MenuColumns.DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame
float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w);
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, 0.0f));
pressed = Selectable("", false, selectable_flags | ImGuiSelectableFlags_SpanAvailWidth, ImVec2(min_w, label_size.y));
if (g.LastItemData.StatusFlags & ImGuiItemStatusFlags_Visible)
{
RenderText(pos + ImVec2(offsets->OffsetLabel, 0.0f), label);
@ -7300,11 +7302,17 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
// - TabBarCalcTabID() [Internal]
// - TabBarCalcMaxTabWidth() [Internal]
// - TabBarFindTabById() [Internal]
// - TabBarFindTabByOrder() [Internal]
// - TabBarGetCurrentTab() [Internal]
// - TabBarGetTabName() [Internal]
// - TabBarRemoveTab() [Internal]
// - TabBarCloseTab() [Internal]
// - TabBarScrollClamp() [Internal]
// - TabBarScrollToTab() [Internal]
// - TabBarQueueChangeTabOrder() [Internal]
// - TabBarQueueFocus() [Internal]
// - TabBarQueueReorder() [Internal]
// - TabBarProcessReorderFromMousePos() [Internal]
// - TabBarProcessReorder() [Internal]
// - TabBarScrollingButtons() [Internal]
// - TabBarTabListPopupButton() [Internal]
//-------------------------------------------------------------------------
@ -7429,6 +7437,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->ItemSpacingY = g.Style.ItemSpacing.y;
tab_bar->FramePadding = g.Style.FramePadding;
tab_bar->TabsActiveCount = 0;
tab_bar->LastTabItemIdx = -1;
tab_bar->BeginCount = 1;
// Set cursor pos in a way which only be used in the off-chance the user erroneously submits item before BeginTabItem(): items will overlap
@ -7477,6 +7486,7 @@ void ImGui::EndTabBar()
if (tab_bar->BeginCount > 1)
window->DC.CursorPos = tab_bar->BackupCursorPos;
tab_bar->LastTabItemIdx = -1;
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
PopID();
@ -7586,7 +7596,7 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Refresh tab width immediately, otherwise changes of style e.g. style.FramePadding.x would noticeably lag in the tab bar.
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab);
const char* tab_name = TabBarGetTabName(tab_bar, tab);
const bool has_close_button_or_unsaved_marker = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0 || (tab->Flags & ImGuiTabItemFlags_UnsavedDocument);
tab->ContentWidth = (tab->RequestedWidth >= 0.0f) ? tab->RequestedWidth : TabItemCalcSize(tab_name, has_close_button_or_unsaved_marker).x;
@ -7747,7 +7757,28 @@ ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
return NULL;
}
// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
// Order = visible order, not submission order! (which is tab->BeginOrder)
ImGuiTabItem* ImGui::TabBarFindTabByOrder(ImGuiTabBar* tab_bar, int order)
{
if (order < 0 || order >= tab_bar->Tabs.Size)
return NULL;
return &tab_bar->Tabs[order];
}
ImGuiTabItem* ImGui::TabBarGetCurrentTab(ImGuiTabBar* tab_bar)
{
if (tab_bar->LastTabItemIdx <= 0 || tab_bar->LastTabItemIdx >= tab_bar->Tabs.Size)
return NULL;
return &tab_bar->Tabs[tab_bar->LastTabItemIdx];
}
const char* ImGui::TabBarGetTabName(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < tab_bar->TabsNames.Buf.Size);
return tab_bar->TabsNames.Buf.Data + tab->NameOffset;
}
// The *TabId fields are already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
{
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
@ -7778,7 +7809,7 @@ void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
// Actually select before expecting closure attempt (on an UnsavedDocument tab user is expect to e.g. show a popup)
if (tab_bar->VisibleTabId != tab->ID)
tab_bar->NextSelectedTabId = tab->ID;
TabBarQueueFocus(tab_bar, tab);
}
}
@ -7799,7 +7830,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
ImGuiContext& g = *GImGui;
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
int order = tab_bar->GetTabOrder(tab);
int order = TabBarGetTabOrder(tab_bar, tab);
// Scrolling happens only in the central section (leading/trailing sections are not scrolling)
// FIXME: This is all confusing.
@ -7823,7 +7854,12 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiID tab_id, ImGui
}
}
void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int offset)
void ImGui::TabBarQueueFocus(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
{
tab_bar->NextSelectedTabId = tab->ID;
}
void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, ImGuiTabItem* tab, int offset)
{
IM_ASSERT(offset != 0);
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
@ -7831,7 +7867,7 @@ void ImGui::TabBarQueueReorder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, in
tab_bar->ReorderRequestOffset = (ImS16)offset;
}
void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, const ImGuiTabItem* src_tab, ImVec2 mouse_pos)
void ImGui::TabBarQueueReorderFromMousePos(ImGuiTabBar* tab_bar, ImGuiTabItem* src_tab, ImVec2 mouse_pos)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
@ -7874,7 +7910,7 @@ bool ImGui::TabBarProcessReorder(ImGuiTabBar* tab_bar)
return false;
//IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable); // <- this may happen when using debug tools
int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestOffset;
int tab2_order = TabBarGetTabOrder(tab_bar, tab1) + tab_bar->ReorderRequestOffset;
if (tab2_order < 0 || tab2_order >= tab_bar->Tabs.Size)
return false;
@ -7934,7 +7970,7 @@ static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
if (select_dir != 0)
if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
{
int selected_order = tab_bar->GetTabOrder(tab_item);
int selected_order = TabBarGetTabOrder(tab_bar, tab_item);
int target_order = selected_order + select_dir;
// Skip tab item buttons until another tab item is found or end is reached
@ -7986,7 +8022,7 @@ static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
if (tab->Flags & ImGuiTabItemFlags_Button)
continue;
const char* tab_name = tab_bar->GetTabName(tab);
const char* tab_name = TabBarGetTabName(tab_bar, tab);
if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID))
tab_to_select = tab;
}
@ -8150,9 +8186,9 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
{
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
tab_bar->NextSelectedTabId = id; // New tabs gets activated
TabBarQueueFocus(tab_bar, tab); // New tabs gets activated
if ((flags & ImGuiTabItemFlags_SetSelected) && (tab_bar->SelectedTabId != id)) // _SetSelected can only be passed on explicit tab bar
tab_bar->NextSelectedTabId = id;
TabBarQueueFocus(tab_bar, tab);
}
// Lock visibility
@ -8216,7 +8252,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
if (pressed && !is_tab_button)
tab_bar->NextSelectedTabId = id;
TabBarQueueFocus(tab_bar, tab);
// Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered)
if (g.ActiveId != id)
@ -8257,9 +8293,8 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)))
if (!is_tab_button)
tab_bar->NextSelectedTabId = id;
if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)) && !is_tab_button)
TabBarQueueFocus(tab_bar, tab);
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;