mirror of
				https://github.com/ocornut/imgui.git
				synced 2025-10-26 12:27:30 +00:00 
			
		
		
		
	Tables: decent support for auto-resize of stretch columns (trickier than it sounds)
Four cases: 1. visible columns are all stretch, resize all : "size all to default" reset to default weight 2. visible columns are all stretch, resize one: "size one to fit" set weight, reapply weight (todo: improve weight redistribution in case of >1 siblings) 3. visible columns are mixed, resize all: "size all to fit/default" reset stretchs to default weight, set fixed to auto width 4. visible columns are mixed, resize one: "size one to fit", redistribute weight the same way as a manual resize + TableSetupColumn() more consistently clear AutoFitQueue. + zero-clear RowCellData buffer.
This commit is contained in:
		| @@ -3514,7 +3514,7 @@ static void ShowDemoWindowTables() | ||||
|     { | ||||
|         // 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. | ||||
|         static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; | ||||
|         static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; | ||||
|         PushStyleCompact(); | ||||
|         ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable); | ||||
|         ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV); | ||||
| @@ -3549,7 +3549,7 @@ static void ShowDemoWindowTables() | ||||
|             "Using _Resizable + _SizingPolicyFixedX flags.\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."); | ||||
|         static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingPolicyFixedX | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV; | ||||
|         static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingPolicyFixedX | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody; | ||||
|         //ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); // FIXME-TABLE: Explain or fix the effect of enable Scroll on outer_size | ||||
|         if (ImGui::BeginTable("##table1", 3, flags)) | ||||
|         { | ||||
|   | ||||
| @@ -519,6 +519,7 @@ struct ImSpan | ||||
|     inline void         set(T* data, int size)      { Data = data; DataEnd = data + size; } | ||||
|     inline void         set(T* data, T* data_end)   { Data = data; DataEnd = data_end; } | ||||
|     inline int          size() const                { return (int)(ptrdiff_t)(DataEnd - Data); } | ||||
|     inline int          size_in_bytes() const       { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } | ||||
|     inline T&           operator[](int i)           { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } | ||||
|     inline const T&     operator[](int i) const     { const T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } | ||||
|  | ||||
| @@ -1941,7 +1942,6 @@ struct ImGuiTableColumn | ||||
|         PrevVisibleColumn = NextVisibleColumn = -1; | ||||
|         SortOrder = -1; | ||||
|         SortDirection = ImGuiSortDirection_None; | ||||
|         AutoFitQueue = CannotSkipItemsQueue = (1 << 3) - 1; // Skip for three frames | ||||
|         DrawChannelCurrent = DrawChannelFrozen = DrawChannelUnfrozen = (ImU8)-1; | ||||
|     } | ||||
| }; | ||||
| @@ -1969,7 +1969,6 @@ struct ImGuiTable | ||||
|     int                         SettingsOffset;             // Offset in g.SettingsTables | ||||
|     int                         LastFrameActive; | ||||
|     int                         ColumnsCount;               // Number of columns declared in BeginTable() | ||||
|     int                         ColumnsVisibleCount;        // Number of non-hidden columns (<= ColumnsCount) | ||||
|     int                         CurrentRow; | ||||
|     int                         CurrentColumn; | ||||
|     ImS16                       InstanceCurrent;            // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. | ||||
| @@ -2018,9 +2017,12 @@ struct ImGuiTable | ||||
|     ImVector<ImGuiTableSortSpecsColumn> SortSpecsData;      // FIXME-OPT: Fixed-size array / small-vector pattern, optimize for single sort spec | ||||
|     ImGuiTableSortSpecs         SortSpecs;                  // Public facing sorts specs, this is what we return in TableGetSortSpecs() | ||||
|     ImS8                        SortSpecsCount; | ||||
|     ImS8                        ColumnsVisibleCount;        // Number of non-hidden columns (<= ColumnsCount) | ||||
|     ImS8                        ColumnsVisibleFixedCount;   // Number of non-hidden columns (<= ColumnsCount) | ||||
|     ImS8                        DeclColumnsCount;           // Count calls to TableSetupColumn() | ||||
|     ImS8                        HoveredColumnBody;          // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column! | ||||
|     ImS8                        HoveredColumnBorder;        // Index of column whose right-border is being hovered (for resizing). | ||||
|     ImS8                        AutoFitSingleStretchColumn; // Index of single stretch column requesting auto-fit. | ||||
|     ImS8                        ResizedColumn;              // Index of column being resized. Reset when InstanceCurrent==0. | ||||
|     ImS8                        LastResizedColumn;          // Index of column being resized from previous frame. | ||||
|     ImS8                        HeldHeaderColumn;           // Index of column header being held. | ||||
| @@ -2287,7 +2289,8 @@ namespace ImGui | ||||
|     IMGUI_API ImRect        TableGetCellBgRect(const ImGuiTable* table, int column_n); | ||||
|     IMGUI_API const char*   TableGetColumnName(const ImGuiTable* table, int column_n); | ||||
|     IMGUI_API ImGuiID       TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0); | ||||
|     IMGUI_API void          TableSetColumnAutofit(ImGuiTable* table, int column_n); | ||||
|     IMGUI_API void          TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); | ||||
|     IMGUI_API void          TableSetColumnWidthAutoAll(ImGuiTable* table); | ||||
|     IMGUI_API void          PushTableBackground(); | ||||
|     IMGUI_API void          PopTableBackground(); | ||||
|     IMGUI_API void          TableRemove(ImGuiTable* table); | ||||
|   | ||||
							
								
								
									
										122
									
								
								imgui_tables.cpp
									
									
									
									
									
								
							
							
						
						
									
										122
									
								
								imgui_tables.cpp
									
									
									
									
									
								
							| @@ -155,6 +155,7 @@ ImGuiTable::ImGuiTable() | ||||
|     ContextPopupColumn = -1; | ||||
|     ReorderColumn = -1; | ||||
|     ResizedColumn = -1; | ||||
|     AutoFitSingleStretchColumn = -1; | ||||
|     HoveredColumnBody = HoveredColumnBorder = -1; | ||||
| } | ||||
|  | ||||
| @@ -216,10 +217,13 @@ static void TableBeginInitMemory(ImGuiTable* table, int columns_count) | ||||
|     span_allocator.GetSpan(1, &table->DisplayOrderToIndex); | ||||
|     span_allocator.GetSpan(2, &table->RowCellData); | ||||
|  | ||||
|     memset(table->RowCellData.Data, 0, table->RowCellData.size_in_bytes()); | ||||
|     for (int n = 0; n < columns_count; n++) | ||||
|     { | ||||
|         table->Columns[n] = ImGuiTableColumn(); | ||||
|         table->Columns[n].DisplayOrder = table->DisplayOrderToIndex[n] = (ImS8)n; | ||||
|         ImGuiTableColumn* column = &table->Columns[n]; | ||||
|         *column = ImGuiTableColumn(); | ||||
|         column->DisplayOrder = table->DisplayOrderToIndex[n] = (ImS8)n; | ||||
|         column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -440,6 +444,15 @@ void ImGui::TableBeginUpdateColumns(ImGuiTable* table) | ||||
|         table->LastResizedColumn = table->ResizedColumn; | ||||
|         table->ResizedColumnNextWidth = FLT_MAX; | ||||
|         table->ResizedColumn = -1; | ||||
|  | ||||
|         // Process auto-fit for single stretch column, which is a special case | ||||
|         // 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) | ||||
|         { | ||||
|             table->Columns[table->AutoFitSingleStretchColumn].AutoFitQueue = 0x00; | ||||
|             TableSetColumnWidth(table->AutoFitSingleStretchColumn, table->Columns[table->AutoFitSingleStretchColumn].WidthAuto); | ||||
|             table->AutoFitSingleStretchColumn = -1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // Handle reordering request | ||||
| @@ -486,7 +499,7 @@ void ImGui::TableBeginUpdateColumns(ImGuiTable* table) | ||||
|         table->IsSettingsDirty = true; | ||||
|     } | ||||
|  | ||||
|     // Setup and lock Visible state and order | ||||
|     // Lock Visible state and Order | ||||
|     table->ColumnsVisibleCount = 0; | ||||
|     table->IsDefaultDisplayOrder = true; | ||||
|     ImGuiTableColumn* last_visible_column = NULL; | ||||
| @@ -522,7 +535,7 @@ void ImGui::TableBeginUpdateColumns(ImGuiTable* table) | ||||
|                 last_visible_column->NextVisibleColumn = (ImS8)column_n; | ||||
|                 column->PrevVisibleColumn = (ImS8)table->Columns.index_from_ptr(last_visible_column); | ||||
|             } | ||||
|             column->IndexWithinVisibleSet = (ImS8)table->ColumnsVisibleCount; | ||||
|             column->IndexWithinVisibleSet = table->ColumnsVisibleCount; | ||||
|             table->ColumnsVisibleCount++; | ||||
|             table->VisibleMaskByIndex |= index_mask; | ||||
|             table->VisibleMaskByDisplayOrder |= display_order_mask; | ||||
| @@ -658,6 +671,7 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table) | ||||
|  | ||||
|         if (column->Flags & (ImGuiTableColumnFlags_WidthAlwaysAutoResize | ImGuiTableColumnFlags_WidthFixed)) | ||||
|         { | ||||
|             // Process auto-fit for non-stretched columns | ||||
|             // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) | ||||
|             if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize) && !column->IsClipped)) | ||||
|                 column->WidthRequest = width_auto; | ||||
| @@ -676,15 +690,16 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table) | ||||
|         else | ||||
|         { | ||||
|             IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); | ||||
|             const int init_size = (column->StretchWeight < 0.0f); | ||||
|             if (init_size) | ||||
|                 column->StretchWeight = 1.0f; | ||||
|             const float default_weight = (column->InitStretchWeightOrWidth > 0.0f) ? column->InitStretchWeightOrWidth : 1.0f; | ||||
|             if (column->AutoFitQueue != 0x00) | ||||
|                 column->StretchWeight = default_weight; | ||||
|             sum_weights_stretched += column->StretchWeight; | ||||
|             if (table->LeftMostStretchedColumnDisplayOrder == -1) | ||||
|                 table->LeftMostStretchedColumnDisplayOrder = (ImS8)column->DisplayOrder; | ||||
|         } | ||||
|         sum_width_fixed_requests += table->CellPaddingX * 2.0f; | ||||
|     } | ||||
|     table->ColumnsVisibleFixedCount = (ImS8)count_fixed; | ||||
|  | ||||
|     // Layout | ||||
|     const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsVisibleCount - 1); | ||||
| @@ -963,10 +978,9 @@ void    ImGui::TableUpdateBorders(ImGuiTable* table) | ||||
|  | ||||
|         bool hovered = false, held = false; | ||||
|         bool pressed = ButtonBehavior(hit_rect, column_id, &hovered, &held, ImGuiButtonFlags_FlattenChildren | ImGuiButtonFlags_AllowItemOverlap | ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_PressedOnDoubleClick); | ||||
|         if (pressed && IsMouseDoubleClicked(0) && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) | ||||
|         if (pressed && IsMouseDoubleClicked(0)) | ||||
|         { | ||||
|             // FIXME-TABLE: Double-clicking on column edge could auto-fit Stretch column? | ||||
|             TableSetColumnAutofit(table, column_n); | ||||
|             TableSetColumnWidthAutoSingle(table, column_n); | ||||
|             ClearActiveID(); | ||||
|             held = hovered = false; | ||||
|         } | ||||
| @@ -1313,21 +1327,28 @@ void ImGui::TableSetColumnWidth(int column_n, float width) | ||||
|     } | ||||
|     else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch) | ||||
|     { | ||||
|         // [Resize Rule 2] | ||||
|         if (column_1 && (column_1->Flags & ImGuiTableColumnFlags_WidthFixed)) | ||||
|         // We can also use previous column if there's no next one | ||||
|         if (column_1 == NULL) | ||||
|             column_1 = (column_0->PrevVisibleColumn != -1) ? &table->Columns[column_0->PrevVisibleColumn] : NULL; | ||||
|         if (column_1 == NULL) | ||||
|             return; | ||||
|  | ||||
|         if (column_1->Flags & ImGuiTableColumnFlags_WidthFixed) | ||||
|         { | ||||
|             // [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); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // (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); | ||||
|         else | ||||
|         { | ||||
|             // (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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -1613,25 +1634,19 @@ void    ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, | ||||
|  | ||||
|     // Initialize defaults | ||||
|     if (flags & ImGuiTableColumnFlags_WidthStretch) | ||||
|     { | ||||
|         IM_ASSERT(init_width_or_weight != 0.0f && "Need to provide a valid weight!"); | ||||
|         if (init_width_or_weight < 0.0f) | ||||
|             init_width_or_weight = 1.0f; | ||||
|     } | ||||
|     column->InitStretchWeightOrWidth = init_width_or_weight; | ||||
|     if (table->IsInitializing && column->WidthRequest < 0.0f && column->StretchWeight < 0.0f) | ||||
|     { | ||||
|         // Init width or weight | ||||
|         if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) | ||||
|         { | ||||
|             // Disable auto-fit if a default fixed width has been specified | ||||
|             column->WidthRequest = init_width_or_weight; | ||||
|             column->AutoFitQueue = 0x00; | ||||
|         } | ||||
|         if (flags & ImGuiTableColumnFlags_WidthStretch) | ||||
|             column->StretchWeight = init_width_or_weight; | ||||
|         else | ||||
|             column->StretchWeight = 1.0f; | ||||
|             column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : 1.0f; | ||||
|  | ||||
|         // Disable auto-fit if an explicit fixed width has been specified | ||||
|         if (init_width_or_weight > 0.0f) | ||||
|             column->AutoFitQueue = 0x00; | ||||
|     } | ||||
|     if (table->IsInitializing) | ||||
|     { | ||||
| @@ -2041,13 +2056,30 @@ ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int | ||||
|     return id; | ||||
| } | ||||
|  | ||||
| void    ImGui::TableSetColumnAutofit(ImGuiTable* table, int column_n) | ||||
| // Disable clipping then auto-fit, will take 2 frames | ||||
| // (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns) | ||||
| void    ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n) | ||||
| { | ||||
|     // Disable clipping then auto-fit, will take 2 frames | ||||
|     // (we don't take a shortcut for unclipped columns to reduce inconsistencies when e.g. resizing multiple columns) | ||||
|     // Single auto width uses auto-fit | ||||
|     ImGuiTableColumn* column = &table->Columns[column_n]; | ||||
|     if (!column->IsVisible) | ||||
|         return; | ||||
|     column->CannotSkipItemsQueue = (1 << 0); | ||||
|     column->AutoFitQueue = (1 << 1); | ||||
|     if (column->Flags & ImGuiTableColumnFlags_WidthStretch) | ||||
|         table->AutoFitSingleStretchColumn = (ImS8)column_n; | ||||
| } | ||||
|  | ||||
| void    ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table) | ||||
| { | ||||
|     for (int column_n = 0; column_n < table->ColumnsCount; column_n++) | ||||
|     { | ||||
|         ImGuiTableColumn* column = &table->Columns[column_n]; | ||||
|         if (!column->IsVisible) | ||||
|             continue; | ||||
|         column->CannotSkipItemsQueue = (1 << 0); | ||||
|         column->AutoFitQueue = (1 << 1); | ||||
|     } | ||||
| } | ||||
|  | ||||
| void    ImGui::PushTableBackground() | ||||
| @@ -2092,20 +2124,20 @@ void    ImGui::TableDrawContextMenu(ImGuiTable* table) | ||||
|     { | ||||
|         if (column != NULL) | ||||
|         { | ||||
|             const bool can_resize = !(column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_WidthStretch)) && column->IsVisible; | ||||
|             const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsVisible; | ||||
|             if (MenuItem("Size column to fit", NULL, false, can_resize)) | ||||
|                 TableSetColumnAutofit(table, column_n); | ||||
|                 TableSetColumnWidthAutoSingle(table, column_n); | ||||
|         } | ||||
|  | ||||
|         if (MenuItem("Size all columns to fit", NULL)) | ||||
|         { | ||||
|             for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++) | ||||
|             { | ||||
|                 ImGuiTableColumn* other_column = &table->Columns[other_column_n]; | ||||
|                 if (other_column->IsVisible) | ||||
|                     TableSetColumnAutofit(table, other_column_n); | ||||
|             } | ||||
|         } | ||||
|         const char* size_all_desc; | ||||
|         if (table->ColumnsVisibleFixedCount == table->ColumnsVisibleCount) | ||||
|             size_all_desc = "Size all columns to fit";          // All fixed | ||||
|         else if (table->ColumnsVisibleFixedCount == 0) | ||||
|             size_all_desc = "Size all columns to default";      // All stretch | ||||
|         else | ||||
|             size_all_desc = "Size all columns to fit/default";  // Mixed | ||||
|         if (MenuItem(size_all_desc, NULL)) | ||||
|             TableSetColumnWidthAutoAll(table); | ||||
|         want_separator = true; | ||||
|     } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 ocornut
					ocornut