Skip to content

Instantly share code, notes, and snippets.

@JKamsker
Last active May 11, 2023 12:41
Show Gist options
  • Select an option

  • Save JKamsker/6e2778076e7ef9d6cb9589da264f059b to your computer and use it in GitHub Desktop.

Select an option

Save JKamsker/6e2778076e7ef9d6cb9589da264f059b to your computer and use it in GitHub Desktop.
Spectre-RainbowSpinner
/*
Usage:
var spinner = new SpectreConsoleSpinner()
.WithRenderer(RenderableSpinner.SpinnerRenderer.Colored(Color.Rainbow));
// Checking logic
table.UpdateCell(currentRow, 0, spinner);
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ApDBT.Utils.SpectreUtils;
internal class Rainbowizer
{
public static string RainbowizeString(string input)
{
return RainbowColorGenerator.RainbowizeString(input);
}
private class RainbowColorGenerator
{
private int _hue;
public RainbowColorGenerator()
{
_hue = 0;
}
public static (byte r, byte g, byte b, byte a) GetNextColorRGBA(int index, int length)
{
int hue = (int)Math.Round((360.0 * index) / length);
return HsvToARgb(hue, 1, 1);
}
public (byte r, byte g, byte b, byte a) GetNextColorRGBA()
{
var hue = _hue;
_hue = (_hue + 10) % 360;
return HsvToARgb(hue, 1, 1);
}
public System.Drawing.Color GetNextColor()
{
var rgba = HsvToARgb(_hue, 1, 1);
var encoded = BitConverter.ToInt32(new[] { rgba.r, rgba.g, rgba.b, rgba.a });
var color = System.Drawing.Color.FromArgb(encoded);
_hue = (_hue + 10) % 360;
return color;
}
private static (byte r, byte g, byte b, byte a) HsvToARgb(int hue, double saturation, double value)
{
double chroma = value * saturation;
double huePrime = hue / 60.0;
double x = chroma * (1 - Math.Abs(huePrime % 2 - 1));
double red = 0, green = 0, blue = 0;
if (huePrime >= 0 && huePrime < 1)
{
red = chroma;
green = x;
}
else if (huePrime >= 1 && huePrime < 2)
{
red = x;
green = chroma;
}
else if (huePrime >= 2 && huePrime < 3)
{
green = chroma;
blue = x;
}
else if (huePrime >= 3 && huePrime < 4)
{
green = x;
blue = chroma;
}
else if (huePrime >= 4 && huePrime < 5)
{
red = x;
blue = chroma;
}
else if (huePrime >= 5 && huePrime < 6)
{
red = chroma;
blue = x;
}
double m = value - chroma;
byte r = (byte)((red + m) * 255);
byte g = (byte)((green + m) * 255);
byte b = (byte)((blue + m) * 255);
return (r, g, b, 255);
}
public static string RainbowizeString(string input)
{
//var output = new List<ColoredOutput>();
var sb = new StringBuilder();
//var colorGenerator = new RainbowColorGenerator();
int index = 0;
foreach (var c in input)
{
var color = RainbowColorGenerator.GetNextColorRGBA(index, input.Length);
var hexColor = $"#{color.r:x2}{color.b:x2}{color.g:x2}";
sb.Append($"[{hexColor}]");
AppendEscaped(sb, c);
sb.Append("[/]");
index++;
}
return sb.ToString();
}
/*
return text
.ReplaceExact("[", "[[")
.ReplaceExact("]", "]]");
*/
private static void AppendEscaped(StringBuilder sb, char input)
{
if (input == '[')
{
sb.Append("[[");
}
else if (input == ']')
{
sb.Append("]]");
}
else
{
sb.Append(input);
}
}
}
}
using Spectre.Console.Rendering;
using Spectre.Console;
namespace ApDBT.Utils.SpectreUtils;
public class RenderableSpinner : IRenderable
{
private readonly string[] _spinnerFrames;
private int _currentFrameIndex;
private Measurement _measurement;
public SpinnerRenderer Renderer = SpinnerRenderer.Default;
public RenderableSpinner(params string[] spinnerFrames)
{
_spinnerFrames = spinnerFrames;
//_minWith = _spinnerFrames.Min(x => x);
_measurement = new
(
spinnerFrames.Min(x => x.Length),
spinnerFrames.Max(x => x.Length)
);
}
public Measurement Measure(RenderOptions options, int maxWidth)
{
// The spinner occupies a fixed width
return _measurement;
}
public IEnumerable<Segment> Render(RenderOptions options, int maxWidth)
{
var currentFrame = _spinnerFrames[_currentFrameIndex];
_currentFrameIndex = (_currentFrameIndex + 1) % _spinnerFrames.Length;
return Render(options, maxWidth, currentFrame);
}
public virtual IEnumerable<Segment> Render(RenderOptions options, int maxWidth, string currentFrame)
{
//var segment = new Segment(currentFrame);
//yield return segment;
return (Renderer ?? SpinnerRenderer.Default).Render(options, maxWidth, currentFrame);
}
public abstract class SpinnerRenderer
{
public abstract IEnumerable<Segment> Render(RenderOptions options, int maxWidth, string currentFrame);
public static SpinnerRenderer Default => new ColoredSpinnerRenderer(null);
public static SpinnerRenderer Rainbow => new RainbowSpinnerRenderer();
public static SpinnerRenderer Colored(Color color) => new ColoredSpinnerRenderer(color);
private class ColoredSpinnerRenderer : SpinnerRenderer
{
private readonly Color? _color;
public ColoredSpinnerRenderer(Color? color)
{
_color = color;
}
public override IEnumerable<Segment> Render(RenderOptions options, int maxWidth, string currentFrame)
{
var style = Style.Plain;
if (_color != null)
{
style = style.Foreground(_color.Value);
}
var segment = new Segment(currentFrame, style);
yield return segment;
}
}
private class RainbowSpinnerRenderer : SpinnerRenderer
{
public override IEnumerable<Segment> Render(RenderOptions options, int maxWidth, string currentFrame)
{
var colored = Rainbowizer.RainbowizeString(currentFrame);
return ((IRenderable)new Markup(colored)).Render(options, maxWidth);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment