diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 1e6766842..e4e8dc0db 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt @@ -60,9 +60,10 @@ Other changes: - ImGuiTreeNodeFlags_DrawLinesNone: No lines drawn (default value in style.TreeLinesFlags). - ImGuiTreeNodeFlags_DrawLinesFull: Horizontal lines to child nodes. Vertical line drawn down to TreePop() position: cover full contents. - ImGuiTreeNodeFlags_DrawLinesToNodes: Horizontal lines to child nodes. Vertical line drawn down to bottom-most child node. - - Added style.TreeLinesFlags which stores the default setting, + - Added style.TreeLinesFlags which stores the default setting, which may be overriden in individual TreeNode() calls. - Added style.TreeLinesSize (default to 1.0f). + - Added style.TreeLinesRadius (default to 0.0f). - Added ImGuiCol_TreeLines (in default style this is the same as ImGuiCol_Border). - Caveats: - Tree nodes may be used in many creative ways (manually positioning openable diff --git a/imgui.cpp b/imgui.cpp index c7566494b..a8d67f9bf 100644 --- a/imgui.cpp +++ b/imgui.cpp @@ -1362,6 +1362,7 @@ ImGuiStyle::ImGuiStyle() TableAngledHeadersTextAlign = ImVec2(0.5f,0.0f);// Alignment of angled headers within the cell TreeLinesFlags = ImGuiTreeNodeFlags_DrawLinesNone; TreeLinesSize = 1.0f; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + TreeLinesRounding = 0.0f; // Radius of lines connecting child nodes to the vertical line. ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text. SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. @@ -1416,6 +1417,7 @@ void ImGuiStyle::ScaleAllSizes(float scale_factor) TabCloseButtonMinWidthSelected = (TabCloseButtonMinWidthSelected > 0.0f && TabCloseButtonMinWidthSelected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthSelected * scale_factor) : TabCloseButtonMinWidthSelected; TabCloseButtonMinWidthUnselected = (TabCloseButtonMinWidthUnselected > 0.0f && TabCloseButtonMinWidthUnselected != FLT_MAX) ? ImTrunc(TabCloseButtonMinWidthUnselected * scale_factor) : TabCloseButtonMinWidthUnselected; TabBarOverlineSize = ImTrunc(TabBarOverlineSize * scale_factor); + TreeLinesRounding = ImTrunc(TreeLinesRounding * scale_factor); SeparatorTextPadding = ImTrunc(SeparatorTextPadding * scale_factor); DisplayWindowPadding = ImTrunc(DisplayWindowPadding * scale_factor); DisplaySafeAreaPadding = ImTrunc(DisplaySafeAreaPadding * scale_factor); @@ -3418,6 +3420,7 @@ static const ImGuiStyleVarInfo GStyleVarsInfo[] = { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersAngle)}, // ImGuiStyleVar_TableAngledHeadersAngle { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TableAngledHeadersTextAlign)},// ImGuiStyleVar_TableAngledHeadersTextAlign { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesSize)}, // ImGuiStyleVar_TreeLinesSize + { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, TreeLinesRounding)}, // ImGuiStyleVar_TreeLinesRounding { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, ButtonTextAlign) }, // ImGuiStyleVar_ButtonTextAlign { 2, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SelectableTextAlign) }, // ImGuiStyleVar_SelectableTextAlign { 1, ImGuiDataType_Float, (ImU32)offsetof(ImGuiStyle, SeparatorTextBorderSize)}, // ImGuiStyleVar_SeparatorTextBorderSize diff --git a/imgui.h b/imgui.h index 98761113f..0ddef9510 100644 --- a/imgui.h +++ b/imgui.h @@ -1730,6 +1730,7 @@ enum ImGuiStyleVar_ ImGuiStyleVar_TableAngledHeadersAngle, // float TableAngledHeadersAngle ImGuiStyleVar_TableAngledHeadersTextAlign,// ImVec2 TableAngledHeadersTextAlign ImGuiStyleVar_TreeLinesSize, // float TreeLinesSize + ImGuiStyleVar_TreeLinesRounding, // float TreeLinesRounding ImGuiStyleVar_ButtonTextAlign, // ImVec2 ButtonTextAlign ImGuiStyleVar_SelectableTextAlign, // ImVec2 SelectableTextAlign ImGuiStyleVar_SeparatorTextBorderSize, // float SeparatorTextBorderSize @@ -2190,7 +2191,8 @@ struct ImGuiStyle float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees). ImVec2 TableAngledHeadersTextAlign;// Alignment of angled headers within the cell ImGuiTreeNodeFlags TreeLinesFlags; // Default way to draw lines connecting TreeNode hierarchy. ImGuiTreeNodeFlags_DrawLinesNone or ImGuiTreeNodeFlags_DrawLinesFull or ImGuiTreeNodeFlags_DrawLinesToNodes. - float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + float TreeLinesSize; // Thickness of outlines when using ImGuiTreeNodeFlags_DrawLines. + float TreeLinesRounding; // Radius of lines connecting child nodes to the vertical line. ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right. ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered). ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line. diff --git a/imgui_demo.cpp b/imgui_demo.cpp index ac51635cf..fbf65aa1d 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -8270,15 +8270,11 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f); ImGui::SliderFloat2("TableAngledHeadersTextAlign", (float*)&style.TableAngledHeadersTextAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SeparatorText("Windows"); - ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); - ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); - int window_menu_button_position = style.WindowMenuButtonPosition + 1; - if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) - style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); - - ImGui::SeparatorText("Widgets"); - if (ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags))) + ImGui::SeparatorText("Trees"); + bool combo_open = ImGui::BeginCombo("TreeLinesFlags", GetTreeLinesFlagsName(style.TreeLinesFlags)); + ImGui::SameLine(); + HelpMarker("[Experimental] Tree lines may not work in all situations (e.g. using a clipper) and may incurs slight traversal overhead.\n\nImGuiTreeNodeFlags_DrawLinesFull is faster than ImGuiTreeNodeFlags_DrawLinesToNode."); + if (combo_open) { const ImGuiTreeNodeFlags options[] = { ImGuiTreeNodeFlags_DrawLinesNone, ImGuiTreeNodeFlags_DrawLinesFull, ImGuiTreeNodeFlags_DrawLinesToNodes }; for (ImGuiTreeNodeFlags option : options) @@ -8287,6 +8283,16 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref) ImGui::EndCombo(); } ImGui::SliderFloat("TreeLinesSize", &style.TreeLinesSize, 0.0f, 2.0f, "%.0f"); + ImGui::SliderFloat("TreeLinesRounding", &style.TreeLinesRounding, 0.0f, 12.0f, "%.0f"); + + ImGui::SeparatorText("Windows"); + ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f"); + ImGui::SliderFloat("WindowBorderHoverPadding", &style.WindowBorderHoverPadding, 1.0f, 20.0f, "%.0f"); + int window_menu_button_position = style.WindowMenuButtonPosition + 1; + if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0")) + style.WindowMenuButtonPosition = (ImGuiDir)(window_menu_button_position - 1); + + ImGui::SeparatorText("Widgets"); ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "Left\0Right\0"); ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content."); diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 140ceb9e1..64f07a41b 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp @@ -6867,9 +6867,22 @@ void ImGui::TreeNodeDrawLineToChildNode(const ImVec2& target_pos) float x1 = ImTrunc(parent_data->DrawLinesX1); float x2 = ImTrunc(target_pos.x - g.Style.ItemInnerSpacing.x); float y = ImTrunc(target_pos.y); - parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y); - if (x1 < x2) + float rounding = (g.Style.TreeLinesRounding > 0.0f) ? ImMin(x2 - x1, g.Style.TreeLinesRounding) : 0.0f; + parent_data->DrawLinesToNodesY2 = ImMax(parent_data->DrawLinesToNodesY2, y - rounding); + if (x1 >= x2) + return; + if (rounding > 0.0f) + { + x1 += 0.5f + rounding; + window->DrawList->PathArcToFast(ImVec2(x1, y - rounding), rounding, 6, 3); + if (x1 < x2) + window->DrawList->PathLineTo(ImVec2(x2, y)); + window->DrawList->PathStroke(GetColorU32(ImGuiCol_TreeLines), ImDrawFlags_None, g.Style.TreeLinesSize); + } + else + { window->DrawList->AddLine(ImVec2(x1, y), ImVec2(x2, y), GetColorU32(ImGuiCol_TreeLines), g.Style.TreeLinesSize); + } } // Draw vertical line of the hierarchy @@ -6885,7 +6898,7 @@ void ImGui::TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data) if (g.CurrentTable) y2_full = ImMax(g.CurrentTable->RowPosY2, y2_full); y2_full = ImTrunc(y2_full - g.Style.ItemSpacing.y - g.FontSize * 0.5f); - if (y2 + g.Style.ItemSpacing.y < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y + if (y2 + (g.Style.ItemSpacing.y + g.Style.TreeLinesRounding) < y2_full) // FIXME: threshold to use ToNodes Y2 instead of Full Y2 when close by ItemSpacing.y y2 = y2_full; } y2 = ImMin(y2, window->ClipRect.Max.y);