From bc170e73257e2be2713f63e0b386e81abca65f64 Mon Sep 17 00:00:00 2001 From: omar Date: Fri, 22 May 2020 15:27:53 +0200 Subject: [PATCH] Tables: Renamed ResizeWeight->WidthStretchWeight, WidthRequested->WidthFixedRequest, clarififications, comments. --- imgui_demo.cpp | 32 +++++++------- imgui_internal.h | 8 ++-- imgui_tables.cpp | 111 ++++++++++++++++++++++++----------------------- 3 files changed, 76 insertions(+), 75 deletions(-) diff --git a/imgui_demo.cpp b/imgui_demo.cpp index b91ec0ab..b55d5492 100644 --- a/imgui_demo.cpp +++ b/imgui_demo.cpp @@ -3246,7 +3246,7 @@ struct MyItem int Quantity; // We have a problem which is affecting _only this demo_ and should not affect your code: - // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), + // As we don't rely on std:: or other third-party library to compile dear imgui, we only have reliable access to qsort(), // however qsort doesn't allow passing user data to comparing function. // As a workaround, we are storing the sort specs in a static/global for the comparing function to access. // In your own use case you would probably pass the sort specs to your sorting/comparing functions directly and not use a global. @@ -3326,9 +3326,9 @@ static void ShowDemoWindowTables() if (ImGui::TreeNode("Basic")) { // Here we will showcase 4 different ways to output a table. They are very simple variations of a same thing! - + // Basic use of tables using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column. - // In many situations, this is the most flexible and easy to use pattern. + // In many situations, this is the most flexible and easy to use pattern. HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop."); if (ImGui::BeginTable("##table1", 3)) { @@ -3363,7 +3363,7 @@ static void ShowDemoWindowTables() } // Another subtle variant, we call TableNextCell() _before_ each cell. At the end of a row, TableNextCell() will create a new row. - // Note that we don't call TableNextRow() here! + // Note that we don't call TableNextRow() here! // If we want to call TableNextRow(), then we don't need to call TableNextCell() for the first cell. HelpMarker("Only using TableNextCell(), which tends to be convenient for tables where every cells contains the same type of contents.\nThis is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition."); if (ImGui::BeginTable("##table4", 3)) @@ -3449,7 +3449,7 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", (unsigned int*)&flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", (unsigned int*)&flags, ImGuiTableFlags_BordersV); ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersV flag as well."); - + if (ImGui::BeginTable("##table1", 3, flags)) { for (int row = 0; row < 5; row++) @@ -3550,7 +3550,7 @@ static void ShowDemoWindowTables() ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", (unsigned int*)&flags, ImGuiTableFlags_Resizable); ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", (unsigned int*)&flags, ImGuiTableFlags_Reorderable); ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", (unsigned int*)&flags, ImGuiTableFlags_Hideable); - + if (ImGui::BeginTable("##table1", 3, flags)) { // Submit columns name with TableSetupColumn() and call TableAutoHeaders() to create a row with a header in each column. @@ -3600,7 +3600,7 @@ static void ShowDemoWindowTables() static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollFreezeTopRow | ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable; ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", (unsigned int*)&flags, ImGuiTableFlags_ScrollY); ImGui::CheckboxFlags("ImGuiTableFlags_ScrollFreezeTopRow", (unsigned int*)&flags, ImGuiTableFlags_ScrollFreezeTopRow); - + if (ImGui::BeginTable("##table1", 3, flags, size)) { ImGui::TableSetupColumn("One", ImGuiTableColumnFlags_None); @@ -3735,7 +3735,7 @@ static void ShowDemoWindowTables() if (ImGui::TreeNode("Recursive")) { HelpMarker("This demonstrate embedding a table into another table cell."); - + if (ImGui::BeginTable("recurse1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_BordersVFullHeight | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable)) { ImGui::TableSetupColumn("A0"); @@ -3904,13 +3904,13 @@ static void ShowDemoWindowTables() ImGui::TableAutoHeaders(); // Simple storage to output a dummy file-system. - struct MyTreeNode - { - const char* Name; - const char* Type; - int Size; - int ChildIdx; - int ChildCount; + struct MyTreeNode + { + const char* Name; + const char* Type; + int Size; + int ChildIdx; + int ChildCount; static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes) { ImGui::TableNextRow(); @@ -3960,7 +3960,7 @@ static void ShowDemoWindowTables() } // Demonstrate using TableHeader() calls instead of TableAutoHeaders() - // FIXME-TABLE: Currently this doesn't get us feature-parity with TableAutoHeaders(), e.g. missing context menu. Tables API needs some work! + // FIXME-TABLE: Currently this doesn't get us feature-parity with TableAutoHeaders(), e.g. missing context menu. Tables API needs some work! if (open_action != -1) ImGui::SetNextItemOpen(open_action != 0); if (ImGui::TreeNode("Custom headers")) diff --git a/imgui_internal.h b/imgui_internal.h index d8d05245..362390a9 100644 --- a/imgui_internal.h +++ b/imgui_internal.h @@ -1897,9 +1897,9 @@ struct ImGuiTableColumn ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_ float MinX; // Absolute positions float MaxX; - float ResizeWeight; // ~1.0f. Master width data when (Flags & _WidthStretch) - float WidthRequested; // Master width data when !(Flags & _WidthStretch) - float WidthGiven; // == (MaxX - MinX). FIXME-TABLE: Store all persistent width in multiple of FontSize? + float WidthStretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially. + float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from WidthStretchWeight in TableUpdateLayout() + float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be >WidthRequest to honor minimum width, may be LeftMostStretchedColumnDisplayOrder = -1; table->ColumnsAutoFitWidth = 0.0f; for (int order_n = 0; order_n < table->ColumnsCount; order_n++) @@ -598,27 +598,27 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) { // Latch initial size for fixed columns count_fixed += 1; - const bool init_size = (column->AutoFitQueue != 0x00) || (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize); - if (init_size) + const bool auto_fit = (column->AutoFitQueue != 0x00) || (column->Flags & ImGuiTableColumnFlags_WidthAlwaysAutoResize); + if (auto_fit) { - column->WidthRequested = column_width_ideal; + column->WidthRequest = column_width_ideal; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets // (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very // large height (= first frame scrollbar display very off + clipper would skip lots of items). // This is merely making the side-effect less extreme, but doesn't properly fixes it. if (column->AutoFitQueue > 0x01 && table->IsInitializing) - column->WidthRequested = ImMax(column->WidthRequested, min_column_width * 4.0f); + column->WidthRequest = ImMax(column->WidthRequest, min_column_width * 4.0f); } - width_fixed += column->WidthRequested; + sum_width_fixed_requests += column->WidthRequest; } else { IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch); - const int init_size = (column->ResizeWeight < 0.0f); + const int init_size = (column->WidthStretchWeight < 0.0f); if (init_size) - column->ResizeWeight = 1.0f; - total_weights += column->ResizeWeight; + column->WidthStretchWeight = 1.0f; + sum_weights_stretched += column->WidthStretchWeight; if (table->LeftMostStretchedColumnDisplayOrder == -1) table->LeftMostStretchedColumnDisplayOrder = (ImS8)column->DisplayOrder; } @@ -636,7 +636,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) width_avail = table->InnerClipRect.GetWidth() - width_spacings - 1.0f; else width_avail = work_rect.GetWidth() - width_spacings - 1.0f; - const float width_avail_for_stretched_columns = width_avail - width_fixed; + const float width_avail_for_stretched_columns = width_avail - sum_width_fixed_requests; float width_remaining_for_stretched_columns = width_avail_for_stretched_columns; // Apply final width based on requested widths @@ -652,12 +652,13 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Allocate width for stretched/weighted columns if (column->Flags & ImGuiTableColumnFlags_WidthStretch) { - float weight_ratio = column->ResizeWeight / total_weights; - column->WidthRequested = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f); - width_remaining_for_stretched_columns -= column->WidthRequested; + // WidthStretchWeight gets converted into WidthRequest + float weight_ratio = column->WidthStretchWeight / sum_weights_stretched; + column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f); + width_remaining_for_stretched_columns -= column->WidthRequest; - // [Resize Rule 2] Resizing from right-side of a weighted column before a fixed column froward sizing - // to left-side of fixed column. We also need to copy the NoResize flag.. + // [Resize Rule 2] Resizing from right-side of a weighted column preceding a fixed column + // needs to forward resizing to left-side of fixed column. We also need to copy the NoResize flag.. if (column->NextVisibleColumn != -1) if (ImGuiTableColumn* next_column = &table->Columns[column->NextVisibleColumn]) if (next_column->Flags & ImGuiTableColumnFlags_WidthFixed) @@ -673,7 +674,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) count_resizable++; // Assign final width, record width in case we will need to shrink - column->WidthGiven = ImFloor(ImMax(column->WidthRequested, min_column_width)); + column->WidthGiven = ImFloor(ImMax(column->WidthRequest, min_column_width)); table->ColumnsTotalWidth += column->WidthGiven; } @@ -703,19 +704,19 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) #endif // Redistribute remainder width due to rounding (remainder width is < 1.0f * number of Stretch column). - // Using right-to-left distribution (more likely to match resizing cursor), could be adjusted depending where - // the mouse cursor is and/or relative weights. + // Using right-to-left distribution (more likely to match resizing cursor), could be adjusted depending + // on where the mouse cursor is and/or relative weights. // FIXME-TABLE: May be simpler to store floating width and floor final positions only // FIXME-TABLE: Make it optional? User might prefer to preserve pixel perfect same size? if (width_remaining_for_stretched_columns >= 1.0f) - for (int order_n = table->ColumnsCount - 1; total_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) + for (int order_n = table->ColumnsCount - 1; sum_weights_stretched > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) { if (!(table->VisibleMaskByDisplayOrder & ((ImU64)1 << order_n))) continue; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) continue; - column->WidthRequested += 1.0f; + column->WidthRequest += 1.0f; column->WidthGiven += 1.0f; width_remaining_for_stretched_columns -= 1.0f; } @@ -1168,8 +1169,8 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table) ImGuiTableColumn* column = &table->Columns[column_n]; if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) continue; - visible_weight += column->ResizeWeight; - visible_width += column->WidthRequested; + visible_weight += column->WidthStretchWeight; + visible_width += column->WidthRequest; } IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f); @@ -1179,7 +1180,7 @@ static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table) ImGuiTableColumn* column = &table->Columns[column_n]; if (!column->IsVisible || !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) continue; - column->ResizeWeight = (column->WidthRequested + 0.0f) / visible_width; + column->WidthStretchWeight = (column->WidthRequest + 0.0f) / visible_width; } } @@ -1205,7 +1206,7 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f column_0_width = ImClamp(column_0_width, min_width, max_width_0); // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded) - if (column_0->WidthGiven == column_0_width || column_0->WidthRequested == column_0_width) + if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width) return; ImGuiTableColumn* column_1 = (column_0->NextVisibleColumn != -1) ? &table->Columns[column_0->NextVisibleColumn] : NULL; @@ -1241,14 +1242,14 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < 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->WidthRequested - (column_0_width - column_0->WidthRequested), min_width); - column_0_width = column_0->WidthRequested + column_1->WidthRequested - column_1_width; - column_1->WidthRequested = column_1_width; + 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->WidthRequested = column_0_width; + column_0->WidthRequest = column_0_width; } else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch) { @@ -1257,15 +1258,15 @@ void ImGui::TableSetColumnWidth(ImGuiTable* table, ImGuiTableColumn* column_0, f { float off = (column_0->WidthGiven - column_0_width); float column_1_width = column_1->WidthGiven + off; - column_1->WidthRequested = ImMax(min_width, column_1_width); + 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->WidthRequested - (column_0_width - column_0->WidthRequested), min_width); - column_0_width = column_0->WidthRequested + column_1->WidthRequested - column_1_width; - column_1->WidthRequested = column_1_width; - column_0->WidthRequested = column_0_width; + 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; @@ -1462,23 +1463,23 @@ void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, // Initialize defaults // FIXME-TABLE: We don't restore widths/weight so let's avoid using IsSettingsLoaded for now - if (table->IsInitializing && column->WidthRequested < 0.0f && column->ResizeWeight < 0.0f)// && !table->IsSettingsLoaded) + if (table->IsInitializing && column->WidthRequest < 0.0f && column->WidthStretchWeight < 0.0f)// && !table->IsSettingsLoaded) { // Init width or weight // Disable auto-fit if a default fixed width has been specified if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f) { - column->WidthRequested = init_width_or_weight; + column->WidthRequest = init_width_or_weight; column->AutoFitQueue = 0x00; } if (flags & ImGuiTableColumnFlags_WidthStretch) { IM_ASSERT(init_width_or_weight < 0.0f || init_width_or_weight > 0.0f); - column->ResizeWeight = (init_width_or_weight < 0.0f ? 1.0f : init_width_or_weight); + column->WidthStretchWeight = (init_width_or_weight < 0.0f ? 1.0f : init_width_or_weight); } else { - column->ResizeWeight = 1.0f; + column->WidthStretchWeight = 1.0f; } } if (table->IsInitializing) @@ -2594,13 +2595,13 @@ void ImGui::DebugNodeTable(ImGuiTable* table) const char* name = TableGetColumnName(table, n); BulletText("Column %d order %d name '%s': +%.1f to +%.1f\n" "Visible: %d, Clipped: %d, DrawChannels: %d,%d\n" - "WidthGiven/Requested: %.1f/%.1f, Weight: %.2f\n" + "WidthGiven/Request: %.1f/%.1f, WidthWeight: %.3f\n" "ContentWidth: RowsFrozen %d, RowsUnfrozen %d, HeadersUsed/Ideal %d/%d\n" "SortOrder: %d, SortDir: %s\n" "UserID: 0x%08X, Flags: 0x%04X: %s%s%s%s..", n, column->DisplayOrder, name ? name : "NULL", column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, column->IsVisible, column->IsClipped, column->DrawChannelRowsBeforeFreeze, column->DrawChannelRowsAfterFreeze, - column->WidthGiven, column->WidthRequested, column->ResizeWeight, + column->WidthGiven, column->WidthRequest, column->WidthStretchWeight, column->ContentWidthRowsFrozen, column->ContentWidthRowsUnfrozen, column->ContentWidthHeadersUsed, column->ContentWidthHeadersIdeal, column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? "Ascending" : (column->SortDirection == ImGuiSortDirection_Descending) ? "Descending" : "None", column->UserID, column->Flags,