Merge branch 'master' into docking

This commit is contained in:
ocornut 2021-01-08 18:55:16 +01:00
commit 70703da782
4 changed files with 475 additions and 349 deletions

34
imgui.h
View File

@ -1081,11 +1081,11 @@ enum ImGuiTabItemFlags_
// Flags for ImGui::BeginTable() // Flags for ImGui::BeginTable()
// - Important! Sizing policies have complex and subtle side effects, more so than you would expect. // - Important! Sizing policies have complex and subtle side effects, more so than you would expect.
// Read comments/demos carefully + experiment with live demos to get acquainted with them. // Read comments/demos carefully + experiment with live demos to get acquainted with them.
// - The DEFAULT policy depends on whether the _ScrollX flag is set on the table, and whether _AlwaysAutoResize flag is set on window. // - The DEFAULT sizing policies are:
// - ImGuiTableFlags_SizingPolicyStretch is the default if ScrollX if off. // - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize.
// - ImGuiTableFlags_SizingPolicyFixed is the default if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize. // - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off.
// - When ScrollX is off: // - When ScrollX is off:
// - Table defaults to ImGuiTableFlags_SizingPolicyStretch -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch. // - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight.
// - Columns sizing policy allowed: Stretch (default), Fixed/Auto. // - Columns sizing policy allowed: Stretch (default), Fixed/Auto.
// - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all). // - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all).
// - Stretch Columns will share the remaining width. // - Stretch Columns will share the remaining width.
@ -1093,9 +1093,10 @@ enum ImGuiTabItemFlags_
// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns. // The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.
// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing). // (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing).
// - When ScrollX is on: // - When ScrollX is on:
// - Table defaults to ImGuiTableFlags_SizingPolicyFixed -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed or ImGuiTableColumnFlags_WidthAuto. // - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed or ImGuiTableColumnFlags_WidthAuto.
// - Columns sizing policy allowed: Fixed/Auto mostly. // - Columns sizing policy allowed: Fixed/Auto mostly.
// - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed. // - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed.
// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop.
// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable(). // - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable().
// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again. // If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again.
// - Read on documentation at the top of imgui_tables.cpp for details. // - Read on documentation at the top of imgui_tables.cpp for details.
@ -1122,11 +1123,12 @@ enum ImGuiTableFlags_
ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders. ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders.
ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style
ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style
// Sizing Policy // Sizing Policy (read above for defaults)
ImGuiTableFlags_SizingPolicyFixed = 1 << 13, // [Default if ScrollX is on] Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width. ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width.
ImGuiTableFlags_SizingPolicyStretch = 1 << 14, // [Default if ScrollX is off] Columns default to _WidthStretch with same weights. ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible.
ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths.
ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overriden by TableSetupColumn().
// Sizing Extra Options // Sizing Extra Options
ImGuiTableFlags_SameWidths = 1 << 15, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable.
ImGuiTableFlags_NoHostExtendY = 1 << 16, // Disable extending table past the limit set by outer_size.y. Only meaningful when neither ScrollX nor ScrollY are set (data below the limit will be clipped and not visible) ImGuiTableFlags_NoHostExtendY = 1 << 16, // Disable extending table past the limit set by outer_size.y. Only meaningful when neither ScrollX nor ScrollY are set (data below the limit will be clipped and not visible)
ImGuiTableFlags_NoKeepColumnsVisible = 1 << 17, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable. ImGuiTableFlags_NoKeepColumnsVisible = 1 << 17, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable.
ImGuiTableFlags_PreciseWidths = 1 << 18, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth. ImGuiTableFlags_PreciseWidths = 1 << 18, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.
@ -1141,11 +1143,15 @@ enum ImGuiTableFlags_
ImGuiTableFlags_ScrollY = 1 << 24, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. ImGuiTableFlags_ScrollY = 1 << 24, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
// Sorting // Sorting
ImGuiTableFlags_SortMulti = 1 << 25, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1). ImGuiTableFlags_SortMulti = 1 << 25, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
ImGuiTableFlags_SortTristate = 1 << 26 // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0). ImGuiTableFlags_SortTristate = 1 << 26, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
// [Internal] Combinations and masks
ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame
// Obsolete names (will be removed soon) // Obsolete names (will be removed soon)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
, ImGuiTableFlags_ColumnsWidthFixed = ImGuiTableFlags_SizingPolicyFixed, ImGuiTableFlags_ColumnsWidthStretch = ImGuiTableFlags_SizingPolicyStretch , ImGuiTableFlags_ColumnsWidthFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_ColumnsWidthStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2020/12
, ImGuiTableFlags_SizingPolicyFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingPolicyStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2021/01
#endif #endif
}; };
@ -1156,9 +1162,9 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_None = 0, ImGuiTableColumnFlags_None = 0,
ImGuiTableColumnFlags_DefaultHide = 1 << 0, // Default as a hidden/disabled column. ImGuiTableColumnFlags_DefaultHide = 1 << 0, // Default as a hidden/disabled column.
ImGuiTableColumnFlags_DefaultSort = 1 << 1, // Default as a sorting column. ImGuiTableColumnFlags_DefaultSort = 1 << 1, // Default as a sorting column.
ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingPolicyStretch). ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp).
ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingPolicyFixed and table is resizable). ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable).
ImGuiTableColumnFlags_WidthAuto = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _SizingPolicyFixed and table is not resizable). Generally compatible with using right-most fitting widgets (e.g. SetNextItemWidth(-FLT_MIN)) ImGuiTableColumnFlags_WidthAuto = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _SizingFixedFit and table is not resizable, or policy is _SizingFixedSame). Generally compatible with using right-most fitting widgets (e.g. SetNextItemWidth(-FLT_MIN))
ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing. ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing.
ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column. ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column.
ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column. ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column.

View File

@ -3403,8 +3403,8 @@ const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
static void PushStyleCompact() static void PushStyleCompact()
{ {
ImGuiStyle& style = ImGui::GetStyle(); ImGuiStyle& style = ImGui::GetStyle();
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.70f))); ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.70f))); ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
} }
static void PopStyleCompact() static void PopStyleCompact()
@ -3412,6 +3412,49 @@ static void PopStyleCompact()
ImGui::PopStyleVar(2); ImGui::PopStyleVar(2);
} }
// Show a combo box with a choice of sizing policies
static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
{
struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
static const EnumDesc policies[] =
{
{ ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
{ ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
{ ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
{ ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
{ ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
};
int idx;
for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
break;
const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
if (ImGui::BeginCombo("Sizing Policy", preview_text))
{
for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
if (ImGui::Selectable(policies[n].Name, idx == n))
*p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
ImGui::EndCombo();
}
ImGui::SameLine();
ImGui::TextDisabled("(?)");
if (ImGui::IsItemHovered())
{
ImGui::BeginTooltip();
ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
{
ImGui::Separator();
ImGui::Text("%s:", policies[m].Name);
ImGui::Separator();
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
ImGui::TextUnformatted(policies[m].Tooltip);
}
ImGui::PopTextWrapPos();
ImGui::EndTooltip();
}
}
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags) static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
{ {
ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide); ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
@ -3576,12 +3619,12 @@ static void ShowDemoWindowTables()
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter); ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner); ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
ImGui::Unindent(); ImGui::Unindent();
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:"); ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text); ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton); ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
ImGui::Checkbox("Display headers", &display_headers); ImGui::Checkbox("Display headers", &display_headers);
ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
PopStyleCompact(); PopStyleCompact();
if (ImGui::BeginTable("##table1", 3, flags)) if (ImGui::BeginTable("##table1", 3, flags))
@ -3621,11 +3664,11 @@ static void ShowDemoWindowTables()
{ {
// By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch" // By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch"
// Each columns maintain a sizing weight, and they will occupy all available width. // Each columns maintain a sizing weight, and they will occupy all available width.
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
PushStyleCompact(); PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersV flag as well."); ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this.");
PopStyleCompact(); PopStyleCompact();
if (ImGui::BeginTable("##table1", 3, flags)) if (ImGui::BeginTable("##table1", 3, flags))
@ -3648,21 +3691,22 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Resizable, fixed")) if (ImGui::TreeNode("Resizable, fixed"))
{ {
// Here we use ImGuiTableFlags_SizingPolicyFixed (even though _ScrollX is not set) // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
// So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small) // So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
// If there is not enough available width to fit all columns, they will however be resized down. // If there is not enough available width to fit all columns, they will however be resized down.
// FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings // FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
HelpMarker( HelpMarker(
"Using _Resizable + _SizingPolicyFixed flags.\n" "Using _Resizable + _SizingFixedFit flags.\n"
"Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n" "Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
"Double-click a column border to auto-fit the column to its contents."); "Double-click a column border to auto-fit the column to its contents.");
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingPolicyFixed | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; PushStyleCompact();
static bool use_all_width = true; static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
if (ImGui::RadioButton("fit", use_all_width == false)) { use_all_width = false; } static bool fixed_fill = true;
ImGui::SameLine(); ImGui::Checkbox("fill", &fixed_fill);
if (ImGui::RadioButton("right-most edge", use_all_width == true)) { use_all_width = true; } PopStyleCompact();
if (ImGui::BeginTable("##table1", 3, flags, ImVec2(use_all_width ? -FLT_MIN : 0.0f, 0.0f))) ImVec2 outer_size(fixed_fill ? -FLT_MIN : 0.0f, 0.0f);
if (ImGui::BeginTable("##table1", 3, flags, outer_size))
{ {
for (int row = 0; row < 5; row++) for (int row = 0; row < 5; row++)
{ {
@ -3682,8 +3726,10 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Resizable, mixed")) if (ImGui::TreeNode("Resizable, mixed"))
{ {
HelpMarker("Using columns flag to alter resizing policy on a per-column basis."); HelpMarker(
static ImGuiTableFlags flags = ImGuiTableFlags_SizingPolicyFixed | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
"When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
if (ImGui::BeginTable("##table1", 3, flags)) if (ImGui::BeginTable("##table1", 3, flags))
{ {
@ -3729,7 +3775,9 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Reorderable, hideable, with headers")) if (ImGui::TreeNode("Reorderable, hideable, with headers"))
{ {
HelpMarker("Click and drag column headers to reorder columns.\n\nYou can also right-click on a header to open a context menu."); HelpMarker(
"Click and drag column headers to reorder columns.\n\n"
"Right-click on a header to open a context menu.");
static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
PushStyleCompact(); PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
@ -3760,7 +3808,7 @@ static void ShowDemoWindowTables()
} }
// Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column) // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column)
if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_SizingPolicyFixed, ImVec2(0.0f, 0.0f))) if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
{ {
ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("One");
ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Two");
@ -3792,7 +3840,8 @@ static void ShowDemoWindowTables()
"- BorderOuterV\n" "- BorderOuterV\n"
"- any form of row selection\n" "- any form of row selection\n"
"Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n" "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n"
"Actual padding values are using style.CellPadding."); "Actual padding values are using style.CellPadding.\n\n"
"In this demo we don't show horizontal borders to emphasis how they don't affect default horizontal padding.");
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV; static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
PushStyleCompact(); PushStyleCompact();
@ -3846,7 +3895,7 @@ static void ShowDemoWindowTables()
HelpMarker("Setting style.CellPadding to (0,0) or a custom value."); HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg; static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
static ImVec2 cell_padding(0.0f, 0.0f); static ImVec2 cell_padding(0.0f, 0.0f);
static bool show_widget_frame_bg = false; static bool show_widget_frame_bg = true;
PushStyleCompact(); PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders); ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
@ -3889,32 +3938,108 @@ static void ShowDemoWindowTables()
if (open_action != -1) if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Explicit widths")) if (ImGui::TreeNode("Sizing policies"))
{ {
static ImGuiTableFlags flags = ImGuiTableFlags_None; static bool fixed_fill = true;
static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
PushStyleCompact(); PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); ImGui::Checkbox("fill", &fixed_fill);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV); ImGui::SameLine(); HelpMarker(
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV); "Value passed to outer_size only affects tables with _SizingFixedFit or _SizingFixedSame sizing policies.\n\n"
" - outer_size.x == 0: table fit to columns total contents.\n"
" - outer_size.x == -FLT_MIN: table fill until right-most edge.");
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
PopStyleCompact(); PopStyleCompact();
if (ImGui::BeginTable("##table1", 4, flags)) ImVec2 outer_size = ImVec2(fixed_fill ? -FLT_MIN : 0.0f, 0.0f);
static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
for (int table_n = 0; table_n < 4; table_n++)
{ {
// We could also set ImGuiTableFlags_SizingPolicyFixed on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed. ImGui::PushID(table_n);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f); ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); EditTableSizingFlags(&sizing_policy_flags[table_n]);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f); // To make it easier to understand the different sizing policy,
for (int row = 0; row < 5; row++) // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width.
if (ImGui::BeginTable("##table1", 3, sizing_policy_flags[table_n] | flags1, outer_size))
{
for (int row = 0; row < 3; row++)
{ {
ImGui::TableNextRow(); ImGui::TableNextRow();
for (int column = 0; column < 4; column++) ImGui::TableNextColumn(); ImGui::Text("Oh dear");
{ ImGui::TableNextColumn(); ImGui::Text("Oh dear");
ImGui::TableSetColumnIndex(column); ImGui::TableNextColumn(); ImGui::Text("Oh dear");
if (row == 0)
ImGui::Text("(%.2f)", ImGui::GetContentRegionAvail().x);
ImGui::Text("Hello %d,%d", column, row);
} }
ImGui::EndTable();
}
if (ImGui::BeginTable("##table2", 3, sizing_policy_flags[table_n] | flags1, outer_size))
{
for (int row = 0; row < 3; row++)
{
ImGui::TableNextRow();
ImGui::TableNextColumn(); ImGui::Text("AAAA");
ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
}
ImGui::EndTable();
}
ImGui::PopID();
}
ImGui::Spacing();
ImGui::TextUnformatted("Advanced");
ImGui::SameLine();
HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns.");
enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
static int contents_type = CT_ShowWidth;
static int column_count = 3;
PushStyleCompact();
ImGui::PushID("Advanced");
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
EditTableSizingFlags(&flags);
ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
if (contents_type == CT_FillButton)
{
ImGui::SameLine();
HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width.");
}
ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
ImGui::PopItemWidth();
ImGui::PopID();
PopStyleCompact();
outer_size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 7);
if (ImGui::BeginTable("##table2", column_count, flags, outer_size))
{
for (int cell = 0; cell < 10 * column_count; cell++)
{
ImGui::TableNextColumn();
int column = ImGui::TableGetColumnIndex();
int row = ImGui::TableGetRowIndex();
ImGui::PushID(cell);
char label[32];
static char text_buf[32] = "";
sprintf(label, "Hello %d,%d", column, row);
switch (contents_type)
{
case CT_ShortText: ImGui::TextUnformatted(label); break;
case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
case CT_Button: ImGui::Button(label); break;
case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
}
ImGui::PopID();
} }
ImGui::EndTable(); ImGui::EndTable();
} }
@ -3968,7 +4093,7 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNode("Horizontal scrolling")) if (ImGui::TreeNode("Horizontal scrolling"))
{ {
HelpMarker( HelpMarker(
"When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingPolicyFixed," "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
"as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n" "as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
"Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX," "Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX,"
"because the container window won't automatically extend vertically to fix contents (this may be improved in future versions)."); "because the container window won't automatically extend vertically to fix contents (this may be improved in future versions).");
@ -4021,6 +4146,33 @@ static void ShowDemoWindowTables()
} }
ImGui::EndTable(); ImGui::EndTable();
} }
ImGui::Spacing();
ImGui::TextUnformatted("Stretch + ScrollX");
ImGui::SameLine();
HelpMarker(
"Showcase using Stretch columns + ScrollX together: "
"this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
"Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense.");
static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
static float inner_width = 1000.0f;
PushStyleCompact();
ImGui::PushID("flags3");
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
ImGui::PopItemWidth();
ImGui::PopID();
PopStyleCompact();
if (ImGui::BeginTable("##table2", 7, flags2, outer_size, inner_width))
{
for (int cell = 0; cell < 20 * 7; cell++)
{
ImGui::TableNextColumn();
ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
}
ImGui::EndTable();
}
ImGui::TreePop(); ImGui::TreePop();
} }
@ -4059,7 +4211,7 @@ static void ShowDemoWindowTables()
// We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in // We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in
// a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down) // a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down)
const ImGuiTableFlags flags const ImGuiTableFlags flags
= ImGuiTableFlags_SizingPolicyFixed | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
| ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable; | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
ImVec2 size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 9); ImVec2 size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 9);
@ -4090,7 +4242,43 @@ static void ShowDemoWindowTables()
if (open_action != -1) if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Nested")) if (ImGui::TreeNode("Columns widths"))
{
HelpMarker("Using TableSetupColumn() to setup explicit width.");
static ImGuiTableFlags flags = ImGuiTableFlags_None;
PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
PopStyleCompact();
if (ImGui::BeginTable("##table1", 4, flags))
{
// We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
for (int row = 0; row < 5; row++)
{
ImGui::TableNextRow();
for (int column = 0; column < 4; column++)
{
ImGui::TableSetColumnIndex(column);
if (row == 0)
ImGui::Text("(%.2f)", ImGui::GetContentRegionAvail().x);
ImGui::Text("Hello %d,%d", column, row);
}
}
ImGui::EndTable();
}
ImGui::TreePop();
}
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Nested tables"))
{ {
HelpMarker("This demonstrate embedding a table into another table cell."); HelpMarker("This demonstrate embedding a table into another table cell.");
@ -4132,141 +4320,6 @@ static void ShowDemoWindowTables()
ImGui::TreePop(); ImGui::TreePop();
} }
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Sizing policies, cell contents"))
{
HelpMarker("This section allows you to interact and see the effect of StretchX vs FixedX sizing policies depending on whether Scroll is enabled and the contents of your columns.");
enum ContentsType { CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg;
static int contents_type = CT_LongText;
static int column_count = 3;
PushStyleCompact();
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
ImGui::Combo("Contents", &contents_type, "Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
if (contents_type == CT_FillButton)
{
ImGui::SameLine();
HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width.");
}
ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
ImGui::PopItemWidth();
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyStretch", &flags, ImGuiTableFlags_SizingPolicyStretch))
flags &= ~ImGuiTableFlags_SizingPolicyFixed; // Can't specify both sizing polices so we clear the other
ImGui::SameLine(); HelpMarker("Default if _ScrollX if disabled. Makes columns use _WidthStretch policy by default.");
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyFixed", &flags, ImGuiTableFlags_SizingPolicyFixed))
flags &= ~ImGuiTableFlags_SizingPolicyStretch; // Can't specify both sizing polices so we clear the other
ImGui::SameLine(); HelpMarker("Default if _ScrollX if enabled. Makes columns use _WidthFixed by default, or _WidthFixedResize if _Resizable is not set.");
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
PopStyleCompact();
ImVec2 outer_size(-FLT_MIN, TEXT_BASE_HEIGHT * 7);
if (ImGui::BeginTable("##nways", column_count, flags, outer_size))
{
for (int cell = 0; cell < 10 * column_count; cell++)
{
ImGui::TableNextColumn();
int column = ImGui::TableGetColumnIndex();
int row = ImGui::TableGetRowIndex();
ImGui::PushID(cell);
char label[32];
static char text_buf[32] = "";
sprintf(label, "Hello %d,%d", column, row);
switch (contents_type)
{
case CT_ShortText: ImGui::TextUnformatted(label); break;
case CT_LongText: ImGui::Text("Some longer text %d,%d\nOver two lines..", column, row); break;
case CT_Button: ImGui::Button(label); break;
case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
}
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::TextUnformatted("Item Widths");
ImGui::SameLine();
HelpMarker("Showcase using PushItemWidth() and how it is preserved on a per-column basis");
if (ImGui::BeginTable("##table2", 3, ImGuiTableFlags_Borders))
{
ImGui::TableSetupColumn("small");
ImGui::TableSetupColumn("half");
ImGui::TableSetupColumn("right-align");
ImGui::TableHeadersRow();
for (int row = 0; row < 3; row++)
{
ImGui::TableNextRow();
if (row == 0)
{
// Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
ImGui::TableSetColumnIndex(0);
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
ImGui::TableSetColumnIndex(1);
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
ImGui::TableSetColumnIndex(2);
ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
}
// Draw our contents
static float dummy_f = 0.0f;
ImGui::PushID(row);
ImGui::TableSetColumnIndex(0);
ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
ImGui::TableSetColumnIndex(1);
ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
ImGui::TableSetColumnIndex(2);
ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f);
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::TextUnformatted("Stretch + ScrollX");
ImGui::SameLine();
HelpMarker(
"Showcase using Stretch columns + ScrollX together: "
"this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
"Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense.");
static ImGuiTableFlags flags3 = ImGuiTableFlags_SizingPolicyStretch | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg;
static float inner_width = 1000.0f;
PushStyleCompact();
ImGui::PushID("flags3");
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags3, ImGuiTableFlags_ScrollX);
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyStretch", &flags3, ImGuiTableFlags_SizingPolicyStretch))
flags3 &= ~ImGuiTableFlags_SizingPolicyFixed; // Can't specify both sizing polices so we clear the other
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyFixed", &flags3, ImGuiTableFlags_SizingPolicyFixed))
flags3 &= ~ImGuiTableFlags_SizingPolicyStretch; // Can't specify both sizing polices so we clear the other
ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
ImGui::PopItemWidth();
ImGui::PopID();
PopStyleCompact();
if (ImGui::BeginTable("##table3", 7, flags3 | ImGuiTableFlags_SizingPolicyStretch | ImGuiTableFlags_ContextMenuInBody, outer_size, inner_width))
{
for (int cell = 0; cell < 20 * 7; cell++)
{
ImGui::TableNextColumn();
ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
}
ImGui::EndTable();
}
ImGui::TreePop();
}
if (open_action != -1) if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Row height")) if (ImGui::TreeNode("Row height"))
@ -4294,11 +4347,15 @@ static void ShowDemoWindowTables()
// The default value of outer_size.x is -FLT_MIN which right-align tables. // The default value of outer_size.x is -FLT_MIN which right-align tables.
// Using outer_size.x == 0.0f on a table with no scrolling and no stretch column we can make them tighter. // Using outer_size.x == 0.0f on a table with no scrolling and no stretch column we can make them tighter.
ImGui::Text("Using auto/all width, using NoHostExtendY:"); ImGui::Text("Using auto/all width, using NoHostExtendY:");
static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingPolicyFixed; PushStyleCompact();
static bool use_all_width = false; static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit;
ImGui::Checkbox("Use all width", &use_all_width); static bool fixed_fill = false;
ImGui::Checkbox("fill", &fixed_fill);
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
if (ImGui::BeginTable("##table3", 3, flags, ImVec2(use_all_width ? -FLT_MIN : 0.0f, TEXT_BASE_HEIGHT * 5.5f))) PopStyleCompact();
ImVec2 outer_size = ImVec2(fixed_fill ? -FLT_MIN : 0.0f, TEXT_BASE_HEIGHT * 5.5f);
if (ImGui::BeginTable("##table3", 3, flags, outer_size))
{ {
for (int row = 0; row < 10; row++) for (int row = 0; row < 10; row++)
{ {
@ -4476,6 +4533,50 @@ static void ShowDemoWindowTables()
ImGui::TreePop(); ImGui::TreePop();
} }
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Item width"))
{
HelpMarker(
"Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
"Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense.");
if (ImGui::BeginTable("##table2", 3, ImGuiTableFlags_Borders))
{
ImGui::TableSetupColumn("small");
ImGui::TableSetupColumn("half");
ImGui::TableSetupColumn("right-align");
ImGui::TableHeadersRow();
for (int row = 0; row < 3; row++)
{
ImGui::TableNextRow();
if (row == 0)
{
// Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
ImGui::TableSetColumnIndex(0);
ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
ImGui::TableSetColumnIndex(1);
ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
ImGui::TableSetColumnIndex(2);
ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
}
// Draw our contents
static float dummy_f = 0.0f;
ImGui::PushID(row);
ImGui::TableSetColumnIndex(0);
ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
ImGui::TableSetColumnIndex(1);
ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
ImGui::TableSetColumnIndex(2);
ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f);
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::TreePop();
}
// Demonstrate using TableHeader() calls instead of TableHeadersRow() // Demonstrate using TableHeader() calls instead of TableHeadersRow()
if (open_action != -1) if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0); ImGui::SetNextItemOpen(open_action != 0);
@ -4566,7 +4667,7 @@ static void ShowDemoWindowTables()
// [2.2] Right-click on the ".." to open a custom popup // [2.2] Right-click on the ".." to open a custom popup
// [2.3] Right-click in columns to open another custom popup // [2.3] Right-click in columns to open another custom popup
HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body)."); HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body).");
ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingPolicyFixed | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders; ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
if (ImGui::BeginTable("##table2", COLUMNS_COUNT, flags2)) if (ImGui::BeginTable("##table2", COLUMNS_COUNT, flags2))
{ {
ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("One");
@ -4640,7 +4741,7 @@ static void ShowDemoWindowTables()
char buf[32]; char buf[32];
sprintf(buf, "Synced Table %d", n); sprintf(buf, "Synced Table %d", n);
bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen); bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingPolicyFixed | ImGuiTableFlags_NoSavedSettings)) if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings))
{ {
ImGui::TableSetupColumn("One"); ImGui::TableSetupColumn("One");
ImGui::TableSetupColumn("Two"); ImGui::TableSetupColumn("Two");
@ -4689,10 +4790,12 @@ static void ShowDemoWindowTables()
ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollY; | ImGuiTableFlags_ScrollY;
PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti); ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1)."); ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate); ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0)."); ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
PopStyleCompact();
if (ImGui::BeginTable("##table", 4, flags, ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 15), 0.0f)) if (ImGui::BeginTable("##table", 4, flags, ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 15), 0.0f))
{ {
@ -4756,7 +4859,7 @@ static void ShowDemoWindowTables()
| ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_SizingPolicyFixed; | ImGuiTableFlags_SizingFixedFit;
enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow }; enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
static int contents_type = CT_SelectableSpanRow; static int contents_type = CT_SelectableSpanRow;
@ -4805,18 +4908,13 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen)) if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
{ {
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyStretch", &flags, ImGuiTableFlags_SizingPolicyStretch)) EditTableSizingFlags(&flags);
flags &= ~ImGuiTableFlags_SizingPolicyFixed; // Can't specify both sizing polices so we clear the other ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
ImGui::SameLine(); HelpMarker("[Default if ScrollX is off]\nFit all columns within available width (or specified inner_width). Fixed and Stretch columns allowed.");
if (ImGui::CheckboxFlags("ImGuiTableFlags_SizingPolicyFixed", &flags, ImGuiTableFlags_SizingPolicyFixed))
flags &= ~ImGuiTableFlags_SizingPolicyStretch; // Can't specify both sizing polices so we clear the other
ImGui::SameLine(); HelpMarker("[Default if ScrollX is on]\nEnlarge as needed: enable scrollbar if ScrollX is enabled, otherwise extend parent window's contents rectangle. Only Fixed columns allowed. Stretched columns will calculate their width assuming no scrolling.");
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY); ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible); ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled."); ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths); ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth."); ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
ImGui::CheckboxFlags("ImGuiTableFlags_SameWidths", &flags, ImGuiTableFlags_SameWidths);
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip); ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options."); ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
ImGui::TreePop(); ImGui::TreePop();

View File

@ -2120,19 +2120,19 @@ typedef ImU8 ImGuiTableDrawChannelIdx;
// 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
{ {
ImRect ClipRect; // Clipping rectangle for the column
ImGuiID UserID; // Optional, value passed to TableSetupColumn()
ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_ ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_
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 MinX; // Absolute positions float MinX; // Absolute positions
float MaxX; float MaxX;
float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
float WidthAuto; // Automatic width
float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout() float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout()
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 WidthAuto; // Automatic width
float WorkMinX; // Start position for the frame, currently ~(MinX + CellPaddingX) float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
float WorkMaxX; float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
float ItemWidth; ImRect ClipRect; // Clipping rectangle for the column
ImGuiID UserID; // Optional, value passed to TableSetupColumn()
float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column
float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2)
float ItemWidth; // Current item width for the column, preserved across rows
float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width. float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width.
float ContentMaxXUnfrozen; float ContentMaxXUnfrozen;
float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls
@ -2261,7 +2261,7 @@ struct ImGuiTable
ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn() ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn()
ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column! ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column!
ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing). ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing).
ImGuiTableColumnIdx AutoFitSingleStretchColumn; // Index of single stretch column requesting auto-fit. ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit.
ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0. ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0.
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame. ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held. ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held.

View File

@ -5,6 +5,8 @@
Index of this file: Index of this file:
// [SECTION] Commentary
// [SECTION] Header mess
// [SECTION] Tables: Main code // [SECTION] Tables: Main code
// [SECTION] Tables: Row changes // [SECTION] Tables: Row changes
// [SECTION] Tables: Columns changes // [SECTION] Tables: Columns changes
@ -24,6 +26,10 @@ Index of this file:
// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot. // - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments. // - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
//-----------------------------------------------------------------------------
// [SECTION] Commentary
//-----------------------------------------------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Typical tables call flow: (root level is generally public API): // Typical tables call flow: (root level is generally public API):
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -100,20 +106,29 @@ Index of this file:
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// COLUMNS SIZING POLICIES // COLUMNS SIZING POLICIES
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// About overriding column width/weight with TableSetupColumn(): // About overriding column sizing policy and width/weight with TableSetupColumn():
// We use a default parameter of 'init_width_or_weight == -1'. // We use a default parameter of 'init_width_or_weight == -1'.
// - With ImGuiTableColumnFlags_WidthAuto, init_width (ignored) --> width is automatic // - with ImGuiTableColumnFlags_WidthAuto, init_width (ignored) --> width is automatic
// - With ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic // - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic
// - With ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom // - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom
// - With ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f // - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f
// - With ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom // - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom
// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f) // Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f)
// and you can fit a 100.0f wide item in it without clipping and with full padding. // and you can fit a 100.0f wide item in it without clipping and with full padding.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// About default width policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag) // About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag)
// - When Table policy ImGuiTableFlags_SizingPolicyStretch --> default Column policy is ImGuiTableColumnFlags_WidthStretch // - with Table policy ImGuiTableFlags_SizingFixedFit && (Resizable == 1 || init_width > 0) --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width
// - When Table policy ImGuiTableFlags_SizingPolicyFixed and (Table is Resizable or init_width > 0) --> default Column policy is ImGuiTableColumnFlags_WidthFixed // - with Table policy ImGuiTableFlags_SizingFixedFit && (Resizable == 0 && init_width <= 0) --> default Column policy is ImGuiTableColumnFlags_WidthAuto, Width always equal to contents width
// - When Table policy ImGuiTableFlags_SizingPolicyFixed and (Table is not Resizable and init_width <= 0) --> default Column policy is ImGuiTableColumnFlags_WidthAuto // - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthAuto, default Width is max of all contents width
// - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f
// - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents
//-----------------------------------------------------------------------------
// About mixing Fixed/Auto and Stretch columns together:
// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.
// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place!
// that is, unless 'inner_width' is passed to BeginTable() to explicitely provide a total width to layout columns in.
// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width.
// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -145,6 +160,10 @@ Index of this file:
// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false. // - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
// [SECTION] Header mess
//-----------------------------------------------------------------------------
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS) #if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS
#endif #endif
@ -164,10 +183,6 @@ Index of this file:
#include <stdint.h> // intptr_t #include <stdint.h> // intptr_t
#endif #endif
//-------------------------------------------------------------------------
// Warnings
//-------------------------------------------------------------------------
// Visual Studio warnings // Visual Studio warnings
#ifdef _MSC_VER #ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant #pragma warning (disable: 4127) // condition expression is constant
@ -214,12 +229,12 @@ static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/tim
inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window) inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window)
{ {
// Adjust flags: set default sizing policy // Adjust flags: set default sizing policy
if ((flags & (ImGuiTableFlags_SizingPolicyStretch | ImGuiTableFlags_SizingPolicyFixed)) == 0) if ((flags & ImGuiTableFlags_SizingMask_) == 0)
flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingPolicyFixed : ImGuiTableFlags_SizingPolicyStretch; flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame;
// Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV) // Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame
if (flags & ImGuiTableFlags_SameWidths) if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
flags = (flags & ~ImGuiTableFlags_Resizable) | ImGuiTableFlags_NoKeepColumnsVisible; flags |= ImGuiTableFlags_NoKeepColumnsVisible;
// Adjust flags: enforce borders when resizable // Adjust flags: enforce borders when resizable
if (flags & ImGuiTableFlags_Resizable) if (flags & ImGuiTableFlags_Resizable)
@ -438,7 +453,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->InstanceInteracted = -1; table->InstanceInteracted = -1;
table->ContextPopupColumn = -1; table->ContextPopupColumn = -1;
table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1; table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
table->AutoFitSingleStretchColumn = -1; table->AutoFitSingleColumn = -1;
table->HoveredColumnBody = table->HoveredColumnBorder = -1; table->HoveredColumnBody = table->HoveredColumnBorder = -1;
for (int n = 0; n < columns_count; n++) for (int n = 0; n < columns_count; n++)
{ {
@ -524,12 +539,12 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
table->ResizedColumnNextWidth = FLT_MAX; table->ResizedColumnNextWidth = FLT_MAX;
table->ResizedColumn = -1; table->ResizedColumn = -1;
// Process auto-fit for single stretch column, which is a special case // Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy.
// 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->AutoFitSingleColumn != -1)
{ {
TableSetColumnWidth(table->AutoFitSingleStretchColumn, table->Columns[table->AutoFitSingleStretchColumn].WidthAuto); TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto);
table->AutoFitSingleStretchColumn = -1; table->AutoFitSingleColumn = -1;
} }
} }
@ -586,14 +601,20 @@ static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, I
// Sizing Policy // Sizing Policy
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0)
{ {
// FIXME-TABLE: Inconsistent to promote columns to WidthAuto // FIXME-TABLE: clarify promotion to WidthAuto?
if (table->Flags & ImGuiTableFlags_SizingPolicyFixed) const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
if (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame)
flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAuto; flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAuto;
else else
flags |= ImGuiTableColumnFlags_WidthStretch; flags |= ImGuiTableColumnFlags_WidthStretch;
} }
else
{
IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used. IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used.
if (flags & ImGuiTableColumnFlags_WidthAuto) }
// Resize
if ((flags & ImGuiTableColumnFlags_WidthAuto) != 0 || (table->Flags & ImGuiTableFlags_Resizable) == 0)
flags |= ImGuiTableColumnFlags_NoResize; flags |= ImGuiTableColumnFlags_NoResize;
// Sorting // Sorting
@ -638,16 +659,22 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
IM_ASSERT(table->IsLayoutLocked == false); IM_ASSERT(table->IsLayoutLocked == false);
const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
table->IsDefaultDisplayOrder = true; table->IsDefaultDisplayOrder = true;
table->ColumnsEnabledCount = 0; table->ColumnsEnabledCount = 0;
table->EnabledMaskByIndex = 0x00; table->EnabledMaskByIndex = 0x00;
table->EnabledMaskByDisplayOrder = 0x00; table->EnabledMaskByDisplayOrder = 0x00;
table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
// [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns.
// Process columns in their visible orders as we are building the Prev/Next indices. // Process columns in their visible orders as we are building the Prev/Next indices.
int count_fixed = 0; // Number of columns that have fixed sizing policies
int count_stretch = 0; // Number of columns that have stretch sizing policies
int last_visible_column_idx = -1; int last_visible_column_idx = -1;
bool want_auto_fit = false; bool has_auto_fit_request = false;
bool has_resizable = false;
float stretch_sum_width_auto = 0.0f;
float fixed_max_width_auto = 0.0f;
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];
@ -655,11 +682,10 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
table->IsDefaultDisplayOrder = false; table->IsDefaultDisplayOrder = false;
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
// Clear column settings if not submitted by user. // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame.
// Currently we make it mandatory to call TableSetupColumn() every frame. // It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway.
// It would easily work without but we're ready to guarantee it since e.g. names need resubmission anyway. // We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect.
// In theory we could be calling TableSetupColumn() here with dummy values it should yield the same effect. if (table->DeclColumnsCount <= column_n)
if (column_n >= table->DeclColumnsCount)
{ {
TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None);
column->NameOffset = -1; column->NameOffset = -1;
@ -667,6 +693,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->InitStretchWeightOrWidth = -1.0f; column->InitStretchWeightOrWidth = -1.0f;
} }
// Update Enabled state, mark settings/sortspecs dirty
if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide)) if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))
column->IsEnabledNextFrame = true; column->IsEnabledNextFrame = true;
if (column->IsEnabled != column->IsEnabledNextFrame) if (column->IsEnabled != column->IsEnabledNextFrame)
@ -679,16 +706,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
bool start_auto_fit = false; // Auto-fit unsized columns
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) const bool start_auto_fit = (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f);
start_auto_fit = column->WidthRequest < 0.0f;
else
start_auto_fit = column->StretchWeight < 0.0f;
if (start_auto_fit) if (start_auto_fit)
column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames
ImU64 index_mask = (ImU64)1 << column_n;
ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder;
if (!column->IsEnabled) if (!column->IsEnabled)
{ {
column->IndexWithinEnabledSet = -1; column->IndexWithinEnabledSet = -1;
@ -700,10 +722,9 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->NextEnabledColumn = -1; column->NextEnabledColumn = -1;
if (last_visible_column_idx != -1) if (last_visible_column_idx != -1)
table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n; table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n;
column->IndexWithinEnabledSet = table->ColumnsEnabledCount; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
table->ColumnsEnabledCount++; table->EnabledMaskByIndex |= (ImU64)1 << column_n;
table->EnabledMaskByIndex |= index_mask; table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder;
table->EnabledMaskByDisplayOrder |= display_order_mask;
last_visible_column_idx = column_n; last_visible_column_idx = column_n;
IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
@ -712,8 +733,25 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (!column->IsPreserveWidthAuto) if (!column->IsPreserveWidthAuto)
column->WidthAuto = TableGetColumnWidthAuto(table, column); column->WidthAuto = TableGetColumnWidthAuto(table, column);
// Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)
const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;
if (column_is_resizable)
has_resizable = true;
if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable)
column->WidthAuto = column->InitStretchWeightOrWidth;
if (column->AutoFitQueue != 0x00) if (column->AutoFitQueue != 0x00)
want_auto_fit = true; has_auto_fit_request = true;
if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
{
stretch_sum_width_auto += column->WidthAuto;
count_stretch++;
}
else
{
fixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto);
count_fixed++;
}
} }
if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate)) if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))
table->IsSortSpecsDirty = true; table->IsSortSpecsDirty = true;
@ -721,19 +759,16 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
IM_ASSERT(table->RightMostEnabledColumn >= 0); IM_ASSERT(table->RightMostEnabledColumn >= 0);
// [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible // [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible
// to avoid 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 having 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. // FIXME-TABLE: for always auto-resizing columns may not want to do that all the time.
if (want_auto_fit && table->OuterWindow != table->InnerWindow) if (has_auto_fit_request && table->OuterWindow != table->InnerWindow)
table->InnerWindow->SkipItems = false; table->InnerWindow->SkipItems = false;
if (want_auto_fit) if (has_auto_fit_request)
table->IsSettingsDirty = true; table->IsSettingsDirty = true;
// [Part 3] Fix column flags. Count how many fixed/stretch columns we have and sum of weights. // [Part 3] Fix column flags and record a few extra information.
int count_fixed = 0; // Number of columns that have fixed sizing policy (not stretched sizing policy) (this is NOT the opposite of count_resizable!) float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding.
int count_resizable = 0; // Number of columns the user can resize (this is NOT the opposite of count_fixed!) float stretch_sum_weights = 0.0f; // Sum of all weights for stretch 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 max_width_auto = 0.0f; // Largest auto-width (used for SameWidths feature)
table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
@ -741,21 +776,18 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
continue; continue;
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
// Count resizable columns const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;
if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0)
count_resizable++;
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto))
{ {
// Non-resizable columns keep their requested width // Apply same widths policy
if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f) float width_auto = column->WidthAuto;
if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize)) if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable))
column->WidthRequest = column->WidthAuto = ImMax(column->WidthAuto, column->InitStretchWeightOrWidth); // Use user value regardless of IsPreserveWidthAuto width_auto = fixed_max_width_auto;
// Process auto-fit for non-stretched columns // Apply automatic width
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAuto) && column->IsVisibleX)) if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAuto) && column->IsVisibleX) || ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable))
column->WidthRequest = column->WidthAuto; column->WidthRequest = width_auto;
// 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
@ -765,60 +797,37 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller. // FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller.
if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto) if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto)
column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale? column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale?
count_fixed += 1; sum_width_requests += column->WidthRequest;
sum_width_fixed_requests += column->WidthRequest;
} }
else else
{ {
IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); // Initialize stretch weight
if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable)
{
if (column->InitStretchWeightOrWidth > 0.0f)
column->StretchWeight = column->InitStretchWeightOrWidth;
else if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp)
column->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch;
else
column->StretchWeight = 1.0f;
}
// Revert or initialize weight (when column->StretchWeight < 0.0f normally it means there has been no init value so it'll always default to 1.0f) stretch_sum_weights += column->StretchWeight;
if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f)
column->StretchWeight = (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : 1.0f;
sum_weights_stretched += column->StretchWeight;
if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder) if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder)
table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n; table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n;
if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder) if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder)
table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n; table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n;
} }
column->IsPreserveWidthAuto = false; column->IsPreserveWidthAuto = false;
max_width_auto = ImMax(max_width_auto, column->WidthAuto); sum_width_requests += table->CellPaddingX * 2.0f;
sum_width_fixed_requests += table->CellPaddingX * 2.0f;
} }
table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed; table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
// [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 stretch: use same weight.
const bool mixed_same_widths = (table->Flags & ImGuiTableFlags_SameWidths) && count_fixed > 0;
if (table->Flags & ImGuiTableFlags_SameWidths)
{
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto))
{
sum_width_fixed_requests += max_width_auto - column->WidthRequest; // Update old sum
column->WidthRequest = max_width_auto;
}
else
{
sum_weights_stretched += 1.0f - column->StretchWeight; // Update old sum
column->StretchWeight = 1.0f;
if (mixed_same_widths)
column->WidthRequest = max_width_auto;
}
}
}
// [Part 5] Apply final widths based on requested widths // [Part 5] Apply final widths based on requested widths
const ImRect work_rect = table->WorkRect; 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 = width_avail - width_spacings - sum_width_requests;
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
@ -828,9 +837,9 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
// Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest) // Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest)
if ((column->Flags & ImGuiTableColumnFlags_WidthStretch) && !mixed_same_widths) if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
{ {
float weight_ratio = column->StretchWeight / sum_weights_stretched; float weight_ratio = column->StretchWeight / stretch_sum_weights;
column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f); column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f);
width_remaining_for_stretched_columns -= column->WidthRequest; width_remaining_for_stretched_columns -= column->WidthRequest;
} }
@ -848,7 +857,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 6] Redistribute stretch 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). // Using right-to-left distribution (more likely to match resizing cursor).
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; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
{ {
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
continue; continue;
@ -1000,7 +1009,7 @@ 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;
} }
if (count_resizable == 0 && (table->Flags & ImGuiTableFlags_Resizable)) if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable))
table->Flags &= ~ImGuiTableFlags_Resizable; table->Flags &= ~ImGuiTableFlags_Resizable;
// [Part 9] Lock actual OuterRect/WorkRect right-most position. // [Part 9] Lock actual OuterRect/WorkRect right-most position.
@ -1302,8 +1311,8 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
// When passing a width automatically enforce WidthFixed policy // When passing a width automatically enforce WidthFixed policy
// (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable) // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0) if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
if ((table->Flags & ImGuiTableFlags_SizingPolicyFixed) && (init_width_or_weight > 0.0f)) if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
flags |= ImGuiTableColumnFlags_WidthFixed; flags |= ImGuiTableColumnFlags_WidthFixed;
TableSetupColumnFlags(table, column, flags); TableSetupColumnFlags(table, column, flags);
@ -1314,9 +1323,11 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
if (flags & ImGuiTableColumnFlags_WidthStretch) if (flags & ImGuiTableColumnFlags_WidthStretch)
IM_ASSERT(init_width_or_weight != 0.0f && "Need to provide a valid weight!"); IM_ASSERT(init_width_or_weight != 0.0f && "Need to provide a valid weight!");
column->InitStretchWeightOrWidth = init_width_or_weight; column->InitStretchWeightOrWidth = init_width_or_weight;
if (table->IsInitializing && column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) if (table->IsInitializing)
{ {
// Init width or weight // Init width or weight
if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
{
if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
column->WidthRequest = init_width_or_weight; column->WidthRequest = init_width_or_weight;
if (flags & ImGuiTableColumnFlags_WidthStretch) if (flags & ImGuiTableColumnFlags_WidthStretch)
@ -1326,8 +1337,7 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, flo
if (init_width_or_weight > 0.0f) if (init_width_or_weight > 0.0f)
column->AutoFitQueue = 0x00; column->AutoFitQueue = 0x00;
} }
if (table->IsInitializing)
{
// Init default visibility/sort state // Init default visibility/sort state
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0) if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
column->IsEnabled = column->IsEnabledNextFrame = false; column->IsEnabled = column->IsEnabledNextFrame = false;
@ -1884,7 +1894,7 @@ float ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column
// Non-resizable fixed columns preserve their requested width // Non-resizable fixed columns preserve 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 = column->InitStretchWeightOrWidth;
return ImMax(width_auto, table->MinColumnWidth); return ImMax(width_auto, table->MinColumnWidth);
} }
@ -1980,10 +1990,7 @@ void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n)
if (!column->IsEnabled) if (!column->IsEnabled)
return; return;
column->CannotSkipItemsQueue = (1 << 0); column->CannotSkipItemsQueue = (1 << 0);
if (column->Flags & ImGuiTableColumnFlags_WidthStretch) table->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n;
table->AutoFitSingleStretchColumn = (ImGuiTableColumnIdx)column_n;
else
column->AutoFitQueue = (1 << 1);
} }
void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table) void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table)
@ -1991,7 +1998,7 @@ void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table)
for (int column_n = 0; column_n < table->ColumnsCount; column_n++) for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{ {
ImGuiTableColumn* column = &table->Columns[column_n]; ImGuiTableColumn* column = &table->Columns[column_n];
if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Can reset weight of hidden stretch column if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column
continue; continue;
column->CannotSkipItemsQueue = (1 << 0); column->CannotSkipItemsQueue = (1 << 0);
column->AutoFitQueue = (1 << 1); column->AutoFitQueue = (1 << 1);
@ -2343,9 +2350,10 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0; const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;
const bool is_frozen_separator = (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1); const bool is_frozen_separator = (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1);
if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)// && is_hovered) if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)
continue; continue;
if (column->NextEnabledColumn == -1 && !is_resizable && (table->Flags & ImGuiTableFlags_SameWidths) == 0) if (column->NextEnabledColumn == -1 && !is_resizable)
if ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || table->IsOuterRectAutoFitX)
continue; continue;
if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size.. if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size..
continue; continue;
@ -2634,6 +2642,10 @@ void ImGui::TableHeadersRow()
ImGuiTable* table = g.CurrentTable; ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!"); IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
// Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)
if (!table->IsLayoutLocked)
TableUpdateLayout(table);
// Open row // Open row
const float row_y1 = GetCursorScreenPos().y; const float row_y1 = GetCursorScreenPos().y;
const float row_height = TableGetHeaderRowHeight(); const float row_height = TableGetHeaderRowHeight();
@ -2856,12 +2868,10 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
} }
const char* size_all_desc; const char* size_all_desc;
if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount) if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame)
size_all_desc = "Size all columns to fit###SizeAll"; // All fixed size_all_desc = "Size all columns to fit###SizeAll"; // All fixed
else if (table->ColumnsEnabledFixedCount == 0)
size_all_desc = "Size all columns to default###SizeAll"; // All stretch
else else
size_all_desc = "Size all columns to fit/default###SizeAll";// Mixed size_all_desc = "Size all columns to default###SizeAll"; // All stretch or mixed
if (MenuItem(size_all_desc, NULL)) if (MenuItem(size_all_desc, NULL))
TableSetColumnWidthAutoAll(table); TableSetColumnWidthAutoAll(table);
want_separator = true; want_separator = true;
@ -3310,6 +3320,16 @@ void ImGui::TableGcCompactSettings()
#ifndef IMGUI_DISABLE_METRICS_WINDOW #ifndef IMGUI_DISABLE_METRICS_WINDOW
static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy)
{
sizing_policy &= ImGuiTableFlags_SizingMask_;
if (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return "FixedFit"; }
if (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return "FixedSame"; }
if (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return "StretchProp"; }
if (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return "StretchSame"; }
return "N/A";
}
void ImGui::DebugNodeTable(ImGuiTable* table) void ImGui::DebugNodeTable(ImGuiTable* table)
{ {
char buf[512]; char buf[512];
@ -3322,10 +3342,12 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
if (!is_active) { PopStyleColor(); } if (!is_active) { PopStyleColor(); }
if (IsItemHovered()) if (IsItemHovered())
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 (IsItemVisible() && table->HoveredColumnBody != -1)
GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
if (!open) if (!open)
return; return;
bool clear_settings = SmallButton("Clear settings"); 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) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));
BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : ""); BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, 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);
BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder); BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder);