Tables: support internal TableResetSettings(), clarify lifetime, fixed missing auto-fit on column unhidden after first run, fixed resize assert when changing column sizing policy to stretch mid-frame (before of -1.0f weight)

This commit is contained in:
ocornut 2020-12-04 15:52:51 +01:00
parent b194df413c
commit 7a61f3407b
3 changed files with 62 additions and 31 deletions

View File

@ -11086,8 +11086,6 @@ void ImGui::DebugNodeDrawList(ImGuiWindow*, const ImDrawList*, const char*) {}
void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {} void ImGui::DebugNodeDrawCmdShowMeshAndBoundingBox(ImGuiWindow*, const ImDrawList*, const ImDrawCmd*, bool, bool) {}
void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {} void ImGui::DebugNodeStorage(ImGuiStorage*, const char*) {}
void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {} void ImGui::DebugNodeTabBar(ImGuiTabBar*, const char*) {}
void ImGui::DebugNodeTable(ImGuiTable*) {}
void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {} void ImGui::DebugNodeWindow(ImGuiWindow*, const char*) {}
void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {} void ImGui::DebugNodeWindowSettings(ImGuiWindowSettings*) {}
void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {} void ImGui::DebugNodeWindowsList(ImVector<ImGuiWindow*>*, const char*) {}

View File

@ -1936,6 +1936,7 @@ struct ImGuiTableColumn
bool IsVisibleY; bool IsVisibleY;
bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not. bool IsRequestOutput; // Return value for TableSetColumnIndex() / TableNextColumn(): whether we request user to output contents or not.
bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen). bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen).
bool IsPreserveWidthAuto;
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
@ -1946,7 +1947,6 @@ struct ImGuiTableColumn
memset(this, 0, sizeof(*this)); memset(this, 0, sizeof(*this));
StretchWeight = WidthRequest = -1.0f; StretchWeight = WidthRequest = -1.0f;
NameOffset = -1; NameOffset = -1;
IsEnabled = IsEnabledNextFrame = true;
DisplayOrder = IndexWithinEnabledSet = -1; DisplayOrder = IndexWithinEnabledSet = -1;
PrevEnabledColumn = NextEnabledColumn = -1; PrevEnabledColumn = NextEnabledColumn = -1;
SortOrder = -1; SortOrder = -1;
@ -2062,6 +2062,7 @@ struct ImGuiTable
bool IsSettingsRequestLoad; bool IsSettingsRequestLoad;
bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data. bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data.
bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
bool IsResetAllRequest;
bool IsResetDisplayOrderRequest; bool IsResetDisplayOrderRequest;
bool IsUnfrozen; // Set when we got past the frozen row. bool IsUnfrozen; // Set when we got past the frozen row.
bool MemoryCompacted; bool MemoryCompacted;
@ -2319,11 +2320,11 @@ namespace ImGui
// Tables: Settings // Tables: Settings
IMGUI_API void TableLoadSettings(ImGuiTable* table); IMGUI_API void TableLoadSettings(ImGuiTable* table);
IMGUI_API void TableSaveSettings(ImGuiTable* table); IMGUI_API void TableSaveSettings(ImGuiTable* table);
IMGUI_API void TableResetSettings(ImGuiTable* table);
IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table);
IMGUI_API void TableSettingsInstallHandler(ImGuiContext* context); IMGUI_API void TableSettingsInstallHandler(ImGuiContext* context);
IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count);
IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id);
IMGUI_API void TableSettingsClearByID(ImGuiID id);
// Tab Bars // Tab Bars
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags); IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);

View File

@ -271,7 +271,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Acquire storage for the table // Acquire storage for the table
ImGuiTable* table = g.Tables.GetOrAddByKey(id); ImGuiTable* table = g.Tables.GetOrAddByKey(id);
const bool table_is_new = (table->ID == 0);
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1; const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceCurrent + 1;
const ImGuiID instance_id = id + instance_no; const ImGuiID instance_id = id + instance_no;
const ImGuiTableFlags table_last_flags = table->Flags; const ImGuiTableFlags table_last_flags = table->Flags;
@ -288,7 +287,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->LastFrameActive = g.FrameCount; table->LastFrameActive = g.FrameCount;
table->OuterWindow = table->InnerWindow = outer_window; table->OuterWindow = table->InnerWindow = outer_window;
table->ColumnsCount = columns_count; table->ColumnsCount = columns_count;
table->IsInitializing = false;
table->IsLayoutLocked = false; table->IsLayoutLocked = false;
table->InnerWidth = inner_width; table->InnerWidth = inner_width;
table->OuterRect = outer_rect; table->OuterRect = outer_rect;
@ -415,10 +413,25 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
if (table->RawData == NULL) if (table->RawData == NULL)
{ {
TableBeginInitMemory(table, columns_count); TableBeginInitMemory(table, columns_count);
if (table_is_new) table->IsInitializing = table->IsSettingsRequestLoad = true;
table->IsInitializing = true; }
table->IsSortSpecsDirty = table->IsSettingsRequestLoad = true; if (table->IsResetAllRequest)
TableResetSettings(table);
if (table->IsInitializing)
{
// Initialize for new settings
table->SettingsOffset = -1; table->SettingsOffset = -1;
table->IsSortSpecsDirty = true;
for (int n = 0; n < columns_count; n++)
{
ImGuiTableColumn* column = &table->Columns[n];
float width_auto = column->WidthAuto;
*column = ImGuiTableColumn();
column->WidthAuto = width_auto;
column->IsPreserveWidthAuto = true; // Preserve WidthAuto when reinitializing a live table: not technically necessary but remove a visible flicker
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
column->IsEnabled = column->IsEnabledNextFrame = true;
}
} }
// Load settings // Load settings
@ -479,19 +492,11 @@ void ImGui::TableBeginInitMemory(ImGuiTable* table, int columns_count)
span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx)); span_allocator.ReserveBytes(1, columns_count * sizeof(ImGuiTableColumnIdx));
span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData)); span_allocator.ReserveBytes(2, columns_count * sizeof(ImGuiTableCellData));
table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes()); table->RawData = IM_ALLOC(span_allocator.GetArenaSizeInBytes());
memset(table->RawData, 0, span_allocator.GetArenaSizeInBytes());
span_allocator.SetArenaBasePtr(table->RawData); span_allocator.SetArenaBasePtr(table->RawData);
span_allocator.GetSpan(0, &table->Columns); span_allocator.GetSpan(0, &table->Columns);
span_allocator.GetSpan(1, &table->DisplayOrderToIndex); span_allocator.GetSpan(1, &table->DisplayOrderToIndex);
span_allocator.GetSpan(2, &table->RowCellData); span_allocator.GetSpan(2, &table->RowCellData);
memset(table->RowCellData.Data, 0, table->RowCellData.size_in_bytes());
for (int n = 0; n < columns_count; n++)
{
ImGuiTableColumn* column = &table->Columns[n];
*column = ImGuiTableColumn();
column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImGuiTableColumnIdx)n;
column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames
}
} }
// Apply queued resizing/reordering/hiding requests // Apply queued resizing/reordering/hiding requests
@ -513,7 +518,6 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
// FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings. // FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings.
if (table->AutoFitSingleStretchColumn != -1) if (table->AutoFitSingleStretchColumn != -1)
{ {
table->Columns[table->AutoFitSingleStretchColumn].AutoFitQueue = 0x00;
TableSetColumnWidth(table->AutoFitSingleStretchColumn, table->Columns[table->AutoFitSingleStretchColumn].WidthAuto); TableSetColumnWidth(table->AutoFitSingleStretchColumn, table->Columns[table->AutoFitSingleStretchColumn].WidthAuto);
table->AutoFitSingleStretchColumn = -1; table->AutoFitSingleStretchColumn = -1;
} }
@ -635,6 +639,15 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
} }
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable)) if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable))
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
bool start_auto_fit = false;
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
start_auto_fit = column->WidthRequest < 0.0f;
else
start_auto_fit = column->StretchWeight < 0.0f;
if (start_auto_fit)
column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames
if (column->AutoFitQueue != 0x00) if (column->AutoFitQueue != 0x00)
want_column_auto_fit = true; want_column_auto_fit = true;
@ -698,6 +711,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping) // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
// Combine width from regular rows + width from headers unless requested not to. // Combine width from regular rows + width from headers unless requested not to.
if (!column->IsPreserveWidthAuto)
{ {
const float content_width_body = (float)ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX; const float content_width_body = (float)ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX;
const float content_width_headers = (float)column->ContentMaxXHeadersIdeal - column->WorkMinX; const float content_width_headers = (float)column->ContentMaxXHeadersIdeal - column->WorkMinX;
@ -708,11 +722,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Non-resizable columns also submit their requested width // Non-resizable columns also submit their requested width
if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f)
if (!(table->Flags & ImGuiTableFlags_Resizable) || !(column->Flags & ImGuiTableColumnFlags_NoResize)) if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize))
width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth); width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth);
column->WidthAuto = width_auto; column->WidthAuto = width_auto;
} }
column->IsPreserveWidthAuto = false;
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize)) if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
{ {
@ -734,9 +749,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
else else
{ {
IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch);
const float default_weight = (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : 1.0f; if (column->StretchWeight < 0.0f)
if (column->AutoFitQueue != 0x00) column->StretchWeight = 1.0f;
column->StretchWeight = default_weight;
sum_weights_stretched += column->StretchWeight; sum_weights_stretched += column->StretchWeight;
if (table->LeftMostStretchedColumnDisplayOrder == -1 || table->LeftMostStretchedColumnDisplayOrder > column->DisplayOrder) if (table->LeftMostStretchedColumnDisplayOrder == -1 || table->LeftMostStretchedColumnDisplayOrder > column->DisplayOrder)
table->LeftMostStretchedColumnDisplayOrder = column->DisplayOrder; table->LeftMostStretchedColumnDisplayOrder = column->DisplayOrder;
@ -1232,6 +1246,7 @@ void ImGui::EndTable()
// Save settings // Save settings
if (table->IsSettingsDirty) if (table->IsSettingsDirty)
TableSaveSettings(table); TableSaveSettings(table);
table->IsInitializing = false;
// Clear or restore current table, if any // Clear or restore current table, if any
IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table); IM_ASSERT(g.CurrentWindow == outer_window && g.CurrentTable == table);
@ -2731,6 +2746,10 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
want_separator = true; want_separator = true;
} }
// Reset all (should work but seems unnecessary/noisy to expose?)
//if (MenuItem("Reset all"))
// table->IsResetAllRequest = true;
// Sorting // Sorting
// (modify TableOpenContextMenu() to add _Sortable flag if enabling this) // (modify TableOpenContextMenu() to add _Sortable flag if enabling this)
#if 0 #if 0
@ -2777,12 +2796,14 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// [SECTION] Tables: Settings (.ini data) // [SECTION] Tables: Settings (.ini data)
//------------------------------------------------------------------------- //-------------------------------------------------------------------------
// FIXME: The binding/finding/creating flow are too confusing.
//-------------------------------------------------------------------------
// - TableSettingsInit() [Internal] // - TableSettingsInit() [Internal]
// - TableSettingsCalcChunkSize() [Internal] // - TableSettingsCalcChunkSize() [Internal]
// - TableSettingsCreate() [Internal] // - TableSettingsCreate() [Internal]
// - TableSettingsFindByID() [Internal] // - TableSettingsFindByID() [Internal]
// - TableSettingsClearByID() [Internal]
// - TableGetBoundSettings() [Internal] // - TableGetBoundSettings() [Internal]
// - TableResetSettings()
// - TableSaveSettings() [Internal] // - TableSaveSettings() [Internal]
// - TableLoadSettings() [Internal] // - TableLoadSettings() [Internal]
// - TableSettingsHandler_ClearAll() [Internal] // - TableSettingsHandler_ClearAll() [Internal]
@ -2835,12 +2856,6 @@ ImGuiTableSettings* ImGui::TableSettingsFindByID(ImGuiID id)
return NULL; return NULL;
} }
void ImGui::TableSettingsClearByID(ImGuiID id)
{
if (ImGuiTableSettings* settings = TableSettingsFindByID(id))
settings->ID = 0;
}
// Get settings for a given table, NULL if none // Get settings for a given table, NULL if none
ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table) ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table)
{ {
@ -2856,6 +2871,15 @@ ImGuiTableSettings* ImGui::TableGetBoundSettings(ImGuiTable* table)
return NULL; return NULL;
} }
// Restore initial state of table (with or without saved settings)
void ImGui::TableResetSettings(ImGuiTable* table)
{
table->IsInitializing = table->IsSettingsDirty = true;
table->IsResetAllRequest = false;
table->IsSettingsRequestLoad = false; // Don't reload from ini
table->SettingsLoadedFlags = ImGuiTableFlags_None; // Mark as nothing loaded so our initialized data becomes authoritative
}
void ImGui::TableSaveSettings(ImGuiTable* table) void ImGui::TableSaveSettings(ImGuiTable* table)
{ {
table->IsSettingsDirty = false; table->IsSettingsDirty = false;
@ -3163,6 +3187,7 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));
if (!open) if (!open)
return; return;
bool clear_settings = SmallButton("Clear settings");
BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f)", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight()); BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f)", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight());
BulletText("ColumnsWidth: %.1f, AutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); BulletText("ColumnsWidth: %.1f, AutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX); BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX);
@ -3200,6 +3225,8 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
} }
if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) if (ImGuiTableSettings* settings = TableGetBoundSettings(table))
DebugNodeTableSettings(settings); DebugNodeTableSettings(settings);
if (clear_settings)
table->IsResetAllRequest = true;
TreePop(); TreePop();
} }
@ -3221,7 +3248,12 @@ void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings)
TreePop(); TreePop();
} }
#endif // #ifndef IMGUI_DISABLE_METRICS_WINDOW #else // #ifndef IMGUI_DISABLE_METRICS_WINDOW
void ImGui::DebugNodeTable(ImGuiTable*) {}
void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
#endif
//------------------------------------------------------------------------- //-------------------------------------------------------------------------