Browse Source

Fixes #3098 & #3099 - Slider bugs (#3121)

* Fixed bugs

* Fixed #3098

* Fixed a slew of issues

* Fixed a slew more of issues

* Code cleanup. Fixed unit test failure

* Code cleanup.

* Code cleanup.

* Code cleanup.
Tig 1 year ago
parent
commit
c6570a5bfd
6 changed files with 513 additions and 450 deletions
  1. 23 1
      .editorconfig
  2. 2 2
      Terminal.Gui/View/ViewDrawing.cs
  3. 269 260
      Terminal.Gui/Views/Slider.cs
  4. 1 0
      Terminal.sln
  5. 152 145
      UICatalog/Scenarios/Sliders.cs
  6. 66 42
      UnitTests/Views/SliderTests.cs

+ 23 - 1
.editorconfig

@@ -27,14 +27,24 @@ csharp_style_var_elsewhere = true:none
 
 # ReSharper properties
 resharper_align_linq_query = true
+resharper_align_multiline_binary_patterns = true
 resharper_align_multiline_calls_chain = true
 resharper_align_multiline_extends_list = true
 resharper_align_multiline_parameter = true
 resharper_blank_lines_around_region = 1
 resharper_braces_redundant = true
+resharper_csharp_alignment_tab_fill_style = optimal_fill
+resharper_csharp_max_line_length = 200
 resharper_csharp_stick_comment = false
+resharper_csharp_wrap_parameters_style = chop_if_long
 resharper_force_attribute_style = separate
 resharper_indent_type_constraints = true
+#resharper_int_align_binary_expressions = true
+resharper_int_align_comments = true
+resharper_int_align_invocations = true
+resharper_int_align_nested_ternary = true
+resharper_int_align_switch_expressions = true
+resharper_int_align_switch_sections = true
 resharper_local_function_body = expression_body
 resharper_remove_blank_lines_near_braces_in_declarations = true
 resharper_use_roslyn_logic_for_evident_types = true
@@ -82,7 +92,19 @@ csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
 csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
 csharp_style_prefer_not_pattern = true:suggestion
 csharp_style_prefer_extended_property_pattern = true:suggestion
-csharp_style_var_for_built_in_types = false:silent
+csharp_style_var_for_built_in_types = true:none
+resharper_wrap_before_linq_expression = true
+resharper_wrap_chained_binary_expressions = chop_if_long
+resharper_wrap_chained_binary_patterns = chop_if_long
+resharper_xmldoc_indent_size = 2
+resharper_xmldoc_indent_style = space
+resharper_xmldoc_indent_text = DoNotTouch
+resharper_xmldoc_linebreaks_inside_tags_for_elements_longer_than = 120
+resharper_xmldoc_max_blank_lines_between_tags = 1
+resharper_xmldoc_max_line_length = 100
+resharper_xmldoc_space_before_self_closing = false
+resharper_xmldoc_tab_width = 2
+resharper_xmldoc_use_indent_from_vs = true
 
 [*.{cs,vb}]
 dotnet_style_operator_placement_when_wrapping = beginning_of_line

+ 2 - 2
Terminal.Gui/View/ViewDrawing.cs

@@ -291,12 +291,12 @@ public partial class View {
 	/// <param name="row">the row to move to, in view-relative coordinates.</param>
 	public void Move (int col, int row)
 	{
-		if (Driver.Rows == 0) {
+		if (Driver == null || Driver?.Rows == 0) {
 			return;
 		}
 
 		BoundsToScreen (col, row, out int rCol, out int rRow, false);
-		Driver.Move (rCol, rRow);
+		Driver?.Move (rCol, rRow);
 	}
 
 	/// <summary>

File diff suppressed because it is too large
+ 269 - 260
Terminal.Gui/Views/Slider.cs


+ 1 - 0
Terminal.sln

@@ -14,6 +14,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Example", "Example\Example.
 EndProject
 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{E143FB1F-0B88-48CB-9086-72CDCECFCD22}"
 	ProjectSection(SolutionItems) = preProject
+		.editorconfig = .editorconfig
 		.gitignore = .gitignore
 		.github\workflows\api-docs.yml = .github\workflows\api-docs.yml
 		.github\CODEOWNERS = .github\CODEOWNERS

+ 152 - 145
UICatalog/Scenarios/Sliders.cs

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

+ 66 - 42
UnitTests/Views/SliderTests.cs

@@ -1,16 +1,11 @@
-using Xunit;
-using Terminal.Gui;
-using System;
+using System;
 using System.Collections.Generic;
-using System.Linq;
 using System.Text;
-using System.Threading.Tasks;
+using Xunit;
 
 namespace Terminal.Gui.ViewsTests;
 
 public class SliderOptionTests {
-
-
 	[Fact]
 	public void Slider_Option_Default_Constructor ()
 	{
@@ -24,9 +19,9 @@ public class SliderOptionTests {
 	public void Slider_Option_Values_Constructor ()
 	{
 		var o = new SliderOption<int> ("1 thousand", new Rune ('y'), 1000);
-		Assert.Equal ("1 thousand", o.Legend);
+		Assert.Equal ("1 thousand",   o.Legend);
 		Assert.Equal (new Rune ('y'), o.LegendAbbr);
-		Assert.Equal (1000, o.Data);
+		Assert.Equal (1000,           o.Data);
 	}
 
 	[Fact]
@@ -87,7 +82,7 @@ public class SliderOptionTests {
 		var sliderOption = new SliderOption<int> {
 			Legend = "Lord flibble",
 			LegendAbbr = new Rune ('l'),
-			Data = 1,
+			Data = 1
 		};
 
 		Assert.Equal ("{Legend=Lord flibble, LegendAbbr=l, Data=1}", sliderOption.ToString ());
@@ -100,7 +95,7 @@ public class SliderOptionTests {
 		var sliderOption = new SliderOption<SizeF> {
 			Legend = "Lord flibble",
 			LegendAbbr = new Rune ('l'),
-			Data = new SizeF(32,11),
+			Data = new SizeF (32, 11)
 		};
 
 		Assert.Equal ("{Legend=Lord flibble, LegendAbbr=l, Data={Width=32, Height=11}}", sliderOption.ToString ());
@@ -150,7 +145,6 @@ public class SliderEventArgsTests {
 	}
 }
 
-
 public class SliderTests {
 	[Fact]
 	public void Constructor_Default ()
@@ -165,9 +159,9 @@ public class SliderTests {
 		Assert.Equal (Orientation.Horizontal, slider.Orientation);
 		Assert.False (slider.AllowEmpty);
 		Assert.True (slider.ShowLegends);
-		Assert.False (slider.ShowSpacing);
+		Assert.False (slider.ShowEndSpacing);
 		Assert.Equal (SliderType.Single, slider.Type);
-		Assert.Equal (0, slider.InnerSpacing);
+		Assert.Equal (0,                 slider.InnerSpacing);
 		Assert.False (slider.AutoSize);
 		Assert.Equal (0, slider.FocusedOption);
 	}
@@ -192,7 +186,7 @@ public class SliderTests {
 	{
 		// Arrange
 		var slider = new Slider<int> ();
-		bool eventRaised = false;
+		var eventRaised = false;
 		slider.OptionsChanged += (sender, args) => eventRaised = true;
 
 		// Act
@@ -207,9 +201,9 @@ public class SliderTests {
 	{
 		// Arrange
 		var slider = new Slider<int> (new List<int> { 1, 2, 3 });
-		bool eventRaised = false;
+		var eventRaised = false;
 		slider.OptionFocused += (sender, args) => eventRaised = true;
-		int newFocusedOption = 1;
+		var newFocusedOption = 1;
 		var args = new SliderEventArgs<int> (new Dictionary<int, SliderOption<int>> (), newFocusedOption);
 
 		// Act
@@ -224,10 +218,10 @@ public class SliderTests {
 	{
 		// Arrange
 		var slider = new Slider<int> (new List<int> { 1, 2, 3 });
-		bool eventRaised = false;
-		bool cancel = false;
+		var eventRaised = false;
+		var cancel = false;
 		slider.OptionFocused += (sender, args) => eventRaised = true;
-		int newFocusedOption = 1;
+		var newFocusedOption = 1;
 
 		// Create args with cancel set to false
 		cancel = false;
@@ -240,7 +234,7 @@ public class SliderTests {
 		slider.OnOptionFocused (newFocusedOption, args);
 
 		// Assert
-		Assert.True (eventRaised); // Event should be raised
+		Assert.True (eventRaised);                             // Event should be raised
 		Assert.Equal (newFocusedOption, slider.FocusedOption); // Focused option should change
 
 		// Create args with cancel set to true
@@ -253,7 +247,7 @@ public class SliderTests {
 		slider.OnOptionFocused (2, args);
 
 		// Assert
-		Assert.True (eventRaised); // Event should be raised
+		Assert.True (eventRaised);                             // Event should be raised
 		Assert.Equal (newFocusedOption, slider.FocusedOption); // Focused option should not change
 	}
 
@@ -271,7 +265,7 @@ public class SliderTests {
 		// 1--2--3--4
 
 		// Act
-		bool result = slider.TryGetPositionByOption (option, out var position);
+		var result = slider.TryGetPositionByOption (option, out var position);
 
 		// Assert
 		Assert.True (result);
@@ -292,7 +286,7 @@ public class SliderTests {
 		slider.InnerSpacing = 2;
 
 		// Act
-		bool result = slider.TryGetPositionByOption (option, out var position);
+		var result = slider.TryGetPositionByOption (option, out var position);
 
 		// Assert
 		Assert.True (result);
@@ -305,11 +299,11 @@ public class SliderTests {
 	{
 		// Arrange
 		var slider = new Slider<int> (new List<int> { 1, 2, 3 });
-		int option = -1;
+		var option = -1;
 		var expectedPosition = (-1, -1);
 
 		// Act
-		bool result = slider.TryGetPositionByOption (option, out var position);
+		var result = slider.TryGetPositionByOption (option, out var position);
 
 		// Assert
 		Assert.False (result);
@@ -335,7 +329,7 @@ public class SliderTests {
 		// Arrange
 
 		// Act
-		bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
+		var result = slider.TryGetOptionByPosition (x, y, threshold, out var option);
 
 		// Assert
 		Assert.True (result);
@@ -366,12 +360,9 @@ public class SliderTests {
 		// 7 |
 		// 8 |
 		// 9 4
-		slider.CalcSpacingConfig ();
-
-		// Arrange
 
 		// Act
-		bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
+		var result = slider.TryGetOptionByPosition (x, y, threshold, out var option);
 
 		// Assert
 		Assert.True (result);
@@ -384,13 +375,13 @@ public class SliderTests {
 	{
 		// Arrange
 		var slider = new Slider<int> (new List<int> { 1, 2, 3 });
-		int x = 10;
-		int y = 10;
-		int threshold = 2;
-		int expectedOption = -1;
+		var x = 10;
+		var y = 10;
+		var threshold = 2;
+		var expectedOption = -1;
 
 		// Act
-		bool result = slider.TryGetOptionByPosition (x, y, threshold, out int option);
+		var result = slider.TryGetOptionByPosition (x, y, threshold, out var option);
 
 		// Assert
 		Assert.False (result);
@@ -405,7 +396,7 @@ public class SliderTests {
 		slider.AutoSize = true;
 
 		// Act
-		bool result = slider.MovePlus ();
+		var result = slider.MovePlus ();
 
 		// Assert
 		Assert.True (result);
@@ -421,7 +412,7 @@ public class SliderTests {
 		slider.FocusedOption = 3;
 
 		// Act
-		bool result = slider.MovePlus ();
+		var result = slider.MovePlus ();
 
 		// Assert
 		Assert.False (result);
@@ -439,7 +430,7 @@ public class SliderTests {
 
 		// Act
 		slider.FocusedOption = 2;
-		bool result = slider.Set ();
+		var result = slider.Set ();
 
 		// Assert
 		Assert.True (result);
@@ -459,14 +450,47 @@ public class SliderTests {
 		Assert.NotEmpty (slider.GetSetOptions ());
 
 		// Act
-		bool result = slider.UnSetOption (slider.FocusedOption);
+		var result = slider.UnSetOption (slider.FocusedOption);
 
 		// Assert
 		Assert.False (result);
 		Assert.NotEmpty (slider.GetSetOptions ());
 	}
 
-	// Add more tests for different scenarios and edge cases.
-}
+	[Fact]
+	void Set_Options_Throws_If_Null ()
+	{
+		// Arrange
+		var slider = new Slider<int> ();
+
+		// Act/Assert
+		Assert.Throws<ArgumentNullException> (() => slider.Options = null);
+
+	}
+
+	[Fact]
+	void Set_Options_No_Legend_Throws ()
+	{
+		// Arrange
+		var slider = new Slider<int> ();
+
+		// Act/Assert
+		Assert.Throws<ArgumentNullException> (() => slider.Options = null);
+
+	}
+
+	// https://github.com/gui-cs/Terminal.Gui/issues/3099
+	[Fact]
+	void One_Option_Does_Not_Throw ()
+	{
+		// Arrange
+		var slider = new Slider<int> ();
+		slider.BeginInit ();
+		slider.EndInit ();
+		// Act/Assert
+		slider.Options = new List<SliderOption<int>> { new () };
 
+	}
 
+	// Add more tests for different scenarios and edge cases.
+}

Some files were not shown because too many files changed in this diff