From 81453ac42cd76aabe2664cd6394e2f335368d17b Mon Sep 17 00:00:00 2001 From: omar Date: Sun, 29 Dec 2019 17:10:42 +0100 Subject: [PATCH] Tables: Comments, better assert, moved some internal flags out of the way. --- imgui.h | 52 +++++++++++++++++++++++++++--------------------- imgui_internal.h | 2 +- imgui_tables.cpp | 21 ++++++++++++------- 3 files changed, 44 insertions(+), 31 deletions(-) diff --git a/imgui.h b/imgui.h index 69ef0d428..a67a541ad 100644 --- a/imgui.h +++ b/imgui.h @@ -671,6 +671,8 @@ namespace ImGui // - In most situations you can use TableNextRow() + TableSetColumnIndex() to populate a table. // - If you are using tables as a sort of grid, populating every columns with the same type of contents, // you may prefer using TableNextCell() instead of TableNextRow() + TableSetColumnIndex(). + // - See Demo->Tables for details. + // - See ImGuiTableFlags_ enums for a description of available flags. #define IMGUI_HAS_TABLE 1 IMGUI_API bool BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true! @@ -678,14 +680,14 @@ namespace ImGui IMGUI_API bool TableNextCell(); // append into the next column (next column, or next row if currently in last column). Return true if column is visible. IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true if column is visible. IMGUI_API int TableGetColumnIndex(); // return current column index. - IMGUI_API const char* TableGetColumnName(int column_n = -1); // return NULL if column didn't have a name declared by TableSetupColumn(). Use pass -1 to use current column. - IMGUI_API bool TableGetColumnIsVisible(int column_n = -1); // return true if column is visible. Same value is also returned by TableNextCell() and TableSetColumnIndex(). Use pass -1 to use current column. - IMGUI_API bool TableGetColumnIsSorted(int column_n = -1); // return true if column is included in the sort specs. Rarely used, can be useful to tell if a data change should trigger resort. Equivalent to test ImGuiTableSortSpecs's ->ColumnsMask & (1 << column_n). Use pass -1 to use current column. + IMGUI_API const char* TableGetColumnName(int column_n = -1); // return NULL if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column. + IMGUI_API bool TableGetColumnIsVisible(int column_n = -1); // return true if column is visible. Same value is also returned by TableNextCell() and TableSetColumnIndex(). Pass -1 to use current column. + IMGUI_API bool TableGetColumnIsSorted(int column_n = -1); // return true if column is included in the sort specs. Rarely used, can be useful to tell if a data change should trigger resort. Equivalent to test ImGuiTableSortSpecs's ->ColumnsMask & (1 << column_n). Pass -1 to use current column. // Tables: Headers & Columns declaration - // - Use TableSetupColumn() to specify resizing policy, default width, name, id, specific flags etc. + // - Use TableSetupColumn() to specify label, resizing policy, default width, id, various other flags etc. // - The name passed to TableSetupColumn() is used by TableAutoHeaders() and by the context-menu // - Use TableAutoHeaders() to submit the whole header row, otherwise you may treat the header row as a regular row, manually call TableHeader() and other widgets. - // - Headers are required to perform some interactions: reordering, sorting, context menu // FIXME-TABLES: remove context from this list! + // - Headers are required to perform some interactions: reordering, sorting, context menu // FIXME-TABLE: remove context from this list! IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = -1.0f, ImU32 user_id = 0); IMGUI_API void TableAutoHeaders(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu IMGUI_API void TableHeader(const char* label); // submit one header cell manually. @@ -1005,6 +1007,10 @@ enum ImGuiTabItemFlags_ }; // Flags for ImGui::BeginTable() +// - Columns can either varying resizing policy: "Fixed", "Stretch" or "AlwaysAutoResize". Toggling ScrollX needs to alter default sizing policy. +// - Sizing policy have many subtle side effects which may be hard to fully comprehend at first.. They'll eventually make sense. +// - with SizingPolicyFixedX (default is ScrollX is on): Columns can be enlarged as needed. Enable scrollbar if ScrollX is enabled, otherwise extend parent window's contents rect. Only Fixed columns allowed. Weighted columns will calculate their width assuming no scrolling. +// - with SizingPolicyStretchX (default is ScrollX is off): Fit all columns within available table width (so it doesn't make sense to use ScrollX with Stretch columns!). Fixed and Weighted columns allowed. enum ImGuiTableFlags_ { // Features @@ -1023,26 +1029,26 @@ enum ImGuiTableFlags_ ImGuiTableFlags_BordersFullHeight = 1 << 10, // Borders covers all lines even when Headers are being used, allow resizing all rows. ImGuiTableFlags_Borders = ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersH, // Padding, Sizing - ImGuiTableFlags_NoClipX = 1 << 12, // Disable pushing clipping rectangle for every individual columns (reduce draw command count, items with be able to overflow) - ImGuiTableFlags_SizingPolicyStretchX = 1 << 13, // (Default if ScrollX is off) Columns will default to use ImGuiTableColumnFlags_WidthStretch. Fit all columns within available width. Fixed and Weighted columns allowed. - ImGuiTableFlags_SizingPolicyFixedX = 1 << 14, // (Default if ScrollX is on) Columns will default to use ImGuiTableColumnFlags_WidthFixed or WidthAuto. Enlarge as needed: enable scrollbar if ScrollX is enabled, otherwise extend parent window's contents rect. Only Fixed columns allowed. Weighted columns will calculate their width assuming no scrolling. - ImGuiTableFlags_NoHeadersWidth = 1 << 15, // Disable header width contribute to automatic width calculation for every columns. + ImGuiTableFlags_NoClipX = 1 << 12, // Disable pushing clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow) + ImGuiTableFlags_SizingPolicyFixedX = 1 << 13, // Default if ScrollX is on. Columns will default to use WidthFixed or WidthAlwaysAutoResize policy. Read description above for more details. + ImGuiTableFlags_SizingPolicyStretchX = 1 << 14, // Default if ScrollX is off. Columns will default to use WidthStretch policy. Read description above for more details. + ImGuiTableFlags_NoHeadersWidth = 1 << 15, // Disable header width contribution to automatic width calculation. ImGuiTableFlags_NoHostExtendY = 1 << 16, // (FIXME-TABLE: Reword as SizingPolicy?) Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible) // Scrolling ImGuiTableFlags_ScrollX = 1 << 17, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Because this create a child window, ScrollY is currently generally recommended when using ScrollX. ImGuiTableFlags_ScrollY = 1 << 18, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. ImGuiTableFlags_Scroll = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY, - ImGuiTableFlags_ScrollFreezeRowsShift_ = 19, // We can lock 1 to 3 rows (starting from the top). Encode each of those values as dedicated flags. - ImGuiTableFlags_ScrollFreezeTopRow = 1 << ImGuiTableFlags_ScrollFreezeRowsShift_, - ImGuiTableFlags_ScrollFreeze2Rows = 2 << ImGuiTableFlags_ScrollFreezeRowsShift_, - ImGuiTableFlags_ScrollFreeze3Rows = 3 << ImGuiTableFlags_ScrollFreezeRowsShift_, - ImGuiTableFlags_ScrollFreezeColumnsShift_ = 21, // We can lock 1 to 3 columns (starting from the left). Encode each of those values as dedicated flags. - ImGuiTableFlags_ScrollFreezeLeftColumn = 1 << ImGuiTableFlags_ScrollFreezeColumnsShift_, - ImGuiTableFlags_ScrollFreeze2Columns = 2 << ImGuiTableFlags_ScrollFreezeColumnsShift_, - ImGuiTableFlags_ScrollFreeze3Columns = 3 << ImGuiTableFlags_ScrollFreezeColumnsShift_, - - // Combinations and masks + ImGuiTableFlags_ScrollFreezeTopRow = 1 << 19, // We can lock 1 to 3 rows (starting from the top). Use with ScrollY enabled. + ImGuiTableFlags_ScrollFreeze2Rows = 2 << 19, + ImGuiTableFlags_ScrollFreeze3Rows = 3 << 19, + ImGuiTableFlags_ScrollFreezeLeftColumn = 1 << 21, // We can lock 1 to 3 columns (starting from the left). Use with ScrollX enabled. + ImGuiTableFlags_ScrollFreeze2Columns = 2 << 21, + ImGuiTableFlags_ScrollFreeze3Columns = 3 << 21, + + // [Internal] Combinations and masks ImGuiTableFlags_SizingPolicyMaskX_ = ImGuiTableFlags_SizingPolicyStretchX | ImGuiTableFlags_SizingPolicyFixedX, + ImGuiTableFlags_ScrollFreezeRowsShift_ = 19, + ImGuiTableFlags_ScrollFreezeColumnsShift_ = 21, ImGuiTableFlags_ScrollFreezeRowsMask_ = 0x03 << ImGuiTableFlags_ScrollFreezeRowsShift_, ImGuiTableFlags_ScrollFreezeColumnsMask_ = 0x03 << ImGuiTableFlags_ScrollFreezeColumnsShift_ }; @@ -1066,13 +1072,13 @@ enum ImGuiTableColumnFlags_ ImGuiTableColumnFlags_NoHeaderWidth = 1 << 11, // Header width don't contribute to automatic column width. ImGuiTableColumnFlags_PreferSortAscending = 1 << 12, // Make the initial sort direction Ascending when first sorting on this column (default). ImGuiTableColumnFlags_PreferSortDescending = 1 << 13, // Make the initial sort direction Descending when first sorting on this column. - //ImGuiTableColumnFlags_AlignLeft = 1 << 14, - //ImGuiTableColumnFlags_AlignCenter = 1 << 15, - //ImGuiTableColumnFlags_AlignRight = 1 << 16, - // Combinations and masks + // [Internal] Combinations and masks ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthAlwaysAutoResize, ImGuiTableColumnFlags_NoDirectResize_ = 1 << 20 // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge) + //ImGuiTableColumnFlags_AlignLeft = 1 << 14, + //ImGuiTableColumnFlags_AlignCenter = 1 << 15, + //ImGuiTableColumnFlags_AlignRight = 1 << 16, //ImGuiTableColumnFlags_AlignMask_ = ImGuiTableColumnFlags_AlignLeft | ImGuiTableColumnFlags_AlignCenter | ImGuiTableColumnFlags_AlignRight }; diff --git a/imgui_internal.h b/imgui_internal.h index ea9b552b2..7f2dc1d9b 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1895,7 +1895,7 @@ struct ImGuiTable int CurrentColumn; int CurrentRow; ImS16 InstanceNo; // Count of BeginTable() calls with same ID in the same frame (generally 0) - ImS16 InstanceInteracted; + ImS16 InstanceInteracted; // Mark which instance (generally 0) of the same ID is being interacted with float RowPosY1; float RowPosY2; float RowTextBaseline; diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 4edcaad0d..79ec8ef79 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp @@ -106,6 +106,7 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags) flags |= ImGuiTableFlags_BordersV; // Adjust flags: disable top rows freezing if there's no scrolling + // In theory we could want to assert if ScrollFreeze was set without the corresponding scroll flag, but that would hinder demos. if ((flags & ImGuiTableFlags_ScrollX) == 0) flags &= ~ImGuiTableFlags_ScrollFreezeColumnsMask_; if ((flags & ImGuiTableFlags_ScrollY) == 0) @@ -154,6 +155,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG { ImGuiContext& g = *GImGui; ImGuiWindow* outer_window = GetCurrentWindow(); + + // Sanity checks IM_ASSERT(columns_count > 0 && columns_count < IMGUI_TABLE_MAX_COLUMNS && "Only 0..63 columns allowed!"); if (flags & ImGuiTableFlags_ScrollX) IM_ASSERT(inner_width >= 0.0f); @@ -840,7 +843,7 @@ void ImGui::EndTable() { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL); + IM_ASSERT(table != NULL && "Only call EndTable() is BeginTable() returns true!"); const ImGuiTableFlags flags = table->Flags; ImGuiWindow* inner_window = table->InnerWindow; @@ -1292,8 +1295,8 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, { ImGuiContext& g = *GImGui; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table != NULL && "Can only call TableSetupColumn() after BeginTable()!"); - IM_ASSERT(!table->IsLayoutLocked && "Can only call TableSetupColumn() before first row!"); + IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); + IM_ASSERT(!table->IsLayoutLocked && "Need to call call TableSetupColumn() before first row!"); IM_ASSERT(table->DeclColumnsCount >= 0 && table->DeclColumnsCount < table->ColumnsCount && "Called TableSetupColumn() too many times!"); ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; @@ -1505,7 +1508,8 @@ void ImGui::TableEndRow(ImGuiTable* table) table->IsInsideRow = false; } -// [Internal] This is called a lot, so we need to be mindful of unnecessary overhead! +// [Internal] Called by TableNextRow()TableNextCell()! +// This is called a lot, so we need to be mindful of unnecessary overhead. void ImGui::TableBeginCell(ImGuiTable* table, int column_no) { table->CurrentColumn = column_no; @@ -1550,7 +1554,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_no) } } -// [Internal] +// [Internal] Called by TableNextRow()TableNextCell()! void ImGui::TableEndCell(ImGuiTable* table) { ImGuiTableColumn* column = &table->Columns[table->CurrentColumn]; @@ -1684,6 +1688,7 @@ void ImGui::PopTableBackground() PopClipRect(); } +// Output context menu into current window (generally a popup) // FIXME-TABLE: Ideally this should be writable by the user. Full programmatic access to that data? void ImGui::TableDrawContextMenu(ImGuiTable* table, int selected_column_n) { @@ -1751,7 +1756,7 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table, int selected_column_n) } } -// This is a helper to output headers based on the column names declared in TableSetupColumn() +// This is a helper to output TableHeader() calls based on the column names declared in TableSetupColumn(). // The intent is that advanced users would not need to use this helper and may create their own. void ImGui::TableAutoHeaders() { @@ -1761,7 +1766,8 @@ void ImGui::TableAutoHeaders() return; ImGuiTable* table = g.CurrentTable; - IM_ASSERT(table && table->CurrentRow == -1); + IM_ASSERT(table != NULL && "Need to call TableAutoHeaders() after BeginTable()!"); + IM_ASSERT(table->CurrentRow == -1); int open_context_popup = INT_MAX; @@ -1852,6 +1858,7 @@ void ImGui::TableHeader(const char* label) return; ImGuiTable* table = g.CurrentTable; + IM_ASSERT(table != NULL && "Need to call TableAutoHeaders() after BeginTable()!"); IM_ASSERT(table->CurrentColumn != -1); const int column_n = table->CurrentColumn; ImGuiTableColumn* column = &table->Columns[column_n];