From cbcf4b5186e2be1cebfb2b96589c7a1cf59c40f3 Mon Sep 17 00:00:00 2001 From: tznind Date: Sun, 7 Jul 2024 10:18:28 +0100 Subject: [PATCH] Remove everything except gradient --- Terminal.Gui/Drawing/FillPair.cs | 2 +- .../Graphics.cs => Drawing/Gradient.cs} | 77 +-- Terminal.Gui/Drawing/GradientFill.cs | 24 + .../{TextEffects/New => Drawing}/SolidFill.cs | 8 +- Terminal.Gui/TextEffects/Animation.cs | 502 ------------------ Terminal.Gui/TextEffects/ArgValidators.cs | 266 ---------- Terminal.Gui/TextEffects/BaseCharacter.cs | 109 ---- Terminal.Gui/TextEffects/BaseEffect.cs | 60 --- Terminal.Gui/TextEffects/Easing.cs | 303 ----------- Terminal.Gui/TextEffects/EffectTemplate.cs | 13 - Terminal.Gui/TextEffects/Effects/Beams.cs | 241 --------- Terminal.Gui/TextEffects/Geometry.cs | 137 ----- Terminal.Gui/TextEffects/HexTerm.cs | 94 ---- Terminal.Gui/TextEffects/Motion.cs | 253 --------- Terminal.Gui/TextEffects/New/GradientFill.cs | 35 -- Terminal.Gui/TextEffects/Terminal.cs | 106 ---- UICatalog/Scenarios/TextEffectsScenario.cs | 289 +--------- UnitTests/TextEffects/AnimationTests.cs | 191 ------- .../TextEffects/New/GradientFillTests.cs | 8 +- 19 files changed, 65 insertions(+), 2653 deletions(-) rename Terminal.Gui/{TextEffects/Graphics.cs => Drawing/Gradient.cs} (63%) create mode 100644 Terminal.Gui/Drawing/GradientFill.cs rename Terminal.Gui/{TextEffects/New => Drawing}/SolidFill.cs (55%) delete mode 100644 Terminal.Gui/TextEffects/Animation.cs delete mode 100644 Terminal.Gui/TextEffects/ArgValidators.cs delete mode 100644 Terminal.Gui/TextEffects/BaseCharacter.cs delete mode 100644 Terminal.Gui/TextEffects/BaseEffect.cs delete mode 100644 Terminal.Gui/TextEffects/Easing.cs delete mode 100644 Terminal.Gui/TextEffects/EffectTemplate.cs delete mode 100644 Terminal.Gui/TextEffects/Effects/Beams.cs delete mode 100644 Terminal.Gui/TextEffects/Geometry.cs delete mode 100644 Terminal.Gui/TextEffects/HexTerm.cs delete mode 100644 Terminal.Gui/TextEffects/Motion.cs delete mode 100644 Terminal.Gui/TextEffects/New/GradientFill.cs delete mode 100644 Terminal.Gui/TextEffects/Terminal.cs delete mode 100644 UnitTests/TextEffects/AnimationTests.cs diff --git a/Terminal.Gui/Drawing/FillPair.cs b/Terminal.Gui/Drawing/FillPair.cs index 41eb2b426..f51ceec65 100644 --- a/Terminal.Gui/Drawing/FillPair.cs +++ b/Terminal.Gui/Drawing/FillPair.cs @@ -1,5 +1,5 @@  -using Terminal.Gui.TextEffects; +using Terminal.Gui.Drawing; namespace Terminal.Gui; diff --git a/Terminal.Gui/TextEffects/Graphics.cs b/Terminal.Gui/Drawing/Gradient.cs similarity index 63% rename from Terminal.Gui/TextEffects/Graphics.cs rename to Terminal.Gui/Drawing/Gradient.cs index 03fb2059a..b5d58e34a 100644 --- a/Terminal.Gui/TextEffects/Graphics.cs +++ b/Terminal.Gui/Drawing/Gradient.cs @@ -1,59 +1,8 @@ -namespace Terminal.Gui.TextEffects; +namespace Terminal.Gui; using System; using System.Collections.Generic; using System.Linq; -public class Color -{ - public string RgbColor { get; private set; } - public int? XtermColor { get; private set; } - - public Color (string rgbColor) - { - if (!ColorUtils.IsValidHexColor (rgbColor)) - throw new ArgumentException ("Invalid RGB hex color format."); - - RgbColor = rgbColor.StartsWith ("#") ? rgbColor.Substring (1).ToUpper () : rgbColor.ToUpper (); - XtermColor = ColorUtils.HexToXterm (RgbColor); // Convert RGB to XTerm-256 - } - - public Color (int xtermColor) - { - if (!ColorUtils.IsValidXtermColor (xtermColor)) - throw new ArgumentException ("Invalid XTerm-256 color code."); - - XtermColor = xtermColor; - RgbColor = ColorUtils.XtermToHex (xtermColor); // Perform the actual conversion - } - public int R => Convert.ToInt32 (RgbColor.Substring (0, 2), 16); - public int G => Convert.ToInt32 (RgbColor.Substring (2, 2), 16); - public int B => Convert.ToInt32 (RgbColor.Substring (4, 2), 16); - - public (int R, int G, int B) GetRgbInts () - { - return ( - Convert.ToInt32 (RgbColor.Substring (0, 2), 16), - Convert.ToInt32 (RgbColor.Substring (2, 2), 16), - Convert.ToInt32 (RgbColor.Substring (4, 2), 16) - ); - } - - public override string ToString () => $"#{RgbColor}"; - - public static Color FromRgb (int r, int g, int b) - { - // Validate the RGB values to ensure they are within the 0-255 range - if (r < 0 || r > 255 || g < 0 || g > 255 || b < 0 || b > 255) - throw new ArgumentOutOfRangeException ("RGB values must be between 0 and 255."); - - // Convert RGB values to a hexadecimal string - string rgbColor = $"#{r:X2}{g:X2}{b:X2}"; - - // Create and return a new Color instance using the hexadecimal string - return new Color (rgbColor); - } -} - public class Gradient { public List Spectrum { get; private set; } @@ -127,13 +76,13 @@ public class Gradient int r = (int)(start.R + fraction * (end.R - start.R)); int g = (int)(start.G + fraction * (end.G - start.G)); int b = (int)(start.B + fraction * (end.B - start.B)); - yield return Color.FromRgb (r, g, b); + yield return new Color (r, g, b); } } - public Dictionary BuildCoordinateColorMapping (int maxRow, int maxColumn, Direction direction) + public Dictionary BuildCoordinateColorMapping (int maxRow, int maxColumn, Direction direction) { - var gradientMapping = new Dictionary (); + var gradientMapping = new Dictionary (); switch (direction) { @@ -144,7 +93,7 @@ public class Gradient Color color = GetColorAtFraction (fraction); for (int col = 0; col <= maxColumn; col++) { - gradientMapping [new Coord (col, row)] = color; + gradientMapping [new Point (col, row)] = color; } } break; @@ -156,7 +105,7 @@ public class Gradient Color color = GetColorAtFraction (fraction); for (int row = 0; row <= maxRow; row++) { - gradientMapping [new Coord (col, row)] = color; + gradientMapping [new Point (col, row)] = color; } } break; @@ -166,9 +115,9 @@ public class Gradient { for (int col = 0; col <= maxColumn; col++) { - double distanceFromCenter = FindNormalizedDistanceFromCenter (maxRow, maxColumn, new Coord (col, row)); + double distanceFromCenter = FindNormalizedDistanceFromCenter (maxRow, maxColumn, new Point (col, row)); Color color = GetColorAtFraction (distanceFromCenter); - gradientMapping [new Coord (col, row)] = color; + gradientMapping [new Point (col, row)] = color; } } break; @@ -178,9 +127,9 @@ public class Gradient { for (int col = 0; col <= maxColumn; col++) { - double fraction = ((double)row * 2 + col) / ((maxRow * 2) + maxColumn); + double fraction = ((double)row * 2 + col) / (maxRow * 2 + maxColumn); Color color = GetColorAtFraction (fraction); - gradientMapping [new Coord (col, row)] = color; + gradientMapping [new Point (col, row)] = color; } } break; @@ -189,12 +138,12 @@ public class Gradient return gradientMapping; } - private double FindNormalizedDistanceFromCenter (int maxRow, int maxColumn, Coord coord) + private double FindNormalizedDistanceFromCenter (int maxRow, int maxColumn, Point coord) { double centerX = maxColumn / 2.0; double centerY = maxRow / 2.0; - double dx = coord.Column - centerX; - double dy = coord.Row - centerY; + double dx = coord.X - centerX; + double dy = coord.Y - centerY; double distance = Math.Sqrt (dx * dx + dy * dy); double maxDistance = Math.Sqrt (centerX * centerX + centerY * centerY); return distance / maxDistance; diff --git a/Terminal.Gui/Drawing/GradientFill.cs b/Terminal.Gui/Drawing/GradientFill.cs new file mode 100644 index 000000000..d0bf163da --- /dev/null +++ b/Terminal.Gui/Drawing/GradientFill.cs @@ -0,0 +1,24 @@ +namespace Terminal.Gui; + +/// +/// Implementation of that uses a color gradient (including +/// radial, diagonal etc). +/// +public class GradientFill : IFill +{ + private Dictionary _map; + + public GradientFill (Rectangle area, Gradient gradient, Gradient.Direction direction) + { + _map = gradient.BuildCoordinateColorMapping (area.Height, area.Width, direction); + } + + public Color GetColor (Point point) + { + if (_map.TryGetValue (point, out var color)) + { + return color; + } + return new Color (0, 0, 0); // Default to black if point not found + } +} \ No newline at end of file diff --git a/Terminal.Gui/TextEffects/New/SolidFill.cs b/Terminal.Gui/Drawing/SolidFill.cs similarity index 55% rename from Terminal.Gui/TextEffects/New/SolidFill.cs rename to Terminal.Gui/Drawing/SolidFill.cs index 4bcc174f5..202cec57c 100644 --- a/Terminal.Gui/TextEffects/New/SolidFill.cs +++ b/Terminal.Gui/Drawing/SolidFill.cs @@ -1,4 +1,4 @@ -namespace Terminal.Gui.TextEffects; +namespace Terminal.Gui.Drawing; /// @@ -6,13 +6,13 @@ /// public class SolidFill : IFill { - readonly Terminal.Gui.Color _color; + readonly Color _color; - public SolidFill (Terminal.Gui.Color color) + public SolidFill (Color color) { _color = color; } - public Gui.Color GetColor (Point point) + public Color GetColor (Point point) { return _color; } diff --git a/Terminal.Gui/TextEffects/Animation.cs b/Terminal.Gui/TextEffects/Animation.cs deleted file mode 100644 index a96f08a9e..000000000 --- a/Terminal.Gui/TextEffects/Animation.cs +++ /dev/null @@ -1,502 +0,0 @@ - -using static Terminal.Gui.TextEffects.EventHandler; - -namespace Terminal.Gui.TextEffects; - -public enum SyncMetric -{ - Distance, - Step -} -public class CharacterVisual -{ - public string Symbol { get; set; } - public bool Bold { get; set; } - public bool Dim { get; set; } - public bool Italic { get; set; } - public bool Underline { get; set; } - public bool Blink { get; set; } - public bool Reverse { get; set; } - public bool Hidden { get; set; } - public bool Strike { get; set; } - public Color Color { get; set; } - public string FormattedSymbol { get; private set; } - private string _colorCode; // Holds the ANSI color code or similar string directly - - public string ColorCode => _colorCode; - - public CharacterVisual (string symbol, bool bold = false, bool dim = false, bool italic = false, bool underline = false, bool blink = false, bool reverse = false, bool hidden = false, bool strike = false, Color color = null, string colorCode = null) - { - Symbol = symbol; - Bold = bold; - Dim = dim; - Italic = italic; - Underline = underline; - Blink = blink; - Reverse = reverse; - Hidden = hidden; - Strike = strike; - Color = color; - _colorCode = colorCode; // Initialize _colorCode from the constructor argument - FormattedSymbol = FormatSymbol (); - } - - private string FormatSymbol () - { - string formattingString = ""; - if (Bold) formattingString += Ansitools.ApplyBold (); - if (Italic) formattingString += Ansitools.ApplyItalic (); - if (Underline) formattingString += Ansitools.ApplyUnderline (); - if (Blink) formattingString += Ansitools.ApplyBlink (); - if (Reverse) formattingString += Ansitools.ApplyReverse (); - if (Hidden) formattingString += Ansitools.ApplyHidden (); - if (Strike) formattingString += Ansitools.ApplyStrikethrough (); - if (_colorCode != null) formattingString += Colorterm.Fg (_colorCode); // Use the direct color code - - return $"{formattingString}{Symbol}{(formattingString != "" ? Ansitools.ResetAll () : "")}"; - } - - public void DisableModes () - { - Bold = false; - Dim = false; - Italic = false; - Underline = false; - Blink = false; - Reverse = false; - Hidden = false; - Strike = false; - } -} - - -public class Frame -{ - public CharacterVisual CharacterVisual { get; } - public int Duration { get; } - public int TicksElapsed { get; set; } - - public Frame (CharacterVisual characterVisual, int duration) - { - CharacterVisual = characterVisual; - Duration = duration; - TicksElapsed = 0; - } - - public void IncrementTicks () - { - TicksElapsed++; - } -} - -public class Scene -{ - public string SceneId { get; } - public bool IsLooping { get; } - public SyncMetric? Sync { get; } - public EasingFunction Ease { get; } - public bool NoColor { get; set; } - public bool UseXtermColors { get; set; } - public List Frames { get; } = new List (); - public List PlayedFrames { get; } = new List (); - public Dictionary FrameIndexMap { get; } = new Dictionary (); - public int EasingTotalSteps { get; set; } - public int EasingCurrentStep { get; set; } - public static Dictionary XtermColorMap { get; } = new Dictionary (); - - public Scene (string sceneId, bool isLooping = false, SyncMetric? sync = null, EasingFunction ease = null, bool noColor = false, bool useXtermColors = false) - { - SceneId = sceneId; - IsLooping = isLooping; - Sync = sync; - Ease = ease; - NoColor = noColor; - UseXtermColors = useXtermColors; - EasingTotalSteps = 0; - EasingCurrentStep = 0; - } - - public void AddFrame (string symbol, int duration, Color color = null, bool bold = false, bool dim = false, bool italic = false, bool underline = false, bool blink = false, bool reverse = false, bool hidden = false, bool strike = false) - { - string charVisColor = null; - if (color != null) - { - if (NoColor) - { - charVisColor = null; - } - else if (UseXtermColors && color.XtermColor.HasValue) - { - charVisColor = color.XtermColor.Value.ToString (); - } - else if (color.RgbColor != null && XtermColorMap.ContainsKey (color.RgbColor)) - { - charVisColor = XtermColorMap [color.RgbColor].ToString (); - } - else - { - charVisColor = color.RgbColor; - } - } - - if (duration < 1) - throw new ArgumentException ("Duration must be greater than 0."); - - var characterVisual = new CharacterVisual (symbol, bold, dim, italic, underline, blink, reverse, hidden, strike, color, charVisColor); - var frame = new Frame (characterVisual, duration); - Frames.Add (frame); - for (int i = 0; i < frame.Duration; i++) - { - FrameIndexMap [EasingTotalSteps] = frame; - EasingTotalSteps++; - } - } - - public CharacterVisual Activate () - { - if (Frames.Count == 0) - throw new InvalidOperationException ("Scene has no frames."); - EasingCurrentStep = 0; - return Frames [0].CharacterVisual; - } - - public CharacterVisual GetNextVisual () - { - if (Frames.Count == 0) - return null; - - var frame = Frames [0]; - if (++EasingCurrentStep >= frame.Duration) - { - EasingCurrentStep = 0; - PlayedFrames.Add (frame); - Frames.RemoveAt (0); - if (IsLooping && Frames.Count == 0) - { - Frames.AddRange (PlayedFrames); - PlayedFrames.Clear (); - } - if (Frames.Count > 0) - return Frames [0].CharacterVisual; - } - return frame.CharacterVisual; - } - - public void ApplyGradientToSymbols (Gradient gradient, IList symbols, int duration) - { - int lastIndex = 0; - for (int symbolIndex = 0; symbolIndex < symbols.Count; symbolIndex++) - { - var symbol = symbols [symbolIndex]; - double symbolProgress = (symbolIndex + 1) / (double)symbols.Count; - int gradientIndex = (int)(symbolProgress * gradient.Spectrum.Count); - foreach (var color in gradient.Spectrum.GetRange (lastIndex, Math.Max (gradientIndex - lastIndex, 1))) - { - AddFrame (symbol, duration, color); - } - lastIndex = gradientIndex; - } - } - - public void ResetScene () - { - EasingCurrentStep = 0; - Frames.Clear (); - Frames.AddRange (PlayedFrames); - PlayedFrames.Clear (); - } - - public override bool Equals (object obj) - { - return obj is Scene other && SceneId == other.SceneId; - } - - public override int GetHashCode () - { - return SceneId.GetHashCode (); - } -} - -public class Animation -{ - public Dictionary Scenes { get; } = new Dictionary (); - public EffectCharacter Character { get; } - public Scene ActiveScene { get; private set; } - public bool UseXtermColors { get; set; } = false; - public bool NoColor { get; set; } = false; - public Dictionary XtermColorMap { get; } = new Dictionary (); - public int ActiveSceneCurrentStep { get; private set; } = 0; - public CharacterVisual CurrentCharacterVisual { get; private set; } - - public Animation (EffectCharacter character) - { - Character = character; - CurrentCharacterVisual = new CharacterVisual (character.InputSymbol); - } - - public Scene NewScene (bool isLooping = false, SyncMetric? sync = null, EasingFunction ease = null, string id = "") - { - if (string.IsNullOrEmpty (id)) - { - bool foundUnique = false; - int currentId = Scenes.Count; - while (!foundUnique) - { - id = $"{Scenes.Count}"; - if (!Scenes.ContainsKey (id)) - { - foundUnique = true; - } - else - { - currentId++; - } - } - } - - var newScene = new Scene (id, isLooping, sync, ease); - Scenes [id] = newScene; - newScene.NoColor = NoColor; - newScene.UseXtermColors = UseXtermColors; - return newScene; - } - - public Scene QueryScene (string sceneId) - { - if (!Scenes.TryGetValue (sceneId, out var scene)) - { - throw new ArgumentException ($"Scene {sceneId} does not exist."); - } - return scene; - } - - public bool ActiveSceneIsComplete () - { - if (ActiveScene == null) - { - return true; - } - return ActiveScene.Frames.Count == 0 && !ActiveScene.IsLooping; - } - - public void SetAppearance (string symbol, Color? color = null) - { - string charVisColor = null; - if (color != null) - { - if (NoColor) - { - charVisColor = null; - } - else if (UseXtermColors) - { - charVisColor = color.XtermColor.ToString(); - } - else - { - charVisColor = color.RgbColor; - } - } - CurrentCharacterVisual = new CharacterVisual (symbol, color: color, colorCode: charVisColor); - } - - public static Color RandomColor () - { - var random = new Random (); - var colorHex = random.Next (0, 0xFFFFFF).ToString ("X6"); - return new Color (colorHex); - } - - public static Color AdjustColorBrightness (Color color, float brightness) - { - float HueToRgb (float p, float q, float t) - { - if (t < 0) t += 1; - if (t > 1) t -= 1; - if (t < 1 / 6f) return p + (q - p) * 6 * t; - if (t < 1 / 2f) return q; - if (t < 2 / 3f) return p + (q - p) * (2 / 3f - t) * 6; - return p; - } - - float r = int.Parse (color.RgbColor.Substring (0, 2), System.Globalization.NumberStyles.HexNumber) / 255f; - float g = int.Parse (color.RgbColor.Substring (2, 2), System.Globalization.NumberStyles.HexNumber) / 255f; - float b = int.Parse (color.RgbColor.Substring (4, 2), System.Globalization.NumberStyles.HexNumber) / 255f; - - float max = Math.Max (r, Math.Max (g, b)); - float min = Math.Min (r, Math.Min (g, b)); - float h, s, l = (max + min) / 2f; - - if (max == min) - { - h = s = 0; // achromatic - } - else - { - float d = max - min; - s = l > 0.5f ? d / (2f - max - min) : d / (max + min); - if (max == r) - { - h = (g - b) / d + (g < b ? 6 : 0); - } - else if (max == g) - { - h = (b - r) / d + 2; - } - else - { - h = (r - g) / d + 4; - } - h /= 6; - } - - l = Math.Max (Math.Min (l * brightness, 1), 0); - - if (s == 0) - { - r = g = b = l; // achromatic - } - else - { - float q = l < 0.5f ? l * (1 + s) : l + s - l * s; - float p = 2 * l - q; - r = HueToRgb (p, q, h + 1 / 3f); - g = HueToRgb (p, q, h); - b = HueToRgb (p, q, h - 1 / 3f); - } - - var adjustedColor = $"{(int)(r * 255):X2}{(int)(g * 255):X2}{(int)(b * 255):X2}"; - return new Color (adjustedColor); - } - - private float EaseAnimation (EasingFunction easingFunc) - { - if (ActiveScene == null) - { - return 0; - } - float elapsedStepRatio = ActiveScene.EasingCurrentStep / (float)ActiveScene.EasingTotalSteps; - return easingFunc (elapsedStepRatio); - } - - public void StepAnimation () - { - if (ActiveScene != null && ActiveScene.Frames.Count > 0) - { - if (ActiveScene.Sync != null) - { - if (Character.Motion.ActivePath != null) - { - int sequenceIndex = 0; - if (ActiveScene.Sync == SyncMetric.Step) - { - sequenceIndex = (int)Math.Round ((ActiveScene.Frames.Count - 1) * - (Math.Max (Character.Motion.ActivePath.CurrentStep, 1) / - (float)Math.Max (Character.Motion.ActivePath.MaxSteps, 1))); - } - else if (ActiveScene.Sync == SyncMetric.Distance) - { - sequenceIndex = (int)Math.Round ((ActiveScene.Frames.Count - 1) * - (Math.Max (Math.Max (Character.Motion.ActivePath.TotalDistance, 1) - - Math.Max (Character.Motion.ActivePath.TotalDistance - - Character.Motion.ActivePath.LastDistanceReached, 1), 1) / - (float)Math.Max (Character.Motion.ActivePath.TotalDistance, 1))); - } - try - { - CurrentCharacterVisual = ActiveScene.Frames [sequenceIndex].CharacterVisual; - } - catch (IndexOutOfRangeException) - { - CurrentCharacterVisual = ActiveScene.Frames [^1].CharacterVisual; - } - } - else - { - CurrentCharacterVisual = ActiveScene.Frames [^1].CharacterVisual; - ActiveScene.PlayedFrames.AddRange (ActiveScene.Frames); - ActiveScene.Frames.Clear (); - } - } - else if (ActiveScene.Ease != null) - { - float easingFactor = EaseAnimation (ActiveScene.Ease); - int frameIndex = (int)Math.Round (easingFactor * Math.Max (ActiveScene.EasingTotalSteps - 1, 0)); - frameIndex = Math.Max (Math.Min (frameIndex, ActiveScene.EasingTotalSteps - 1), 0); - Frame frame = ActiveScene.FrameIndexMap [frameIndex]; - CurrentCharacterVisual = frame.CharacterVisual; - ActiveScene.EasingCurrentStep++; - if (ActiveScene.EasingCurrentStep == ActiveScene.EasingTotalSteps) - { - if (ActiveScene.IsLooping) - { - ActiveScene.EasingCurrentStep = 0; - } - else - { - ActiveScene.PlayedFrames.AddRange (ActiveScene.Frames); - ActiveScene.Frames.Clear (); - } - } - } - else - { - CurrentCharacterVisual = ActiveScene.GetNextVisual (); - } - if (ActiveSceneIsComplete ()) - { - var completedScene = ActiveScene; - if (!ActiveScene.IsLooping) - { - ActiveScene.ResetScene (); - ActiveScene = null; - } - Character.EventHandler.HandleEvent (Event.SceneComplete, completedScene); - } - } - } - - public void ActivateScene (Scene scene) - { - ActiveScene = scene; - ActiveSceneCurrentStep = 0; - CurrentCharacterVisual = ActiveScene.Activate (); - Character.EventHandler.HandleEvent (Event.SceneActivated, scene); - } - - public void DeactivateScene (Scene scene) - { - if (ActiveScene == scene) - { - ActiveScene = null; - } - } -} - - -// Dummy classes for Ansitools, Colorterm, and Hexterm as placeholders -public static class Ansitools -{ - public static string ApplyBold () => "\x1b[1m"; - public static string ApplyItalic () => "\x1b[3m"; - public static string ApplyUnderline () => "\x1b[4m"; - public static string ApplyBlink () => "\x1b[5m"; - public static string ApplyReverse () => "\x1b[7m"; - public static string ApplyHidden () => "\x1b[8m"; - public static string ApplyStrikethrough () => "\x1b[9m"; - public static string ResetAll () => "\x1b[0m"; -} - -public static class Colorterm -{ - public static string Fg (string colorCode) => $"\x1b[38;5;{colorCode}m"; -} - -public static class Hexterm -{ - public static string HexToXterm (string hex) - { - // Convert hex color to xterm color code (0-255) - return "15"; // Example output - } -} diff --git a/Terminal.Gui/TextEffects/ArgValidators.cs b/Terminal.Gui/TextEffects/ArgValidators.cs deleted file mode 100644 index 4070a56ae..000000000 --- a/Terminal.Gui/TextEffects/ArgValidators.cs +++ /dev/null @@ -1,266 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Globalization; -using System.Linq; -using System.Text; -using Terminal.Gui.TextEffects; - -using Color = Terminal.Gui.TextEffects.Color; - -public static class PositiveInt -{ - public static int Parse (string arg) - { - if (int.TryParse (arg, out int value) && value > 0) - { - return value; - } - else - { - throw new ArgumentException ($"invalid value: '{arg}' is not > 0."); - } - } -} - -public static class NonNegativeInt -{ - public static int Parse (string arg) - { - if (int.TryParse (arg, out int value) && value >= 0) - { - return value; - } - else - { - throw new ArgumentException ($"invalid value: '{arg}' Argument must be int >= 0."); - } - } -} - -public static class IntRange -{ - public static (int, int) Parse (string arg) - { - var parts = arg.Split ('-'); - if (parts.Length == 2 && int.TryParse (parts [0], out int start) && int.TryParse (parts [1], out int end) && start > 0 && start <= end) - { - return (start, end); - } - else - { - throw new ArgumentException ($"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 1-10"); - } - } -} - -public static class PositiveFloat -{ - public static float Parse (string arg) - { - if (float.TryParse (arg, out float value) && value > 0) - { - return value; - } - else - { - throw new ArgumentException ($"invalid value: '{arg}' is not a valid value. Argument must be a float > 0."); - } - } -} - -public static class NonNegativeFloat -{ - public static float Parse (string arg) - { - if (float.TryParse (arg, out float value) && value >= 0) - { - return value; - } - else - { - throw new ArgumentException ($"invalid argument value: '{arg}' is out of range. Must be float >= 0."); - } - } -} - -public static class PositiveFloatRange -{ - public static (float, float) Parse (string arg) - { - var parts = arg.Split ('-'); - if (parts.Length == 2 && float.TryParse (parts [0], out float start) && float.TryParse (parts [1], out float end) && start > 0 && start <= end) - { - return (start, end); - } - else - { - throw new ArgumentException ($"invalid range: '{arg}' is not a valid range. Must be start-end. Ex: 0.1-1.0"); - } - } -} - -public static class Ratio -{ - public static float Parse (string arg) - { - if (float.TryParse (arg, out float value) && value >= 0 && value <= 1) - { - return value; - } - else - { - throw new ArgumentException ($"invalid value: '{arg}' is not a float >= 0 and <= 1. Example: 0.5"); - } - } -} - - -public static class GradientDirectionParser -{ - public static Gradient.Direction Parse (string arg) - { - return arg.ToLower () switch - { - "horizontal" => Gradient.Direction.Horizontal, - "vertical" => Gradient.Direction.Vertical, - "diagonal" => Gradient.Direction.Diagonal, - "radial" => Gradient.Direction.Radial, - _ => throw new ArgumentException ($"invalid gradient direction: '{arg}' is not a valid gradient direction. Choices are diagonal, horizontal, vertical, or radial."), - }; - } -} - -public static class ColorArg -{ - public static Color Parse (string arg) - { - if (int.TryParse (arg, out int xtermValue) && xtermValue >= 0 && xtermValue <= 255) - { - return new Color (xtermValue); - } - else if (arg.Length == 6 && int.TryParse (arg, NumberStyles.HexNumber, null, out int _)) - { - return new Color (arg); - } - else - { - throw new ArgumentException ($"invalid color value: '{arg}' is not a valid XTerm or RGB color. Must be in range 0-255 or 000000-FFFFFF."); - } - } -} - -public static class Symbol -{ - public static string Parse (string arg) - { - if (arg.Length == 1 && IsAsciiOrUtf8 (arg)) - { - return arg; - } - else - { - throw new ArgumentException ($"invalid symbol: '{arg}' is not a valid symbol. Must be a single ASCII/UTF-8 character."); - } - } - - private static bool IsAsciiOrUtf8 (string s) - { - try - { - Encoding.ASCII.GetBytes (s); - } - catch (EncoderFallbackException) - { - try - { - Encoding.UTF8.GetBytes (s); - } - catch (EncoderFallbackException) - { - return false; - } - } - return true; - } -} - -public static class CanvasDimension -{ - public static int Parse (string arg) - { - if (int.TryParse (arg, out int value) && value >= -1) - { - return value; - } - else - { - throw new ArgumentException ($"invalid value: '{arg}' is not >= -1."); - } - } -} - -public static class TerminalDimensions -{ - public static (int, int) Parse (string arg) - { - var parts = arg.Split (' '); - if (parts.Length == 2 && int.TryParse (parts [0], out int width) && int.TryParse (parts [1], out int height) && width >= 0 && height >= 0) - { - return (width, height); - } - else - { - throw new ArgumentException ($"invalid terminal dimensions: '{arg}' is not a valid terminal dimension. Must be >= 0."); - } - } -} - -public static class Ease -{ - private static readonly Dictionary easingFuncMap = new () - { - {"linear", Easing.Linear}, - {"in_sine", Easing.InSine}, - {"out_sine", Easing.OutSine}, - {"in_out_sine", Easing.InOutSine}, - {"in_quad", Easing.InQuad}, - {"out_quad", Easing.OutQuad}, - {"in_out_quad", Easing.InOutQuad}, - {"in_cubic", Easing.InCubic}, - {"out_cubic", Easing.OutCubic}, - {"in_out_cubic", Easing.InOutCubic}, - {"in_quart", Easing.InQuart}, - {"out_quart", Easing.OutQuart}, - {"in_out_quart", Easing.InOutQuart}, - {"in_quint", Easing.InQuint}, - {"out_quint", Easing.OutQuint}, - {"in_out_quint", Easing.InOutQuint}, - {"in_expo", Easing.InExpo}, - {"out_expo", Easing.OutExpo}, - {"in_out_expo", Easing.InOutExpo}, - {"in_circ", Easing.InCirc}, - {"out_circ", Easing.OutCirc}, - {"in_out_circ", Easing.InOutCirc}, - {"in_back", Easing.InBack}, - {"out_back", Easing.OutBack}, - {"in_out_back", Easing.InOutBack}, - {"in_elastic", Easing.InElastic}, - {"out_elastic", Easing.OutElastic}, - {"in_out_elastic", Easing.InOutElastic}, - {"in_bounce", Easing.InBounce}, - {"out_bounce", Easing.OutBounce}, - {"in_out_bounce", Easing.InOutBounce}, - }; - - public static EasingFunction Parse (string arg) - { - if (easingFuncMap.TryGetValue (arg.ToLower (), out var easingFunc)) - { - return easingFunc; - } - else - { - throw new ArgumentException ($"invalid ease value: '{arg}' is not a valid ease."); - } - } -} diff --git a/Terminal.Gui/TextEffects/BaseCharacter.cs b/Terminal.Gui/TextEffects/BaseCharacter.cs deleted file mode 100644 index 886cd6b59..000000000 --- a/Terminal.Gui/TextEffects/BaseCharacter.cs +++ /dev/null @@ -1,109 +0,0 @@ -namespace Terminal.Gui.TextEffects; - -public class EffectCharacter -{ - public int CharacterId { get; } - public string InputSymbol { get; } - public Coord InputCoord { get; } - public bool IsVisible { get; set; } - public Animation Animation { get; } - public Motion Motion { get; } - public EventHandler EventHandler { get; } - public int Layer { get; set; } - public bool IsFillCharacter { get; set; } - - public EffectCharacter (int characterId, string symbol, int inputColumn, int inputRow) - { - CharacterId = characterId; - InputSymbol = symbol; - InputCoord = new Coord (inputColumn, inputRow); - IsVisible = false; - Animation = new Animation (this); - Motion = new Motion (this); - EventHandler = new EventHandler (this); - Layer = 0; - IsFillCharacter = false; - } - - public bool IsActive => !Animation.ActiveSceneIsComplete() || !Motion.MovementIsComplete (); - - public void Tick () - { - Motion.Move (); - Animation.StepAnimation (); - } -} - -public class EventHandler -{ - public EffectCharacter Character { get; } - public Dictionary<(Event, object), List<(Action, object)>> RegisteredEvents { get; } - - public EventHandler (EffectCharacter character) - { - Character = character; - RegisteredEvents = new Dictionary<(Event, object), List<(Action, object)>> (); - } - - public void RegisterEvent (Event @event, object caller, Action action, object target) - { - var key = (@event, caller); - if (!RegisteredEvents.ContainsKey (key)) - RegisteredEvents [key] = new List<(Action, object)> (); - - RegisteredEvents [key].Add ((action, target)); - } - - public void HandleEvent (Event @event, object caller) - { - var key = (@event, caller); - if (!RegisteredEvents.ContainsKey (key)) - return; - - foreach (var (action, target) in RegisteredEvents [key]) - { - switch (action) - { - case Action.ActivatePath: - Character.Motion.ActivatePath (target as Path); - break; - case Action.DeactivatePath: - Character.Motion.DeactivatePath (target as Path); - break; - case Action.SetLayer: - Character.Layer = (int)target; - break; - case Action.SetCoordinate: - Character.Motion.CurrentCoord = (Coord)target; - break; - case Action.Callback: - - // TODO: - throw new NotImplementedException ("TODO, port (target as Action)?.Invoke ()"); - break; - default: - throw new ArgumentOutOfRangeException (nameof (action), "Unhandled action."); - } - } - } - - public enum Event - { - SegmentEntered, - SegmentExited, - PathActivated, - PathComplete, - PathHolding, - SceneActivated, - SceneComplete - } - - public enum Action - { - ActivatePath, - DeactivatePath, - SetLayer, - SetCoordinate, - Callback - } -} diff --git a/Terminal.Gui/TextEffects/BaseEffect.cs b/Terminal.Gui/TextEffects/BaseEffect.cs deleted file mode 100644 index f8a710302..000000000 --- a/Terminal.Gui/TextEffects/BaseEffect.cs +++ /dev/null @@ -1,60 +0,0 @@ -namespace Terminal.Gui.TextEffects; - -public abstract class BaseEffectIterator where T : EffectConfig, new() -{ - protected T Config { get; set; } - protected TerminalA Terminal { get; set; } - protected List ActiveCharacters { get; set; } = new List (); - - protected BaseEffect Effect { get; } - - - - public BaseEffectIterator (BaseEffect effect) - { - Effect = effect; - Config = effect.EffectConfig; - Terminal = new TerminalA (effect.InputData, effect.TerminalConfig); - - } - - public void Update () - { - foreach (var character in ActiveCharacters) - { - character.Tick (); - } - ActiveCharacters.RemoveAll (character => !character.IsActive); - } - -} - -public abstract class BaseEffect where T : EffectConfig, new() -{ - public string InputData { get; set; } - public T EffectConfig { get; set; } - public TerminalConfig TerminalConfig { get; set; } - - protected BaseEffect (string inputData) - { - InputData = inputData; - EffectConfig = new T (); - TerminalConfig = new TerminalConfig (); - } - - /* - public IDisposable TerminalOutput (string endSymbol = "\n") - { - var terminal = new Terminal (InputData, TerminalConfig); - terminal.PrepCanvas (); - try - { - return terminal; - } - finally - { - terminal.RestoreCursor (endSymbol); - } - }*/ -} - diff --git a/Terminal.Gui/TextEffects/Easing.cs b/Terminal.Gui/TextEffects/Easing.cs deleted file mode 100644 index 3b63ca032..000000000 --- a/Terminal.Gui/TextEffects/Easing.cs +++ /dev/null @@ -1,303 +0,0 @@ -namespace Terminal.Gui.TextEffects; -using System; - -public delegate float EasingFunction (float progressRatio); - -public static class Easing -{ - public static float Linear (float progressRatio) - { - return progressRatio; - } - - public static float InSine (float progressRatio) - { - return 1 - (float)Math.Cos ((progressRatio * Math.PI) / 2); - } - - public static float OutSine (float progressRatio) - { - return (float)Math.Sin ((progressRatio * Math.PI) / 2); - } - - public static float InOutSine (float progressRatio) - { - return -(float)(Math.Cos (Math.PI * progressRatio) - 1) / 2; - } - - public static float InQuad (float progressRatio) - { - return progressRatio * progressRatio; - } - - public static float OutQuad (float progressRatio) - { - return 1 - (1 - progressRatio) * (1 - progressRatio); - } - - public static float InOutQuad (float progressRatio) - { - if (progressRatio < 0.5) - { - return 2 * progressRatio * progressRatio; - } - else - { - return 1 - (float)Math.Pow (-2 * progressRatio + 2, 2) / 2; - } - } - - public static float InCubic (float progressRatio) - { - return progressRatio * progressRatio * progressRatio; - } - - public static float OutCubic (float progressRatio) - { - return 1 - (float)Math.Pow (1 - progressRatio, 3); - } - - public static float InOutCubic (float progressRatio) - { - if (progressRatio < 0.5) - { - return 4 * progressRatio * progressRatio * progressRatio; - } - else - { - return 1 - (float)Math.Pow (-2 * progressRatio + 2, 3) / 2; - } - } - - public static float InQuart (float progressRatio) - { - return progressRatio * progressRatio * progressRatio * progressRatio; - } - - public static float OutQuart (float progressRatio) - { - return 1 - (float)Math.Pow (1 - progressRatio, 4); - } - - public static float InOutQuart (float progressRatio) - { - if (progressRatio < 0.5) - { - return 8 * progressRatio * progressRatio * progressRatio * progressRatio; - } - else - { - return 1 - (float)Math.Pow (-2 * progressRatio + 2, 4) / 2; - } - } - - public static float InQuint (float progressRatio) - { - return progressRatio * progressRatio * progressRatio * progressRatio * progressRatio; - } - - public static float OutQuint (float progressRatio) - { - return 1 - (float)Math.Pow (1 - progressRatio, 5); - } - - public static float InOutQuint (float progressRatio) - { - if (progressRatio < 0.5) - { - return 16 * progressRatio * progressRatio * progressRatio * progressRatio * progressRatio; - } - else - { - return 1 - (float)Math.Pow (-2 * progressRatio + 2, 5) / 2; - } - } - - public static float InExpo (float progressRatio) - { - if (progressRatio == 0) - { - return 0; - } - else - { - return (float)Math.Pow (2, 10 * progressRatio - 10); - } - } - - public static float OutExpo (float progressRatio) - { - if (progressRatio == 1) - { - return 1; - } - else - { - return 1 - (float)Math.Pow (2, -10 * progressRatio); - } - } - - public static float InOutExpo (float progressRatio) - { - if (progressRatio == 0) - { - return 0; - } - else if (progressRatio == 1) - { - return 1; - } - else if (progressRatio < 0.5) - { - return (float)Math.Pow (2, 20 * progressRatio - 10) / 2; - } - else - { - return (2 - (float)Math.Pow (2, -20 * progressRatio + 10)) / 2; - } - } - - public static float InCirc (float progressRatio) - { - return 1 - (float)Math.Sqrt (1 - progressRatio * progressRatio); - } - - public static float OutCirc (float progressRatio) - { - return (float)Math.Sqrt (1 - (progressRatio - 1) * (progressRatio - 1)); - } - - public static float InOutCirc (float progressRatio) - { - if (progressRatio < 0.5) - { - return (1 - (float)Math.Sqrt (1 - (2 * progressRatio) * (2 * progressRatio))) / 2; - } - else - { - return ((float)Math.Sqrt (1 - (-2 * progressRatio + 2) * (-2 * progressRatio + 2)) + 1) / 2; - } - } - - public static float InBack (float progressRatio) - { - const float c1 = 1.70158f; - const float c3 = c1 + 1; - return c3 * progressRatio * progressRatio * progressRatio - c1 * progressRatio * progressRatio; - } - - public static float OutBack (float progressRatio) - { - const float c1 = 1.70158f; - const float c3 = c1 + 1; - return 1 + c3 * (progressRatio - 1) * (progressRatio - 1) * (progressRatio - 1) + c1 * (progressRatio - 1) * (progressRatio - 1); - } - - public static float InOutBack (float progressRatio) - { - const float c1 = 1.70158f; - const float c2 = c1 * 1.525f; - if (progressRatio < 0.5) - { - return ((2 * progressRatio) * (2 * progressRatio) * ((c2 + 1) * 2 * progressRatio - c2)) / 2; - } - else - { - return ((2 * progressRatio - 2) * (2 * progressRatio - 2) * ((c2 + 1) * (progressRatio * 2 - 2) + c2) + 2) / 2; - } - } - - public static float InElastic (float progressRatio) - { - const float c4 = (2 * (float)Math.PI) / 3; - if (progressRatio == 0) - { - return 0; - } - else if (progressRatio == 1) - { - return 1; - } - else - { - return -(float)Math.Pow (2, 10 * progressRatio - 10) * (float)Math.Sin ((progressRatio * 10 - 10.75) * c4); - } - } - - public static float OutElastic (float progressRatio) - { - const float c4 = (2 * (float)Math.PI) / 3; - if (progressRatio == 0) - { - return 0; - } - else if (progressRatio == 1) - { - return 1; - } - else - { - return (float)Math.Pow (2, -10 * progressRatio) * (float)Math.Sin ((progressRatio * 10 - 0.75) * c4) + 1; - } - } - - public static float InOutElastic (float progressRatio) - { - const float c5 = (2 * (float)Math.PI) / 4.5f; - if (progressRatio == 0) - { - return 0; - } - else if (progressRatio == 1) - { - return 1; - } - else if (progressRatio < 0.5) - { - return -(float)Math.Pow (2, 20 * progressRatio - 10) * (float)Math.Sin ((20 * progressRatio - 11.125) * c5) / 2; - } - else - { - return ((float)Math.Pow (2, -20 * progressRatio + 10) * (float)Math.Sin ((20 * progressRatio - 11.125) * c5)) / 2 + 1; - } - } - - public static float InBounce (float progressRatio) - { - return 1 - OutBounce (1 - progressRatio); - } - - public static float OutBounce (float progressRatio) - { - const float n1 = 7.5625f; - const float d1 = 2.75f; - if (progressRatio < 1 / d1) - { - return n1 * progressRatio * progressRatio; - } - else if (progressRatio < 2 / d1) - { - return n1 * (progressRatio - 1.5f / d1) * (progressRatio - 1.5f / d1) + 0.75f; - } - else if (progressRatio < 2.5 / d1) - { - return n1 * (progressRatio - 2.25f / d1) * (progressRatio - 2.25f / d1) + 0.9375f; - } - else - { - return n1 * (progressRatio - 2.625f / d1) * (progressRatio - 2.625f / d1) + 0.984375f; - } - } - - public static float InOutBounce (float progressRatio) - { - if (progressRatio < 0.5) - { - return (1 - OutBounce (1 - 2 * progressRatio)) / 2; - } - else - { - return (1 + OutBounce (2 * progressRatio - 1)) / 2; - } - } -} diff --git a/Terminal.Gui/TextEffects/EffectTemplate.cs b/Terminal.Gui/TextEffects/EffectTemplate.cs deleted file mode 100644 index 4b0fddcb7..000000000 --- a/Terminal.Gui/TextEffects/EffectTemplate.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace Terminal.Gui.TextEffects; - -public class EffectConfig -{ - public Color ColorSingle { get; set; } - public List ColorList { get; set; } - public Color FinalColor { get; set; } - public List FinalGradientStops { get; set; } - public List FinalGradientSteps { get; set; } - public int FinalGradientFrames { get; set; } - public float MovementSpeed { get; set; } - public EasingFunction Easing { get; set; } -} diff --git a/Terminal.Gui/TextEffects/Effects/Beams.cs b/Terminal.Gui/TextEffects/Effects/Beams.cs deleted file mode 100644 index b39ef9a91..000000000 --- a/Terminal.Gui/TextEffects/Effects/Beams.cs +++ /dev/null @@ -1,241 +0,0 @@ -/*namespace Terminal.Gui.TextEffects.Effects; - -public class BeamsConfig : EffectConfig -{ - public string [] BeamRowSymbols { get; set; } = { "▂", "▁", "_" }; - public string [] BeamColumnSymbols { get; set; } = { "▌", "▍", "▎", "▏" }; - public int BeamDelay { get; set; } = 10; - public (int, int) BeamRowSpeedRange { get; set; } = (10, 40); - public (int, int) BeamColumnSpeedRange { get; set; } = (6, 10); - public Color [] BeamGradientStops { get; set; } = { new Color ("ffffff"), new Color ("00D1FF"), new Color ("8A008A") }; - public int [] BeamGradientSteps { get; set; } = { 2, 8 }; - public int BeamGradientFrames { get; set; } = 2; - public Color [] FinalGradientStops { get; set; } = { new Color ("8A008A"), new Color ("00D1FF"), new Color ("ffffff") }; - public int [] FinalGradientSteps { get; set; } = { 12 }; - public int FinalGradientFrames { get; set; } = 5; - public GradientDirection FinalGradientDirection { get; set; } = GradientDirection.Vertical; - public int FinalWipeSpeed { get; set; } = 1; -} - -public class Beams : BaseEffect -{ - public Beams (string inputData) : base (inputData) - { - } - - protected override BaseEffectIterator CreateIterator () - { - return new BeamsIterator (this); - } -} - - -public class BeamsIterator : BaseEffectIterator -{ - private class Group - { - public List Characters { get; private set; } - public string Direction { get; private set; } - private Terminal Terminal; - private BeamsConfig Config; - private double Speed; - private float NextCharacterCounter; - private List SortedCharacters; - - public Group (List characters, string direction, Terminal terminal, BeamsConfig config) - { - Characters = characters; - Direction = direction; - Terminal = terminal; - Config = config; - Speed = new Random ().Next (config.BeamRowSpeedRange.Item1, config.BeamRowSpeedRange.Item2) * 0.1; - NextCharacterCounter = 0; - SortedCharacters = direction == "row" - ? characters.OrderBy (c => c.InputCoord.Column).ToList () - : characters.OrderBy (c => c.InputCoord.Row).ToList (); - - if (new Random ().Next (0, 2) == 0) - { - SortedCharacters.Reverse (); - } - } - - public void IncrementNextCharacterCounter () - { - NextCharacterCounter += (float)Speed; - } - - public EffectCharacter GetNextCharacter () - { - NextCharacterCounter -= 1; - var nextCharacter = SortedCharacters.First (); - SortedCharacters.RemoveAt (0); - if (nextCharacter.Animation.ActiveScene != null) - { - nextCharacter.Animation.ActiveScene.ResetScene (); - return null; - } - - Terminal.SetCharacterVisibility (nextCharacter, true); - nextCharacter.Animation.ActivateScene (nextCharacter.Animation.QueryScene ("beam_" + Direction)); - return nextCharacter; - } - - public bool Complete () - { - return !SortedCharacters.Any (); - } - } - - private List PendingGroups = new List (); - private Dictionary CharacterFinalColorMap = new Dictionary (); - private List ActiveGroups = new List (); - private int Delay = 0; - private string Phase = "beams"; - private List> FinalWipeGroups; - - public BeamsIterator (Beams effect) : base (effect) - { - Build (); - } - - private void Build () - { - var finalGradient = new Gradient (Effect.Config.FinalGradientStops, Effect.Config.FinalGradientSteps); - var finalGradientMapping = finalGradient.BuildCoordinateColorMapping ( - Effect.Terminal.Canvas.Top, - Effect.Terminal.Canvas.Right, - Effect.Config.FinalGradientDirection - ); - - foreach (var character in Effect.Terminal.GetCharacters (fillChars: true)) - { - CharacterFinalColorMap [character] = finalGradientMapping [character.InputCoord]; - } - - var beamGradient = new Gradient (Effect.Config.BeamGradientStops, Effect.Config.BeamGradientSteps); - var groups = new List (); - - foreach (var row in Effect.Terminal.GetCharactersGrouped (Terminal.CharacterGroup.RowTopToBottom, fillChars: true)) - { - groups.Add (new Group (row, "row", Effect.Terminal, Effect.Config)); - } - - foreach (var column in Effect.Terminal.GetCharactersGrouped (Terminal.CharacterGroup.ColumnLeftToRight, fillChars: true)) - { - groups.Add (new Group (column, "column", Effect.Terminal, Effect.Config)); - } - - foreach (var group in groups) - { - foreach (var character in group.Characters) - { - var beamRowScene = character.Animation.NewScene (id: "beam_row"); - var beamColumnScene = character.Animation.NewScene (id: "beam_column"); - beamRowScene.ApplyGradientToSymbols ( - beamGradient, Effect.Config.BeamRowSymbols, Effect.Config.BeamGradientFrames); - beamColumnScene.ApplyGradientToSymbols ( - beamGradient, Effect.Config.BeamColumnSymbols, Effect.Config.BeamGradientFrames); - - var fadedColor = character.Animation.AdjustColorBrightness (CharacterFinalColorMap [character], 0.3f); - var fadeGradient = new Gradient (CharacterFinalColorMap [character], fadedColor, steps: 10); - beamRowScene.ApplyGradientToSymbols (fadeGradient, character.InputSymbol, 5); - beamColumnScene.ApplyGradientToSymbols (fadeGradient, character.InputSymbol, 5); - - var brightenGradient = new Gradient (fadedColor, CharacterFinalColorMap [character], steps: 10); - var brightenScene = character.Animation.NewScene (id: "brighten"); - brightenScene.ApplyGradientToSymbols ( - brightenGradient, character.InputSymbol, Effect.Config.FinalGradientFrames); - } - } - - PendingGroups = groups; - new Random ().Shuffle (PendingGroups); - } - - public override bool MoveNext () - { - if (Phase != "complete" || ActiveCharacters.Any ()) - { - if (Phase == "beams") - { - if (Delay == 0) - { - if (PendingGroups.Any ()) - { - for (int i = 0; i < new Random ().Next (1, 6); i++) - { - if (PendingGroups.Any ()) - { - ActiveGroups.Add (PendingGroups.First ()); - PendingGroups.RemoveAt (0); - } - } - } - Delay = Effect.Config.BeamDelay; - } - else - { - Delay--; - } - - foreach (var group in ActiveGroups) - { - group.IncrementNextCharacterCounter (); - if ((int)group.NextCharacterCounter > 1) - { - for (int i = 0; i < (int)group.NextCharacterCounter; i++) - { - if (!group.Complete ()) - { - var nextChar = group.GetNextCharacter (); - if (nextChar != null) - { - ActiveCharacters.Add (nextChar); - } - } - } - } - } - - ActiveGroups = ActiveGroups.Where (g => !g.Complete ()).ToList (); - if (!PendingGroups.Any () && !ActiveGroups.Any () && !ActiveCharacters.Any ()) - { - Phase = "final_wipe"; - } - } - else if (Phase == "final_wipe") - { - if (FinalWipeGroups.Any ()) - { - for (int i = 0; i < Effect.Config.FinalWipeSpeed; i++) - { - if (!FinalWipeGroups.Any ()) break; - - var nextGroup = FinalWipeGroups.First (); - FinalWipeGroups.RemoveAt (0); - - foreach (var character in nextGroup) - { - character.Animation.ActivateScene (character.Animation.QueryScene ("brighten")); - Effect.Terminal.SetCharacterVisibility (character, true); - ActiveCharacters.Add (character); - } - } - } - else - { - Phase = "complete"; - } - } - - Update (); - return true; - } - else - { - return false; - } - } -} -*/ \ No newline at end of file diff --git a/Terminal.Gui/TextEffects/Geometry.cs b/Terminal.Gui/TextEffects/Geometry.cs deleted file mode 100644 index 5de2f7073..000000000 --- a/Terminal.Gui/TextEffects/Geometry.cs +++ /dev/null @@ -1,137 +0,0 @@ -namespace Terminal.Gui.TextEffects; - - -public static class GeometryUtils -{ - - public static List FindCoordsOnCircle (Coord origin, int radius, int coordsLimit = 0, bool unique = true) - { - var points = new List (); - var seenPoints = new HashSet (); - if (coordsLimit == 0) - coordsLimit = (int)Math.Ceiling (2 * Math.PI * radius); - double angleStep = 2 * Math.PI / coordsLimit; - - for (int i = 0; i < coordsLimit; i++) - { - double angle = i * angleStep; - int x = (int)(origin.Column + radius * Math.Cos (angle)); - int y = (int)(origin.Row + radius * Math.Sin (angle)); - var coord = new Coord (x, y); - - if (unique && !seenPoints.Contains (coord)) - { - points.Add (coord); - seenPoints.Add (coord); - } - else if (!unique) - { - points.Add (coord); - } - } - - return points; - } - - public static List FindCoordsInCircle (Coord center, int diameter) - { - var coordsInEllipse = new List (); - int radius = diameter / 2; - for (int x = center.Column - radius; x <= center.Column + radius; x++) - { - for (int y = center.Row - radius; y <= center.Row + radius; y++) - { - if (Math.Pow (x - center.Column, 2) + Math.Pow (y - center.Row, 2) <= Math.Pow (radius, 2)) - coordsInEllipse.Add (new Coord (x, y)); - } - } - return coordsInEllipse; - } - - public static List FindCoordsInRect (Coord origin, int distance) - { - var coords = new List (); - for (int column = origin.Column - distance; column <= origin.Column + distance; column++) - { - for (int row = origin.Row - distance; row <= origin.Row + distance; row++) - { - coords.Add (new Coord (column, row)); - } - } - return coords; - } - - public static Coord FindCoordAtDistance (Coord origin, Coord target, double distance) - { - double totalDistance = FindLengthOfLine (origin, target) + distance; - double t = distance / totalDistance; - int nextColumn = (int)((1 - t) * origin.Column + t * target.Column); - int nextRow = (int)((1 - t) * origin.Row + t * target.Row); - return new Coord (nextColumn, nextRow); - } - - public static Coord FindCoordOnBezierCurve (Coord start, List controlPoints, Coord end, double t) - { - // Implementing De Casteljau's algorithm for Bezier curve - if (controlPoints.Count == 1) // Quadratic - { - double x = Math.Pow (1 - t, 2) * start.Column + - 2 * (1 - t) * t * controlPoints [0].Column + - Math.Pow (t, 2) * end.Column; - double y = Math.Pow (1 - t, 2) * start.Row + - 2 * (1 - t) * t * controlPoints [0].Row + - Math.Pow (t, 2) * end.Row; - return new Coord ((int)x, (int)y); - } - else if (controlPoints.Count == 2) // Cubic - { - double x = Math.Pow (1 - t, 3) * start.Column + - 3 * Math.Pow (1 - t, 2) * t * controlPoints [0].Column + - 3 * (1 - t) * Math.Pow (t, 2) * controlPoints [1].Column + - Math.Pow (t, 3) * end.Column; - double y = Math.Pow (1 - t, 3) * start.Row + - 3 * Math.Pow (1 - t, 2) * t * controlPoints [0].Row + - 3 * (1 - t) * Math.Pow (t, 2) * controlPoints [1].Row + - Math.Pow (t, 3) * end.Row; - return new Coord ((int)x, (int)y); - } - throw new ArgumentException ("Invalid number of control points for bezier curve"); - } - - public static Coord FindCoordOnLine (Coord start, Coord end, double t) - { - int x = (int)((1 - t) * start.Column + t * end.Column); - int y = (int)((1 - t) * start.Row + t * end.Row); - return new Coord (x, y); - } - - public static double FindLengthOfBezierCurve (Coord start, List controlPoints, Coord end) - { - double length = 0.0; - Coord prevCoord = start; - for (int i = 1; i <= 10; i++) - { - double t = i / 10.0; - Coord coord = FindCoordOnBezierCurve (start, controlPoints, end, t); - length += FindLengthOfLine (prevCoord, coord); - prevCoord = coord; - } - return length; - } - - public static double FindLengthOfLine (Coord coord1, Coord coord2) - { - return Math.Sqrt (Math.Pow (coord2.Column - coord1.Column, 2) + - Math.Pow (coord2.Row - coord1.Row, 2)); - } - - public static double FindNormalizedDistanceFromCenter (int maxRow, int maxColumn, Coord otherCoord) - { - double center_x = maxColumn / 2.0; - double center_y = maxRow / 2.0; - double maxDistance = Math.Sqrt (Math.Pow (maxColumn, 2) + Math.Pow (maxRow, 2)); - double distance = Math.Sqrt (Math.Pow (otherCoord.Column - center_x, 2) + - Math.Pow (otherCoord.Row - center_y, 2)); - return distance / (maxDistance / 2); - } -} \ No newline at end of file diff --git a/Terminal.Gui/TextEffects/HexTerm.cs b/Terminal.Gui/TextEffects/HexTerm.cs deleted file mode 100644 index b3b96c4d3..000000000 --- a/Terminal.Gui/TextEffects/HexTerm.cs +++ /dev/null @@ -1,94 +0,0 @@ -using System.Text.RegularExpressions; - -namespace Terminal.Gui.TextEffects; -using System; -using System.Collections.Generic; -using System.Linq; - -public static class ColorUtils -{ - private static readonly Dictionary xtermToHexMap = new Dictionary - { - {0, "#000000"}, {1, "#800000"}, {2, "#008000"}, {3, "#808000"}, {4, "#000080"}, {5, "#800080"}, {6, "#008080"}, {7, "#c0c0c0"}, - {8, "#808080"}, {9, "#ff0000"}, {10, "#00ff00"}, {11, "#ffff00"}, {12, "#0000ff"}, {13, "#ff00ff"}, {14, "#00ffff"}, {15, "#ffffff"}, - {16, "#000000"}, {17, "#00005f"}, {18, "#000087"}, {19, "#0000af"}, {20, "#0000d7"}, {21, "#0000ff"}, {22, "#005f00"}, {23, "#005f5f"}, - {24, "#005f87"}, {25, "#005faf"}, {26, "#005fd7"}, {27, "#005fff"}, {28, "#008700"}, {29, "#00875f"}, {30, "#008787"}, {31, "#0087af"}, - {32, "#0087d7"}, {33, "#0087ff"}, {34, "#00af00"}, {35, "#00af5f"}, {36, "#00af87"}, {37, "#00afaf"}, {38, "#00afd7"}, {39, "#00afff"}, - {40, "#00d700"}, {41, "#00d75f"}, {42, "#00d787"}, {43, "#00d7af"}, {44, "#00d7d7"}, {45, "#00d7ff"}, {46, "#00ff00"}, {47, "#00ff5f"}, - {48, "#00ff87"}, {49, "#00ffaf"}, {50, "#00ffd7"}, {51, "#00ffff"}, {52, "#5f0000"}, {53, "#5f005f"}, {54, "#5f0087"}, {55, "#5f00af"}, - {56, "#5f00d7"}, {57, "#5f00ff"}, {58, "#5f5f00"}, {59, "#5f5f5f"}, {60, "#5f5f87"}, {61, "#5f5faf"}, {62, "#5f5fd7"}, {63, "#5f5fff"}, - {64, "#5f8700"}, {65, "#5f875f"}, {66, "#5f8787"}, {67, "#5f87af"}, {68, "#5f87d7"}, {69, "#5f87ff"}, {70, "#5faf00"}, {71, "#5faf5f"}, - {72, "#5faf87"}, {73, "#5fafaf"}, {74, "#5fafd7"}, {75, "#5fafff"}, {76, "#5fd700"}, {77, "#5fd75f"}, {78, "#5fd787"}, {79, "#5fd7af"}, - {80, "#5fd7d7"}, {81, "#5fd7ff"}, {82, "#5fff00"}, {83, "#5fff5f"}, {84, "#5fff87"}, {85, "#5fffaf"}, {86, "#5fffd7"}, {87, "#5fffff"}, - {88, "#870000"}, {89, "#87005f"}, {90, "#870087"}, {91, "#8700af"}, {92, "#8700d7"}, {93, "#8700ff"}, {94, "#875f00"}, {95, "#875f5f"}, - {96, "#875f87"}, {97, "#875faf"}, {98, "#875fd7"}, {99, "#875fff"}, {100, "#878700"}, {101, "#87875f"}, {102, "#878787"}, {103, "#8787af"}, - {104, "#8787d7"}, {105, "#8787ff"}, {106, "#87af00"}, {107, "#87af5f"}, {108, "#87af87"}, {109, "#87afaf"}, {110, "#87afd7"}, {111, "#87afff"}, - {112, "#87d700"}, {113, "#87d75f"}, {114, "#87d787"}, {115, "#87d7af"}, {116, "#87d7d7"}, {117, "#87d7ff"}, {118, "#87ff00"}, {119, "#87ff5f"}, - {120, "#87ff87"}, {121, "#87ffaf"}, {122, "#87ffd7"}, {123, "#87ffff"}, {124, "#af0000"}, {125, "#af005f"}, {126, "#af0087"}, {127, "#af00af"}, - {128, "#af00d7"}, {129, "#af00ff"}, {130, "#af5f00"}, {131, "#af5f5f"}, {132, "#af5f87"}, {133, "#af5faf"}, {134, "#af5fd7"}, {135, "#af5fff"}, - {136, "#af8700"}, {137, "#af875f"}, {138, "#af8787"}, {139, "#af87af"}, {140, "#af87d7"}, {141, "#af87ff"}, {142, "#afaf00"}, {143, "#afaf5f"}, - {144, "#afaf87"}, {145, "#afafaf"}, {146, "#afafd7"}, {147, "#afafff"}, {148, "#afd700"}, {149, "#afd75f"}, {150, "#afd787"}, {151, "#afd7af"}, - {152, "#afd7d7"}, {153, "#afd7ff"}, {154, "#afff00"}, {155, "#afff5f"}, {156, "#afff87"}, {157, "#afffaf"}, {158, "#afffd7"}, {159, "#afffff"}, - {160, "#d70000"}, {161, "#d7005f"}, {162, "#d70087"}, {163, "#d700af"}, {164, "#d700d7"}, {165, "#d700ff"}, {166, "#d75f00"}, {167, "#d75f5f"}, - {168, "#d75f87"}, {169, "#d75faf"}, {170, "#d75fd7"}, {171, "#d75fff"}, {172, "#d78700"}, {173, "#d7875f"}, {174, "#d78787"}, {175, "#d787af"}, - {176, "#d787d7"}, {177, "#d787ff"}, {178, "#d7af00"}, {179, "#d7af5f"}, {180, "#d7af87"}, {181, "#d7afaf"}, {182, "#d7afd7"}, {183, "#d7afff"}, - {184, "#d7d700"}, {185, "#d7d75f"}, {186, "#d7d787"}, {187, "#d7d7af"}, {188, "#d7d7d7"}, {189, "#d7d7ff"}, {190, "#d7ff00"}, {191, "#d7ff5f"}, - {192, "#d7ff87"}, {193, "#d7ffaf"}, {194, "#d7ffd7"}, {195, "#d7ffff"}, {196, "#ff0000"}, {197, "#ff005f"}, {198, "#ff0087"}, {199, "#ff00af"}, - {200, "#ff00d7"}, {201, "#ff00ff"}, {202, "#ff5f00"}, {203, "#ff5f5f"}, {204, "#ff5f87"}, {205, "#ff5faf"}, {206, "#ff5fd7"}, {207, "#ff5fff"}, - {208, "#ff8700"}, {209, "#ff875f"}, {210, "#ff8787"}, {211, "#ff87af"}, {212, "#ff87d7"}, {213, "#ff87ff"}, {214, "#ffaf00"}, {215, "#ffaf5f"}, - {216, "#ffaf87"}, {217, "#ffafaf"}, {218, "#ffafd7"}, {219, "#ffafff"}, {220, "#ffd700"}, {221, "#ffd75f"}, {222, "#ffd787"}, {223, "#ffd7af"}, - {224, "#ffd7d7"}, {225, "#ffd7ff"}, {226, "#ffff00"}, {227, "#ffff5f"}, {228, "#ffff87"}, {229, "#ffffaf"}, {230, "#ffffd7"}, {231, "#ffffff"}, - {232, "#080808"}, {233, "#121212"}, {234, "#1c1c1c"}, {235, "#262626"}, {236, "#303030"}, {237, "#3a3a3a"}, {238, "#444444"}, {239, "#4e4e4e"}, - {240, "#585858"}, {241, "#626262"}, {242, "#6c6c6c"}, {243, "#767676"}, {244, "#808080"}, {245, "#8a8a8a"}, {246, "#949494"}, {247, "#9e9e9e"}, - {248, "#a8a8a8"}, {249, "#b2b2b2"}, {250, "#bcbcbc"}, {251, "#c6c6c6"}, {252, "#d0d0d0"}, {253, "#dadada"}, {254, "#e4e4e4"}, {255, "#eeeeee"} - }; - - private static readonly Dictionary xtermToRgbMap = xtermToHexMap.ToDictionary ( - item => item.Key, - item => ( - R: Convert.ToInt32 (item.Value.Substring (1, 2), 16), - G: Convert.ToInt32 (item.Value.Substring (3, 2), 16), - B: Convert.ToInt32 (item.Value.Substring (5, 2), 16) - )); - private static readonly Regex hexColorRegex = new Regex ("^#?[0-9A-Fa-f]{6}$"); - - public static bool IsValidHexColor (string hexColor) - { - return hexColorRegex.IsMatch (hexColor); - } - - public static bool IsValidXtermColor (int xtermColor) - { - return xtermColor >= 0 && xtermColor <= 255; - } - - public static string XtermToHex (int xtermColor) - { - if (xtermToHexMap.TryGetValue (xtermColor, out string hex)) - { - return hex; - } - throw new ArgumentException ($"Invalid XTerm-256 color code: {xtermColor}"); - } - - public static int HexToXterm (string hexColor) - { - if (!IsValidHexColor (hexColor)) - throw new ArgumentException ("Invalid RGB hex color format."); - - hexColor = hexColor.StartsWith ("#") ? hexColor.Substring (1) : hexColor; - var rgb = ( - R: Convert.ToInt32 (hexColor.Substring (0, 2), 16), - G: Convert.ToInt32 (hexColor.Substring (2, 2), 16), - B: Convert.ToInt32 (hexColor.Substring (4, 2), 16) - ); - - return xtermToRgbMap.Aggregate ((current, next) => - ColorDifference (current.Value, rgb) < ColorDifference (next.Value, rgb) ? current : next).Key; - } - - private static double ColorDifference ((int R, int G, int B) c1, (int R, int G, int B) c2) - { - return Math.Sqrt (Math.Pow (c1.R - c2.R, 2) + Math.Pow (c1.G - c2.G, 2) + Math.Pow (c1.B - c2.B, 2)); - } -} diff --git a/Terminal.Gui/TextEffects/Motion.cs b/Terminal.Gui/TextEffects/Motion.cs deleted file mode 100644 index 9ed544f5e..000000000 --- a/Terminal.Gui/TextEffects/Motion.cs +++ /dev/null @@ -1,253 +0,0 @@ -namespace Terminal.Gui.TextEffects; -public class Coord -{ - public int Column { get; set; } - public int Row { get; set; } - - public Coord (int column, int row) - { - Column = column; - Row = row; - } - - public override string ToString () => $"({Column}, {Row})"; - - public override bool Equals (object obj) - { - if (obj is Coord other) - { - return Column == other.Column && Row == other.Row; - } - return false; - } - - public override int GetHashCode () - { - return HashCode.Combine (Column, Row); - } - - public static bool operator == (Coord left, Coord right) - { - if (left is null) - { - return right is null; - } - return left.Equals (right); - } - - public static bool operator != (Coord left, Coord right) - { - return !(left == right); - } -} - -public class Waypoint -{ - public string WaypointId { get; set; } - public Coord Coord { get; set; } - public List BezierControl { get; set; } - - public Waypoint (string waypointId, Coord coord, List bezierControl = null) - { - WaypointId = waypointId; - Coord = coord; - BezierControl = bezierControl ?? new List (); - } -} - -public class Segment -{ - public Waypoint Start { get; private set; } - public Waypoint End { get; private set; } - public double Distance { get; private set; } - public bool EnterEventTriggered { get; set; } - public bool ExitEventTriggered { get; set; } - - public Segment (Waypoint start, Waypoint end) - { - Start = start; - End = end; - Distance = CalculateDistance (start, end); - } - - private double CalculateDistance (Waypoint start, Waypoint end) - { - // Add bezier control point distance calculation if needed - return Math.Sqrt (Math.Pow (end.Coord.Column - start.Coord.Column, 2) + Math.Pow (end.Coord.Row - start.Coord.Row, 2)); - } - - public Coord GetCoordOnSegment (double distanceFactor) - { - int column = (int)(Start.Coord.Column + (End.Coord.Column - Start.Coord.Column) * distanceFactor); - int row = (int)(Start.Coord.Row + (End.Coord.Row - Start.Coord.Row) * distanceFactor); - return new Coord (column, row); - } -} -public class Path -{ - public string PathId { get; private set; } - public double Speed { get; set; } - public Func EaseFunction { get; set; } - public int Layer { get; set; } - public int HoldTime { get; set; } - public bool Loop { get; set; } - public List Segments { get; private set; } = new List (); - public int CurrentStep { get; set; } - public double TotalDistance { get; set; } - public double LastDistanceReached { get; set; } - public int MaxSteps => (int)Math.Ceiling (TotalDistance / Speed); // Calculates max steps based on total distance and speed - - public Path (string pathId, double speed, Func easeFunction = null, int layer = 0, int holdTime = 0, bool loop = false) - { - PathId = pathId; - Speed = speed; - EaseFunction = easeFunction; - Layer = layer; - HoldTime = holdTime; - Loop = loop; - } - - public void AddWaypoint (Waypoint waypoint) - { - if (Segments.Count > 0) - { - var lastSegment = Segments.Last (); - var newSegment = new Segment (lastSegment.End, waypoint); - Segments.Add (newSegment); - TotalDistance += newSegment.Distance; - } - else - { - var originWaypoint = new Waypoint ("origin", new Coord (0, 0)); // Assuming the path starts at origin - var initialSegment = new Segment (originWaypoint, waypoint); - Segments.Add (initialSegment); - TotalDistance = initialSegment.Distance; - } - } - - public Coord Step () - { - if (CurrentStep <= MaxSteps) - { - double progress = EaseFunction?.Invoke ((double)CurrentStep / TotalDistance) ?? (double)CurrentStep / TotalDistance; - double distanceTravelled = TotalDistance * progress; - LastDistanceReached = distanceTravelled; - - foreach (var segment in Segments) - { - if (distanceTravelled <= segment.Distance) - { - double segmentProgress = distanceTravelled / segment.Distance; - return segment.GetCoordOnSegment (segmentProgress); - } - - distanceTravelled -= segment.Distance; - } - } - - return Segments.Last ().End.Coord; // Return the end of the last segment if out of bounds - } -} - -public class Motion -{ - public Dictionary Paths { get; private set; } = new Dictionary (); - public Path ActivePath { get; private set; } - public Coord CurrentCoord { get; set; } - public Coord PreviousCoord { get; set; } - public EffectCharacter Character { get; private set; } // Assuming EffectCharacter is similar to base_character.EffectCharacter - - public Motion (EffectCharacter character) - { - Character = character; - CurrentCoord = new Coord (character.InputCoord.Column, character.InputCoord.Row); // Assuming similar properties - PreviousCoord = new Coord (-1, -1); - } - - public void SetCoordinate (Coord coord) - { - CurrentCoord = coord; - } - - public Path CreatePath (string pathId, double speed, Func easeFunction = null, int layer = 0, int holdTime = 0, bool loop = false) - { - if (Paths.ContainsKey (pathId)) - throw new ArgumentException ($"A path with ID {pathId} already exists."); - - var path = new Path (pathId, speed, easeFunction, layer, holdTime, loop); - Paths [pathId] = path; - return path; - } - - public Path QueryPath (string pathId) - { - if (!Paths.TryGetValue (pathId, out var path)) - throw new KeyNotFoundException ($"No path found with ID {pathId}."); - - return path; - } - - public bool MovementIsComplete () - { - return ActivePath == null || ActivePath.CurrentStep >= ActivePath.TotalDistance; - } - - public void ActivatePath (Path path) - { - if (path == null) - throw new ArgumentNullException (nameof (path), "Path cannot be null when activating."); - - ActivePath = path; - ActivePath.CurrentStep = 0; // Reset the path's progress - } - - /// - /// Set the active path to None if the active path is the given path. - /// - public void DeactivatePath (Path p) - { - if (p == ActivePath) - { - ActivePath = null; - } - } - public void DeactivatePath () - { - ActivePath = null; - } - - public void Move () - { - if (ActivePath != null) - { - PreviousCoord = CurrentCoord; - CurrentCoord = ActivePath.Step (); - ActivePath.CurrentStep++; - - if (ActivePath.CurrentStep >= ActivePath.TotalDistance) - { - if (ActivePath.Loop) - ActivePath.CurrentStep = 0; // Reset the path for looping - else - DeactivatePath (); // Deactivate the path if it is not set to loop - } - } - } - - public void ChainPaths (IEnumerable paths, bool loop = false) - { - var pathList = paths.ToList (); - for (int i = 0; i < pathList.Count; i++) - { - var currentPath = pathList [i]; - var nextPath = i + 1 < pathList.Count ? pathList [i + 1] : pathList.FirstOrDefault (); - - // Here we could define an event system to trigger path activation when another completes - // For example, you could listen for a "path complete" event and then activate the next path - if (loop && nextPath != null) - { - // Implementation depends on your event system - } - } - } -} diff --git a/Terminal.Gui/TextEffects/New/GradientFill.cs b/Terminal.Gui/TextEffects/New/GradientFill.cs deleted file mode 100644 index a6d69f4e3..000000000 --- a/Terminal.Gui/TextEffects/New/GradientFill.cs +++ /dev/null @@ -1,35 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Drawing; -using System.Linq; -using System.Text; -using System.Threading.Tasks; - -namespace Terminal.Gui.TextEffects; - -/// -/// Implementation of that uses a color gradient (including -/// radial, diagonal etc). -/// -public class GradientFill : IFill -{ - private Dictionary _map; - - public GradientFill (Rectangle area, Gradient gradient, Gradient.Direction direction) - { - _map = - gradient.BuildCoordinateColorMapping (area.Height, area.Width, direction) - .ToDictionary ( - (k) => new Point (k.Key.Column, k.Key.Row), - (v) => new Terminal.Gui.Color (v.Value.R, v.Value.G, v.Value.B)); - } - - public Terminal.Gui.Color GetColor (Point point) - { - if (_map.TryGetValue (point, out var color)) - { - return color; - } - return new Terminal.Gui.Color (0, 0, 0); // Default to black if point not found - } -} \ No newline at end of file diff --git a/Terminal.Gui/TextEffects/Terminal.cs b/Terminal.Gui/TextEffects/Terminal.cs deleted file mode 100644 index 08522069d..000000000 --- a/Terminal.Gui/TextEffects/Terminal.cs +++ /dev/null @@ -1,106 +0,0 @@ -namespace Terminal.Gui.TextEffects; -public class TerminalConfig -{ - public int TabWidth { get; set; } = 4; - public bool XtermColors { get; set; } = false; - public bool NoColor { get; set; } = false; - public bool WrapText { get; set; } = false; - public float FrameRate { get; set; } = 100.0f; - public int CanvasWidth { get; set; } = -1; - public int CanvasHeight { get; set; } = -1; - public string AnchorCanvas { get; set; } = "sw"; - public string AnchorText { get; set; } = "sw"; - public bool IgnoreTerminalDimensions { get; set; } = false; -} - -public class Canvas -{ - public int Top { get; private set; } - public int Right { get; private set; } - public int Bottom { get; private set; } = 1; - public int Left { get; private set; } = 1; - - public int CenterRow => (Top + Bottom) / 2; - public int CenterColumn => (Right + Left) / 2; - public Coord Center => new Coord (CenterColumn, CenterRow); - public int Width => Right - Left + 1; - public int Height => Top - Bottom + 1; - - public Canvas (int top, int right) - { - Top = top; - Right = right; - } - - public bool IsCoordInCanvas (Coord coord) - { - return coord.Column >= Left && coord.Column <= Right && - coord.Row >= Bottom && coord.Row <= Top; - } - - public Coord GetRandomCoord (bool outsideScope = false) - { - var random = new Random (); - if (outsideScope) - { - switch (random.Next (4)) - { - case 0: return new Coord (random.Next (Left, Right + 1), Top + 1); - case 1: return new Coord (random.Next (Left, Right + 1), Bottom - 1); - case 2: return new Coord (Left - 1, random.Next (Bottom, Top + 1)); - case 3: return new Coord (Right + 1, random.Next (Bottom, Top + 1)); - } - } - return new Coord ( - random.Next (Left, Right + 1), - random.Next (Bottom, Top + 1)); - } -} - -public class TerminalA -{ - public TerminalConfig Config { get; } - public Canvas Canvas { get; private set; } - private Dictionary CharacterByInputCoord = new Dictionary (); - - public TerminalA (string input, TerminalConfig config = null) - { - Config = config ?? new TerminalConfig (); - var dimensions = GetTerminalDimensions (); - Canvas = new Canvas (dimensions.height, dimensions.width); - ProcessInput (input); - } - - private void ProcessInput (string input) - { - // Handling input processing logic similar to Python's version - } - - public string GetPipedInput () - { - // C# way to get piped input or indicate there's none - return Console.IsInputRedirected ? Console.In.ReadToEnd () : string.Empty; - } - - public void Print (string output, bool enforceFrameRate = true) - { - if (enforceFrameRate) - EnforceFrameRate (); - - // Move cursor to top and clear the current console line - Console.SetCursorPosition (0, 0); - Console.Write (output); - Console.ResetColor (); - } - - private void EnforceFrameRate () - { - // Limit the printing speed based on the Config.FrameRate - } - - private (int width, int height) GetTerminalDimensions () - { - // Return terminal dimensions or defaults if not determinable - return (Console.WindowWidth, Console.WindowHeight); - } -} diff --git a/UICatalog/Scenarios/TextEffectsScenario.cs b/UICatalog/Scenarios/TextEffectsScenario.cs index 2df1131e9..d8f20bac1 100644 --- a/UICatalog/Scenarios/TextEffectsScenario.cs +++ b/UICatalog/Scenarios/TextEffectsScenario.cs @@ -3,10 +3,8 @@ using System.Collections.Generic; using System.Text; using System.Threading; using Terminal.Gui; -using Terminal.Gui.TextEffects; -using Color = Terminal.Gui.TextEffects.Color; -using Animation = Terminal.Gui.TextEffects.Animation; +using Terminal.Gui.Drawing; namespace UICatalog.Scenarios; @@ -68,18 +66,8 @@ public class TextEffectsScenario : Scenario }, DisplayText = "Gradients" }; - var t2 = new Tab () - { - View = new BallsView () - { - Width = Dim.Fill (), - Height = Dim.Fill (), - }, - DisplayText = "Ball" - }; tabView.AddTab (t1,false); - tabView.AddTab (t2,false); w.Add (tabView); @@ -111,11 +99,11 @@ public class TextEffectsScenario : Scenario // Define the colors of the gradient stops with more appealing colors stops = new List { - Color.FromRgb(0, 128, 255), // Bright Blue - Color.FromRgb(0, 255, 128), // Bright Green - Color.FromRgb(255, 255, 0), // Bright Yellow - Color.FromRgb(255, 128, 0), // Bright Orange - Color.FromRgb(255, 0, 128) // Bright Pink + new Color(0, 128, 255), // Bright Blue + new Color(0, 255, 128), // Bright Green + new Color(255, 255, 0), // Bright Yellow + new Color(255, 128, 0), // Bright Orange + new Color(255, 0, 128) // Bright Pink }; // Define the number of steps between each color for smoother transitions @@ -159,9 +147,9 @@ internal class GradientsView : View // Define the colors of the gradient stops var stops = new List { - Color.FromRgb(255, 0, 0), // Red - Color.FromRgb(0, 255, 0), // Green - Color.FromRgb(238, 130, 238) // Violet + new Color(255, 0, 0), // Red + new Color(0, 255, 0), // Green + new Color(238, 130, 238) // Violet }; // Define the number of steps between each color @@ -182,7 +170,7 @@ internal class GradientsView : View { for (int col = 0; col <= maxColumn; col++) { - var coord = new Coord (col, row); + var coord = new Point (col, row); var color = gradientMapping [coord]; SetColor (color); @@ -197,13 +185,13 @@ internal class GradientsView : View // Define the colors of the rainbow var stops = new List { - Color.FromRgb(255, 0, 0), // Red - Color.FromRgb(255, 165, 0), // Orange - Color.FromRgb(255, 255, 0), // Yellow - Color.FromRgb(0, 128, 0), // Green - Color.FromRgb(0, 0, 255), // Blue - Color.FromRgb(75, 0, 130), // Indigo - Color.FromRgb(238, 130, 238) // Violet + new Color(255, 0, 0), // Red + new Color(255, 165, 0), // Orange + new Color(255, 255, 0), // Yellow + new Color(0, 128, 0), // Green + new Color(0, 0, 255), // Blue + new Color(75, 0, 130), // Indigo + new Color(238, 130, 238) // Violet }; // Define the number of steps between each color @@ -240,245 +228,4 @@ internal class GradientsView : View new Terminal.Gui.Color (color.R, color.G, color.B) )); // Setting color based on RGB } -} - -internal class BallsView : View -{ - private Ball? _ball; - private bool _resized; - private LineCanvas lc; - private Gradient gradient; - - protected override void OnViewportChanged (DrawEventArgs e) - { - base.OnViewportChanged (e); - _resized = true; - - lc = new LineCanvas (new []{ - new StraightLine(new System.Drawing.Point(0,0),10,Orientation.Horizontal,LineStyle.Single), - - }); - TextEffectsScenario.GetAppealingGradientColors (out var stops, out var steps); - gradient = new Gradient (stops, steps); - var fill = new FillPair ( - new GradientFill (new System.Drawing.Rectangle (0, 0, 10, 0), gradient , Gradient.Direction.Horizontal), - new SolidFill(Terminal.Gui.Color.Black) - ); - lc.Fill = fill; - - } - - public override void OnDrawContent (Rectangle viewport) - { - base.OnDrawContent (viewport); - - if ((_ball == null && viewport.Width > 0 && viewport.Height > 0) || _resized) - { - _ball = new Ball (this); - _ball.Start (); - _resized = false; - } - - _ball?.Draw (); - - foreach(var map in lc.GetCellMap()) - { - Driver.SetAttribute (map.Value.Value.Attribute.Value); - AddRune (map.Key.X, map.Key.Y, map.Value.Value.Rune); - } - - for (int x = 0; x < 10; x++) - { - double fraction = (double)x / 10; - Color color = gradient.GetColorAtFraction (fraction); - - SetColor (color); - - AddRune (x, 2, new Rune ('█')); - } - - var map2 = gradient.BuildCoordinateColorMapping (0,10,Gradient.Direction.Horizontal); - - for (int x = 0; x < map2.Count; x++) - { - SetColor (map2[new Coord(x,0)]); - - AddRune (x, 3, new Rune ('█')); - } - } - - private void SetColor (Color color) - { - // Assuming AddRune is a method you have for drawing at specific positions - Application.Driver.SetAttribute ( - new Attribute ( - new Terminal.Gui.Color (color.R, color.G, color.B), - new Terminal.Gui.Color (color.R, color.G, color.B) - )); // Setting color based on RGB - } - public class Ball - { - public Animation Animation { get; private set; } - public Scene BouncingScene { get; private set; } - public View Viewport { get; private set; } - public EffectCharacter Character { get; private set; } - - public Ball (View viewport) - { - Viewport = viewport; - Character = new EffectCharacter (1, "O", 0, 0); - Animation = Character.Animation; - CreateBouncingScene (); - CreateMotionPath (); - } - - private void CreateBouncingScene () - { - BouncingScene = Animation.NewScene (isLooping: true); - int width = Viewport.Frame.Width; - int height = Viewport.Frame.Height; - double frequency = 4 * Math.PI / width; // Double the frequency - - for (int x = 0; x < width; x++) - { - int y = (int)((height - 1) / 2 * (1 + Math.Sin (frequency * x) * 0.8)); // Decrease amplitude - BouncingScene.AddFrame ("O", 1); - } - - for (int x = width - 1; x >= 0; x--) - { - int y = (int)((height - 1) / 2 * (1 + Math.Sin (frequency * x) * 0.8)); // Decrease amplitude - BouncingScene.AddFrame ("O", 1); - } - } - - private void CreateMotionPath () - { - int width = Viewport.Frame.Width; - int height = Viewport.Frame.Height; - double frequency = 4 * Math.PI / width; // Double the frequency - - var path = Character.Motion.CreatePath ("sineWavePath", speed: 1, loop: true); - - for (int x = 0; x < width; x++) - { - int y = (int)((height - 1) / 2 * (1 + Math.Sin (frequency * x) * 0.8)); // Decrease amplitude - path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y))); - } - - for (int x = width - 1; x >= 0; x--) - { - int y = (int)((height - 1) / 2 * (1 + Math.Sin (frequency * x) * 0.8)); // Decrease amplitude - path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y))); - } - - Character.Motion.ActivatePath (path); - } - - public void Start () - { - Animation.ActivateScene (BouncingScene); - new Thread (() => - { - while (true) - { - Thread.Sleep (10); // Adjust the speed of animation - Character.Tick (); - - Application.Invoke (() => Viewport.SetNeedsDisplay ()); - } - }) - { IsBackground = true }.Start (); - } - - public void Draw () - { - Driver.SetAttribute (Viewport.ColorScheme.Normal); - Viewport.AddRune (Character.Motion.CurrentCoord.Column, Character.Motion.CurrentCoord.Row, new Rune ('O')); - } - } -} - - -public class Ball -{ - public Animation Animation { get; private set; } - public Scene BouncingScene { get; private set; } - public View Viewport { get; private set; } - public EffectCharacter Character { get; private set; } - - public Ball (View viewport) - { - Viewport = viewport; - Character = new EffectCharacter (1, "O", 0, 0); - Animation = Character.Animation; - CreateBouncingScene (); - CreateMotionPath (); - } - - private void CreateBouncingScene () - { - BouncingScene = Animation.NewScene (isLooping: true); - int width = Viewport.Frame.Width; - int height = Viewport.Frame.Height; - double frequency = 4 * Math.PI / width; // Double the frequency - - for (int x = 0; x < width; x++) - { - int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude - BouncingScene.AddFrame ("O", 1); - } - - for (int x = width - 1; x >= 0; x--) - { - int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude - BouncingScene.AddFrame ("O", 1); - } - } - - private void CreateMotionPath () - { - int width = Viewport.Frame.Width; - int height = Viewport.Frame.Height; - double frequency = 4 * Math.PI / width; // Double the frequency - - var path = Character.Motion.CreatePath ("sineWavePath", speed: 1, loop: true); - - for (int x = 0; x < width; x++) - { - int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude - path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y))); - } - - for (int x = width - 1; x >= 0; x--) - { - int y = (int)((height) / 2 * (1 + Math.Sin (frequency * x))); // Decrease amplitude - path.AddWaypoint (new Waypoint ($"waypoint_{x}", new Coord (x, y))); - } - - Character.Motion.ActivatePath (path); - } - - public void Start () - { - Animation.ActivateScene (BouncingScene); - new Thread (() => - { - while (true) - { - Thread.Sleep (10); // Adjust the speed of animation - Character.Tick (); - - Application.Invoke (() => Viewport.SetNeedsDisplay ()); - } - }) - { IsBackground = true }.Start (); - } - - public void Draw () - { - Application.Driver.SetAttribute (Viewport.ColorScheme.Normal); - Viewport.AddRune (Character.Motion.CurrentCoord.Column, Character.Motion.CurrentCoord.Row, new Rune ('O')); - } -} - +} \ No newline at end of file diff --git a/UnitTests/TextEffects/AnimationTests.cs b/UnitTests/TextEffects/AnimationTests.cs deleted file mode 100644 index 84de80f70..000000000 --- a/UnitTests/TextEffects/AnimationTests.cs +++ /dev/null @@ -1,191 +0,0 @@ -using Terminal.Gui.TextEffects; - -namespace Terminal.Gui.TextEffectsTests; -using Color = Terminal.Gui.TextEffects.Color; - -public class AnimationTests -{ - private EffectCharacter character; - - public AnimationTests () - { - character = new EffectCharacter (0, "a", 0, 0); - } - - [Fact] - public void TestCharacterVisualInit () - { - var visual = new CharacterVisual ( - symbol: "a", - bold: true, - dim: false, - italic: true, - underline: false, - blink: true, - reverse: false, - hidden: true, - strike: false, - color: new Color ("ffffff"), - colorCode: "ffffff" - ); - Assert.Equal ("\x1b[1m\x1b[3m\x1b[5m\x1b[8m\x1b[38;2;255;255;255ma\x1b[0m", visual.FormattedSymbol); - Assert.True (visual.Bold); - Assert.False (visual.Dim); - Assert.True (visual.Italic); - Assert.False (visual.Underline); - Assert.True (visual.Blink); - Assert.False (visual.Reverse); - Assert.True (visual.Hidden); - Assert.False (visual.Strike); - Assert.Equal (new Color ("ffffff"), visual.Color); - Assert.Equal ("ffffff", visual.ColorCode); - } - - [Fact] - public void TestFrameInit () - { - var visual = new CharacterVisual ( - symbol: "a", - bold: true, - dim: false, - italic: true, - underline: false, - blink: true, - reverse: false, - hidden: true, - strike: false, - color: new Color ("ffffff") - ); - var frame = new Frame (characterVisual: visual, duration: 5); - Assert.Equal (visual, frame.CharacterVisual); - Assert.Equal (5, frame.Duration); - Assert.Equal (0, frame.TicksElapsed); - } - - [Fact] - public void TestSceneInit () - { - var scene = new Scene (sceneId: "test_scene", isLooping: true, sync: SyncMetric.Step, ease: Easing.InSine); - Assert.Equal ("test_scene", scene.SceneId); - Assert.True (scene.IsLooping); - Assert.Equal (SyncMetric.Step, scene.Sync); - Assert.Equal (Easing.InSine, scene.Ease); - } - - [Fact] - public void TestSceneAddFrame () - { - var scene = new Scene (sceneId: "test_scene"); - scene.AddFrame (symbol: "a", duration: 5, color: new Color ("ffffff"), bold: true, italic: true, blink: true, hidden: true); - Assert.Single (scene.Frames); - var frame = scene.Frames [0]; - Assert.Equal ("\x1b[1m\x1b[3m\x1b[5m\x1b[8m\x1b[38;2;255;255;255ma\x1b[0m", frame.CharacterVisual.FormattedSymbol); - Assert.Equal (5, frame.Duration); - Assert.Equal (new Color ("ffffff"), frame.CharacterVisual.Color); - Assert.True (frame.CharacterVisual.Bold); - } - - [Fact] - public void TestSceneAddFrameInvalidDuration () - { - var scene = new Scene (sceneId: "test_scene"); - var exception = Assert.Throws (() => scene.AddFrame (symbol: "a", duration: 0, color: new Color ("ffffff"))); - Assert.Equal ("duration must be greater than 0", exception.Message); - } - - [Fact] - public void TestSceneApplyGradientToSymbolsEqualColorsAndSymbols () - { - var scene = new Scene (sceneId: "test_scene"); - var gradient = new Gradient (new [] { new Color ("000000"), new Color ("ffffff") }, - steps: new [] { 2 }); - var symbols = new List { "a", "b", "c" }; - scene.ApplyGradientToSymbols (gradient, symbols, duration: 1); - Assert.Equal (3, scene.Frames.Count); - for (int i = 0; i < scene.Frames.Count; i++) - { - Assert.Equal (1, scene.Frames [i].Duration); - Assert.Equal (gradient.Spectrum [i].RgbColor, scene.Frames [i].CharacterVisual.ColorCode); - } - } - - [Fact] - public void TestSceneApplyGradientToSymbolsUnequalColorsAndSymbols () - { - var scene = new Scene (sceneId: "test_scene"); - var gradient = new Gradient ( - new [] { new Color ("000000"), new Color ("ffffff") }, - steps: new [] { 4 }); - var symbols = new List { "q", "z" }; - scene.ApplyGradientToSymbols (gradient, symbols, duration: 1); - Assert.Equal (5, scene.Frames.Count); - Assert.Equal (gradient.Spectrum [0].RgbColor, scene.Frames [0].CharacterVisual.ColorCode); - Assert.Contains ("q", scene.Frames [0].CharacterVisual.Symbol); - Assert.Equal (gradient.Spectrum [^1].RgbColor, scene.Frames [^1].CharacterVisual.ColorCode); - Assert.Contains ("z", scene.Frames [^1].CharacterVisual.Symbol); - } - - [Fact] - public void TestAnimationInit () - { - var animation = character.Animation; - Assert.Equal (character, animation.Character); - Assert.Empty (animation.Scenes); - Assert.Null (animation.ActiveScene); - Assert.False (animation.UseXtermColors); - Assert.False (animation.NoColor); - Assert.Empty (animation.XtermColorMap); - Assert.Equal (0, animation.ActiveSceneCurrentStep); - } - - [Fact] - public void TestAnimationNewScene () - { - var animation = character.Animation; - var scene = animation.NewScene (id:"test_scene", isLooping: true); - Assert.IsType (scene); - Assert.Equal ("test_scene", scene.SceneId); - Assert.True (scene.IsLooping); - Assert.True (animation.Scenes.ContainsKey ("test_scene")); - } - - [Fact] - public void TestAnimationNewSceneWithoutId () - { - var animation = character.Animation; - var scene = animation.NewScene (); - Assert.IsType (scene); - Assert.Equal ("0", scene.SceneId); - Assert.True (animation.Scenes.ContainsKey ("0")); - } - - [Fact] - public void TestAnimationQueryScene () - { - var animation = character.Animation; - var scene = animation.NewScene (id:"test_scene", isLooping: true); - Assert.Equal (scene, animation.QueryScene ("test_scene")); - } - - [Fact] - public void TestAnimationLoopingActiveSceneIsComplete () - { - var animation = character.Animation; - var scene = animation.NewScene (id: "test_scene", isLooping: true); - scene.AddFrame (symbol: "a", duration: 2); - animation.ActivateScene (scene); - Assert.True (animation.ActiveSceneIsComplete ()); - } - - [Fact] - public void TestAnimationNonLoopingActiveSceneIsComplete () - { - var animation = character.Animation; - var scene = animation.NewScene (id: "test_scene"); - scene.AddFrame (symbol: "a", duration: 1); - animation.ActivateScene (scene); - Assert.False (animation.ActiveSceneIsComplete ()); - animation.StepAnimation (); - Assert.True (animation.ActiveSceneIsComplete ()); - } -} \ No newline at end of file diff --git a/UnitTests/TextEffects/New/GradientFillTests.cs b/UnitTests/TextEffects/New/GradientFillTests.cs index 400425dc5..a4f38d9fe 100644 --- a/UnitTests/TextEffects/New/GradientFillTests.cs +++ b/UnitTests/TextEffects/New/GradientFillTests.cs @@ -1,4 +1,6 @@ -namespace Terminal.Gui.TextEffects.Tests; +using Terminal.Gui.Drawing; + +namespace Terminal.Gui.TextEffects.Tests; public class GradientFillTests { @@ -9,8 +11,8 @@ public class GradientFillTests // Define the colors of the gradient stops var stops = new List { - Color.FromRgb(255, 0, 0), // Red - Color.FromRgb(0, 0, 255) // Blue + new Color(255, 0, 0), // Red + new Color(0, 0, 255) // Blue }; // Define the number of steps between each color