ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
57.5k stars 9.89k forks source link

Text followed by SameLine and then SmallButton inside table cell disables SmallButton #7703

Open leidegre opened 1 week ago

leidegre commented 1 week ago

Version/Branch of Dear ImGui:

Version 1.90.4, Branch: master

Back-ends:

imgui_impl_win32.cpp + imgui_impl_dx12.cpp

Compiler, OS:

Windows 11 + MSVC 2022

Full config/build information:

Dear ImGui 1.90.4 (19040)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=199711
define: _WIN32
define: _WIN64
define: _MSC_VER=1937
define: _MSVC_LANG=202002
--------------------------------
io.BackendPlatformName: imgui_impl_win32
io.BackendRendererName: imgui_impl_dx12
io.ConfigFlags: 0x00000003
 NavEnableKeyboard
 NavEnableGamepad
io.ConfigInputTextCursorBlink
io.ConfigWindowsResizeFromEdges
io.ConfigMemoryCompactTimer = 60.0
io.BackendFlags: 0x0000000E
 HasMouseCursors
 HasSetMousePos
 RendererHasVtxOffset
--------------------------------
io.Fonts: 1 fonts, Flags: 0x00000000, TexSize: 512,64
io.DisplaySize: 1957.00,1072.00
io.DisplayFramebufferScale: 1.00,1.00
--------------------------------
style.WindowPadding: 8.00,8.00
style.WindowBorderSize: 1.00
style.FramePadding: 4.00,3.00
style.FrameRounding: 0.00
style.FrameBorderSize: 0.00
style.ItemSpacing: 8.00,4.00
style.ItemInnerSpacing: 4.00,4.00

Details:

My Issue/Question:

The issue I'm having is that when I try to use SameLine the button is not interactable.

Please see attached video.

Screenshots/Video:

https://github.com/ocornut/imgui/assets/63085/e6d15e05-b3df-4b03-b5c0-fefccde2d787

Minimal, Complete and Verifiable Example code:

I do think it's reproducible in the demo by adding a few lines to the advance table section. It's not the exact same problem but in this case the button disappears so I'm assuming there's something with the way the sizing calculation that's going wrong here. My problem is specially egregious because the button is visible but just not interactable.

// Try adding these lines 5871-5872 to the demo app
ImGui::Text("Oh no");
ImGui::SameLine();

The advanced table demo app column index 2 should look like this

if (ImGui::TableSetColumnIndex(2))
{
    ImGui::Text("Oh no");
    ImGui::SameLine();
    if (ImGui::SmallButton("Chop")) { item->Quantity += 1; }
    if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
    ImGui::SameLine();
    if (ImGui::SmallButton("Eat")) { item->Quantity -= 1; }
    if (sorts_specs_using_quantity && ImGui::IsItemDeactivated()) { items_need_sort = true; }
}

I can't see that the column is using a fixed width, and I've tried that as well. Doesn't seem to work. Any help or insight would be much appricated.

leidegre commented 1 week ago

I could be completely wrong here and there's ofcourse something I'm doing that's wrong with the selectable row. Seems like it's eating the click or something. I can only get it to work if I get a button on a different line.

Here's the complete code for the table.

void game::show_data_explorer_debug_window(Game_State* state) {
  if (!ImGui::Begin("Data Explorer", &state->tools_.data_explorer_.show_)) {
    ImGui::End();
    return; // early out
  }

  auto table_flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg;
  auto table_outer_size = ImVec2(0.0f, ImGui::GetTextLineHeightWithSpacing() * 8);

  static ImGuiTextFilter filter;

  filter.Draw();
  // ImGui::SameLine();
  if (ImGui::Button("Clear")) {
    filter.Clear();
  }

  // todo: scratch allocator
  List<int> filtered = { .allocator_ = state->frame_allocator_ };
  defer (filtered.destroy());
  for (int i = 0; i < (int)Asset_Table_Size; i += 1) {
    const Asset& asset = Asset_Table[i];
    if (filter.PassFilter(asset.path_.begin(), asset.path_.end())) {
      filtered.add(i);
    }
  }

  if (ImGui::BeginTable("Assets Table", 2, table_flags, table_outer_size)) {
    ImGui::TableSetupScrollFreeze(0, 1);
    ImGui::TableSetupColumn("Path", ImGuiTableColumnFlags_None, 0, 0);
    ImGui::TableSetupColumn("Mem", ImGuiTableColumnFlags_WidthFixed, 100, 1);
    ImGui::TableHeadersRow();

    ImGuiListClipper clipper;
    clipper.Begin((int)filtered.size());
    while (clipper.Step())
    {
        for (int row = clipper.DisplayStart; row < clipper.DisplayEnd; row++)
        {
            auto& asset = Asset_Table[filtered[row]];

            ImGui::PushID(row);
            ImGui::TableNextRow();

            ImGui::TableSetColumnIndex(0);

            bool is_selected = state->tools_.data_explorer_.selected_asset_ == &asset;
            if (ImGui::Selectable(asset.path_.begin(), &is_selected, ImGuiSelectableFlags_SpanAllColumns)) {
              state->tools_.data_explorer_.selected_asset_ = &asset;
            }

            // don't know if we need these, maybe it's enough to just do filename
            ImGui::TableSetColumnIndex(1);
            ImGui::Text("%zu", asset.data_.size()); // Size of this asset in memory, if it is zero then it is not loaded.

            // Does not work, will render button non-interactable.
            ImGui::SameLine();

            if (0 < asset.data_.size()) {
              if (ImGui::SmallButton("Reload")) { 
                // ...
              }              
            } else {
              if (ImGui::SmallButton("Load")) { 
                OR_ABORT(load_asset(&asset));
              }
            }

            ImGui::PopID();
        }
    }

    ImGui::EndTable();
  }

  ImGui::End();
}
leidegre commented 1 week ago

Tried 1.90.8 unfortunately it didn't fix my issue.

lukaasm commented 1 week ago

use ImGui::SetNextItemAllowOverlap() before selectable

When multiple widgets fight over same interactive air-space ( selectable and button in this case ), first one that is encountered consumes action by default( selectable ). You can change this behaviour by allowing overlap on item that consumed your actions with side-effect that click action will be delayed by a frame

leidegre commented 1 week ago

use ImGui::SetNextItemAllowOverlap() before selectable

@lukaasm Great, thanks this works 👍Do you know what makes my code special? This doesn't seem to be used in the advanced table demo.

lukaasm commented 1 week ago

Do you know what makes my code special? This doesn't seem to be used in the advanced table demo.

Because in Advanced table demo Selectable is submited with: ImGuiSelectableFlags_AllowOverlap flag which enables same behaviour as calling ImGui::SetNextItemAllowOverlap()

ImGuiSelectableFlags selectable_flags = (contents_type == CT_SelectableSpanRow) ? ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap : ImGuiSelectableFlags_None;
if (ImGui::Selectable(label, item_is_selected, selectable_flags, ImVec2(0, row_min_height)))