mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Gradient tests
This commit is contained in:
@@ -44,15 +44,42 @@ public class Gradient
|
||||
private readonly List<int> _steps;
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="Gradient"/> class which hosts a <see cref="Spectrum"/>
|
||||
/// of colors including all <paramref name="stops"/> and <paramref name="steps"/> interpolated colors
|
||||
/// between each corresponding pair.
|
||||
/// </summary>
|
||||
/// <param name="stops">The colors to use in the spectrum (N)</param>
|
||||
/// <param name="steps">The number of colors to generate between each pair (must be N-1 numbers).
|
||||
/// If only one step is passed then it is assumed to be the same distance for all pairs.</param>
|
||||
/// <param name="loop">True to duplicate the first stop and step so that the gradient repeats itself</param>
|
||||
/// <exception cref="ArgumentException"></exception>
|
||||
public Gradient (IEnumerable<Color> stops, IEnumerable<int> steps, bool loop = false)
|
||||
{
|
||||
_stops = stops.ToList ();
|
||||
|
||||
if (_stops.Count < 1)
|
||||
{
|
||||
throw new ArgumentException ("At least one color stop must be provided.");
|
||||
}
|
||||
|
||||
_steps = steps.ToList ();
|
||||
|
||||
// If multiple colors and only 1 step assume same distance applies to all steps
|
||||
if (_stops.Count > 2 && _steps.Count == 1)
|
||||
{
|
||||
_steps = Enumerable.Repeat (_steps.Single (),_stops.Count() - 1).ToList();
|
||||
}
|
||||
|
||||
if (_steps.Any (step => step < 1))
|
||||
{
|
||||
throw new ArgumentException ("Steps must be greater than 0.");
|
||||
}
|
||||
|
||||
if (_steps.Count != _stops.Count - 1)
|
||||
{
|
||||
throw new ArgumentException ("Number of steps must be N-1");
|
||||
}
|
||||
|
||||
_loop = loop;
|
||||
Spectrum = GenerateGradient (_steps);
|
||||
@@ -85,6 +112,7 @@ public class Gradient
|
||||
private List<Color> GenerateGradient (IEnumerable<int> steps)
|
||||
{
|
||||
List<Color> gradient = new List<Color> ();
|
||||
|
||||
if (_stops.Count == 1)
|
||||
{
|
||||
for (int i = 0; i < steps.Sum (); i++)
|
||||
@@ -94,13 +122,17 @@ public class Gradient
|
||||
return gradient;
|
||||
}
|
||||
|
||||
var stopsToUse = _stops.ToList ();
|
||||
var stepsToUse = _steps.ToList ();
|
||||
|
||||
if (_loop)
|
||||
{
|
||||
_stops.Add (_stops [0]);
|
||||
stopsToUse.Add (_stops [0]);
|
||||
stepsToUse.Add (_steps.First ());
|
||||
}
|
||||
|
||||
var colorPairs = _stops.Zip (_stops.Skip (1), (start, end) => new { start, end });
|
||||
var stepsList = _steps.ToList ();
|
||||
var colorPairs = stopsToUse.Zip (stopsToUse.Skip (1), (start, end) => new { start, end });
|
||||
var stepsList = stepsToUse;
|
||||
|
||||
foreach (var (colorPair, thesteps) in colorPairs.Zip (stepsList, (pair, step) => (pair, step)))
|
||||
{
|
||||
@@ -112,7 +144,7 @@ public class Gradient
|
||||
|
||||
private IEnumerable<Color> InterpolateColors (Color start, Color end, int steps)
|
||||
{
|
||||
for (int step = 0; step <= steps; step++)
|
||||
for (int step = 0; step < steps; step++)
|
||||
{
|
||||
double fraction = (double)step / steps;
|
||||
int r = (int)(start.R + fraction * (end.R - start.R));
|
||||
@@ -120,8 +152,10 @@ public class Gradient
|
||||
int b = (int)(start.B + fraction * (end.B - start.B));
|
||||
yield return new Color (r, g, b);
|
||||
}
|
||||
yield return end; // Ensure the last color is included
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// <para>
|
||||
/// Creates a mapping starting at 0,0 and going to <paramref name="maxRow"/> and <paramref name="maxColumn"/>
|
||||
|
||||
@@ -14,6 +14,8 @@ public class TextEffectsScenario : Scenario
|
||||
{
|
||||
private TabView tabView;
|
||||
|
||||
public static bool LoopingGradient = false;
|
||||
|
||||
public override void Main ()
|
||||
{
|
||||
Application.Init ();
|
||||
@@ -27,8 +29,6 @@ public class TextEffectsScenario : Scenario
|
||||
w.Loaded += (s, e) =>
|
||||
{
|
||||
SetupGradientLineCanvas (w, w.Frame.Size);
|
||||
// TODO: Does not work
|
||||
// SetupGradientLineCanvas (tabView, tabView.Frame.Size);
|
||||
};
|
||||
w.SizeChanging += (s, e) =>
|
||||
{
|
||||
@@ -36,9 +36,6 @@ public class TextEffectsScenario : Scenario
|
||||
{
|
||||
SetupGradientLineCanvas (w, e.Size.Value);
|
||||
}
|
||||
|
||||
// TODO: Does not work
|
||||
//SetupGradientLineCanvas (tabView, tabView.Frame.Size);
|
||||
};
|
||||
|
||||
w.ColorScheme = new ColorScheme
|
||||
@@ -57,16 +54,32 @@ public class TextEffectsScenario : Scenario
|
||||
Height = Dim.Fill (),
|
||||
};
|
||||
|
||||
var gradientsView = new GradientsView ()
|
||||
{
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill (),
|
||||
};
|
||||
var t1 = new Tab ()
|
||||
{
|
||||
View = new GradientsView ()
|
||||
{
|
||||
Width = Dim.Fill (),
|
||||
Height = Dim.Fill (),
|
||||
},
|
||||
View = gradientsView,
|
||||
DisplayText = "Gradients"
|
||||
};
|
||||
|
||||
|
||||
var cbLooping = new CheckBox ()
|
||||
{
|
||||
Text = "Looping",
|
||||
Y = Pos.AnchorEnd (1)
|
||||
};
|
||||
cbLooping.Toggle += (s, e) =>
|
||||
{
|
||||
LoopingGradient = e.NewValue == CheckState.Checked;
|
||||
SetupGradientLineCanvas (w, w.Frame.Size);
|
||||
tabView.SetNeedsDisplay ();
|
||||
};
|
||||
|
||||
gradientsView.Add (cbLooping);
|
||||
|
||||
tabView.AddTab (t1, false);
|
||||
|
||||
w.Add (tabView);
|
||||
@@ -83,7 +96,7 @@ public class TextEffectsScenario : Scenario
|
||||
{
|
||||
GetAppealingGradientColors (out var stops, out var steps);
|
||||
|
||||
var g = new Gradient (stops, steps);
|
||||
var g = new Gradient (stops, steps, LoopingGradient);
|
||||
|
||||
var fore = new GradientFill (
|
||||
new Rectangle (0, 0, size.Width, size.Height), g, GradientDirection.Diagonal);
|
||||
@@ -107,7 +120,8 @@ public class TextEffectsScenario : Scenario
|
||||
};
|
||||
|
||||
// Define the number of steps between each color for smoother transitions
|
||||
steps = new List<int> { 15, 15, 15, 15 };
|
||||
// If we pass only a single value then it will assume equal steps between all pairs
|
||||
steps = new List<int> { 15 };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +171,7 @@ internal class GradientsView : View
|
||||
var steps = new List<int> { 10, 10 }; // 10 steps between Red -> Green, and Green -> Blue
|
||||
|
||||
// Create the gradient
|
||||
var radialGradient = new Gradient (stops, steps, loop: false);
|
||||
var radialGradient = new Gradient (stops, steps, loop: TextEffectsScenario.LoopingGradient);
|
||||
|
||||
// Define the size of the rectangle
|
||||
int maxRow = 15; // Adjusted to keep aspect ratio
|
||||
@@ -207,7 +221,7 @@ internal class GradientsView : View
|
||||
};
|
||||
|
||||
// Create the gradient
|
||||
var rainbowGradient = new Gradient (stops, steps, loop: true);
|
||||
var rainbowGradient = new Gradient (stops, steps, TextEffectsScenario.LoopingGradient);
|
||||
|
||||
for (int x = 0; x < viewport.Width; x++)
|
||||
{
|
||||
|
||||
@@ -50,4 +50,126 @@ public class GradientTests
|
||||
Assert.Equal (c.Key, new Point(0,0));
|
||||
Assert.Equal (c.Value, new Color (0, 0, 255));
|
||||
}
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void SingleColorStop ()
|
||||
{
|
||||
var stops = new List<Color> { new Color (255, 0, 0) }; // Red
|
||||
var steps = new List<int> { };
|
||||
|
||||
var g = new Gradient (stops, steps, loop: false);
|
||||
Assert.All (g.Spectrum, color => Assert.Equal (new Color (255, 0, 0), color));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void LoopingGradient_CorrectColors ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var steps = new List<int> { 10 };
|
||||
|
||||
var g = new Gradient (stops, steps, loop: true);
|
||||
Assert.Equal (new Color (255, 0, 0), g.Spectrum.First ());
|
||||
Assert.Equal (new Color (255, 0, 0), g.Spectrum.Last ());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void DifferentStepSizes ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 255, 0), // Green
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var steps = new List<int> { 5, 15 }; // Different steps
|
||||
|
||||
var g = new Gradient (stops, steps, loop: false);
|
||||
Assert.Equal (22, g.Spectrum.Count);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void FractionOutOfRange_ThrowsException ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var steps = new List<int> { 10 };
|
||||
|
||||
var g = new Gradient (stops, steps, loop: false);
|
||||
|
||||
Assert.Throws<ArgumentOutOfRangeException> (() => g.GetColorAtFraction (-0.1));
|
||||
Assert.Throws<ArgumentOutOfRangeException> (() => g.GetColorAtFraction (1.1));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void NaNFraction_ReturnsLastColor ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var steps = new List<int> { 10 };
|
||||
|
||||
var g = new Gradient (stops, steps, loop: false);
|
||||
Assert.Equal (new Color (0, 0, 255), g.GetColorAtFraction (double.NaN));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_SingleStepProvided_ReplicatesForAllPairs ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 255, 0), // Green
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var singleStep = new List<int> { 5 }; // Single step provided
|
||||
var gradient = new Gradient (stops, singleStep, loop: false);
|
||||
|
||||
Assert.NotNull (gradient.Spectrum);
|
||||
Assert.Equal (12, gradient.Spectrum.Count); // 5 steps Red -> Green + 5 steps Green -> Blue + 2 end colors
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_InvalidStepsLength_ThrowsArgumentException ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var invalidSteps = new List<int> { 5, 5 }; // Invalid length (N-1 expected)
|
||||
Assert.Throws<ArgumentException> (() => new Gradient (stops, invalidSteps, loop: false));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Constructor_ValidStepsLength_DoesNotThrow ()
|
||||
{
|
||||
var stops = new List<Color>
|
||||
{
|
||||
new Color(255, 0, 0), // Red
|
||||
new Color(0, 255, 0), // Green
|
||||
new Color(0, 0, 255) // Blue
|
||||
};
|
||||
|
||||
var validSteps = new List<int> { 5, 5 }; // Valid length (N-1)
|
||||
var gradient = new Gradient (stops, validSteps, loop: false);
|
||||
|
||||
Assert.NotNull (gradient.Spectrum);
|
||||
Assert.Equal (12, gradient.Spectrum.Count); // 5 steps Red -> Green + 5 steps Green -> Blue + 2 end colors
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user