mirror of
https://github.com/gui-cs/Terminal.Gui.git
synced 2025-12-26 15:57:56 +01:00
Building
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
using static Unix.Terminal.Curses;
|
||||
|
||||
using static Terminal.Gui.TextEffects.EventHandler;
|
||||
|
||||
namespace Terminal.Gui.TextEffects;
|
||||
|
||||
@@ -7,7 +8,6 @@ public enum SyncMetric
|
||||
Distance,
|
||||
Step
|
||||
}
|
||||
|
||||
public class CharacterVisual
|
||||
{
|
||||
public string Symbol { get; set; }
|
||||
@@ -21,7 +21,9 @@ public class CharacterVisual
|
||||
public bool Strike { get; set; }
|
||||
public Color Color { get; set; }
|
||||
public string FormattedSymbol { get; private set; }
|
||||
private string _colorCode;
|
||||
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)
|
||||
{
|
||||
@@ -35,7 +37,7 @@ public class CharacterVisual
|
||||
Hidden = hidden;
|
||||
Strike = strike;
|
||||
Color = color;
|
||||
_colorCode = colorCode;
|
||||
_colorCode = colorCode; // Initialize _colorCode from the constructor argument
|
||||
FormattedSymbol = FormatSymbol ();
|
||||
}
|
||||
|
||||
@@ -49,7 +51,7 @@ public class CharacterVisual
|
||||
if (Reverse) formattingString += Ansitools.ApplyReverse ();
|
||||
if (Hidden) formattingString += Ansitools.ApplyHidden ();
|
||||
if (Strike) formattingString += Ansitools.ApplyStrikethrough ();
|
||||
if (_colorCode != null) formattingString += Colorterm.Fg (_colorCode);
|
||||
if (_colorCode != null) formattingString += Colorterm.Fg (_colorCode); // Use the direct color code
|
||||
|
||||
return $"{formattingString}{Symbol}{(formattingString != "" ? Ansitools.ResetAll () : "")}";
|
||||
}
|
||||
@@ -67,6 +69,7 @@ public class CharacterVisual
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Frame
|
||||
{
|
||||
public CharacterVisual CharacterVisual { get; }
|
||||
@@ -97,8 +100,8 @@ public class Scene
|
||||
public List<Frame> Frames { get; } = new List<Frame> ();
|
||||
public List<Frame> PlayedFrames { get; } = new List<Frame> ();
|
||||
public Dictionary<int, Frame> FrameIndexMap { get; } = new Dictionary<int, Frame> ();
|
||||
public int EasingTotalSteps { get; private set; }
|
||||
public int EasingCurrentStep { get; private set; }
|
||||
public int EasingTotalSteps { get; set; }
|
||||
public int EasingCurrentStep { get; set; }
|
||||
public static Dictionary<string, int> XtermColorMap { get; } = new Dictionary<string, int> ();
|
||||
|
||||
public Scene (string sceneId, bool isLooping = false, SyncMetric? sync = null, EasingFunction ease = null, bool noColor = false, bool useXtermColors = false)
|
||||
@@ -470,12 +473,6 @@ public class Animation
|
||||
}
|
||||
}
|
||||
|
||||
// Dummy Enum for Event handling
|
||||
public enum Event
|
||||
{
|
||||
SceneComplete,
|
||||
SceneActivated
|
||||
}
|
||||
|
||||
// Dummy classes for Ansitools, Colorterm, and Hexterm as placeholders
|
||||
public static class Ansitools
|
||||
|
||||
@@ -77,7 +77,9 @@ public class EventHandler
|
||||
Character.Motion.CurrentCoord = (Coord)target;
|
||||
break;
|
||||
case Action.Callback:
|
||||
(target as Action)?.Invoke ();
|
||||
|
||||
// TODO:
|
||||
throw new NotImplementedException ("TODO, port (target as Action)?.Invoke ()");
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException (nameof (action), "Unhandled action.");
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
namespace Terminal.Gui.TextEffects;
|
||||
|
||||
public abstract class BaseEffectIterator<T> : IEnumerable<string> where T : EffectConfig
|
||||
public abstract class BaseEffectIterator<T> where T : EffectConfig, new()
|
||||
{
|
||||
protected T Config { get; set; }
|
||||
protected Terminal Terminal { get; set; }
|
||||
@@ -12,8 +12,6 @@ public abstract class BaseEffectIterator<T> : IEnumerable<string> where T : Effe
|
||||
Terminal = new Terminal (effect.InputData, effect.TerminalConfig);
|
||||
}
|
||||
|
||||
public string Frame => Terminal.GetFormattedOutputString ();
|
||||
|
||||
public void Update ()
|
||||
{
|
||||
foreach (var character in ActiveCharacters)
|
||||
@@ -23,17 +21,6 @@ public abstract class BaseEffectIterator<T> : IEnumerable<string> where T : Effe
|
||||
ActiveCharacters.RemoveAll (character => !character.IsActive);
|
||||
}
|
||||
|
||||
public IEnumerator<string> GetEnumerator ()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator ()
|
||||
{
|
||||
return GetEnumerator ();
|
||||
}
|
||||
|
||||
public abstract string Next ();
|
||||
}
|
||||
|
||||
public abstract class BaseEffect<T> where T : EffectConfig, new()
|
||||
@@ -49,14 +36,7 @@ public abstract class BaseEffect<T> where T : EffectConfig, new()
|
||||
TerminalConfig = new TerminalConfig ();
|
||||
}
|
||||
|
||||
public abstract Type IteratorClass { get; }
|
||||
|
||||
public IEnumerator<string> GetEnumerator ()
|
||||
{
|
||||
var iterator = (BaseEffectIterator<T>)Activator.CreateInstance (IteratorClass, this);
|
||||
return iterator;
|
||||
}
|
||||
|
||||
/*
|
||||
public IDisposable TerminalOutput (string endSymbol = "\n")
|
||||
{
|
||||
var terminal = new Terminal (InputData, TerminalConfig);
|
||||
@@ -69,6 +49,6 @@ public abstract class BaseEffect<T> where T : EffectConfig, new()
|
||||
{
|
||||
terminal.RestoreCursor (endSymbol);
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
@@ -11,48 +11,3 @@ public class EffectConfig
|
||||
public float MovementSpeed { get; set; }
|
||||
public EasingFunction Easing { get; set; }
|
||||
}
|
||||
|
||||
public class NamedEffectIterator : BaseEffectIterator<EffectConfig>
|
||||
{
|
||||
public NamedEffectIterator (NamedEffect effect) : base (effect)
|
||||
{
|
||||
Build ();
|
||||
}
|
||||
|
||||
private void Build ()
|
||||
{
|
||||
var finalGradient = new Gradient (Config.FinalGradientStops, Config.FinalGradientSteps);
|
||||
foreach (var character in Terminal.GetCharacters ())
|
||||
{
|
||||
CharacterFinalColorMap [character] = finalGradient.GetColorAtFraction (
|
||||
character.InputCoord.Row / (float)Terminal.Canvas.Top
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public override string Next ()
|
||||
{
|
||||
if (PendingChars.Any () || ActiveCharacters.Any ())
|
||||
{
|
||||
Update ();
|
||||
return Frame;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InvalidOperationException ("No more elements in effect iterator.");
|
||||
}
|
||||
}
|
||||
|
||||
private List<EffectCharacter> PendingChars = new List<EffectCharacter> ();
|
||||
private Dictionary<EffectCharacter, Color> CharacterFinalColorMap = new Dictionary<EffectCharacter, Color> ();
|
||||
}
|
||||
|
||||
public class NamedEffect : BaseEffect<EffectConfig>
|
||||
{
|
||||
public NamedEffect (string inputData) : base (inputData)
|
||||
{
|
||||
}
|
||||
|
||||
protected override Type ConfigCls => typeof (EffectConfig);
|
||||
protected override Type IteratorCls => typeof (NamedEffectIterator);
|
||||
}
|
||||
|
||||
@@ -5,69 +5,64 @@ using System.Linq;
|
||||
|
||||
public class Color
|
||||
{
|
||||
public string RgbColor { get; }
|
||||
public int? XtermColor { get; }
|
||||
public string RgbColor { get; private set; }
|
||||
public int? XtermColor { get; private set; }
|
||||
|
||||
public Color (string rgbColor)
|
||||
{
|
||||
if (!IsValidHexColor (rgbColor))
|
||||
if (!ColorUtils.IsValidHexColor (rgbColor))
|
||||
throw new ArgumentException ("Invalid RGB hex color format.");
|
||||
|
||||
RgbColor = rgbColor.StartsWith ("#") ? rgbColor.Substring (1) : rgbColor;
|
||||
XtermColor = null; // Convert RGB to XTerm-256 here if necessary
|
||||
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 = ConvertXtermToHex (xtermColor); // Implement conversion logic
|
||||
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)
|
||||
);
|
||||
}
|
||||
|
||||
private bool IsValidHexColor (string color)
|
||||
{
|
||||
if (color.StartsWith ("#"))
|
||||
{
|
||||
color = color.Substring (1);
|
||||
}
|
||||
return color.Length == 6 && int.TryParse (color, System.Globalization.NumberStyles.HexNumber, null, out _);
|
||||
}
|
||||
public override string ToString () => $"#{RgbColor}";
|
||||
|
||||
private string ConvertXtermToHex (int xtermColor)
|
||||
public static Color FromRgb (int r, int g, int b)
|
||||
{
|
||||
// Dummy conversion for the sake of example
|
||||
return "000000"; // Actual conversion logic needed
|
||||
}
|
||||
// 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.");
|
||||
|
||||
public (int, int, int) GetRgbInts ()
|
||||
{
|
||||
int r = Convert.ToInt32 (RgbColor.Substring (0, 2), 16);
|
||||
int g = Convert.ToInt32 (RgbColor.Substring (2, 2), 16);
|
||||
int b = Convert.ToInt32 (RgbColor.Substring (4, 2), 16);
|
||||
return (r, g, b);
|
||||
}
|
||||
// Convert RGB values to a hexadecimal string
|
||||
string rgbColor = $"#{r:X2}{g:X2}{b:X2}";
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return $"#{RgbColor.ToUpper ()}";
|
||||
}
|
||||
|
||||
public override bool Equals (object obj)
|
||||
{
|
||||
return obj is Color other && RgbColor == other.RgbColor;
|
||||
}
|
||||
|
||||
public override int GetHashCode ()
|
||||
{
|
||||
return HashCode.Combine (RgbColor);
|
||||
// Create and return a new Color instance using the hexadecimal string
|
||||
return new Color (rgbColor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public class Gradient
|
||||
{
|
||||
public List<Color> Spectrum { get; private set; }
|
||||
|
||||
// Constructor now accepts IEnumerable<int> for steps.
|
||||
public Gradient (IEnumerable<Color> stops, IEnumerable<int> steps, bool loop = false)
|
||||
{
|
||||
if (stops == null || stops.Count () < 2)
|
||||
if (stops == null || !stops.Any () || stops.Count () < 2)
|
||||
throw new ArgumentException ("At least two color stops are required to create a gradient.");
|
||||
if (steps == null || !steps.Any ())
|
||||
throw new ArgumentException ("Steps are required to define the transitions between colors.");
|
||||
@@ -83,7 +78,8 @@ public class Gradient
|
||||
|
||||
for (int i = 0; i < stops.Count - 1; i++)
|
||||
{
|
||||
gradient.AddRange (InterpolateColors (stops [i], stops [i + 1], i < steps.Count ? steps [i] : steps.Last ()));
|
||||
int currentSteps = i < steps.Count ? steps [i] : steps.Last ();
|
||||
gradient.AddRange (InterpolateColors (stops [i], stops [i + 1], currentSteps));
|
||||
}
|
||||
|
||||
return gradient;
|
||||
@@ -93,16 +89,16 @@ public class Gradient
|
||||
{
|
||||
for (int step = 0; step <= steps; step++)
|
||||
{
|
||||
int r = Interpolate (start.GetRgbInts ().Item1, end.GetRgbInts ().Item1, steps, step);
|
||||
int g = Interpolate (start.GetRgbInts ().Item2, end.GetRgbInts ().Item2, steps, step);
|
||||
int b = Interpolate (start.GetRgbInts ().Item3, end.GetRgbInts ().Item3, steps, step);
|
||||
yield return new Color ($"#{r:X2}{g:X2}{b:X2}");
|
||||
int r = Interpolate (start.R, end.R, steps, step);
|
||||
int g = Interpolate (start.G, end.G, steps, step);
|
||||
int b = Interpolate (start.B, end.B, steps, step);
|
||||
yield return Color.FromRgb (r, g, b);
|
||||
}
|
||||
}
|
||||
|
||||
private int Interpolate (int start, int end, int steps, int currentStep)
|
||||
{
|
||||
return start + (end - start) * currentStep / steps;
|
||||
return start + (int)((end - start) * (double)currentStep / steps);
|
||||
}
|
||||
|
||||
public Color GetColorAtFraction (double fraction)
|
||||
@@ -112,15 +108,6 @@ public class Gradient
|
||||
int index = (int)(fraction * (Spectrum.Count - 1));
|
||||
return Spectrum [index];
|
||||
}
|
||||
|
||||
public IEnumerable<Color> GetRange (int startIndex, int count)
|
||||
{
|
||||
return Spectrum.Skip (startIndex).Take (count);
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return $"Gradient with {Spectrum.Count} colors.";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
94
Terminal.Gui/TextEffects/HexTerm.cs
Normal file
94
Terminal.Gui/TextEffects/HexTerm.cs
Normal file
@@ -0,0 +1,94 @@
|
||||
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<int, string> xtermToHexMap = new Dictionary<int, string>
|
||||
{
|
||||
{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<int, (int R, int G, int B)> 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));
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,6 @@ public class Segment
|
||||
return new Coord (column, row);
|
||||
}
|
||||
}
|
||||
|
||||
public class Path
|
||||
{
|
||||
public string PathId { get; private set; }
|
||||
@@ -69,6 +68,7 @@ public class Path
|
||||
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<double, double> easeFunction = null, int layer = 0, int holdTime = 0, bool loop = false)
|
||||
{
|
||||
@@ -100,9 +100,9 @@ public class Path
|
||||
|
||||
public Coord Step ()
|
||||
{
|
||||
if (EaseFunction != null && CurrentStep <= TotalDistance)
|
||||
if (CurrentStep <= MaxSteps)
|
||||
{
|
||||
double progress = EaseFunction ((double)CurrentStep / TotalDistance);
|
||||
double progress = EaseFunction?.Invoke ((double)CurrentStep / TotalDistance) ?? (double)CurrentStep / TotalDistance;
|
||||
double distanceTravelled = TotalDistance * progress;
|
||||
LastDistanceReached = distanceTravelled;
|
||||
|
||||
@@ -174,9 +174,19 @@ public class Motion
|
||||
ActivePath.CurrentStep = 0; // Reset the path's progress
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the active path to None if the active path is the given path.
|
||||
/// </summary>
|
||||
public void DeactivatePath (Path p)
|
||||
{
|
||||
if (p == ActivePath)
|
||||
{
|
||||
ActivePath = null;
|
||||
}
|
||||
}
|
||||
public void DeactivatePath ()
|
||||
{
|
||||
ActivePath = null;
|
||||
ActivePath = null;
|
||||
}
|
||||
|
||||
public void Move ()
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Security.Cryptography;
|
||||
using Terminal.Gui.TextEffects;
|
||||
using Xunit;
|
||||
using Terminal.Gui.TextEffects;
|
||||
|
||||
namespace Terminal.Gui.TextEffectsTests;
|
||||
using Color = Terminal.Gui.TextEffects.Color;
|
||||
|
||||
public class AnimationTests
|
||||
{
|
||||
@@ -100,7 +97,8 @@ public class AnimationTests
|
||||
public void TestSceneApplyGradientToSymbolsEqualColorsAndSymbols ()
|
||||
{
|
||||
var scene = new Scene (sceneId: "test_scene");
|
||||
var gradient = new Gradient (new Color ("000000"), new Color ("ffffff"), steps: 2);
|
||||
var gradient = new Gradient (new [] { new Color ("000000"), new Color ("ffffff") },
|
||||
steps: new [] { 2 });
|
||||
var symbols = new List<string> { "a", "b", "c" };
|
||||
scene.ApplyGradientToSymbols (gradient, symbols, duration: 1);
|
||||
Assert.Equal (3, scene.Frames.Count);
|
||||
@@ -115,7 +113,9 @@ public class AnimationTests
|
||||
public void TestSceneApplyGradientToSymbolsUnequalColorsAndSymbols ()
|
||||
{
|
||||
var scene = new Scene (sceneId: "test_scene");
|
||||
var gradient = new Gradient (new Color ("000000"), new Color ("ffffff"), steps: 4);
|
||||
var gradient = new Gradient (
|
||||
new [] { new Color ("000000"), new Color ("ffffff") },
|
||||
steps: new [] { 4 });
|
||||
var symbols = new List<string> { "q", "z" };
|
||||
scene.ApplyGradientToSymbols (gradient, symbols, duration: 1);
|
||||
Assert.Equal (5, scene.Frames.Count);
|
||||
@@ -142,7 +142,7 @@ public class AnimationTests
|
||||
public void TestAnimationNewScene ()
|
||||
{
|
||||
var animation = character.Animation;
|
||||
var scene = animation.NewScene ("test_scene", isLooping: true);
|
||||
var scene = animation.NewScene (id:"test_scene", isLooping: true);
|
||||
Assert.IsType<Scene> (scene);
|
||||
Assert.Equal ("test_scene", scene.SceneId);
|
||||
Assert.True (scene.IsLooping);
|
||||
@@ -163,7 +163,7 @@ public class AnimationTests
|
||||
public void TestAnimationQueryScene ()
|
||||
{
|
||||
var animation = character.Animation;
|
||||
var scene = animation.NewScene ("test_scene", isLooping: true);
|
||||
var scene = animation.NewScene (id:"test_scene", isLooping: true);
|
||||
Assert.Equal (scene, animation.QueryScene ("test_scene"));
|
||||
}
|
||||
|
||||
@@ -171,7 +171,7 @@ public class AnimationTests
|
||||
public void TestAnimationLoopingActiveSceneIsComplete ()
|
||||
{
|
||||
var animation = character.Animation;
|
||||
var scene = animation.NewScene ("test_scene", isLooping: true);
|
||||
var scene = animation.NewScene (id: "test_scene", isLooping: true);
|
||||
scene.AddFrame (symbol: "a", duration: 2);
|
||||
animation.ActivateScene (scene);
|
||||
Assert.True (animation.ActiveSceneIsComplete ());
|
||||
@@ -181,7 +181,7 @@ public class AnimationTests
|
||||
public void TestAnimationNonLoopingActiveSceneIsComplete ()
|
||||
{
|
||||
var animation = character.Animation;
|
||||
var scene = animation.NewScene ("test_scene");
|
||||
var scene = animation.NewScene (id: "test_scene");
|
||||
scene.AddFrame (symbol: "a", duration: 1);
|
||||
animation.ActivateScene (scene);
|
||||
Assert.False (animation.ActiveSceneIsComplete ());
|
||||
|
||||
Reference in New Issue
Block a user