Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix strikethrough implementation #134

Merged
merged 5 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 40 additions & 1 deletion src/Consolonia.Core/Drawing/DrawingContextImpl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
private const byte HorizontalLinePattern = 0b0101;
private const byte HorizontalEndPattern = 0b0001;

public const int UnderlineThickness = 10;
public const int StrikthroughThickness = 11;
private readonly Stack<Rect> _clipStack = new(100);
private readonly ConsoleWindow _consoleWindow;
private readonly PixelBuffer _pixelBuffer;
Expand Down Expand Up @@ -304,6 +306,13 @@
if (IfMoveConsoleCaretMove(pen, head))
return;

if (line.Vertical == false && pen.Thickness > 1)
{
// horizontal lines with thickness larger than one are text decorations
ApplyTextDecorationLineInternal(ref head, pen, line);
return;
}

var extractColorCheckPlatformSupported = ExtractColorOrNullWithPlatformCheck(pen, out var lineStyle);
if (extractColorCheckPlatformSupported == null)
return;
Expand All @@ -314,6 +323,36 @@
DrawPixelAndMoveHead(ref head, line, lineStyle, pattern, color, line.Length); //line
}

private void ApplyTextDecorationLineInternal(ref Point head, IPen pen, Line line)
{
TextDecorationCollection textDecoration = pen.Thickness switch
{
UnderlineThickness => TextDecorations.Underline,
StrikthroughThickness => TextDecorations.Strikethrough,
_ => throw new ArgumentOutOfRangeException($"Unsupported thickness {pen.Thickness}")
};

for (int x = 0; x < line.Length; x++)
{
Point h = head;
CurrentClip.ExecuteWithClipping(h, () =>
{
// ReSharper disable once AccessToModifiedClosure todo: pass as a parameter
_pixelBuffer.Set((PixelBufferCoordinate)h,
pixel =>
{
var newPixelForeground = new PixelForeground(pixel.Foreground.Symbol,
pixel.Foreground.Weight,
pixel.Foreground.Style,
textDecoration,
pixel.Foreground.Color);
return pixel.Blend(new Pixel(newPixelForeground, pixel.Background));
});
});
head = head.WithX(head.X + 1);
}
}
tomlm marked this conversation as resolved.
Show resolved Hide resolved

/// <summary>
/// Draw a rectangle line with corners
/// </summary>
Expand Down Expand Up @@ -388,7 +427,7 @@
if (pen is not
{
Brush: ConsoleBrush or LineBrush or ImmutableSolidColorBrush,
Thickness: 1,
// Thickness: 1,
DashStyle: null or { Dashes: { Count: 0 } },
LineCap: PenLineCap.Flat,
LineJoin: PenLineJoin.Miter
Expand Down Expand Up @@ -671,7 +710,7 @@
var clusteredColors = colors.Where((_, i) => clusters[i] == cluster).ToList();
if (clusteredColors.Any())
newClusterCenters[cluster] = GetAverageColor(clusteredColors);
if (clusteredColors.Count == 4)

Check notice on line 713 in src/Consolonia.Core/Drawing/DrawingContextImpl.cs

View workflow job for this annotation

GitHub Actions / build

"[InvertIf] Invert 'if' statement to reduce nesting" on /home/runner/work/Consolonia/Consolonia/src/Consolonia.Core/Drawing/DrawingContextImpl.cs(713,21)
if (clusteredColors.All(c => c.Alpha == 0))
return "FFFF";
// return "TTTT";
Expand Down
12 changes: 1 addition & 11 deletions src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -72,17 +72,7 @@ public Pixel Blend(Pixel pixelAbove)
new PixelBackground(mergedColors));

case PixelBackgroundMode.Transparent:
// when a textdecoration of underline happens a DrawLine() is called over the top of the a pixel with non-zero symbol.
// this detects this situation and eats the draw line, turning it into a textdecoration
if (pixelAbove.Foreground.Symbol is DrawingBoxSymbol &&
Foreground.Symbol is SimpleSymbol simpleSymbol &&
((ISymbol)simpleSymbol).GetCharacter() != (char)0)
// this is a line being draw through text. add TextDecoration for underline.
newForeground = new PixelForeground(Foreground.Symbol, Foreground.Weight, Foreground.Style,
TextDecorations.Underline, Foreground.Color);
else
// do normal blend.
newForeground = Foreground.Blend(pixelAbove.Foreground);
newForeground = Foreground.Blend(pixelAbove.Foreground);
newBackground = Background;
break;
case PixelBackgroundMode.Shaded:
Expand Down
8 changes: 4 additions & 4 deletions src/Consolonia.Core/Text/GlyphTypeface.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using Avalonia.Media;
using Consolonia.Core.Drawing;

namespace Consolonia.Core.Text
{
Expand Down Expand Up @@ -73,11 +74,10 @@ public bool TryGetTable(uint tag, out byte[] table)
Ascent = -1, //var height = (GlyphTypeface.Descent - GlyphTypeface.Ascent + GlyphTypeface.LineGap) * Scale; //todo: need to consult Avalonia guys
Descent = 0,
LineGap = 0,
UnderlinePosition =
-1, // this turns on TextDecorations="Underline", -1 is so it draws over the top of the text.
UnderlineThickness = 1, // this is the thickness of the underline, aka 1 char thick.
UnderlinePosition = -1,
UnderlineThickness = DrawingContextImpl.UnderlineThickness,
StrikethroughPosition = -1,
StrikethroughThickness = 1,
StrikethroughThickness = DrawingContextImpl.StrikthroughThickness,
IsFixedPitch = true
};

Expand Down
29 changes: 14 additions & 15 deletions src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,20 @@
Text="Multiline TextBlock with TextWrapping.&#xD;&#xD;Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." />
<TextBlock TextWrapping="Wrap"
Text="Special characters: Élève naïve: “𝔉𝔞𝔫𝔠𝔶” ligatures like ff, fi, and fl; numbers ½, ¼; symbols like @, #, and €; emoji 😊; and math symbols Ω, ∑, √…"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="TextDecoration=Underline" TextDecorations="Underline" HorizontalAlignment="Left"/>
<TextBlock Text="TextDecoration=Strikethrough" HorizontalAlignment="Left" TextDecorations="Strikethrough" />
<TextBlock Text="FontStyle=Italic" FontStyle="Italic" HorizontalAlignment="Left"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="FontWeight=BOLD" FontWeight="Bold" Foreground="Sienna"/>
<TextBlock Text="FontWeight=NORMAL" FontWeight="Normal" Foreground="Sienna"/>
<TextBlock Text="FontWeight=LIGHT" FontWeight="Light" Foreground="Sienna"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="FontWeight=BOLD" Background="DarkMagenta" Foreground="Yellow" FontWeight="Bold"/>
<TextBlock Text="FontWeight=NORMAL" Background="DarkMagenta" Foreground="Yellow" FontWeight="Normal"/>
<TextBlock Text="FontWeight=LIGHT" Background="DarkMagenta" Foreground="Yellow" FontWeight="Light"/>
</StackPanel>
<WrapPanel>
<TextBlock Text="Underline" TextDecorations="Underline" HorizontalAlignment="Left" Margin="1 0"/>
<TextBlock Text="Strikethrough" HorizontalAlignment="Left" TextDecorations="Strikethrough" Margin="1 0"/>
<TextBlock Text="Italic" FontStyle="Italic" HorizontalAlignment="Left" Margin="1 0"/>
<TextBlock Text="Italic and Underline" FontStyle="Italic" TextDecorations="Underline" HorizontalAlignment="Left" Margin="1 0"/>
</WrapPanel>
<WrapPanel >
<TextBlock Text="BOLD" FontWeight="Bold" Foreground="Sienna" Margin="1 0"/>
<TextBlock Text="NORMAL" FontWeight="Normal" Foreground="Sienna" Margin="1 0"/>
<TextBlock Text="LIGHT" FontWeight="Light" Foreground="Sienna" Margin="1 0"/>
<TextBlock Text="BOLD" Background="DarkMagenta" Foreground="Yellow" FontWeight="Bold" Margin="1 0"/>
<TextBlock Text="NORMAL" Background="DarkMagenta" Foreground="Yellow" FontWeight="Normal" Margin="1 0"/>
<TextBlock Text="LIGHT" Background="DarkMagenta" Foreground="Yellow" FontWeight="Light" Margin="1 0"/>
</WrapPanel>

</StackPanel>

Expand Down
Loading