diff --git a/Terminal.Gui/View/Layout/ViewLayout.cs b/Terminal.Gui/View/Layout/ViewLayout.cs
index 4270a8d8f..1420367c0 100644
--- a/Terminal.Gui/View/Layout/ViewLayout.cs
+++ b/Terminal.Gui/View/Layout/ViewLayout.cs
@@ -649,6 +649,7 @@ public partial class View
start = nextStart;
x = startOffsetX;
y = startOffsetY;
+
break;
}
@@ -664,7 +665,7 @@ public partial class View
}
}
- return null;
+ return start;
}
#nullable restore
diff --git a/Terminal.Gui/View/ViewContent.cs b/Terminal.Gui/View/ViewContent.cs
index a65a54e86..dbd7f031a 100644
--- a/Terminal.Gui/View/ViewContent.cs
+++ b/Terminal.Gui/View/ViewContent.cs
@@ -3,10 +3,10 @@
namespace Terminal.Gui;
///
-/// Settings for how scrolling the on the View's Content Area is handled.
+/// Settings for how the behaves relative to the View's Content area.
///
[Flags]
-public enum ScrollSettings
+public enum ViewportSettings
{
///
/// No settings.
@@ -22,7 +22,7 @@ public enum ScrollSettings
/// When not set, is constrained to the bounds of the Content Area rectangle in the horizontal direction.
///
///
- AllowViewportOutsideContentHorizontal = 1,
+ AllowNegativeX = 1,
///
/// If set, can be set to a rectangle that does not perfectly intersect with the Content Area
@@ -33,7 +33,7 @@ public enum ScrollSettings
/// When not set, is constrained to the bounds of the Content Area rectangle in the vertical direction.
///
///
- AllowViewportOutsideContentVertical = 2,
+ AllowNegativeY = 2,
///
/// If set, can be set to a rectangle that does not perfectly intersect with the Content Area
@@ -44,7 +44,13 @@ public enum ScrollSettings
/// When not set, is constrained to the bounds of the Content Area rectangle.
///
///
- AllowViewportOutsideContent = AllowViewportOutsideContentHorizontal | AllowViewportOutsideContentVertical
+ AllowNegativeLocation = AllowNegativeX | AllowNegativeY,
+
+ AllowXGreaterThanContentWidth = 4,
+ AllowYGreaterThanContentHeight = 8,
+ AllowLocationCreaterThanContentSize = AllowXGreaterThanContentWidth | AllowYGreaterThanContentHeight,
+
+ ClearVisibleContentOnly = 16,
}
public partial class View
@@ -147,22 +153,22 @@ public partial class View
#region Viewport
- private ScrollSettings _scrollSettings;
+ private ViewportSettings _viewportSettings;
///
/// Gets or sets how scrolling the on the View's Content Area is handled.
///
- public ScrollSettings ScrollSettings
+ public ViewportSettings ViewportSettings
{
- get => _scrollSettings;
+ get => _viewportSettings;
set
{
- if (_scrollSettings == value)
+ if (_viewportSettings == value)
{
return;
}
- _scrollSettings = value;
+ _viewportSettings = value;
// Force set Viewport to cause settings to be applied as needed
SetViewport (Viewport);
@@ -195,7 +201,7 @@ public partial class View
/// . This enables virtual zoom.
///
///
- /// The property controls how scrolling is handled. If is
+ /// The property controls how scrolling is handled. If is
///
///
/// If is the value of Viewport is indeterminate until
@@ -274,33 +280,41 @@ public partial class View
};
- void ApplySettings (ref Rectangle location)
+ void ApplySettings (ref Rectangle newViewport)
{
- if (!ScrollSettings.HasFlag (ScrollSettings.AllowViewportOutsideContentHorizontal))
+ if (!ViewportSettings.HasFlag (ViewportSettings.AllowNegativeX))
{
- if (location.Y + Viewport.Height > ContentSize.Height)
- {
- location.Y = ContentSize.Height - Viewport.Height;
- }
- if (location.Y < 0)
+ if (newViewport.X < 0)
{
- location.Y = 0;
+ newViewport.X = 0;
}
}
- if (!ScrollSettings.HasFlag (ScrollSettings.AllowViewportOutsideContentVertical))
+ if (!ViewportSettings.HasFlag (ViewportSettings.AllowXGreaterThanContentWidth))
{
- if (location.X + Viewport.Width > ContentSize.Width)
+ if (newViewport.X >= ContentSize.Width)
{
- location.X = ContentSize.Width - Viewport.Width;
- }
-
- if (location.X < 0)
- {
- location.X = 0;
+ newViewport.X = ContentSize.Width - 1;
}
}
+
+ if (!ViewportSettings.HasFlag (ViewportSettings.AllowNegativeY))
+ {
+ if (newViewport.Y < 0)
+ {
+ newViewport.Y = 0;
+ }
+ }
+
+ if (!ViewportSettings.HasFlag (ViewportSettings.AllowYGreaterThanContentHeight))
+ {
+ if (newViewport.Y >= ContentSize.Height)
+ {
+ newViewport.Y = ContentSize.Height - 1;
+ }
+ }
+
}
}
diff --git a/Terminal.Gui/View/ViewDrawing.cs b/Terminal.Gui/View/ViewDrawing.cs
index 3ef5a5825..cb07b673f 100644
--- a/Terminal.Gui/View/ViewDrawing.cs
+++ b/Terminal.Gui/View/ViewDrawing.cs
@@ -99,13 +99,6 @@ public partial class View
Rectangle toClear = new (-Viewport.Location.X, -Viewport.Location.Y, ContentSize.Width, ContentSize.Height);
- // If toClear does not fill the Viewport, we need to clear the area outside toClear with DarkGray.
- // TODO: Need a configurable color for this
- // PERF: Put an if around this if toClear is not smaller than Viewport
- Attribute prev = Driver.SetAttribute (new Attribute (ColorName.DarkGray, ColorName.DarkGray));
- Rectangle viewport = new (Point.Empty, Viewport.Size);
- Driver.FillRect (ViewportToScreen (viewport));
- Driver.SetAttribute (prev);
Clear (toClear);
}
@@ -433,7 +426,14 @@ public partial class View
{
if (SuperView is { })
{
- ClearVisibleContent ();
+ if (ViewportSettings.HasFlag(ViewportSettings.ClearVisibleContentOnly))
+ {
+ ClearVisibleContent ();
+ }
+ else
+ {
+ Clear ();
+ }
}
if (!string.IsNullOrEmpty (TextFormatter.Text))
diff --git a/Terminal.Gui/Views/ListView.cs b/Terminal.Gui/Views/ListView.cs
index 9c8ff6f7f..507dcc852 100644
--- a/Terminal.Gui/Views/ListView.cs
+++ b/Terminal.Gui/Views/ListView.cs
@@ -1,4 +1,5 @@
using System.Collections;
+using static Terminal.Gui.SpinnerStyle;
namespace Terminal.Gui;
@@ -106,13 +107,12 @@ public class ListView : View
public ListView ()
{
CanFocus = true;
- ScrollSettings = ScrollSettings.AllowViewportOutsideContent;
// Things this view knows how to do
AddCommand (Command.LineUp, () => MoveUp ());
AddCommand (Command.LineDown, () => MoveDown ());
- AddCommand (Command.ScrollUp, () => ScrollUp (1));
- AddCommand (Command.ScrollDown, () => ScrollDown (1));
+ AddCommand (Command.ScrollUp, () => ScrollVertical (-1));
+ AddCommand (Command.ScrollDown, () => ScrollVertical (1));
AddCommand (Command.PageUp, () => MovePageUp ());
AddCommand (Command.PageDown, () => MovePageDown ());
AddCommand (Command.TopHome, () => MoveHome ());
@@ -121,6 +121,9 @@ public class ListView : View
AddCommand (Command.OpenSelectedItem, () => OnOpenSelectedItem ());
AddCommand (Command.Select, () => MarkUnmarkRow ());
+ AddCommand (Command.ScrollLeft, () => ScrollHorizontal (-1));
+ AddCommand (Command.ScrollRight, () => ScrollHorizontal (1));
+
// Default keybindings for all ListViews
KeyBindings.Add (Key.CursorUp, Command.LineUp);
KeyBindings.Add (Key.P.WithCtrl, Command.LineUp);
@@ -261,7 +264,7 @@ public class ListView : View
}
_source = value;
- ContentSize = new Size (Viewport.Width, _source?.Count ?? 0);
+ ContentSize = new Size (_source?.Length ?? Viewport.Width, _source?.Count ?? Viewport.Width);
Viewport = Viewport with { Y = 0 };
KeystrokeNavigator.Collection = _source?.ToList ();
_selected = -1;
@@ -383,28 +386,28 @@ public class ListView : View
if (me.Flags == MouseFlags.WheeledDown)
{
- ScrollDown (1);
+ ScrollVertical (1);
return true;
}
if (me.Flags == MouseFlags.WheeledUp)
{
- ScrollUp (1);
+ ScrollVertical (-1);
return true;
}
if (me.Flags == MouseFlags.WheeledRight)
{
- ScrollRight (1);
+ ScrollHorizontal (1);
return true;
}
if (me.Flags == MouseFlags.WheeledLeft)
{
- ScrollLeft (1);
+ ScrollHorizontal(-1);
return true;
}
@@ -792,46 +795,6 @@ public class ListView : View
/// This event is invoked when this is being drawn before rendering.
public event EventHandler RowRender;
- /// Scrolls the view down by items.
- /// Number of items to scroll down.
- public virtual bool ScrollDown (int items)
- {
- Viewport = Viewport with { Y = Math.Max (Math.Min (Viewport.Y + items, _source.Count - 1), 0) };
- SetNeedsDisplay ();
-
- return true;
- }
-
- /// Scrolls the view left.
- /// Number of columns to scroll left.
- public virtual bool ScrollLeft (int cols)
- {
- Viewport = Viewport with { X = Math.Max (Viewport.X - cols, 0) };
- SetNeedsDisplay ();
-
- return true;
- }
-
- /// Scrolls the view right.
- /// Number of columns to scroll right.
- public virtual bool ScrollRight (int cols)
- {
- Viewport = Viewport with { X = Math.Max (Math.Min (Viewport.X + cols, MaxLength - 1), 0) };
- SetNeedsDisplay ();
-
- return true;
- }
-
- /// Scrolls the view up by items.
- /// Number of items to scroll up.
- public virtual bool ScrollUp (int items)
- {
- Viewport = Viewport with { Y = Math.Max (Viewport.Y - items, 0) };
- SetNeedsDisplay ();
-
- return true;
- }
-
/// This event is raised when the selected item in the has changed.
public event EventHandler SelectedItemChanged;
@@ -1040,8 +1003,8 @@ public class ListWrapper : IListDataSource
private void RenderUstr (ConsoleDriver driver, string ustr, int col, int line, int width, int start = 0)
{
- string u = TextFormatter.ClipAndJustify (ustr, width, TextAlignment.Left);
- driver.AddStr (u);
+ string str = start > ustr.GetColumns () ? string.Empty : ustr.Substring (start);
+ string u = TextFormatter.ClipAndJustify (str, width, TextAlignment.Left); driver.AddStr (u);
width -= u.GetColumns ();
while (width-- > 0)
diff --git a/UICatalog/Scenarios/VirtualContentScrolling.cs b/UICatalog/Scenarios/VirtualContentScrolling.cs
index 35918506b..81aaecd59 100644
--- a/UICatalog/Scenarios/VirtualContentScrolling.cs
+++ b/UICatalog/Scenarios/VirtualContentScrolling.cs
@@ -25,7 +25,7 @@ public class VirtualScrolling : Scenario
// TODO: Add a way to set the scroll settings in the Scenario
ContentSize = new Size (60, 40);
- ScrollSettings = ScrollSettings.AllowViewportOutsideContent;
+ ViewportSettings |= ViewportSettings.ClearVisibleContentOnly;
// Things this view knows how to do
AddCommand (Command.ScrollDown, () => ScrollVertical (1));
@@ -104,60 +104,107 @@ public class VirtualScrolling : Scenario
var view = new VirtualDemoView { Title = "Virtual Scrolling" };
// Add Scroll Setting UI to Padding
- view.Padding.Thickness = new (0, 2, 0, 0);
+ view.Padding.Thickness = new (0, 3, 0, 0);
view.Padding.ColorScheme = Colors.ColorSchemes["Error"];
- var cbAllowXBeyondContent = new CheckBox ()
+ var cbAllowNegativeX = new CheckBox ()
{
- Title = "Allow Viewport._X Beyond Content",
+ Title = "Allow _X < 0",
Y = 0,
CanFocus = false
};
- cbAllowXBeyondContent.Checked = view.ScrollSettings.HasFlag (ScrollSettings.AllowViewportOutsideContentVertical);
- cbAllowXBeyondContent.Toggled += NoRestrictHorizontal_Toggled;
+ cbAllowNegativeX.Checked = view.ViewportSettings.HasFlag (ViewportSettings.AllowNegativeX);
+ cbAllowNegativeX.Toggled += AllowNegativeX_Toggled;
- void NoRestrictHorizontal_Toggled (object sender, StateEventArgs e)
+ void AllowNegativeX_Toggled (object sender, StateEventArgs e)
{
if (e.NewValue == true)
{
- view.ScrollSettings = view.ScrollSettings | ScrollSettings.AllowViewportOutsideContentVertical;
+ view.ViewportSettings |= ViewportSettings.AllowNegativeX;
}
else
{
- view.ScrollSettings = view.ScrollSettings & ~ScrollSettings.AllowViewportOutsideContentVertical;
+ view.ViewportSettings &= ~ViewportSettings.AllowNegativeX;
}
}
- view.Padding.Add (cbAllowXBeyondContent);
+ view.Padding.Add (cbAllowNegativeX);
- var cbAllowYBeyondContent = new CheckBox ()
+ var cbAllowNegativeY = new CheckBox ()
{
- Title = "Allow Viewport._Y Beyond Content",
- X = Pos.Right (cbAllowXBeyondContent) + 1,
+ Title = "Allow _Y < 0",
+ X = Pos.Right (cbAllowNegativeX) + 1,
Y = 0,
CanFocus = false
};
- cbAllowYBeyondContent.Checked = view.ScrollSettings.HasFlag (ScrollSettings.AllowViewportOutsideContentHorizontal);
- cbAllowYBeyondContent.Toggled += NoRestrictVertical_Toggled;
+ cbAllowNegativeY.Checked = view.ViewportSettings.HasFlag (ViewportSettings.AllowNegativeY);
+ cbAllowNegativeY.Toggled += AllowNegativeY_Toggled;
- void NoRestrictVertical_Toggled (object sender, StateEventArgs e)
+ void AllowNegativeY_Toggled (object sender, StateEventArgs e)
{
if (e.NewValue == true)
{
- view.ScrollSettings = view.ScrollSettings | ScrollSettings.AllowViewportOutsideContentHorizontal;
+ view.ViewportSettings |= ViewportSettings.AllowNegativeY;
}
else
{
- view.ScrollSettings = view.ScrollSettings & ~ScrollSettings.AllowViewportOutsideContentHorizontal;
+ view.ViewportSettings &= ~ViewportSettings.AllowNegativeY;
}
}
- view.Padding.Add (cbAllowYBeyondContent);
+ view.Padding.Add (cbAllowNegativeY);
+
+ var cbAllowXGreaterThanContentWidth = new CheckBox ()
+ {
+ Title = "Allow X > Content",
+ Y = Pos.Bottom(cbAllowNegativeX),
+ CanFocus = false
+ };
+ cbAllowXGreaterThanContentWidth.Checked = view.ViewportSettings.HasFlag (ViewportSettings.AllowXGreaterThanContentWidth);
+ cbAllowXGreaterThanContentWidth.Toggled += AllowXGreaterThanContentWidth_Toggled;
+
+ void AllowXGreaterThanContentWidth_Toggled (object sender, StateEventArgs e)
+ {
+ if (e.NewValue == true)
+ {
+ view.ViewportSettings |= ViewportSettings.AllowXGreaterThanContentWidth;
+ }
+ else
+ {
+ view.ViewportSettings &= ~ViewportSettings.AllowXGreaterThanContentWidth;
+ }
+ }
+
+ view.Padding.Add (cbAllowXGreaterThanContentWidth);
+
+ var cbAllowYGreaterThanContentHeight = new CheckBox ()
+ {
+ Title = "Allow Y > Content",
+ X = Pos.Right (cbAllowXGreaterThanContentWidth) + 1,
+ Y = Pos.Bottom (cbAllowNegativeX),
+ CanFocus = false
+ };
+ cbAllowYGreaterThanContentHeight.Checked = view.ViewportSettings.HasFlag (ViewportSettings.AllowYGreaterThanContentHeight);
+ cbAllowYGreaterThanContentHeight.Toggled += AllowYGreaterThanContentHeight_Toggled;
+
+ void AllowYGreaterThanContentHeight_Toggled (object sender, StateEventArgs e)
+ {
+ if (e.NewValue == true)
+ {
+ view.ViewportSettings |= ViewportSettings.AllowYGreaterThanContentHeight;
+ }
+ else
+ {
+ view.ViewportSettings &= ~ViewportSettings.AllowYGreaterThanContentHeight;
+ }
+ }
+
+ view.Padding.Add (cbAllowYGreaterThanContentHeight);
var labelContentSize = new Label ()
{
Title = "_ContentSize:",
- Y = 1,
+ Y = Pos.Bottom(cbAllowYGreaterThanContentHeight),
};
var contentSizeWidth = new Buttons.NumericUpDown()
diff --git a/UnitTests/View/Layout/ToScreenTests.cs b/UnitTests/View/Layout/ToScreenTests.cs
index e2152c476..7eddeb1e4 100644
--- a/UnitTests/View/Layout/ToScreenTests.cs
+++ b/UnitTests/View/Layout/ToScreenTests.cs
@@ -630,7 +630,7 @@ public class ToScreenTests (ITestOutputHelper output)
{
Width = 10,
Height = 10,
- ScrollSettings = ScrollSettings.AllowViewportOutsideContent
+ ViewportSettings = ViewportSettings.AllowNegativeLocation
};
Rectangle testRect = new Rectangle (0, 0, 1, 1);
diff --git a/UnitTests/View/Layout/ViewportTests.cs b/UnitTests/View/Layout/ViewportTests.cs
index 12d930290..5c0e0e603 100644
--- a/UnitTests/View/Layout/ViewportTests.cs
+++ b/UnitTests/View/Layout/ViewportTests.cs
@@ -161,7 +161,7 @@ public class ViewportTests (ITestOutputHelper output)
{
Width = 10,
Height = 10,
- ScrollSettings = ScrollSettings.AllowViewportOutsideContent
+ ViewportSettings = ViewportSettings.AllowNegativeLocation
};
Assert.Equal (new Rectangle (0, 0, 10, 10), view.Frame);
diff --git a/UnitTests/Views/ListViewTests.cs b/UnitTests/Views/ListViewTests.cs
index 252efc537..611cc719f 100644
--- a/UnitTests/Views/ListViewTests.cs
+++ b/UnitTests/Views/ListViewTests.cs
@@ -78,7 +78,7 @@ public class ListViewTests
_output
);
- Assert.True (lv.ScrollDown (10));
+ Assert.True (lv.ScrollVertical(10));
lv.Draw ();
Assert.Equal (-1, lv.SelectedItem);
@@ -141,7 +141,7 @@ public class ListViewTests
_output
);
- Assert.True (lv.ScrollUp (20));
+ Assert.True (lv.ScrollVertical (-20));
lv.Draw ();
Assert.Equal (19, lv.SelectedItem);
@@ -183,7 +183,7 @@ public class ListViewTests
_output
);
- Assert.True (lv.ScrollUp (20));
+ Assert.True (lv.ScrollVertical (-20));
lv.Draw ();
Assert.Equal (19, lv.SelectedItem);
@@ -246,7 +246,7 @@ public class ListViewTests
_output
);
- Assert.True (lv.ScrollDown (20));
+ Assert.True (lv.ScrollVertical (20));
lv.Draw ();
Assert.Equal (0, lv.SelectedItem);
@@ -671,7 +671,7 @@ Item 6",
private class NewListDataSource : IListDataSource
{
public int Count => 0;
- public int Length => throw new NotImplementedException ();
+ public int Length => 0;
public bool IsMarked (int item) { throw new NotImplementedException (); }
public void Render (