Tables: Additionally commentary about clipper in the demo + minor padding tweak.

This commit is contained in:
ocornut 2020-11-03 18:47:05 +01:00
parent 94d99f9d0b
commit fe6131168a
4 changed files with 28 additions and 18 deletions

View File

@ -2246,8 +2246,9 @@ struct ImDrawChannel
ImVector<ImDrawIdx> _IdxBuffer; ImVector<ImDrawIdx> _IdxBuffer;
}; };
// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order. // Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.
// This is used by the Columns api, so items of each column can be batched together in a same draw call. // This is used by the Columns/Tables API, so items of each column can be batched together in a same draw call.
struct ImDrawListSplitter struct ImDrawListSplitter
{ {
int _Current; // Current channel number (0) int _Current; // Current channel number (0)

View File

@ -3755,7 +3755,7 @@ static void ShowDemoWindowTables()
if (open_action != -1) if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Vertical scrolling")) if (ImGui::TreeNode("Vertical scrolling, with clipping"))
{ {
HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items."); HelpMarker("Here we activate ScrollY, which will create a child window container to allow hosting scrollable contents.\n\nWe also demonstrate using ImGuiListClipper to virtualize the submission of many items.");
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
@ -3774,6 +3774,8 @@ static void ShowDemoWindowTables()
ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Two", ImGuiTableColumnFlags_None);
ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None); ImGui::TableSetupColumn("Three", ImGuiTableColumnFlags_None);
ImGui::TableHeadersRow(); ImGui::TableHeadersRow();
// Demonstrate using clipper for large vertical lists
ImGuiListClipper clipper; ImGuiListClipper clipper;
clipper.Begin(1000); clipper.Begin(1000);
while (clipper.Step()) while (clipper.Step())
@ -4393,6 +4395,7 @@ static void ShowDemoWindowTables()
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action); ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action);
ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, -1.0f, MyItemColumnID_Quantity); ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, -1.0f, MyItemColumnID_Quantity);
ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible ImGui::TableSetupScrollFreeze(0, 1); // Make row always visible
ImGui::TableHeadersRow();
// Sort our data if sort specs have been changed! // Sort our data if sort specs have been changed!
if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs()) if (ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs())
@ -4405,13 +4408,13 @@ static void ShowDemoWindowTables()
sorts_specs->SpecsDirty = false; sorts_specs->SpecsDirty = false;
} }
// Display data // Demonstrate using clipper for large vertical lists
ImGui::TableHeadersRow();
ImGuiListClipper clipper; ImGuiListClipper clipper;
clipper.Begin(items.Size); clipper.Begin(items.Size);
while (clipper.Step()) while (clipper.Step())
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
{ {
// Display a data item
MyItem* item = &items[row_n]; MyItem* item = &items[row_n];
ImGui::PushID(item->ID); ImGui::PushID(item->ID);
ImGui::TableNextRow(); ImGui::TableNextRow();
@ -4448,7 +4451,7 @@ static void ShowDemoWindowTables()
static int freeze_cols = 1; static int freeze_cols = 1;
static int freeze_rows = 1; static int freeze_rows = 1;
static int items_count = IM_ARRAYSIZE(template_items_names); static int items_count = IM_ARRAYSIZE(template_items_names);
static ImVec2 outer_size_value = ImVec2(0, TEXT_BASE_HEIGHT * 15); static ImVec2 outer_size_value = ImVec2(0, TEXT_BASE_HEIGHT * 12);
static float row_min_height = 0.0f; // Auto static float row_min_height = 0.0f; // Auto
static float inner_width_with_scroll = 0.0f; // Auto-extend static float inner_width_with_scroll = 0.0f; // Auto-extend
static bool outer_size_enabled = true; static bool outer_size_enabled = true;
@ -4609,14 +4612,16 @@ static void ShowDemoWindowTables()
// FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here? // FIXME-TABLE FIXME-NAV: How we can get decent up/down even though we have the buttons here?
ImGui::PushButtonRepeat(true); ImGui::PushButtonRepeat(true);
#if 1 #if 1
// Demonstrate using clipper for large vertical lists
ImGuiListClipper clipper; ImGuiListClipper clipper;
clipper.Begin(items.Size); clipper.Begin(items.Size);
while (clipper.Step()) while (clipper.Step())
{ {
for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++) for (int row_n = clipper.DisplayStart; row_n < clipper.DisplayEnd; row_n++)
#else #else
// Without clipper
{ {
for (int row_n = 0; row_n < items_count; row_n++) for (int row_n = 0; row_n < items.Size; row_n++)
#endif #endif
{ {
MyItem* item = &items[row_n]; MyItem* item = &items[row_n];
@ -4691,6 +4696,7 @@ static void ShowDemoWindowTables()
} }
ImGui::PopButtonRepeat(); ImGui::PopButtonRepeat();
// Store some info to display debug details below
table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY()); table_scroll_cur = ImVec2(ImGui::GetScrollX(), ImGui::GetScrollY());
table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY()); table_scroll_max = ImVec2(ImGui::GetScrollMaxX(), ImGui::GetScrollMaxY());
table_draw_list = ImGui::GetWindowDrawList(); table_draw_list = ImGui::GetWindowDrawList();
@ -4703,7 +4709,8 @@ static void ShowDemoWindowTables()
ImGui::SameLine(0.0f, 0.0f); ImGui::SameLine(0.0f, 0.0f);
const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size; const int table_draw_list_draw_cmd_count = table_draw_list->CmdBuffer.Size;
if (table_draw_list == parent_draw_list) if (table_draw_list == parent_draw_list)
ImGui::Text(": DrawCmd: +%d (in same window)", table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count); ImGui::Text(": DrawCmd: +%d (in same window)",
table_draw_list_draw_cmd_count - parent_draw_list_draw_cmd_count);
else else
ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)", ImGui::Text(": DrawCmd: +%d (in child window), Scroll: (%.f/%.f) (%.f/%.f)",
table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y); table_draw_list_draw_cmd_count - 1, table_scroll_cur.x, table_scroll_max.x, table_scroll_cur.y, table_scroll_max.y);
@ -4860,8 +4867,10 @@ static void ShowDemoWindowColumns()
ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f); ImVec2 child_size = ImVec2(0, ImGui::GetFontSize() * 20.0f);
ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar); ImGui::BeginChild("##ScrollingRegion", child_size, false, ImGuiWindowFlags_HorizontalScrollbar);
ImGui::Columns(10); ImGui::Columns(10);
// Also demonstrate using clipper for large vertical lists
int ITEMS_COUNT = 2000; int ITEMS_COUNT = 2000;
ImGuiListClipper clipper; // Also demonstrate using the clipper for large list ImGuiListClipper clipper;
clipper.Begin(ITEMS_COUNT); clipper.Begin(ITEMS_COUNT);
while (clipper.Step()) while (clipper.Step())
{ {

View File

@ -1914,8 +1914,8 @@ struct ImGuiTableColumn
bool IsVisible; // Is the column not marked Hidden by the user? (could be clipped by scrolling, etc). bool IsVisible; // Is the column not marked Hidden by the user? (could be clipped by scrolling, etc).
bool IsVisibleNextFrame; bool IsVisibleNextFrame;
bool IsClipped; // Set when not overlapping the host window clipping rectangle. bool IsClipped; // Set when not overlapping the host window clipping rectangle.
bool SkipItems; bool IsSkipItems;
ImGuiNavLayer NavLayerCurrent; ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
ImS8 DisplayOrder; // Index within Table's IndexToDisplayOrder[] (column may be reordered by users) ImS8 DisplayOrder; // Index within Table's IndexToDisplayOrder[] (column may be reordered by users)
ImS8 IndexWithinVisibleSet; // Index within visible set (<= IndexToDisplayOrder) ImS8 IndexWithinVisibleSet; // Index within visible set (<= IndexToDisplayOrder)
ImS8 PrevVisibleColumn; // Index of prev visible column within Columns[], -1 if first visible column ImS8 PrevVisibleColumn; // Index of prev visible column within Columns[], -1 if first visible column

View File

@ -761,7 +761,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
const int column_n = table->DisplayOrderToIndex[order_n]; const int column_n = table->DisplayOrderToIndex[order_n];
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
column->NavLayerCurrent = (table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main; column->NavLayerCurrent = (ImS8)((table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main);
if (table->FreezeColumnsCount > 0 && table->FreezeColumnsCount == visible_n) if (table->FreezeColumnsCount > 0 && table->FreezeColumnsCount == visible_n)
offset_x += work_rect.Min.x - table->OuterRect.Min.x; offset_x += work_rect.Min.x - table->OuterRect.Min.x;
@ -777,7 +777,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->ClipRect.Max.x = offset_x; column->ClipRect.Max.x = offset_x;
column->ClipRect.Max.y = FLT_MAX; column->ClipRect.Max.y = FLT_MAX;
column->ClipRect.ClipWithFull(host_clip_rect); column->ClipRect.ClipWithFull(host_clip_rect);
column->IsClipped = column->SkipItems = true; column->IsClipped = column->IsSkipItems = true;
continue; continue;
} }
@ -813,7 +813,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (column->IsClipped) if (column->IsClipped)
table->VisibleUnclippedMaskByIndex &= ~((ImU64)1 << column_n); // Columns with the _WidthAlwaysAutoResize sizing policy will never be updated then. table->VisibleUnclippedMaskByIndex &= ~((ImU64)1 << column_n); // Columns with the _WidthAlwaysAutoResize sizing policy will never be updated then.
column->SkipItems = !column->IsVisible || table->HostSkipItems; column->IsSkipItems = !column->IsVisible || table->HostSkipItems;
// Detect hovered column // Detect hovered column
if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x) if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x)
@ -1346,7 +1346,7 @@ void ImGui::TableUpdateDrawChannels(ImGuiTable* table)
const int channels_for_dummy = (table->ColumnsVisibleCount < table->ColumnsCount || table->VisibleUnclippedMaskByIndex != table->VisibleMaskByIndex) ? +1 : 0; const int channels_for_dummy = (table->ColumnsVisibleCount < table->ColumnsCount || table->VisibleUnclippedMaskByIndex != table->VisibleMaskByIndex) ? +1 : 0;
const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy; const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;
table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total); table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total);
table->DummyDrawChannel = (channels_for_dummy > 0) ? (ImU8)(channels_total - 1) : -1; table->DummyDrawChannel = (ImU8)((channels_for_dummy > 0) ? channels_total - 1 : -1);
table->BgDrawChannelUnfrozen = (ImU8)((table->FreezeRowsCount > 0) ? channels_for_row + 1 : 0); table->BgDrawChannelUnfrozen = (ImU8)((table->FreezeRowsCount > 0) ? channels_for_row + 1 : 0);
int draw_channel_current = 1; int draw_channel_current = 1;
@ -1804,7 +1804,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
column->NavLayerCurrent = (column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main; column->NavLayerCurrent = (ImS8)((column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main);
} }
if (unfreeze_rows_actual) if (unfreeze_rows_actual)
{ {
@ -1858,7 +1858,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT
window->DC.CurrLineTextBaseOffset = table->RowTextBaseline; window->DC.CurrLineTextBaseOffset = table->RowTextBaseline;
window->DC.LastItemId = 0; window->DC.LastItemId = 0;
window->DC.NavLayerCurrent = column->NavLayerCurrent; window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent;
window->WorkRect.Min.y = window->DC.CursorPos.y; window->WorkRect.Min.y = window->DC.CursorPos.y;
window->WorkRect.Min.x = column->MinX + table->CellPaddingX + table->CellSpacingX1; window->WorkRect.Min.x = column->MinX + table->CellPaddingX + table->CellSpacingX1;
@ -1868,7 +1868,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
if (!column->IsVisible) if (!column->IsVisible)
window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2); window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2);
window->SkipItems = column->SkipItems; window->SkipItems = column->IsSkipItems;
if (table->Flags & ImGuiTableFlags_NoClip) if (table->Flags & ImGuiTableFlags_NoClip)
{ {
table->DrawSplitter.SetCurrentChannel(window->DrawList, 1); table->DrawSplitter.SetCurrentChannel(window->DrawList, 1);