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

When using MultiSelect with BoxSelect in a Table with ScrollY and BordersOuter, items sometimes get skipped #7970

Closed
bratpilz opened this issue Sep 10, 2024 · 4 comments

Comments

@bratpilz
Copy link

Version/Branch of Dear ImGui:

Version 1.91.2 WIP, Branch: master

Back-ends:

imgui_impl_glfw.cpp + imgui_impl_opengl3.cpp

Compiler, OS:

Linux + GCC

Full config/build information:

Dear ImGui 1.91.2 WIP (19112)
--------------------------------
sizeof(size_t): 8, sizeof(ImDrawIdx): 2, sizeof(ImDrawVert): 20
define: __cplusplus=201103
define: __linux__
define: __GNUC__=12
--------------------------------
io.BackendPlatformName: imgui_impl_glfw
io.BackendRendererName: imgui_impl_opengl3
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: 1280.00,720.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:

Hello! As described in the title, I've noticed that MultiSelect_BoxSelect1d sometimes skips items when the Table has the ScrollY and BordersOuter flags set. The BordersInner flag seems to have no effect either way, probably because it doesn't change the layout of the table like the BordersOuter flag does.

Screenshots/Video:

multi-select-borders-outer-issue.mp4

Minimal, Complete and Verifiable Example code:

// Here's some code anyone can copy and paste to reproduce your issue
	  using namespace ImGui;
	  SetNextWindowSize (ImVec2 (400.0f, 300.0f), ImGuiCond_Appearing);
	  Begin ("Test");
	  static int flags = ImGuiTableFlags_ScrollY;
	  CheckboxFlags ("BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
	  SameLine();
	  CheckboxFlags ("BordersInner", &flags, ImGuiTableFlags_BordersInner);
	  if (BeginTable ("Table", 1, flags))
	    {
	      static ImGuiSelectionBasicStorage selection;
	      static unsigned const N = 1000;
	      auto ms = BeginMultiSelect (ImGuiMultiSelectFlags_BoxSelect1d, selection.Size, N);
	      selection.ApplyRequests (ms);
	      for (unsigned i = 0; i < N; ++i)
		{
		  char buf[32];
		  snprintf (buf, sizeof buf, "Item %03d", i);
		  SetNextItemSelectionUserData (i);
		  TableNextColumn();
		  Selectable (buf, selection.Contains (i));
		}
	      ms = EndMultiSelect();
	      selection.ApplyRequests (ms);
	      EndTable();
	    }
	  End();
@ocornut
Copy link
Owner

ocornut commented Sep 10, 2024

Thanks for the reporting this. The box-select system requires very precise matching of how cliprect clips item logic, and I guess there is a calculation in there will a mismatch due to border size which breaks it. Will investigate.

@ocornut
Copy link
Owner

ocornut commented Sep 12, 2024

Some details:

Specifically caused by adding:

if (inner_window->DecoOuterSizeY2 == 0.0f)
    table->HostClipRect.Max.y = ImMax(table->HostClipRect.Max.y - TABLE_BORDER_SIZE, table->HostClipRect.Min.y);

and changing:

table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;

to

table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y;

So there's what I do, add a dynamic toggle to either of the change:

    if (g.IO.KeyShift)
        table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y; // this problem fixed
    else
        table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : table->HostClipRect.Max.y; // this problem exists

Then I look in Metrics->Tables and Metrics->Tools->Show Rectangles to visualize what values are affected:

toggle

Commit 864a2bf moved the Max.y of table->HostClipRect, table->InnerClipRect, table->BackgroundClipRect and column's ColumnsClipRect up by 1.0f (from 395 to 394), which in turns affected the ImDrawCmd's ClipRect the same way. That seems correct and desirable to align with the intent of that fix.

The problem is that at the time of the call BeginMultiSelect() we haven't submitted the first table row, meaning TableUpdateLayout() was not called yet, and BeginMultiSelect()->BeginBoxSelect() which is passed CalcScopeRect() is essentially using the rectangle before entering into the table.

It didn't happen before that fix because before it the value of Max.y didn't change between/after entering the table.

My fix b847c41 for #7821 (also your issue) was a bit flawed since it basically aim to "predict" what the ClipRect will be when inside the table. So essentially it is that fix for #7821 which is in fault.

Additionally, subtly, this logic means that the value of CalcScopeRect() in BeginMultiSelect() is incorrect while the one in EndMultiSelect() is correct.

One possible solution would be to store a window->DecoInnerSizeY2 and use that in CalcScopeRect(), which would rely on temporal coherency but this is already what we do for the top border anyhow. I'm not yet sure what's the best course of action.

ocornut added a commit that referenced this issue Sep 12, 2024
…while drag-scrolling in a table with outer borders. (#7970, #7821).

See "widgets_multiselect_boxselect_2" test.
ocornut added a commit to ocornut/imgui_test_engine that referenced this issue Sep 12, 2024
@ocornut
Copy link
Owner

ocornut commented Sep 12, 2024

Pushed a fix 4d00bf8

And a test: ocornut/imgui_test_engine@ec15ef4

@ocornut ocornut closed this as completed Sep 12, 2024
@bratpilz
Copy link
Author

Thanks for the fix and the detailed explanation!

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

2 participants