Tables: Renamed ResizeWeight->WidthStretchWeight, WidthRequested->WidthFixedRequest, clarififications, comments.

This commit is contained in:
omar 2020-05-22 15:27:53 +02:00 committed by ocornut
parent 23c60b2814
commit bc170e7325
3 changed files with 76 additions and 75 deletions

View File

@ -1897,9 +1897,9 @@ struct ImGuiTableColumn
ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_ ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_
float MinX; // Absolute positions float MinX; // Absolute positions
float MaxX; float MaxX;
float ResizeWeight; // ~1.0f. Master width data when (Flags & _WidthStretch) float WidthStretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
float WidthRequested; // Master width data when !(Flags & _WidthStretch) float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from WidthStretchWeight in TableUpdateLayout()
float WidthGiven; // == (MaxX - MinX). FIXME-TABLE: Store all persistent width in multiple of FontSize? float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be >WidthRequest to honor minimum width, may be <WidthRequest to honor shrinking columns down in tight space.
float StartXRows; // Start position for the frame, currently ~(MinX + CellPaddingX) float StartXRows; // Start position for the frame, currently ~(MinX + CellPaddingX)
float StartXHeaders; float StartXHeaders;
float ContentMaxPosRowsFrozen; // Submitted contents absolute maximum position, from which we can infer width. float ContentMaxPosRowsFrozen; // Submitted contents absolute maximum position, from which we can infer width.
@ -1930,7 +1930,7 @@ struct ImGuiTableColumn
ImGuiTableColumn() ImGuiTableColumn()
{ {
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
ResizeWeight = WidthRequested = WidthGiven = -1.0f; WidthStretchWeight = WidthRequest = WidthGiven = -1.0f;
NameOffset = -1; NameOffset = -1;
IsVisible = IsVisibleNextFrame = true; IsVisible = IsVisibleNextFrame = true;
DisplayOrder = IndexWithinVisibleSet = -1; DisplayOrder = IndexWithinVisibleSet = -1;

View File

@ -64,26 +64,26 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Typical call flow: (root level is public API): // Typical call flow: (root level is public API):
// - BeginTable() user begin into a table // - BeginTable() user begin into a table
// - BeginChild() - (if ScrollX/ScrollY is set) // | BeginChild() - (if ScrollX/ScrollY is set)
// - TableBeginUpdateColumns() - apply resize/order requests, lock columns active state, order // | TableBeginUpdateColumns() - apply resize/order requests, lock columns active state, order
// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame)
// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of weighted columns) from their respective width
// - TableSetupColumn() user submit columns details (optional) // - TableSetupColumn() user submit columns details (optional)
// - TableAutoHeaders() or TableHeader() user submit a headers row (optional) // - TableAutoHeaders() or TableHeader() user submit a headers row (optional)
// - TableSortSpecsClickColumn() - when clicked: alter sort order and sort direction // | TableSortSpecsClickColumn() - when clicked: alter sort order and sort direction
// - TableGetSortSpecs() user queries updated sort specs (optional) // - TableGetSortSpecs() user queries updated sort specs (optional, generally after submitting headers)
// - TableNextRow() / TableNextCell() user begin into the first row, also automatically called by TableAutoHeaders() // - TableNextRow() / TableNextCell() user begin into the first row, also automatically called by TableAutoHeaders()
// - TableUpdateLayout() - called by the FIRST call to TableNextRow()! // | TableUpdateLayout() - called by the FIRST call to TableNextRow()! lock all widths and columns positions.
// - TableUpdateDrawChannels() - setup ImDrawList channels // | - TableUpdateDrawChannels() - setup ImDrawList channels
// - TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission // | - TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission
// - TableDrawContextMenu() - draw right-click context menu // | - TableDrawContextMenu() - draw right-click context menu
// - TableEndCell() - close existing cell if not the first time // | TableEndCell() - close existing cell if not the first time
// - TableBeginCell() - enter into current cell // | TableBeginCell() - enter into current cell
// - [...] user emit contents // - [...] user emit contents
// - EndTable() user ends the table // - EndTable() user ends the table
// - TableDrawBorders() - draw outer borders, inner vertical borders // | TableDrawBorders() - draw outer borders, inner vertical borders
// - TableDrawMergeChannels() - merge draw channels if clipping isn't required // | TableDrawMergeChannels() - merge draw channels if clipping isn't required
// - TableSetColumnWidth() - apply resizing width // | EndChild() - (if ScrollX/ScrollY is set)
// - TableUpdateColumnsWeightFromWidth() - recompute columns weights (of weighted columns) from their respective width
// - EndChild() - (if ScrollX/ScrollY is set)
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Configuration // Configuration
@ -562,8 +562,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
const float min_column_width = TableGetMinColumnWidth(); const float min_column_width = TableGetMinColumnWidth();
int count_fixed = 0; int count_fixed = 0;
float width_fixed = 0.0f; float sum_weights_stretched = 0.0f; // Sum of all weights for weighted columns.
float total_weights = 0.0f; float sum_width_fixed_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns.
table->LeftMostStretchedColumnDisplayOrder = -1; table->LeftMostStretchedColumnDisplayOrder = -1;
table->ColumnsAutoFitWidth = 0.0f; table->ColumnsAutoFitWidth = 0.0f;
for (int order_n = 0; order_n < table->ColumnsCount; order_n++) for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
@ -598,27 +598,27 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
{ {
// Latch initial size for fixed columns // Latch initial size for fixed columns
count_fixed += 1; count_fixed += 1;
const bool init_size = (column->AutoFitQueue != 0x00) || (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize); const bool auto_fit = (column->AutoFitQueue != 0x00) || (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize);
if (init_size) if (auto_fit)
{ {
column->WidthRequested = column_width_ideal; column->WidthRequest = column_width_ideal;
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
// (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very
// large height (= first frame scrollbar display very off + clipper would skip lots of items). // large height (= first frame scrollbar display very off + clipper would skip lots of items).
// This is merely making the side-effect less extreme, but doesn't properly fixes it. // This is merely making the side-effect less extreme, but doesn't properly fixes it.
if (column->AutoFitQueue > 0x01 && table->IsInitializing) if (column->AutoFitQueue > 0x01 && table->IsInitializing)
column->WidthRequested = ImMax(column->WidthRequested, min_column_width * 4.0f); column->WidthRequest = ImMax(column->WidthRequest, min_column_width * 4.0f);
} }
width_fixed += column->WidthRequested; sum_width_fixed_requests += column->WidthRequest;
} }
else else
{ {
IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch);
const int init_size = (column->ResizeWeight < 0.0f); const int init_size = (column->WidthStretchWeight < 0.0f);
if (init_size) if (init_size)
column->ResizeWeight = 1.0f; column->WidthStretchWeight = 1.0f;
total_weights += column->ResizeWeight; sum_weights_stretched += column->WidthStretchWeight;
if (table->LeftMostStretchedColumnDisplayOrder == -1) if (table->LeftMostStretchedColumnDisplayOrder == -1)
table->LeftMostStretchedColumnDisplayOrder = (ImS8)column->DisplayOrder; table->LeftMostStretchedColumnDisplayOrder = (ImS8)column->DisplayOrder;
} }
@ -636,7 +636,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
width_avail = table->InnerClipRect.GetWidth() - width_spacings - 1.0f; width_avail = table->InnerClipRect.GetWidth() - width_spacings - 1.0f;
else else
width_avail = work_rect.GetWidth() - width_spacings - 1.0f; width_avail = work_rect.GetWidth() - width_spacings - 1.0f;
const float width_avail_for_stretched_columns = width_avail - width_fixed; const float width_avail_for_stretched_columns = width_avail - sum_width_fixed_requests;
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
// Apply final width based on requested widths // Apply final width based on requested widths
@ -652,12 +652,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Allocate width for stretched/weighted columns // Allocate width for stretched/weighted columns
if (column->Flags & ImGuiTableColumnFlags_WidthStretch) if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
{ {
float weight_ratio = column->ResizeWeight / total_weights; // WidthStretchWeight gets converted into WidthRequest
column->WidthRequested = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f); float weight_ratio = column->WidthStretchWeight / sum_weights_stretched;
width_remaining_for_stretched_columns -= column->WidthRequested; column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f);
width_remaining_for_stretched_columns -= column->WidthRequest;
// [Resize Rule 2] Resizing from right-side of a weighted column before a fixed column froward sizing // [Resize Rule 2] Resizing from right-side of a weighted column preceding a fixed column
// to left-side of fixed column. We also need to copy the NoResize flag.. // needs to forward resizing to left-side of fixed column. We also need to copy the NoResize flag..
if (column->NextVisibleColumn != -1) if (column->NextVisibleColumn != -1)
if (ImGuiTableColumn* next_column = &table->Columns[column->NextVisibleColumn]) if (ImGuiTableColumn* next_column = &table->Columns[column->NextVisibleColumn])
if (next_column->Flags & ImGuiTableColumnFlags_WidthFixed) if (next_column->Flags & ImGuiTableColumnFlags_WidthFixed)
@ -673,7 +674,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
count_resizable++; count_resizable++;
// Assign final width, record width in case we will need to shrink // Assign final width, record width in case we will need to shrink
column->WidthGiven = ImFloor(ImMax(column->WidthRequested, min_column_width)); column->WidthGiven = ImFloor(ImMax(column->WidthRequest, min_column_width));
table->ColumnsTotalWidth += column->WidthGiven; table->ColumnsTotalWidth += column->WidthGiven;
} }
@ -703,19 +704,19 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
#endif #endif
// Redistribute remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). // Redistribute remainder width due to rounding (remainder width is < 1.0f * number of Stretch column).
// Using right-to-left distribution (more likely to match resizing cursor), could be adjusted depending where // Using right-to-left distribution (more likely to match resizing cursor), could be adjusted depending
// the mouse cursor is and/or relative weights. // on where the mouse cursor is and/or relative weights.
// FIXME-TABLE: May be simpler to store floating width and floor final positions only // FIXME-TABLE: May be simpler to store floating width and floor final positions only
// FIXME-TABLE: Make it optional? User might prefer to preserve pixel perfect same size? // FIXME-TABLE: Make it optional? User might prefer to preserve pixel perfect same size?
if (width_remaining_for_stretched_columns >= 1.0f) if (width_remaining_for_stretched_columns >= 1.0f)
for (int order_n = table->ColumnsCount - 1; total_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) for (int order_n = table->ColumnsCount - 1; sum_weights_stretched > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
{ {
if (!(table->VisibleMaskByDisplayOrder & ((ImU64)1 << order_n))) if (!(table->VisibleMaskByDisplayOrder & ((ImU64)1 << order_n)))
continue; continue;
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch))
continue; continue;
column->WidthRequested += 1.0f; column->WidthRequest += 1.0f;
column->WidthGiven += 1.0f; column->WidthGiven += 1.0f;
width_remaining_for_stretched_columns -= 1.0f; width_remaining_for_stretched_columns -= 1.0f;
} }
@ -1168,8 +1169,8 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
continue; continue;
visible_weight += column->ResizeWeight; visible_weight += column->WidthStretchWeight;
visible_width += column->WidthRequested; visible_width += column->WidthRequest;
} }
IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f);
@ -1179,7 +1180,7 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
continue; continue;
column->ResizeWeight = (column->WidthRequested + 0.0f) / visible_width; column->WidthStretchWeight = (column->WidthRequest + 0.0f) / visible_width;
} }
} }
@ -1205,7 +1206,7 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f
column_0_width = ImClamp(column_0_width, min_width, max_width_0); column_0_width = ImClamp(column_0_width, min_width, max_width_0);
// Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
if (column_0->WidthGiven == column_0_width || column_0->WidthRequested == column_0_width) if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
return; return;
ImGuiTableColumn* column_1 = (column_0->NextVisibleColumn != -1) ? &table->Columns[column_0->NextVisibleColumn] : NULL; ImGuiTableColumn* column_1 = (column_0->NextVisibleColumn != -1) ? &table->Columns[column_0->NextVisibleColumn] : NULL;
@ -1241,14 +1242,14 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f
if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < column_0->DisplayOrder) if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < column_0->DisplayOrder)
{ {
// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
float column_1_width = ImMax(column_1->WidthRequested - (column_0_width - column_0->WidthRequested), min_width); float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
column_0_width = column_0->WidthRequested + column_1->WidthRequested - column_1_width; column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
column_1->WidthRequested = column_1_width; column_1->WidthRequest = column_1_width;
} }
// Apply // Apply
//IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width); //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width);
column_0->WidthRequested = column_0_width; column_0->WidthRequest = column_0_width;
} }
else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch) else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch)
{ {
@ -1257,15 +1258,15 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f
{ {
float off = (column_0->WidthGiven - column_0_width); float off = (column_0->WidthGiven - column_0_width);
float column_1_width = column_1->WidthGiven + off; float column_1_width = column_1->WidthGiven + off;
column_1->WidthRequested = ImMax(min_width, column_1_width); column_1->WidthRequest = ImMax(min_width, column_1_width);
return; return;
} }
// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b) // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
float column_1_width = ImMax(column_1->WidthRequested - (column_0_width - column_0->WidthRequested), min_width); float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
column_0_width = column_0->WidthRequested + column_1->WidthRequested - column_1_width; column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
column_1->WidthRequested = column_1_width; column_1->WidthRequest = column_1_width;
column_0->WidthRequested = column_0_width; column_0->WidthRequest = column_0_width;
TableUpdateColumnsWeightFromWidth(table); TableUpdateColumnsWeightFromWidth(table);
} }
table->IsSettingsDirty = true; table->IsSettingsDirty = true;
@ -1462,23 +1463,23 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags,
// Initialize defaults // Initialize defaults
// FIXME-TABLE: We don't restore widths/weight so let's avoid using IsSettingsLoaded for now // FIXME-TABLE: We don't restore widths/weight so let's avoid using IsSettingsLoaded for now
if (table->IsInitializing && column->WidthRequested < 0.0f && column->ResizeWeight < 0.0f)// && !table->IsSettingsLoaded) if (table->IsInitializing && column->WidthRequest < 0.0f && column->WidthStretchWeight < 0.0f)// && !table->IsSettingsLoaded)
{ {
// Init width or weight // Init width or weight
// Disable auto-fit if a default fixed width has been specified // Disable auto-fit if a default fixed width has been specified
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
{ {
column->WidthRequested = init_width_or_weight; column->WidthRequest = init_width_or_weight;
column->AutoFitQueue = 0x00; column->AutoFitQueue = 0x00;
} }
if (flags & ImGuiTableColumnFlags_WidthStretch) if (flags & ImGuiTableColumnFlags_WidthStretch)
{ {
IM_ASSERT(init_width_or_weight < 0.0f || init_width_or_weight > 0.0f); IM_ASSERT(init_width_or_weight < 0.0f || init_width_or_weight > 0.0f);
column->ResizeWeight = (init_width_or_weight < 0.0f ? 1.0f : init_width_or_weight); column->WidthStretchWeight = (init_width_or_weight < 0.0f ? 1.0f : init_width_or_weight);
} }
else else
{ {
column->ResizeWeight = 1.0f; column->WidthStretchWeight = 1.0f;
} }
} }
if (table->IsInitializing) if (table->IsInitializing)
@ -2594,13 +2595,13 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
const char* name = TableGetColumnName(table, n); const char* name = TableGetColumnName(table, n);
BulletText("Column %d order %d name '%s': +%.1f to +%.1f\n" BulletText("Column %d order %d name '%s': +%.1f to +%.1f\n"
"Visible: %d, Clipped: %d, DrawChannels: %d,%d\n" "Visible: %d, Clipped: %d, DrawChannels: %d,%d\n"
"WidthGiven/Requested: %.1f/%.1f, Weight: %.2f\n" "WidthGiven/Request: %.1f/%.1f, WidthWeight: %.3f\n"
"ContentWidth: RowsFrozen %d, RowsUnfrozen %d, HeadersUsed/Ideal %d/%d\n" "ContentWidth: RowsFrozen %d, RowsUnfrozen %d, HeadersUsed/Ideal %d/%d\n"
"SortOrder: %d, SortDir: %s\n" "SortOrder: %d, SortDir: %s\n"
"UserID: 0x%08X, Flags: 0x%04X: %s%s%s%s..", "UserID: 0x%08X, Flags: 0x%04X: %s%s%s%s..",
n, column->DisplayOrder, name ? name : "NULL", column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, n, column->DisplayOrder, name ? name : "NULL", column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x,
column->IsVisible, column->IsClipped, column->DrawChannelRowsBeforeFreeze, column->DrawChannelRowsAfterFreeze, column->IsVisible, column->IsClipped, column->DrawChannelRowsBeforeFreeze, column->DrawChannelRowsAfterFreeze,
column->WidthGiven, column->WidthRequested, column->ResizeWeight, column->WidthGiven, column->WidthRequest, column->WidthStretchWeight,
column->ContentWidthRowsFrozen, column->ContentWidthRowsUnfrozen, column->ContentWidthHeadersUsed, column->ContentWidthHeadersIdeal, column->ContentWidthRowsFrozen, column->ContentWidthRowsUnfrozen, column->ContentWidthHeadersUsed, column->ContentWidthHeadersIdeal,
column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? "Ascending" : (column->SortDirection == ImGuiSortDirection_Descending) ? "Descending" : "None", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? "Ascending" : (column->SortDirection == ImGuiSortDirection_Descending) ? "Descending" : "None",
column->UserID, column->Flags, column->UserID, column->Flags,