From c7c378c5dd3b28b23db52da618f7dc09b3b477f4 Mon Sep 17 00:00:00 2001 From: lyrae-versebound Date: Thu, 13 Aug 2026 23:12:33 -0400 Subject: [PATCH 1/5] Fix automatic Table scrollbars --- SadConsole.Extended/UI/Controls/Table.cs | 10 ++++++--- Tests/SadConsole.Tests/UI/TableTests.cs | 26 ++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 3 deletions(-) diff --git a/SadConsole.Extended/UI/Controls/Table.cs b/SadConsole.Extended/UI/Controls/Table.cs index cee2e92b..157c7ef8 100644 --- a/SadConsole.Extended/UI/Controls/Table.cs +++ b/SadConsole.Extended/UI/Controls/Table.cs @@ -128,12 +128,12 @@ internal set public event EventHandler? OnDrawFakeCell; /// - /// The vertical scrollbar, use the SetupScrollBar method with Vertical orientation to initialize it. + /// The vertical scrollbar, automatically configured by the table. /// public ScrollBar? VerticalScrollBar { get; private set; } /// - /// The horizontal scrollbar, use the SetupScrollBar method with Horizontal orientation to initialize it. + /// The horizontal scrollbar, automatically configured by the table. /// public ScrollBar? HorizontalScrollBar { get; private set; } @@ -243,6 +243,10 @@ public Table(int width, int height) : base(width, height) DefaultForeground = Color.White; DefaultBackground = Color.TransparentBlack; DefaultCellSize = new Point(1, 1); + if (width >= 2) + SetupScrollBar(Orientation.Horizontal, width, new Point(0, height - 1)); + if (height >= 2) + SetupScrollBar(Orientation.Vertical, height, new Point(width - 1, 0)); } /// @@ -285,7 +289,7 @@ internal void DrawFakeCell(Cell cell) } /// - /// Configures the associated . + /// Reconfigures the scrollbar for the specified orientation. /// /// The orientation of the scrollbar. /// diff --git a/Tests/SadConsole.Tests/UI/TableTests.cs b/Tests/SadConsole.Tests/UI/TableTests.cs index f754a095..4d62939d 100644 --- a/Tests/SadConsole.Tests/UI/TableTests.cs +++ b/Tests/SadConsole.Tests/UI/TableTests.cs @@ -261,6 +261,31 @@ public void Cells_Cell_CopyAppearanceFrom_Correct() Assert.AreEqual(cellB.Settings.Selectable, true); } + [TestMethod] + public void Table_ScrollBars_AutomaticallyAppearForOverflowingData() + { + var table = new Table(6, 6, 2, 2); + + for (int column = 0; column < 4; column++) + table.Cells[0, column].Value = column.ToString(); + + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsFalse(table.IsVerticalScrollBarVisible); + Assert.IsNotNull(table.HorizontalScrollBar); + Assert.AreEqual(1, table.HorizontalScrollBar.MaximumValue); + + for (int row = 0; row < 4; row++) + table.Cells[row, 0].Value = row.ToString(); + + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.IsNotNull(table.VerticalScrollBar); + Assert.AreEqual(1, table.VerticalScrollBar.MaximumValue); + } + [TestMethod] public void Table_ScrollBar_Vertical_Scrolling_EqualSizes_Correct() { @@ -589,6 +614,7 @@ protected TableTestsBase(int width, int height, int cellWidth, int cellHeight) [TestInitialize] public virtual void Setup() { + new BasicGameHost(); Table = new Table(Width, Height, CellWidth, CellHeight); } From 2d4290b54ee0dd58b46852e0be24e85521eef7fb Mon Sep 17 00:00:00 2001 From: lyrae-versebound Date: Thu, 13 Aug 2026 23:50:09 -0400 Subject: [PATCH 2/5] Reflow automatic Table scrollbars --- SadConsole.Extended/UI/Controls/Table.cs | 65 ++++++++++++++++++++++-- Tests/SadConsole.Tests/UI/TableTests.cs | 59 +++++++++++++++++++++ 2 files changed, 119 insertions(+), 5 deletions(-) diff --git a/SadConsole.Extended/UI/Controls/Table.cs b/SadConsole.Extended/UI/Controls/Table.cs index 157c7ef8..23bd7a10 100644 --- a/SadConsole.Extended/UI/Controls/Table.cs +++ b/SadConsole.Extended/UI/Controls/Table.cs @@ -143,7 +143,12 @@ internal set public bool IsVerticalScrollBarVisible { get => VerticalScrollBar != null && VerticalScrollBar.IsVisible; - internal set { if (VerticalScrollBar == null) return; VerticalScrollBar.IsVisible = value; } + internal set + { + if (VerticalScrollBar == null) return; + VerticalScrollBar.IsVisible = value; + UpdateAutomaticScrollBarGeometry(); + } } /// /// Returns true if the horizontal scroll bar is currently visible. @@ -151,7 +156,12 @@ public bool IsVerticalScrollBarVisible public bool IsHorizontalScrollBarVisible { get => HorizontalScrollBar != null && HorizontalScrollBar.IsVisible; - internal set { if (HorizontalScrollBar == null) return; HorizontalScrollBar.IsVisible = value; } + internal set + { + if (HorizontalScrollBar == null) return; + HorizontalScrollBar.IsVisible = value; + UpdateAutomaticScrollBarGeometry(); + } } /// @@ -208,6 +218,8 @@ public int HorizontalScrollBarMaximum private DateTime _leftMouseLastClick = DateTime.Now; private Point? _leftMouseLastClickPosition; internal bool _checkScrollBarVisibility; + private bool _automaticallyManageHorizontalScrollBar; + private bool _automaticallyManageVerticalScrollBar; private int _previousScrollValueVertical, _previousScrollValueHorizontal; private void ScrollBar_ValueChanged(object? sender, EventArgs e) @@ -244,9 +256,11 @@ public Table(int width, int height) : base(width, height) DefaultBackground = Color.TransparentBlack; DefaultCellSize = new Point(1, 1); if (width >= 2) - SetupScrollBar(Orientation.Horizontal, width, new Point(0, height - 1)); + SetupScrollBar(Orientation.Horizontal, width, new Point(0, height - 1), true); if (height >= 2) - SetupScrollBar(Orientation.Vertical, height, new Point(width - 1, 0)); + SetupScrollBar(Orientation.Vertical, height, new Point(width - 1, 0), true); + + UpdateAutomaticScrollBarGeometry(); } /// @@ -294,7 +308,10 @@ internal void DrawFakeCell(Cell cell) /// The orientation of the scrollbar. /// /// The position of the scrollbar. - public void SetupScrollBar(Orientation orientation, int size, Point position) + public void SetupScrollBar(Orientation orientation, int size, Point position) => + SetupScrollBar(orientation, size, position, false); + + private void SetupScrollBar(Orientation orientation, int size, Point position, bool automaticallyManageGeometry) { bool scrollBarExists = false; int value = 0; @@ -323,13 +340,51 @@ public void SetupScrollBar(Orientation orientation, int size, Point position) AddControl(existingScrollBar); if (orientation == Orientation.Vertical) + { VerticalScrollBar = existingScrollBar; + _automaticallyManageVerticalScrollBar = automaticallyManageGeometry; + } else + { HorizontalScrollBar = existingScrollBar; + _automaticallyManageHorizontalScrollBar = automaticallyManageGeometry; + } _checkScrollBarVisibility = true; DetermineState(); + UpdateAutomaticScrollBarGeometry(); + } + + private void UpdateAutomaticScrollBarGeometry() + { + bool reserveCorner = IsHorizontalScrollBarVisible && IsVerticalScrollBarVisible; + + if (_automaticallyManageHorizontalScrollBar && HorizontalScrollBar != null) + { + int width = reserveCorner ? Width - 1 : Width; + if (width >= 2 && HorizontalScrollBar.Width != width) + HorizontalScrollBar.Resize(width, 1); + + HorizontalScrollBar.Position = new Point(0, Height - 1); + } + + if (_automaticallyManageVerticalScrollBar && VerticalScrollBar != null) + { + int height = reserveCorner ? Height - 1 : Height; + if (height >= 2 && VerticalScrollBar.Height != height) + VerticalScrollBar.Resize(1, height); + + VerticalScrollBar.Position = new Point(Width - 1, 0); + } + } + + /// + protected override void OnResized() + { + base.OnResized(); + UpdateAutomaticScrollBarGeometry(); + _checkScrollBarVisibility = true; } internal HashSet GetIndexesWithContent(TableCells.Layout.LayoutType indexType) diff --git a/Tests/SadConsole.Tests/UI/TableTests.cs b/Tests/SadConsole.Tests/UI/TableTests.cs index 4d62939d..8b23f0dc 100644 --- a/Tests/SadConsole.Tests/UI/TableTests.cs +++ b/Tests/SadConsole.Tests/UI/TableTests.cs @@ -286,6 +286,65 @@ public void Table_ScrollBars_AutomaticallyAppearForOverflowingData() Assert.AreEqual(1, table.VerticalScrollBar.MaximumValue); } + [TestMethod] + public void Table_ScrollBars_AutomaticallyReflowWithoutOverlap() + { + var table = new Table(6, 6, 2, 2); + + for (int index = 0; index < 7; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(new Point(0, 5), table.HorizontalScrollBar.Position); + Assert.AreEqual(5, table.HorizontalScrollBar.Width); + Assert.AreEqual(new Point(5, 0), table.VerticalScrollBar.Position); + Assert.AreEqual(5, table.VerticalScrollBar.Height); + Assert.IsFalse(table.HorizontalScrollBar.Bounds.Intersects(table.VerticalScrollBar.Bounds)); + + table.Resize(10, 8); + + Assert.AreEqual(new Point(0, 7), table.HorizontalScrollBar.Position); + Assert.AreEqual(9, table.HorizontalScrollBar.Width); + Assert.AreEqual(new Point(9, 0), table.VerticalScrollBar.Position); + Assert.AreEqual(7, table.VerticalScrollBar.Height); + Assert.IsFalse(table.HorizontalScrollBar.Bounds.Intersects(table.VerticalScrollBar.Bounds)); + + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + } + + [TestMethod] + public void Table_SetupScrollBar_ReconfiguresAutomaticBarWithoutDuplicates() + { + var table = new Table(6, 6, 2, 2); + ScrollBar originalHorizontalScrollBar = table.HorizontalScrollBar; + + table.SetupScrollBar(Orientation.Horizontal, 4, new Point(1, 4)); + + Assert.AreEqual(2, ((IContainer)table).Count); + Assert.AreNotSame(originalHorizontalScrollBar, table.HorizontalScrollBar); + Assert.AreEqual(new Point(1, 4), table.HorizontalScrollBar.Position); + Assert.AreEqual(4, table.HorizontalScrollBar.Width); + + for (int column = 0; column < 4; column++) + table.Cells[0, column].Value = column.ToString(); + + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.Resize(10, 8); + + Assert.AreEqual(2, ((IContainer)table).Count); + Assert.AreEqual(new Point(1, 4), table.HorizontalScrollBar.Position); + Assert.AreEqual(4, table.HorizontalScrollBar.Width); + } + [TestMethod] public void Table_ScrollBar_Vertical_Scrolling_EqualSizes_Correct() { From 349fd1534819cc14c3eb9693c45af6774c605b5d Mon Sep 17 00:00:00 2001 From: lyrae-versebound Date: Fri, 14 Aug 2026 00:33:05 -0400 Subject: [PATCH 3/5] Fix Table scrollbar lifecycle --- .../UI/Controls/Table.Theme.cs | 87 ++++++++--- SadConsole.Extended/UI/Controls/Table.cs | 137 ++++++++++++----- Tests/SadConsole.Tests/UI/TableTests.cs | 144 +++++++++++++++++- 3 files changed, 313 insertions(+), 55 deletions(-) diff --git a/SadConsole.Extended/UI/Controls/Table.Theme.cs b/SadConsole.Extended/UI/Controls/Table.Theme.cs index 5accb69f..1777aed2 100644 --- a/SadConsole.Extended/UI/Controls/Table.Theme.cs +++ b/SadConsole.Extended/UI/Controls/Table.Theme.cs @@ -14,6 +14,7 @@ public override void UpdateAndRedraw(TimeSpan time) { if (!IsDirty) return; + EnsureAutomaticScrollBars(); RefreshThemeStateColors(FindThemeColors()); // Draw the basic table surface foreground and background, and clear the glyphs @@ -31,12 +32,15 @@ public override void UpdateAndRedraw(TimeSpan time) SetScrollBarVisibility(maxRowsHeight, maxColumnsWidth); + int viewportWidth = EffectiveViewportWidth; + int viewportHeight = EffectiveViewportHeight; + int rows = 0; int rowIndexPos = Cells.GetIndexAtCellPosition(StartRenderYPos, Table.TableCells.Layout.LayoutType.Row, out _); int rowIndex = IsVerticalScrollBarVisible ? rowIndexPos : 0; bool offScreenY = false; List<((int x, int y), (int row, int col))>? fakeCells = DrawFakeCells ? new() : null; - for (int row = 0; row <= Height; row++) + for (int row = 0; row <= viewportHeight; row++) { if (rows >= allRowIndexesWithContent.Count) break; if (allRowIndexesWithContent.Contains(row)) rows++; @@ -51,7 +55,7 @@ public override void UpdateAndRedraw(TimeSpan time) int fullRowSize = 0; bool headerRow = false; - for (int col = 0; col <= Width; col++) + for (int col = 0; col <= viewportWidth; col++) { if (columns >= allColumnIndexesWithContent.Count) break; if (allColumnIndexesWithContent.Contains(col)) columns++; @@ -84,15 +88,15 @@ public override void UpdateAndRedraw(TimeSpan time) } // Don't attempt to render off-screen rows/columns - if (cellPosition.X > Width || cellPosition.Y > Height) + if (cellPosition.X > viewportWidth || cellPosition.Y > viewportHeight) { - if (cellPosition.Y > Height) + if (cellPosition.Y > viewportHeight) { offScreenY = true; break; } - if (cellPosition.X > Width) + if (cellPosition.X > viewportWidth) break; } @@ -184,11 +188,10 @@ private void SetScrollBarPropertiesOnTable(ScrollBar scrollBar, int maxRowsHeigh { if (scrollBar != null) { + int max = scrollBar.Orientation == Orientation.Vertical ? EffectiveViewportHeight : EffectiveViewportWidth; int total = scrollBar.Orientation == Orientation.Vertical ? - (maxRowsHeight >= Height ? Height : maxRowsHeight) : - (maxColumnsWidth >= Width ? Width : maxColumnsWidth); - - int max = scrollBar.Orientation == Orientation.Vertical ? Height : Width; + Math.Min(maxRowsHeight, max) : + Math.Min(maxColumnsWidth, max); if (scrollBar.Orientation == Orientation.Vertical) { @@ -211,19 +214,63 @@ private void SetScrollBarPropertiesOnTable(ScrollBar scrollBar, int maxRowsHeigh /// The maximum width of the columns. protected void SetScrollBarVisibility(int maxRowsHeight, int maxColumnsWidth) { - if (_checkScrollBarVisibility) + if (!_checkScrollBarVisibility) + return; + + EnsureAutomaticScrollBars(); + + ScrollBar? horizontalScrollBar = HorizontalScrollBar; + ScrollBar? verticalScrollBar = VerticalScrollBar; + bool horizontalWasVisible = IsHorizontalScrollBarVisible; + bool verticalWasVisible = IsVerticalScrollBarVisible; + + bool showHorizontal = horizontalScrollBar != null && GetScrollBarItems(Orientation.Horizontal, Width) > 0; + bool showVertical = verticalScrollBar != null && GetScrollBarItems(Orientation.Vertical, Height) > 0; + + for (int i = 0; i < 2; i++) { - if (VerticalScrollBar != null) - { - IsVerticalScrollBarVisible = ShowHideScrollBar(VerticalScrollBar); - SetScrollBarPropertiesOnTable(VerticalScrollBar, maxRowsHeight, maxColumnsWidth); - } - if (HorizontalScrollBar != null) - { - IsHorizontalScrollBarVisible = ShowHideScrollBar(HorizontalScrollBar); - SetScrollBarPropertiesOnTable(HorizontalScrollBar, maxRowsHeight, maxColumnsWidth); - } + int viewportWidth = Math.Max(Width - (_automaticallyManageVerticalScrollBar && showVertical ? 1 : 0), 0); + int viewportHeight = Math.Max(Height - (_automaticallyManageHorizontalScrollBar && showHorizontal ? 1 : 0), 0); + bool nextShowHorizontal = horizontalScrollBar != null && GetScrollBarItems(Orientation.Horizontal, viewportWidth) > 0; + bool nextShowVertical = verticalScrollBar != null && GetScrollBarItems(Orientation.Vertical, viewportHeight) > 0; + + if (showHorizontal == nextShowHorizontal && showVertical == nextShowVertical) + break; + + showHorizontal = nextShowHorizontal; + showVertical = nextShowVertical; + } + + if (horizontalScrollBar != null) + horizontalScrollBar.IsVisible = showHorizontal; + if (verticalScrollBar != null) + verticalScrollBar.IsVisible = showVertical; + + UpdateAutomaticScrollBarGeometry(); + + bool stateChanged = horizontalWasVisible != IsHorizontalScrollBarVisible || + verticalWasVisible != IsVerticalScrollBarVisible || + horizontalScrollBar != HorizontalScrollBar || + verticalScrollBar != VerticalScrollBar; + + if (HorizontalScrollBar != null) + { + int scrollItems = GetScrollBarItems(Orientation.Horizontal); + stateChanged |= ReconcileScrollBarState(HorizontalScrollBar, HorizontalScrollBar.IsVisible, scrollItems); + SetScrollBarPropertiesOnTable(HorizontalScrollBar, maxRowsHeight, maxColumnsWidth); + } + + if (VerticalScrollBar != null) + { + int scrollItems = GetScrollBarItems(Orientation.Vertical); + stateChanged |= ReconcileScrollBarState(VerticalScrollBar, VerticalScrollBar.IsVisible, scrollItems); + SetScrollBarPropertiesOnTable(VerticalScrollBar, maxRowsHeight, maxColumnsWidth); } + + if (stateChanged) + SynchronizeScrollOffsetsFromValues(); + + _checkScrollBarVisibility = false; } /// diff --git a/SadConsole.Extended/UI/Controls/Table.cs b/SadConsole.Extended/UI/Controls/Table.cs index 23bd7a10..06d195d3 100644 --- a/SadConsole.Extended/UI/Controls/Table.cs +++ b/SadConsole.Extended/UI/Controls/Table.cs @@ -147,7 +147,6 @@ internal set { if (VerticalScrollBar == null) return; VerticalScrollBar.IsVisible = value; - UpdateAutomaticScrollBarGeometry(); } } /// @@ -160,7 +159,6 @@ internal set { if (HorizontalScrollBar == null) return; HorizontalScrollBar.IsVisible = value; - UpdateAutomaticScrollBarGeometry(); } } @@ -218,8 +216,14 @@ public int HorizontalScrollBarMaximum private DateTime _leftMouseLastClick = DateTime.Now; private Point? _leftMouseLastClickPosition; internal bool _checkScrollBarVisibility; - private bool _automaticallyManageHorizontalScrollBar; - private bool _automaticallyManageVerticalScrollBar; + private bool _automaticallyManageHorizontalScrollBar = true; + private bool _automaticallyManageVerticalScrollBar = true; + + private int EffectiveViewportWidth => + Math.Max(Width - (_automaticallyManageVerticalScrollBar && IsVerticalScrollBarVisible ? 1 : 0), 0); + + private int EffectiveViewportHeight => + Math.Max(Height - (_automaticallyManageHorizontalScrollBar && IsHorizontalScrollBarVisible ? 1 : 0), 0); private int _previousScrollValueVertical, _previousScrollValueHorizontal; private void ScrollBar_ValueChanged(object? sender, EventArgs e) @@ -255,11 +259,7 @@ public Table(int width, int height) : base(width, height) DefaultForeground = Color.White; DefaultBackground = Color.TransparentBlack; DefaultCellSize = new Point(1, 1); - if (width >= 2) - SetupScrollBar(Orientation.Horizontal, width, new Point(0, height - 1), true); - if (height >= 2) - SetupScrollBar(Orientation.Vertical, height, new Point(width - 1, 0), true); - + EnsureAutomaticScrollBars(); UpdateAutomaticScrollBarGeometry(); } @@ -329,6 +329,9 @@ private void SetupScrollBar(Orientation orientation, int size, Point position, b existingScrollBar = new ScrollBar(orientation, size); + if (automaticallyManageGeometry) + existingScrollBar.IsVisible = false; + if (scrollBarExists) { existingScrollBar.MaximumValue = max; @@ -356,24 +359,66 @@ private void SetupScrollBar(Orientation orientation, int size, Point position, b UpdateAutomaticScrollBarGeometry(); } + private void EnsureAutomaticScrollBars() + { + if (_automaticallyManageHorizontalScrollBar && HorizontalScrollBar == null && Width >= 2) + SetupScrollBar(Orientation.Horizontal, Width, new Point(0, Height - 1), true); + + if (_automaticallyManageVerticalScrollBar && VerticalScrollBar == null && Height >= 2) + SetupScrollBar(Orientation.Vertical, Height, new Point(Width - 1, 0), true); + } + + private void RemoveAutomaticScrollBar(Orientation orientation) + { + ScrollBar? scrollBar = orientation == Orientation.Horizontal ? HorizontalScrollBar : VerticalScrollBar; + if (scrollBar == null) + return; + + scrollBar.ValueChanged -= ScrollBar_ValueChanged; + RemoveControl(scrollBar); + + if (orientation == Orientation.Horizontal) + { + HorizontalScrollBar = null; + StartRenderXPos = 0; + _previousScrollValueHorizontal = 0; + } + else + { + VerticalScrollBar = null; + StartRenderYPos = 0; + _previousScrollValueVertical = 0; + } + } + private void UpdateAutomaticScrollBarGeometry() { bool reserveCorner = IsHorizontalScrollBarVisible && IsVerticalScrollBarVisible; + int horizontalWidth = reserveCorner ? Width - 1 : Width; + int verticalHeight = reserveCorner ? Height - 1 : Height; + + if (_automaticallyManageHorizontalScrollBar && HorizontalScrollBar != null && horizontalWidth < 2) + RemoveAutomaticScrollBar(Orientation.Horizontal); + + if (_automaticallyManageVerticalScrollBar && VerticalScrollBar != null && verticalHeight < 2) + RemoveAutomaticScrollBar(Orientation.Vertical); + + reserveCorner = IsHorizontalScrollBarVisible && IsVerticalScrollBarVisible; if (_automaticallyManageHorizontalScrollBar && HorizontalScrollBar != null) { - int width = reserveCorner ? Width - 1 : Width; - if (width >= 2 && HorizontalScrollBar.Width != width) - HorizontalScrollBar.Resize(width, 1); + horizontalWidth = reserveCorner ? Width - 1 : Width; + if (HorizontalScrollBar.Width != horizontalWidth) + HorizontalScrollBar.Resize(horizontalWidth, 1); HorizontalScrollBar.Position = new Point(0, Height - 1); } if (_automaticallyManageVerticalScrollBar && VerticalScrollBar != null) { - int height = reserveCorner ? Height - 1 : Height; - if (height >= 2 && VerticalScrollBar.Height != height) - VerticalScrollBar.Resize(1, height); + verticalHeight = reserveCorner ? Height - 1 : Height; + if (VerticalScrollBar.Height != verticalHeight) + VerticalScrollBar.Resize(1, verticalHeight); VerticalScrollBar.Position = new Point(Width - 1, 0); } @@ -383,6 +428,7 @@ private void UpdateAutomaticScrollBarGeometry() protected override void OnResized() { base.OnResized(); + EnsureAutomaticScrollBars(); UpdateAutomaticScrollBarGeometry(); _checkScrollBarVisibility = true; } @@ -430,18 +476,24 @@ private void UpdateScrollBarMaximum(Orientation orientation) if (scrollBar != null) { int scrollItems = GetScrollBarItems(orientation); - scrollBar.MaximumValue = scrollItems < 0 ? 0 : scrollItems; + if (ReconcileScrollBarState(scrollBar, scrollBar.IsVisible, scrollItems)) + SynchronizeScrollOffsetsFromValues(); } } internal int GetScrollBarItems(Orientation orientation) + { + int maxSize = orientation == Orientation.Vertical ? EffectiveViewportHeight : EffectiveViewportWidth; + return GetScrollBarItems(orientation, maxSize); + } + + private int GetScrollBarItems(Orientation orientation, int maxSize) { IEnumerable> indexes = orientation == Orientation.Vertical ? Cells.GroupBy(a => a.Row) : Cells.GroupBy(a => a.Column); IOrderedEnumerable> orderedIndex = indexes.OrderBy(a => a.Key); TableCells.Layout.LayoutType layoutType = orientation == Orientation.Vertical ? TableCells.Layout.LayoutType.Row : TableCells.Layout.LayoutType.Column; - int maxSize = orientation == Orientation.Vertical ? Height : Width; int totalSize = 0; int items = 0; foreach (IGrouping index in orderedIndex) @@ -466,18 +518,30 @@ internal int GetScrollBarItems(Orientation orientation) /// internal bool ShowHideScrollBar(ScrollBar scrollBar) { - // process the scroll bar int scrollbarItems = GetScrollBarItems(scrollBar.Orientation); - if (scrollbarItems > 0) - { - scrollBar.MaximumValue = scrollbarItems; - return true; - } + bool isVisible = scrollbarItems > 0; + ReconcileScrollBarState(scrollBar, isVisible, scrollbarItems); + return isVisible; + } + + private bool ReconcileScrollBarState(ScrollBar scrollBar, bool isVisible, int scrollItems) + { + int oldMaximum = scrollBar.MaximumValue; + int oldValue = scrollBar.Value; + int maximum = Math.Max(scrollItems, 0); + int value = isVisible ? Math.Min(oldValue, maximum) : 0; + + scrollBar.ValueChanged -= ScrollBar_ValueChanged; + scrollBar.MaximumValue = maximum; + scrollBar.Value = value; + scrollBar.ValueChanged += ScrollBar_ValueChanged; + + if (scrollBar.Orientation == Orientation.Vertical) + _previousScrollValueVertical = scrollBar.Value; else - { - scrollBar.MaximumValue = 0; - return false; - } + _previousScrollValueHorizontal = scrollBar.Value; + + return oldMaximum != scrollBar.MaximumValue || oldValue != scrollBar.Value; } internal bool IsEntireRowOrColumnNotVisible(int index, TableCells.Layout.LayoutType type) @@ -534,10 +598,11 @@ public void ScrollToSelectedItem() /// internal void SyncScrollAmountOnResize() { - if ((!IsVerticalScrollBarVisible && !IsHorizontalScrollBarVisible) || - (StartRenderXPos == 0 && StartRenderYPos == 0)) - return; + SynchronizeScrollOffsetsFromValues(); + } + private void SynchronizeScrollOffsetsFromValues() + { StartRenderYPos = 0; StartRenderXPos = 0; @@ -555,6 +620,9 @@ internal void SyncScrollAmountOnResize() SetScrollAmount(Orientation.Horizontal, true); Cells.AdjustCellPositionsAfterResize(); } + + _previousScrollValueVertical = amountVertical; + _previousScrollValueHorizontal = amountHorizontal; } /// @@ -587,6 +655,7 @@ internal int GetNextScrollPos(bool increment, Orientation orientation) : TableCells.Layout.LayoutType.Column; bool isRowType = type == TableCells.Layout.LayoutType.Row; + int viewportSize = isRowType ? EffectiveViewportHeight : EffectiveViewportWidth; IEnumerable> cellGroups = Cells.GroupBy(a => isRowType ? a.Row : a.Column); @@ -604,21 +673,21 @@ internal int GetNextScrollPos(bool increment, Orientation orientation) if (!increment) { // Check if cell position is the last cell on screen - if (indexSizeCell >= (isRowType ? Height : Width)) + if (indexSizeCell >= viewportSize) break; } else { // Check if cell position is the next off-screen // >= because it assumes the cell starts at Height, and thats off screen - bool isPositionOfScreen = isRowType ? indexSizeCell >= Height : indexSizeCell >= Width; + bool isPositionOfScreen = indexSizeCell >= viewportSize; if (!isPositionOfScreen) { // Here it is only > because if the real cell pos is 20 its the ending, so where the next cell starts // which means its not off screen int realCellPosition = isRowType ? (cell._position.Y + cell.Height) : (cell._position.X + cell.Width); - if (realCellPosition > (isRowType ? Height : Width)) + if (realCellPosition > viewportSize) partialOverlap = true; else break; @@ -635,7 +704,7 @@ internal int GetNextScrollPos(bool increment, Orientation orientation) // Calculate the overlap amount if (partialOverlap) { - int overlapAmount = indexSizeCell + cellSize - (isRowType ? Height : Width); + int overlapAmount = indexSizeCell + cellSize - viewportSize; cellSize = overlapAmount; } diff --git a/Tests/SadConsole.Tests/UI/TableTests.cs b/Tests/SadConsole.Tests/UI/TableTests.cs index 8b23f0dc..f1c52b5d 100644 --- a/Tests/SadConsole.Tests/UI/TableTests.cs +++ b/Tests/SadConsole.Tests/UI/TableTests.cs @@ -283,7 +283,8 @@ public void Table_ScrollBars_AutomaticallyAppearForOverflowingData() Assert.IsTrue(table.IsVerticalScrollBarVisible); Assert.IsNotNull(table.VerticalScrollBar); - Assert.AreEqual(1, table.VerticalScrollBar.MaximumValue); + Assert.AreEqual(2, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(2, table.VerticalScrollBar.MaximumValue); } [TestMethod] @@ -321,6 +322,147 @@ public void Table_ScrollBars_AutomaticallyReflowWithoutOverlap() Assert.IsTrue(table.IsVerticalScrollBarVisible); } + [TestMethod] + public void Table_ScrollBars_AutomaticallyRecreateAfterGrowingPastMinimumSize() + { + var table = new Table(1, 1); + + Assert.IsNull(table.HorizontalScrollBar); + Assert.IsNull(table.VerticalScrollBar); + Assert.AreEqual(0, ((IContainer)table).Count); + + table.Resize(6, 6); + + Assert.IsNotNull(table.HorizontalScrollBar); + Assert.IsNotNull(table.VerticalScrollBar); + Assert.AreEqual(2, ((IContainer)table).Count); + + for (int index = 0; index < 7; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(5, table.HorizontalScrollBar.Width); + Assert.AreEqual(5, table.VerticalScrollBar.Height); + } + + [TestMethod] + public void Table_ScrollBars_AutomaticallyRemoveInvalidJointGeometryAndRecreate() + { + var table = new Table(6, 6); + + for (int index = 0; index < 7; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + + table.Resize(2, 2); + + Assert.IsNull(table.HorizontalScrollBar); + Assert.IsNull(table.VerticalScrollBar); + Assert.AreEqual(0, ((IContainer)table).Count); + + table.Resize(6, 6); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(2, ((IContainer)table).Count); + Assert.AreEqual(new Point(0, 5), table.HorizontalScrollBar.Position); + Assert.AreEqual(5, table.HorizontalScrollBar.Width); + Assert.AreEqual(new Point(5, 0), table.VerticalScrollBar.Position); + Assert.AreEqual(5, table.VerticalScrollBar.Height); + Assert.IsFalse(table.HorizontalScrollBar.Bounds.Intersects(table.VerticalScrollBar.Bounds)); + } + + [TestMethod] + public void Table_ScrollBars_AutomaticallyCoupleVisibilityAcrossEffectiveViewport() + { + var verticalInducesHorizontal = new Table(6, 6); + var horizontalInducesVertical = new Table(6, 6); + + for (int column = 0; column < 6; column++) + verticalInducesHorizontal.Cells[0, column].Value = column.ToString(); + for (int row = 0; row < 7; row++) + verticalInducesHorizontal.Cells[row, 0].Value = row.ToString(); + + for (int column = 0; column < 7; column++) + horizontalInducesVertical.Cells[0, column].Value = column.ToString(); + for (int row = 0; row < 6; row++) + horizontalInducesVertical.Cells[row, 0].Value = row.ToString(); + + verticalInducesHorizontal.UpdateAndRedraw(System.TimeSpan.Zero); + horizontalInducesVertical.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(verticalInducesHorizontal.IsVerticalScrollBarVisible); + Assert.IsTrue(verticalInducesHorizontal.IsHorizontalScrollBarVisible); + Assert.AreEqual(1, verticalInducesHorizontal.HorizontalScrollBar.MaximumValue); + Assert.IsTrue(horizontalInducesVertical.IsHorizontalScrollBarVisible); + Assert.IsTrue(horizontalInducesVertical.IsVerticalScrollBarVisible); + Assert.AreEqual(1, horizontalInducesVertical.VerticalScrollBar.MaximumValue); + } + + [TestMethod] + public void Table_ScrollBars_ReconcileRangeAndOffsetsAcrossResize() + { + var table = new Table(4, 4); + + for (int index = 0; index < 7; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.HorizontalScrollBar.MaximumValue = 4; + table.VerticalScrollBar.MaximumValue = 4; + table.HorizontalScrollBar.Value = 4; + table.VerticalScrollBar.Value = 4; + + Assert.AreEqual(4, table.HorizontalScrollBar.Value); + Assert.AreEqual(4, table.VerticalScrollBar.Value); + Assert.AreNotEqual(0, table.StartRenderXPos); + Assert.AreNotEqual(0, table.StartRenderYPos); + + table.Resize(10, 10); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsFalse(table.IsHorizontalScrollBarVisible); + Assert.IsFalse(table.IsVerticalScrollBarVisible); + Assert.AreEqual(1, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(1, table.VerticalScrollBar.MaximumValue); + Assert.AreEqual(0, table.HorizontalScrollBar.Value); + Assert.AreEqual(0, table.VerticalScrollBar.Value); + Assert.AreEqual(0, table.StartRenderXPos); + Assert.AreEqual(0, table.StartRenderYPos); + + table.Resize(4, 4); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(4, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(4, table.VerticalScrollBar.MaximumValue); + Assert.AreEqual(0, table.HorizontalScrollBar.Value); + Assert.AreEqual(0, table.VerticalScrollBar.Value); + + table.HorizontalScrollBar.Value = 1; + table.VerticalScrollBar.Value = 1; + + Assert.AreEqual(1, table.StartRenderXPos); + Assert.AreEqual(1, table.StartRenderYPos); + } + [TestMethod] public void Table_SetupScrollBar_ReconfiguresAutomaticBarWithoutDuplicates() { From c80cadc3d4113713d9bfd6b4821dbcbd6cd0cfbe Mon Sep 17 00:00:00 2001 From: lyrae-versebound Date: Fri, 14 Aug 2026 01:29:43 -0400 Subject: [PATCH 4/5] Reconcile Table scrollbars after cell mutations --- .../UI/Controls/Table.TableCells.cs | 2 + Tests/SadConsole.Tests/UI/TableTests.cs | 91 +++++++++++++++++++ 2 files changed, 93 insertions(+) diff --git a/SadConsole.Extended/UI/Controls/Table.TableCells.cs b/SadConsole.Extended/UI/Controls/Table.TableCells.cs index 80fab81d..63aa3f2a 100644 --- a/SadConsole.Extended/UI/Controls/Table.TableCells.cs +++ b/SadConsole.Extended/UI/Controls/Table.TableCells.cs @@ -226,6 +226,7 @@ public void Clear(bool clearLayoutOptions = true) MaxRow = 0; MaxColumn = 0; _cells.Clear(); + _table._checkScrollBarVisibility = true; _table.IsDirty = true; } @@ -521,6 +522,7 @@ public void Remove() { Dictionary layoutDict = _layoutType == LayoutType.Row ? _table.Cells._rowLayout : _table.Cells._columnLayout; layoutDict.Remove(_index); + _table._checkScrollBarVisibility = true; _table.IsDirty = true; } diff --git a/Tests/SadConsole.Tests/UI/TableTests.cs b/Tests/SadConsole.Tests/UI/TableTests.cs index f1c52b5d..e4483135 100644 --- a/Tests/SadConsole.Tests/UI/TableTests.cs +++ b/Tests/SadConsole.Tests/UI/TableTests.cs @@ -463,6 +463,97 @@ public void Table_ScrollBars_ReconcileRangeAndOffsetsAcrossResize() Assert.AreEqual(1, table.StartRenderYPos); } + [TestMethod] + public void Table_ScrollBars_ReconcileRangeAndOffsetsAfterCellsClear() + { + var table = new Table(4, 4); + + for (int index = 0; index < 10; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + ScrollBar horizontalScrollBar = table.HorizontalScrollBar; + ScrollBar verticalScrollBar = table.VerticalScrollBar; + table.HorizontalScrollBar.Value = 4; + table.VerticalScrollBar.Value = 4; + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(4, table.HorizontalScrollBar.Value); + Assert.AreEqual(4, table.VerticalScrollBar.Value); + Assert.AreEqual(4, table.StartRenderXPos); + Assert.AreEqual(4, table.StartRenderYPos); + + table.Cells.Clear(); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsFalse(table.IsHorizontalScrollBarVisible); + Assert.IsFalse(table.IsVerticalScrollBarVisible); + Assert.AreSame(horizontalScrollBar, table.HorizontalScrollBar); + Assert.AreSame(verticalScrollBar, table.VerticalScrollBar); + Assert.AreEqual(2, ((IContainer)table).Count); + Assert.AreEqual(0, table.HorizontalScrollBar.Value); + Assert.AreEqual(0, table.VerticalScrollBar.Value); + Assert.AreEqual(0, table.StartRenderXPos); + Assert.AreEqual(0, table.StartRenderYPos); + + for (int index = 0; index < 10; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.HorizontalScrollBar.Value = 1; + table.VerticalScrollBar.Value = 1; + + Assert.AreEqual(1, table.StartRenderXPos); + Assert.AreEqual(1, table.StartRenderYPos); + Assert.AreEqual(2, ((IContainer)table).Count); + } + + [TestMethod] + public void Table_ScrollBars_ReconcileVisibilityAfterLayoutRemoval() + { + var table = new Table(4, 4); + + for (int index = 0; index < 4; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + Table.TableCells.Layout columnLayout = table.Cells.Column(3); + Table.TableCells.Layout rowLayout = table.Cells.Row(3); + columnLayout.SetLayout(4); + rowLayout.SetLayout(4); + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.HorizontalScrollBar.Value = 1; + table.VerticalScrollBar.Value = 1; + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreNotEqual(0, table.StartRenderXPos); + Assert.AreNotEqual(0, table.StartRenderYPos); + + columnLayout.Remove(); + rowLayout.Remove(); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsFalse(table.IsHorizontalScrollBarVisible); + Assert.IsFalse(table.IsVerticalScrollBarVisible); + Assert.AreEqual(0, table.HorizontalScrollBar.Value); + Assert.AreEqual(0, table.VerticalScrollBar.Value); + Assert.AreEqual(0, table.StartRenderXPos); + Assert.AreEqual(0, table.StartRenderYPos); + Assert.AreEqual(2, ((IContainer)table).Count); + } + [TestMethod] public void Table_SetupScrollBar_ReconfiguresAutomaticBarWithoutDuplicates() { From a4ddc022846d4849775872a1702092488e49700b Mon Sep 17 00:00:00 2001 From: lyrae-versebound Date: Fri, 14 Aug 2026 02:17:47 -0400 Subject: [PATCH 5/5] Reconcile Table scrollbars after geometry changes --- .../UI/Controls/Table.Theme.cs | 14 +--- SadConsole.Extended/UI/Controls/Table.cs | 16 +++- Tests/SadConsole.Tests/UI/TableTests.cs | 79 +++++++++++++++++++ 3 files changed, 97 insertions(+), 12 deletions(-) diff --git a/SadConsole.Extended/UI/Controls/Table.Theme.cs b/SadConsole.Extended/UI/Controls/Table.Theme.cs index 1777aed2..cc6fa13b 100644 --- a/SadConsole.Extended/UI/Controls/Table.Theme.cs +++ b/SadConsole.Extended/UI/Controls/Table.Theme.cs @@ -221,8 +221,6 @@ protected void SetScrollBarVisibility(int maxRowsHeight, int maxColumnsWidth) ScrollBar? horizontalScrollBar = HorizontalScrollBar; ScrollBar? verticalScrollBar = VerticalScrollBar; - bool horizontalWasVisible = IsHorizontalScrollBarVisible; - bool verticalWasVisible = IsVerticalScrollBarVisible; bool showHorizontal = horizontalScrollBar != null && GetScrollBarItems(Orientation.Horizontal, Width) > 0; bool showVertical = verticalScrollBar != null && GetScrollBarItems(Orientation.Vertical, Height) > 0; @@ -248,27 +246,21 @@ protected void SetScrollBarVisibility(int maxRowsHeight, int maxColumnsWidth) UpdateAutomaticScrollBarGeometry(); - bool stateChanged = horizontalWasVisible != IsHorizontalScrollBarVisible || - verticalWasVisible != IsVerticalScrollBarVisible || - horizontalScrollBar != HorizontalScrollBar || - verticalScrollBar != VerticalScrollBar; - if (HorizontalScrollBar != null) { int scrollItems = GetScrollBarItems(Orientation.Horizontal); - stateChanged |= ReconcileScrollBarState(HorizontalScrollBar, HorizontalScrollBar.IsVisible, scrollItems); + ReconcileScrollBarState(HorizontalScrollBar, HorizontalScrollBar.IsVisible, scrollItems); SetScrollBarPropertiesOnTable(HorizontalScrollBar, maxRowsHeight, maxColumnsWidth); } if (VerticalScrollBar != null) { int scrollItems = GetScrollBarItems(Orientation.Vertical); - stateChanged |= ReconcileScrollBarState(VerticalScrollBar, VerticalScrollBar.IsVisible, scrollItems); + ReconcileScrollBarState(VerticalScrollBar, VerticalScrollBar.IsVisible, scrollItems); SetScrollBarPropertiesOnTable(VerticalScrollBar, maxRowsHeight, maxColumnsWidth); } - if (stateChanged) - SynchronizeScrollOffsetsFromValues(); + SynchronizeScrollOffsetsFromValues(); _checkScrollBarVisibility = false; } diff --git a/SadConsole.Extended/UI/Controls/Table.cs b/SadConsole.Extended/UI/Controls/Table.cs index 06d195d3..1a2d7d25 100644 --- a/SadConsole.Extended/UI/Controls/Table.cs +++ b/SadConsole.Extended/UI/Controls/Table.cs @@ -30,7 +30,21 @@ public partial class Table : CompositeControl /// /// The default size a cell gets when it is newly created /// - public Point DefaultCellSize { get; set; } + public Point DefaultCellSize + { + get => _defaultCellSize; + set + { + if (_defaultCellSize == value) return; + + _defaultCellSize = value; + Cells.AdjustCellPositionsAfterResize(); + SyncScrollAmountOnResize(); + _checkScrollBarVisibility = true; + IsDirty = true; + } + } + private Point _defaultCellSize; /// /// The default visual hovering mode when hovering over cells diff --git a/Tests/SadConsole.Tests/UI/TableTests.cs b/Tests/SadConsole.Tests/UI/TableTests.cs index e4483135..21c05af8 100644 --- a/Tests/SadConsole.Tests/UI/TableTests.cs +++ b/Tests/SadConsole.Tests/UI/TableTests.cs @@ -554,6 +554,85 @@ public void Table_ScrollBars_ReconcileVisibilityAfterLayoutRemoval() Assert.AreEqual(2, ((IContainer)table).Count); } + [TestMethod] + public void Table_ScrollBars_ReconcileOffsetsAfterLateLayoutRemovalWithStableRange() + { + var table = new Table(6, 6); + + for (int column = 0; column < 15; column++) + table.Cells[0, column].Value = column.ToString(); + + Table.TableCells.Layout columnLayout = table.Cells.Column(10); + columnLayout.SetLayout(4); + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.HorizontalScrollBar.Value = table.HorizontalScrollBar.MaximumValue; + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.AreEqual(9, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(9, table.HorizontalScrollBar.Value); + Assert.AreEqual(12, table.StartRenderXPos); + + columnLayout.Remove(); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.AreEqual(9, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(9, table.HorizontalScrollBar.Value); + Assert.AreEqual(9, table.StartRenderXPos); + Assert.AreEqual(2, ((IContainer)table).Count); + + table.HorizontalScrollBar.Value = 8; + + Assert.AreEqual(8, table.StartRenderXPos); + } + + [TestMethod] + public void Table_ScrollBars_ReconcileAfterDefaultCellSizeShrink() + { + var table = new Table(4, 4, 4, 4); + + for (int index = 0; index < 4; index++) + { + table.Cells[0, index].Value = index.ToString(); + table.Cells[index, 0].Value = index.ToString(); + } + + table.UpdateAndRedraw(System.TimeSpan.Zero); + ScrollBar horizontalScrollBar = table.HorizontalScrollBar; + ScrollBar verticalScrollBar = table.VerticalScrollBar; + table.HorizontalScrollBar.Value = 1; + table.VerticalScrollBar.Value = 1; + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsTrue(table.IsHorizontalScrollBarVisible); + Assert.IsTrue(table.IsVerticalScrollBarVisible); + Assert.AreEqual(1, table.StartRenderXPos); + Assert.AreEqual(1, table.StartRenderYPos); + + table.DefaultCellSize = new Point(1, 1); + table.UpdateAndRedraw(System.TimeSpan.Zero); + + Assert.IsFalse(table.IsHorizontalScrollBarVisible); + Assert.IsFalse(table.IsVerticalScrollBarVisible); + Assert.AreSame(horizontalScrollBar, table.HorizontalScrollBar); + Assert.AreSame(verticalScrollBar, table.VerticalScrollBar); + Assert.AreEqual(1, table.HorizontalScrollBar.MaximumValue); + Assert.AreEqual(1, table.VerticalScrollBar.MaximumValue); + Assert.AreEqual(0, table.HorizontalScrollBar.Value); + Assert.AreEqual(0, table.VerticalScrollBar.Value); + Assert.AreEqual(0, table.StartRenderXPos); + Assert.AreEqual(0, table.StartRenderYPos); + Assert.AreEqual(2, ((IContainer)table).Count); + + table.DefaultCellSize = new Point(4, 4); + table.UpdateAndRedraw(System.TimeSpan.Zero); + table.HorizontalScrollBar.Value = 1; + table.VerticalScrollBar.Value = 1; + + Assert.AreEqual(1, table.StartRenderXPos); + Assert.AreEqual(1, table.StartRenderYPos); + } + [TestMethod] public void Table_SetupScrollBar_ReconfiguresAutomaticBarWithoutDuplicates() {