2 * Copyright(c) 2020 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 using System.Collections;
19 using System.Collections.Generic;
20 using System.ComponentModel;
22 using Tizen.NUI.BaseComponents;
23 using Tizen.NUI.Binding;
28 /// <summary></summary>
29 [EditorBrowsable(EditorBrowsableState.Never)]
30 public class Theme : BindableObject
32 private readonly Dictionary<string, ViewStyle> map;
33 private string baseTheme;
35 /// <summary>Create an empty theme.</summary>
36 [EditorBrowsable(EditorBrowsableState.Never)]
39 map = new Dictionary<string, ViewStyle>();
42 /// <summary>Create a new theme from the xaml file.</summary>
43 /// <param name="xamlFile">An absolute path to the xaml file.</param>
44 /// <exception cref="ArgumentNullException">Thrown when the given xamlFile is null or empty string.</exception>
45 /// <exception cref="global::System.IO.IOException">Thrown when there are file IO problems.</exception>
46 /// <exception cref="Exception">Thrown when the content of the xaml file is not valid xaml form.</exception>
47 [EditorBrowsable(EditorBrowsableState.Never)]
48 public Theme(string xamlFile) : this()
50 if (string.IsNullOrEmpty(xamlFile))
52 throw new ArgumentNullException("The xaml file path cannot be null or empty string", nameof(xamlFile));
57 using(var reader = XmlReader.Create(xamlFile))
59 XamlLoader.Load(this, reader);
62 catch (global::System.IO.IOException e)
64 Tizen.Log.Info("NUI", $"Could not load \"{xamlFile}\".\n");
69 Tizen.Log.Info("NUI", $"Could not parse \"{xamlFile}\".\n");
70 Tizen.Log.Info("NUI", "Make sure the all used assemblies (e.g. Tizen.NUI.Components) are included in the application project.\n");
71 Tizen.Log.Info("NUI", "Make sure the type and namespace are correct.\n");
76 /// <summary></summary>
77 [EditorBrowsable(EditorBrowsableState.Never)]
78 public string Id { get; set; }
81 /// For Xaml use only.
82 /// The bulit-in theme id that will be used as base of this.
83 /// View styles with same key are merged.
85 internal string BasedOn
92 if (string.IsNullOrEmpty(baseTheme)) return;
94 var baseThemeInstance = ThemeManager.GetBuiltinTheme(baseTheme);
96 if (baseThemeInstance != null)
98 foreach (var item in baseThemeInstance)
100 var baseStyle = item.Value?.Clone();
101 if (map.ContainsKey(item.Key))
103 baseStyle.Merge(map[item.Key]);
105 map[item.Key] = baseStyle;
112 /// For Xaml use only.
113 /// Note that it is not a normal indexer.
114 /// Setter will merge the new value with existing item.
116 internal ViewStyle this[string styleName]
118 get => map[styleName];
123 map.Remove(styleName);
127 if (map.TryGetValue(styleName, out ViewStyle style) && style != null && style.GetType() == value.GetType())
133 map[styleName] = value;
138 internal int Count => map.Count;
141 /// Get an enumerator of the theme.
143 [EditorBrowsable(EditorBrowsableState.Never)]
144 public IEnumerator<KeyValuePair<string, ViewStyle>> GetEnumerator() => map.GetEnumerator();
147 /// Removes all styles in the theme.
149 [EditorBrowsable(EditorBrowsableState.Never)]
150 public void Clear() => map.Clear();
153 /// Determines whether the theme contains the specified style name.
155 /// <exception cref="ArgumentNullException">The given style name is null.</exception>
156 [EditorBrowsable(EditorBrowsableState.Never)]
157 public bool HasStyle(string styleName) => map.ContainsKey(styleName);
160 /// Removes the style with the specified style name.
162 /// <exception cref="ArgumentNullException">The given style name is null.</exception>
163 [EditorBrowsable(EditorBrowsableState.Never)]
164 public bool RemoveStyle(string styleName) => map.Remove(styleName);
167 /// Gets a style of given style name.
169 /// <param name="styleName">The string key to find a ViewStyle.</param>
170 /// <returns>Founded style instance.</returns>
171 [EditorBrowsable(EditorBrowsableState.Never)]
172 public ViewStyle GetStyle(string styleName) => map.ContainsKey(styleName) ? map[styleName] : null;
175 /// Gets a style of given view type.
177 /// <param name="viewType">The type of View.</param>
178 /// <returns>Founded style instance.</returns>
179 [EditorBrowsable(EditorBrowsableState.Never)]
180 public ViewStyle GetStyle(Type viewType)
182 var currentType = viewType;
183 ViewStyle resultStyle = null;
187 if (currentType.Equals(typeof(View))) break;
188 resultStyle = GetStyle(currentType.FullName);
189 currentType = currentType.BaseType;
191 while (resultStyle == null && currentType != null);
197 /// Adds the specified style name and value to the theme.
198 /// This replace existing value if the theme already has a style with given name.
200 /// <param name="styleName">The style name to add.</param>
201 /// <param name="value">The style instance to add.</param>
202 [EditorBrowsable(EditorBrowsableState.Never)]
203 public void AddStyle(string styleName, ViewStyle value) => map[styleName] = value?.Clone();
207 [EditorBrowsable(EditorBrowsableState.Never)]
208 public object Clone()
210 var result = new Theme()
215 foreach (var item in this)
217 result.AddStyle(item.Key, item.Value);
222 /// <summary>Merge other Theme into this.</summary>
223 /// <param name="xamlFile">An absolute path to the xaml file of the theme.</param>
224 /// <exception cref="ArgumentException">Thrown when the given xamlFile is null or empty string.</exception>
225 /// <exception cref="global::System.IO.IOException">Thrown when there are file IO problems.</exception>
226 /// <exception cref="XamlParseException">Thrown when the content of the xaml file is not valid xaml form.</exception>
227 [EditorBrowsable(EditorBrowsableState.Never)]
228 public void Merge(string xamlFile)
230 Merge(new Theme(xamlFile));
233 /// <summary>Merge other Theme into this.</summary>
234 /// <param name="theme">The Theme.</param>
235 [EditorBrowsable(EditorBrowsableState.Never)]
236 public void Merge(Theme theme)
239 throw new ArgumentNullException(nameof(theme));
241 foreach (var item in theme)
243 if (item.Value == null)
245 map[item.Key] = null;
247 else if (map.ContainsKey(item.Key) && !item.Value.SolidNull)
249 map[item.Key].Merge(theme.GetStyle(item.Key));
253 map[item.Key] = theme.GetStyle(item.Key).Clone();
259 /// Internal use only.
261 internal void AddStyleWithoutClone(string styleName, ViewStyle value) => map[styleName] = value;