forked from gui-cs/Terminal.Gui
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
399 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,399 @@ | ||
using System; | ||
using System.Collections.Generic; | ||
using static System.Runtime.InteropServices.JavaScript.JSType; | ||
using Terminal.Gui; | ||
|
||
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; | ||
|
||
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; | ||
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); | ||
|
||
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<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 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) | ||
{ | ||
SceneId = sceneId; | ||
IsLooping = isLooping; | ||
Sync = sync; | ||
Ease = ease; | ||
NoColor = noColor; | ||
UseXtermColors = useXtermColors; | ||
} | ||
|
||
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) | ||
{ | ||
if (color.XtermColor != null) | ||
{ | ||
charVisColor = color.XtermColor; | ||
} | ||
else if (XtermColorMap.ContainsKey (color.RgbColor)) | ||
{ | ||
// Build error says Error CS0029 Cannot implicitly convert type 'int' to 'string' Terminal.Gui (net8.0) D:\Repos\TerminalGuiDesigner\gui.cs\Terminal.Gui\TextEffects\Animation.cs 120 Active | ||
charVisColor = XtermColorMap [color.RgbColor].ToString (); | ||
} | ||
else | ||
{ | ||
var xtermColor = Hexterm.HexToXterm (color.RgbColor); | ||
XtermColorMap [color.RgbColor] = int.Parse (xtermColor); | ||
charVisColor = xtermColor; | ||
} | ||
} | ||
else | ||
{ | ||
charVisColor = color.RgbColor; | ||
} | ||
} | ||
|
||
if (duration < 1) | ||
{ | ||
throw new ArgumentException ("duration must be greater than 0"); | ||
} | ||
|
||
var charVis = new CharacterVisual (symbol, bold, dim, italic, underline, blink, reverse, hidden, strike, color, charVisColor); | ||
var frame = new Frame (charVis, duration); | ||
Frames.Add (frame); | ||
for (int i = 0; i < frame.Duration; i++) | ||
{ | ||
FrameIndexMap [EasingTotalSteps] = frame; | ||
EasingTotalSteps++; | ||
} | ||
} | ||
|
||
public CharacterVisual Activate () | ||
{ | ||
if (Frames.Count > 0) | ||
{ | ||
return Frames [0].CharacterVisual; | ||
} | ||
else | ||
{ | ||
throw new InvalidOperationException ("Scene has no frames."); | ||
} | ||
} | ||
|
||
public CharacterVisual GetNextVisual () | ||
{ | ||
var currentFrame = Frames [0]; | ||
var nextVisual = currentFrame.CharacterVisual; | ||
currentFrame.IncrementTicks (); | ||
if (currentFrame.TicksElapsed == currentFrame.Duration) | ||
{ | ||
currentFrame.TicksElapsed = 0; | ||
PlayedFrames.Add (Frames [0]); | ||
Frames.RemoveAt (0); | ||
if (IsLooping && Frames.Count == 0) | ||
{ | ||
Frames.AddRange (PlayedFrames); | ||
PlayedFrames.Clear (); | ||
} | ||
} | ||
return nextVisual; | ||
} | ||
|
||
public void ApplyGradientToSymbols (Gradient gradient, IList<string> 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 () | ||
{ | ||
foreach (var sequence in Frames) | ||
{ | ||
sequence.TicksElapsed = 0; | ||
PlayedFrames.Add (sequence); | ||
} | ||
Frames.Clear (); | ||
Frames.AddRange (PlayedFrames); | ||
PlayedFrames.Clear (); | ||
} | ||
|
||
public override bool Equals (object obj) | ||
{ | ||
if (obj is Scene other) | ||
{ | ||
return SceneId == other.SceneId; | ||
} | ||
return false; | ||
} | ||
|
||
public override int GetHashCode () | ||
{ | ||
return SceneId.GetHashCode (); | ||
} | ||
} | ||
|
||
public class Animation | ||
{ | ||
public Dictionary<string, Scene> Scenes { get; } = new Dictionary<string, Scene> (); | ||
public EffectCharacter Character { get; } | ||
public Scene ActiveScene { get; private set; } | ||
public bool UseXtermColors { get; set; } = false; | ||
public bool NoColor { get; set; } = false; | ||
public Dictionary<string, int> XtermColorMap { get; } = new Dictionary<string, int> (); | ||
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 bool SceneExists (string sceneId) | ||
{ | ||
return Scenes.ContainsKey (sceneId); | ||
} | ||
|
||
public void ActivateScene (string sceneId) | ||
{ | ||
ActiveScene = QueryScene (sceneId); | ||
CurrentCharacterVisual = ActiveScene.Activate (); | ||
ActiveSceneCurrentStep = 0; | ||
} | ||
|
||
public void IncrementScene () | ||
{ | ||
if (ActiveScene == null || ActiveSceneIsComplete ()) | ||
{ | ||
return; | ||
} | ||
CurrentCharacterVisual = ActiveScene.GetNextVisual (); | ||
} | ||
} | ||
|
||
public class EffectCharacter | ||
{ | ||
public string InputSymbol { get; } | ||
public CharacterVisual CharacterVisual { get; set; } | ||
public Animation Animation { get; set; } | ||
|
||
public EffectCharacter (string inputSymbol) | ||
{ | ||
InputSymbol = inputSymbol; | ||
CharacterVisual = new CharacterVisual (inputSymbol); | ||
Animation = new Animation (this); | ||
} | ||
|
||
public void Animate (string sceneId) | ||
{ | ||
Animation.ActivateScene (sceneId); | ||
Animation.IncrementScene (); | ||
CharacterVisual = Animation.CurrentCharacterVisual; | ||
} | ||
|
||
public void ResetEffects () | ||
{ | ||
CharacterVisual.DisableModes (); | ||
} | ||
} | ||
|
||
public class Color | ||
{ | ||
public string RgbColor { get; } | ||
public string XtermColor { get; } | ||
|
||
public Color (string rgbColor, string xtermColor) | ||
{ | ||
RgbColor = rgbColor; | ||
XtermColor = xtermColor; | ||
} | ||
} | ||
|
||
public class Gradient | ||
{ | ||
public List<Color> Spectrum { get; } | ||
|
||
public Gradient (List<Color> spectrum) | ||
{ | ||
Spectrum = spectrum; | ||
} | ||
} | ||
|
||
public class EasingFunction | ||
{ | ||
// Easing functions implementation | ||
} | ||
|
||
// 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 | ||
} | ||
} |