[NUI] Fix color format to #RRGGBBAA from #AARRGGBB (#3225)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / XamlBinding / ColorTypeConverter.cs
1 /*
2  * Copyright(c) 2021 Samsung Electronics Co., Ltd.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  */
17
18 using System;
19 using System.ComponentModel;
20 using System.Globalization;
21 using Tizen.NUI.Xaml;
22
23 namespace Tizen.NUI.Binding
24 {
25     /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
26     [EditorBrowsable(EditorBrowsableState.Never)]
27     [ProvideCompiled("Tizen.NUI.Xaml.Core.XamlC.ColorTypeConverter")]
28     [TypeConversion(typeof(Color))]
29     public class ColorTypeConverter : TypeConverter
30     {
31         // Supported inputs
32         // HEX          #rgb, #argb, #rrggbb, #aarrggbb
33         // float array      0.5,0.5,0.5,0.5
34         // Predefined color         case insensitive
35         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
36         [EditorBrowsable(EditorBrowsableState.Never)]
37         public override object ConvertFromInvariantString(string value)
38         {
39             if (value != null)
40             {
41                 value = value.Trim();
42                 if (value.StartsWith("#", StringComparison.Ordinal))
43                 {
44                     return FromHex(value);
45                 }
46
47                 string[] parts = value.Split(',');
48                 if (parts.Length == 1) //like Red or Color.Red
49                 {
50                     parts = value.Split('.');
51                     if (parts.Length == 1 || (parts.Length == 2 && parts[0] == "Color"))
52                     {
53                         string color = parts[parts.Length - 1];
54                         switch (color)
55                         {
56                             case "Black": return Color.Black;
57                             case "White": return Color.White;
58                             case "Red": return Color.Red;
59                             case "Green": return Color.Green;
60                             case "Blue": return Color.Blue;
61                             case "Yellow": return Color.Yellow;
62                             case "Magenta": return Color.Magenta;
63                             case "Cyan": return Color.Cyan;
64                             case "Transparent": return Color.Transparent;
65                         }
66                     }
67                 }
68                 else if (parts.Length == 4) //like 0.5,0.5,0.5,0.5
69                 {
70                     return new Color(Single.Parse(parts[0].Trim(), CultureInfo.InvariantCulture),
71                                      Single.Parse(parts[1].Trim(), CultureInfo.InvariantCulture),
72                                      Single.Parse(parts[2].Trim(), CultureInfo.InvariantCulture),
73                                      Single.Parse(parts[3].Trim(), CultureInfo.InvariantCulture));
74                 }
75             }
76
77             throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(Color)}");
78         }
79
80         static uint ToHex(char c)
81         {
82             ushort x = (ushort)c;
83             if (x >= '0' && x <= '9')
84                 return (uint)(x - '0');
85
86             x |= 0x20;
87             if (x >= 'a' && x <= 'f')
88                 return (uint)(x - 'a' + 10);
89             return 0;
90         }
91
92         static uint ToHexD(char c)
93         {
94             var j = ToHex(c);
95             return (j << 4) | j;
96         }
97
98         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
99         [EditorBrowsable(EditorBrowsableState.Never)]
100         public static Color FromRgba(int r, int g, int b, int a)
101         {
102             float red = (float)r / 255;
103             float green = (float)g / 255;
104             float blue = (float)b / 255;
105             float alpha = (float)a / 255;
106             return new Color(red, green, blue, alpha);
107         }
108
109         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
110         [EditorBrowsable(EditorBrowsableState.Never)]
111         public static Color FromRgb(int r, int g, int b)
112         {
113             return FromRgba(r, g, b, 255);
114         }
115
116         static Color FromHex(string hex)
117         {
118             // Undefined
119             if (hex.Length < 3)
120                 return Color.Black;
121             int idx = (hex[0] == '#') ? 1 : 0;
122
123             switch (hex.Length - idx)
124             {
125                 case 3: //#rgb => ffrrggbb
126                     var t1 = ToHexD(hex[idx++]);
127                     var t2 = ToHexD(hex[idx++]);
128                     var t3 = ToHexD(hex[idx]);
129
130                     return FromRgb((int)t1, (int)t2, (int)t3);
131
132                 case 4: //#rgba => rrggbbaa
133                     var f1 = ToHexD(hex[idx++]);
134                     var f2 = ToHexD(hex[idx++]);
135                     var f3 = ToHexD(hex[idx++]);
136                     var f4 = ToHexD(hex[idx]);
137                     return FromRgba((int)f1, (int)f2, (int)f3, (int)f4);
138
139                 case 6: //#rrggbb => ffrrggbb
140                     return FromRgb((int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
141                             (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
142                             (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx])));
143
144                 case 8: //#rrggbbaa
145                     return FromRgba((int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
146                             (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
147                             (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx++])),
148                             (int)(ToHex(hex[idx++]) << 4 | ToHex(hex[idx])));
149
150                 default: //everything else will result in unexpected results
151                     return Color.Black;
152             }
153         }
154
155         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
156         [EditorBrowsable(EditorBrowsableState.Never)]
157         public override string ConvertToString(object value)
158         {
159             if (value != null)
160             {
161                 Color color = (Color)value;
162                 return color.R.ToString() + " " + color.G.ToString() + " " + color.B.ToString() + " " + color.A.ToString();
163             }
164             return "";
165         }
166     }
167 }