Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

is there a way to know when a table cell is hovered? #6588

Closed
sodamouse opened this issue Jul 9, 2023 · 8 comments
Closed

is there a way to know when a table cell is hovered? #6588

sodamouse opened this issue Jul 9, 2023 · 8 comments

Comments

@sodamouse
Copy link

Version/Branch of Dear ImGui:

Version: 1.89.7
Branch: Docking

Back-end/Renderer/Compiler/OS

Back-ends: imgui_impl_glfw.cpp + imgui_impl.opengl3.cpp
Compiler: clang++
Operating System: Archlinux

My Issue/Question:
My objective is to have an entire row of a table highlighted with a different color, when a cell belonging to the same row is hovered. Is there a way to achieve this? I know how to do this for columns. I can get if a column is hovered using column flags, but not rows.

Screenshots/Video
None

Standalone, minimal, complete and verifiable example: (see #2261)

ImGui::TableNextColumn();
ImGui::PushID(&ENTRIES[i].title);
ImGui::PushItemWidth(-1);
ImGui::InputText("##On", &ENTRIES[i].title);
static ImU32 row_bg_color = ImGui::GetColorU32(ImVec4(0.7f, 0.3f, 0.3f, 0.65f));
if (ImGui::TableGetColumnFlags(0) & ImGuiTableColumnFlags_IsHovered)   // How to check this for rows instead?
    ImGui::TableSetBgColor(ImGuiTableBgTarget_RowBg0, row_bg_color);
(void)ImGui::PopItemWidth();
ImGui::PopID();
@sakiodre
Copy link
Contributor

sakiodre commented Jul 13, 2023

Dear ImGui really needs to add support for whole row hovers in tables, there are no official ways to do it. I had to read through a bunch of internal code to find a way to make it work.

You'll need to #include "imgui_internal.h" for this

ImGuiContext& g = *ImGui::GetCurrentContext();
if (ImGui::BeginTable("test", 3, flags))
{
    ImGuiTable* table = g.CurrentTable;

    ImGui::TableSetupColumn("a");
    ImGui::TableSetupColumn("b");
    ImGui::TableSetupColumn("c");

    ImGui::TableSetupScrollFreeze(0, 1);
    ImGui::TableHeadersRow();

    for (size_t i = 0; i < 10; i++)
    {
        ImGui::TableNextRow();
        ImGui::TableSetColumnIndex(0);
        ImGui::Text("title");

        ImGui::TableNextColumn();
        ImGui::Text("text");

        ImGui::TableNextColumn();
        ImGui::Text("properties");

        // if we don't jump to the last column
        // it will fail to calculate the rect size
        // just in case we didn't render enough columns
        ImGui::TableSetColumnIndex(table->Columns.size() - 1);

        // get the row rect
        ImRect row_rect(
            table->WorkRect.Min.x,
            table->RowPosY1,
            table->WorkRect.Max.x,
            table->RowPosY2
        );
        row_rect.ClipWith(table->BgClipRect);

        bool bHover =
            ImGui::IsMouseHoveringRect(row_rect.Min, row_rect.Max, false) &&
            ImGui::IsWindowHovered(ImGuiHoveredFlags_None) &&
            !ImGui::IsAnyItemHovered(); // optional

        if (bHover)
        {
            // override row bg color
            // see https://github.com/ocornut/imgui/blob/77eba4d0d1682917fee5638e746d5f599c47dc6e/imgui_tables.cpp#L1808
            table->RowBgColor[1] = ImGui::GetColorU32(ImGuiCol_Border); // set to any color of your choice
        }
    }

    ImGui::EndTable();
}

This will work for any row height

Recording.2023-07-13.221555.mp4

@ocornut
Copy link
Owner

ocornut commented Jul 13, 2023

Dear ImGui really needs to add support for whole row hovers in tables, there are no official ways to do it

We have limited resources and I don't have a satisfying solution for this problem yet.

See #6250 and #6347 for a fuller explanation.
The TL;DR; with this approach (equivalent to calling TableGetCellBgRect() + TableSetBgColor(), no need to copy so much code) is the hover check is only valid if you call it after every items of the row have been submitted, or if you passed the height to TableNextRow(), otherwise we don't have a reliable row height.

As mentioned in #6250 (comment) I have an internal patch for a TableGetHoveredRow() but it has a temporal incoherency with TableGetHoveredColumn() and I am not happy with that.

ocornut added a commit that referenced this issue Jul 13, 2023
…#6588, #3740)

Works with one-frame delay inconsistent with other functions, may be too bug-prone.
@ocornut
Copy link
Owner

ocornut commented Jul 13, 2023

Since this is likely going to be commonly requested, I have pushed my code for TableGetHoveredRow() in imgui_internal.h : 52125a5.
The fact that it has a latency isn't so much the problem, the problem is that it has latency while other functions don't, so I worry about side-effects for user.

Vs a solution like the one you highlighted above can work without latency but with the constraint it needs to be called at end of row. Maybe we can come with an hybrid design that provides the best of both worlds, but that design should not lead to shearing inconsistency such as two rows reporting hovered different when the calls are made).

@ocornut
Copy link
Owner

ocornut commented Jul 13, 2023

Please note that the "usual" answer to OP problem is to submit a row height manually using TableNextRow() then submit a Selectable("##nolabel", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap) filling the row, but custom hovering/highlight behavior may want to bypass the selectable.

@sodamouse
Copy link
Author

Thanks. I will follow up when I try the explanations here.

@sodamouse
Copy link
Author

sodamouse commented Jul 14, 2023

The example by @sakiodre works very well. I encountered the Selectable before when I was looking at the imgui files. Will check that solution as well as the new commit. Thanks @ocornut

@sodamouse
Copy link
Author

This issue can be marked as resolved based on the feedback provided in the comments.

@sodamouse
Copy link
Author

sodamouse commented Nov 22, 2024

For posterity's sake, this is how I currently achieve this:

{
    ImGuiTable* table = g.CurrentTable;
    u64 i = entry - visibleEntries[0];  // Some array that corresponds to table rows. I'm just calculating row index. entry is a ptr.
    ImRect rowRect(table->WorkRect.Min.x, table->RowPosY1, table->WorkRect.Max.x, table->RowPosY2);

    static constexpr auto MY_COL32_TABLE_HIGHLIGHT = IM_COL32(255,255,255,64);  // 64 is lowered alpha
    if (ImGui::TableGetHoveredRow() == i + 1)
    {
        ImGui::GetForegroundDrawList()->AddRectFilled(
            rowRect.Min,
            rowRect.Max,
            MY_COL32_TABLE_HIGHLIGHT
        );
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants