diff --git a/Demos/Sharpie.Demos.Events/Program.cs b/Demos/Sharpie.Demos.Events/Program.cs
index 794474f..cf8927e 100644
--- a/Demos/Sharpie.Demos.Events/Program.cs
+++ b/Demos/Sharpie.Demos.Events/Program.cs
@@ -35,7 +35,7 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
[assembly: ExcludeFromCodeCoverage]
// Create the terminal instance without any non-standard settings.
-using var terminal = new Terminal(CursesBackend.Load(), new(UseStandardKeySequenceResolvers: false));
+using var terminal = new Terminal(CursesBackend.Load(), new(UseStandardKeySequenceResolvers: true));
// Set the main screen attributes for text and drawings.
terminal.Screen.ColorMixture = terminal.Colors.MixColors(StandardColor.Green, StandardColor.Blue);
diff --git a/Demos/Sharpie.Demos.Font/Program.cs b/Demos/Sharpie.Demos.Font/Program.cs
index b975f86..2384d11 100644
--- a/Demos/Sharpie.Demos.Font/Program.cs
+++ b/Demos/Sharpie.Demos.Font/Program.cs
@@ -48,6 +48,8 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
})
.ToArray();
+var font = new DosCp866AsciiFont();
+
// This method draws the given string and applies color starting with a specific shift.
void DrawFunAsciiMessage(ITerminal t, string str, int colorShift)
{
@@ -56,7 +58,7 @@ void DrawFunAsciiMessage(ITerminal t, string str, int colorShift)
foreach (var ch in str)
{
- var gl = new AsciiGlyph((byte) ch, styles[colorShift % styles.Length]);
+ var gl = font.GetGlyph(new(ch), styles[colorShift % styles.Length]);
t.Screen.Draw(new(x, y), gl);
x += gl.Size.Width;
diff --git a/Sharpie.Tests/AsciiGlyphTests.cs b/Sharpie.Tests/DosCp866AsciiFontTests.cs
similarity index 63%
rename from Sharpie.Tests/AsciiGlyphTests.cs
rename to Sharpie.Tests/DosCp866AsciiFontTests.cs
index abf1d57..187b37e 100644
--- a/Sharpie.Tests/AsciiGlyphTests.cs
+++ b/Sharpie.Tests/DosCp866AsciiFontTests.cs
@@ -31,21 +31,31 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
namespace Sharpie.Tests;
[TestClass]
-public class AsciiGlyphTests
+public class DosCp866AsciiFontTests
{
+ private readonly DosCp866AsciiFont _font = new();
private readonly Style _style1 = new() { Attributes = VideoAttribute.Bold, ColorMixture = new() { Handle = 99 } };
+ [TestMethod, DataRow(0, true), DataRow(255, true), DataRow(256, false)]
+ public void HasGlyph_ChecksIfGlyphInRange(int c, bool t)
+ {
+ _font.HasGlyph(new(c))
+ .ShouldBe(t);
+ }
+
+ [TestMethod] public void Name_ReturnsTheExpectedValue() { _font.Name.ShouldBe("CP866 Block Characters"); }
+
[TestMethod]
- public void Size_Returns_4By4()
+ public void GetGlyph_ReturnsA4By4Drawable()
{
- var glyph = new AsciiGlyph((byte) 'A', _style1);
+ var glyph = _font.GetGlyph(new('A'), _style1);
glyph.Size.ShouldBe(new(4, 4));
}
[TestMethod]
- public void DrawTo_DrawsTheExpectedGlyph()
+ public void GetGlyph_ReturnsTheExpectedGlyph_IfFound()
{
- var glyph = new AsciiGlyph((byte) 'A', _style1);
+ var glyph = _font.GetGlyph(new('A'), _style1);
var contents = glyph.GetContents();
var cols = new[,]
@@ -58,4 +68,21 @@ public void DrawTo_DrawsTheExpectedGlyph()
contents.ShouldBe(cols);
}
+
+ [TestMethod]
+ public void GetGlyph_ReturnsTheDefault_IfNotFound()
+ {
+ var glyph = _font.GetGlyph(new(256), _style1);
+ var contents = glyph.GetContents();
+
+ var cols = new[,]
+ {
+ { (new('┌'), _style1), (new('│'), _style1), (new('│'), _style1), (new('└'), _style1) },
+ { (new('─'), _style1), (new(' '), _style1), (new(' '), _style1), (new('─'), _style1) },
+ { (new('─'), _style1), (new(' '), _style1), (new(' '), _style1), (new('─'), _style1) },
+ { (new('┐'), _style1), (new('│'), _style1), (new('│'), _style1), (new Rune('┘'), _style1) }
+ };
+
+ contents.ShouldBe(cols);
+ }
}
diff --git a/Sharpie/Abstractions/IAsciiFont.cs b/Sharpie/Abstractions/IAsciiFont.cs
new file mode 100644
index 0000000..2955073
--- /dev/null
+++ b/Sharpie/Abstractions/IAsciiFont.cs
@@ -0,0 +1,28 @@
+namespace Sharpie.Abstractions;
+
+///
+/// Defines the traits implemented by ASCII font providers.
+///
+[PublicAPI]
+public interface IAsciiFont
+{
+ ///
+ /// The font's name.
+ ///
+ string Name { get; }
+
+ ///
+ /// Checks if the font contains a given glyph.
+ ///
+ /// The character.
+ /// true if the font contains the given glyph; false otherwise.
+ bool HasGlyph(Rune @char);
+
+ ///
+ /// Tries to get a glyph for a given .
+ ///
+ /// The character.
+ /// The style to apply to the glyph.
+ /// The output glyph, if found. Otherwise, the font will substitute the glyph with something else.
+ IDrawable GetGlyph(Rune @char, Style style);
+}
diff --git a/Sharpie/AsciiGlyph.cs b/Sharpie/DosCp866AsciiFont.cs
similarity index 82%
rename from Sharpie/AsciiGlyph.cs
rename to Sharpie/DosCp866AsciiFont.cs
index 99e4567..871816e 100644
--- a/Sharpie/AsciiGlyph.cs
+++ b/Sharpie/DosCp866AsciiFont.cs
@@ -1,10 +1,10 @@
namespace Sharpie;
///
-/// Allows for the drawing of large ASCII glyphs.
+/// Base class implemented by ASCII font providers.
///
[PublicAPI]
-public sealed class AsciiGlyph: IDrawable
+public sealed class DosCp866AsciiFont: IAsciiFont
{
private const int BitsPerLine = 8;
private const int Lines = 8;
@@ -15,9 +15,7 @@ public sealed class AsciiGlyph: IDrawable
private static readonly IReadOnlyList Shapes;
- private readonly Canvas _canvas;
-
- static AsciiGlyph()
+ static DosCp866AsciiFont()
{
Debug.Assert(Raw.Length % CharsPerByte == 0);
var byteCount = Raw.Length / CharsPerByte;
@@ -34,52 +32,57 @@ static AsciiGlyph()
Shapes = glyphs.ToArray();
}
- ///
- /// Creates a new large ASCII glyph for a given .
- ///
- /// The character to obtain the glyph of.
- /// The text style to use.
- public AsciiGlyph(byte @char, Style style)
+ private static bool[,] ExtractGlyph(ReadOnlySpan str)
{
- _canvas = new(new(BitsPerLine / 2, Lines / 2));
- _canvas.Fill(new(new(0, 0), _canvas.Size), new Rune(ControlCharacter.Whitespace), style);
-
- var shape = Shapes[@char];
+ Debug.Assert(str.Length == Lines * CharsPerByte);
- for (var x = 0; x < BitsPerLine; x++)
+ var shape = new bool[8, 8];
+ for (var y = 0; y < Lines; y++)
{
- for (var y = 0; y < Lines; y++)
+ var pb = byte.Parse(str.Slice(y * CharsPerByte, CharsPerByte), NumberStyles.HexNumber);
+ for (var x = 0; x < BitsPerLine; x++)
{
- var ap = new PointF(x / 2F, y / 2F);
- if (shape[x, y])
- {
- _canvas.Point(ap, style);
- }
+ shape[7 - x, y] = (pb & (1 << x)) != 0;
}
}
+
+ return shape;
}
- ///
- public Size Size => _canvas.Size;
+ ///
+ public string Name => "CP866 Block Characters";
- ///
- public void DrawOnto(IDrawSurface destination, Rectangle srcArea, Point destLocation) =>
- _canvas.DrawOnto(destination, srcArea, destLocation);
+ ///
+ public bool HasGlyph(Rune @char) => @char.Value >= 0 && @char.Value < Shapes.Count;
- private static bool[,] ExtractGlyph(ReadOnlySpan str)
+ ///
+ public IDrawable GetGlyph(Rune @char, Style style)
{
- Debug.Assert(str.Length == Lines * CharsPerByte);
-
- var shape = new bool[8, 8];
- for (var y = 0; y < Lines; y++)
+ var canvas = new Canvas(new(BitsPerLine / 2, Lines / 2));
+ var canvasRect = new Rectangle(new(0, 0), canvas.Size);
+
+ canvas.Fill(canvasRect, new Rune(ControlCharacter.Whitespace), style);
+
+ if (!HasGlyph(@char))
{
- var pb = byte.Parse(str.Slice(y * CharsPerByte, CharsPerByte), NumberStyles.HexNumber);
+ canvas.Box(canvasRect, Canvas.LineStyle.Light, style);
+ } else
+ {
+ var shape = Shapes[@char.Value];
+
for (var x = 0; x < BitsPerLine; x++)
{
- shape[7 - x, y] = (pb & (1 << x)) != 0;
+ for (var y = 0; y < Lines; y++)
+ {
+ var ap = new PointF(x / 2F, y / 2F);
+ if (shape[x, y])
+ {
+ canvas.Point(ap, style);
+ }
+ }
}
}
- return shape;
+ return canvas;
}
}