mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 07:47:54 +01:00
Merge branch 'v2_develop' of tig:gui-cs/Terminal.Gui into v2_develop
This commit is contained in:
@@ -627,7 +627,7 @@ internal class CursesDriver : ConsoleDriver {
|
||||
return true;
|
||||
});
|
||||
|
||||
_mainLoop.WinChanged += ProcessInput;
|
||||
_mainLoop.WinChanged = ProcessInput;
|
||||
}
|
||||
|
||||
public override void Init (Action terminalResized)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 ());
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
1712
Terminal.Gui/Views/Slider.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -22,6 +22,10 @@
|
||||
"commandLineArgs": "dotnet UICatalog.dll -usc",
|
||||
"distributionName": ""
|
||||
},
|
||||
"Sliders": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "Sliders"
|
||||
},
|
||||
"Wizards": {
|
||||
"commandName": "Project",
|
||||
"commandLineArgs": "Wizards"
|
||||
|
||||
320
UICatalog/Scenarios/Sliders.cs
Normal file
320
UICatalog/Scenarios/Sliders.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -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.");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using Terminal.Gui;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
420
UnitTests/Views/SliderTests.cs
Normal file
420
UnitTests/Views/SliderTests.cs
Normal 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.
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user