imgui icon indicating copy to clipboard operation
imgui copied to clipboard

How do I get a Selectable to fill a table cell/row height?

Open lailoken opened this issue 9 months ago • 2 comments

Version/Branch of Dear ImGui:

1.92.0 WIP

Back-ends:

any

Compiler, OS:

any

Full config/build information:

No response

Details:

My Question:

I have a table with texts and selectables. I want:

  • The selectable must always fill the full row height exactly, no matter the current CellPadding (or ItemSpacing)
  • The selectable text must still align vertically with normal text on the row.

In my example I explicitly call TableNextRow() with a height because I sometimes don't have anything to render on certain lines and I want the line heights to be consistent (for clipper etc.)

This is a simplified example of what I'm trying to do, in reality I may not even know in my table loop whether I am rendering a selectable or text (that is determined in a called module).

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

void test()
{
    ImGui::Begin("Test", nullptr, LocalConfig::ViewportWindowFlags());
    ImGui::BeginTable("Test", 2, ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders);
    const float rowHeight = ImGui::GetTextLineHeight() + ImGui::GetStyle().CellPadding.y * 2;  // force height, even if we don't have text
    for (int i = 0; i < 10; i++)
    {
        ImGui::TableNextRow(ImGuiTableRowFlags_None, rowHeight);
        ImGui::PushID(i);
        ImGui::TableNextColumn();
        ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.5f, 0.f));
        ImGui::Selectable("Selectable", false, ImGuiSelectableFlags_SpanAllColumns);
        ImGui::PopStyleVar();
        ImGui::TableNextColumn();
        ImGui::Text("Text");
        ImGui::PopID();
    }
    ImGui::EndTable();
    ImGui::End();
}

lailoken avatar Apr 01 '25 13:04 lailoken

Out of curiosity are you using the Selectable() only for highlight or as a clicking device?

We ought to add a ImGuiTableFlags_HighlightHoveredRow (#8498) but you could technically use TableSetBgColor().

The selectable text must still align vertically with normal text on the row.

For this, in case you end up manually submitting a Selectable() from the top of the cell, the simpler may be to submit a Selectable() with no label, and the Text() separately.

But we ought to aim to support that a little better, e.g. hypothetically a ImGuiSelectableFlags_SpanAllRow could alter Y1/Y2 of the selectable.

ocornut avatar Apr 01 '25 21:04 ocornut

I use it mostly as buttons but with variations.

Sometimes we:

  • Show selection state,
  • Right click context
  • Left click to select or execute (sometimes also double click)
  • Sometimes we span all columns, and other times not.
  • (or combintations of these)

What I want is a way to fill the entire cell/row with the selection, up to the edges (ignoring frame/item/cell-padding whaever it is at the time)

Not this:

Image

I have found ways to do it, but then I have text alignment issues (which I then need to solve by just writing text and using a blank selection overlay). But I would prefer to avoid this. For now it's purely aesthetic, not a big problem.

lailoken avatar Apr 15 '25 15:04 lailoken

My hack for aligned selectable, as someone might find it useful till a proper solution arrives. The sgr object is a RAII wrapper for styling, and Color class inherits from ImColor

            const ImGuiSelectableFlags sflags =
                ImGuiSelectableFlags_SpanAllColumns
                | ImGuiSelectableFlags_AllowItemOverlap
                | ImGuiSelectableFlags_AllowDoubleClick;

            // Disable selectables interaction styling, we're going to fake draw it ourselves using ImGuiTableBgTarget_RowBg0
            sgr.PushColor( ImGuiCol_Header, Colors::Transparent );
            sgr.PushColor( ImGuiCol_HeaderHovered, Colors::Transparent );
            sgr.PushColor( ImGuiCol_HeaderActive, Colors::Transparent );

            ImGuiTable * imtable = GetCurrentTable();
            BOOST_ASSERT_MSG( imtable, "Expected valid ImGuiTable in DrawSingleRowList" );
            AlignTextToFramePadding();
            // Hack for selectable to fill entire cell; https://github.com/ocornut/imgui/issues/5615
            sgr.PushStyleVar( &ImGuiStyle::ItemSpacing, ImVec2{ sgr->ItemSpacing.x, sgr->CellPadding.y * 4.f } );
            const bool activated = Selectable( first_label.c_str(), selected, sflags );
            const bool hovered = IsItemHovered();
            const bool held = IsItemActive();
            // Copy and paste color selection logic from selectable widget
            if ( hovered || selected )
            {
                Color col;
                if ( selected && !hovered )
                {
                    col = ImLerp( Colors::editor::SchemaRowSelection * Colors::Transparent40,
                        Colors::editor::SchemaRowHover * Colors::Transparent30,
                        0.5f );
                }
                else
                {
                    col = ( held && hovered ) ? ( Colors::editor::SchemaRowSelection * Colors::Transparent60 )
                        : hovered ? ( Colors::editor::SchemaRowHover * Colors::Transparent40 )
                        : ( Colors::editor::SchemaRowSelection * Colors::Transparent10 );
                }

                // actually set the color for an entire row
                TableSetBgColor( ImGuiTableBgTarget_RowBg0, col, -1 );
            }

results in following, the bar on the left is not included :)

Image

Riztazz avatar Oct 17 '25 12:10 Riztazz