Skip to content

SeparatorText / TextSeparator / CenteredSeparator (which respects columns and SameLine) #1643

@phed

Description

@phed

I wanted to write a decorative combined text and separator.
So, this TextSeparator can be used inside columns and respects SameLine().

There is a number of variations, and CenteredSeparator is the main function, which is obviously an edit of ImGui::Separator

The main difference between this and ImGui::Separator is that it is aligned centered vertically, and that it does not align to the edges of the window when used alone, since I haven't found a clean way to detect if it is the first element on a line.

Maybe someone will find it useful. I would love any feedback for how to make it cleaner.

Other issues discussing the topic is #759 #205 #697 - Probably more too

namespace ImGui {
    // This one is not public, so we just re-declare it :(
    // It is not used so it can be safely discarded. But here it is in case I/you want to put the original ::Separator back
    static void PushColumnClipRect(int column_index = -1)
    {
        ImGuiWindow* window = ImGui::GetCurrentWindow();
        if (column_index < 0)
            column_index = window->DC.ColumnsCurrent;

        float x1 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index) - 1.0f);
        float x2 = ImFloor(0.5f + window->Pos.x + ImGui::GetColumnOffset(column_index+1) - 1.0f);
        ImGui::PushClipRect(ImVec2(x1,-FLT_MAX), ImVec2(x2,+FLT_MAX), true);
    }

    void CenteredSeparator(float width=0)
    {
        ImGuiWindow* window = GetCurrentWindow();
        if (window->SkipItems)
            return;
        ImGuiContext& g = *GImGui;
        /* // Commented out because it is not tested, but it should work, but it won't be centered
        ImGuiWindowFlags flags = 0;
        if ((flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical)) == 0)
            flags |= (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
        IM_ASSERT(ImIsPowerOfTwo((int)(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))));   // Check that only 1 option is selected
        if (flags & ImGuiSeparatorFlags_Vertical)
        {
            VerticalSeparator();
            return;
        }
        */

        // Horizontal Separator
        float x1, x2;
        if ((window->DC.ColumnsCount == 1) && (width == 0))
        {
            // Span whole window
            ///x1 = window->Pos.x; // This fails with SameLine(); CenteredSeparator();
            // Nah, we have to detect if we have a sameline in a different way
            x1 = window->DC.CursorPos.x;
            x2 = x1 + window->Size.x;
        }
        else
        {
            // Start at the cursor
            x1 = window->DC.CursorPos.x;
            if (width != 0) {
                x2 = x1 + width;
            }
            else {
                x2 = window->ClipRect.Max.x;
                // Pad right side of columns (except the last one)
                if (window->DC.ColumnsCount > 1 && (window->DC.ColumnsCurrent < window->DC.ColumnsCount-1)) x2 -= g.Style.ItemSpacing.x; 
            }
        }
        float y1 = window->DC.CursorPos.y + int(window->DC.CurrentLineHeight / 2.0f);
        float y2 = y1 + 1.0f;

        window->DC.CursorPos.x += width; //+ g.Style.ItemSpacing.x;

        if (!window->DC.GroupStack.empty())
            x1 += window->DC.IndentX;

        const ImRect bb(ImVec2(x1, y1), ImVec2(x2, y2));
        ItemSize(ImVec2(0.0f, 0.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit, we don't provide height to not alter layout.
        if (!ItemAdd(bb, NULL))
        {
            return;
        }

        window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Border));
            
        /* // Commented out because LogText is hard to reach outside imgui.cpp
        if (g.LogEnabled)
            LogText(IM_NEWLINE "--------------------------------");
        */
    }

    // Create a centered separator right after the current item.
    // Eg.: 
    // ImGui::PreSeparator(10);
    // ImGui::Text("Section VI");
    // ImGui::SameLineSeparator();
    void SameLineSeparator(float width = 0) {
        ImGui::SameLine();
        CenteredSeparator(width);
    }

    // Create a centered separator which can be immediately followed by a item
    void PreSeparator(float width) {
        ImGuiWindow* window = GetCurrentWindow();
        if (window->DC.CurrentLineHeight == 0)
            window->DC.CurrentLineHeight = ImGui::GetTextLineHeight();
        CenteredSeparator(width);
        ImGui::SameLine();
    }

    // The value for width is arbitrary. But it looks nice.
    void TextSeparator(char* text, int pre_width = 10) {
        ImGui::PreSeparator(pre_width);
        ImGui::Text(text);
        ImGui::SameLineSeparator();
    }

    void test_fancy_separator() {
        ImGuiIO io = ImGui::GetIO();
        static float t = 0.0f;
        t += io.DeltaTime;
        float f = sinf(4 * t * 3.14 / 9) * sinf(4 * t * 3.14 / 7);
        ImGui::PreSeparator(20 + 100*abs(f));
        ImGui::TextColored(ImColor(0.6f, 0.3f, 0.3f, 1.0f), "Fancy separators");
        ImGui::SameLineSeparator();
        ImGui::Bullet();
        ImGui::CenteredSeparator(100);
        ImGui::SameLine();
        ImGui::Text("Centered separator");
        ImGui::Columns(2);
        ImGui::PreSeparator(10);
        ImGui::Text("Separator");
        ImGui::SameLineSeparator();
        ImGui::CenteredSeparator();
        ImGui::Text("Column 1");
        ImGui::SameLineSeparator();

        ImGui::NextColumn();

        ImGui::PreSeparator(10);
        ImGui::Text("The Same Separator");
        ImGui::SameLineSeparator();
        ImGui::CenteredSeparator();
        ImGui::Text("Column 2");
        ImGui::SameLineSeparator();

        ImGui::Columns(1);
        ImGui::TextSeparator("So decorative");
        ImGui::CenteredSeparator();
    }
}

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions