Files
Terminal.Gui/Examples/UICatalog/Scenarios/ScrollBarDemo.cs
BDisp 00aaefb962 Fixes #3951. Adds View dependency to DimFunc and PosFunc (#4210)
* Fixes #4208. MainLoopSyncContext doesn't work with the v2 drivers

* Fixes #3951. Add DimFuncWithView with a View dependency

* Revert to iteration which will handle the necessary processes

* Revert "Revert to iteration which will handle the necessary processes"

This reverts commit 50015ac6da.

* Layout and draw before position cursor

* Add optional View parameter and property to the DimFunc and PosFunc

* Trying fix unit test error

* Revert layout changes

* Fixes #4216. Legacy drivers aren't refreshing the screen correctly on view drag

* Add assertion proving NeedsLayout is always false before call OnSubViewsLaidOut

* Fix unit test error

* Increasing time to abort

* Revert "Increasing time to abort"

This reverts commit d7306e72f3.

* Trying fix integration tests

* Still trying fix integrations unit tests

* Revert comment

* Layout is performed during the iteration

* Using Dim.Func with status bar view

* Still trying fix integrations tests by locking _subviews

* Still trying fix integrations tests by locking _subviews

* Add internal SnapshotSubviews method

* Remove lock from SnapshotSubviews method

* Using SnapshotSubviews method in the DrawSubViews method

* Remove lock from SnapshotSubviews method

* Using SnapshotSubviews method in the DrawSubViews method

* Using SnapshotSubviews

* Prevent new app if the previous wasn't yet finished

* Replace SnapshotSubviews method with ViewCollectionHelpers class

* Lock entire GuiTestContext constructor

* Using Snapshot in the ordered field

* Fixes #4221 Extra modifiers f1 to f4 in v2net (#4220)

* Assume we are running in a terminal that supports true color by default unless user explicitly forces 16

* Add support for extra modifiers for F1 to F4 keys

* Revert "Assume we are running in a terminal that supports true color by default unless user explicitly forces 16"

This reverts commit 4cc2530de0.

* Cleanup

* Update comments

* Code cleanup

---------

Co-authored-by: Tig <tig@users.noreply.github.com>

* Move ViewCollectionHelpers class to a separate file

* Remove Border.Layout call in the DoDrawAdornmentsSubViews method.

* Remove adornments layout call within the draw

---------

Co-authored-by: Tig <tig@users.noreply.github.com>
Co-authored-by: Thomas Nind <31306100+tznind@users.noreply.github.com>
2025-09-01 10:40:10 -06:00

398 lines
16 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Linq;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("ScrollBar Demo", "Demonstrates ScrollBar.")]
[ScenarioCategory ("Scrolling")]
public class ScrollBarDemo : Scenario
{
public override void Main ()
{
Application.Init ();
Window app = new ()
{
Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()}",
Arrangement = ViewArrangement.Fixed
};
var demoFrame = new FrameView ()
{
Title = "Demo View",
X = 0,
Width = 75,
Height = 25 + 4,
SchemeName = "Base",
Arrangement = ViewArrangement.Resizable
};
demoFrame!.Padding!.Thickness = new (1);
demoFrame.Padding.Diagnostics = ViewDiagnosticFlags.Ruler;
app.Add (demoFrame);
var scrollBar = new ScrollBar
{
X = Pos.AnchorEnd () - 5,
AutoShow = false,
ScrollableContentSize = 100,
Height = Dim.Fill()
};
demoFrame.Add (scrollBar);
ListView controlledList = new ()
{
X = Pos.AnchorEnd (),
Width = 5,
Height = Dim.Fill (),
SchemeName = "Error",
};
demoFrame.Add (controlledList);
// populate the list box with Size items of the form "{n:00000}"
controlledList.SetSource (new ObservableCollection<string> (Enumerable.Range (0, scrollBar.ScrollableContentSize).Select (n => $"{n:00000}")));
int GetMaxLabelWidth (int groupId)
{
return demoFrame.SubViews.Max (
v =>
{
if (v.Y.Has<PosAlign> (out var pos) && pos.GroupId == groupId)
{
return v.Text.GetColumns ();
}
return 0;
});
}
var lblWidthHeight = new Label
{
Text = "_Width/Height:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, AlignmentModes.StartToEnd, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblWidthHeight);
NumericUpDown<int> scrollWidthHeight = new ()
{
Value = 1,
X = Pos.Right (lblWidthHeight) + 1,
Y = Pos.Top (lblWidthHeight),
};
demoFrame.Add (scrollWidthHeight);
scrollWidthHeight.ValueChanging += (s, e) =>
{
if (e.NewValue < 1
|| (e.NewValue
> (scrollBar.Orientation == Orientation.Vertical
? scrollBar.SuperView?.GetContentSize ().Width
: scrollBar.SuperView?.GetContentSize ().Height)))
{
// TODO: This must be handled in the ScrollSlider if Width and Height being virtual
e.Cancel = true;
return;
}
if (scrollBar.Orientation == Orientation.Vertical)
{
scrollBar.Width = e.NewValue;
}
else
{
scrollBar.Height = e.NewValue;
}
};
var lblOrientationLabel = new Label
{
Text = "_Orientation:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblOrientationLabel);
var rgOrientation = new RadioGroup
{
X = Pos.Right (lblOrientationLabel) + 1,
Y = Pos.Top (lblOrientationLabel),
RadioLabels = ["Vertical", "Horizontal"],
Orientation = Orientation.Horizontal
};
demoFrame.Add (rgOrientation);
rgOrientation.SelectedItemChanged += (s, e) =>
{
if (e.SelectedItem == e.PreviousSelectedItem)
{
return;
}
if (rgOrientation.SelectedItem == 0)
{
scrollBar.Orientation = Orientation.Vertical;
scrollBar.X = Pos.AnchorEnd () - 5;
scrollBar.Y = 0;
scrollBar.Width = scrollWidthHeight.Value;
scrollBar.Height = Dim.Fill ();
controlledList.Visible = true;
}
else
{
scrollBar.Orientation = Orientation.Horizontal;
scrollBar.X = 0;
scrollBar.Y = Pos.AnchorEnd ();
scrollBar.Height = scrollWidthHeight.Value;
scrollBar.Width = Dim.Fill ();
controlledList.Visible = false;
}
};
var lblSize = new Label
{
Text = "Scrollable_ContentSize:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblSize);
NumericUpDown<int> scrollContentSize = new ()
{
Value = scrollBar.ScrollableContentSize,
X = Pos.Right (lblSize) + 1,
Y = Pos.Top (lblSize)
};
demoFrame.Add (scrollContentSize);
scrollContentSize.ValueChanging += (s, e) =>
{
if (e.NewValue < 0)
{
e.Cancel = true;
return;
}
if (scrollBar.ScrollableContentSize != e.NewValue)
{
scrollBar.ScrollableContentSize = e.NewValue;
controlledList.SetSource (new ObservableCollection<string> (Enumerable.Range (0, scrollBar.ScrollableContentSize).Select (n => $"{n:00000}")));
}
};
var lblVisibleContentSize = new Label
{
Text = "_VisibleContentSize:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblVisibleContentSize);
NumericUpDown<int> visibleContentSize = new ()
{
Value = scrollBar.VisibleContentSize,
X = Pos.Right (lblVisibleContentSize) + 1,
Y = Pos.Top (lblVisibleContentSize)
};
demoFrame.Add (visibleContentSize);
visibleContentSize.ValueChanging += (s, e) =>
{
if (e.NewValue < 0)
{
e.Cancel = true;
return;
}
if (scrollBar.VisibleContentSize != e.NewValue)
{
scrollBar.VisibleContentSize = e.NewValue;
}
};
var lblPosition = new Label
{
Text = "_Position:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblPosition);
NumericUpDown<int> scrollPosition = new ()
{
Value = scrollBar.GetSliderPosition (),
X = Pos.Right (lblPosition) + 1,
Y = Pos.Top (lblPosition)
};
demoFrame.Add (scrollPosition);
scrollPosition.ValueChanging += (s, e) =>
{
if (e.NewValue < 0)
{
e.Cancel = true;
return;
}
if (scrollBar.Position != e.NewValue)
{
scrollBar.Position = e.NewValue;
}
if (scrollBar.Position != e.NewValue)
{
e.Cancel = true;
}
};
var lblOptions = new Label
{
Text = "Options:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblOptions);
var autoShow = new CheckBox
{
Y = Pos.Top (lblOptions),
X = Pos.Right (lblOptions) + 1,
Text = $"_AutoShow",
CheckedState = scrollBar.AutoShow ? CheckState.Checked : CheckState.UnChecked
};
autoShow.CheckedStateChanging += (s, e) => scrollBar.AutoShow = e.Result == CheckState.Checked;
demoFrame.Add (autoShow);
var lblSliderPosition = new Label
{
Text = "SliderPosition:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblSliderPosition);
Label scrollSliderPosition = new ()
{
Text = scrollBar.GetSliderPosition ().ToString (),
X = Pos.Right (lblSliderPosition) + 1,
Y = Pos.Top (lblSliderPosition)
};
demoFrame.Add (scrollSliderPosition);
var lblScrolled = new Label
{
Text = "Scrolled:",
TextAlignment = Alignment.End,
Y = Pos.Align (Alignment.Start, groupId: 1),
Width = Dim.Func (_ => GetMaxLabelWidth (1))
};
demoFrame.Add (lblScrolled);
Label scrolled = new ()
{
X = Pos.Right (lblScrolled) + 1,
Y = Pos.Top (lblScrolled)
};
demoFrame.Add (scrolled);
var lblScrollFrame = new Label
{
Y = Pos.Bottom (lblScrolled) + 1
};
demoFrame.Add (lblScrollFrame);
var lblScrollViewport = new Label
{
Y = Pos.Bottom (lblScrollFrame)
};
demoFrame.Add (lblScrollViewport);
var lblScrollContentSize = new Label
{
Y = Pos.Bottom (lblScrollViewport)
};
demoFrame.Add (lblScrollContentSize);
scrollBar.SubViewsLaidOut += (s, e) =>
{
lblScrollFrame.Text = $"Scroll Frame: {scrollBar.Frame.ToString ()}";
lblScrollViewport.Text = $"Scroll Viewport: {scrollBar.Viewport.ToString ()}";
lblScrollContentSize.Text = $"Scroll ContentSize: {scrollBar.GetContentSize ().ToString ()}";
visibleContentSize.Value = scrollBar.VisibleContentSize;
};
EventLog eventLog = new ()
{
X = Pos.AnchorEnd (),
Y = 0,
Height = Dim.Fill (),
BorderStyle = LineStyle.Single,
ViewToLog = scrollBar
};
app.Add (eventLog);
app.Initialized += AppOnInitialized;
void AppOnInitialized (object sender, EventArgs e)
{
scrollBar.ScrollableContentSizeChanged += (s, e) =>
{
eventLog.Log ($"SizeChanged: {e.Value}");
if (scrollContentSize.Value != e.Value)
{
scrollContentSize.Value = e.Value;
}
};
scrollBar.SliderPositionChanged += (s, e) =>
{
eventLog.Log ($"SliderPositionChanged: {e.Value}");
eventLog.Log ($" Position: {scrollBar.Position}");
scrollSliderPosition.Text = e.Value.ToString ();
};
scrollBar.Scrolled += (s, e) =>
{
eventLog.Log ($"Scrolled: {e.Value}");
eventLog.Log ($" SliderPosition: {scrollBar.GetSliderPosition ()}");
scrolled.Text = e.Value.ToString ();
};
scrollBar.PositionChanged += (s, e) =>
{
eventLog.Log ($"PositionChanged: {e.Value}");
scrollPosition.Value = e.Value;
controlledList.Viewport = controlledList.Viewport with { Y = e.Value };
};
controlledList.ViewportChanged += (s, e) =>
{
eventLog.Log ($"ViewportChanged: {e.NewViewport}");
scrollBar.Position = e.NewViewport.Y;
};
}
Application.Run (app);
app.Dispose ();
Application.Shutdown ();
}
}