mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-15 01:17:00 +00:00
Tables: comments and tweaks on TableUpdateLayout(). changed "apply final width" loop to use natural column order.
This commit is contained in:
parent
155b8bb816
commit
f70bf69e3b
15
imgui.h
15
imgui.h
@ -663,19 +663,20 @@ namespace ImGui
|
|||||||
// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows
|
// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows
|
||||||
// - 4. Optionally call TableHeadersRow() to submit a header row (names will be pulled from data submitted to TableSetupColumns)
|
// - 4. Optionally call TableHeadersRow() to submit a header row (names will be pulled from data submitted to TableSetupColumns)
|
||||||
// - 5. Populate contents
|
// - 5. Populate contents
|
||||||
// - In most situations you can use TableNextRow() + TableSetColumnIndex(xx) to start appending into a column.
|
// - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column.
|
||||||
// - If you are using tables as a sort of grid, where every columns is holding the same type of contents,
|
// - If you are using tables as a sort of grid, where every columns is holding the same type of contents,
|
||||||
// you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex().
|
// you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex().
|
||||||
// TableNextColumn() will automatically wrap-around into the next row if needed.
|
// TableNextColumn() will automatically wrap-around into the next row if needed.
|
||||||
// - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column!
|
// - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column!
|
||||||
// - Both TableSetColumnIndex() and TableNextColumn() return false when the column is not visible, so you can
|
// - Both TableSetColumnIndex() and TableNextColumn() return false when the column is not visible, so you can
|
||||||
// skip submitting the contents of a cell but only if you know the contents is not going to alter row height.
|
// skip submitting the contents of a cell BUT ONLY if you know the contents is not going to alter row height.
|
||||||
|
// In many situations, you may skip submitting contents for every columns but one (e.g. the first one).
|
||||||
// - Summary of possible call flow:
|
// - Summary of possible call flow:
|
||||||
// ----------------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------------
|
||||||
// TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK
|
// TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1") // OK
|
||||||
// TableNextRow() -> TableNextColumn() Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK
|
// TableNextRow() -> TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK
|
||||||
// TableNextColumn() Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row!
|
// TableNextColumn() -> Text("Hello 0") -> TableNextColumn() -> Text("Hello 1") // OK: TableNextColumn() automatically gets to next row!
|
||||||
// TableNextRow() Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
|
// TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
|
||||||
// ----------------------------------------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------------------------------------
|
||||||
// - 5. Call EndTable()
|
// - 5. Call EndTable()
|
||||||
#define IMGUI_HAS_TABLE 1
|
#define IMGUI_HAS_TABLE 1
|
||||||
@ -1109,8 +1110,8 @@ enum ImGuiTableColumnFlags_
|
|||||||
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Header width don't contribute to automatic column width.
|
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Header width don't contribute to automatic column width.
|
||||||
ImGuiTableColumnFlags_PreferSortAscending = 1 << 13, // Make the initial sort direction Ascending when first sorting on this column (default).
|
ImGuiTableColumnFlags_PreferSortAscending = 1 << 13, // Make the initial sort direction Ascending when first sorting on this column (default).
|
||||||
ImGuiTableColumnFlags_PreferSortDescending = 1 << 14, // Make the initial sort direction Descending when first sorting on this column.
|
ImGuiTableColumnFlags_PreferSortDescending = 1 << 14, // Make the initial sort direction Descending when first sorting on this column.
|
||||||
ImGuiTableColumnFlags_IndentEnable = 1 << 15, // Use current Indent value when entering cell (default for 1st column).
|
ImGuiTableColumnFlags_IndentEnable = 1 << 15, // Use current Indent value when entering cell (default for column 0).
|
||||||
ImGuiTableColumnFlags_IndentDisable = 1 << 16, // Ignore current Indent value when entering cell (default for columns after the 1st one). Indentation changes _within_ the cell will still be honored.
|
ImGuiTableColumnFlags_IndentDisable = 1 << 16, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.
|
||||||
|
|
||||||
// [Internal] Combinations and masks
|
// [Internal] Combinations and masks
|
||||||
ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize,
|
ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize,
|
||||||
|
@ -1898,7 +1898,8 @@ typedef ImS8 ImGuiTableColumnIdx;
|
|||||||
typedef ImU8 ImGuiTableDrawChannelIdx;
|
typedef ImU8 ImGuiTableDrawChannelIdx;
|
||||||
|
|
||||||
// [Internal] sizeof() ~ 104
|
// [Internal] sizeof() ~ 104
|
||||||
// We use the terminology "Visible" to refer to a columns that are not Hidden by user or settings. However it may still be out of view and clipped (and IsClipped would be set).
|
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
|
||||||
|
// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping.
|
||||||
// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped".
|
// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped".
|
||||||
struct ImGuiTableColumn
|
struct ImGuiTableColumn
|
||||||
{
|
{
|
||||||
@ -1932,7 +1933,7 @@ struct ImGuiTableColumn
|
|||||||
bool IsEnabled; // Is the column not marked Hidden by the user? (even if off view, e.g. clipped by scrolling).
|
bool IsEnabled; // Is the column not marked Hidden by the user? (even if off view, e.g. clipped by scrolling).
|
||||||
bool IsEnabledNextFrame;
|
bool IsEnabledNextFrame;
|
||||||
bool IsClipped; // Is not actually in view (e.g. not overlapping the host window clipping rectangle).
|
bool IsClipped; // Is not actually in view (e.g. not overlapping the host window clipping rectangle).
|
||||||
bool IsSkipItems; // Do we want item submissions to this column to be ignored early on.
|
bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen).
|
||||||
ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
|
ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
|
||||||
ImS8 SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
|
ImS8 SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
|
||||||
ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit
|
ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit
|
||||||
@ -1969,9 +1970,9 @@ struct ImGuiTable
|
|||||||
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
ImSpan<ImGuiTableColumn> Columns; // Point within RawData[]
|
||||||
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
ImSpan<ImGuiTableColumnIdx> DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1)
|
||||||
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
|
ImSpan<ImGuiTableCellData> RowCellData; // Point within RawData[]. Store cells background requests for current row.
|
||||||
ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
|
|
||||||
ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
|
ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map
|
||||||
ImU64 EnabledUnclippedMaskByIndex;// Enabled and not Clipped, aka "actually visible" "not hidden by some scrolling"
|
ImU64 EnabledUnclippedMaskByIndex;// Enabled and not Clipped, aka "actually visible" "not hidden by some scrolling"
|
||||||
|
ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data
|
||||||
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
|
ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order)
|
||||||
int SettingsOffset; // Offset in g.SettingsTables
|
int SettingsOffset; // Offset in g.SettingsTables
|
||||||
int LastFrameActive;
|
int LastFrameActive;
|
||||||
|
117
imgui_tables.cpp
117
imgui_tables.cpp
@ -569,7 +569,7 @@ static float TableGetMinColumnWidth()
|
|||||||
return g.Style.FramePadding.x * 1.0f;
|
return g.Style.FramePadding.x * 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout columns for the frame
|
// Layout columns for the frame. This is in essence the followup to BeginTable().
|
||||||
// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first.
|
// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first.
|
||||||
// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for WidthAutoResize
|
// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for WidthAutoResize
|
||||||
// columns, increase feedback side-effect with widgets relying on WorkRect.Max.x. Maybe provide a default distribution
|
// columns, increase feedback side-effect with widgets relying on WorkRect.Max.x. Maybe provide a default distribution
|
||||||
@ -579,14 +579,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
ImGuiContext& g = *GImGui;
|
ImGuiContext& g = *GImGui;
|
||||||
IM_ASSERT(table->IsLayoutLocked == false);
|
IM_ASSERT(table->IsLayoutLocked == false);
|
||||||
|
|
||||||
table->HoveredColumnBody = -1;
|
// [Part 1] Apply/lock Enabled and Order states.
|
||||||
table->HoveredColumnBorder = -1;
|
// Process columns in their visible orders as we are building the Prev/Next indices.
|
||||||
|
int last_visible_column_idx = -1;
|
||||||
// Lock Enabled state and Order
|
|
||||||
ImGuiTableColumn* last_visible_column = NULL;
|
|
||||||
bool want_column_auto_fit = false;
|
bool want_column_auto_fit = false;
|
||||||
table->IsDefaultDisplayOrder = true;
|
table->IsDefaultDisplayOrder = true;
|
||||||
table->ColumnsEnabledCount = 0;
|
table->ColumnsEnabledCount = 0;
|
||||||
|
table->EnabledMaskByIndex = 0x00;
|
||||||
|
table->EnabledMaskByDisplayOrder = 0x00;
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
{
|
{
|
||||||
const int column_n = table->DisplayOrderToIndex[order_n];
|
const int column_n = table->DisplayOrderToIndex[order_n];
|
||||||
@ -611,46 +611,41 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder;
|
ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder;
|
||||||
if (column->IsEnabled)
|
if (column->IsEnabled)
|
||||||
{
|
{
|
||||||
column->PrevEnabledColumn = column->NextEnabledColumn = -1;
|
column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
|
||||||
if (last_visible_column)
|
column->NextEnabledColumn = -1;
|
||||||
{
|
if (last_visible_column_idx != -1)
|
||||||
last_visible_column->NextEnabledColumn = (ImGuiTableColumnIdx)column_n;
|
table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n;
|
||||||
column->PrevEnabledColumn = (ImGuiTableColumnIdx)table->Columns.index_from_ptr(last_visible_column);
|
|
||||||
}
|
|
||||||
column->IndexWithinEnabledSet = table->ColumnsEnabledCount;
|
column->IndexWithinEnabledSet = table->ColumnsEnabledCount;
|
||||||
table->ColumnsEnabledCount++;
|
table->ColumnsEnabledCount++;
|
||||||
table->EnabledMaskByIndex |= index_mask;
|
table->EnabledMaskByIndex |= index_mask;
|
||||||
table->EnabledMaskByDisplayOrder |= display_order_mask;
|
table->EnabledMaskByDisplayOrder |= display_order_mask;
|
||||||
last_visible_column = column;
|
last_visible_column_idx = column_n;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
column->IndexWithinEnabledSet = -1;
|
column->IndexWithinEnabledSet = -1;
|
||||||
table->EnabledMaskByIndex &= ~index_mask;
|
|
||||||
table->EnabledMaskByDisplayOrder &= ~display_order_mask;
|
|
||||||
}
|
}
|
||||||
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
|
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
|
||||||
}
|
}
|
||||||
table->EnabledUnclippedMaskByIndex = table->EnabledMaskByIndex; // Columns will be masked out below when Clipped
|
table->EnabledUnclippedMaskByIndex = table->EnabledMaskByIndex; // Columns will be masked out below when Clipped
|
||||||
table->RightMostEnabledColumn = (ImGuiTableColumnIdx)(last_visible_column ? table->Columns.index_from_ptr(last_visible_column) : -1);
|
table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
|
||||||
|
|
||||||
// Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible to avoid
|
// [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible
|
||||||
// the column fitting to wait until the first visible frame of the child container (may or not be a good thing).
|
// to avoid the column fitting to wait until the first visible frame of the child container (may or not be a good thing).
|
||||||
|
// FIXME-TABLE: for always auto-resizing columns may not want to do that all the time.
|
||||||
if (want_column_auto_fit && table->OuterWindow != table->InnerWindow)
|
if (want_column_auto_fit && table->OuterWindow != table->InnerWindow)
|
||||||
table->InnerWindow->SkipItems = false;
|
table->InnerWindow->SkipItems = false;
|
||||||
if (want_column_auto_fit)
|
if (want_column_auto_fit)
|
||||||
table->IsSettingsDirty = true;
|
table->IsSettingsDirty = true;
|
||||||
|
|
||||||
// Compute offset, clip rect for the frame
|
// [Part 3] Fix column flags. Calculate ideal width for columns. Count how many fixed/stretch columns we have and sum of weights.
|
||||||
// (can't make auto padding larger than what WorkRect knows about so right-alignment matches)
|
|
||||||
const ImRect work_rect = table->WorkRect;
|
|
||||||
const float min_column_width = TableGetMinColumnWidth();
|
const float min_column_width = TableGetMinColumnWidth();
|
||||||
const float min_column_distance = min_column_width + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2;
|
const float min_column_distance = min_column_width + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2;
|
||||||
|
int count_fixed = 0; // Number of columns that have fixed sizing policy (not stretched sizing policy) (this is NOT the opposite of count_resizable!)
|
||||||
int count_fixed = 0;
|
int count_resizable = 0; // Number of columns the user can resize (this is NOT the opposite of count_fixed!)
|
||||||
float sum_weights_stretched = 0.0f; // Sum of all weights for weighted columns.
|
float sum_weights_stretched = 0.0f; // Sum of all weights for weighted columns.
|
||||||
float sum_width_fixed_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns.
|
float sum_width_fixed_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns.
|
||||||
float max_width_auto = 0.0f;
|
float max_width_auto = 0.0f; // Largest auto-width (used for SameWidths feature)
|
||||||
table->LeftMostStretchedColumnDisplayOrder = -1;
|
table->LeftMostStretchedColumnDisplayOrder = -1;
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
@ -663,6 +658,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
column->Flags = TableFixColumnFlags(table, column->FlagsIn);
|
column->Flags = TableFixColumnFlags(table, column->FlagsIn);
|
||||||
if ((column->Flags & ImGuiTableColumnFlags_IndentMask_) == 0)
|
if ((column->Flags & ImGuiTableColumnFlags_IndentMask_) == 0)
|
||||||
column->Flags |= (column_n == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable;
|
column->Flags |= (column_n == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable;
|
||||||
|
if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0)
|
||||||
|
count_resizable++;
|
||||||
|
|
||||||
// We have a unusual edge case where if the user doesn't call TableGetSortSpecs() but has sorting enabled
|
// We have a unusual edge case where if the user doesn't call TableGetSortSpecs() but has sorting enabled
|
||||||
// or varying sorting flags, we still want the sorting arrows to honor those flags.
|
// or varying sorting flags, we still want the sorting arrows to honor those flags.
|
||||||
@ -684,7 +681,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth);
|
width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth);
|
||||||
|
|
||||||
column->WidthAuto = width_auto;
|
column->WidthAuto = width_auto;
|
||||||
|
|
||||||
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
|
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
|
||||||
{
|
{
|
||||||
// Process auto-fit for non-stretched columns
|
// Process auto-fit for non-stretched columns
|
||||||
@ -699,7 +695,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
// FIXME: Move this to ->WidthGiven to avoid temporary lossyless?
|
// FIXME: Move this to ->WidthGiven to avoid temporary lossyless?
|
||||||
if (column->AutoFitQueue > 0x01 && table->IsInitializing)
|
if (column->AutoFitQueue > 0x01 && table->IsInitializing)
|
||||||
column->WidthRequest = ImMax(column->WidthRequest, min_column_width * 4.0f); // FIXME-TABLE: Another constant/scale?
|
column->WidthRequest = ImMax(column->WidthRequest, min_column_width * 4.0f); // FIXME-TABLE: Another constant/scale?
|
||||||
|
|
||||||
count_fixed += 1;
|
count_fixed += 1;
|
||||||
sum_width_fixed_requests += column->WidthRequest;
|
sum_width_fixed_requests += column->WidthRequest;
|
||||||
}
|
}
|
||||||
@ -718,15 +713,16 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
}
|
}
|
||||||
table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
|
table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
|
||||||
|
|
||||||
// Apply "same widths"
|
// [Part 4] Apply "same widths" feature.
|
||||||
// - When all columns are fixed or columns are of mixed type: use the maximum auto width
|
// - When all columns are fixed or columns are of mixed type: use the maximum auto width.
|
||||||
// - When all columns are stretch: use same weight
|
// - When all columns are stretch: use same weight.
|
||||||
const bool mixed_same_widths = (table->Flags & ImGuiTableFlags_SameWidths) && count_fixed > 0;
|
const bool mixed_same_widths = (table->Flags & ImGuiTableFlags_SameWidths) && count_fixed > 0;
|
||||||
if (table->Flags & ImGuiTableFlags_SameWidths)
|
if (table->Flags & ImGuiTableFlags_SameWidths)
|
||||||
{
|
{
|
||||||
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
|
|
||||||
{
|
{
|
||||||
|
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
||||||
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
|
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
|
||||||
{
|
{
|
||||||
@ -743,22 +739,19 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout
|
// [Part 5] Apply final widths based on requested widths
|
||||||
|
const ImRect work_rect = table->WorkRect;
|
||||||
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
|
||||||
const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth();
|
const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth();
|
||||||
const float width_avail_for_stretched_columns = mixed_same_widths ? 0.0f : width_avail - width_spacings - sum_width_fixed_requests;
|
const float width_avail_for_stretched_columns = mixed_same_widths ? 0.0f : width_avail - width_spacings - 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
|
|
||||||
// Mark some columns as not resizable
|
|
||||||
int count_resizable = 0;
|
|
||||||
table->ColumnsTotalWidth = width_spacings;
|
table->ColumnsTotalWidth = width_spacings;
|
||||||
table->ColumnsAutoFitWidth = width_spacings;
|
table->ColumnsAutoFitWidth = width_spacings;
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
|
||||||
{
|
{
|
||||||
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
|
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
|
||||||
continue;
|
continue;
|
||||||
ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
|
|
||||||
// Allocate width for stretched/weighted columns
|
// Allocate width for stretched/weighted columns
|
||||||
if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
|
if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
|
||||||
@ -784,18 +777,14 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumnDisplayOrder != -1)
|
if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumnDisplayOrder != -1)
|
||||||
column->Flags |= ImGuiTableColumnFlags_NoDirectResize_;
|
column->Flags |= ImGuiTableColumnFlags_NoDirectResize_;
|
||||||
|
|
||||||
if (!(column->Flags & ImGuiTableColumnFlags_NoResize))
|
|
||||||
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->WidthRequest, min_column_width));
|
column->WidthGiven = ImFloor(ImMax(column->WidthRequest, min_column_width));
|
||||||
table->ColumnsTotalWidth += column->WidthGiven + table->CellPaddingX * 2.0f;
|
table->ColumnsTotalWidth += column->WidthGiven + table->CellPaddingX * 2.0f;
|
||||||
table->ColumnsAutoFitWidth += column->WidthAuto + table->CellPaddingX * 2.0f;
|
table->ColumnsAutoFitWidth += column->WidthAuto + table->CellPaddingX * 2.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Redistribute remainder width due to rounding (remainder width is < 1.0f * number of Stretch column).
|
// [Part 6] Redistribute stretch 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
|
// Using right-to-left distribution (more likely to match resizing cursor).
|
||||||
// on where the mouse cursor is and/or relative weights.
|
|
||||||
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
|
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
|
||||||
for (int order_n = table->ColumnsCount - 1; sum_weights_stretched > 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--)
|
||||||
{
|
{
|
||||||
@ -809,15 +798,15 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
width_remaining_for_stretched_columns -= 1.0f;
|
width_remaining_for_stretched_columns -= 1.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect hovered column
|
table->HoveredColumnBody = -1;
|
||||||
|
table->HoveredColumnBorder = -1;
|
||||||
const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table->LastOuterHeight));
|
const ImRect mouse_hit_rect(table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.Max.x, ImMax(table->OuterRect.Max.y, table->OuterRect.Min.y + table->LastOuterHeight));
|
||||||
const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
|
const bool is_hovering_table = ItemHoverable(mouse_hit_rect, 0);
|
||||||
|
|
||||||
// Setup final position, offset and clipping rectangles
|
// [Part 7] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
|
||||||
|
// Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping.
|
||||||
int visible_n = 0;
|
int visible_n = 0;
|
||||||
float offset_x = (table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x;
|
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
|
||||||
offset_x += table->OuterPaddingX;
|
|
||||||
offset_x -= table->CellSpacingX1;
|
|
||||||
ImRect host_clip_rect = table->InnerClipRect;
|
ImRect host_clip_rect = table->InnerClipRect;
|
||||||
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
|
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
|
||||||
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
|
||||||
@ -925,7 +914,9 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
visible_n++;
|
visible_n++;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it)
|
// [Part 8] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it)
|
||||||
|
// Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either
|
||||||
|
// because of using _WidthAutoResize/_WidthStretch). This will hide the resizing option from the context menu.
|
||||||
if (is_hovering_table && table->HoveredColumnBody == -1)
|
if (is_hovering_table && table->HoveredColumnBody == -1)
|
||||||
{
|
{
|
||||||
float unused_x1 = table->WorkRect.Min.x;
|
float unused_x1 = table->WorkRect.Min.x;
|
||||||
@ -934,26 +925,20 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
if (g.IO.MousePos.x >= unused_x1)
|
if (g.IO.MousePos.x >= unused_x1)
|
||||||
table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;
|
table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag,
|
|
||||||
// either because of using _WidthAutoResize/_WidthStretch).
|
|
||||||
// This will hide the resizing option from the context menu.
|
|
||||||
if (count_resizable == 0 && (table->Flags & ImGuiTableFlags_Resizable))
|
if (count_resizable == 0 && (table->Flags & ImGuiTableFlags_Resizable))
|
||||||
table->Flags &= ~ImGuiTableFlags_Resizable;
|
table->Flags &= ~ImGuiTableFlags_Resizable;
|
||||||
|
|
||||||
// Allocate draw channels
|
// [Part 9] Allocate draw channels
|
||||||
TableSetupDrawChannels(table);
|
TableSetupDrawChannels(table);
|
||||||
|
|
||||||
// Borders
|
// [Part 10] Hit testing on borders
|
||||||
if (table->Flags & ImGuiTableFlags_Resizable)
|
if (table->Flags & ImGuiTableFlags_Resizable)
|
||||||
TableUpdateBorders(table);
|
TableUpdateBorders(table);
|
||||||
|
|
||||||
// Reset fields after we used them in TableSetupResize()
|
|
||||||
table->LastFirstRowHeight = 0.0f;
|
table->LastFirstRowHeight = 0.0f;
|
||||||
table->IsLayoutLocked = true;
|
table->IsLayoutLocked = true;
|
||||||
table->IsUsingHeaders = false;
|
table->IsUsingHeaders = false;
|
||||||
|
|
||||||
// Context menu
|
// [Part 11] Context menu
|
||||||
if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted)
|
if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted)
|
||||||
{
|
{
|
||||||
const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID);
|
const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID);
|
||||||
@ -968,20 +953,20 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// [Part 13] Sanitize and build sort specs before we have a change to use them for display.
|
||||||
|
// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)
|
||||||
|
if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable))
|
||||||
|
TableSortSpecsBuild(table);
|
||||||
|
|
||||||
// Initial state
|
// Initial state
|
||||||
ImGuiWindow* inner_window = table->InnerWindow;
|
ImGuiWindow* inner_window = table->InnerWindow;
|
||||||
if (table->Flags & ImGuiTableFlags_NoClip)
|
if (table->Flags & ImGuiTableFlags_NoClip)
|
||||||
table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED);
|
table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED);
|
||||||
else
|
else
|
||||||
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
|
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
|
||||||
|
|
||||||
// Sanitize and build sort specs before we have a change to use them for display.
|
|
||||||
// This path will only be exercised when sort specs are modified before header rows (e.g. init or visibility change)
|
|
||||||
if (table->IsSortSpecsDirty && (table->Flags & ImGuiTableFlags_Sortable))
|
|
||||||
TableSortSpecsBuild(table);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process interaction on resizing borders. Actual size change will be applied in EndTable()
|
// Process hit-testing on resizing borders. Actual size change will be applied in EndTable()
|
||||||
// - Set table->HoveredColumnBorder with a short delay/timer to reduce feedback noise
|
// - Set table->HoveredColumnBorder with a short delay/timer to reduce feedback noise
|
||||||
// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize widgets
|
// - Submit ahead of table contents and header, use ImGuiButtonFlags_AllowItemOverlap to prioritize widgets
|
||||||
// overlapping the same area.
|
// overlapping the same area.
|
||||||
@ -3110,7 +3095,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
|
|||||||
char buf[512];
|
char buf[512];
|
||||||
char* p = buf;
|
char* p = buf;
|
||||||
const char* buf_end = buf + IM_ARRAYSIZE(buf);
|
const char* buf_end = buf + IM_ARRAYSIZE(buf);
|
||||||
const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2);
|
const bool is_active = (table->LastFrameActive >= ImGui::GetFrameCount() - 2); // Note that fully clipped early out scrolling tables will appear as inactive here.
|
||||||
ImFormatString(p, buf_end - p, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*");
|
ImFormatString(p, buf_end - p, "Table 0x%08X (%d columns, in '%s')%s", table->ID, table->ColumnsCount, table->OuterWindow->Name, is_active ? "" : " *Inactive*");
|
||||||
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
if (!is_active) { PushStyleColor(ImGuiCol_Text, GetStyleColorVec4(ImGuiCol_TextDisabled)); }
|
||||||
bool open = TreeNode(table, "%s", buf);
|
bool open = TreeNode(table, "%s", buf);
|
||||||
|
Loading…
Reference in New Issue
Block a user