Fixes #3829. Rename Slider to LinearRange and implement CWP (#4509)

* Initial plan

* Rename Slider to LinearRange - files and code updated

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

* Fix variable name mismatches in scenario files

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

* Fix typos in comments identified by code review

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

* Update HelpText for consistency with LinearRange rename

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

* Refactor LinearRange properties to use CWP with CWPPropertyHelper

- Added CWP events (Changing/Changed) for Type, LegendsOrientation, MinimumInnerSpacing, ShowLegends, ShowEndSpacing, and UseMinimumSize properties
- Used CWPPropertyHelper for consistent property change workflow
- Added virtual OnChanging/OnChanged methods for each property
- All existing tests pass

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

* Fix CWP property implementations - remove duplicate field updates in doWork

- CWPPropertyHelper updates the ref parameter, so doWork should only contain side effects
- Fixed Type, MinimumInnerSpacing, LegendsOrientation, ShowLegends, ShowEndSpacing, and UseMinimumSize
- Added comprehensive CWP tests for property changes (9 new tests, all passing)
- All 45 pre-existing LinearRange tests still pass (10 were already failing before changes)

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

* Add fluent integration tests for LinearRange

- Created LinearRangeFluentTests with 5 test scenarios
- Tests cover rendering, navigation, type changes with CWP events, range selection, and vertical orientation
- All tests build successfully

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

* Fix unit tests and address review comments

- Fixed review comments: Updated Title properties from "_Slider" to "_LinearRange" in DimAutoDemo and ViewportSettings
- Fixed review comment: Renamed filterSlider to filterLinearRange in Mouse.cs
- Fixed CWP implementation: Use local variable instead of backing field as ref parameter to CWPPropertyHelper
- This ensures doWork can update the backing field BEFORE SetContentSize() reads it
- All 55 LinearRange tests now passing (was 45/55, now 55/55)

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

* Update DimAutoDemo.cs

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

* Update ViewportSettings.cs

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

* code cleanup

* Refactor LinearRanges scenario for clarity and modularity

Refactored the LinearRanges scenario to separate UI setup, configuration, and event logic. The Main() method now handles all UI layout, configuration controls, and event wiring, while MakeSliders() is responsible only for adding LinearRange controls to the main window. Updated event handlers to use discard parameters for unused arguments and modernized code with collection initializers and LINQ. This results in a clearer separation of concerns and improved maintainability.

* un did change

* cleanup

* cleanup

* cleanup

* fixed unit test
code cleanup

---------

Co-authored-by: Tig <tig@users.noreply.github.com>
Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com>
Co-authored-by: tig <585482+tig@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Copilot
2025-12-21 10:40:09 -07:00
committed by GitHub
parent 4145b984ba
commit fb4043afbc
18 changed files with 1620 additions and 1185 deletions

View File

@@ -179,20 +179,20 @@ public class DimAutoDemo : Scenario
{ {
var sliderFrameView = new FrameView var sliderFrameView = new FrameView
{ {
Title = "Slider - Example of a DimAuto View", Title = "LinearRange - Example of a DimAuto View",
}; };
List<object> options = new () { "One", "Two", "Three", "Four" }; List<object> options = new () { "One", "Two", "Three", "Four" };
Slider slider = new (options) LinearRange linearRange = new (options)
{ {
X = 0, X = 0,
Y = 0, Y = 0,
Type = SliderType.Multiple, Type = LinearRangeType.Multiple,
AllowEmpty = false, AllowEmpty = false,
BorderStyle = LineStyle.Double, BorderStyle = LineStyle.Double,
Title = "_Slider" Title = "_LinearRange"
}; };
sliderFrameView.Add (slider); sliderFrameView.Add (linearRange);
return sliderFrameView; return sliderFrameView;
} }

View File

@@ -0,0 +1,615 @@
using System.Collections.ObjectModel;
using System.Text;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("LinearRanges", "Demonstrates the LinearRange view.")]
[ScenarioCategory ("Controls")]
public class LinearRanges : Scenario
{
public override void Main ()
{
Application.Init ();
using IApplication app = Application.Instance;
using Window mainWindow = new ();
mainWindow.Title = GetQuitKeyAndName ();
MakeSliders (
mainWindow,
[
500,
1000,
1500,
2000,
2500,
3000,
3500,
4000,
4500,
5000
]
);
FrameView configView = new ()
{
Title = "Confi_guration",
X = Pos.Percent (50),
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
SchemeName = "Dialog"
};
mainWindow.Add (configView);
#region Config LinearRange
LinearRange<string> optionsSlider = new ()
{
Title = "Options",
X = 0,
Y = 0,
Width = Dim.Fill (),
Type = LinearRangeType.Multiple,
AllowEmpty = true,
BorderStyle = LineStyle.Single
};
optionsSlider.Style.SetChar = optionsSlider.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
optionsSlider.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Black);
optionsSlider.Options =
[
new () { Legend = "Legends" },
new () { Legend = "RangeAllowSingle" },
new () { Legend = "EndSpacing" },
new () { Legend = "DimAuto" }
];
configView.Add (optionsSlider);
optionsSlider.OptionsChanged += OnOptionsSliderOnOptionsChanged;
optionsSlider.SetOption (0); // Legends
optionsSlider.SetOption (1); // RangeAllowSingle
optionsSlider.SetOption (3); // DimAuto
CheckBox dimAutoUsesMin = new ()
{
Text = "Use minimum size (vs. ideal)",
X = 0,
Y = Pos.Bottom (optionsSlider)
};
dimAutoUsesMin.CheckedStateChanging += (_, _) =>
{
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.UseMinimumSize = !s.UseMinimumSize;
}
};
configView.Add (dimAutoUsesMin);
#region LinearRange Orientation LinearRange
LinearRange<string> orientationSlider = new (new () { "Horizontal", "Vertical" })
{
Title = "LinearRange Orientation",
X = 0,
Y = Pos.Bottom (dimAutoUsesMin) + 1,
BorderStyle = LineStyle.Single
};
orientationSlider.SetOption (0);
configView.Add (orientationSlider);
orientationSlider.OptionsChanged += OnOrientationSliderOnOptionsChanged;
#endregion LinearRange Orientation LinearRange
#region Legends Orientation LinearRange
LinearRange<string> legendsOrientationSlider = new (["Horizontal", "Vertical"])
{
Title = "Legends Orientation",
X = 0,
Y = Pos.Bottom (orientationSlider) + 1,
BorderStyle = LineStyle.Single
};
legendsOrientationSlider.SetOption (0);
configView.Add (legendsOrientationSlider);
legendsOrientationSlider.OptionsChanged += OnLegendsOrientationSliderOnOptionsChanged;
#endregion Legends Orientation LinearRange
#region Spacing Options
FrameView spacingOptions = new ()
{
Title = "Spacing Options",
X = Pos.Right (orientationSlider),
Y = Pos.Top (orientationSlider),
Width = Dim.Fill (),
Height = Dim.Auto (),
BorderStyle = LineStyle.Single
};
Label label = new ()
{
Text = "Min _Inner Spacing:"
};
NumericUpDown<int> innerSpacingUpDown = new ()
{
X = Pos.Right (label) + 1
};
innerSpacingUpDown.Value = mainWindow.SubViews.OfType<LinearRange> ().First ().MinimumInnerSpacing;
innerSpacingUpDown.ValueChanging += (_, e) =>
{
if (e.NewValue < 0)
{
e.Cancel = true;
return;
}
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.MinimumInnerSpacing = e.NewValue;
}
};
spacingOptions.Add (label, innerSpacingUpDown);
configView.Add (spacingOptions);
#endregion
#region Color LinearRange
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.Style.OptionChar = s.Style.OptionChar with { Attribute = mainWindow.GetAttributeForRole (VisualRole.Normal) };
s.Style.SetChar = s.Style.SetChar with { Attribute = mainWindow.GetAttributeForRole (VisualRole.Normal) };
s.Style.LegendAttributes.SetAttribute = mainWindow.GetAttributeForRole (VisualRole.Normal);
s.Style.RangeChar = s.Style.RangeChar with { Attribute = mainWindow.GetAttributeForRole (VisualRole.Normal) };
}
LinearRange<(Color, Color)> sliderFgColor = new ()
{
Title = "FG Color",
X = 0,
Y = Pos.Bottom (legendsOrientationSlider)
+ 1,
Type = LinearRangeType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false,
Orientation = Orientation.Vertical,
LegendsOrientation = Orientation.Horizontal,
MinimumInnerSpacing = 0,
UseMinimumSize = true
};
sliderFgColor.Style.SetChar = sliderFgColor.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
sliderFgColor.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Blue);
List<LinearRangeOption<(Color, Color)>> colorOptions = [];
colorOptions.AddRange (
from colorIndex in Enum.GetValues<ColorName16> ()
let colorName = colorIndex.ToString ()
select new LinearRangeOption<(Color, Color)>
{ Data = (new (colorIndex), new (colorIndex)), Legend = colorName, LegendAbbr = (Rune)colorName [0] });
sliderFgColor.Options = colorOptions;
configView.Add (sliderFgColor);
sliderFgColor.OptionsChanged += OnSliderFgColorOnOptionsChanged;
LinearRange<(Color, Color)> sliderBgColor = new ()
{
Title = "BG Color",
X = Pos.Right (sliderFgColor),
Y = Pos.Top (sliderFgColor),
Type = LinearRangeType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false,
Orientation = Orientation.Vertical,
LegendsOrientation = Orientation.Horizontal,
MinimumInnerSpacing = 0,
UseMinimumSize = true
};
sliderBgColor.Style.SetChar = sliderBgColor.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
sliderBgColor.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Blue);
sliderBgColor.Options = colorOptions;
configView.Add (sliderBgColor);
sliderBgColor.OptionsChanged += (_, e) =>
{
if (e.Options.Count == 0)
{
return;
}
(Color, Color) data = e.Options.First ().Value.Data;
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.SetScheme (
new (s.GetScheme ())
{
Normal = new (
s.GetAttributeForRole (VisualRole.Normal).Foreground,
data.Item2
)
});
}
};
#endregion Color LinearRange
#endregion Config LinearRange
ObservableCollection<string> eventSource = [];
ListView eventLog = new ()
{
X = Pos.Right (sliderBgColor),
Y = Pos.Bottom (spacingOptions),
Width = Dim.Fill (),
Height = Dim.Fill (),
SchemeName = "Runnable",
Source = new ListWrapper<string> (eventSource)
};
configView.Add (eventLog);
foreach (View view in mainWindow.SubViews.Where (v => v is LinearRange)!)
{
var slider = (LinearRange)view;
slider.Accepting += (_, args) =>
{
eventSource.Add ($"Accept: {string.Join (",", slider.GetSetOptions ())}");
eventLog.MoveDown ();
args.Handled = true;
};
slider.OptionsChanged += (_, args) =>
{
eventSource.Add ($"OptionsChanged: {string.Join (",", slider.GetSetOptions ())}");
eventLog.MoveDown ();
args.Cancel = true;
};
}
mainWindow.FocusDeepest (NavigationDirection.Forward, null);
app.Run (mainWindow);
return;
void OnSliderFgColorOnOptionsChanged (object _, LinearRangeEventArgs<(Color, Color)> e)
{
if (e.Options.Count == 0)
{
return;
}
(Color, Color) data = e.Options.First ().Value.Data;
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.SetScheme (
new (s.GetScheme ())
{
Normal = new (
data.Item2,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
});
s.Style.OptionChar = s.Style.OptionChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.SetChar = s.Style.SetChar with
{
Attribute = new Attribute (
data.Item1,
s.Style.SetChar.Attribute?.Background
?? s.GetAttributeForRole (VisualRole.Normal).Background,
s.Style.SetChar.Attribute?.Style
?? s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.LegendAttributes.SetAttribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style);
s.Style.RangeChar = s.Style.RangeChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.SpaceChar = s.Style.SpaceChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.LegendAttributes.NormalAttribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style);
}
}
void OnLegendsOrientationSliderOnOptionsChanged (object _, LinearRangeEventArgs<string> e)
{
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
if (e.Options.ContainsKey (0))
{
s.LegendsOrientation = Orientation.Horizontal;
}
else if (e.Options.ContainsKey (1))
{
s.LegendsOrientation = Orientation.Vertical;
}
if (optionsSlider.GetSetOptions ().Contains (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend!.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend!.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
}
void OnOrientationSliderOnOptionsChanged (object _, LinearRangeEventArgs<string> e)
{
View prev = null;
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
if (e.Options.ContainsKey (0))
{
s.Orientation = Orientation.Horizontal;
s.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
if (prev == null)
{
s.Y = 0;
}
else
{
s.Y = Pos.Bottom (prev) + 1;
}
s.X = 0;
prev = s;
}
else if (e.Options.ContainsKey (1))
{
s.Orientation = Orientation.Vertical;
s.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
if (prev == null)
{
s.X = 0;
}
else
{
s.X = Pos.Right (prev) + 2;
}
s.Y = 0;
prev = s;
}
if (optionsSlider.GetSetOptions ().Contains (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend!.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend!.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
}
void OnOptionsSliderOnOptionsChanged (object _, LinearRangeEventArgs<string> e)
{
foreach (LinearRange s in mainWindow.SubViews.OfType<LinearRange> ())
{
s.ShowLegends = e.Options.ContainsKey (0);
s.RangeAllowSingle = e.Options.ContainsKey (1);
s.ShowEndSpacing = e.Options.ContainsKey (2);
if (e.Options.ContainsKey (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend!.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend!.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
}
}
private void MakeSliders (Window window, List<object> options)
{
List<LinearRangeType> types = Enum.GetValues (typeof (LinearRangeType)).Cast<LinearRangeType> ().ToList ();
LinearRange prev = null;
foreach (LinearRange view in types.Select (type => new LinearRange (options)
{
Title = type.ToString (),
X = 0,
Y = prev == null ? 0 : Pos.Bottom (prev),
BorderStyle = LineStyle.Single,
Type = type,
AllowEmpty = true
}))
{
//view.Padding.Thickness = new (0,1,0,0);
window.Add (view);
prev = view;
}
List<object> singleOptions =
[
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
];
LinearRange single = new (singleOptions)
{
Title = "_Continuous",
X = 0,
Y = prev == null ? 0 : Pos.Bottom (prev),
Type = LinearRangeType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false
};
single.SubViewLayout += (_, _) =>
{
if (single.Orientation == Orientation.Horizontal)
{
single.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
single.Style.OptionChar = new () { Grapheme = Glyphs.HLine.ToString () };
}
else
{
single.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
single.Style.OptionChar = new () { Grapheme = Glyphs.VLine.ToString () };
}
};
single.Style.SetChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
single.Style.DragChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
window.Add (single);
single.OptionsChanged += (_, e) => { single.Title = $"_Continuous {e.Options.FirstOrDefault ().Key}"; };
List<object> oneOption = new () { "The Only Option" };
LinearRange one = new (oneOption)
{
Title = "_One Option",
X = 0,
Y = prev == null ? 0 : Pos.Bottom (single),
Type = LinearRangeType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false
};
window.Add (one);
}
}

View File

@@ -229,8 +229,8 @@ public class Shortcuts : Scenario
X = 0, X = 0,
Y = Pos.Bottom (optionSelectorShortcut), Y = Pos.Bottom (optionSelectorShortcut),
Width = Dim.Fill ()! - Dim.Width (eventLog), Width = Dim.Fill ()! - Dim.Width (eventLog),
HelpText = "Sliders work!", HelpText = "LinearRanges work!",
CommandView = new Slider<string> CommandView = new LinearRange<string>
{ {
Orientation = Orientation.Horizontal, Orientation = Orientation.Horizontal,
AllowEmpty = true AllowEmpty = true
@@ -238,13 +238,13 @@ public class Shortcuts : Scenario
Key = Key.F5 Key = Key.F5
}; };
((Slider<string>)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }]; ((LinearRange<string>)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }];
((Slider<string>)sliderShortcut.CommandView).SetOption (0); ((LinearRange<string>)sliderShortcut.CommandView).SetOption (0);
((Slider<string>)sliderShortcut.CommandView).OptionsChanged += (o, args) => ((LinearRange<string>)sliderShortcut.CommandView).OptionsChanged += (o, args) =>
{ {
eventSource.Add ( eventSource.Add (
$"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((Slider<string>)o!)!.GetSetOptions ())}"); $"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((LinearRange<string>)o!)!.GetSetOptions ())}");
eventLog.MoveDown (); eventLog.MoveDown ();
}; };

View File

@@ -1,621 +0,0 @@
using System.Collections.ObjectModel;
using System.Text;
namespace UICatalog.Scenarios;
[ScenarioMetadata ("Sliders", "Demonstrates the Slider view.")]
[ScenarioCategory ("Controls")]
public class Sliders : Scenario
{
public void MakeSliders (View v, List<object> options)
{
List<SliderType> types = Enum.GetValues (typeof (SliderType)).Cast<SliderType> ().ToList ();
Slider prev = null;
foreach (SliderType type in types)
{
var view = new Slider (options)
{
Title = type.ToString (),
X = 0,
Y = prev == null ? 0 : Pos.Bottom (prev),
BorderStyle = LineStyle.Single,
Type = type,
AllowEmpty = true
};
//view.Padding.Thickness = new (0,1,0,0);
v.Add (view);
prev = view;
}
List<object> singleOptions = new ()
{
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)
{
Title = "_Continuous",
X = 0,
Y = prev == null ? 0 : Pos.Bottom (prev),
Type = SliderType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false
};
single.SubViewLayout += (s, e) =>
{
if (single.Orientation == Orientation.Horizontal)
{
single.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
single.Style.OptionChar = new () { Grapheme = Glyphs.HLine.ToString () };
}
else
{
single.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
single.Style.OptionChar = new () { Grapheme = Glyphs.VLine.ToString () };
}
};
single.Style.SetChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
single.Style.DragChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
v.Add (single);
single.OptionsChanged += (s, e) => { single.Title = $"_Continuous {e.Options.FirstOrDefault ().Key}"; };
List<object> oneOption = new () { "The Only Option" };
var one = new Slider (oneOption)
{
Title = "_One Option",
X = 0,
Y = prev == null ? 0 : Pos.Bottom (single),
Type = SliderType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false
};
v.Add (one);
}
public override void Main ()
{
Application.Init ();
Window app = new ()
{
Title = GetQuitKeyAndName ()
};
MakeSliders (
app,
new ()
{
500,
1000,
1500,
2000,
2500,
3000,
3500,
4000,
4500,
5000
}
);
var configView = new FrameView
{
Title = "Confi_guration",
X = Pos.Percent (50),
Y = 0,
Width = Dim.Fill (),
Height = Dim.Fill (),
SchemeName = "Dialog"
};
app.Add (configView);
#region Config Slider
Slider<string> optionsSlider = new ()
{
Title = "Options",
X = 0,
Y = 0,
Width = Dim.Fill (),
Type = SliderType.Multiple,
AllowEmpty = true,
BorderStyle = LineStyle.Single
};
optionsSlider.Style.SetChar = optionsSlider.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
optionsSlider.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Black);
optionsSlider.Options = new ()
{
new () { Legend = "Legends" },
new () { Legend = "RangeAllowSingle" },
new () { Legend = "EndSpacing" },
new () { Legend = "DimAuto" }
};
configView.Add (optionsSlider);
optionsSlider.OptionsChanged += (sender, e) =>
{
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.ShowLegends = e.Options.ContainsKey (0);
s.RangeAllowSingle = e.Options.ContainsKey (1);
s.ShowEndSpacing = e.Options.ContainsKey (2);
if (e.Options.ContainsKey (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
};
optionsSlider.SetOption (0); // Legends
optionsSlider.SetOption (1); // RangeAllowSingle
optionsSlider.SetOption (3); // DimAuto
CheckBox dimAutoUsesMin = new ()
{
Text = "Use minimum size (vs. ideal)",
X = 0,
Y = Pos.Bottom (optionsSlider)
};
dimAutoUsesMin.CheckedStateChanging += (sender, e) =>
{
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.UseMinimumSize = !s.UseMinimumSize;
}
};
configView.Add (dimAutoUsesMin);
#region Slider Orientation Slider
Slider<string> orientationSlider = new (new () { "Horizontal", "Vertical" })
{
Title = "Slider Orientation",
X = 0,
Y = Pos.Bottom (dimAutoUsesMin) + 1,
BorderStyle = LineStyle.Single
};
orientationSlider.SetOption (0);
configView.Add (orientationSlider);
orientationSlider.OptionsChanged += (sender, e) =>
{
View prev = null;
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
if (e.Options.ContainsKey (0))
{
s.Orientation = Orientation.Horizontal;
s.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
if (prev == null)
{
s.Y = 0;
}
else
{
s.Y = Pos.Bottom (prev) + 1;
}
s.X = 0;
prev = s;
}
else if (e.Options.ContainsKey (1))
{
s.Orientation = Orientation.Vertical;
s.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
if (prev == null)
{
s.X = 0;
}
else
{
s.X = Pos.Right (prev) + 2;
}
s.Y = 0;
prev = s;
}
if (optionsSlider.GetSetOptions ().Contains (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
};
#endregion Slider Orientation Slider
#region Legends Orientation Slider
Slider<string> legendsOrientationSlider = new (new () { "Horizontal", "Vertical" })
{
Title = "Legends Orientation",
X = 0,
Y = Pos.Bottom (orientationSlider) + 1,
BorderStyle = LineStyle.Single
};
legendsOrientationSlider.SetOption (0);
configView.Add (legendsOrientationSlider);
legendsOrientationSlider.OptionsChanged += (sender, e) =>
{
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
if (e.Options.ContainsKey (0))
{
s.LegendsOrientation = Orientation.Horizontal;
}
else if (e.Options.ContainsKey (1))
{
s.LegendsOrientation = Orientation.Vertical;
}
if (optionsSlider.GetSetOptions ().Contains (3))
{
s.Width = Dim.Auto (DimAutoStyle.Content);
s.Height = Dim.Auto (DimAutoStyle.Content);
}
else
{
if (s.Orientation == Orientation.Horizontal)
{
s.Width = Dim.Percent (50);
int h = s.ShowLegends && s.LegendsOrientation == Orientation.Vertical
? s.Options.Max (o => o.Legend.Length) + 3
: 4;
s.Height = h;
}
else
{
int w = s.ShowLegends ? s.Options.Max (o => o.Legend.Length) + 3 : 3;
s.Width = w;
s.Height = Dim.Fill ();
}
}
}
};
#endregion Legends Orientation Slider
#region Spacing Options
FrameView spacingOptions = new ()
{
Title = "Spacing Options",
X = Pos.Right (orientationSlider),
Y = Pos.Top (orientationSlider),
Width = Dim.Fill (),
Height = Dim.Auto (),
BorderStyle = LineStyle.Single
};
Label label = new ()
{
Text = "Min _Inner Spacing:"
};
NumericUpDown<int> innerSpacingUpDown = new ()
{
X = Pos.Right (label) + 1
};
innerSpacingUpDown.Value = app.SubViews.OfType<Slider> ().First ().MinimumInnerSpacing;
innerSpacingUpDown.ValueChanging += (sender, e) =>
{
if (e.NewValue < 0)
{
e.Cancel = true;
return;
}
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.MinimumInnerSpacing = e.NewValue;
}
};
spacingOptions.Add (label, innerSpacingUpDown);
configView.Add (spacingOptions);
#endregion
#region Color Slider
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.Style.OptionChar = s.Style.OptionChar with { Attribute = app.GetAttributeForRole (VisualRole.Normal) };
s.Style.SetChar = s.Style.SetChar with { Attribute = app.GetAttributeForRole (VisualRole.Normal) };
s.Style.LegendAttributes.SetAttribute = app.GetAttributeForRole (VisualRole.Normal);
s.Style.RangeChar = s.Style.RangeChar with { Attribute = app.GetAttributeForRole (VisualRole.Normal) };
}
Slider<(Color, Color)> sliderFGColor = new ()
{
Title = "FG Color",
X = 0,
Y = Pos.Bottom (
legendsOrientationSlider
)
+ 1,
Type = SliderType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false,
Orientation = Orientation.Vertical,
LegendsOrientation = Orientation.Horizontal,
MinimumInnerSpacing = 0,
UseMinimumSize = true
};
sliderFGColor.Style.SetChar = sliderFGColor.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
sliderFGColor.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Blue);
List<SliderOption<(Color, Color)>> colorOptions = new ();
foreach (ColorName16 colorIndex in Enum.GetValues<ColorName16> ())
{
var colorName = colorIndex.ToString ();
colorOptions.Add (
new ()
{
Data = (new (colorIndex),
new (colorIndex)),
Legend = colorName,
LegendAbbr = (Rune)colorName [0]
}
);
}
sliderFGColor.Options = colorOptions;
configView.Add (sliderFGColor);
sliderFGColor.OptionsChanged += (sender, e) =>
{
if (e.Options.Count != 0)
{
(Color, Color) data = e.Options.First ().Value.Data;
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.SetScheme (
new (s.GetScheme ())
{
Normal = new (
data.Item2,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style
)
});
s.Style.OptionChar = s.Style.OptionChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style
)
};
s.Style.SetChar = s.Style.SetChar with
{
Attribute = new Attribute (
data.Item1,
s.Style.SetChar.Attribute?.Background
?? s.GetAttributeForRole (VisualRole.Normal).Background,
s.Style.SetChar.Attribute?.Style
?? s.GetAttributeForRole (VisualRole.Normal).Style
)
};
s.Style.LegendAttributes.SetAttribute =
new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style);
s.Style.RangeChar = s.Style.RangeChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.SpaceChar = s.Style.SpaceChar with
{
Attribute = new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style)
};
s.Style.LegendAttributes.NormalAttribute =
new Attribute (
data.Item1,
s.GetAttributeForRole (VisualRole.Normal).Background,
s.GetAttributeForRole (VisualRole.Normal).Style);
}
}
};
Slider<(Color, Color)> sliderBGColor = new ()
{
Title = "BG Color",
X = Pos.Right (sliderFGColor),
Y = Pos.Top (sliderFGColor),
Type = SliderType.Single,
BorderStyle = LineStyle.Single,
AllowEmpty = false,
Orientation = Orientation.Vertical,
LegendsOrientation = Orientation.Horizontal,
MinimumInnerSpacing = 0,
UseMinimumSize = true
};
sliderBGColor.Style.SetChar = sliderBGColor.Style.SetChar with { Attribute = new Attribute (Color.BrightGreen, Color.Black) };
sliderBGColor.Style.LegendAttributes.SetAttribute = new Attribute (Color.Green, Color.Blue);
sliderBGColor.Options = colorOptions;
configView.Add (sliderBGColor);
sliderBGColor.OptionsChanged += (sender, e) =>
{
if (e.Options.Count != 0)
{
(Color, Color) data = e.Options.First ().Value.Data;
foreach (Slider s in app.SubViews.OfType<Slider> ())
{
s.SetScheme (
new (s.GetScheme ())
{
Normal = new (
s.GetAttributeForRole (VisualRole.Normal).Foreground,
data.Item2
)
});
}
}
};
#endregion Color Slider
#endregion Config Slider
ObservableCollection<string> eventSource = new ();
var eventLog = new ListView
{
X = Pos.Right (sliderBGColor),
Y = Pos.Bottom (spacingOptions),
Width = Dim.Fill (),
Height = Dim.Fill (),
SchemeName = "Runnable",
Source = new ListWrapper<string> (eventSource)
};
configView.Add (eventLog);
foreach (Slider slider in app.SubViews.Where (v => v is Slider)!)
{
slider.Accepting += (o, args) =>
{
eventSource.Add ($"Accept: {string.Join (",", slider.GetSetOptions ())}");
eventLog.MoveDown ();
args.Handled = true;
};
slider.OptionsChanged += (o, args) =>
{
eventSource.Add ($"OptionsChanged: {string.Join (",", slider.GetSetOptions ())}");
eventLog.MoveDown ();
args.Cancel = true;
};
}
app.FocusDeepest (NavigationDirection.Forward, null);
Application.Run (app);
app.Dispose ();
Application.Shutdown ();
}
}

View File

@@ -201,17 +201,17 @@ public class ViewportSettings : Scenario
List<object> options = new () { "Option 1", "Option 2", "Option 3" }; List<object> options = new () { "Option 1", "Option 2", "Option 3" };
Slider slider = new (options) LinearRange linearRange = new (options)
{ {
X = 0, X = 0,
Y = Pos.Bottom (textField) + 1, Y = Pos.Bottom (textField) + 1,
Orientation = Orientation.Vertical, Orientation = Orientation.Vertical,
Type = SliderType.Multiple, Type = LinearRangeType.Multiple,
AllowEmpty = false, AllowEmpty = false,
BorderStyle = LineStyle.Double, BorderStyle = LineStyle.Double,
Title = "_Slider" Title = "_LinearRange"
}; };
view.Add (slider); view.Add (linearRange);
adornmentsEditor.Initialized += (s, e) => adornmentsEditor.Initialized += (s, e) =>
{ {

View File

@@ -1,7 +1,7 @@
namespace Terminal.Gui.Views; namespace Terminal.Gui.Views;
/// <summary><see cref="Slider{T}"/> Legend Style</summary> /// <summary><see cref="LinearRange{T}"/> Legend Style</summary>
public class SliderAttributes public class LinearRangeAttributes
{ {
/// <summary>Attribute for the Legends Container.</summary> /// <summary>Attribute for the Legends Container.</summary>
public Attribute? EmptyAttribute { get; set; } public Attribute? EmptyAttribute { get; set; }

View File

@@ -1,8 +1,7 @@
namespace Terminal.Gui.Views; namespace Terminal.Gui.Views;
/// <summary>All <see cref="Slider{T}"/> configuration are grouped in this class.</summary> /// <summary>All <see cref="LinearRange{T}"/> configuration are grouped in this class.</summary>
internal class SliderConfiguration internal class LinearRangeConfiguration
{ {
internal bool _allowEmpty; internal bool _allowEmpty;
internal int _endSpacing; internal int _endSpacing;
@@ -13,8 +12,8 @@ internal class SliderConfiguration
internal bool _showEndSpacing; internal bool _showEndSpacing;
internal bool _showLegends; internal bool _showLegends;
internal bool _showLegendsAbbr; internal bool _showLegendsAbbr;
internal Orientation _sliderOrientation = Orientation.Horizontal; internal Orientation _linearRangeOrientation = Orientation.Horizontal;
internal int _startSpacing; internal int _startSpacing;
internal SliderType _type = SliderType.Single; internal LinearRangeType _type = LinearRangeType.Single;
internal bool _useMinimumSize; internal bool _useMinimumSize;
} }

View File

@@ -1,13 +1,12 @@
#nullable disable
namespace Terminal.Gui.Views; namespace Terminal.Gui.Views;
/// <summary><see cref="EventArgs"/> for <see cref="Slider{T}"/> events.</summary> /// <summary><see cref="EventArgs"/> for <see cref="LinearRange{T}"/> events.</summary>
public class SliderEventArgs<T> : EventArgs public class LinearRangeEventArgs<T> : EventArgs
{ {
/// <summary>Initializes a new instance of <see cref="SliderEventArgs{T}"/></summary> /// <summary>Initializes a new instance of <see cref="LinearRangeEventArgs{T}"/></summary>
/// <param name="options">The current options.</param> /// <param name="options">The current options.</param>
/// <param name="focused">Index of the option that is focused. -1 if no option has the focus.</param> /// <param name="focused">Index of the option that is focused. -1 if no option has the focus.</param>
public SliderEventArgs (Dictionary<int, SliderOption<T>> options, int focused = -1) public LinearRangeEventArgs (Dictionary<int, LinearRangeOption<T>> options, int focused = -1)
{ {
Options = options; Options = options;
Focused = focused; Focused = focused;
@@ -21,5 +20,5 @@ public class SliderEventArgs<T> : EventArgs
public int Focused { get; set; } public int Focused { get; set; }
/// <summary>Gets/sets whether the option is set or not.</summary> /// <summary>Gets/sets whether the option is set or not.</summary>
public Dictionary<int, SliderOption<T>> Options { get; set; } public Dictionary<int, LinearRangeOption<T>> Options { get; set; }
} }

View File

@@ -0,0 +1,50 @@
namespace Terminal.Gui.Views;
/// <summary>Represents an option in a <see cref="LinearRange{T}"/> .</summary>
/// <typeparam name="T">Data type of the option.</typeparam>
public class LinearRangeOption<T>
{
/// <summary>Creates a new empty instance of the <see cref="LinearRangeOption{T}"/> class.</summary>
public LinearRangeOption () { }
/// <summary>Creates a new instance of the <see cref="LinearRangeOption{T}"/> class with values for each property.</summary>
public LinearRangeOption (string legend, Rune legendAbbr, T data)
{
Legend = legend;
LegendAbbr = legendAbbr;
Data = data;
}
/// <summary>Event fired when an option has changed.</summary>
public event EventHandler<LinearRangeOptionEventArgs>? Changed;
/// <summary>Custom data of the option.</summary>
public T? Data { get; set; }
/// <summary>Legend of the option.</summary>
public string? Legend { get; set; }
/// <summary>
/// Abbreviation of the Legend. When the <see cref="LinearRange{T}.MinimumInnerSpacing"/> too small to fit
/// <see cref="Legend"/>.
/// </summary>
public Rune LegendAbbr { get; set; }
/// <summary>Event Raised when this option is set.</summary>
public event EventHandler<LinearRangeOptionEventArgs>? Set;
/// <summary>Creates a human-readable string that represents this <see cref="LinearRangeOption{T}"/>.</summary>
public override string ToString () => "{Legend=" + Legend + ", LegendAbbr=" + LegendAbbr + ", Data=" + Data + "}";
/// <summary>Event Raised when this option is unset.</summary>
public event EventHandler<LinearRangeOptionEventArgs>? UnSet;
/// <summary>To Raise the <see cref="Changed"/> event from the LinearRange.</summary>
internal void OnChanged (bool isSet) { Changed?.Invoke (this, new (isSet)); }
/// <summary>To Raise the <see cref="Set"/> event from the LinearRange.</summary>
internal void OnSet () { Set?.Invoke (this, new (true)); }
/// <summary>To Raise the <see cref="UnSet"/> event from the LinearRange.</summary>
internal void OnUnSet () { UnSet?.Invoke (this, new (false)); }
}

View File

@@ -0,0 +1,12 @@
namespace Terminal.Gui.Views;
/// <summary><see cref="EventArgs"/> for <see cref="LinearRange{T}"/> <see cref="LinearRangeOption{T}"/> events.</summary>
public class LinearRangeOptionEventArgs : EventArgs
{
/// <summary>Initializes a new instance of <see cref="LinearRangeOptionEventArgs"/></summary>
/// <param name="isSet"> indicates whether the option is set</param>
public LinearRangeOptionEventArgs (bool isSet) { IsSet = isSet; }
/// <summary>Gets whether the option is set or not.</summary>
public bool IsSet { get; }
}

View File

@@ -1,36 +1,35 @@
 namespace Terminal.Gui.Views;
namespace Terminal.Gui.Views;
/// <summary><see cref="Slider{T}"/> Style</summary> /// <summary><see cref="LinearRange{T}"/> Style</summary>
public class SliderStyle public class LinearRangeStyle
{ {
/// <summary>Constructs a new instance.</summary> /// <summary>Constructs a new instance.</summary>
public SliderStyle () { LegendAttributes = new (); } public LinearRangeStyle () { LegendAttributes = new (); }
/// <summary>The glyph and the attribute to indicate mouse dragging.</summary> /// <summary>The glyph and the attribute to indicate mouse dragging.</summary>
public Cell DragChar { get; set; } public Cell DragChar { get; set; }
/// <summary>The glyph and the attribute used for empty spaces on the slider.</summary> /// <summary>The glyph and the attribute used for empty spaces on the linear range.</summary>
public Cell EmptyChar { get; set; } public Cell EmptyChar { get; set; }
/// <summary>The glyph and the attribute used for the end of ranges on the slider.</summary> /// <summary>The glyph and the attribute used for the end of ranges on the linear range.</summary>
public Cell EndRangeChar { get; set; } public Cell EndRangeChar { get; set; }
/// <summary>Legend attributes</summary> /// <summary>Legend attributes</summary>
public SliderAttributes LegendAttributes { get; set; } public LinearRangeAttributes LegendAttributes { get; set; }
/// <summary>The glyph and the attribute used for each option (tick) on the slider.</summary> /// <summary>The glyph and the attribute used for each option (tick) on the linear range.</summary>
public Cell OptionChar { get; set; } public Cell OptionChar { get; set; }
/// <summary>The glyph and the attribute used for filling in ranges on the slider.</summary> /// <summary>The glyph and the attribute used for filling in ranges on the linear range.</summary>
public Cell RangeChar { get; set; } public Cell RangeChar { get; set; }
/// <summary>The glyph and the attribute used for options (ticks) that are set on the slider.</summary> /// <summary>The glyph and the attribute used for options (ticks) that are set on the linear range.</summary>
public Cell SetChar { get; set; } public Cell SetChar { get; set; }
/// <summary>The glyph and the attribute used for spaces between options (ticks) on the slider.</summary> /// <summary>The glyph and the attribute used for spaces between options (ticks) on the linear range.</summary>
public Cell SpaceChar { get; set; } public Cell SpaceChar { get; set; }
/// <summary>The glyph and the attribute used for the start of ranges on the slider.</summary> /// <summary>The glyph and the attribute used for the start of ranges on the linear range.</summary>
public Cell StartRangeChar { get; set; } public Cell StartRangeChar { get; set; }
} }

View File

@@ -1,7 +1,7 @@
namespace Terminal.Gui.Views; namespace Terminal.Gui.Views;
/// <summary><see cref="Slider{T}"/> Types</summary> /// <summary><see cref="LinearRange{T}"/> Types</summary>
public enum SliderType public enum LinearRangeType
{ {
/// <summary> /// <summary>
/// <code> /// <code>

View File

@@ -1,51 +0,0 @@
#nullable disable
namespace Terminal.Gui.Views;
/// <summary>Represents an option in a <see cref="Slider{T}"/> .</summary>
/// <typeparam name="T">Data type of the option.</typeparam>
public class SliderOption<T>
{
/// <summary>Creates a new empty instance of the <see cref="SliderOption{T}"/> class.</summary>
public SliderOption () { }
/// <summary>Creates a new instance of the <see cref="SliderOption{T}"/> class with values for each property.</summary>
public SliderOption (string legend, Rune legendAbbr, T data)
{
Legend = legend;
LegendAbbr = legendAbbr;
Data = data;
}
/// <summary>Event fired when an option has changed.</summary>
public event EventHandler<SliderOptionEventArgs> Changed;
/// <summary>Custom data of the option.</summary>
public T Data { get; set; }
/// <summary>Legend of the option.</summary>
public string Legend { get; set; }
/// <summary>
/// Abbreviation of the Legend. When the <see cref="Slider{T}.MinimumInnerSpacing"/> too small to fit
/// <see cref="Legend"/>.
/// </summary>
public Rune LegendAbbr { get; set; }
/// <summary>Event Raised when this option is set.</summary>
public event EventHandler<SliderOptionEventArgs> Set;
/// <summary>Creates a human-readable string that represents this <see cref="SliderOption{T}"/>.</summary>
public override string ToString () { return "{Legend=" + Legend + ", LegendAbbr=" + LegendAbbr + ", Data=" + Data + "}"; }
/// <summary>Event Raised when this option is unset.</summary>
public event EventHandler<SliderOptionEventArgs> UnSet;
/// <summary>To Raise the <see cref="Changed"/> event from the Slider.</summary>
internal void OnChanged (bool isSet) { Changed?.Invoke (this, new (isSet)); }
/// <summary>To Raise the <see cref="Set"/> event from the Slider.</summary>
internal void OnSet () { Set?.Invoke (this, new (true)); }
/// <summary>To Raise the <see cref="UnSet"/> event from the Slider.</summary>
internal void OnUnSet () { UnSet?.Invoke (this, new (false)); }
}

View File

@@ -1,13 +0,0 @@
#nullable disable
namespace Terminal.Gui.Views;
/// <summary><see cref="EventArgs"/> for <see cref="Slider{T}"/> <see cref="SliderOption{T}"/> events.</summary>
public class SliderOptionEventArgs : EventArgs
{
/// <summary>Initializes a new instance of <see cref="SliderOptionEventArgs"/></summary>
/// <param name="isSet"> indicates whether the option is set</param>
public SliderOptionEventArgs (bool isSet) { IsSet = isSet; }
/// <summary>Gets whether the option is set or not.</summary>
public bool IsSet { get; }
}

View File

@@ -0,0 +1,144 @@
using TerminalGuiFluentTesting;
using Xunit.Abstractions;
namespace IntegrationTests.FluentTests;
public class LinearRangeFluentTests (ITestOutputHelper outputHelper)
{
private readonly TextWriter _out = new TestOutputWriter (outputHelper);
[Theory]
[ClassData (typeof (TestDrivers))]
public void LinearRange_CanCreateAndRender (TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d, _out)
.Add (
new LinearRange<int> (new() { 0, 10, 20, 30, 40, 50 })
{
X = 2,
Y = 2,
Type = LinearRangeType.Single
})
.Focus<LinearRange<int>> ()
.WaitIteration ()
.ScreenShot ("LinearRange initial render", _out)
.Stop ();
}
[Theory]
[ClassData (typeof (TestDrivers))]
public void LinearRange_CanNavigateWithArrowKeys (TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d, _out)
.Add (
new LinearRange<int> (new() { 0, 10, 20, 30 })
{
X = 2,
Y = 2,
Type = LinearRangeType.Single,
AllowEmpty = false
})
.Focus<LinearRange<int>> ()
.WaitIteration ()
.ScreenShot ("Initial state", _out)
.EnqueueKeyEvent (Key.CursorRight)
.WaitIteration ()
.ScreenShot ("After right arrow", _out)
.EnqueueKeyEvent (Key.CursorRight)
.WaitIteration ()
.ScreenShot ("After second right arrow", _out)
.Stop ();
}
[Theory]
[ClassData (typeof (TestDrivers))]
public void LinearRange_TypeChange_TriggersEvents (TestDriver d)
{
LinearRange<int> linearRange = new (new() { 0, 10, 20, 30 })
{
X = 2,
Y = 2,
Type = LinearRangeType.Single
};
var changingEventRaised = false;
var changedEventRaised = false;
linearRange.TypeChanging += (_, args) =>
{
changingEventRaised = true;
Assert.Equal (LinearRangeType.Single, args.CurrentValue);
Assert.Equal (LinearRangeType.Range, args.NewValue);
};
linearRange.TypeChanged += (_, args) =>
{
changedEventRaised = true;
Assert.Equal (LinearRangeType.Single, args.OldValue);
Assert.Equal (LinearRangeType.Range, args.NewValue);
};
// Change the type before adding to window
linearRange.Type = LinearRangeType.Range;
using GuiTestContext c = With.A<Window> (80, 25, d, _out)
.Add (linearRange)
.Focus<LinearRange<int>> ()
.WaitIteration ()
.ScreenShot ("After type change to Range", _out)
.Stop ();
Assert.True (changingEventRaised);
Assert.True (changedEventRaised);
Assert.Equal (LinearRangeType.Range, linearRange.Type);
}
[Theory]
[ClassData (typeof (TestDrivers))]
public void LinearRange_RangeType_CanSelectRange (TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d, _out)
.Add (
new LinearRange<int> (new() { 0, 10, 20, 30, 40 })
{
X = 2,
Y = 2,
Type = LinearRangeType.Range,
AllowEmpty = false
})
.Focus<LinearRange<int>> ()
.WaitIteration ()
.ScreenShot ("Range type initial", _out)
.EnqueueKeyEvent (Key.Space)
.WaitIteration ()
.ScreenShot ("After first selection", _out)
.EnqueueKeyEvent (Key.CursorRight.WithCtrl)
.WaitIteration ()
.EnqueueKeyEvent (Key.CursorRight.WithCtrl)
.WaitIteration ()
.ScreenShot ("After extending range", _out)
.Stop ();
}
[Theory]
[ClassData (typeof (TestDrivers))]
public void LinearRange_VerticalOrientation_Renders (TestDriver d)
{
using GuiTestContext c = With.A<Window> (80, 25, d, _out)
.Add (
new LinearRange<int> (new() { 0, 10, 20, 30 })
{
X = 2,
Y = 2,
Orientation = Orientation.Vertical,
Type = LinearRangeType.Single
})
.Focus<LinearRange<int>> ()
.WaitIteration ()
.ScreenShot ("Vertical orientation", _out)
.EnqueueKeyEvent (Key.CursorDown)
.WaitIteration ()
.ScreenShot ("After down arrow", _out)
.Stop ();
}
}

View File

@@ -1,10 +1,6 @@
#nullable enable namespace ViewBaseTests.Adornments;
using UnitTests;
using Xunit.Abstractions;
namespace ViewBaseTests.Adornments; public class PaddingTests
public class PaddingTests (ITestOutputHelper output)
{ {
[Fact] [Fact]
public void Constructor_Defaults () public void Constructor_Defaults ()
@@ -21,5 +17,4 @@ public class PaddingTests (ITestOutputHelper output)
View view = new () { Height = 3, Width = 3 }; View view = new () { Height = 3, Width = 3 };
Assert.Equal (Thickness.Empty, view.Padding!.Thickness); Assert.Equal (Thickness.Empty, view.Padding!.Thickness);
} }
} }

View File

@@ -3,13 +3,13 @@ using UnitTests;
namespace ViewsTests; namespace ViewsTests;
public class SliderOptionTests : FakeDriverBase public class LinearRangeOptionTests : FakeDriverBase
{ {
[Fact] [Fact]
public void OnChanged_Should_Raise_ChangedEvent () public void OnChanged_Should_Raise_ChangedEvent ()
{ {
// Arrange // Arrange
SliderOption<int> sliderOption = new (); LinearRangeOption<int> sliderOption = new ();
var eventRaised = false; var eventRaised = false;
sliderOption.Changed += (sender, args) => eventRaised = true; sliderOption.Changed += (sender, args) => eventRaised = true;
@@ -24,7 +24,7 @@ public class SliderOptionTests : FakeDriverBase
public void OnSet_Should_Raise_SetEvent () public void OnSet_Should_Raise_SetEvent ()
{ {
// Arrange // Arrange
SliderOption<int> sliderOption = new (); LinearRangeOption<int> sliderOption = new ();
var eventRaised = false; var eventRaised = false;
sliderOption.Set += (sender, args) => eventRaised = true; sliderOption.Set += (sender, args) => eventRaised = true;
@@ -39,7 +39,7 @@ public class SliderOptionTests : FakeDriverBase
public void OnUnSet_Should_Raise_UnSetEvent () public void OnUnSet_Should_Raise_UnSetEvent ()
{ {
// Arrange // Arrange
SliderOption<int> sliderOption = new (); LinearRangeOption<int> sliderOption = new ();
var eventRaised = false; var eventRaised = false;
sliderOption.UnSet += (sender, args) => eventRaised = true; sliderOption.UnSet += (sender, args) => eventRaised = true;
@@ -51,42 +51,42 @@ public class SliderOptionTests : FakeDriverBase
} }
[Fact] [Fact]
public void Slider_Option_Default_Constructor () public void LinearRange_Option_Default_Constructor ()
{ {
SliderOption<int> o = new (); LinearRangeOption<int> o = new ();
Assert.Null (o.Legend); Assert.Null (o.Legend);
Assert.Equal (default (Rune), o.LegendAbbr); Assert.Equal (default (Rune), o.LegendAbbr);
Assert.Equal (default (int), o.Data); Assert.Equal (default (int), o.Data);
} }
[Fact] [Fact]
public void Slider_Option_Values_Constructor () public void LinearRange_Option_Values_Constructor ()
{ {
SliderOption<int> o = new ("1 thousand", new ('y'), 1000); LinearRangeOption<int> o = new ("1 thousand", new ('y'), 1000);
Assert.Equal ("1 thousand", o.Legend); Assert.Equal ("1 thousand", o.Legend);
Assert.Equal (new ('y'), o.LegendAbbr); Assert.Equal (new ('y'), o.LegendAbbr);
Assert.Equal (1000, o.Data); Assert.Equal (1000, o.Data);
} }
[Fact] [Fact]
public void SliderOption_ToString_WhenEmpty () public void LinearRangeOption_ToString_WhenEmpty ()
{ {
SliderOption<object> sliderOption = new (); LinearRangeOption<object> sliderOption = new ();
Assert.Equal ("{Legend=, LegendAbbr=\0, Data=}", sliderOption.ToString ()); Assert.Equal ("{Legend=, LegendAbbr=\0, Data=}", sliderOption.ToString ());
} }
[Fact] [Fact]
public void SliderOption_ToString_WhenPopulated_WithInt () public void LinearRangeOption_ToString_WhenPopulated_WithInt ()
{ {
SliderOption<int> sliderOption = new () { Legend = "Lord flibble", LegendAbbr = new ('l'), Data = 1 }; LinearRangeOption<int> sliderOption = new () { Legend = "Lord flibble", LegendAbbr = new ('l'), Data = 1 };
Assert.Equal ("{Legend=Lord flibble, LegendAbbr=l, Data=1}", sliderOption.ToString ()); Assert.Equal ("{Legend=Lord flibble, LegendAbbr=l, Data=1}", sliderOption.ToString ());
} }
[Fact] [Fact]
public void SliderOption_ToString_WhenPopulated_WithSizeF () public void LinearRangeOption_ToString_WhenPopulated_WithSizeF ()
{ {
SliderOption<SizeF> sliderOption = new () LinearRangeOption<SizeF> sliderOption = new ()
{ {
Legend = "Lord flibble", LegendAbbr = new ('l'), Data = new (32, 11) Legend = "Lord flibble", LegendAbbr = new ('l'), Data = new (32, 11)
}; };
@@ -95,17 +95,17 @@ public class SliderOptionTests : FakeDriverBase
} }
} }
public class SliderEventArgsTests : FakeDriverBase public class LinearRangeEventArgsTests : FakeDriverBase
{ {
[Fact] [Fact]
public void Constructor_Sets_Cancel_Default_To_False () public void Constructor_Sets_Cancel_Default_To_False ()
{ {
// Arrange // Arrange
Dictionary<int, SliderOption<int>> options = new (); Dictionary<int, LinearRangeOption<int>> options = new ();
var focused = 42; var focused = 42;
// Act // Act
SliderEventArgs<int> sliderEventArgs = new (options, focused); LinearRangeEventArgs<int> sliderEventArgs = new (options, focused);
// Assert // Assert
Assert.False (sliderEventArgs.Cancel); Assert.False (sliderEventArgs.Cancel);
@@ -115,11 +115,11 @@ public class SliderEventArgsTests : FakeDriverBase
public void Constructor_Sets_Focused () public void Constructor_Sets_Focused ()
{ {
// Arrange // Arrange
Dictionary<int, SliderOption<int>> options = new (); Dictionary<int, LinearRangeOption<int>> options = new ();
var focused = 42; var focused = 42;
// Act // Act
SliderEventArgs<int> sliderEventArgs = new (options, focused); LinearRangeEventArgs<int> sliderEventArgs = new (options, focused);
// Assert // Assert
Assert.Equal (focused, sliderEventArgs.Focused); Assert.Equal (focused, sliderEventArgs.Focused);
@@ -129,23 +129,23 @@ public class SliderEventArgsTests : FakeDriverBase
public void Constructor_Sets_Options () public void Constructor_Sets_Options ()
{ {
// Arrange // Arrange
Dictionary<int, SliderOption<int>> options = new (); Dictionary<int, LinearRangeOption<int>> options = new ();
// Act // Act
SliderEventArgs<int> sliderEventArgs = new (options); LinearRangeEventArgs<int> sliderEventArgs = new (options);
// Assert // Assert
Assert.Equal (options, sliderEventArgs.Options); Assert.Equal (options, sliderEventArgs.Options);
} }
} }
public class SliderTests : FakeDriverBase public class LinearRangeTests : FakeDriverBase
{ {
[Fact] [Fact]
public void Constructor_Default () public void Constructor_Default ()
{ {
// Arrange & Act // Arrange & Act
Slider<int> slider = new (); LinearRange<int> slider = new ();
// Assert // Assert
Assert.NotNull (slider); Assert.NotNull (slider);
@@ -155,7 +155,7 @@ public class SliderTests : FakeDriverBase
Assert.False (slider.AllowEmpty); Assert.False (slider.AllowEmpty);
Assert.True (slider.ShowLegends); Assert.True (slider.ShowLegends);
Assert.False (slider.ShowEndSpacing); Assert.False (slider.ShowEndSpacing);
Assert.Equal (SliderType.Single, slider.Type); Assert.Equal (LinearRangeType.Single, slider.Type);
Assert.Equal (1, slider.MinimumInnerSpacing); Assert.Equal (1, slider.MinimumInnerSpacing);
Assert.True (slider.Width is DimAuto); Assert.True (slider.Width is DimAuto);
Assert.True (slider.Height is DimAuto); Assert.True (slider.Height is DimAuto);
@@ -169,15 +169,15 @@ public class SliderTests : FakeDriverBase
List<int> options = new () { 1, 2, 3 }; List<int> options = new () { 1, 2, 3 };
// Act // Act
Slider<int> slider = new (options); LinearRange<int> slider = new (options);
slider.SetRelativeLayout (new (100, 100)); slider.SetRelativeLayout (new (100, 100));
// Assert // Assert
// 0123456789 // 0123456789
// 1 2 3 // 1 2 3
Assert.Equal (1, slider.MinimumInnerSpacing); Assert.Equal (1, slider.MinimumInnerSpacing);
Assert.Equal (new Size (5, 2), slider.GetContentSize ()); Assert.Equal (new (5, 2), slider.GetContentSize ());
Assert.Equal (new Size (5, 2), slider.Frame.Size); Assert.Equal (new (5, 2), slider.Frame.Size);
Assert.NotNull (slider); Assert.NotNull (slider);
Assert.NotNull (slider.Options); Assert.NotNull (slider.Options);
Assert.Equal (options.Count, slider.Options.Count); Assert.Equal (options.Count, slider.Options.Count);
@@ -187,7 +187,7 @@ public class SliderTests : FakeDriverBase
public void MovePlus_Should_MoveFocusRight_When_OptionIsAvailable () public void MovePlus_Should_MoveFocusRight_When_OptionIsAvailable ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
// Act // Act
bool result = slider.MovePlus (); bool result = slider.MovePlus ();
@@ -201,7 +201,7 @@ public class SliderTests : FakeDriverBase
public void MovePlus_Should_NotMoveFocusRight_When_AtEnd () public void MovePlus_Should_NotMoveFocusRight_When_AtEnd ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
slider.FocusedOption = 3; slider.FocusedOption = 3;
@@ -217,7 +217,7 @@ public class SliderTests : FakeDriverBase
public void OnOptionFocused_Event_Cancelled () public void OnOptionFocused_Event_Cancelled ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3 }); LinearRange<int> slider = new (new () { 1, 2, 3 });
var eventRaised = false; var eventRaised = false;
var cancel = false; var cancel = false;
slider.OptionFocused += (sender, args) => eventRaised = true; slider.OptionFocused += (sender, args) => eventRaised = true;
@@ -226,7 +226,7 @@ public class SliderTests : FakeDriverBase
// Create args with cancel set to false // Create args with cancel set to false
cancel = false; cancel = false;
SliderEventArgs<int> args = LinearRangeEventArgs<int> args =
new (new (), newFocusedOption) { Cancel = cancel }; new (new (), newFocusedOption) { Cancel = cancel };
Assert.Equal (0, slider.FocusedOption); Assert.Equal (0, slider.FocusedOption);
@@ -257,11 +257,11 @@ public class SliderTests : FakeDriverBase
public void OnOptionFocused_Event_Raised () public void OnOptionFocused_Event_Raised ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3 }); LinearRange<int> slider = new (new () { 1, 2, 3 });
var eventRaised = false; var eventRaised = false;
slider.OptionFocused += (sender, args) => eventRaised = true; slider.OptionFocused += (sender, args) => eventRaised = true;
var newFocusedOption = 1; var newFocusedOption = 1;
SliderEventArgs<int> args = new (new (), newFocusedOption); LinearRangeEventArgs<int> args = new (new (), newFocusedOption);
// Act // Act
slider.OnOptionFocused (newFocusedOption, args); slider.OnOptionFocused (newFocusedOption, args);
@@ -274,7 +274,7 @@ public class SliderTests : FakeDriverBase
public void OnOptionsChanged_Event_Raised () public void OnOptionsChanged_Event_Raised ()
{ {
// Arrange // Arrange
Slider<int> slider = new (); LinearRange<int> slider = new ();
var eventRaised = false; var eventRaised = false;
slider.OptionsChanged += (sender, args) => eventRaised = true; slider.OptionsChanged += (sender, args) => eventRaised = true;
@@ -289,7 +289,7 @@ public class SliderTests : FakeDriverBase
public void Set_Should_Not_UnSetFocusedOption_When_EmptyNotAllowed () public void Set_Should_Not_UnSetFocusedOption_When_EmptyNotAllowed ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }) { AllowEmpty = false }; LinearRange<int> slider = new (new () { 1, 2, 3, 4 }) { AllowEmpty = false };
Assert.NotEmpty (slider.GetSetOptions ()); Assert.NotEmpty (slider.GetSetOptions ());
@@ -307,7 +307,7 @@ public class SliderTests : FakeDriverBase
public void Set_Should_SetFocusedOption () public void Set_Should_SetFocusedOption ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
// Act // Act
slider.FocusedOption = 2; slider.FocusedOption = 2;
@@ -323,7 +323,7 @@ public class SliderTests : FakeDriverBase
public void TryGetOptionByPosition_InvalidPosition_Failure () public void TryGetOptionByPosition_InvalidPosition_Failure ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3 }); LinearRange<int> slider = new (new () { 1, 2, 3 });
var x = 10; var x = 10;
var y = 10; var y = 10;
var threshold = 2; var threshold = 2;
@@ -347,7 +347,8 @@ public class SliderTests : FakeDriverBase
public void TryGetOptionByPosition_ValidPositionHorizontal_Success (int x, int y, int threshold, int expectedData) public void TryGetOptionByPosition_ValidPositionHorizontal_Success (int x, int y, int threshold, int expectedData)
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
// 0123456789 // 0123456789
// 1234 // 1234
@@ -376,7 +377,7 @@ public class SliderTests : FakeDriverBase
public void TryGetOptionByPosition_ValidPositionVertical_Success (int x, int y, int threshold, int expectedData) public void TryGetOptionByPosition_ValidPositionVertical_Success (int x, int y, int threshold, int expectedData)
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
slider.Orientation = Orientation.Vertical; slider.Orientation = Orientation.Vertical;
// Set auto size to true to enable testing // Set auto size to true to enable testing
@@ -405,7 +406,7 @@ public class SliderTests : FakeDriverBase
public void TryGetPositionByOption_InvalidOption_Failure () public void TryGetPositionByOption_InvalidOption_Failure ()
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3 }); LinearRange<int> slider = new (new () { 1, 2, 3 });
int option = -1; int option = -1;
(int, int) expectedPosition = (-1, -1); (int, int) expectedPosition = (-1, -1);
@@ -424,7 +425,7 @@ public class SliderTests : FakeDriverBase
public void TryGetPositionByOption_ValidOptionHorizontal_Success (int option, int expectedX, int expectedY) public void TryGetPositionByOption_ValidOptionHorizontal_Success (int option, int expectedX, int expectedY)
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
// Set auto size to true to enable testing // Set auto size to true to enable testing
slider.MinimumInnerSpacing = 2; slider.MinimumInnerSpacing = 2;
@@ -448,7 +449,7 @@ public class SliderTests : FakeDriverBase
public void TryGetPositionByOption_ValidOptionVertical_Success (int option, int expectedX, int expectedY) public void TryGetPositionByOption_ValidOptionVertical_Success (int option, int expectedX, int expectedY)
{ {
// Arrange // Arrange
Slider<int> slider = new (new () { 1, 2, 3, 4 }); LinearRange<int> slider = new (new () { 1, 2, 3, 4 });
slider.Orientation = Orientation.Vertical; slider.Orientation = Orientation.Vertical;
// Set auto size to true to enable testing // Set auto size to true to enable testing
@@ -468,32 +469,12 @@ public class SliderTests : FakeDriverBase
private void One_Option_Does_Not_Throw () private void One_Option_Does_Not_Throw ()
{ {
// Arrange // Arrange
Slider<int> slider = new (); LinearRange<int> slider = new ();
slider.BeginInit (); slider.BeginInit ();
slider.EndInit (); slider.EndInit ();
// Act/Assert // Act/Assert
slider.Options = new () { new () }; slider.Options = [new ()];
}
[Fact]
private void Set_Options_No_Legend_Throws ()
{
// Arrange
Slider<int> slider = new ();
// Act/Assert
Assert.Throws<ArgumentNullException> (() => slider.Options = null);
}
[Fact]
private void Set_Options_Throws_If_Null ()
{
// Arrange
Slider<int> slider = new ();
// Act/Assert
Assert.Throws<ArgumentNullException> (() => slider.Options = null);
} }
[Fact] [Fact]
@@ -505,12 +486,12 @@ public class SliderTests : FakeDriverBase
Height = Dim.Fill () Height = Dim.Fill ()
}; };
List<object> options = new () { "01234", "01234" }; List<object> options = ["01234", "01234"];
Slider slider = new (options) LinearRange slider = new (options)
{ {
Orientation = Orientation.Vertical, Orientation = Orientation.Vertical,
Type = SliderType.Multiple, Type = LinearRangeType.Multiple
}; };
view.Add (slider); view.Add (slider);
view.BeginInit (); view.BeginInit ();
@@ -539,10 +520,10 @@ public class SliderTests : FakeDriverBase
List<object> options = new () { "01234", "01234" }; List<object> options = new () { "01234", "01234" };
Slider slider = new (options) LinearRange slider = new (options)
{ {
Orientation = Orientation.Vertical, Orientation = Orientation.Vertical,
Type = SliderType.Multiple, Type = LinearRangeType.Multiple,
Height = 10 Height = 10
}; };
view.Add (slider); view.Add (slider);
@@ -572,11 +553,11 @@ public class SliderTests : FakeDriverBase
List<object> options = new () { "01234", "01234" }; List<object> options = new () { "01234", "01234" };
Slider slider = new (options) LinearRange slider = new (options)
{ {
Orientation = Orientation.Vertical, Orientation = Orientation.Vertical,
Type = SliderType.Multiple, Type = LinearRangeType.Multiple,
Width = 10, Width = 10
}; };
view.Add (slider); view.Add (slider);
view.BeginInit (); view.BeginInit ();
@@ -596,3 +577,254 @@ public class SliderTests : FakeDriverBase
// Add more tests for different scenarios and edge cases. // Add more tests for different scenarios and edge cases.
} }
public class LinearRangeCWPTests : FakeDriverBase
{
[Fact]
public void Type_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = LinearRangeType.Single;
var newValue = LinearRangeType.Range;
linearRange.TypeChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.TypeChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.Type = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.Type);
}
[Fact]
public void Type_PropertyChange_CanBeCancelled ()
{
// Arrange
LinearRange<int> linearRange = new ();
LinearRangeType oldValue = linearRange.Type;
linearRange.TypeChanging += (sender, args) => { args.Handled = true; };
// Act
linearRange.Type = LinearRangeType.Range;
// Assert
Assert.Equal (oldValue, linearRange.Type);
}
[Fact]
public void LegendsOrientation_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = Orientation.Horizontal;
var newValue = Orientation.Vertical;
linearRange.LegendsOrientationChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.LegendsOrientationChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.LegendsOrientation = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.LegendsOrientation);
}
[Fact]
public void MinimumInnerSpacing_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = 1;
var newValue = 5;
linearRange.MinimumInnerSpacingChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.MinimumInnerSpacingChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.MinimumInnerSpacing = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.MinimumInnerSpacing);
}
[Fact]
public void ShowLegends_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = true;
var newValue = false;
linearRange.ShowLegendsChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.ShowLegendsChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.ShowLegends = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.ShowLegends);
}
[Fact]
public void ShowEndSpacing_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = false;
var newValue = true;
linearRange.ShowEndSpacingChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.ShowEndSpacingChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.ShowEndSpacing = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.ShowEndSpacing);
}
[Fact]
public void UseMinimumSize_PropertyChange_RaisesChangingAndChangedEvents ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
var oldValue = false;
var newValue = true;
linearRange.UseMinimumSizeChanging += (sender, args) =>
{
changingRaised = true;
Assert.Equal (oldValue, args.CurrentValue);
Assert.Equal (newValue, args.NewValue);
};
linearRange.UseMinimumSizeChanged += (sender, args) =>
{
changedRaised = true;
Assert.Equal (oldValue, args.OldValue);
Assert.Equal (newValue, args.NewValue);
};
// Act
linearRange.UseMinimumSize = newValue;
// Assert
Assert.True (changingRaised);
Assert.True (changedRaised);
Assert.Equal (newValue, linearRange.UseMinimumSize);
}
[Fact]
public void Type_PropertyChange_NoEventsWhenValueUnchanged ()
{
// Arrange
LinearRange<int> linearRange = new ();
var changingRaised = false;
var changedRaised = false;
linearRange.TypeChanging += (sender, args) => changingRaised = true;
linearRange.TypeChanged += (sender, args) => changedRaised = true;
// Act
linearRange.Type = linearRange.Type;
// Assert
Assert.False (changingRaised);
Assert.False (changedRaised);
}
[Fact]
public void Type_PropertyChange_ChangingEventCanModifyNewValue ()
{
// Arrange
LinearRange<int> linearRange = new ();
var modifiedValue = LinearRangeType.Multiple;
linearRange.TypeChanging += (sender, args) => { args.NewValue = modifiedValue; };
// Act
linearRange.Type = LinearRangeType.Range;
// Assert
Assert.Equal (modifiedValue, linearRange.Type);
}
}