Version/Branch of Dear ImGui:
Version: 1.72 WIP
Branch: master
Back-end/Renderer/Compiler/OS
Back-ends: imgui_impl_dx11.cpp
Compiler: MSVC 2019
Operating System: Win10
My Issue/Question:
Alternate (odd-even) row background for lists and trees. Only one extra call is required (see function below), just before actual list/tree UI code. List/tree items are supposed to be of the same height (ImGui::GetTextLineHeight()), or alternatively you can specify any other height via optional argument. The color of alternate (highlighted) rows is passed as second optional argument.
I know, this is supposed to be standard functionality someday, maybe by using additional flags, but this is what I currently use and possibly it will help in any way. Otherwise, just ignore this. Feedback is appreciated.
Screenshots/Video


Standalone, minimal, complete and verifiable example:
void ItemRowsBackground(float lineHeight = -1.0f, const ImColor& color = ImColor(20, 20, 20, 64))
{
auto* drawList = ImGui::GetWindowDrawList();
const auto& style = ImGui::GetStyle();
if (lineHeight < 0)
{
lineHeight = ImGui::GetTextLineHeight();
}
lineHeight += style.ItemSpacing.y;
float scrollOffsetH = ImGui::GetScrollX();
float scrollOffsetV = ImGui::GetScrollY();
float scrolledOutLines = floorf(scrollOffsetV / lineHeight);
scrollOffsetV -= lineHeight * scrolledOutLines;
ImVec2 clipRectMin(ImGui::GetWindowPos().x, ImGui::GetWindowPos().y);
ImVec2 clipRectMax(clipRectMin.x + ImGui::GetWindowWidth(), clipRectMin.y + ImGui::GetWindowHeight());
if (ImGui::GetScrollMaxX() > 0)
{
clipRectMax.y -= style.ScrollbarSize;
}
drawList->PushClipRect(clipRectMin, clipRectMax);
bool isOdd = (static_cast<int>(scrolledOutLines) % 2) == 0;
float yMin = clipRectMin.y - scrollOffsetV + ImGui::GetCursorPosY();
float yMax = clipRectMax.y - scrollOffsetV + lineHeight;
float xMin = clipRectMin.x + scrollOffsetH + ImGui::GetWindowContentRegionMin().x;
float xMax = clipRectMin.x + scrollOffsetH + ImGui::GetWindowContentRegionMax().x;
for (float y = yMin; y < yMax; y += lineHeight, isOdd = !isOdd)
{
if (isOdd)
{
drawList->AddRectFilled({ xMin, y - style.ItemSpacing.y }, { xMax, y + lineHeight }, color);
}
}
drawList->PopClipRect();
}
// Please do not forget this!
ImGui::Begin("Example Bug");
ItemRowsBackground();
// whatever code that draws list or tree items
ImGui::End();
Hi, first of all great idea. I took it for a spin and worked right away. Just having a tiny artifact at the bottom of my scroll, the line appears and disappears while scrolling, seems like a "Z" ordering problem, any idea how I might solve this?

Hi DJLink, just a quick guess: try decrease clipRectMax.y by 1.
Hi DJLink, just a quick guess: try decrease clipRectMax.y by 1.
Ah silly me, simple enough, thank you for the help, and again for this code :)
Hello @mrduda, thanks for the suggestion and sorry for my late answer.
This will be available in the upcoming Tables API, however I do understand it may be useful even without tables.
Starting from your suggestion, I tried to rewrite it to make it simpler and improve on some points.Here's what I eventually settled on:
void DrawRowsBackground(int row_count, float line_height, float x1, float x2, float y_offset, ImU32 col_even, ImU32 col_odd)
{
ImDrawList* draw_list = ImGui::GetWindowDrawList();
float y0 = ImGui::GetCursorScreenPos().y + (float)(int)y_offset;
int row_display_start;
int row_display_end;
ImGui::CalcListClipping(row_count, line_height, &row_display_start, &row_display_end);
for (int row_n = row_display_start; row_n < row_display_end; row_n++)
{
ImU32 col = (row_n & 1) ? col_odd : col_even;
if ((col & IM_COL32_A_MASK) == 0)
continue;
float y1 = y0 + (line_height * row_n);
float y2 = y1 + line_height;
draw_list->AddRectFilled(ImVec2(x1, y1), ImVec2(x2, y2), col);
}
}
It's a little different from yours:
Usage demo:
ImGui::Begin("Manual Row background Test");
ImGui::Text("Some text before..");
float x1 = ImGui::GetCurrentWindow()->WorkRect.Min.x;
float x2 = ImGui::GetCurrentWindow()->WorkRect.Max.x;
float item_spacing_y = ImGui::GetStyle().ItemSpacing.y;
float item_offset_y = -item_spacing_y * 0.5f;
float line_height = ImGui::GetTextLineHeight() + item_spacing_y;
DrawRowsBackground(50, line_height, x1, x2, item_offset_y, 0, ImGui::GetColorU32(ImVec4(0.4f, 0.4f, 0.4f, 0.5f)));
for (int n = 0; n < 50; n++)
ImGui::Text("Item %03d", n);
ImGui::End();

Using ImGui::GetCurrentWindow()->WorkRect.Min.x / Max.x for the extents is the more correct thing to do, but this is not a currently public API, so it needs including `imgui_internal.h" to work. You may replace it with:
float x1 = ImGui::GetWindowPos().x;
float x2 = x1 + ImGui::GetWindowSize().x;
I'll close this now as the topic is available for searching. I would consider adding the function as an internal helper if it was useful but being such a simpler and potentially tweakable function it may be reasonable for people to copy it.
Thanks again!
Most helpful comment
Hello @mrduda, thanks for the suggestion and sorry for my late answer.
This will be available in the upcoming Tables API, however I do understand it may be useful even without tables.
Starting from your suggestion, I tried to rewrite it to make it simpler and improve on some points.Here's what I eventually settled on:
It's a little different from yours:
Usage demo:
Using
ImGui::GetCurrentWindow()->WorkRect.Min.x / Max.xfor the extents is the more correct thing to do, but this is not a currently public API, so it needs including `imgui_internal.h" to work. You may replace it with:I'll close this now as the topic is available for searching. I would consider adding the function as an internal helper if it was useful but being such a simpler and potentially tweakable function it may be reasonable for people to copy it.
Thanks again!