Skip to content

Commit

Permalink
Generate random colors for highlights
Browse files Browse the repository at this point in the history
  • Loading branch information
KyrietS committed Oct 18, 2024
1 parent 7ba3f28 commit 8d19a86
Show file tree
Hide file tree
Showing 4 changed files with 86 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -274,15 +274,16 @@ private void SetBackgroundToLineWithCaret(int viewLineIndex)

private void SetLineHighlight(int viewLineIndex, ReadOnlyMemory<char> line)
{
foreach (var (pattern, background, foreground) in _highlights ?? [])
foreach (var highlight in _highlights ?? [])
{
var matches = pattern.MatchAll(line);
var matches = highlight.Pattern.MatchAll(line);
foreach (var (matchBegin, matchEnd) in matches)
{
TextArea.ApplyStyleToLine(viewLineIndex, (matchBegin..matchEnd),
new Style
{
Background = new SolidColorBrush(background),
Foreground = highlight.HasEnoughContrastWith(TextArea.ForegroundColor) ? TextArea.Foreground : TextArea.Background,
Background = new SolidColorBrush(highlight.Background),
Typeface = new Typeface(TextArea.SecondaryFontFamily)
});
}
Expand Down
3 changes: 3 additions & 0 deletions src/LogAlligator.App/Controls/TextView/TextArea.cs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ public IBrush Foreground
set => SetValue(ForegroundProperty, value);
}

public Color ForegroundColor => ((SolidColorBrush)Foreground).Color;
public Color BackgroundColor => ((SolidColorBrush)Background).Color;

public static readonly StyledProperty<double> FontSizeProperty =
AvaloniaProperty.Register<TextArea, double>(nameof(FontSize), 12);

Expand Down
38 changes: 38 additions & 0 deletions src/LogAlligator.App/Utils/HighlightColorProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using System;
using Avalonia.Media;

namespace LogAlligator.App.Utils;

public class HighlightColorProvider(Random? random = null)
{
private Random _random = random ?? Random.Shared;

public Color GetHighlightColor()
{
return GetRandomColor();
}

private Color GetRandomColor()
{
double hue = GetHue();
double saturation = 1.0;
double lightness = GetLightness();

return HslColor.ToRgb(hue * 360, saturation, lightness);
}

private double GetHue()
{
return _random.NextDouble();
}

private double GetLightness()
{
return RandomBetween(0.1, 0.9);
}

private double RandomBetween(double min, double max)
{
return min + _random.NextDouble() * (max - min);
}
}
86 changes: 41 additions & 45 deletions src/LogAlligator.App/Utils/Highlights.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,83 +8,79 @@ namespace LogAlligator.App.Utils;

public record struct Highlight
{
private const double MINIMAL_CONTRAST_RATIO = 7.5;
public SearchPattern Pattern { get; set; }
public Color Background { get; set; }
public Color? Foreground { get; set; }

public void Deconstruct(out SearchPattern pattern, out Color background, out Color? foreground)
{
pattern = Pattern;
background = Background;
foreground = Foreground;
}
public bool HasEnoughContrastWith(Color color) => ContrastRatio(Background, color) >= MINIMAL_CONTRAST_RATIO;

public override string ToString()
{
return Pattern.Pattern.ToString();
}

private static double ContrastRatio(Color color1, Color color2)
{
return ContrastRatio(RelativeLuminance(color1), RelativeLuminance(color2));
}

/// <summary>
/// Constrast ratio calculated according to WCAG.
/// https://www.w3.org/TR/WCAG21/#dfn-contrast-ratio
/// </summary>
private static double ContrastRatio(double luminance1, double luminance2)
{
return (Math.Max(luminance1, luminance2) + 0.05) / (Math.Min(luminance1, luminance2) + 0.05);
}

/// <summary>
/// Relative luminance calculated according to WCAG.
/// https://www.w3.org/TR/WCAG21/#dfn-relative-luminance
/// </summary>
private static double RelativeLuminance(Color color)
{
double R = color.R / 255.0;
double G = color.G / 255.0;
double B = color.B / 255.0;

R = R <= 0.04045 ? R / 12.92 : Math.Pow((R + 0.055) / 1.055, 2.4);
G = G <= 0.04045 ? G / 12.92 : Math.Pow((G + 0.055) / 1.055, 2.4);
B = B <= 0.04045 ? B / 12.92 : Math.Pow((B + 0.055) / 1.055, 2.4);

return 0.2126 * R + 0.7152 * G + 0.0722 * B;
}
}

public class Highlights : IEnumerable<Highlight>
{
private readonly List<Highlight> _highlights = [];
private readonly HighlightColorProvider _colorProvider = new();

public event EventHandler? OnChange;

public void Add(ReadOnlyMemory<char> pattern, Color background)
public void Add(ReadOnlyMemory<char> pattern)
{
if (pattern.Length == 0 || Contains(pattern))
if (pattern.Length == 0)
return;

_highlights.Add(new Highlight { Pattern = new SearchPattern(pattern), Background = background });
var highlight = _colorProvider.GetHighlightColor();
_highlights.Add(new Highlight { Pattern = new SearchPattern(pattern), Background = highlight });
OnChange?.Invoke(this, EventArgs.Empty);
}

public void Add(ReadOnlyMemory<char> pattern)
{
Add(pattern, GetColor());
}

public void Remove(ReadOnlyMemory<char> pattern)
{
if (!Contains(pattern))
return;

_highlights.RemoveAll(h => h.Pattern.Equals(pattern));
OnChange?.Invoke(this, EventArgs.Empty);
int numOfRemoved = _highlights.RemoveAll(h => h.Pattern.Equals(pattern));
if (numOfRemoved > 0)
OnChange?.Invoke(this, EventArgs.Empty);
}

public bool Contains(ReadOnlyMemory<char> pattern)
{
return _highlights.Any(h => h.Pattern.Equals(pattern));
}

private Color GetColor()
{
Color[] colors =
[
Colors.Yellow,
Colors.Orange,
Colors.LimeGreen,
Colors.Pink,
Colors.Cyan,
Colors.Lime,
Colors.Aqua,
Colors.Beige,
Colors.Coral,
Colors.Gold,
];

foreach (var color in colors)
{
if (_highlights.All(h => h.Background != color))
return color;
}

// All colors are used, return yellow
return Colors.Yellow;
}

public IEnumerator<Highlight> GetEnumerator()
{
return _highlights.GetEnumerator();
Expand Down

0 comments on commit 8d19a86

Please sign in to comment.