diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index 1f518620..438dbe66 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -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 _clipStack = new(100); private readonly ConsoleWindow _consoleWindow; private readonly PixelBuffer _pixelBuffer; @@ -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; @@ -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); + } + } + /// /// Draw a rectangle line with corners /// @@ -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 diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs index ab68445d..54b3010a 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs @@ -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: diff --git a/src/Consolonia.Core/Text/GlyphTypeface.cs b/src/Consolonia.Core/Text/GlyphTypeface.cs index 14b16805..6ce98a97 100644 --- a/src/Consolonia.Core/Text/GlyphTypeface.cs +++ b/src/Consolonia.Core/Text/GlyphTypeface.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using Avalonia.Media; +using Consolonia.Core.Drawing; namespace Consolonia.Core.Text { @@ -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 }; diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml index eed9e198..a0f44c58 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryTextBlock.axaml @@ -30,21 +30,20 @@ Text="Multiline TextBlock with TextWrapping. 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." /> - - - - - - - - - - - - - - - + + + + + + + + + + + + + +