From 2dd81adefe2f88da719d127c1be7e2ebb21fa962 Mon Sep 17 00:00:00 2001 From: Evgeny Gorbovoy Date: Thu, 26 Dec 2024 00:20:39 +0100 Subject: [PATCH] 190-strange-coloring-remove-console-brush (#227) --- src/.editorconfig | 2 +- .../Controls/Dialog/DialogWrap.axaml | 3 +- .../{ConsoleBrush.cs => BrushExtensions.cs} | 107 ++---------------- .../Drawing/DrawingContextImpl.cs | 37 +++--- .../DrawingBoxSymbol.cs | 6 +- .../PixelBufferImplementation/ISymbol.cs | 2 +- .../PixelBufferImplementation/Pixel.cs | 100 ++++++++-------- .../PixelBackground.cs | 51 +-------- .../PixelBackgroundMode.cs | 3 + .../PixelForeground.cs | 5 + .../PixelBufferImplementation/SimpleSymbol.cs | 4 +- .../GalleryViews/GalleryColors.axaml.cs | 7 +- .../GalleryViews/GalleryDataGrid.axaml.cs | 7 +- src/Consolonia.NUnit/UnitTestConsole.cs | 2 +- .../Fluent/FluentColors.axaml | 50 ++++---- .../Material/MaterialColors.axaml | 50 ++++---- .../Templates/Controls/CalendarItem.axaml | 7 +- .../Templates/Controls/DataGrid.axaml | 8 +- .../Templates/Controls/DialogWindow.axaml | 4 +- .../Helpers/ConsoloniaTextPresenter.cs | 10 +- .../Templates/Controls/Popup.axaml | 9 +- .../Templates/TurboVisionDefaultColors.axaml | 55 +++++---- .../TurboVisionBlackColors.axaml | 49 ++++---- .../TurboVisionDarkColors.axaml | 49 ++++---- src/Example/Views/DataGridTestWindow.axaml | 8 +- .../PixelBackgroundTests.cs | 25 +--- src/Tests/Consolonia.Core.Tests/PixelTests.cs | 39 +++++-- .../SimpleSymbolTests.cs | 6 +- 28 files changed, 280 insertions(+), 425 deletions(-) rename src/Consolonia.Core/Drawing/{ConsoleBrush.cs => BrushExtensions.cs} (60%) diff --git a/src/.editorconfig b/src/.editorconfig index f8c01848..85fa8dcd 100644 --- a/src/.editorconfig +++ b/src/.editorconfig @@ -2677,7 +2677,7 @@ resharper_int_variable_overflow_in_unchecked_context_highlighting = warning resharper_invalid_value_type_highlighting = warning resharper_invalid_xml_doc_comment_highlighting = warning resharper_invert_condition_1_highlighting = hint -resharper_invert_if_highlighting = hint +resharper_invert_if_highlighting = none resharper_invocation_is_skipped_highlighting = hint resharper_invoke_as_extension_method_highlighting = suggestion resharper_is_expression_always_false_highlighting = warning diff --git a/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml b/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml index 89fcd51e..fa2d13c1 100644 --- a/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml +++ b/src/Consolonia.Core/Controls/Dialog/DialogWrap.axaml @@ -1,10 +1,9 @@ - diff --git a/src/Consolonia.Core/Drawing/ConsoleBrush.cs b/src/Consolonia.Core/Drawing/BrushExtensions.cs similarity index 60% rename from src/Consolonia.Core/Drawing/ConsoleBrush.cs rename to src/Consolonia.Core/Drawing/BrushExtensions.cs index a2d3bc88..8c37d15c 100644 --- a/src/Consolonia.Core/Drawing/ConsoleBrush.cs +++ b/src/Consolonia.Core/Drawing/BrushExtensions.cs @@ -1,96 +1,14 @@ using System; -using System.Diagnostics; -using Avalonia; using Avalonia.Media; -using Consolonia.Core.Drawing.PixelBufferImplementation; using Consolonia.Core.Infrastructure; namespace Consolonia.Core.Drawing { - [DebuggerDisplay("{Color} [{Mode}]")] - public class ConsoleBrush : AvaloniaObject, IImmutableBrush + public static class BrushExtensions //todo: investigate why resharper does not complain about wrong file naming { - public static readonly StyledProperty ColorProperty = - AvaloniaProperty.Register(nameof(Color)); - - public static readonly StyledProperty ModeProperty = - AvaloniaProperty.Register(nameof(Mode)); - - // ReSharper disable once UnusedMember.Global - public ConsoleBrush(Color color, PixelBackgroundMode mode) : this(color) - { - Mode = mode; - } - - public ConsoleBrush(Color color) - { - Color = color; - } - - public ConsoleBrush() - { - } - - public PixelBackgroundMode Mode - { - get => GetValue(ModeProperty); - set => SetValue(ModeProperty, value); - } - - public Color Color - { - get => GetValue(ColorProperty); - set => SetValue(ColorProperty, value); - } - - public double Opacity => 1; - public ITransform Transform => null; - public RelativePoint TransformOrigin => RelativePoint.TopLeft; - - /// - /// Convert a IBrush to a Brush. - /// - /// - /// NOTE: If it's a ConsoleBrush it will be passed through unchanged, unless mode is set then it will convert - /// consolebrush to mode - /// - /// - /// Default is Colored. - /// - public static ConsoleBrush FromBrush(IBrush brush, PixelBackgroundMode? mode = null) - { - ArgumentNullException.ThrowIfNull(brush, nameof(brush)); - - switch (brush) - { - case ConsoleBrush consoleBrush: - if (mode != null && consoleBrush.Mode != mode) - return new ConsoleBrush(consoleBrush.Color, mode.Value); - return consoleBrush; - - case LineBrush lineBrush: - switch (lineBrush.Brush) - { - case ConsoleBrush consoleBrush: - return consoleBrush; - case ISolidColorBrush br: - return new ConsoleBrush(br.Color, mode ?? PixelBackgroundMode.Colored); - default: - ConsoloniaPlatform.RaiseNotSupported(6); - return null; - } - - case ISolidColorBrush solidBrush: - return new ConsoleBrush(solidBrush.Color, mode ?? PixelBackgroundMode.Colored); - - default: - ConsoloniaPlatform.RaiseNotSupported(6); - return null; - } - } - - public static ConsoleBrush FromPosition(IBrush brush, int x, int y, int width, int height) + public static Color FromPosition(this IBrush brush, int x, int y, int width, int height) { + //todo: apply brush opacity ArgumentNullException.ThrowIfNull(brush); if (x < 0 || x > width) throw new ArgumentOutOfRangeException(nameof(x), "x is out bounds"); @@ -115,7 +33,7 @@ public static ConsoleBrush FromPosition(IBrush brush, int x, int y, int width, i // Average the two colors to get the final color Color color = BlendColors(horizontalColor, verticalColor); - return new ConsoleBrush(color); + return color; } case IRadialGradientBrush radialBrush: { @@ -142,7 +60,7 @@ public static ConsoleBrush FromPosition(IBrush brush, int x, int y, int width, i // Interpolate the color based on the normalized distance Color color = InterpolateColor(radialBrush, normalizedDistance); - return new ConsoleBrush(color); + return color; } case IConicGradientBrush conicBrush: { @@ -160,21 +78,18 @@ public static ConsoleBrush FromPosition(IBrush brush, int x, int y, int width, i // Average the two colors to get the final color Color color = BlendColors(horizontalColor, verticalColor); - return new ConsoleBrush(color); + return color; } + case ISolidColorBrush solidColorBrush: + return solidColorBrush.Color; + default: - return FromBrush(brush); + ConsoloniaPlatform.RaiseNotSupported(751, brush); //todo: allow RaiseNotSupported to return a result + return new Color(); } } - // ReSharper disable once UnusedMember.Global used by Avalonia - // ReSharper disable once UnusedParameter.Global - public IBrush ProvideValue(IServiceProvider _) - { - return this; - } - private static Color InterpolateColor(IGradientBrush brush, double relativePosition) { IGradientStop before = null; diff --git a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs index 3582dee6..0c82b258 100644 --- a/src/Consolonia.Core/Drawing/DrawingContextImpl.cs +++ b/src/Consolonia.Core/Drawing/DrawingContextImpl.cs @@ -4,7 +4,6 @@ using System.Text; using Avalonia; using Avalonia.Media; -using Avalonia.Media.Immutable; using Avalonia.Media.TextFormatting; using Avalonia.Platform; using Consolonia.Core.Drawing.PixelBufferImplementation; @@ -528,12 +527,11 @@ private void FillRectangleWithBrush(IBrush brush, IPen pen, Rect r) int px = (int)(r2.TopLeft.X + x); int py = (int)(r2.TopLeft.Y + y); - ConsoleBrush backgroundBrush = ConsoleBrush.FromPosition(brush, x, y, (int)width, (int)height); + Color backgroundColor = brush.FromPosition(x, y, (int)width, (int)height); CurrentClip.ExecuteWithClipping(new Point(px, py), () => { _pixelBuffer.Set(new PixelBufferCoordinate((ushort)px, (ushort)py), - pixel => pixel.Blend(new Pixel(new PixelBackground(backgroundBrush.Mode, - backgroundBrush.Color)))); + pixel => pixel.Blend(new Pixel(new PixelBackground(backgroundColor)))); }); } } @@ -653,9 +651,9 @@ private Line TransformLineInternal(Line line) lineStyle = null; if (pen is not { - Brush: ConsoleBrush or LineBrush or ImmutableSolidColorBrush, + Brush: LineBrush or ISolidColorBrush, // Thickness: 1, - DashStyle: null or { Dashes: { Count: 0 } }, + DashStyle: null or { Dashes.Count: 0 }, LineCap: PenLineCap.Flat, LineJoin: PenLineJoin.Miter }) @@ -664,23 +662,15 @@ private Line TransformLineInternal(Line line) return null; } - if (pen.Brush is LineBrush lineBrush) - lineStyle = lineBrush.LineStyle; - - ConsoleBrush consoleBrush = ConsoleBrush.FromBrush(pen.Brush); + IBrush brush = pen.Brush; - switch (consoleBrush.Mode) + if (brush is LineBrush lineBrush) { - case PixelBackgroundMode.Colored: - return consoleBrush.Color; - case PixelBackgroundMode.Transparent: - return null; - case PixelBackgroundMode.Shaded: - ConsoloniaPlatform.RaiseNotSupported(8); - return null; - default: - throw new ArgumentOutOfRangeException(nameof(pen)); + lineStyle = lineBrush.LineStyle; + brush = lineBrush.Brush; } + + return ((ISolidColorBrush)brush).Color; } /// @@ -731,14 +721,13 @@ private void DrawLineSymbolAndMoveHead(ref Point head, bool isVertical, ISymbol private void DrawStringInternal(IBrush foreground, string text, IGlyphTypeface typeface, Point origin = new()) { - foreground = ConsoleBrush.FromBrush(foreground); - if (foreground is not ConsoleBrush { Mode: PixelBackgroundMode.Colored } consoleBrush) + if (foreground is not ISolidColorBrush solidColorBrush) { ConsoloniaPlatform.RaiseNotSupported(4); return; } - // if (!Transform.IsTranslateOnly()) ConsoloniaPlatform.RaiseNotSupported(15); + // if (!Transform.IsTranslateOnly()) ConsoloniaPlatform.RaiseNotSupported(15); //todo: what to do if a rotation? Point whereToDraw = origin.Transform(Transform); int currentXPosition = 0; @@ -751,7 +740,7 @@ private void DrawLineSymbolAndMoveHead(ref Point head, bool isVertical, ISymbol { Point characterPoint = whereToDraw.Transform(Matrix.CreateTranslation(currentXPosition, currentYPosition)); - Color foregroundColor = consoleBrush.Color; + Color foregroundColor = solidColorBrush.Color; switch (glyph) { diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs index eaaf67e0..056dd982 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/DrawingBoxSymbol.cs @@ -31,16 +31,16 @@ public bool Equals(DrawingBoxSymbol other) [JsonIgnore] public string Text { get; init; } - [JsonIgnore] public ushort Width { get; } = 1; + [JsonIgnore] public ushort Width => 1; - public bool IsWhiteSpace() + public bool NothingToDraw() { return UpRightDownLeft == EmptySymbol; } public ISymbol Blend(ref ISymbol symbolAbove) { - if (symbolAbove.IsWhiteSpace()) return this; + if (symbolAbove.NothingToDraw()) return this; if (symbolAbove is not DrawingBoxSymbol drawingBoxSymbol) return symbolAbove; diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs index 7d58fc27..4065766c 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/ISymbol.cs @@ -15,7 +15,7 @@ public interface ISymbol /// ushort Width { get; } - bool IsWhiteSpace(); + bool NothingToDraw(); /// /// Blend 2 symbols together diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs index 595a3bcf..79ea9cb3 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/Pixel.cs @@ -40,7 +40,7 @@ public Pixel(ISymbol symbol, FontWeight weight = FontWeight.Normal, TextDecorationLocation? textDecorations = null) : this( new PixelForeground(symbol, foregroundColor, weight, style, textDecorations), - new PixelBackground(PixelBackgroundMode.Transparent)) + new PixelBackground()) { } @@ -102,56 +102,45 @@ public bool Equals(Pixel other) public Pixel Blend(Pixel pixelAbove) { PixelForeground newForeground; - PixelBackground newBackground; - if (pixelAbove.IsCaret) return new Pixel(Foreground, Background, true); + var newBackground = new PixelBackground(MergeColors(Background.Color, pixelAbove.Background.Color)); - switch (pixelAbove.Background.Mode) + bool newIsCaret; + + if (pixelAbove.Background.Color.A == 0x0 /*todo: can be approximate, extract to extension method*/) + { + newForeground = pixelAbove.Foreground.NothingToDraw() + ? Foreground + : Foreground.Blend(pixelAbove.Foreground); + newIsCaret = pixelAbove.IsCaret | IsCaret; + } + else { - case PixelBackgroundMode.Colored: - // merge pixelAbove into this pixel using alpha channel. - Color mergedColors = MergeColors(Background.Color, pixelAbove.Background.Color); + if (!pixelAbove.Foreground.NothingToDraw()) + { newForeground = pixelAbove.Foreground; - newBackground = new PixelBackground(mergedColors); - return new Pixel(newForeground, newBackground, pixelAbove.IsCaret); - - case PixelBackgroundMode.Transparent: - // if the foreground is transparent, ignore pixelAbove foreground. - newForeground = pixelAbove.Foreground.Color != Colors.Transparent - ? Foreground.Blend(pixelAbove.Foreground) - : Foreground; - - // background is transparent, ignore pixelAbove background. - newBackground = Background; - break; - case PixelBackgroundMode.Shaded: - // shade the current pixel - (newForeground, newBackground) = Shade(); - - // blend the pixelAbove foreground into the shaded pixel - newForeground = newForeground.Blend(pixelAbove.Foreground); - - // resulting in new pixel with shaded background and blended foreground - return new Pixel(newForeground, newBackground); - - default: throw new ArgumentOutOfRangeException(nameof(pixelAbove)); + } + else + { + // merge the PixelForeground color with the pixelAbove background color + + if (pixelAbove.Background.Color.A == 0xFF) + // non-transparent layer above + newForeground = new PixelForeground(); + else + newForeground = new PixelForeground(Foreground.Symbol, + MergeColors(Foreground.Color, pixelAbove.Background.Color), + Foreground.Weight, + Foreground.Style, + Foreground.TextDecoration); + } + + newIsCaret = pixelAbove.IsCaret; } - bool newIsCaret = IsCaret | pixelAbove.IsCaret; - return new Pixel(newForeground, newBackground, newIsCaret); } - public bool IsEmpty() - { - return Foreground.Symbol.Width == 0; - } - - private (PixelForeground, PixelBackground) Shade() - { - return (Foreground.Shade(), Background.Shade()); - } - /// /// merge colors with alpha blending /// @@ -160,14 +149,29 @@ public bool IsEmpty() /// source blended into target private static Color MergeColors(Color target, Color source) { - float alphaB = source.A / 255.0f; - float inverseAlphaB = 1.0f - alphaB; + // by chatGPT o1 + // Convert alpha from [0..255] to [0..1] + float fgAlpha = source.A / 255f; + float bgAlpha = target.A / 255f; + + // Compute output alpha + float outAlpha = fgAlpha + bgAlpha * (1 - fgAlpha); + + // If there's no alpha in the result, return transparent + if (outAlpha <= 0f) return Color.FromArgb(0, 0, 0, 0); + + // Calculate the composited color channels, also converting channels to [0..1] + float outR = (source.R / 255f * fgAlpha + target.R / 255f * bgAlpha * (1 - fgAlpha)) / outAlpha; + float outG = (source.G / 255f * fgAlpha + target.G / 255f * bgAlpha * (1 - fgAlpha)) / outAlpha; + float outB = (source.B / 255f * fgAlpha + target.B / 255f * bgAlpha * (1 - fgAlpha)) / outAlpha; - byte red = (byte)(target.R * inverseAlphaB + source.R * alphaB); - byte green = (byte)(target.G * inverseAlphaB + source.G * alphaB); - byte blue = (byte)(target.B * inverseAlphaB + source.B * alphaB); + // Convert back to [0..255] + byte a = (byte)(outAlpha * 255f); + byte r = (byte)(outR * 255f); + byte g = (byte)(outG * 255f); + byte b = (byte)(outB * 255f); - return new Color(0xFF, red, green, blue); + return Color.FromArgb(a, r, g, b); } public override bool Equals([NotNullWhen(true)] object obj) diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs index b2f72afd..c55a39f5 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackground.cs @@ -6,59 +6,20 @@ namespace Consolonia.Core.Drawing.PixelBufferImplementation { - [DebuggerDisplay("[{Color}, {Mode}]")] - public readonly struct PixelBackground : IEquatable + [DebuggerDisplay("[{Color}]")] + public readonly struct PixelBackground(Color color) : IEquatable { - public PixelBackground() + public PixelBackground() : this(Colors.Transparent) { - Mode = PixelBackgroundMode.Transparent; - Color = Colors.Transparent; } - public PixelBackground(Color color) - { - Mode = color.A == 0 ? PixelBackgroundMode.Transparent : PixelBackgroundMode.Colored; - Color = color; - } - - public PixelBackground(PixelBackgroundMode mode, Color? color = null) - { - Color = color ?? Colors.Transparent; - Mode = mode; - } [JsonConverter(typeof(ColorConverter))] - public Color Color { get; init; } - - [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)] - public PixelBackgroundMode Mode { get; init; } + public Color Color { get; init; } = color; public bool Equals(PixelBackground other) { - return Color.Equals(other.Color) && Mode == other.Mode; - } - - public PixelBackground Shade() - { - Color newColor = Color; - PixelBackgroundMode newMode = Mode; - switch (Mode) - { - case PixelBackgroundMode.Colored: - newColor = Color.Shade(); - break; - case PixelBackgroundMode.Transparent: - newMode = PixelBackgroundMode.Shaded; - break; - case PixelBackgroundMode.Shaded: - newMode = PixelBackgroundMode.Colored; - newColor = Colors.Black; - break; - default: - throw new ArgumentOutOfRangeException(); - } - - return new PixelBackground(newMode, newColor); + return Color.Equals(other.Color); } public override bool Equals([NotNullWhen(true)] object obj) @@ -68,7 +29,7 @@ public override bool Equals([NotNullWhen(true)] object obj) public override int GetHashCode() { - return HashCode.Combine(Color, Mode); + return HashCode.Combine(Color); } public static bool operator ==(PixelBackground left, PixelBackground right) diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackgroundMode.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackgroundMode.cs index 86173494..89057053 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackgroundMode.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelBackgroundMode.cs @@ -1,5 +1,8 @@ namespace Consolonia.Core.Drawing.PixelBufferImplementation { + /// + /// todo: use it for EGA extension + /// public enum PixelBackgroundMode : byte { Colored, diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs index 92b85a70..73f74f2b 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/PixelForeground.cs @@ -96,5 +96,10 @@ public override int GetHashCode() { return !left.Equals(right); } + + public bool NothingToDraw() + { + return Color.A == 0x0 || Symbol.NothingToDraw(); + } } } \ No newline at end of file diff --git a/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs b/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs index fb6b103b..251edd20 100644 --- a/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs +++ b/src/Consolonia.Core/Drawing/PixelBufferImplementation/SimpleSymbol.cs @@ -45,14 +45,14 @@ public bool Equals(SimpleSymbol other) [JsonIgnore] public ushort Width { get; init; } - public bool IsWhiteSpace() + public bool NothingToDraw() { return string.IsNullOrEmpty(Text); } public ISymbol Blend(ref ISymbol symbolAbove) { - return symbolAbove.IsWhiteSpace() ? this : symbolAbove; + return symbolAbove.NothingToDraw() ? this : symbolAbove; } public override bool Equals([NotNullWhen(true)] object obj) diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryColors.axaml.cs b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryColors.axaml.cs index d94ed00a..f1b10391 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryColors.axaml.cs +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryColors.axaml.cs @@ -4,7 +4,6 @@ using Avalonia.Controls; using Avalonia.Interactivity; using Avalonia.Media; -using Consolonia.Core.Drawing; namespace Consolonia.Gallery.Gallery.GalleryViews { @@ -49,7 +48,7 @@ private void Blue_Click(object sender, RoutedEventArgs e) public class RgbModel : INotifyPropertyChanged { - private ConsoleBrush _brush; + private IBrush _brush; private Color _color; @@ -59,11 +58,11 @@ public Color Color set { _color = value; - Brush = new ConsoleBrush(_color); + Brush = new SolidColorBrush(_color); } } - public ConsoleBrush Brush + public IBrush Brush { get => _brush; set diff --git a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryDataGrid.axaml.cs b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryDataGrid.axaml.cs index 762f0076..37ecd056 100644 --- a/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryDataGrid.axaml.cs +++ b/src/Consolonia.Gallery/Gallery/GalleryViews/GalleryDataGrid.axaml.cs @@ -9,7 +9,6 @@ using Avalonia.Data; using Avalonia.Data.Converters; using Avalonia.Media; -using Consolonia.Core.Drawing; // ReSharper disable UnusedMember.Global @@ -600,10 +599,10 @@ public object Convert(object value, Type targetType, object parameter, CultureIn if (value is int gdp) { if (gdp <= 5000) - return new ConsoleBrush(Colors.Yellow); + return new SolidColorBrush(Colors.Yellow); if (gdp <= 10000) - return new ConsoleBrush(Colors.DarkGoldenrod); - return new ConsoleBrush(Colors.Green); + return new SolidColorBrush(Colors.DarkGoldenrod); + return new SolidColorBrush(Colors.Green); } return value; diff --git a/src/Consolonia.NUnit/UnitTestConsole.cs b/src/Consolonia.NUnit/UnitTestConsole.cs index 58566d59..95922054 100644 --- a/src/Consolonia.NUnit/UnitTestConsole.cs +++ b/src/Consolonia.NUnit/UnitTestConsole.cs @@ -71,7 +71,7 @@ void IConsole.Print(PixelBufferCoordinate bufferPoint, Color background, Color f new Pixel( new PixelForeground(new SimpleSymbol(rune), foreground, style: style, weight: weight, textDecoration: textDecoration), - new PixelBackground(PixelBackgroundMode.Colored, background))); + new PixelBackground(background))); i++; } } diff --git a/src/Consolonia.Themes/Fluent/FluentColors.axaml b/src/Consolonia.Themes/Fluent/FluentColors.axaml index 98def9c1..67d0c2f6 100644 --- a/src/Consolonia.Themes/Fluent/FluentColors.axaml +++ b/src/Consolonia.Themes/Fluent/FluentColors.axaml @@ -1,45 +1,43 @@ 1 - + - + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file diff --git a/src/Consolonia.Themes/Material/MaterialColors.axaml b/src/Consolonia.Themes/Material/MaterialColors.axaml index e4ab8cd1..52a41606 100644 --- a/src/Consolonia.Themes/Material/MaterialColors.axaml +++ b/src/Consolonia.Themes/Material/MaterialColors.axaml @@ -1,45 +1,43 @@ 1 - + - + - + - + - + - + - + - + - + - + - + - + \ No newline at end of file diff --git a/src/Consolonia.Themes/Templates/Controls/CalendarItem.axaml b/src/Consolonia.Themes/Templates/Controls/CalendarItem.axaml index c4b288d8..f28ad201 100644 --- a/src/Consolonia.Themes/Templates/Controls/CalendarItem.axaml +++ b/src/Consolonia.Themes/Templates/Controls/CalendarItem.axaml @@ -1,7 +1,6 @@ + xmlns:helpers="clr-namespace:Consolonia.Themes.Templates.Controls.Helpers;assembly=Consolonia.Themes"> diff --git a/src/Tests/Consolonia.Core.Tests/PixelBackgroundTests.cs b/src/Tests/Consolonia.Core.Tests/PixelBackgroundTests.cs index 89f37f70..7f43b8ca 100644 --- a/src/Tests/Consolonia.Core.Tests/PixelBackgroundTests.cs +++ b/src/Tests/Consolonia.Core.Tests/PixelBackgroundTests.cs @@ -13,7 +13,6 @@ public void Constructor() { var pixelBackground = new PixelBackground(); Assert.That(pixelBackground.Color, Is.EqualTo(Colors.Transparent)); - Assert.That(pixelBackground.Mode, Is.EqualTo(PixelBackgroundMode.Transparent)); } [Test] @@ -21,18 +20,6 @@ public void ConstructorWithColor() { var pixelBackground = new PixelBackground(Colors.Red); Assert.That(pixelBackground.Color, Is.EqualTo(Colors.Red)); - Assert.That(pixelBackground.Mode, Is.EqualTo(PixelBackgroundMode.Colored)); - } - - [Test] - [TestCase(PixelBackgroundMode.Transparent)] - [TestCase(PixelBackgroundMode.Colored)] - [TestCase(PixelBackgroundMode.Shaded)] - public void ConstructorWithMode(PixelBackgroundMode mode) - { - var pixelBackground = new PixelBackground(mode, Colors.Red); - Assert.That(pixelBackground.Color.Equals(Colors.Red)); - Assert.That(pixelBackground.Mode.Equals(mode)); } [Test] @@ -44,8 +31,8 @@ public void Equality() Assert.That(pixelBackground.Equals(pixelBackground2)); Assert.That(pixelBackground == pixelBackground2); - pixelBackground = new PixelBackground(PixelBackgroundMode.Transparent, Colors.Blue); - pixelBackground2 = new PixelBackground(PixelBackgroundMode.Transparent, Colors.Blue); + pixelBackground = new PixelBackground(Color.Parse("#000000FF")); + pixelBackground2 = new PixelBackground(Color.Parse("#000000FF")); Assert.That(pixelBackground.Equals((object)pixelBackground2)); Assert.That(pixelBackground.Equals(pixelBackground2)); Assert.That(pixelBackground == pixelBackground2); @@ -59,8 +46,8 @@ public void Inequality() Assert.That(!pixelBackground.Equals(pixelBackground2)); Assert.That(pixelBackground != pixelBackground2); - pixelBackground = new PixelBackground(PixelBackgroundMode.Colored, Colors.Red); - pixelBackground2 = new PixelBackground(PixelBackgroundMode.Transparent, Colors.Red); + pixelBackground = new PixelBackground(Colors.Red); + pixelBackground2 = new PixelBackground(Color.Parse("#7FFF0000")); Assert.That(!pixelBackground.Equals((object)pixelBackground2)); Assert.That(!pixelBackground.Equals(pixelBackground2)); Assert.That(pixelBackground != pixelBackground2); @@ -73,8 +60,8 @@ public void HashCode() var pixelBackground2 = new PixelBackground(Colors.Red); Assert.That(pixelBackground.GetHashCode(), Is.EqualTo(pixelBackground2.GetHashCode())); - pixelBackground = new PixelBackground(PixelBackgroundMode.Transparent, Colors.Blue); - pixelBackground2 = new PixelBackground(PixelBackgroundMode.Transparent, Colors.Blue); + pixelBackground = new PixelBackground(Color.Parse("#000000FF")); + pixelBackground2 = new PixelBackground(Color.Parse("#000000FF")); Assert.That(pixelBackground.GetHashCode(), Is.EqualTo(pixelBackground2.GetHashCode())); // inequal hashcode diff --git a/src/Tests/Consolonia.Core.Tests/PixelTests.cs b/src/Tests/Consolonia.Core.Tests/PixelTests.cs index eeae1b37..89d52dd7 100644 --- a/src/Tests/Consolonia.Core.Tests/PixelTests.cs +++ b/src/Tests/Consolonia.Core.Tests/PixelTests.cs @@ -23,7 +23,6 @@ public void ConstructorColorOnly() { var pixel = new Pixel(new PixelBackground(Colors.Red)); Assert.That(pixel.Background.Color, Is.EqualTo(Colors.Red)); - Assert.That(pixel.Background.Mode, Is.EqualTo(PixelBackgroundMode.Colored)); } [Test] @@ -36,7 +35,6 @@ public void ConstructorColorAndSymbol() Assert.That(pixel.Foreground.Weight, Is.EqualTo(FontWeight.Normal)); Assert.That(pixel.Foreground.TextDecoration, Is.Null); Assert.That(pixel.Background.Color, Is.EqualTo(Colors.Transparent)); - Assert.That(pixel.Background.Mode, Is.EqualTo(PixelBackgroundMode.Transparent)); } [Test] @@ -49,7 +47,6 @@ public void ConstructorDrawingBoxSymbol() Assert.That(pixel.Foreground.Weight, Is.EqualTo(FontWeight.Normal)); Assert.That(pixel.Foreground.TextDecoration, Is.Null); Assert.That(pixel.Background.Color, Is.EqualTo(Colors.Transparent)); - Assert.That(pixel.Background.Mode, Is.EqualTo(PixelBackgroundMode.Transparent)); } [Test] @@ -63,7 +60,6 @@ public void ConstructorDrawingBoxSymbolAndColor() Assert.IsNull(pixel.Foreground.Weight); Assert.IsNull(pixel.Foreground.TextDecoration); Assert.That(pixel.Background.Color, Is.EqualTo(Colors.Blue)); - Assert.That(pixel.Background.Mode, Is.EqualTo(PixelBackgroundMode.Colored)); } [Test] @@ -147,10 +143,10 @@ public void BlendShadedBackground() { var pixel = new Pixel(new PixelForeground(new SimpleSymbol("x"), Colors.Gray), new PixelBackground(Colors.White)); - var pixel2 = new Pixel(new PixelBackground(PixelBackgroundMode.Shaded)); + var pixel2 = new Pixel(new PixelBackground(Color.Parse("#7F000000"))); Pixel newPixel = pixel.Blend(pixel2); Assert.True(newPixel.Foreground.Symbol.Text == "x"); - // foreground should be lighter than original + // foreground should be darker than original Assert.True(newPixel.Foreground.Color.R < pixel.Foreground.Color.R && newPixel.Foreground.Color.G < pixel.Foreground.Color.G && newPixel.Foreground.Color.B < pixel.Foreground.Color.B); @@ -165,17 +161,38 @@ public void BlendShadedBackground2() { var pixel = new Pixel(new PixelForeground(new SimpleSymbol("x"), Colors.Gray), new PixelBackground(Colors.Black)); - var pixel2 = new Pixel(new PixelBackground(PixelBackgroundMode.Shaded)); + var pixel2 = new Pixel(new PixelBackground(Color.Parse("#7F000000"))); Pixel newPixel = pixel.Blend(pixel2); Assert.True(newPixel.Foreground.Symbol.Text == "x"); // foreground should be darker than original Assert.True(newPixel.Foreground.Color.R < pixel.Foreground.Color.R && newPixel.Foreground.Color.G < pixel.Foreground.Color.G && newPixel.Foreground.Color.B < pixel.Foreground.Color.B); - // background should be darker than original - Assert.True(newPixel.Background.Color.R > pixel.Background.Color.R && - newPixel.Background.Color.G > pixel.Background.Color.G && - newPixel.Background.Color.B > pixel.Background.Color.B); + // background should be not lighter than original + Assert.True(newPixel.Background.Color.R <= pixel.Background.Color.R && + newPixel.Background.Color.G <= pixel.Background.Color.G && + newPixel.Background.Color.B <= pixel.Background.Color.B); + } + + [Test] + public void TextBelowSemiTransparentBackgroundIsStillVisible() + { + var pixel = new Pixel(new PixelForeground(new SimpleSymbol("x"), Colors.Gray), + new PixelBackground(Colors.White)); + var pixel2 = new Pixel(new PixelBackground(Color.Parse("#7F000000"))); + Pixel newPixel = pixel2.Blend(pixel); + Assert.True(newPixel.Foreground.Symbol.Text == "x"); + } + + [Test] + public void TextBelowNoneTransparentNullCharacterIsStillVisible() + { + var pixel = new Pixel(new PixelForeground(new SimpleSymbol("x"), Colors.Gray), + new PixelBackground(Colors.White)); + var pixel2 = new Pixel(new PixelForeground(new SimpleSymbol(char.MinValue), Colors.White), + new PixelBackground(Color.Parse("#7F000000"))); + Pixel newPixel = pixel2.Blend(pixel); + Assert.True(newPixel.Foreground.Symbol.Text == "x"); } [Test] diff --git a/src/Tests/Consolonia.Core.Tests/SimpleSymbolTests.cs b/src/Tests/Consolonia.Core.Tests/SimpleSymbolTests.cs index 639b2085..c068ca23 100644 --- a/src/Tests/Consolonia.Core.Tests/SimpleSymbolTests.cs +++ b/src/Tests/Consolonia.Core.Tests/SimpleSymbolTests.cs @@ -106,9 +106,9 @@ public void HashCode() [Test] public void IsWhiteSpace() { - Assert.That(new SimpleSymbol(string.Empty).IsWhiteSpace(), Is.True); - Assert.That(new SimpleSymbol(" ").IsWhiteSpace(), Is.False); - Assert.That(new SimpleSymbol("a").IsWhiteSpace(), Is.False); + Assert.That(new SimpleSymbol(string.Empty).NothingToDraw(), Is.True); + Assert.That(new SimpleSymbol(" ").NothingToDraw(), Is.False); + Assert.That(new SimpleSymbol("a").NothingToDraw(), Is.False); } [Test]