1+ // Code authored by Dean Edis (DeanTheCoder).
2+ // Anyone is free to copy, modify, use, compile, or distribute this software,
3+ // either in source code form or as a compiled binary, for any non-commercial
4+ // purpose.
5+ //
6+ // If you modify the code, please retain this copyright header,
7+ // and consider contributing back to the repository or letting us know
8+ // about your modifications. Your contributions are valued!
9+ //
10+ // THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND.
11+
12+ using System ;
13+ using System . Diagnostics ;
14+ using System . Linq ;
15+ using System . Reflection ;
16+ using DTC . Core . Extensions ;
17+ using G33kShell . Desktop . Console . Controls ;
18+ using JetBrains . Annotations ;
19+ using WenceyWang . FIGlet ;
20+
21+ namespace G33kShell . Desktop . Console . Screensavers ;
22+
23+ /// <summary>
24+ /// Digital clock that bounces around the screen.
25+ /// </summary>
26+ [ DebuggerDisplay ( "ClockCanvas:{X},{Y} {Width}x{Height}" ) ]
27+ [ UsedImplicitly ]
28+ public class ClockCanvas : ScreensaverBase
29+ {
30+ private readonly FIGletFont m_font ;
31+ private int m_posX ;
32+ private int m_posY ;
33+ private int m_dX = 1 ;
34+ private int m_dY = 1 ;
35+
36+ public ClockCanvas ( int screenWidth , int screenHeight ) : base ( screenWidth , screenHeight , 5 )
37+ {
38+ Name = "clock" ;
39+
40+ m_font = LoadFont ( ) ;
41+ }
42+
43+ public override void UpdateFrame ( ScreenData screen )
44+ {
45+ screen . Clear ( Foreground , Background ) ;
46+ var highResScreen = new HighResScreen ( screen ) ;
47+
48+ var now = DateTime . Now . ToString ( "HH:mm" ) ;
49+
50+ // Calculate width and height of the text.
51+ var textWidth = 0 ;
52+ var textHeight = 0 ;
53+ foreach ( var ch in now )
54+ {
55+ var charLines = Enumerable . Range ( 0 , m_font . Height )
56+ . Select ( y => m_font . GetCharacter ( ch , y ) )
57+ . ToArray ( ) ;
58+ if ( charLines . Length > 0 )
59+ textWidth += charLines [ 0 ] . Length ;
60+
61+ var blankLines = charLines
62+ . Reverse ( )
63+ . TakeWhile ( string . IsNullOrWhiteSpace )
64+ . Count ( ) ;
65+ textHeight = Math . Max ( textHeight , m_font . Height - blankLines ) ;
66+ }
67+
68+ // Update position.
69+ m_posX += m_dX ;
70+ m_posY += m_dY ;
71+
72+ // Bounce off walls.
73+ if ( m_posX <= 0 || m_posX + textWidth >= highResScreen . Width )
74+ {
75+ m_dX = - m_dX ;
76+ m_posX = Math . Max ( 0 , Math . Min ( highResScreen . Width - textWidth , m_posX ) ) ;
77+ }
78+
79+ if ( m_posY <= 0 || m_posY + textHeight >= highResScreen . Height )
80+ {
81+ m_dY = - m_dY ;
82+ m_posY = Math . Max ( 0 , Math . Min ( highResScreen . Height - textHeight , m_posY ) ) ;
83+ }
84+
85+ // Draw the time at the bouncing position
86+ for ( var y = 0 ; y < m_font . Height ; y ++ )
87+ {
88+ var offset = 0 ;
89+ foreach ( var textRow in now . Select ( ch => m_font . GetCharacter ( ch , y ) ) )
90+ {
91+ for ( var x = 0 ; x < textRow . Length ; x ++ )
92+ {
93+ var ch = textRow [ x ] ;
94+ if ( ch == ' ' )
95+ continue ; // Nothing to draw.
96+
97+ var screenX = m_posX + x + offset ;
98+ var screenY = m_posY + y ;
99+ highResScreen . Plot ( screenX , screenY , ch == '█' ? Foreground : 0.25 . Lerp ( Background , Foreground ) ) ;
100+ }
101+
102+ offset += textRow . Length ;
103+ }
104+ }
105+ }
106+
107+ private static FIGletFont LoadFont ( )
108+ {
109+ // Enumerate all Avalonia embedded resources.
110+ var fontFolder = Assembly . GetExecutingAssembly ( ) . GetDirectory ( ) ;
111+ var fontFile = fontFolder . GetFiles ( "Assets/Fonts/Figlet/*.flf" ) . Single ( ) ;
112+
113+ // Load the font.
114+ using var fontStream = fontFile . OpenRead ( ) ;
115+ return new FIGletFont ( fontStream ) ;
116+ }
117+ }
0 commit comments