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
{
Title = "Slider - Example of a DimAuto View",
Title = "LinearRange - Example of a DimAuto View",
};
List<object> options = new () { "One", "Two", "Three", "Four" };
Slider slider = new (options)
LinearRange linearRange = new (options)
{
X = 0,
Y = 0,
Type = SliderType.Multiple,
Type = LinearRangeType.Multiple,
AllowEmpty = false,
BorderStyle = LineStyle.Double,
Title = "_Slider"
Title = "_LinearRange"
};
sliderFrameView.Add (slider);
sliderFrameView.Add (linearRange);
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,
Y = Pos.Bottom (optionSelectorShortcut),
Width = Dim.Fill ()! - Dim.Width (eventLog),
HelpText = "Sliders work!",
CommandView = new Slider<string>
HelpText = "LinearRanges work!",
CommandView = new LinearRange<string>
{
Orientation = Orientation.Horizontal,
AllowEmpty = true
@@ -238,13 +238,13 @@ public class Shortcuts : Scenario
Key = Key.F5
};
((Slider<string>)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }];
((Slider<string>)sliderShortcut.CommandView).SetOption (0);
((LinearRange<string>)sliderShortcut.CommandView).Options = [new () { Legend = "A" }, new () { Legend = "B" }, new () { Legend = "C" }];
((LinearRange<string>)sliderShortcut.CommandView).SetOption (0);
((Slider<string>)sliderShortcut.CommandView).OptionsChanged += (o, args) =>
((LinearRange<string>)sliderShortcut.CommandView).OptionsChanged += (o, args) =>
{
eventSource.Add (
$"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((Slider<string>)o!)!.GetSetOptions ())}");
$"OptionsChanged: {o?.GetType ().Name} - {string.Join (",", ((LinearRange<string>)o!)!.GetSetOptions ())}");
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" };
Slider slider = new (options)
LinearRange linearRange = new (options)
{
X = 0,
Y = Pos.Bottom (textField) + 1,
Orientation = Orientation.Vertical,
Type = SliderType.Multiple,
Type = LinearRangeType.Multiple,
AllowEmpty = false,
BorderStyle = LineStyle.Double,
Title = "_Slider"
Title = "_LinearRange"
};
view.Add (slider);
view.Add (linearRange);
adornmentsEditor.Initialized += (s, e) =>
{