1+ #define BUILDTASK
2+ //Added this into the project as we would need to manually pull in a lot of Avalonia projects, it's more simple to just contain these files in the source gen
3+ //From https://github.com/AvaloniaUI/Avalonia/blob/master/src/Avalonia.Visuals/Media/Color.cs
4+
5+ using System ;
6+ using System . Globalization ;
7+ #if ! BUILDTASK
8+ using Avalonia . Animation . Animators ;
9+ #endif
10+
11+ namespace Avalonia . Media
12+ {
13+ /// <summary>
14+ /// An ARGB color.
15+ /// </summary>
16+ public readonly struct Color : IEquatable < Color >
17+ {
18+ static Color ( )
19+ {
20+ #if ! BUILDTASK
21+ Animation . Animation . RegisterAnimator < ColorAnimator > ( prop => typeof ( Color ) . IsAssignableFrom ( prop . PropertyType ) ) ;
22+ #endif
23+ }
24+
25+ /// <summary>
26+ /// Gets the Alpha component of the color.
27+ /// </summary>
28+ public byte A { get ; }
29+
30+ /// <summary>
31+ /// Gets the Red component of the color.
32+ /// </summary>
33+ public byte R { get ; }
34+
35+ /// <summary>
36+ /// Gets the Green component of the color.
37+ /// </summary>
38+ public byte G { get ; }
39+
40+ /// <summary>
41+ /// Gets the Blue component of the color.
42+ /// </summary>
43+ public byte B { get ; }
44+
45+ public Color ( byte a , byte r , byte g , byte b )
46+ {
47+ A = a ;
48+ R = r ;
49+ G = g ;
50+ B = b ;
51+ }
52+
53+ /// <summary>
54+ /// Creates a <see cref="Color"/> from alpha, red, green and blue components.
55+ /// </summary>
56+ /// <param name="a">The alpha component.</param>
57+ /// <param name="r">The red component.</param>
58+ /// <param name="g">The green component.</param>
59+ /// <param name="b">The blue component.</param>
60+ /// <returns>The color.</returns>
61+ public static Color FromArgb ( byte a , byte r , byte g , byte b )
62+ {
63+ return new Color ( a , r , g , b ) ;
64+ }
65+
66+ /// <summary>
67+ /// Creates a <see cref="Color"/> from red, green and blue components.
68+ /// </summary>
69+ /// <param name="r">The red component.</param>
70+ /// <param name="g">The green component.</param>
71+ /// <param name="b">The blue component.</param>
72+ /// <returns>The color.</returns>
73+ public static Color FromRgb ( byte r , byte g , byte b )
74+ {
75+ return new Color ( 0xff , r , g , b ) ;
76+ }
77+
78+ /// <summary>
79+ /// Creates a <see cref="Color"/> from an integer.
80+ /// </summary>
81+ /// <param name="value">The integer value.</param>
82+ /// <returns>The color.</returns>
83+ public static Color FromUInt32 ( uint value )
84+ {
85+ return new Color (
86+ ( byte ) ( ( value >> 24 ) & 0xff ) ,
87+ ( byte ) ( ( value >> 16 ) & 0xff ) ,
88+ ( byte ) ( ( value >> 8 ) & 0xff ) ,
89+ ( byte ) ( value & 0xff )
90+ ) ;
91+ }
92+
93+ /// <summary>
94+ /// Parses a color string.
95+ /// </summary>
96+ /// <param name="s">The color string.</param>
97+ /// <returns>The <see cref="Color"/>.</returns>
98+ public static Color Parse ( string s )
99+ {
100+ if ( s is null )
101+ {
102+ throw new ArgumentNullException ( nameof ( s ) ) ;
103+ }
104+
105+ if ( TryParse ( s , out Color color ) )
106+ {
107+ return color ;
108+ }
109+
110+ throw new FormatException ( $ "Invalid color string: '{ s } '.") ;
111+ }
112+
113+ /// <summary>
114+ /// Parses a color string.
115+ /// </summary>
116+ /// <param name="s">The color string.</param>
117+ /// <returns>The <see cref="Color"/>.</returns>
118+ public static Color Parse ( ReadOnlySpan < char > s )
119+ {
120+ if ( TryParse ( s , out Color color ) )
121+ {
122+ return color ;
123+ }
124+
125+ throw new FormatException ( $ "Invalid color string: '{ s . ToString ( ) } '.") ;
126+ }
127+
128+ /// <summary>
129+ /// Parses a color string.
130+ /// </summary>
131+ /// <param name="s">The color string.</param>
132+ /// <param name="color">The parsed color</param>
133+ /// <returns>The status of the operation.</returns>
134+ public static bool TryParse ( string s , out Color color )
135+ {
136+ color = default ;
137+
138+ if ( s is null )
139+ {
140+ return false ;
141+ }
142+
143+ if ( s . Length == 0 )
144+ {
145+ return false ;
146+ }
147+
148+ if ( s [ 0 ] == '#' && TryParseInternal ( s . AsSpan ( ) , out color ) )
149+ {
150+ return true ;
151+ }
152+
153+ var knownColor = KnownColors . GetKnownColor ( s ) ;
154+
155+ if ( knownColor != KnownColor . None )
156+ {
157+ color = knownColor . ToColor ( ) ;
158+
159+ return true ;
160+ }
161+
162+ return false ;
163+ }
164+
165+ /// <summary>
166+ /// Parses a color string.
167+ /// </summary>
168+ /// <param name="s">The color string.</param>
169+ /// <param name="color">The parsed color</param>
170+ /// <returns>The status of the operation.</returns>
171+ public static bool TryParse ( ReadOnlySpan < char > s , out Color color )
172+ {
173+ if ( s . Length == 0 )
174+ {
175+ color = default ;
176+
177+ return false ;
178+ }
179+
180+ if ( s [ 0 ] == '#' )
181+ {
182+ return TryParseInternal ( s , out color ) ;
183+ }
184+
185+ var knownColor = KnownColors . GetKnownColor ( s . ToString ( ) ) ;
186+
187+ if ( knownColor != KnownColor . None )
188+ {
189+ color = knownColor . ToColor ( ) ;
190+
191+ return true ;
192+ }
193+
194+ color = default ;
195+
196+ return false ;
197+ }
198+
199+ private static bool TryParseInternal ( ReadOnlySpan < char > s , out Color color )
200+ {
201+ static bool TryParseCore ( ReadOnlySpan < char > input , ref Color color )
202+ {
203+ var alphaComponent = 0u ;
204+
205+ if ( input . Length == 6 )
206+ {
207+ alphaComponent = 0xff000000 ;
208+ }
209+ else if ( input . Length != 8 )
210+ {
211+ return false ;
212+ }
213+
214+ // TODO: (netstandard 2.1) Can use allocation free parsing.
215+ if ( ! uint . TryParse ( input . ToString ( ) , NumberStyles . HexNumber , CultureInfo . InvariantCulture ,
216+ out var parsed ) )
217+ {
218+ return false ;
219+ }
220+
221+ color = FromUInt32 ( parsed | alphaComponent ) ;
222+
223+ return true ;
224+ }
225+
226+ color = default ;
227+
228+ ReadOnlySpan < char > input = s . Slice ( 1 ) ;
229+
230+ // Handle shorthand cases like #FFF (RGB) or #FFFF (ARGB).
231+ if ( input . Length == 3 || input . Length == 4 )
232+ {
233+ var extendedLength = 2 * input . Length ;
234+
235+ #if ! BUILDTASK
236+ Span < char > extended = stackalloc char [ extendedLength ] ;
237+ #else
238+ char [ ] extended = new char [ extendedLength ] ;
239+ #endif
240+
241+ for ( int i = 0 ; i < input . Length ; i ++ )
242+ {
243+ extended [ 2 * i + 0 ] = input [ i ] ;
244+ extended [ 2 * i + 1 ] = input [ i ] ;
245+ }
246+
247+ return TryParseCore ( extended , ref color ) ;
248+ }
249+
250+ return TryParseCore ( input , ref color ) ;
251+ }
252+
253+ /// <summary>
254+ /// Returns the string representation of the color.
255+ /// </summary>
256+ /// <returns>
257+ /// The string representation of the color.
258+ /// </returns>
259+ public override string ToString ( )
260+ {
261+ uint rgb = ToUint32 ( ) ;
262+ return KnownColors . GetKnownColorName ( rgb ) ?? $ "#{ rgb : x8} ";
263+ }
264+
265+ /// <summary>
266+ /// Returns the integer representation of the color.
267+ /// </summary>
268+ /// <returns>
269+ /// The integer representation of the color.
270+ /// </returns>
271+ public uint ToUint32 ( )
272+ {
273+ return ( ( uint ) A << 24 ) | ( ( uint ) R << 16 ) | ( ( uint ) G << 8 ) | ( uint ) B ;
274+ }
275+
276+ /// <summary>
277+ /// Check if two colors are equal.
278+ /// </summary>
279+ public bool Equals ( Color other )
280+ {
281+ return A == other . A && R == other . R && G == other . G && B == other . B ;
282+ }
283+
284+ public override bool Equals ( object obj )
285+ {
286+ return obj is Color other && Equals ( other ) ;
287+ }
288+
289+ public override int GetHashCode ( )
290+ {
291+ unchecked
292+ {
293+ int hashCode = A . GetHashCode ( ) ;
294+ hashCode = ( hashCode * 397 ) ^ R . GetHashCode ( ) ;
295+ hashCode = ( hashCode * 397 ) ^ G . GetHashCode ( ) ;
296+ hashCode = ( hashCode * 397 ) ^ B . GetHashCode ( ) ;
297+ return hashCode ;
298+ }
299+ }
300+
301+ public static bool operator == ( Color left , Color right )
302+ {
303+ return left . Equals ( right ) ;
304+ }
305+
306+ public static bool operator != ( Color left , Color right )
307+ {
308+ return ! left . Equals ( right ) ;
309+ }
310+ }
311+ }
0 commit comments