Browse Source

Tables: Frozen rows/columns in nav menu layer, fixed conflict between column id and holding child id.

ocornut 4 years ago
parent
commit
2ee20fdb7c
2 changed files with 26 additions and 17 deletions
  1. 2 1
      imgui_internal.h
  2. 24 16
      imgui_tables.cpp

+ 2 - 1
imgui_internal.h

@@ -1916,6 +1916,7 @@ struct ImGuiTableColumn
     bool                    IsVisibleNextFrame;
     bool                    IsVisibleNextFrame;
     bool                    IsClipped;                      // Set when not overlapping the host window clipping rectangle.
     bool                    IsClipped;                      // Set when not overlapping the host window clipping rectangle.
     bool                    SkipItems;
     bool                    SkipItems;
+    ImGuiNavLayer           NavLayerCurrent;
     ImS8                    DisplayOrder;                   // Index within Table's IndexToDisplayOrder[] (column may be reordered by users)
     ImS8                    DisplayOrder;                   // Index within Table's IndexToDisplayOrder[] (column may be reordered by users)
     ImS8                    IndexWithinVisibleSet;          // Index within visible set (<= IndexToDisplayOrder)
     ImS8                    IndexWithinVisibleSet;          // Index within visible set (<= IndexToDisplayOrder)
     ImS8                    DrawChannelCurrent;             // Index within DrawSplitter.Channels[]
     ImS8                    DrawChannelCurrent;             // Index within DrawSplitter.Channels[]
@@ -2039,7 +2040,7 @@ struct ImGuiTable
     bool                        IsSettingsDirty;            // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data.
     bool                        IsSettingsDirty;            // Set when table settings have changed and needs to be reported into ImGuiTableSetttings data.
     bool                        IsDefaultDisplayOrder;      // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
     bool                        IsDefaultDisplayOrder;      // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
     bool                        IsResetDisplayOrderRequest;
     bool                        IsResetDisplayOrderRequest;
-    bool                        IsFreezeRowsPassed;         // Set when we got past the frozen row (the first one).
+    bool                        IsFreezeRowsPassed;         // Set when we got past the frozen row.
     bool                        HostSkipItems;              // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis
     bool                        HostSkipItems;              // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis
 
 
     ImGuiTable()
     ImGuiTable()

+ 24 - 16
imgui_tables.cpp

@@ -235,12 +235,13 @@ bool    ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
         if (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX)
         if (override_content_size.x != FLT_MAX || override_content_size.y != FLT_MAX)
             SetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f));
             SetNextWindowContentSize(ImVec2(override_content_size.x != FLT_MAX ? override_content_size.x : 0.0f, override_content_size.y != FLT_MAX ? override_content_size.y : 0.0f));
 
 
-        // Create scrolling region (without border = zero window padding)
+        // Create scrolling region (without border and zero window padding)
         ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
         ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
         BeginChildEx(name, instance_id, table->OuterRect.GetSize(), false, child_flags);
         BeginChildEx(name, 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();
+        IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f);
     }
     }
 
 
     // Push a standardized ID for both child and not-child using tables, equivalent to BeginTable() doing PushID(label) matching
     // Push a standardized ID for both child and not-child using tables, equivalent to BeginTable() doing PushID(label) matching
@@ -479,7 +480,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
     ImGuiContext& g = *GImGui;
     ImGuiContext& g = *GImGui;
     ImGuiTable* table = g.CurrentTable;
     ImGuiTable* table = g.CurrentTable;
     IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
     IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
-    IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!");
+    IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!");
     IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
     IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS);
     IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
     IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit
 
 
@@ -487,7 +488,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
     table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
     table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
     table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImS8)rows : 0;
     table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImS8)rows : 0;
     table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
     table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
-    table->IsFreezeRowsPassed = (table->FreezeRowsCount == 0);
+    table->IsFreezeRowsPassed = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
 }
 }
 
 
 void ImGui::TableUpdateDrawChannels(ImGuiTable* table)
 void ImGui::TableUpdateDrawChannels(ImGuiTable* table)
@@ -778,6 +779,8 @@ void    ImGui::TableUpdateLayout(ImGuiTable* table)
         const int column_n = table->DisplayOrderToIndex[order_n];
         const int column_n = table->DisplayOrderToIndex[order_n];
         ImGuiTableColumn* column = &table->Columns[column_n];
         ImGuiTableColumn* column = &table->Columns[column_n];
 
 
+        column->NavLayerCurrent = (table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main;
+
         if (table->FreezeColumnsCount > 0 && table->FreezeColumnsCount == visible_n)
         if (table->FreezeColumnsCount > 0 && table->FreezeColumnsCount == visible_n)
             offset_x += work_rect.Min.x - table->OuterRect.Min.x;
             offset_x += work_rect.Min.x - table->OuterRect.Min.x;
 
 
@@ -1671,12 +1674,12 @@ void    ImGui::TableEndRow(ImGuiTable* table)
     const float bg_y1 = table->RowPosY1;
     const float bg_y1 = table->RowPosY1;
     const float bg_y2 = table->RowPosY2;
     const float bg_y2 = table->RowPosY2;
 
 
-    const bool unfreeze_rows = (table->CurrentRow + 1 == table->FreezeRowsCount && table->FreezeRowsCount > 0);
-
+    const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
+    const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
     if (table->CurrentRow == 0)
     if (table->CurrentRow == 0)
         table->LastFirstRowHeight = bg_y2 - bg_y1;
         table->LastFirstRowHeight = bg_y2 - bg_y1;
 
 
-    const bool is_visible = table->CurrentRow >= 0 && bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y;
+    const bool is_visible = (bg_y2 >= table->InnerClipRect.Min.y && bg_y1 <= table->InnerClipRect.Max.y);
     if (is_visible)
     if (is_visible)
     {
     {
         // Decide of background color for the row
         // Decide of background color for the row
@@ -1710,7 +1713,7 @@ void    ImGui::TableEndRow(ImGuiTable* table)
         }
         }
 
 
         const bool draw_cell_bg_color = table->RowCellDataCurrent >= 0;
         const bool draw_cell_bg_color = table->RowCellDataCurrent >= 0;
-        const bool draw_strong_bottom_border = unfreeze_rows;// || (table->RowFlags & ImGuiTableRowFlags_Headers);
+        const bool draw_strong_bottom_border = unfreeze_rows_actual;// || (table->RowFlags & ImGuiTableRowFlags_Headers);
         if ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color)
         if ((bg_col0 | bg_col1 | border_col) != 0 || draw_strong_bottom_border || draw_cell_bg_color)
         {
         {
             // In theory we could call SetWindowClipRectBeforeChannelChange() but since we know TableEndRow() is
             // In theory we could call SetWindowClipRectBeforeChannelChange() but since we know TableEndRow() is
@@ -1757,18 +1760,22 @@ void    ImGui::TableEndRow(ImGuiTable* table)
     // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle)
     // End frozen rows (when we are past the last frozen row line, teleport cursor and alter clipping rectangle)
     // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and
     // We need to do that in TableEndRow() instead of TableBeginRow() so the list clipper can mark end of row and
     // get the new cursor position.
     // get the new cursor position.
-    if (unfreeze_rows)
+    if (unfreeze_rows_request)
+        for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
+        {
+            ImGuiTableColumn* column = &table->Columns[column_n];
+            column->NavLayerCurrent = (column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main;
+        }
+    if (unfreeze_rows_actual)
     {
     {
         IM_ASSERT(table->IsFreezeRowsPassed == false);
         IM_ASSERT(table->IsFreezeRowsPassed == false);
         table->IsFreezeRowsPassed = true;
         table->IsFreezeRowsPassed = true;
         table->DrawSplitter.SetCurrentChannel(window->DrawList, 0);
         table->DrawSplitter.SetCurrentChannel(window->DrawList, 0);
 
 
-        ImRect r;
-        r.Min.x = table->InnerClipRect.Min.x;
-        r.Min.y = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
-        r.Max.x = table->InnerClipRect.Max.x;
-        r.Max.y = window->InnerClipRect.Max.y;
-        table->BackgroundClipRect = r;
+        // BackgroundClipRect starts as table->InnerClipRect, reduce it now
+        float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
+        table->BackgroundClipRect.Min.y = y0;
+        table->BackgroundClipRect.Max.y = window->InnerClipRect.Max.y;
 
 
         float row_height = table->RowPosY2 - table->RowPosY1;
         float row_height = table->RowPosY2 - table->RowPosY1;
         table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
         table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
@@ -1777,7 +1784,7 @@ void    ImGui::TableEndRow(ImGuiTable* table)
         {
         {
             ImGuiTableColumn* column = &table->Columns[column_n];
             ImGuiTableColumn* column = &table->Columns[column_n];
             column->DrawChannelCurrent = column->DrawChannelRowsAfterFreeze;
             column->DrawChannelCurrent = column->DrawChannelRowsAfterFreeze;
-            column->ClipRect.Min.y = r.Min.y;
+            column->ClipRect.Min.y = table->BackgroundClipRect.Min.y;
         }
         }
 
 
         // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
         // Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
@@ -1810,6 +1817,7 @@ void    ImGui::TableBeginCell(ImGuiTable* table, int column_n)
     window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT
     window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT
     window->DC.CurrLineTextBaseOffset = table->RowTextBaseline;
     window->DC.CurrLineTextBaseOffset = table->RowTextBaseline;
     window->DC.LastItemId = 0;
     window->DC.LastItemId = 0;
+    window->DC.NavLayerCurrent = column->NavLayerCurrent;
 
 
     window->WorkRect.Min.y = window->DC.CursorPos.y;
     window->WorkRect.Min.y = window->DC.CursorPos.y;
     window->WorkRect.Min.x = column->MinX + table->CellPaddingX1;
     window->WorkRect.Min.x = column->MinX + table->CellPaddingX1;
@@ -1964,7 +1972,7 @@ const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)
 ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no)
 ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no)
 {
 {
     IM_ASSERT(column_n < table->ColumnsCount);
     IM_ASSERT(column_n < table->ColumnsCount);
-    ImGuiID id = table->ID + (instance_no * table->ColumnsCount) + column_n;
+    ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n;
     return id;
     return id;
 }
 }