diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/imgui.h b/imgui.h index c9492f7..6cacf38 100644 --- a/imgui.h +++ b/imgui.h @@ -849,8 +849,8 @@ ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit @@ -1673,7 +1673,7 @@ inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Data ? Buf.Size - 1 : 0; } + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/imgui.h b/imgui.h index c9492f7..6cacf38 100644 --- a/imgui.h +++ b/imgui.h @@ -849,8 +849,8 @@ ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit @@ -1673,7 +1673,7 @@ inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Data ? Buf.Size - 1 : 0; } + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c6df162..549938d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1833,6 +1833,7 @@ static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; @@ -2873,7 +2874,6 @@ { ImGui::Text("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); @@ -2891,6 +2891,7 @@ ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + 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("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); @@ -2962,7 +2963,8 @@ if (ImGui::BeginTabItem("Fonts")) { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) @@ -2970,7 +2972,7 @@ ImFont* font = atlas->Fonts[i]; ImGui::PushID(font); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } if (font_details_opened) { ImGui::PushFont(font); @@ -3035,9 +3037,9 @@ } static float window_scale = 1.0f; - if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/imgui.h b/imgui.h index c9492f7..6cacf38 100644 --- a/imgui.h +++ b/imgui.h @@ -849,8 +849,8 @@ ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit @@ -1673,7 +1673,7 @@ inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Data ? Buf.Size - 1 : 0; } + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c6df162..549938d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1833,6 +1833,7 @@ static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; @@ -2873,7 +2874,6 @@ { ImGui::Text("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); @@ -2891,6 +2891,7 @@ ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + 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("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); @@ -2962,7 +2963,8 @@ if (ImGui::BeginTabItem("Fonts")) { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) @@ -2970,7 +2972,7 @@ ImFont* font = atlas->Fonts[i]; ImGui::PushID(font); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } if (font_details_opened) { ImGui::PushFont(font); @@ -3035,9 +3037,9 @@ } static float window_scale = 1.0f; - if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bcafa0b..09f4046 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1598,8 +1598,10 @@ font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.PixelSnapH = true; } - if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); - if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f; + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); @@ -3101,7 +3103,8 @@ void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) { ImFont* font = draw_list->_Data->Font; - pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); + const float font_scale = draw_list->_Data->FontSize / font->FontSize; + pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f); for (int dot_n = 0; dot_n < count; dot_n++) draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); } diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/imgui.h b/imgui.h index c9492f7..6cacf38 100644 --- a/imgui.h +++ b/imgui.h @@ -849,8 +849,8 @@ ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit @@ -1673,7 +1673,7 @@ inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Data ? Buf.Size - 1 : 0; } + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c6df162..549938d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1833,6 +1833,7 @@ static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; @@ -2873,7 +2874,6 @@ { ImGui::Text("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); @@ -2891,6 +2891,7 @@ ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + 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("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); @@ -2962,7 +2963,8 @@ if (ImGui::BeginTabItem("Fonts")) { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) @@ -2970,7 +2972,7 @@ ImFont* font = atlas->Fonts[i]; ImGui::PushID(font); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } if (font_details_opened) { ImGui::PushFont(font); @@ -3035,9 +3037,9 @@ } static float window_scale = 1.0f; - if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bcafa0b..09f4046 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1598,8 +1598,10 @@ font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.PixelSnapH = true; } - if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); - if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f; + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); @@ -3101,7 +3103,8 @@ void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) { ImFont* font = draw_list->_Data->Font; - pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); + const float font_scale = draw_list->_Data->FontSize / font->FontSize; + pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f); for (int dot_n = 0; dot_n < count; dot_n++) draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); } diff --git a/imgui_internal.h b/imgui_internal.h index be5ac90..e1fa7c8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1420,8 +1420,9 @@ enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_Unsorted = 1 << 20, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. - ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Store whether p_open is set or not, which we need to recompute WidthContents during layout. + ImGuiTabItemFlags_Unsorted = 1 << 21, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Preview = 1 << 22 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) }; // Storage for one active tab item (sizeof() 32~40 bytes) @@ -1432,11 +1433,12 @@ ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. int LastFrameVisible; int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames float Offset; // Position relative to beginning of tab float Width; // Width currently displayed float WidthContents; // Width of actual contents, stored during BeginTabItem() call - ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } + ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1461,9 +1463,18 @@ bool WantLayout; bool VisibleTabWasSubmitted; short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + 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); } + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + if (tab->Window) + return tab->Window->Name; + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } }; //----------------------------------------------------------------------------- @@ -1635,7 +1646,7 @@ 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); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); - IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id); + IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id); // Render helpers // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index c5473fb..af98235 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -107,6 +107,9 @@ - InputText: Fixed a bug where ESCAPE would be first captured by the Keyboard Navigation code. (#2321, #787) - Fixed range-version of PushID() and GetID() not honoring the ### operator to restart from the seed value. - Fixed CloseCurrentPopup() on a child-menu of a modal incorrectly closing the modal. (#2308) +- Tabs: Added ImGuiTabBarFlags_TabListPopupButton flag to show a popup button on manual tab bars. (#261, #351) +- Tabs: Removed ImGuiTabBarFlags_NoTabListPopupButton which was available in 1.67 but actually had zero use. +- RadioButton: Fixed label horizontal alignment to precisely match Checkbox(). - Window: When resizing from an edge, the border is more visible and better follow the rounded corners. - ImDrawList: Fixed AddCircle(), AddCircleFilled() angle step being off, which was visible when drawing a "circle" with a small number of segments (e.g. an hexagon). (#2287) [@baktery] diff --git a/imgui.cpp b/imgui.cpp index 975f8dd..3e4388d 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1150,7 +1150,6 @@ PopupRounding = ImFloor(PopupRounding * scale_factor); FramePadding = ImFloor(FramePadding * scale_factor); FrameRounding = ImFloor(FrameRounding * scale_factor); - TabRounding = ImFloor(TabRounding * scale_factor); ItemSpacing = ImFloor(ItemSpacing * scale_factor); ItemInnerSpacing = ImFloor(ItemInnerSpacing * scale_factor); TouchExtraPadding = ImFloor(TouchExtraPadding * scale_factor); @@ -1160,6 +1159,7 @@ ScrollbarRounding = ImFloor(ScrollbarRounding * scale_factor); GrabMinSize = ImFloor(GrabMinSize * scale_factor); GrabRounding = ImFloor(GrabRounding * scale_factor); + TabRounding = ImFloor(TabRounding * scale_factor); DisplayWindowPadding = ImFloor(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImFloor(DisplaySafeAreaPadding * scale_factor); MouseCursorScale = ImFloor(MouseCursorScale * scale_factor); @@ -6199,7 +6199,7 @@ IM_ASSERT(font && font->IsLoaded()); // Font Atlas not created. Did you call io.Fonts->GetTexDataAsRGBA32 / GetTexDataAsAlpha8 ? IM_ASSERT(font->Scale > 0.0f); g.Font = font; - g.FontBaseSize = g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale; + g.FontBaseSize = ImMax(1.0f, g.IO.FontGlobalScale * g.Font->FontSize * g.Font->Scale); g.FontSize = g.CurrentWindow ? g.CurrentWindow->CalcFontSize() : 0.0f; ImFontAtlas* atlas = g.Font->ContainerAtlas; @@ -11516,7 +11516,7 @@ // Begin tab bar const ImRect tab_bar_rect = DockNodeCalcTabBarRect(node); - ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs | ImGuiTabBarFlags_NoTabListPopupButton;// | ImGuiTabBarFlags_NoTabListScrollingButtons); + ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs; // | ImGuiTabBarFlags_NoTabListScrollingButtons); tab_bar_flags |= ImGuiTabBarFlags_SaveSettings | ImGuiTabBarFlags_DockNode; if (!host_window->Collapsed && is_focused) tab_bar_flags |= ImGuiTabBarFlags_IsFocused; @@ -11904,7 +11904,7 @@ if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PushClipRect(tab_bar_rect.Min, tab_bar_rect.Max); TabItemBackground(overlay_draw_lists[overlay_n], tab_bb, tab_flags, overlay_col_tabs); - TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, payload->Name, 0, 0); + TabItemLabelAndCloseButton(overlay_draw_lists[overlay_n], tab_bb, tab_flags, g.Style.FramePadding, payload->Name, 0, 0); if (!tab_bar_rect.Contains(tab_bb)) overlay_draw_lists[overlay_n]->PopClipRect(); } @@ -13813,16 +13813,18 @@ // Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted. ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible. while (clipper.Step()) - for (int prim = clipper.DisplayStart, vtx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) + for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++) { char buf[300]; char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf); ImVec2 triangles_pos[3]; - for (int n = 0; n < 3; n++, vtx_i++) + for (int n = 0; n < 3; n++, idx_i++) { - ImDrawVert& v = draw_list->VtxBuffer[idx_buffer ? idx_buffer[vtx_i] : vtx_i]; + int vtx_i = idx_buffer ? idx_buffer[idx_i] : idx_i; + ImDrawVert& v = draw_list->VtxBuffer[vtx_i]; triangles_pos[n] = v.pos; - buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", (n == 0) ? "vtx" : " ", vtx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); + buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n", + (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col); } ImGui::Selectable(buf, false); if (overlay_draw_list && ImGui::IsItemHovered()) diff --git a/imgui.h b/imgui.h index c9492f7..6cacf38 100644 --- a/imgui.h +++ b/imgui.h @@ -849,8 +849,8 @@ ImGuiTabBarFlags_None = 0, ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear - ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. - ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3, + ImGuiTabBarFlags_TabListPopupButton = 1 << 2, + ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false. ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit @@ -1673,7 +1673,7 @@ inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; } const char* begin() const { return Buf.Data ? &Buf.front() : EmptyString; } const char* end() const { return Buf.Data ? &Buf.back() : EmptyString; } // Buf is zero-terminated, so end() will point on the zero-terminator - int size() const { return Buf.Data ? Buf.Size - 1 : 0; } + int size() const { return Buf.Size ? Buf.Size - 1 : 0; } bool empty() { return Buf.Size <= 1; } void clear() { Buf.clear(); } void reserve(int capacity) { Buf.reserve(capacity); } diff --git a/imgui_demo.cpp b/imgui_demo.cpp index c6df162..549938d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -1833,6 +1833,7 @@ static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable; ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs); + ImGui::CheckboxFlags("ImGuiTabBarFlags_TabListPopupButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_TabListPopupButton); ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton); if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0) tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_; @@ -2873,7 +2874,6 @@ { ImGui::Text("Main"); ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f"); - ImGui::SliderFloat("PopupRounding", &style.PopupRounding, 0.0f, 16.0f, "%.0f"); ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f"); ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f"); @@ -2891,6 +2891,7 @@ ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 12.0f, "%.0f"); ImGui::SliderFloat("FrameRounding", &style.FrameRounding, 0.0f, 12.0f, "%.0f"); + 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("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f"); @@ -2962,7 +2963,8 @@ if (ImGui::BeginTabItem("Fonts")) { - ImFontAtlas* atlas = ImGui::GetIO().Fonts; + ImGuiIO& io = ImGui::GetIO(); + ImFontAtlas* atlas = io.Fonts; ShowHelpMarker("Read FAQ and misc/fonts/README.txt for details on font loading."); ImGui::PushItemWidth(120); for (int i = 0; i < atlas->Fonts.Size; i++) @@ -2970,7 +2972,7 @@ ImFont* font = atlas->Fonts[i]; ImGui::PushID(font); bool font_details_opened = ImGui::TreeNode(font, "Font %d: \"%s\"\n%.2f px, %d glyphs, %d file(s)", i, font->ConfigData ? font->ConfigData[0].Name : "", font->FontSize, font->Glyphs.Size, font->ConfigDataCount); - ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) ImGui::GetIO().FontDefault = font; + ImGui::SameLine(); if (ImGui::SmallButton("Set as default")) { io.FontDefault = font; } if (font_details_opened) { ImGui::PushFont(font); @@ -3035,9 +3037,9 @@ } static float window_scale = 1.0f; - if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.1f")) // scale only this window + if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window ImGui::SetWindowFontScale(window_scale); - ImGui::DragFloat("global scale", &ImGui::GetIO().FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.1f"); // scale everything + ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything ImGui::PopItemWidth(); ImGui::EndTabItem(); diff --git a/imgui_draw.cpp b/imgui_draw.cpp index bcafa0b..09f4046 100644 --- a/imgui_draw.cpp +++ b/imgui_draw.cpp @@ -1598,8 +1598,10 @@ font_cfg.OversampleH = font_cfg.OversampleV = 1; font_cfg.PixelSnapH = true; } - if (font_cfg.Name[0] == '\0') strcpy(font_cfg.Name, "ProggyClean.ttf, 13px"); - if (font_cfg.SizePixels <= 0.0f) font_cfg.SizePixels = 13.0f; + if (font_cfg.SizePixels <= 0.0f) + font_cfg.SizePixels = 13.0f * 1.0f; + if (font_cfg.Name[0] == '\0') + ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels); const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85(); const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault(); @@ -3101,7 +3103,8 @@ void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col) { ImFont* font = draw_list->_Data->Font; - pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f); + const float font_scale = draw_list->_Data->FontSize / font->FontSize; + pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f); for (int dot_n = 0; dot_n < count; dot_n++) draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col); } diff --git a/imgui_internal.h b/imgui_internal.h index be5ac90..e1fa7c8 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1420,8 +1420,9 @@ enum ImGuiTabItemFlagsPrivate_ { - ImGuiTabItemFlags_Unsorted = 1 << 20, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. - ImGuiTabItemFlags_Preview = 1 << 21 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) + ImGuiTabItemFlags_NoCloseButton = 1 << 20, // Store whether p_open is set or not, which we need to recompute WidthContents during layout. + ImGuiTabItemFlags_Unsorted = 1 << 21, // [Docking] Trailing tabs with the _Unsorted flag will be sorted based on the DockOrder of their Window. + ImGuiTabItemFlags_Preview = 1 << 22 // [Docking] Display tab shape for docking preview (height is adjusted slightly to compensate for the yet missing tab bar) }; // Storage for one active tab item (sizeof() 32~40 bytes) @@ -1432,11 +1433,12 @@ ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window. int LastFrameVisible; int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance + int NameOffset; // When Window==NULL, offset to name within parent ImGuiTabBar::TabsNames float Offset; // Position relative to beginning of tab float Width; // Width currently displayed float WidthContents; // Width of actual contents, stored during BeginTabItem() call - ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; } + ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; NameOffset = -1; Offset = Width = WidthContents = 0.0f; } }; // Storage for a tab bar (sizeof() 92~96 bytes) @@ -1461,9 +1463,18 @@ bool WantLayout; bool VisibleTabWasSubmitted; short LastTabItemIdx; // For BeginTabItem()/EndTabItem() + ImVec2 FramePadding; // style.FramePadding locked at the time of BeginTabBar() + 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); } + int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_ptr(tab); } + const char* GetTabName(const ImGuiTabItem* tab) const + { + if (tab->Window) + return tab->Window->Name; + IM_ASSERT(tab->NameOffset != -1 && tab->NameOffset < TabsNames.Buf.Size); + return TabsNames.Buf.Data + tab->NameOffset; + } }; //----------------------------------------------------------------------------- @@ -1635,7 +1646,7 @@ 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); IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col); - IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id); + IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id); // Render helpers // AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT. diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index caeb849..849b1e9 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -926,19 +926,11 @@ const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2, label_size.y + style.FramePadding.y*2)); // We want a square shape to we use Y twice - ItemSize(check_bb, style.FramePadding.y); - - ImRect total_bb = check_bb; - if (label_size.x > 0) - SameLine(0, style.ItemInnerSpacing.x); - const ImRect text_bb(window->DC.CursorPos + ImVec2(0,style.FramePadding.y), window->DC.CursorPos + ImVec2(0,style.FramePadding.y) + label_size); - if (label_size.x > 0) - { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); - total_bb = ImRect(ImMin(check_bb.Min, text_bb.Min), ImMax(check_bb.Max, text_bb.Max)); - } - + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + 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)); + ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id)) return false; @@ -954,15 +946,14 @@ RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding); if (*v) { - const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); - const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); - RenderCheckMark(check_bb.Min + ImVec2(pad,pad), GetColorU32(ImGuiCol_CheckMark), check_bb.GetWidth() - pad*2.0f); + const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f)); + RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), square_sz - pad*2.0f); } if (g.LogEnabled) - LogRenderedText(&text_bb.Min, *v ? "[x]" : "[ ]"); + LogRenderedText(&total_bb.Min, *v ? "[x]" : "[ ]"); if (label_size.x > 0.0f) - RenderText(text_bb.Min, label); + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0)); return pressed; @@ -994,26 +985,18 @@ const ImGuiID id = window->GetID(label); const ImVec2 label_size = CalcTextSize(label, NULL, true); - const ImRect check_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(label_size.y + style.FramePadding.y*2-1, label_size.y + style.FramePadding.y*2-1)); - ItemSize(check_bb, style.FramePadding.y); - - ImRect total_bb = check_bb; - if (label_size.x > 0) - SameLine(0, style.ItemInnerSpacing.x); - const ImRect text_bb(window->DC.CursorPos + ImVec2(0, style.FramePadding.y), window->DC.CursorPos + ImVec2(0, style.FramePadding.y) + label_size); - if (label_size.x > 0) - { - ItemSize(ImVec2(text_bb.GetWidth(), check_bb.GetHeight()), style.FramePadding.y); - total_bb.Add(text_bb); - } - + const float square_sz = GetFrameHeight(); + const ImVec2 pos = window->DC.CursorPos; + const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz)); + 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)); + ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id)) return false; ImVec2 center = check_bb.GetCenter(); center.x = (float)(int)center.x + 0.5f; center.y = (float)(int)center.y + 0.5f; - const float radius = check_bb.GetHeight() * 0.5f; + const float radius = (square_sz - 1.0f) * 0.5f; bool hovered, held; bool pressed = ButtonBehavior(total_bb, id, &hovered, &held); @@ -1024,21 +1007,20 @@ window->DrawList->AddCircleFilled(center, radius, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), 16); if (active) { - const float check_sz = ImMin(check_bb.GetWidth(), check_bb.GetHeight()); - const float pad = ImMax(1.0f, (float)(int)(check_sz / 6.0f)); - window->DrawList->AddCircleFilled(center, radius-pad, GetColorU32(ImGuiCol_CheckMark), 16); + const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f)); + window->DrawList->AddCircleFilled(center, radius - pad, GetColorU32(ImGuiCol_CheckMark), 16); } if (style.FrameBorderSize > 0.0f) { - window->DrawList->AddCircle(center+ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); + window->DrawList->AddCircle(center + ImVec2(1,1), radius, GetColorU32(ImGuiCol_BorderShadow), 16, style.FrameBorderSize); window->DrawList->AddCircle(center, radius, GetColorU32(ImGuiCol_Border), 16, style.FrameBorderSize); } if (g.LogEnabled) - LogRenderedText(&text_bb.Min, active ? "(x)" : "( )"); + LogRenderedText(&total_bb.Min, active ? "(x)" : "( )"); if (label_size.x > 0.0f) - RenderText(text_bb.Min, label); + RenderText(ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y), label); return pressed; } @@ -1907,12 +1889,10 @@ const ImRect inner_bb(frame_bb.Min + style.FramePadding, frame_bb.Max - style.FramePadding); 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)); - // NB- we don't call ItemSize() yet because we may turn into a text edit box below + ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id, &frame_bb)) - { - ItemSize(total_bb, style.FramePadding.y); return false; - } + const bool hovered = ItemHoverable(frame_bb, id); // Default format string when passing NULL @@ -1940,12 +1920,12 @@ } if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) { + window->DC.CursorPos = frame_bb.Min; FocusableItemUnregister(window); return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); } // Actual drag behavior - ItemSize(total_bb, style.FramePadding.y); const bool value_changed = DragBehavior(id, data_type, v, v_speed, v_min, v_max, format, power, ImGuiDragFlags_None); if (value_changed) MarkItemEdited(id); @@ -2342,12 +2322,9 @@ const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f)); 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)); - // NB- we don't call ItemSize() yet because we may turn into a text edit box below + ItemSize(total_bb, style.FramePadding.y); if (!ItemAdd(total_bb, id, &frame_bb)) - { - ItemSize(total_bb, style.FramePadding.y); return false; - } // Default format string when passing NULL // Patch old "%.0f" format string to use "%d", read function comments for more details. @@ -2375,12 +2352,11 @@ } if (start_text_input || (g.ActiveId == id && g.ScalarAsInputTextId == id)) { + window->DC.CursorPos = frame_bb.Min; FocusableItemUnregister(window); return InputScalarAsWidgetReplacement(frame_bb, id, label, data_type, v, format); } - ItemSize(total_bb, style.FramePadding.y); - // Draw frame const ImU32 frame_col = GetColorU32(g.ActiveId == id ? ImGuiCol_FrameBgActive : g.HoveredId == id ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg); RenderNavHighlight(frame_bb, id); @@ -5931,6 +5907,7 @@ tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab() tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible; tab_bar->CurrFrameVisible = g.FrameCount; + tab_bar->FramePadding = g.Style.FramePadding; // Layout ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight())); @@ -6035,6 +6012,12 @@ tab_bar->ReorderRequestTabId = 0; } + // Tab List Popup (will alter tab_bar->BarRect and therefore the available width!) + const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_TabListPopupButton) != 0; + if (tab_list_popup_button) + if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! + scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; + ImVector& width_sort_buffer = g.TabSortByWidthBuffer; width_sort_buffer.resize(tab_bar->Tabs.Size); @@ -6052,11 +6035,13 @@ if (tab->ID == tab_bar->SelectedTabId) found_selected_tab_id = true; - // Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x) + // 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. - if (tab->Window) - tab->WidthContents = TabItemCalcSize(tab->Window->Name, tab->Window->HasCloseButton).x; + const char* tab_name = tab_bar->GetTabName(tab); + const bool has_close_button = tab->Window ? tab->Window->HasCloseButton : ((tab->Flags & ImGuiTabItemFlags_NoCloseButton) == 0); + tab->WidthContents = TabItemCalcSize(tab_name, has_close_button).x; + width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents; // Store data so we can build an array sorted by width if we need to shrink tabs down @@ -6109,12 +6094,6 @@ tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f); tab_bar->OffsetNextTab = 0.0f; - // Tab List Popup - const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_DockNode) != 0 && (tab_bar->Flags & ImGuiTabBarFlags_NoTabListPopupButton) == 0; - if (tab_list_popup_button) - if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x! - scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID; - // Horizontal scrolling buttons const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll); if (scrolling_buttons) @@ -6144,6 +6123,10 @@ const float scrolling_speed = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) ? FLT_MAX : (g.IO.DeltaTime * g.FontSize * 70.0f); if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget) tab_bar->ScrollingAnim = ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, scrolling_speed); + + // Clear name buffers + if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0) + tab_bar->TabsNames.Buf.resize(0); } // Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack. @@ -6303,18 +6286,16 @@ return tab_to_select; } -// FIXME-DOCK: Unused by Docking system static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar) { ImGuiContext& g = *GImGui; ImGuiWindow* window = g.CurrentWindow; - const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y * 2.0f; + // We use g.Style.FramePadding.y to match the square ArrowButton size + const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y; const ImVec2 backup_cursor_pos = window->DC.CursorPos; - tab_bar->BarRect.Max.x -= tab_list_popup_button_width; - if (window->HasCloseButton) - tab_bar->BarRect.Max.x += g.Style.ItemInnerSpacing.x; - window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Min.y); + window->DC.CursorPos = ImVec2(tab_bar->BarRect.Min.x - g.Style.FramePadding.y, tab_bar->BarRect.Min.y); + tab_bar->BarRect.Min.x += tab_list_popup_button_width; ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text]; arrow_col.w *= 0.5f; @@ -6329,8 +6310,8 @@ for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++) { ImGuiTabItem* tab = &tab_bar->Tabs[tab_n]; - IM_ASSERT(tab->Window != NULL); - if (MenuItem(tab->Window->Name)) + const char* tab_name = tab_bar->GetTabName(tab); + if (Selectable(tab_name, tab_bar->SelectedTabId == tab->ID)) tab_to_select = tab; } EndCombo(); @@ -6425,6 +6406,9 @@ tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_ptr(tab); tab->WidthContents = size.x; + if (p_open == NULL) + flags |= ImGuiTabItemFlags_NoCloseButton; + const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount); const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0; const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount); @@ -6432,6 +6416,10 @@ tab->Flags = flags; tab->Window = docked_window; + // Append name with zero-terminator + tab->NameOffset = tab_bar->TabsNames.size(); + tab_bar->TabsNames.append(label, label + strlen(label) + 1); + // If we are not reorderable, always reset offset based on submission order. // (We already handled layout and sizing using the previous known order, but sizing is not affected by order!) if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable)) @@ -6593,7 +6581,7 @@ // Render tab label, process close button const ImGuiID close_button_id = p_open ? window->GetID((void*)((intptr_t)id + 1)) : 0; - bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id); + bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, tab_bar->FramePadding, label, id, close_button_id); if (just_closed && p_open != NULL) { *p_open = false; @@ -6671,22 +6659,22 @@ } // Render text label (with custom clipping) + Unsaved Document marker + Close Button logic -bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id) +// We tend to lock style.FramePadding for a given tab-bar, hence the 'frame_padding' parameter. +bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImVec2 frame_padding, const char* label, ImGuiID tab_id, ImGuiID close_button_id) { ImGuiContext& g = *GImGui; - ImGuiStyle& style = g.Style; ImVec2 label_size = CalcTextSize(label, NULL, true); if (bb.GetWidth() <= 1.0f) return false; // Render text label (with clipping + alpha gradient) + unsaved marker const char* TAB_UNSAVED_MARKER = "*"; - ImRect text_pixel_clip_bb(bb.Min.x + style.FramePadding.x, bb.Min.y + style.FramePadding.y, bb.Max.x - style.FramePadding.x, bb.Max.y); + 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); if (flags & ImGuiTabItemFlags_UnsavedDocument) { text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x; - ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + style.FramePadding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + style.FramePadding.y + (float)(int)(-g.FontSize * 0.25f)); - RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - style.FramePadding, TAB_UNSAVED_MARKER, NULL, NULL); + ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + frame_padding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + frame_padding.y + (float)(int)(-g.FontSize * 0.25f)); + RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - frame_padding, TAB_UNSAVED_MARKER, NULL, NULL); } ImRect text_ellipsis_clip_bb = text_pixel_clip_bb; @@ -6704,7 +6692,7 @@ { ImGuiItemHoveredDataBackup last_item_backup; const float close_button_sz = g.FontSize * 0.5f; - if (CloseButton(close_button_id, ImVec2(bb.Max.x - style.FramePadding.x - close_button_sz, bb.Min.y + style.FramePadding.y + close_button_sz), close_button_sz)) + if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x - close_button_sz, bb.Min.y + frame_padding.y + close_button_sz), close_button_sz)) close_button_pressed = true; last_item_backup.Restore();