Tables: simplified and tidying up TableSetColumnWidth(), fixes resizing a fixed column surrounded by stretch column (manually or via auto-fit menu). TableHeader() showing highlighted when held.

This commit is contained in:
ocornut 2020-12-22 16:55:40 +01:00
parent 972ca8166f
commit d497f112e7
2 changed files with 28 additions and 49 deletions

View File

@ -1050,7 +1050,7 @@ enum ImGuiTabItemFlags_
// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable().
// - Mixing up columns with different sizing policy is possible BUT can be tricky and has some side-effects and restrictions.
// (their visible order and the scrolling state have subtle but necessary effects on how they can be manually resized).
// The typical use of mixing sizing policies is to have ScrollX disabled, one or two Stretch Column and many Fixed Columns.
// The typical use of mixing sizing policies is to have ScrollX disabled, first Fixed columns and then one or two TRAILING Stretch columns.
enum ImGuiTableFlags_
{
// Features

View File

@ -1876,6 +1876,7 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
return;
//IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width);
ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;
// In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns.
@ -1897,66 +1898,44 @@ void ImGui::TableSetColumnWidth(int column_n, float width)
// - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1)
// - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1)
// - W1 W2 F3 resize from W1| or W2| --> ok
// - W1 F2 W3 resize from W1| or F2| --> FIXME
// - W1 F2 W3 resize from W1| or F2| --> ok
// - F1 W2 F3 resize from W2| --> ok
// - F1 W3 F2 resize from W3| --> ok
// - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. (forwarded by Resize Rule 2)
// - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move.
// - W1 F2 F3 resize from F2| --> ok
// All resizes from a Wx columns are locking other columns.
// Possible improvements:
// - W1 W2 W3 resize W1| --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns.
// - W1 F2 W3 resize W1| or F2| --> symmetrical resize is weird and glitchy. Seems possible to fix.
// - W3 F1 F2 resize W3| --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix.
// Rules:
// - [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout().
// - [Resize Rule 2] Resizing from right-side of a Stretch column before a fixed column forward sizing to left-side of fixed column.
// - [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure that our left border won't move.
table->IsSettingsDirty = true;
// [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout().
// If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize.
// This is the preferred resize path
if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed)
{
// [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure
// that our left border won't move, which we can do by making sure column_a/column_b resizes cancels each others.
if (column_1 && (column_1->Flags & ImGuiTableColumnFlags_WidthFixed))
if (table->LeftMostStretchedColumn != -1 && table->Columns[table->LeftMostStretchedColumn].DisplayOrder < column_0->DisplayOrder)
{
// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
column_1->WidthRequest = column_1_width;
}
// Apply
//IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width);
column_0->WidthRequest = column_0_width;
}
else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch)
{
// We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column)
if (column_1 == NULL)
column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL;
if (column_1 == NULL)
return;
if (column_1->Flags & ImGuiTableColumnFlags_WidthFixed)
if (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder)
{
// [Resize Rule 2]
float off = (column_0->WidthGiven - column_0_width);
float column_1_width = column_1->WidthGiven + off;
column_1->WidthRequest = ImMax(min_width, column_1_width);
}
else
{
// At this point column_1 is the next OR previous column and we know it is a stretch column.
// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
column_1->WidthRequest = column_1_width;
column_0->WidthRequest = column_0_width;
TableUpdateColumnsWeightFromWidth(table);
table->IsSettingsDirty = true;
return;
}
}
// We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column)
if (column_1 == NULL)
column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL;
if (column_1 == NULL)
return;
// Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column.
// (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
column_0->WidthRequest = column_0_width;
column_1->WidthRequest = column_1_width;
if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch)
TableUpdateColumnsWeightFromWidth(table);
table->IsSettingsDirty = true;
}
// Disable clipping then auto-fit, will take 2 frames
@ -2715,7 +2694,7 @@ void ImGui::TableHeader(const char* label)
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap);
if (g.ActiveId != id)
SetItemAllowOverlap();
if (hovered || selected)
if (held || hovered || selected)
{
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);