Merge branch 'v2_develop' of tig:gui-cs/Terminal.Gui into v2_develop

This commit is contained in:
Tig Kindel
2023-10-17 13:23:43 -04:00
12 changed files with 2489 additions and 16 deletions

View File

@@ -627,7 +627,7 @@ internal class CursesDriver : ConsoleDriver {
return true;
});
_mainLoop.WinChanged += ProcessInput;
_mainLoop.WinChanged = ProcessInput;
}
public override void Init (Action terminalResized)

View File

@@ -353,7 +353,7 @@ public class FakeDriver : ConsoleDriver {
_keyUpHandler = keyUpHandler;
// Note: Net doesn't support keydown/up events and thus any passed keyDown/UpHandlers will never be called
(mainLoop.MainLoopDriver as FakeMainLoop).KeyPressed += (consoleKey) => ProcessInput (consoleKey);
(mainLoop.MainLoopDriver as FakeMainLoop).KeyPressed = (consoleKey) => ProcessInput (consoleKey);
}
void ProcessInput (ConsoleKeyInfo consoleKey)

View File

@@ -136,7 +136,7 @@ internal class NetEvents : IDisposable {
public InputResult? DequeueInput ()
{
while (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested) {
while (_inputReadyCancellationTokenSource != null && !_inputReadyCancellationTokenSource.Token.IsCancellationRequested) {
_waitForStart.Set ();
_winChange.Set ();
@@ -185,7 +185,12 @@ internal class NetEvents : IDisposable {
{
while (!_inputReadyCancellationTokenSource.Token.IsCancellationRequested) {
_waitForStart.Wait (_inputReadyCancellationTokenSource.Token);
try {
_waitForStart.Wait (_inputReadyCancellationTokenSource.Token);
} catch (OperationCanceledException) {
return;
}
_waitForStart.Reset ();
if (_inputQueue.Count == 0) {
@@ -1339,9 +1344,14 @@ internal class NetMainLoop : IMainLoopDriver {
} catch (OperationCanceledException) {
return;
} finally {
_waitForProbe.Reset ();
if (_waitForProbe.IsSet) {
_waitForProbe.Reset ();
}
}
if (_inputHandlerTokenSource.IsCancellationRequested) {
return;
}
if (_resultQueue.Count == 0) {
_resultQueue.Enqueue (_netEvents.DequeueInput ());
}

View File

@@ -861,9 +861,9 @@ internal class WindowsDriver : ConsoleDriver {
_mouseHandler = mouseHandler;
_mainLoop = mainLoop.MainLoopDriver as WindowsMainLoop;
_mainLoop.ProcessInput += ProcessInput;
_mainLoop.ProcessInput = ProcessInput;
#if HACK_CHECK_WINCHANGED
_mainLoop.WinChanged += ChangeWin;
_mainLoop.WinChanged = ChangeWin;
#endif
}

View File

@@ -129,6 +129,11 @@ namespace Terminal.Gui {
/// </summary>
public Rune Dot { get; set; } = (Rune)'∙';
/// <summary>
/// Black Circle . Default is (U+025cf) - ●.
/// </summary>
public Rune BlackCircle { get; set; } = (Rune)'●'; // Black Circle - ● U+025cf
/// <summary>
/// Expand (e.g. for <see cref="TreeView"/>.
/// </summary>

View File

@@ -41,7 +41,7 @@ namespace Terminal.Gui
/// <remarks>
/// An uninitialized Point Structure.
/// </remarks>
public static readonly Point Empty;
/// <summary>

1712
Terminal.Gui/Views/Slider.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -22,6 +22,10 @@
"commandLineArgs": "dotnet UICatalog.dll -usc",
"distributionName": ""
},
"Sliders": {
"commandName": "Project",
"commandLineArgs": "Sliders"
},
"Wizards": {
"commandName": "Project",
"commandLineArgs": "Wizards"

View File

@@ -0,0 +1,320 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Terminal.Gui;
namespace UICatalog.Scenarios;
[ScenarioMetadata (Name: "Sliders", Description: "Demonstrates the Slider view.")]
[ScenarioCategory ("Controls")]
public class Sliders : Scenario {
public override void Setup ()
{
MakeSliders (Win, new List<object> { 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500, 5000 });
#region configView
var configView = new FrameView {
Title = "Configuration",
X = Pos.Percent (50),
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
ColorScheme = Colors.Dialog
};
Win.Add (configView);
#region Config Slider
var slider = new Slider<string> () {
Title = "Options",
X = Pos.Center (),
Y = 0,
Type = SliderType.Multiple,
Width = Dim.Fill (),
AllowEmpty = true,
BorderStyle = LineStyle.Single
};
slider.Style.SetChar.Attribute = new Terminal.Gui.Attribute (Color.BrightGreen, Color.Black);
slider.Style.LegendAttributes.SetAttribute = new Terminal.Gui.Attribute (Color.Green, Color.Black);
slider.Options = new List<SliderOption<string>> {
new SliderOption<string>{
Legend="Legends"
},
new SliderOption<string>{
Legend="RangeAllowSingle"
},
new SliderOption<string>{
Legend="Spacing"
}
};
configView.Add (slider);
slider.OptionsChanged += (sender, e) => {
foreach (var s in Win.Subviews.OfType<Slider> ()) {
if (e.Options.ContainsKey (0))
s.ShowLegends = true;
else
s.ShowLegends = false;
if (e.Options.ContainsKey (1))
s.RangeAllowSingle = true;
else
s.RangeAllowSingle = false;
if (e.Options.ContainsKey (2))
s.ShowSpacing = true;
else
s.ShowSpacing = false;
}
Win.LayoutSubviews ();
};
slider.SetOption (0);
slider.SetOption (1);
#endregion
#region InnerSpacing Input
// var innerspacing_slider = new Slider<string> ("Innerspacing", new List<string> { "Auto", "0", "1", "2", "3", "4", "5" }) {
// X = Pos.Center (),
// Y = Pos.Bottom (slider) + 1
// };
// innerspacing_slider.SetOption (0);
// configView.Add (innerspacing_slider);
// innerspacing_slider.OptionsChanged += (options) => {
// foreach (var s in leftView.Subviews.OfType<Slider> () ()) {
// if (options.ContainsKey (0)) { }
// //s.la = S.SliderLayout.Auto;
// else {
// s.InnerSpacing = options.Keys.First () - 1;
// }
// }
// };
#endregion
#region Slider Orientation Slider
var slider_orientation_slider = new Slider<string> (new List<string> { "Horizontal", "Vertical" }) {
Title = "Slider Orientation",
X = 0,
Y = Pos.Bottom (slider) + 1,
Width = Dim.Fill (),
BorderStyle = LineStyle.Single
};
slider_orientation_slider.SetOption (0);
configView.Add (slider_orientation_slider);
slider_orientation_slider.OptionsChanged += (sender, e) => {
View prev = null;
foreach (var s in Win.Subviews.OfType<Slider> ()) {
if (e.Options.ContainsKey (0)) {
s.Orientation = Orientation.Horizontal;
s.AdjustBestHeight ();
s.Width = Dim.Percent (50);
s.Style.SpaceChar = new Cell () { Runes = { CM.Glyphs.HLine } };
if (prev == null) {
s.LayoutStyle = LayoutStyle.Absolute;
s.Y = 0;
s.LayoutStyle = LayoutStyle.Computed;
} else {
s.Y = Pos.Bottom (prev) + 1;
}
s.X = 0;
prev = s;
} else if (e.Options.ContainsKey (1)) {
s.Orientation = Orientation.Vertical;
s.AdjustBestWidth ();
s.Height = Dim.Fill ();
s.Style.SpaceChar = new Cell () { Runes = { CM.Glyphs.VLine } };
if (prev == null) {
s.LayoutStyle = LayoutStyle.Absolute;
s.X = 0;
s.LayoutStyle = LayoutStyle.Computed;
} else {
s.X = Pos.Right (prev) + 2;
}
s.Y = 0;
prev = s;
}
}
Win.LayoutSubviews ();
};
#endregion
#region Legends Orientation Slider
var legends_orientation_slider = new Slider<string> (new List<string> { "Horizontal", "Vertical" }) {
Title = "Legends Orientation",
X = Pos.Center (),
Y = Pos.Bottom (slider_orientation_slider) + 1,
Width = Dim.Fill (),
BorderStyle = LineStyle.Single
};
legends_orientation_slider.SetOption (0);
configView.Add (legends_orientation_slider);
legends_orientation_slider.OptionsChanged += (sender, e) => {
foreach (var s in Win.Subviews.OfType<Slider> ()) {
if (e.Options.ContainsKey (0))
s.LegendsOrientation = Orientation.Horizontal;
else if (e.Options.ContainsKey (1))
s.LegendsOrientation = Orientation.Vertical;
}
Win.LayoutSubviews ();
};
#endregion
#region Color Slider
var sliderColor = new Slider<(Color, Color)> () {
Title = "Color",
X = Pos.Center (),
Y = Pos.Bottom (legends_orientation_slider) + 1,
Type = SliderType.Single,
Width = Dim.Fill (),
BorderStyle = LineStyle.Single,
AllowEmpty = false
};
sliderColor.Style.SetChar.Attribute = new Terminal.Gui.Attribute (Color.BrightGreen, Color.Black);
sliderColor.Style.LegendAttributes.SetAttribute = new Terminal.Gui.Attribute (Color.Green, Color.Blue);
sliderColor.LegendsOrientation = Orientation.Vertical;
var colorOptions = new List<SliderOption<(Color, Color)>> ();
foreach (var colorIndex in Enum.GetValues<ColorName> ()) {
var colorName = colorIndex.ToString ();
colorOptions.Add (new SliderOption<(Color, Color)> {
Data = (new Color((ColorName)colorIndex), Win.GetNormalColor ().Background),
Legend = colorName,
LegendAbbr = (Rune)colorName [0],
});
}
sliderColor.Options = colorOptions;
configView.Add (sliderColor);
sliderColor.OptionsChanged += (sender, e) => {
if (e.Options.Count != 0) {
var data = e.Options.First ().Value.Data;
foreach (var s in Win.Subviews.OfType<Slider> ()) {
s.Style.OptionChar.Attribute = new Attribute (data.Item1, data.Item2);
s.Style.SetChar.Attribute = new Attribute (data.Item1, data.Item2);
s.Style.LegendAttributes.SetAttribute = new Attribute (data.Item1, Win.GetNormalColor ().Background);
s.Style.RangeChar.Attribute = new Attribute (data.Item1, Win.GetNormalColor ().Background);
s.Style.SpaceChar.Attribute = new Attribute (data.Item1, Win.GetNormalColor ().Background);
s.Style.LegendAttributes.NormalAttribute = new Attribute (data.Item1, Win.GetNormalColor ().Background);
// Here we can not call SetNeedDisplay(), because the OptionsChanged was triggered by Key Pressing,
// that internaly calls SetNeedDisplay.
}
} else {
foreach (var s in Win.Subviews.OfType<Slider> ()) {
s.Style.SetChar.Attribute = null;
s.Style.LegendAttributes.SetAttribute = null;
s.Style.RangeChar.Attribute = null;
}
}
};
// Set option after Eventhandler def, so it updates the sliders color.
// sliderColor.SetOption (2);
#endregion
#endregion
Win.FocusFirst ();
}
public void MakeSliders (View v, List<object> options)
{
var types = Enum.GetValues (typeof (SliderType)).Cast<SliderType> ().ToList ();
Slider prev = null;
foreach (var type in types) {
var view = new Slider (options, Orientation.Horizontal) {
Title = type.ToString (),
X = 0,
//X = Pos.Right (view) + 1,
Y = prev == null ? 0 : Pos.Bottom (prev),
//Y = Pos.Center (),
Width = Dim.Percent (50),
BorderStyle = LineStyle.Single,
Type = type,
LegendsOrientation = Orientation.Horizontal,
AllowEmpty = true,
};
v.Add (view);
prev = view;
};
var singleOptions = new List<object> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39 };
var single = new Slider (singleOptions, Orientation.Horizontal) {
Title = "Actual slider",
X = 0,
//X = Pos.Right (view) + 1,
Y = prev == null ? 0 : Pos.Bottom (prev),
//Y = Pos.Center (),
Type = SliderType.Single,
//BorderStyle = LineStyle.Single,
LegendsOrientation = Orientation.Horizontal,
Width = Dim.Percent (50),
AllowEmpty = false,
//ShowSpacing = true
};
single.LayoutStarted += (s, e) => {
if (single.Orientation == Orientation.Horizontal) {
single.Style.SpaceChar = new Cell () { Runes = { CM.Glyphs.HLine } };
single.Style.OptionChar = new Cell () { Runes = { CM.Glyphs.HLine } };
} else {
single.Style.SpaceChar = new Cell () { Runes = { CM.Glyphs.VLine } };
single.Style.OptionChar = new Cell () { Runes = { CM.Glyphs.VLine } };
}
};
single.Style.SetChar = new Cell () { Runes = { CM.Glyphs.ContinuousMeterSegment } };
single.Style.DragChar = new Cell () { Runes = { CM.Glyphs.ContinuousMeterSegment } };
v.Add (single);
var label = new Label () {
X = 0,
Y = Pos.Bottom (single),
Height = 1,
Width = Dim.Width (single),
Text = $"{single.GetSetOptions ().FirstOrDefault ()}"
};
single.OptionsChanged += (s, e) => {
label.Text = $"{e.Options.FirstOrDefault ().Key}";
};
v.Add (label);
}
}

View File

@@ -74,16 +74,17 @@ namespace UICatalog.Tests {
// BUGBUG: (#2474) For some reason ReadKey is not returning the QuitKey for some Scenarios
// by adding this Space it seems to work.
// See #2474 for why this is commented out
//Assert.Equal (Application.QuitKey, args.KeyEvent.Key);
args.Handled = false;
Assert.Equal (Application.QuitKey, args.KeyEvent.Key);
};
uint abortTime = 500;
// If the scenario doesn't close within 500ms, this will force it to quit
Func<MainLoop, bool> forceCloseCallback = (MainLoop loop) => {
Application.RequestStop ();
// See #2474 for why this is commented out
//Assert.Fail ($"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms. Force quit.");
if (Application.Top.Running && FakeConsole.MockKeyPresses.Count == 0) {
Application.RequestStop ();
// See #2474 for why this is commented out
Assert.Fail ($"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey} after {abortTime}ms. Force quit.");
}
return false;
};
//output.WriteLine ($" Add timeout to force quit after {abortTime}ms");
@@ -91,9 +92,9 @@ namespace UICatalog.Tests {
Application.Iteration += () => {
//output.WriteLine ($" iteration {++iterations}");
if (FakeConsole.MockKeyPresses.Count == 0) {
if (Application.Top.Running && FakeConsole.MockKeyPresses.Count == 0) {
Application.RequestStop ();
//Assert.Fail ($"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey}. Force quit.");
Assert.Fail ($"'{scenario.GetName ()}' failed to Quit with {Application.QuitKey}. Force quit.");
}
};

View File

@@ -1,4 +1,5 @@
using System;
using Terminal.Gui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

View File

@@ -0,0 +1,420 @@
using Xunit;
using Terminal.Gui;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Terminal.Gui.ViewsTests;
public class SliderOptionTests {
[Fact]
public void OnSet_Should_Raise_SetEvent ()
{
// Arrange
var sliderOption = new SliderOption<int> ();
var eventRaised = false;
sliderOption.Set += (sender, args) => eventRaised = true;
// Act
sliderOption.OnSet ();
// Assert
Assert.True (eventRaised);
}
[Fact]
public void OnUnSet_Should_Raise_UnSetEvent ()
{
// Arrange
var sliderOption = new SliderOption<int> ();
var eventRaised = false;
sliderOption.UnSet += (sender, args) => eventRaised = true;
// Act
sliderOption.OnUnSet ();
// Assert
Assert.True (eventRaised);
}
[Fact]
public void OnChanged_Should_Raise_ChangedEvent ()
{
// Arrange
var sliderOption = new SliderOption<int> ();
var eventRaised = false;
sliderOption.Changed += (sender, args) => eventRaised = true;
// Act
sliderOption.OnChanged (true);
// Assert
Assert.True (eventRaised);
}
}
public class SliderEventArgsTests {
[Fact]
public void Constructor_Sets_Options ()
{
// Arrange
var options = new Dictionary<int, SliderOption<int>> ();
// Act
var sliderEventArgs = new SliderEventArgs<int> (options);
// Assert
Assert.Equal (options, sliderEventArgs.Options);
}
[Fact]
public void Constructor_Sets_Focused ()
{
// Arrange
var options = new Dictionary<int, SliderOption<int>> ();
var focused = 42;
// Act
var sliderEventArgs = new SliderEventArgs<int> (options, focused);
// Assert
Assert.Equal (focused, sliderEventArgs.Focused);
}
[Fact]
public void Constructor_Sets_Cancel_Default_To_False ()
{
// Arrange
var options = new Dictionary<int, SliderOption<int>> ();
var focused = 42;
// Act
var sliderEventArgs = new SliderEventArgs<int> (options, focused);
// Assert
Assert.False (sliderEventArgs.Cancel);
}
}
public class SliderTests {
[Fact]
public void Constructor_Default ()
{
// Arrange & Act
var slider = new Slider<int> ();
// Assert
Assert.NotNull (slider);
Assert.NotNull (slider.Options);
Assert.Empty (slider.Options);
Assert.Equal (Orientation.Horizontal, slider.Orientation);
Assert.False (slider.AllowEmpty);
Assert.True (slider.ShowLegends);
Assert.False (slider.ShowSpacing);
Assert.Equal (SliderType.Single, slider.Type);
Assert.Equal (0, slider.InnerSpacing);
Assert.False (slider.AutoSize);
Assert.Equal (0, slider.FocusedOption);
}
[Fact]
public void Constructor_With_Options ()
{
// Arrange
var options = new List<int> { 1, 2, 3 };
// Act
var slider = new Slider<int> (options);
// Assert
Assert.NotNull (slider);
Assert.NotNull (slider.Options);
Assert.Equal (options.Count, slider.Options.Count);
}
[Fact]
public void OnOptionsChanged_Event_Raised ()
{
// Arrange
var slider = new Slider<int> ();
bool eventRaised = false;
slider.OptionsChanged += (sender, args) => eventRaised = true;
// Act
slider.OnOptionsChanged ();
// Assert
Assert.True (eventRaised);
}
[Fact]
public void OnOptionFocused_Event_Raised ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3 });
bool eventRaised = false;
slider.OptionFocused += (sender, args) => eventRaised = true;
int newFocusedOption = 1;
var args = new SliderEventArgs<int> (new Dictionary<int, SliderOption<int>> (), newFocusedOption);
// Act
slider.OnOptionFocused (newFocusedOption, args);
// Assert
Assert.True (eventRaised);
}
[Fact]
public void OnOptionFocused_Event_Cancelled ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3 });
bool eventRaised = false;
bool cancel = false;
slider.OptionFocused += (sender, args) => eventRaised = true;
int newFocusedOption = 1;
// Create args with cancel set to false
cancel = false;
var args = new SliderEventArgs<int> (new Dictionary<int, SliderOption<int>> (), newFocusedOption) {
Cancel = cancel
};
Assert.Equal (0, slider.FocusedOption);
// Act
slider.OnOptionFocused (newFocusedOption, args);
// Assert
Assert.True (eventRaised); // Event should be raised
Assert.Equal (newFocusedOption, slider.FocusedOption); // Focused option should change
// Create args with cancel set to true
cancel = true;
args = new SliderEventArgs<int> (new Dictionary<int, SliderOption<int>> (), newFocusedOption) {
Cancel = cancel
};
// Act
slider.OnOptionFocused (2, args);
// Assert
Assert.True (eventRaised); // Event should be raised
Assert.Equal (newFocusedOption, slider.FocusedOption); // Focused option should not change
}
[Theory]
[InlineData (0, 0, 0)]
[InlineData (1, 3, 0)]
[InlineData (3, 9, 0)]
public void TryGetPositionByOption_ValidOptionHorizontal_Success (int option, int expectedX, int expectedY)
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.AutoSize = true; // Set auto size to true to enable testing
slider.InnerSpacing = 2;
// 0123456789
// 1--2--3--4
// Act
bool result = slider.TryGetPositionByOption (option, out var position);
// Assert
Assert.True (result);
Assert.Equal (expectedX, position.x);
Assert.Equal (expectedY, position.y);
}
[Theory]
[InlineData (0, 0, 0)]
[InlineData (1, 0, 3)]
[InlineData (3, 0, 9)]
public void TryGetPositionByOption_ValidOptionVertical_Success (int option, int expectedX, int expectedY)
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.Orientation = Orientation.Vertical;
slider.AutoSize = true; // Set auto size to true to enable testing
slider.InnerSpacing = 2;
// Act
bool result = slider.TryGetPositionByOption (option, out var position);
// Assert
Assert.True (result);
Assert.Equal (expectedX, position.x);
Assert.Equal (expectedY, position.y);
}
[Fact]
public void TryGetPositionByOption_InvalidOption_Failure ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3 });
int option = -1;
var expectedPosition = (-1, -1);
// Act
bool result = slider.TryGetPositionByOption (option, out var position);
// Assert
Assert.False (result);
Assert.Equal (expectedPosition, position);
}
[Theory]
[InlineData (0, 0, 0, 1)]
[InlineData (3, 0, 0, 2)]
[InlineData (9, 0, 0, 4)]
[InlineData (0, 0, 1, 1)]
[InlineData (3, 0, 1, 2)]
[InlineData (9, 0, 1, 4)]
public void TryGetOptionByPosition_ValidPositionHorizontal_Success (int x, int y, int threshold, int expectedData)
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.AutoSize = true; // Set auto size to true to enable testing
slider.InnerSpacing = 2;
// 0123456789
// 1--2--3--4
// Arrange
// Act
bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
// Assert
Assert.True (result);
Assert.Equal (expectedData, slider.Options [option].Data);
}
[Theory]
[InlineData (0, 0, 0, 1)]
[InlineData (0, 3, 0, 2)]
[InlineData (0, 9, 0, 4)]
[InlineData (0, 0, 1, 1)]
[InlineData (0, 3, 1, 2)]
[InlineData (0, 9, 1, 4)]
public void TryGetOptionByPosition_ValidPositionVertical_Success (int x, int y, int threshold, int expectedData)
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.Orientation = Orientation.Vertical;
slider.AutoSize = true; // Set auto size to true to enable testing
slider.InnerSpacing = 2;
// 0 1
// 1 |
// 2 |
// 3 2
// 4 |
// 5 |
// 6 3
// 7 |
// 8 |
// 9 4
slider.CalcSpacingConfig ();
// Arrange
// Act
bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
// Assert
Assert.True (result);
Assert.Equal (expectedData, slider.Options [option].Data);
}
[Fact]
public void TryGetOptionByPosition_InvalidPosition_Failure ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3 });
int x = 10;
int y = 10;
int threshold = 2;
int expectedOption = -1;
// Act
bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
// Assert
Assert.False (result);
Assert.Equal (expectedOption, option);
}
[Fact]
public void MovePlus_Should_MoveFocusRight_When_OptionIsAvailable ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.AutoSize = true;
// Act
bool result = slider.MovePlus ();
// Assert
Assert.True (result);
Assert.Equal (1, slider.FocusedOption);
}
[Fact]
public void MovePlus_Should_NotMoveFocusRight_When_AtEnd ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.AutoSize = true;
slider.FocusedOption = 3;
// Act
bool result = slider.MovePlus ();
// Assert
Assert.False (result);
Assert.Equal (3, slider.FocusedOption);
}
// Add similar tests for other methods like MoveMinus, MoveStart, MoveEnd, Set, etc.
[Fact]
public void Set_Should_SetFocusedOption ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 });
slider.AutoSize = true;
// Act
slider.FocusedOption = 2;
bool result = slider.Set ();
// Assert
Assert.True (result);
Assert.Equal (2, slider.FocusedOption);
Assert.Single (slider.GetSetOptions ());
}
[Fact]
public void Set_Should_Not_UnSetFocusedOption_When_EmptyNotAllowed ()
{
// Arrange
var slider = new Slider<int> (new List<int> { 1, 2, 3, 4 }) {
AllowEmpty = false
};
slider.AutoSize = true;
Assert.NotEmpty (slider.GetSetOptions ());
// Act
bool result = slider.UnSetOption (slider.FocusedOption);
// Assert
Assert.False (result);
Assert.NotEmpty (slider.GetSetOptions());
}
// Add more tests for different scenarios and edge cases.
}