Skip to content

Commit 346d062

Browse files
committed
feat: added large ASCII glyph support and a demo.
1 parent 115bce0 commit 346d062

File tree

7 files changed

+222
-0
lines changed

7 files changed

+222
-0
lines changed

Demos/Sharpie.Demos.Font/Program.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
/*
2+
Copyright (c) 2022, Alexandru Ciobanu
3+
All rights reserved.
4+
5+
Redistribution and use in source and binary forms, with or without
6+
modification, are permitted provided that the following conditions are met:
7+
8+
1. Redistributions of source code must retain the above copyright notice, this
9+
list of conditions and the following disclaimer.
10+
11+
2. Redistributions in binary form must reproduce the above copyright notice,
12+
this list of conditions and the following disclaimer in the documentation
13+
and/or other materials provided with the distribution.
14+
15+
3. Neither the name of the copyright holder nor the names of its
16+
contributors may be used to endorse or promote products derived from
17+
this software without specific prior written permission.
18+
19+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
23+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
25+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
26+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29+
*/
30+
31+
using System.Diagnostics.CodeAnalysis;
32+
using Sharpie;
33+
using Sharpie.Abstractions;
34+
using Sharpie.Backend;
35+
36+
[assembly: ExcludeFromCodeCoverage]
37+
38+
// Create a new terminal instance with an invisible cursor.
39+
using var terminal = new Terminal(NativeCursesProvider.Instance, new(CaretMode: CaretMode.Invisible));
40+
41+
// Setup the message and a number of rotating styles that will be applied for each letter of the message.
42+
var message = "\x001 Let the ASCII fun begin! \x003";
43+
var styles = Enumerable.Range(0, message.Length)
44+
.Select(i => new Style
45+
{
46+
Attributes = VideoAttribute.None,
47+
ColorMixture = terminal.Colors.MixColors((short) (i + 10), (short) StandardColor.Default)
48+
})
49+
.ToArray();
50+
51+
// This method draws the given string and applies color starting with a specific shift.
52+
void DrawFunAsciiMessage(ITerminal t, string str, int colorShift)
53+
{
54+
var x = 0;
55+
var y = 0;
56+
57+
foreach (var ch in str)
58+
{
59+
var gl = new LargeAsciiGlyph((byte)ch, styles[colorShift % styles.Length]);
60+
t.Screen.Draw(new (x, y), gl);
61+
62+
x += gl.Size.Width;
63+
if (x >= t.Screen.Size.Width - gl.Size.Width)
64+
{
65+
x = 0;
66+
y += gl.Size.Height;
67+
}
68+
69+
colorShift++;
70+
}
71+
}
72+
73+
// A repeating timer that draws the message with different colors.
74+
var colorShift = 0;
75+
terminal.Repeat((t) =>
76+
{
77+
DrawFunAsciiMessage(t, message, colorShift++);
78+
t.Screen.Refresh();
79+
80+
return Task.CompletedTask;
81+
}, 100);
82+
83+
// The main loop -- we need to monitor for resizes.
84+
terminal.Run((t, e) =>
85+
{
86+
if (e is TerminalResizeEvent)
87+
{
88+
t.Screen.Clear();
89+
}
90+
91+
return Task.CompletedTask;
92+
});
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net6.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
<AssemblyName>sharpie-demos-font</AssemblyName>
9+
<LangVersion>11</LangVersion>
10+
<IsPackable>false</IsPackable>
11+
<Title>A Curses-based terminal manipulation library.</Title>
12+
<Description>Demo application for Sharpie library.</Description>
13+
<Copyright>Alexandru Ciobanu</Copyright>
14+
<PackageProjectUrl>https://github.com/pavkam/sharpie/</PackageProjectUrl>
15+
<PackageLicenseUrl>https://github.com/pavkam/sharpie/blob/main/LICENSE</PackageLicenseUrl>
16+
<RepositoryUrl>https://github.com/pavkam/sharpie.git</RepositoryUrl>
17+
<RepositoryType>git</RepositoryType>
18+
<PackageVersion>1.0.0</PackageVersion>
19+
<AssemblyVersion>1.0.0</AssemblyVersion>
20+
<FileVersion>1.0.0</FileVersion>
21+
<Authors>Alexandru Ciobanu</Authors>
22+
<Company>sharpie-demos-font</Company>
23+
<Product>sharpie-demos-font</Product>
24+
<PackageId>sharpie-demos-font</PackageId>
25+
</PropertyGroup>
26+
27+
28+
<ItemGroup>
29+
<ProjectReference Include="..\..\Sharpie\Sharpie.csproj" />
30+
</ItemGroup>
31+
32+
</Project>

Sharpie.sln

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharpie.Demos.Windows", "De
1616
EndProject
1717
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharpie.Demos.Snake", "Demos\Sharpie.Demos.Snake\Sharpie.Demos.Snake.csproj", "{B746C675-0FB6-4B9E-8C0C-045C0585CBC4}"
1818
EndProject
19+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Sharpie.Demos.Font", "Demos\Sharpie.Demos.Font\Sharpie.Demos.Font.csproj", "{846FCE76-3D6D-4680-B81E-2187B375D2F4}"
20+
EndProject
1921
Global
2022
GlobalSection(SolutionConfigurationPlatforms) = preSolution
2123
Debug|Any CPU = Debug|Any CPU
@@ -50,12 +52,17 @@ Global
5052
{B746C675-0FB6-4B9E-8C0C-045C0585CBC4}.Debug|Any CPU.Build.0 = Debug|Any CPU
5153
{B746C675-0FB6-4B9E-8C0C-045C0585CBC4}.Release|Any CPU.ActiveCfg = Release|Any CPU
5254
{B746C675-0FB6-4B9E-8C0C-045C0585CBC4}.Release|Any CPU.Build.0 = Release|Any CPU
55+
{846FCE76-3D6D-4680-B81E-2187B375D2F4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
56+
{846FCE76-3D6D-4680-B81E-2187B375D2F4}.Debug|Any CPU.Build.0 = Debug|Any CPU
57+
{846FCE76-3D6D-4680-B81E-2187B375D2F4}.Release|Any CPU.ActiveCfg = Release|Any CPU
58+
{846FCE76-3D6D-4680-B81E-2187B375D2F4}.Release|Any CPU.Build.0 = Release|Any CPU
5359
EndGlobalSection
5460
GlobalSection(NestedProjects) = preSolution
5561
{8F82A851-2053-4079-82D2-5BA2C1987AF2} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
5662
{68997860-DF84-4DFF-9B24-5F5B531B994A} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
5763
{6E0FFEE1-21B5-4B26-B65D-FC4C5457A154} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
5864
{C5E6AEF6-E39C-4ADE-A684-55B901D9871B} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
5965
{B746C675-0FB6-4B9E-8C0C-045C0585CBC4} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
66+
{846FCE76-3D6D-4680-B81E-2187B375D2F4} = {D93C7AAD-B597-44E4-B05B-81A52F0D5E9B}
6067
EndGlobalSection
6168
EndGlobal

Sharpie/LargeAsciiGlyph.cs

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,86 @@
1+
namespace Sharpie;
2+
3+
/// <summary>
4+
/// Contains the definition of the standard ASCII font.
5+
/// </summary>
6+
[PublicAPI]
7+
public sealed class LargeAsciiGlyph : IDrawable
8+
{
9+
private const int BitsPerLine = 8;
10+
private const int Lines = 8;
11+
private const int CharsPerByte = 2;
12+
private const string Raw =
13+
"00000000000000007E81A581BD99817E7EFFDBFFC3E7FF7E6CFEFEFE7C38100010387CFE7C381008387C38FEFE7C387C1010387CFE7C387C0000183C3C180000FFFFE7C3C3E7FFFF003C664242663C00FFC399BDBD99C3FF0F070F7DCCCCCC783C6666663C187E183F333F303070F0E07F637F636367E6C0995A3CE7E73C5A9980E0F8FEF8E08000020E3EFE3E0E0200183C7E18187E3C1866666666660066007FDBDB7B1B1B1B003E63386C6C38CC78000000007E7E7E00183C7E187E3C18FF183C7E1818181800181818187E3C180000180CFE0C180000003060FE603000000000C0C0C0FE0000002466FF6624000000183C7EFFFF000000FFFF7E3C180000000000000000000030787830300030006C6C6C00000000006C6CFE6CFE6C6C00307CC0780CF8300000C6CC183066C600386C3876DCCC76006060C000000000001830606060301800603018181830600000663CFF3C660000003030FC303000000000000000303060000000FC000000000000000000303000060C183060C080007CC6CEDEF6E67C00307030303030FC0078CC0C3860CCFC0078CC0C380CCC78001C3C6CCCFE0C1E00FCC0F80C0CCC78003860C0F8CCCC7800FCCC0C183030300078CCCC78CCCC780078CCCC7C0C18700000303000003030000030300000303060183060C0603018000000FC0000FC00006030180C1830600078CC0C18300030007CC6DEDEDEC078003078CCCCFCCCCC00FC66667C6666FC003C66C0C0C0663C00F86C6666666CF800FE6268786862FE00FE6268786860F0003C66C0C0CE663E00CCCCCCFCCCCCCC0078303030303078001E0C0C0CCCCC7800E6666C786C66E600F06060606266FE00C6EEFEFED6C6C600C6E6F6DECEC6C600386CC6C6C66C3800FC66667C6060F00078CCCCCCDC781C00FC66667C6C66E60078CCE0701CCC7800FCB4303030307800CCCCCCCCCCCCFC00CCCCCCCCCC783000C6C6C6D6FEEEC600C6C66C38386CC600CCCCCC7830307800FEC68C183266FE007860606060607800C06030180C060200781818181818780010386CC60000000000000000000000FF30301800000000000000780C7CCC7600E060607C6666DC00000078CCC0CC78001C0C0C7CCCCC7600000078CCFCC07800386C60F06060F000000076CCCC7C0CF8E0606C766666E60030007030303078000C000C0C0CCCCC78E060666C786CE60070303030303078000000CCFEFED6C6000000F8CCCCCCCC00000078CCCCCC78000000DC66667C60F0000076CCCC7C0C1E0000DC766660F00000007CC0780CF80010307C30303418000000CCCCCCCC76000000CCCCCC7830000000C6D6FEFE6C000000C66C386CC6000000CCCCCC7C0CF80000FC983064FC001C3030E030301C001818180018181800E030301C3030E00076DC0000000000000010386CC6C6FE003E6CCCCCFCCCCE00FC60706C6666FC00F86C786C6666FC00FC6260606060F0003E6666666666FFC3FC6268786862FC00D6D67C54D6D6D600BC66061C06C6FC00CECCCCDCFCECCE00D6CCCCDCFCECCE00CCD8F0D8CCCCC6001E3C6C6C6C6CCE0082C6EEFED6C6C600C6C6FEC6C6C6C600386CC6C6C66C3800FEC6C6C6C6C6C600FC66666C7060F0003C66C0C0C0663C00FCB43030303078006666663E06663C007EDBDBDB7E183C00C66C386CC6C6C600CECCCCCCCCCCFE06CECCCCCC7C0C1E00D6D6D6D6D6D6FE00D6D6D6D6D6D6FE03F0B0383633337E00C6C6E6D6DEDEF600E060706C6666FC0078CC063E06CC7800CEDBDBFBDBDBCE007ECCCC6C1C6CEE000000780C7CCC7E00027CC0FCC6C67C000000FC667C66FC000000FC626060F00000003E6C6C6CFE82000078CCFCC078001010D6387CD6D60000007CC61C06C67C0000CEDCFCECCE003800CEDCFCECCE000000CCF0D8CCC60000001E3C6C6CCE000000C6EEFED6C6000000C6C6FEC6C60000007CC6C6C67C000000FEC6C6C6C600114411441144114455AA55AA55AA55AADB77DBEEBD77DBEE181818181818181818181818F81818181818F818F818181836363636F636363600000000FE3636360000F818F81818183636F606F636363636363636363636360000FE06F63636363636F606FE00000036363636FE0000001818F818F800000000000000F8181818181818181F00000018181818FF00000000000000FF181818181818181F18181800000000FF00000018181818FF18181818181F181F1818183636363637363636363637303F00000000003F30373636363636F700FF0000000000FF00F736363636363730373636360000FF00FF0000003636F700F73636361818FF00FF00000036363636FF0000000000FF00FF18181800000000FF363636363636363F00000018181F181F00000000001F181F181818000000003F36363636363636FF3636361818FF18FF18181818181818F8000000000000001F181818FFFFFFFFFFFFFFFF00000000FFFFFFFFF0F0F0F0F0F0F0F00F0F0F0F0F0F0F0FFFFFFFFF000000000000FC66667C60F000007CC6C0C67C000000FCB4303078000000CECC7C0CCC783C187EDBDB7E183C0000C66C386CC6000000CECCCCCCFE060000CECC7C0C1E000000D6D6D6D6FE000000D6D6D6D6FF030000F0B03C363C000000C6C6F6DEF6000000E0607C66FC0000007CC61EC67C000000CEDBFBDBCE0000007ECC7C3C6EC06CFC62786062FC006C007CC6FEC07C000000000003060C1800000000C0603018183060C000000000180C060300000000000C06FF060C0000003060FF6030000018181818187E3C18183C7E18181818181818007E0018180018187E1818007E008BCBE8B8A888880000C33C66663CC30000003C3C3C0000000000000000000000";
14+
15+
private static readonly IReadOnlyList<bool[,]> Shapes;
16+
17+
private static bool[,] ExtractGlyph(ReadOnlySpan<char> str)
18+
{
19+
Debug.Assert(str.Length == Lines * CharsPerByte);
20+
21+
var shape = new bool[8, 8];
22+
for (var y = 0; y < Lines; y++)
23+
{
24+
var pb = byte.Parse(str.Slice(y * CharsPerByte, CharsPerByte), NumberStyles.HexNumber);
25+
for (var x = 0; x < BitsPerLine; x++)
26+
{
27+
shape[7 - x, y] = (pb & (1 << x)) != 0;
28+
}
29+
}
30+
31+
return shape;
32+
}
33+
34+
private readonly Drawing _drawing;
35+
36+
static LargeAsciiGlyph()
37+
{
38+
Debug.Assert(Raw.Length % CharsPerByte == 0);
39+
var byteCount = Raw.Length / CharsPerByte;
40+
41+
Debug.Assert(byteCount % Lines == 0);
42+
var glyphCount = byteCount / Lines;
43+
44+
var glyphs = new List<bool[,]>();
45+
for (var i = 0; i < glyphCount; i ++)
46+
{
47+
glyphs.Add(ExtractGlyph(Raw.AsSpan(i * Lines * CharsPerByte,
48+
Lines * CharsPerByte))
49+
);
50+
}
51+
52+
Shapes = glyphs.ToArray();
53+
}
54+
55+
/// <summary>
56+
/// Creates a new large ASCII glyph for a given <see cref="char"/>.
57+
/// </summary>
58+
/// <param name="char">The character to obtain the glyph of.</param>
59+
/// <param name="style">The text style to use.</param>
60+
public LargeAsciiGlyph(byte @char, Style style)
61+
{
62+
_drawing = new(new(BitsPerLine / 2, Lines));
63+
_drawing.Fill(new(new(0, 0), _drawing.Size), new Rune(ControlCharacter.Whitespace), style);
64+
65+
var shape = Shapes[@char];
66+
67+
for (var x = 0; x < BitsPerLine; x++)
68+
{
69+
for (var y = 0; y < Lines; y++)
70+
{
71+
var ap = new PointF(x / 2F, y / 2F);
72+
if (shape[x, y])
73+
{
74+
_drawing.Point(ap, style);
75+
}
76+
}
77+
}
78+
}
79+
80+
/// <inheritdoc cref="IDrawable.Size"/>
81+
public Size Size => _drawing.Size;
82+
83+
/// <inheritdoc cref="IDrawable.DrawTo"/>
84+
public void DrawTo(IDrawSurface destination, Rectangle srcArea, Point destLocation) =>
85+
_drawing.DrawTo(destination, srcArea, destLocation);
86+
}

Sharpie/Sharpie.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,8 @@
4141
</None>
4242
</ItemGroup>
4343

44+
<ItemGroup>
45+
<None Remove="basic.font" />
46+
</ItemGroup>
47+
4448
</Project>

Sharpie/Usings.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,4 @@ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3636
global using System.Runtime.InteropServices;
3737
global using Sharpie.Abstractions;
3838
global using Sharpie.Backend;
39+
global using System.Globalization;

media/demo-3.gif

138 KB
Loading

0 commit comments

Comments
 (0)