55using System . Xml ;
66using Microsoft . CodeAnalysis ;
77using Microsoft . Maui . Controls . Xaml ;
8+ using Microsoft . Maui . Graphics ;
9+
10+ using static Microsoft . Maui . Controls . SourceGen . GeneratorHelpers ;
811
912namespace Microsoft . Maui . Controls . SourceGen . TypeConverters ;
1013
1114internal class ColorConverter : ISGTypeConverter
1215{
13- private static readonly HashSet < string > KnownNamedColors = new ( StringComparer . OrdinalIgnoreCase )
14- {
15- "AliceBlue" , "AntiqueWhite" , "Aqua" , "Aquamarine" , "Azure" , "Beige" , "Bisque" , "Black" ,
16- "BlanchedAlmond" , "Blue" , "BlueViolet" , "Brown" , "BurlyWood" , "CadetBlue" , "Chartreuse" ,
17- "Chocolate" , "Coral" , "CornflowerBlue" , "Cornsilk" , "Crimson" , "Cyan" , "DarkBlue" ,
18- "DarkCyan" , "DarkGoldenrod" , "DarkGray" , "DarkGreen" , "DarkGrey" , "DarkKhaki" ,
19- "DarkMagenta" , "DarkOliveGreen" , "DarkOrange" , "DarkOrchid" , "DarkRed" , "DarkSalmon" ,
20- "DarkSeaGreen" , "DarkSlateBlue" , "DarkSlateGray" , "DarkSlateGrey" , "DarkTurquoise" ,
21- "DarkViolet" , "DeepPink" , "DeepSkyBlue" , "DimGray" , "DimGrey" , "DodgerBlue" , "Firebrick" ,
22- "FloralWhite" , "ForestGreen" , "Fuchsia" , "Gainsboro" , "GhostWhite" , "Gold" , "Goldenrod" ,
23- "Gray" , "Green" , "GreenYellow" , "Grey" , "Honeydew" , "HotPink" , "IndianRed" , "Indigo" ,
24- "Ivory" , "Khaki" , "Lavender" , "LavenderBlush" , "LawnGreen" , "LemonChiffon" , "LightBlue" ,
25- "LightCoral" , "LightCyan" , "LightGoldenrodYellow" , "LightGray" , "LightGreen" , "LightGrey" ,
26- "LightPink" , "LightSalmon" , "LightSeaGreen" , "LightSkyBlue" , "LightSlateGray" , "LightSlateGrey" ,
27- "LightSteelBlue" , "LightYellow" , "Lime" , "LimeGreen" , "Linen" , "Magenta" , "Maroon" ,
28- "MediumAquamarine" , "MediumBlue" , "MediumOrchid" , "MediumPurple" , "MediumSeaGreen" ,
29- "MediumSlateBlue" , "MediumSpringGreen" , "MediumTurquoise" , "MediumVioletRed" , "MidnightBlue" ,
30- "MintCream" , "MistyRose" , "Moccasin" , "NavajoWhite" , "Navy" , "OldLace" , "Olive" , "OliveDrab" ,
31- "Orange" , "OrangeRed" , "Orchid" , "PaleGoldenrod" , "PaleGreen" , "PaleTurquoise" , "PaleVioletRed" ,
32- "PapayaWhip" , "PeachPuff" , "Peru" , "Pink" , "Plum" , "PowderBlue" , "Purple" , "Red" , "RosyBrown" ,
33- "RoyalBlue" , "SaddleBrown" , "Salmon" , "SandyBrown" , "SeaGreen" , "SeaShell" , "Sienna" , "Silver" ,
34- "SkyBlue" , "SlateBlue" , "SlateGray" , "SlateGrey" , "Snow" , "SpringGreen" , "SteelBlue" , "Tan" ,
35- "Teal" , "Thistle" , "Tomato" , "Transparent" , "Turquoise" , "Violet" , "Wheat" , "White" ,
36- "WhiteSmoke" , "Yellow" , "YellowGreen"
37- } ;
38-
39- // #rgb, #rrggbb, #aarrggbb are all valid
40- private const string RxColorHexPattern = @"^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}([0-9a-fA-F]{2})?)$" ;
41- private static readonly Lazy < Regex > RxColorHex = new ( ( ) => new Regex ( RxColorHexPattern , RegexOptions . Compiled | RegexOptions . Singleline ) ) ;
42-
43- // RGB, RGBA, HSL, HSLA, HSV, HSVA function patterns
44- private const string RxFuncPattern = "^(?<func>rgba|argb|rgb|hsla|hsl|hsva|hsv)\\ (((?<v>\\ d%?),){2}((?<v>\\ d%?)|(?<v>\\ d%?),(?<v>\\ d%?))\\ );?$" ;
45- private static readonly Lazy < Regex > RxFuncExpr = new ( ( ) => new Regex ( RxFuncPattern , RegexOptions . Compiled | RegexOptions . IgnoreCase | RegexOptions . IgnorePatternWhitespace | RegexOptions . Singleline ) ) ;
46-
4716 public IEnumerable < string > SupportedTypes => new [ ] { "Color" , "Microsoft.Maui.Graphics.Color" } ;
4817
4918 public string Convert ( string value , BaseNode node , ITypeSymbol toType , SourceGenContext context , LocalVariable ? parentVar = null )
5019 {
51- var xmlLineInfo = ( IXmlLineInfo ) node ;
52- if ( ! string . IsNullOrEmpty ( value ) )
20+ if ( ColorUtils . TryParse ( value , out float red , out float green , out float blue , out float alpha ) )
5321 {
54- // Any named colors are ok. Surrounding white spaces are ok. Case insensitive.
55- var actualColorName = KnownNamedColors . FirstOrDefault ( c => string . Equals ( c , value . Trim ( ) , StringComparison . OrdinalIgnoreCase ) ) ;
56- if ( actualColorName is not null )
57- {
58- var colorsType = context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Colors" ) ! ;
59- return $ "{ colorsType . ToFQDisplayString ( ) } .{ actualColorName } ";
60- }
61-
62- // Check for HEX Color string
63- if ( RxColorHex . Value . IsMatch ( value ) )
64- {
65- var colorType = context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Color" ) ! ;
66- return $ "{ colorType . ToFQDisplayString ( ) } .FromArgb(\" { value } \" )";
67- }
68-
69- var match = RxFuncExpr . Value . Match ( value ) ;
70-
71- var funcName = match ? . Groups ? [ "func" ] ? . Value ;
72- var funcValues = match ? . Groups ? [ "v" ] ? . Captures ;
73-
74- if ( ! string . IsNullOrEmpty ( funcName ) && funcValues is not null )
75- {
76- // ie: argb() needs 4 parameters:
77- if ( funcValues . Count == funcName ? . Length )
78- {
79- var colorType = context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Color" ) ! ;
80- return $ "{ colorType . ToFQDisplayString ( ) } .Parse(\" { value } \" )";
81- }
82- }
22+ var colorType = context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Color" ) ! ;
23+ return $ "new { colorType . ToFQDisplayString ( ) } ({ FormatInvariant ( red ) } f, { FormatInvariant ( green ) } f, { FormatInvariant ( blue ) } f, { FormatInvariant ( alpha ) } f) /* { value } */";
24+ }
8325
84- // As a last resort, try Color.Parse() for any other valid color formats
85- var colorType2 = context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Color" ) ! ;
86- return $ "{ colorType2 . ToFQDisplayString ( ) } .Parse( \" { value } \" ) ";
26+ if ( GetNamedColorField ( value ) is IFieldSymbol colorsField )
27+ {
28+ return $ "{ colorsField . ContainingType . ToFQDisplayString ( ) } .{ colorsField . Name } ";
8729 }
8830
89- context . ReportConversionFailed ( xmlLineInfo , value , toType , Descriptors . ConversionFailed ) ;
31+ context . ReportConversionFailed ( ( IXmlLineInfo ) node , value , toType , Descriptors . ConversionFailed ) ;
9032 return "default" ;
33+
34+ IFieldSymbol ? GetNamedColorField ( string name )
35+ {
36+ return context . Compilation . GetTypeByMetadataName ( "Microsoft.Maui.Graphics.Colors" )
37+ ? . GetMembers ( )
38+ . OfType < IFieldSymbol > ( )
39+ . Where ( f => f . IsPublic ( ) && f . IsStatic && f . IsReadOnly && f . Type . ToFQDisplayString ( ) == "global::Microsoft.Maui.Graphics.Color" )
40+ . FirstOrDefault ( f => string . Equals ( f . Name , name , StringComparison . OrdinalIgnoreCase ) ) ;
41+ }
9142 }
9243}
0 commit comments