Skip to content

Commit

Permalink
Fix strikethrough implementation (#134)
Browse files Browse the repository at this point in the history
* Fix strikethrough implementation

Details:
I didn't have a way of determing when strikethrough vs underline was happening.

I finally figured a somewhat hacky but legit as far as I can tell way to signal underline and strikethrough, which is to use a large value of thickness in the font metric.

Since we only support a thickness of 1 in a console app, this feels like a safe way to do it and shouldn't get in the way of anything.

* add default to switch with exception

* fix lint issue

* Automated JetBrains cleanup

Co-authored-by:  <[email protected]>

---------

Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
  • Loading branch information
tomlm and github-actions[bot] authored Nov 5, 2024
1 parent e04d738 commit d03adf2
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 31 deletions.
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 @@ internal class DrawingContextImpl : IDrawingContextImpl
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 @@ private void DrawLineInternal(IPen pen, Line line)
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 @@ private void DrawLineInternal(IPen pen, Line line)
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);
}
}

/// <summary>
/// Draw a rectangle line with corners
/// </summary>
Expand Down Expand Up @@ -388,7 +427,7 @@ private bool IfMoveConsoleCaretMove(IPen pen, Point head)
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
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

0 comments on commit d03adf2

Please sign in to comment.