Skip to content

Commit

Permalink
Tables: added Angled headers support. Added ImGuiTableColumnFlags_Ang…
Browse files Browse the repository at this point in the history
…ledHeader, ImGui::TableHeadersAngledRow(), style.TableAngledHeadersAngle. (#2957)
  • Loading branch information
ocornut committed Oct 12, 2023
1 parent 9f851eb commit 32228d8
Show file tree
Hide file tree
Showing 7 changed files with 250 additions and 28 deletions.
25 changes: 14 additions & 11 deletions docs/CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -94,17 +94,20 @@ Other changes:
- Drag and Drop: Fixed submitting a tooltip from drop target location when using AcceptDragDropPayload()
with ImGuiDragDropFlags_AcceptNoPreviewTooltip and submitting a tooltip manually.
- TreeNode: Added ImGuiTreeNodeFlags_SpanAllColumns for use in tables. (#3151, #3565, #2451, #2438)
- Tables: Added ImGuiTableFlags_HighlightHoveredColumn flag, currently highlighting column header.
- Tables: Fixed an edge-case when no columns are visible + table scrollbar is visible + user
code is always testing return value of TableSetColumnIndex() to coarse clip. With an active
clipper it would have asserted. Without a clipper, the scrollbar range would be wrong.
- Tables: Request user to submit contents when outer host-window is requesting auto-resize,
so a scrolling table can contribute to initial window size. (#6510)
- Tables: Fixed subtle drawing overlap between borders in some situations.
- Tables: Fixed bottom-most and right-most outer border offset by one. (#6765, #3752) [@v-ein]
- Tables: Fixed top-most outer border being drawn with both TableBorderLight and TableBorderStrong
in some situations, causing the earlier to be visible underneath when alpha is not 1.0f.
- Tables: fixed right-clicking right-most section (past right-most column) from highlighting a column.
- Tables:
- Added angled headers support. You need to set ImGuiTableColumnFlags_AngledHeader on selected
columns and call TableAngledHeadersRow(). Added style.TableAngledHeadersAngle style option.
- Added ImGuiTableFlags_HighlightHoveredColumn flag, currently highlighting column header.
- Fixed an edge-case when no columns are visible + table scrollbar is visible + user
code is always testing return value of TableSetColumnIndex() to coarse clip. With an active
clipper it would have asserted. Without a clipper, the scrollbar range would be wrong.
- Request user to submit contents when outer host-window is requesting auto-resize,
so a scrolling table can contribute to initial window size. (#6510)
- Fixed subtle drawing overlap between borders in some situations.
- Fixed bottom-most and right-most outer border offset by one. (#6765, #3752) [@v-ein]
- Fixed top-most outer border being drawn with both TableBorderLight and TableBorderStrong
in some situations, causing the earlier to be visible underneath when alpha is not 1.0f.
- fixed right-clicking right-most section (past right-most column) from highlighting a column.
- TabBar: Fixed position of unsaved document marker (ImGuiTabItemFlags_UnsavedDocument) which was
accidentally offset in 1.89.9. (#6862) [@alektron]
- Fonts: 'float size_pixels' passed to AddFontXXX() functions is now rounded to lowest integer.
Expand Down
1 change: 1 addition & 0 deletions imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1188,6 +1188,7 @@ ImGuiStyle::ImGuiStyle()
TabBorderSize = 0.0f; // Thickness of border around tabs.
TabMinWidthForCloseButton = 0.0f; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
TabBarBorderSize = 1.0f; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
TableAngledHeadersAngle = 35.0f * (IM_PI / 180.0f); // Angle of angled headers (supported values range from -50 degrees to +50 degrees).
ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
Expand Down
7 changes: 5 additions & 2 deletions imgui.h
Original file line number Diff line number Diff line change
Expand Up @@ -771,8 +771,9 @@ namespace ImGui
// - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled.
IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0);
IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
IMGUI_API void TableHeadersRow(); // submit all headers cells based on data provided to TableSetupColumn() + submit context menu
IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used)
IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + submit context menu
IMGUI_API void TableAngledHeadersRow(); // submit a row with angled headers for every column with the ImGuiTableColumnFlags_AngledHeader flag. MUST BE FIRST ROW.

// Tables: Sorting & Miscellaneous functions
// - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. NULL when not sorting.
Expand Down Expand Up @@ -1240,12 +1241,13 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).
ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction.
ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction.
ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit label for this column. Convenient for some small columns. Name will still appear in context menu.
ImGuiTableColumnFlags_NoHeaderLabel = 1 << 12, // TableHeadersRow() will not submit horizontal label for this column. Convenient for some small columns. Name will still appear in context menu or in angled headers.
ImGuiTableColumnFlags_NoHeaderWidth = 1 << 13, // Disable header text width contribution to automatic column width.
ImGuiTableColumnFlags_PreferSortAscending = 1 << 14, // Make the initial sort direction Ascending when first sorting on this column (default).
ImGuiTableColumnFlags_PreferSortDescending = 1 << 15, // Make the initial sort direction Descending when first sorting on this column.
ImGuiTableColumnFlags_IndentEnable = 1 << 16, // Use current Indent value when entering cell (default for column 0).
ImGuiTableColumnFlags_IndentDisable = 1 << 17, // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.
ImGuiTableColumnFlags_AngledHeader = 1 << 18, // TableHeadersRow() will submit an angled header row for this column. Note this will add an extra row.

// Output status flags, read-only via TableGetColumnFlags()
ImGuiTableColumnFlags_IsEnabled = 1 << 24, // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags.
Expand Down Expand Up @@ -1926,6 +1928,7 @@ struct ImGuiStyle
float TabBorderSize; // Thickness of border around tabs.
float TabMinWidthForCloseButton; // Minimum width for close button to appear on an unselected tab when hovered. Set to 0.0f to always show when hovering, set to FLT_MAX to never show close button unless selected.
float TabBarBorderSize; // Thickness of tab-bar separator, which takes on the tab active color to denote focus.
float TableAngledHeadersAngle; // Angle of angled headers (supported values range from -50.0f degrees to +50.0f degrees).
ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text. Defaults to (0.0f, 0.0f) (top-left aligned). It's generally important to keep this left-aligned if you want to lay multiple items on a same line.
Expand Down
79 changes: 72 additions & 7 deletions imgui_demo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3949,6 +3949,7 @@ static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
ImGui::CheckboxFlags("_PreferSortDescending", p_flags, ImGuiTableColumnFlags_PreferSortDescending);
ImGui::CheckboxFlags("_IndentEnable", p_flags, ImGuiTableColumnFlags_IndentEnable); ImGui::SameLine(); HelpMarker("Default for column 0");
ImGui::CheckboxFlags("_IndentDisable", p_flags, ImGuiTableColumnFlags_IndentDisable); ImGui::SameLine(); HelpMarker("Default for column >0");
ImGui::CheckboxFlags("_AngledHeader", p_flags, ImGuiTableColumnFlags_AngledHeader);
}

static void ShowTableColumnsStatusFlags(ImGuiTableColumnFlags flags)
Expand Down Expand Up @@ -4695,8 +4696,14 @@ static void ShowDemoWindowTables()
ImVec2 outer_size = ImVec2(0.0f, TEXT_BASE_HEIGHT * 9);
if (ImGui::BeginTable("table_columns_flags", column_count, flags, outer_size))
{
bool has_angled_header = false;
for (int column = 0; column < column_count; column++)
{
has_angled_header |= (column_flags[column] & ImGuiTableColumnFlags_AngledHeader) != 0;
ImGui::TableSetupColumn(column_names[column], column_flags[column]);
}
if (has_angled_header)
ImGui::TableAngledHeadersRow();
ImGui::TableHeadersRow();
for (int column = 0; column < column_count; column++)
column_flags_out[column] = ImGui::TableGetColumnFlags(column);
Expand Down Expand Up @@ -5182,6 +5189,56 @@ static void ShowDemoWindowTables()
ImGui::TreePop();
}

// Demonstrate using ImGuiTableColumnFlags_AngledHeader flag to create angled headers
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
IMGUI_DEMO_MARKER("Tables/Angled headers");
if (ImGui::TreeNode("Angled headers"))
{
const char* column_names[] = { "Track", "cabasa", "ride", "smash", "tom-hi", "tom-mid", "tom-low", "hihat-o", "hihat-c", "snare-s", "snare-c", "clap", "rim", "kick" };
const int columns_count = IM_ARRAYSIZE(column_names);
const int rows_count = 12;

static ImGuiTableFlags table_flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_Hideable | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_HighlightHoveredColumn;
static bool bools[columns_count * rows_count] = {}; // Dummy storage selection storage
static int frozen_rows = 2;
ImGui::CheckboxFlags("_ScrollX", &table_flags, ImGuiTableFlags_ScrollX);
ImGui::CheckboxFlags("_ScrollY", &table_flags, ImGuiTableFlags_ScrollY);
ImGui::CheckboxFlags("_NoBordersInBody", &table_flags, ImGuiTableFlags_NoBordersInBody);
ImGui::CheckboxFlags("_HighlightHoveredColumn", &table_flags, ImGuiTableFlags_HighlightHoveredColumn);
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
ImGui::SliderInt("Frozen rows", &frozen_rows, 0, 2);

if (ImGui::BeginTable("table_angled_headers", columns_count, table_flags, ImVec2(0.0f, TEXT_BASE_HEIGHT * 12)))
{
ImGui::TableSetupColumn(column_names[0], ImGuiTableColumnFlags_NoHide | ImGuiTableColumnFlags_NoReorder);
for (int n = 1; n < columns_count; n++)
ImGui::TableSetupColumn(column_names[n], ImGuiTableColumnFlags_AngledHeader | ImGuiTableColumnFlags_WidthFixed);
ImGui::TableSetupScrollFreeze(0, frozen_rows);

ImGui::TableAngledHeadersRow(); // Draw angled headers for all columns with the ImGuiTableColumnFlags_AngledHeader flag.
ImGui::TableHeadersRow(); // Draw remaining headers and allow access to context-menu and other functions.
for (int row = 0; row < rows_count; row++)
{
ImGui::PushID(row);
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::AlignTextToFramePadding();
ImGui::Text("Track %d", row);
for (int column = 1; column < columns_count; column++)
if (ImGui::TableSetColumnIndex(column))
{
ImGui::PushID(column);
ImGui::Checkbox("", &bools[row * columns_count + column]);
ImGui::PopID();
}
ImGui::PopID();
}
ImGui::EndTable();
}
ImGui::TreePop();
}

// Demonstrate creating custom context menus inside columns, while playing it nice with context menus provided by TableHeadersRow()/TableHeader()
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
Expand Down Expand Up @@ -5428,6 +5485,7 @@ static void ShowDemoWindowTables()
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_SizingFixedFit;
static ImGuiTableColumnFlags columns_base_flags = ImGuiTableColumnFlags_None;

enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
static int contents_type = CT_SelectableSpanRow;
Expand Down Expand Up @@ -5525,6 +5583,8 @@ static void ShowDemoWindowTables()
{
ImGui::Checkbox("show_headers", &show_headers);
ImGui::CheckboxFlags("ImGuiTableFlags_HighlightHoveredColumn", &flags, ImGuiTableFlags_HighlightHoveredColumn);
ImGui::CheckboxFlags("ImGuiTableColumnFlags_AngledHeader", &columns_base_flags, ImGuiTableColumnFlags_AngledHeader);
ImGui::SameLine(); HelpMarker("Enable AngledHeader on all columns. Best enabled on selected narrow columns (see \"Angled headers\" section of the demo).");
ImGui::TreePop();
}

Expand Down Expand Up @@ -5590,12 +5650,12 @@ static void ShowDemoWindowTables()
// Declare columns
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
ImGui::TableSetupColumn("Description", (flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch, 0.0f, MyItemColumnID_Description);
ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
ImGui::TableSetupColumn("ID", columns_base_flags | ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, 0.0f, MyItemColumnID_ID);
ImGui::TableSetupColumn("Name", columns_base_flags | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Name);
ImGui::TableSetupColumn("Action", columns_base_flags | ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, 0.0f, MyItemColumnID_Action);
ImGui::TableSetupColumn("Quantity", columns_base_flags | ImGuiTableColumnFlags_PreferSortDescending, 0.0f, MyItemColumnID_Quantity);
ImGui::TableSetupColumn("Description", columns_base_flags | ((flags & ImGuiTableFlags_NoHostExtendX) ? 0 : ImGuiTableColumnFlags_WidthStretch), 0.0f, MyItemColumnID_Description);
ImGui::TableSetupColumn("Hidden", columns_base_flags | ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);

// Sort our data if sort specs have been changed!
Expand All @@ -5614,6 +5674,8 @@ static void ShowDemoWindowTables()
const bool sorts_specs_using_quantity = (ImGui::TableGetColumnFlags(3) & ImGuiTableColumnFlags_IsSorted) != 0;

// Show headers
if (show_headers && (columns_base_flags & ImGuiTableColumnFlags_AngledHeader) != 0)
ImGui::TableAngledHeadersRow();
if (show_headers)
ImGui::TableHeadersRow();

Expand Down Expand Up @@ -6400,7 +6462,6 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SeparatorText("Main");
ImGui::SliderFloat2("WindowPadding", (float*)&style.WindowPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("FramePadding", (float*)&style.FramePadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("ItemSpacing", (float*)&style.ItemSpacing, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("ItemInnerSpacing", (float*)&style.ItemInnerSpacing, 0.0f, 20.0f, "%.0f");
ImGui::SliderFloat2("TouchExtraPadding", (float*)&style.TouchExtraPadding, 0.0f, 10.0f, "%.0f");
Expand All @@ -6425,6 +6486,10 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("GrabRounding", &style.GrabRounding, 0.0f, 12.0f, "%.0f");
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");

ImGui::SeparatorText("Tables");
ImGui::SliderFloat2("CellPadding", (float*)&style.CellPadding, 0.0f, 20.0f, "%.0f");
ImGui::SliderAngle("TableAngledHeadersAngle", &style.TableAngledHeadersAngle, -50.0f, +50.0f);

ImGui::SeparatorText("Widgets");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
int window_menu_button_position = style.WindowMenuButtonPosition + 1;
Expand Down
8 changes: 8 additions & 0 deletions imgui_draw.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1989,6 +1989,14 @@ void ImGui::ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int ve
}
}

void ImGui::ShadeVertsTransformPos(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& pivot_in, float cos_a, float sin_a, const ImVec2& pivot_out)
{
ImDrawVert* vert_start = draw_list->VtxBuffer.Data + vert_start_idx;
ImDrawVert* vert_end = draw_list->VtxBuffer.Data + vert_end_idx;
for (ImDrawVert* vertex = vert_start; vertex < vert_end; ++vertex)
vertex->pos = ImRotate(vertex->pos- pivot_in, cos_a, sin_a) + pivot_out;
}

//-----------------------------------------------------------------------------
// [SECTION] ImFontConfig
//-----------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 32228d8

Please sign in to comment.