mirror of
				https://github.com/Drezil/imgui.git
				synced 2025-10-30 12:41:06 +01: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:
		| @@ -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. | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user