mirror of
https://github.com/Drezil/imgui.git
synced 2024-11-26 05:27:01 +00:00
Tables: Support for multiple Tables using same id where most settings are synced.
(some minor one-frame lack of sync when e.g. toggling visibility in context menu)
This commit is contained in:
parent
a09954bdaf
commit
e06a36ab12
@ -1891,6 +1891,8 @@ struct ImGuiTable
|
|||||||
int ColumnsActiveCount; // Number of non-hidden columns (<= ColumnsCount)
|
int ColumnsActiveCount; // Number of non-hidden columns (<= ColumnsCount)
|
||||||
int CurrentColumn;
|
int CurrentColumn;
|
||||||
int CurrentRow;
|
int CurrentRow;
|
||||||
|
ImS16 InstanceNo; // Count of BeginTable() calls with same ID in the same frame (generally 0)
|
||||||
|
ImS16 InstanceInteracted;
|
||||||
float RowPosY1;
|
float RowPosY1;
|
||||||
float RowPosY2;
|
float RowPosY2;
|
||||||
float RowTextBaseline;
|
float RowTextBaseline;
|
||||||
@ -1910,6 +1912,7 @@ struct ImGuiTable
|
|||||||
float LastFirstRowHeight; // Height of first row from last frame
|
float LastFirstRowHeight; // Height of first row from last frame
|
||||||
float ColumnsTotalWidth;
|
float ColumnsTotalWidth;
|
||||||
float InnerWidth;
|
float InnerWidth;
|
||||||
|
float ResizedColumnNextWidth;
|
||||||
ImRect OuterRect; // Note: OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
|
ImRect OuterRect; // Note: OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
|
||||||
ImRect WorkRect;
|
ImRect WorkRect;
|
||||||
ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.
|
ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.
|
||||||
@ -1925,7 +1928,8 @@ struct ImGuiTable
|
|||||||
ImS8 DeclColumnsCount; // Count calls to TableSetupColumn()
|
ImS8 DeclColumnsCount; // Count calls to TableSetupColumn()
|
||||||
ImS8 HoveredColumnBody; // [DEBUG] Unlike HoveredColumnBorder this doesn't fulfill all Hovering rules properly. Used for debugging/tools for now.
|
ImS8 HoveredColumnBody; // [DEBUG] Unlike HoveredColumnBorder this doesn't fulfill all Hovering rules properly. Used for debugging/tools for now.
|
||||||
ImS8 HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing).
|
ImS8 HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing).
|
||||||
ImS8 ResizedColumn; // Index of column being resized.
|
ImS8 ResizedColumn; // Index of column being resized. Reset by InstanceNo==0.
|
||||||
|
ImS8 HeadHeaderColumn; // Index of column header being held.
|
||||||
ImS8 LastResizedColumn;
|
ImS8 LastResizedColumn;
|
||||||
ImS8 ReorderColumn; // Index of column being reordered. (not cleared)
|
ImS8 ReorderColumn; // Index of column being reordered. (not cleared)
|
||||||
ImS8 ReorderColumnDir; // -1 or +1
|
ImS8 ReorderColumnDir; // -1 or +1
|
||||||
@ -1957,6 +1961,7 @@ struct ImGuiTable
|
|||||||
{
|
{
|
||||||
memset(this, 0, sizeof(*this));
|
memset(this, 0, sizeof(*this));
|
||||||
SettingsOffset = -1;
|
SettingsOffset = -1;
|
||||||
|
InstanceInteracted = -1;
|
||||||
LastFrameActive = -1;
|
LastFrameActive = -1;
|
||||||
LastResizedColumn = -1;
|
LastResizedColumn = -1;
|
||||||
ContextPopupColumn = -1;
|
ContextPopupColumn = -1;
|
||||||
|
@ -158,9 +158,8 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
|
ImVec2 actual_outer_size = CalcItemSize(outer_size, ImMax(avail_size.x, 1.0f), use_child_window ? ImMax(avail_size.y, 1.0f) : 0.0f);
|
||||||
ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
|
ImRect outer_rect(outer_window->DC.CursorPos, outer_window->DC.CursorPos + actual_outer_size);
|
||||||
|
|
||||||
// If an outer size is specified ahead we will be able to early out when not visible,
|
// If an outer size is specified ahead we will be able to early out when not visible. Exact clipping rules may evolve.
|
||||||
// The exact rules here can evolve.
|
if (use_child_window && IsClippedEx(outer_rect, 0, false))
|
||||||
if (use_child_window && IsClippedEx(outer_rect, id, false))
|
|
||||||
{
|
{
|
||||||
ItemSize(outer_rect);
|
ItemSize(outer_rect);
|
||||||
return false;
|
return false;
|
||||||
@ -173,9 +172,16 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
// Acquire storage for the table
|
// Acquire storage for the table
|
||||||
ImGuiTable* table = g.Tables.GetOrAddByKey(id);
|
ImGuiTable* table = g.Tables.GetOrAddByKey(id);
|
||||||
const ImGuiTableFlags table_last_flags = table->Flags;
|
const ImGuiTableFlags table_last_flags = table->Flags;
|
||||||
|
const int instance_no = (table->LastFrameActive != g.FrameCount) ? 0 : table->InstanceNo + 1;
|
||||||
|
const ImGuiID instance_id = id + instance_no;
|
||||||
|
if (instance_no > 0)
|
||||||
|
IM_ASSERT(table->ColumnsCount == columns_count && "BeginTable(): Cannot change columns count mid-frame while preserving same ID");
|
||||||
|
|
||||||
|
// Initialize
|
||||||
table->ID = id;
|
table->ID = id;
|
||||||
table->Flags = flags;
|
table->Flags = flags;
|
||||||
table->IsFirstFrame = (table->LastFrameActive == -1);
|
table->IsFirstFrame = (table->LastFrameActive == -1);
|
||||||
|
table->InstanceNo = (ImS16)instance_no;
|
||||||
table->LastFrameActive = g.FrameCount;
|
table->LastFrameActive = g.FrameCount;
|
||||||
table->OuterWindow = table->InnerWindow = outer_window;
|
table->OuterWindow = table->InnerWindow = outer_window;
|
||||||
table->ColumnsCount = columns_count;
|
table->ColumnsCount = columns_count;
|
||||||
@ -203,7 +209,7 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
|
|
||||||
// Create scrolling region (without border = zero window padding)
|
// Create scrolling region (without border = zero window padding)
|
||||||
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
|
||||||
BeginChildEx(str_id, id, table->OuterRect.GetSize(), false, child_flags);
|
BeginChildEx(str_id, instance_id, table->OuterRect.GetSize(), false, child_flags);
|
||||||
table->InnerWindow = g.CurrentWindow;
|
table->InnerWindow = g.CurrentWindow;
|
||||||
table->WorkRect = table->InnerWindow->WorkRect;
|
table->WorkRect = table->InnerWindow->WorkRect;
|
||||||
table->OuterRect = table->InnerWindow->Rect();
|
table->OuterRect = table->InnerWindow->Rect();
|
||||||
@ -211,7 +217,7 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// WorkRect.Max will grow as we append contents.
|
// WorkRect.Max will grow as we append contents.
|
||||||
PushID(id);
|
PushID(instance_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool has_cell_padding_x = (flags & (ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV)) != 0;
|
const bool has_cell_padding_x = (flags & (ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV)) != 0;
|
||||||
@ -244,7 +250,6 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
table->HoveredColumnBody = -1;
|
table->HoveredColumnBody = -1;
|
||||||
table->HoveredColumnBorder = -1;
|
table->HoveredColumnBorder = -1;
|
||||||
table->RightMostActiveColumn = -1;
|
table->RightMostActiveColumn = -1;
|
||||||
table->LeftMostStretchedColumnDisplayOrder = -1;
|
|
||||||
table->IsFirstFrame = false;
|
table->IsFirstFrame = false;
|
||||||
|
|
||||||
// FIXME-TABLE FIXME-STYLE: Using opaque colors facilitate overlapping elements of the grid
|
// FIXME-TABLE FIXME-STYLE: Using opaque colors facilitate overlapping elements of the grid
|
||||||
@ -291,8 +296,25 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
if (table->IsFirstFrame || table->IsSettingsRequestLoad)
|
if (table->IsFirstFrame || table->IsSettingsRequestLoad)
|
||||||
TableLoadSettings(table);
|
TableLoadSettings(table);
|
||||||
|
|
||||||
|
// Handle resizing request
|
||||||
|
// (We process this at the first beginning of the frame)
|
||||||
|
// FIXME-TABLE: Preserve contents width _while resizing down_ until releasing.
|
||||||
|
// FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling.
|
||||||
|
if (table->InstanceNo == 0)
|
||||||
|
{
|
||||||
|
if (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX)
|
||||||
|
TableSetColumnWidth(table, &table->Columns[table->ResizedColumn], table->ResizedColumnNextWidth);
|
||||||
|
table->ResizedColumnNextWidth = FLT_MAX;
|
||||||
|
table->ResizedColumn = -1;
|
||||||
|
}
|
||||||
|
|
||||||
// Handle reordering request
|
// Handle reordering request
|
||||||
// Note: we don't clear ReorderColumn after handling the request.
|
// Note: we don't clear ReorderColumn after handling the request.
|
||||||
|
if (table->InstanceNo == 0)
|
||||||
|
{
|
||||||
|
if (table->HeadHeaderColumn == -1 && table->ReorderColumn != -1)
|
||||||
|
table->ReorderColumn = -1;
|
||||||
|
table->HeadHeaderColumn = -1;
|
||||||
if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0)
|
if (table->ReorderColumn != -1 && table->ReorderColumnDir != 0)
|
||||||
{
|
{
|
||||||
IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1);
|
IM_ASSERT(table->ReorderColumnDir == -1 || table->ReorderColumnDir == +1);
|
||||||
@ -304,6 +326,7 @@ bool ImGui::BeginTable(const char* str_id, int columns_count, ImGuiTableFlags
|
|||||||
table->ReorderColumnDir = 0;
|
table->ReorderColumnDir = 0;
|
||||||
table->IsSettingsDirty = true;
|
table->IsSettingsDirty = true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle display order reset request
|
// Handle display order reset request
|
||||||
if (table->IsResetDisplayOrderRequest)
|
if (table->IsResetDisplayOrderRequest)
|
||||||
@ -713,7 +736,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
|
|||||||
table->IsUsingHeaders = false;
|
table->IsUsingHeaders = false;
|
||||||
|
|
||||||
// Context menu
|
// Context menu
|
||||||
if (table->IsContextPopupOpen)
|
if (table->IsContextPopupOpen && table->InstanceNo == table->InstanceInteracted)
|
||||||
{
|
{
|
||||||
if (BeginPopup("##TableContextMenu"))
|
if (BeginPopup("##TableContextMenu"))
|
||||||
{
|
{
|
||||||
@ -763,7 +786,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
|||||||
if (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_))
|
if (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
ImGuiID column_id = table->ID + (ImGuiID)column_n;
|
ImGuiID column_id = table->ID + (table->InstanceNo * table->ColumnsCount) + column_n;
|
||||||
ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, hit_y2);
|
ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, hit_y2);
|
||||||
//GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100));
|
//GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100));
|
||||||
KeepAliveID(column_id);
|
KeepAliveID(column_id);
|
||||||
@ -771,7 +794,10 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
|
|||||||
bool hovered = false, held = false;
|
bool hovered = false, held = false;
|
||||||
ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
|
ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap);
|
||||||
if (held)
|
if (held)
|
||||||
|
{
|
||||||
table->ResizedColumn = (ImS8)column_n;
|
table->ResizedColumn = (ImS8)column_n;
|
||||||
|
table->InstanceInteracted = table->InstanceNo;
|
||||||
|
}
|
||||||
if ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held)
|
if ((hovered && g.HoveredIdTimer > TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER) || held)
|
||||||
{
|
{
|
||||||
table->HoveredColumnBorder = (ImS8)column_n;
|
table->HoveredColumnBorder = (ImS8)column_n;
|
||||||
@ -861,14 +887,12 @@ void ImGui::EndTable()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Apply resizing/dragging at the end of the frame
|
// Apply resizing/dragging at the end of the frame
|
||||||
// FIXME-TABLE: Preserve contents width _while resizing down_ until releasing.
|
|
||||||
// FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling.
|
|
||||||
if (table->ResizedColumn != -1)
|
if (table->ResizedColumn != -1)
|
||||||
{
|
{
|
||||||
ImGuiTableColumn* column = &table->Columns[table->ResizedColumn];
|
ImGuiTableColumn* column = &table->Columns[table->ResizedColumn];
|
||||||
const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS);
|
const float new_x2 = (g.IO.MousePos.x - g.ActiveIdClickOffset.x + TABLE_RESIZE_SEPARATOR_HALF_THICKNESS);
|
||||||
const float new_width = ImFloor(new_x2 - column->MinX);
|
const float new_width = ImFloor(new_x2 - column->MinX);
|
||||||
TableSetColumnWidth(table, column, new_width);
|
table->ResizedColumnNextWidth = new_width;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Layout in outer window
|
// Layout in outer window
|
||||||
@ -940,7 +964,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
|
|||||||
const int column_n = table->DisplayOrder[order_n];
|
const int column_n = table->DisplayOrder[order_n];
|
||||||
ImGuiTableColumn* column = &table->Columns[column_n];
|
ImGuiTableColumn* column = &table->Columns[column_n];
|
||||||
const bool is_hovered = (table->HoveredColumnBorder == column_n);
|
const bool is_hovered = (table->HoveredColumnBorder == column_n);
|
||||||
const bool is_resized = (table->ResizedColumn == column_n);
|
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceNo);
|
||||||
const bool draw_right_border = (column->MaxX <= table->InnerClipRect.Max.x) || (is_resized || is_hovered);
|
const bool draw_right_border = (column->MaxX <= table->InnerClipRect.Max.x) || (is_resized || is_hovered);
|
||||||
if (draw_right_border && 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 (draw_right_border && column->MaxX > column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size..
|
||||||
{
|
{
|
||||||
@ -1724,7 +1748,7 @@ void ImGui::TableAutoHeaders()
|
|||||||
// [DEBUG]
|
// [DEBUG]
|
||||||
//if (g.IO.KeyCtrl) { static char buf[32]; name = buf; ImGuiTableColumn* c = &table->Columns[column_n]; if (c->Flags & ImGuiTableColumnFlags_WidthStretch) ImFormatString(buf, 32, "%.3f>%.1f", c->ResizeWeight, c->WidthGiven); else ImFormatString(buf, 32, "%.1f", c->WidthGiven); }
|
//if (g.IO.KeyCtrl) { static char buf[32]; name = buf; ImGuiTableColumn* c = &table->Columns[column_n]; if (c->Flags & ImGuiTableColumnFlags_WidthStretch) ImFormatString(buf, 32, "%.3f>%.1f", c->ResizeWeight, c->WidthGiven); else ImFormatString(buf, 32, "%.1f", c->WidthGiven); }
|
||||||
|
|
||||||
PushID(column_n); // Allow unnamed labels (generally accidental, but let's behave nicely with them)
|
PushID(table->InstanceNo * table->ColumnsCount + column_n); // Allow unnamed labels (generally accidental, but let's behave nicely with them)
|
||||||
TableHeader(name);
|
TableHeader(name);
|
||||||
PopID();
|
PopID();
|
||||||
|
|
||||||
@ -1767,6 +1791,7 @@ void ImGui::TableAutoHeaders()
|
|||||||
{
|
{
|
||||||
table->IsContextPopupOpen = true;
|
table->IsContextPopupOpen = true;
|
||||||
table->ContextPopupColumn = (ImS8)open_context_popup;
|
table->ContextPopupColumn = (ImS8)open_context_popup;
|
||||||
|
table->InstanceInteracted = table->InstanceNo;
|
||||||
OpenPopup("##TableContextMenu");
|
OpenPopup("##TableContextMenu");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1807,9 +1832,11 @@ void ImGui::TableHeader(const char* label)
|
|||||||
//window->DC.CursorPos.x = column->MinX + table->CellPadding.x;
|
//window->DC.CursorPos.x = column->MinX + table->CellPadding.x;
|
||||||
|
|
||||||
// Keep header highlighted when context menu is open. (FIXME-TABLE: however we cannot assume the ID of said popup if it has been created by the user...)
|
// Keep header highlighted when context menu is open. (FIXME-TABLE: however we cannot assume the ID of said popup if it has been created by the user...)
|
||||||
const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n);
|
const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceNo);
|
||||||
const bool pressed = Selectable("", selected, ImGuiSelectableFlags_DrawHoveredWhenHeld, ImVec2(0.0f, row_height));
|
const bool pressed = Selectable("", selected, ImGuiSelectableFlags_DrawHoveredWhenHeld, ImVec2(0.0f, row_height));
|
||||||
const bool held = IsItemActive();
|
const bool held = IsItemActive();
|
||||||
|
if (held)
|
||||||
|
table->HeadHeaderColumn = (ImS8)column_n;
|
||||||
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
|
||||||
|
|
||||||
// Drag and drop: re-order columns. Frozen columns are not reorderable.
|
// Drag and drop: re-order columns. Frozen columns are not reorderable.
|
||||||
@ -1818,6 +1845,7 @@ void ImGui::TableHeader(const char* label)
|
|||||||
{
|
{
|
||||||
// While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x
|
// While moving a column it will jump on the other side of the mouse, so we also test for MouseDelta.x
|
||||||
table->ReorderColumn = (ImS8)column_n;
|
table->ReorderColumn = (ImS8)column_n;
|
||||||
|
table->InstanceInteracted = table->InstanceNo;
|
||||||
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x)
|
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < cell_r.Min.x)
|
||||||
if (column->PrevActiveColumn != -1 && (column->IndexWithinActiveSet < table->FreezeColumnsRequest) == (table->Columns[column->PrevActiveColumn].IndexWithinActiveSet < table->FreezeColumnsRequest))
|
if (column->PrevActiveColumn != -1 && (column->IndexWithinActiveSet < table->FreezeColumnsRequest) == (table->Columns[column->PrevActiveColumn].IndexWithinActiveSet < table->FreezeColumnsRequest))
|
||||||
table->ReorderColumnDir = -1;
|
table->ReorderColumnDir = -1;
|
||||||
@ -1863,8 +1891,6 @@ void ImGui::TableHeader(const char* label)
|
|||||||
if (pressed && table->ReorderColumn != column_n)
|
if (pressed && table->ReorderColumn != column_n)
|
||||||
TableSortSpecsClickColumn(table, column, g.IO.KeyShift);
|
TableSortSpecsClickColumn(table, column, g.IO.KeyShift);
|
||||||
}
|
}
|
||||||
if (!held && table->ReorderColumn == column_n)
|
|
||||||
table->ReorderColumn = -1;
|
|
||||||
|
|
||||||
// Render clipped label
|
// Render clipped label
|
||||||
// Clipping here ensure that in the majority of situations, all our header cells will be merged into a single draw call.
|
// Clipping here ensure that in the majority of situations, all our header cells will be merged into a single draw call.
|
||||||
|
Loading…
Reference in New Issue
Block a user