Files
Terminal.Gui/Examples/UICatalog/Scenarios/ScrollBarDemo.cs
Tig 3e2eebfd2c Fixes #4057 - MASSIVE! Fully implements ColorScheme->Scheme + VisualRole + Colors.->SchemeManager. (#4062)
* touching publish.yml

* ColorScheme->Scheme

* ColorScheme->Scheme 2

* Prototype of GetAttributeForRole

* Badly broke CM

* Further Badly broke CM

* Refactored CM big-time. View still broken

* All unit test pass again. Tons added. CM is still WIP, but Schemes is not mostly refactored and working.

* Actually:
All unit test pass again.
Tons added.
CM is still WIP, but Schemes is not mostly refactored and working.

* Bug fixes.
DeepMemberWiseClone cleanup

* Further cleanup of Scope<T>, ConfigProperty, etc.

* Made ConfigManager thread safe.

* WIP: Broken

* WIP: new deep clone impl

* WIP: new deep clone impl is done. Now fixing CM

* WIP:
- config.md
- Working on AOT clean up
- Core CM is broken; but known.

* WIP

* Merged.
Removed CM from Application.Init

* WIP

* More WIP; Less broke

* All CM unit tests pass... Not sure if it actually works though

* All unit tests pass... Themes are broken though in UI Cat

* CM Ready for review?

* Fixed failures due to TextStyles PR

* Working on Scheme/Attribute

* Working on Scheme/Attribute 2

* Working on Scheme/Attribute 3

* Working on Scheme/Attribute 4

* Working on Scheme/Attribute 5

* Working on Scheme/Attribute 6

* Added test to show how awful memory usage is

* Improved schema. Updated config.json

* Nade Scope<T> concurrentdictionary and added test to prove

* Made Themes ConcrurrentDictionary. Added bunches of tests

* Code cleanup

* Code cleanup 2

* Code cleanup 3

* Tweaking Scheme

* ClearJsonErrors

* ClearJsonErrors2

* Updated Attribute API

* It all (mostly) works!

* Skip odd unit test

* Messed with Themes

* Theme tweaks

* Code reorg. New .md stuff

* Fixed Enabled. Added mock driver

* Fixed a bunch of View.Enabled related issues

* Scheme -> Get/SetScheme()

* Cleanup

* Cleanup2

* Broke something

* Fixed everything

* Made CM.Enable better

* Text Style Scenario

* Added comments

* Fixed UI Catalog Theme Changing

* Fixed more dynamic CM update stuff

* Warning cleanup

* New Default Theme

* fixed unit test

* Refactoring Scheme and Attribute to fix inheritance

* more unit tests

* ConfigProperty is not updating schemes correctly

* All unit tests pass.
Code cleanup

* All unit tests pass.
Code cleanup2

* Fixed unit tests

* Upgraded TextField and TextView

* Fixed TextView !Enabled bug

* More updates to TextView. More unit tests for SchemeManager

* Upgraded CharMap

* API docs

* Fixe HexView API

* upgrade HexView

* Fixed shortcut KeyView

* Fixed more bugs. Added new themes

* updated themes

* upgraded Border

* Fixed themes memory usage...mostly

* Fixed themes memory usage...mostly2

* Fixed themes memory usage...2

* Fixed themes memory usage...3

* Added new colors

* Fixed GetHardCodedConfig bug

* Added Themes Scenario - WIP

* Added Themes Scenario

* Tweaked Themes Scenario

* Code cleanup

* Fixed json schmea

* updated deepdives

* updated deepdives

* Tweaked Themes Scenario

* Made Schemes a concurrent dict

* Test cleanup

* Thread safe ConfigProperty tests

* trying to make things more thread safe

* more trying to make things more thread safe

* Fixing bugs in shadowview

* Fixing bugs in shadowview 2

* Refactored GetViewsUnderMouse to GetViewsUnderLocation etc...

* Fixed dupe unit tests?

* Added better description of layout and coordiantes to deep dive

* Added better description of layout and coordiantes to deep dive

* Modified tests that call v2.AddTimeout; they were returning true which means restart the timer!
This was causing mac/linux unit test failures.
I think

* Fixed auto scheme.
Broke TextView/TextField selection

* Realized Attribute.IsExplicitlySet is stupid; just use nullable

* Fixed Attribute. Simplified. MOre theme testing

* Updated themes again

* GetViewsUnderMouse to GetViewsUnderLocation broke TransparentMouse.

* Fixing mouseunder bugs

* rewriting...

* All working again.
Shadows are now slick as snot.
GetViewsUnderLocation is rewritten to actually work and be readable.
Tons more low-level unit tests.
Margin is now actually ViewportSettings.Transparent.

* Code cleanup

* Code cleanup

* Code cleanup of color apis

* Fixed Hover/Highlight

* Update Examples/UICatalog/Scenarios/AllViewsTester.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Update Examples/UICatalog/Scenarios/Clipping.cs

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>

* Fixed race condition?

* reverted

* Simplified Attribute API by removing events from SetAttributeForRole

* Removed recursion from GetViewsAtLocation

* Removed unneeded code

* Code clean up.
Fixed Scheme bug.

* reverted temporary disable

* Adjusted scheme algo

* Upgraded TextValidateField

* Fixed TextValidate bugs

* Tweaks

* Frameview rounded border by default

* API doc cleanup

* Readme fix

* Addressed tznind feeback

* Fixed more unit test issues by protecting Application statics from being set if Application.Initialized is not true

* Fixed more unit test issues by protecting Application statics from being set if Application.Initialized is not true 2

* cleanup

---------

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
2025-05-29 14:08:48 -06:00

399 lines
16 KiB
C#

using System;
using System.Collections.ObjectModel;
using System.Linq;
using Terminal.Gui;
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.NewValue == 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.CurrentValue}");
if (scrollContentSize.Value != e.CurrentValue)
{
scrollContentSize.Value = e.CurrentValue;
}
};
scrollBar.SliderPositionChanged += (s, e) =>
{
eventLog.Log ($"SliderPositionChanged: {e.CurrentValue}");
eventLog.Log ($" Position: {scrollBar.Position}");
scrollSliderPosition.Text = e.CurrentValue.ToString ();
};
scrollBar.Scrolled += (s, e) =>
{
eventLog.Log ($"Scrolled: {e.CurrentValue}");
eventLog.Log ($" SliderPosition: {scrollBar.GetSliderPosition ()}");
scrolled.Text = e.CurrentValue.ToString ();
};
scrollBar.PositionChanged += (s, e) =>
{
eventLog.Log ($"PositionChanged: {e.CurrentValue}");
scrollPosition.Value = e.CurrentValue;
controlledList.Viewport = controlledList.Viewport with { Y = e.CurrentValue };
};
controlledList.ViewportChanged += (s, e) =>
{
eventLog.Log ($"ViewportChanged: {e.NewViewport}");
scrollBar.Position = e.NewViewport.Y;
};
}
Application.Run (app);
app.Dispose ();
Application.Shutdown ();
}
}