Tables: Try to report contents width to outer window, generally better auto-fit.

This commit is contained in:
omar 2020-05-13 23:42:22 +02:00 committed by ocornut
parent 466b6e619a
commit dff26191bd
3 changed files with 63 additions and 30 deletions

View File

@ -3570,6 +3570,24 @@ static void ShowDemoWindowTables()
}
ImGui::EndTable();
}
if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_SizingPolicyFixedX))
{
ImGui::TableSetupColumn("One");
ImGui::TableSetupColumn("Two");
ImGui::TableSetupColumn("Three");
ImGui::TableAutoHeaders();
for (int row = 0; row < 6; row++)
{
ImGui::TableNextRow();
for (int column = 0; column < 3; column++)
{
ImGui::TableSetColumnIndex(column);
ImGui::Text("Fixed %d,%d", row, column);
}
}
ImGui::EndTable();
}
ImGui::TreePop();
}

View File

@ -1981,9 +1981,9 @@ struct ImGuiTable
float CellSpacingX; // Spacing between non-bordered cells
float LastOuterHeight; // Outer height from last frame
float LastFirstRowHeight; // Height of first row from last frame
float ColumnsTotalWidth;
float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
float IdealTotalWidth; // Sum of ideal column width for nothing to be clipped
float ColumnsTotalWidth; // Sum of current column width
float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window
float ResizedColumnNextWidth;
ImRect OuterRect; // Note: OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
ImRect WorkRect;

View File

@ -558,13 +558,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// (can't make auto padding larger than what WorkRect knows about so right-alignment matches)
const ImRect work_rect = table->WorkRect;
const float padding_auto_x = table->CellPaddingX2;
const float spacing_auto_x = table->CellSpacingX * (1.0f + 2.0f); // CellSpacingX is >0.0f when there's no vertical border, in which case we add two extra CellSpacingX to make auto-fit look nice instead of cramped. We may want to expose this somehow.
const float min_column_width = TableGetMinColumnWidth();
int count_fixed = 0;
float width_fixed = 0.0f;
float total_weights = 0.0f;
table->LeftMostStretchedColumnDisplayOrder = -1;
table->IdealTotalWidth = 0.0f;
table->ColumnsAutoFitWidth = 0.0f;
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
if (!(table->ActiveMaskByDisplayOrder & ((ImU64)1 << order_n)))
@ -591,7 +592,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (!(table->Flags & ImGuiTableFlags_NoHeadersWidth) && !(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth))
column_width_ideal = ImMax(column_width_ideal, column_content_width_headers);
column_width_ideal = ImMax(column_width_ideal + padding_auto_x, min_column_width);
table->IdealTotalWidth += column_width_ideal;
table->ColumnsAutoFitWidth += column_width_ideal;
if (column->Flags & (ImGuiTableColumnFlags_WidthAlwaysAutoResize | ImGuiTableColumnFlags_WidthFixed))
{
@ -623,6 +624,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
}
}
// CellSpacingX is >0.0f when there's no vertical border, in which case we add two extra CellSpacingX to make auto-fit look nice instead of cramped.
// We may want to expose this somehow.
table->ColumnsAutoFitWidth += spacing_auto_x * (table->ColumnsActiveCount - 1);
// Layout
// Remove -1.0f to cancel out the +1.0f we are doing in EndTable() to make last column line visible
const float width_spacings = table->CellSpacingX * (table->ColumnsActiveCount - 1);
@ -956,28 +961,6 @@ void ImGui::EndTable()
table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
table->LastOuterHeight = table->OuterRect.GetHeight();
// Store content width reference for each column
float max_pos_x = inner_window->DC.CursorMaxPos.x;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
// Store content width (for both Headers and Rows)
//float ref_x = column->MinX;
float ref_x_rows = column->StartXRows - table->CellPaddingX1;
float ref_x_headers = column->StartXHeaders - table->CellPaddingX1;
column->ContentWidthRowsFrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsFrozen - ref_x_rows);
column->ContentWidthRowsUnfrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsUnfrozen - ref_x_rows);
column->ContentWidthHeadersUsed = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersUsed - ref_x_headers);
column->ContentWidthHeadersIdeal = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersIdeal - ref_x_headers);
// Add an extra 1 pixel so we can see the last column vertical line if it lies on the right-most edge.
if (table->ActiveMaskByIndex & ((ImU64)1 << column_n))
max_pos_x = ImMax(max_pos_x, column->MaxX + 1.0f);
}
inner_window->DC.CursorMaxPos.x = max_pos_x;
if (!(flags & ImGuiTableFlags_NoClipX))
inner_window->DrawList->PopClipRect();
inner_window->ClipRect = inner_window->DrawList->_ClipRectStack.back();
@ -1015,16 +998,16 @@ void ImGui::EndTable()
}
// Layout in outer window
const float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
const float backup_outer_max_pos_x = outer_window->DC.CursorMaxPos.x;
const float backup_inner_max_pos_x = inner_window->DC.CursorMaxPos.x;
inner_window->WorkRect = table->HostWorkRect;
inner_window->SkipItems = table->HostSkipItems;
outer_window->DC.CursorPos = table->OuterRect.Min;
outer_window->DC.ColumnsOffset.x = 0.0f;
if (inner_window != outer_window)
{
// Override EndChild's ItemSize with our own to enable auto-resize on the X axis when possible
float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
EndChild();
outer_window->DC.CursorMaxPos.x = backup_outer_cursor_pos_x + table->ColumnsTotalWidth + 1.0f + inner_window->ScrollbarSizes.x;
}
else
{
@ -1034,6 +1017,38 @@ void ImGui::EndTable()
ItemSize(item_size);
}
// Store content width reference for each column
float max_pos_x = backup_inner_max_pos_x;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
// Store content width (for both Headers and Rows)
//float ref_x = column->MinX;
float ref_x_rows = column->StartXRows - table->CellPaddingX1;
float ref_x_headers = column->StartXHeaders - table->CellPaddingX1;
column->ContentWidthRowsFrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsFrozen - ref_x_rows);
column->ContentWidthRowsUnfrozen = (ImS16)ImMax(0.0f, column->ContentMaxPosRowsUnfrozen - ref_x_rows);
column->ContentWidthHeadersUsed = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersUsed - ref_x_headers);
column->ContentWidthHeadersIdeal = (ImS16)ImMax(0.0f, column->ContentMaxPosHeadersIdeal - ref_x_headers);
// Add an extra 1 pixel so we can see the last column vertical line if it lies on the right-most edge.
if (table->ActiveMaskByIndex & ((ImU64)1 << column_n))
max_pos_x = ImMax(max_pos_x, column->MaxX + 1.0f);
}
// Override EndChild/ItemSize max extent with our own to enable auto-resize on the X axis when possible
// FIXME-TABLE: This can be improved (e.g. for Fixed columns we don't want to auto AutoFitWidth? or propagate window auto-fit to table?)
if (table->Flags & ImGuiTableFlags_ScrollX)
{
inner_window->DC.CursorMaxPos.x = max_pos_x; // Set contents width for scrolling
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, backup_outer_cursor_pos_x + table->ColumnsTotalWidth + 1.0f + inner_window->ScrollbarSizes.x); // For auto-fit
}
else
{
outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, table->WorkRect.Min.x + table->ColumnsAutoFitWidth); // For auto-fit
}
// Save settings
if (table->IsSettingsDirty)
TableSaveSettings(table);
@ -2571,7 +2586,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));
if (!open)
return;
BulletText("OuterWidth: %.1f, InnerWidth: %.1f%s, IdealWidth: %.1f", table->OuterRect.GetWidth(), table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "", table->IdealTotalWidth);
BulletText("OuterWidth: %.1f, InnerWidth: %.1f%s, ColumnsWidth: %.1f, AutoFitWidth: %.1f", table->OuterRect.GetWidth(), table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth);
for (int n = 0; n < table->ColumnsCount; n++)
{
ImGuiTableColumn* column = &table->Columns[n];