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.
17 extern alias TizenSystemInformation;
18 using TizenSystemInformation.Tizen.System;
20 using System.Collections.Generic;
21 using System.ComponentModel;
23 using Tizen.NUI.BaseComponents;
27 /// <summary></summary>
28 [EditorBrowsable(EditorBrowsableState.Never)]
29 public static class ThemeManager
39 private static readonly string[] nuiThemeProjects =
42 "Tizen.NUI.Components",
47 /// Table that indicates default theme id by device profile.
48 /// Note that, the fallback of null value is Common value.
50 private static readonly string[] profileDefaultTheme =
52 /* Common */ "Tizen.NUI.Theme.Common",
53 /* Mobile */ "Tizen.NUI.Theme.Common",
55 /* Wearable */ "Tizen.NUI.Theme.Wearable",
58 private static Theme currentTheme;
59 private static Theme defaultTheme;
60 private static bool isLoadingDefault = false;
61 private static Profile? currentProfile;
62 private static List<Theme> builtinThemes = new List<Theme>(); // Themes provided by framework.
63 internal static List<Theme> customThemes = new List<Theme>(); // Themes registered by user.
65 static ThemeManager() {}
69 [EditorBrowsable(EditorBrowsableState.Never)]
70 public static event EventHandler<ThemeChangedEventArgs> ThemeChanged;
73 /// Internal one should be called before calling public ThemeChanged
75 internal static event EventHandler<ThemeChangedEventArgs> ThemeChangedInternal;
77 internal static Theme CurrentTheme
81 if (currentTheme == null)
83 currentTheme = DefaultTheme;
94 internal static Theme DefaultTheme
98 if (defaultTheme == null && !isLoadingDefault)
100 isLoadingDefault = true;
101 defaultTheme = LoadBuiltinTheme(profileDefaultTheme[(int)CurrentProfile]);
102 isLoadingDefault = false;
106 set => defaultTheme = (Theme)value?.Clone();
109 internal static bool ThemeApplied => (CurrentTheme.Count > 0 || DefaultTheme.Count > 0);
111 private static Profile CurrentProfile
115 if (currentProfile == null)
117 currentProfile = Profile.Common;
118 string profileString = "";
122 Information.TryGetValue<string>("tizen.org/feature/profile", out profileString);
123 Tizen.Log.Info("NUI", "Profile for initial theme found : " + profileString);
127 Tizen.Log.Info("NUI", "Unknown device profile\n");
131 if (string.Equals(profileString, "mobile"))
133 currentProfile = Profile.Mobile;
135 else if (string.Equals(profileString, "tv"))
137 currentProfile = Profile.TV;
139 else if (string.Equals(profileString, "wearable"))
141 currentProfile = Profile.Wearable;
145 return (Profile)currentProfile;
150 /// Set a theme to be used as fallback.
151 /// The fallback theme is set to profile specified theme by default.
153 /// <param name="fallbackTheme">The theme instance to be applied as a fallback.</param>
154 /// <exception cref="ArgumentNullException">The given theme is null.</exception>
155 [EditorBrowsable(EditorBrowsableState.Never)]
156 public static void ApplyFallbackTheme(Theme fallbackTheme)
158 DefaultTheme = fallbackTheme ?? throw new ArgumentNullException("Invalid theme.");
162 /// Apply theme to the NUI.
163 /// This will change the appreance of the existing components with property <seealso cref="View.ThemeChangeSensitive"/> on.
164 /// This also affects all components created afterwards.
166 /// <param name="theme">The theme instance to be applied.</param>
167 /// <exception cref="ArgumentNullException">Thrown when the given theme is null.</exception>
168 [EditorBrowsable(EditorBrowsableState.Never)]
169 public static void ApplyTheme(Theme theme)
171 var newTheme = (Theme)theme?.Clone() ?? throw new ArgumentNullException("Invalid theme.");
173 if (string.IsNullOrEmpty(newTheme.Id))
175 newTheme.Id = "NONAME";
178 CurrentTheme = newTheme;
182 /// Note that this API is to support legacy Tizen.NUI.Components.StyleManager.
183 /// Please use <seealso cref="ApplyTheme(Theme)"/> instead.
185 /// Apply theme to the NUI using theme id.
186 /// The id of theme should be either a registered custom theme or a built-in theme.
187 /// You can register custom theme using <seealso cref="RegisterTheme(Theme)"/>.
188 /// This will change the appreance of the existing components with property <seealso cref="View.ThemeChangeSensitive"/> on.
189 /// This also affects all components created afterwards.
191 /// <param name="themeId">The theme Id.</param>
192 /// <exception cref="ArgumentNullException">Thrown when the given themeId is null.</exception>
193 [EditorBrowsable(EditorBrowsableState.Never)]
194 public static void ApplyTheme(string themeId)
196 if (themeId == null) throw new ArgumentNullException("Invalid themeId");
198 int index = customThemes.FindIndex(x => x.Id.Equals(themeId, StringComparison.OrdinalIgnoreCase));
201 CurrentTheme = customThemes[index];
205 index = builtinThemes.FindIndex(x => string.Equals(x.Id, themeId, StringComparison.OrdinalIgnoreCase));
208 CurrentTheme = builtinThemes[index];
212 Tizen.Log.Info("NUI", $"No Theme found with given id : {themeId}");
217 /// Note that this API is to support legacy Tizen.NUI.Components.StyleManager.
219 /// Register a custom theme that can be used as an id when calling <seealso cref="ApplyTheme(string)"/>.
221 /// <param name="theme">The theme instance.</param>
222 /// <exception cref="ArgumentException">Thrown when the given theme is null or invalid.</exception>
223 [EditorBrowsable(EditorBrowsableState.Never)]
224 public static void RegisterTheme(Theme theme)
226 if (theme == null || string.IsNullOrEmpty(theme.Id)) throw new ArgumentException("Invalid theme.");
228 int index = customThemes.FindIndex(x => x.Id.Equals(theme.Id, StringComparison.OrdinalIgnoreCase));
231 customThemes[index] = (Theme)theme.Clone();
235 customThemes.Add((Theme)theme.Clone());
240 /// Load a style with style name in the current theme.
241 /// For components, the style name is a component name (e.g. Button) in normal case.
243 /// <param name="styleName">The style name.</param>
244 /// <exception cref="ArgumentNullException">Thrown when the given styleName is null.</exception>
245 [EditorBrowsable(EditorBrowsableState.Never)]
246 public static ViewStyle GetStyle(string styleName)
248 if (styleName == null) throw new ArgumentNullException("Invalid style name");
250 if (!ThemeApplied) return null;
252 return (CurrentTheme.GetStyle(styleName) ?? DefaultTheme.GetStyle(styleName))?.Clone();
256 /// Load a style with View type in the current theme.
258 /// <param name="viewType">The type of View.</param>
259 /// <exception cref="ArgumentNullException">Thrown when the given viewType is null.</exception>
260 [EditorBrowsable(EditorBrowsableState.Never)]
261 public static ViewStyle GetStyle(Type viewType)
263 if (viewType == null) throw new ArgumentNullException("Invalid viewType");
265 if (!ThemeApplied) return null;
267 return (CurrentTheme.GetStyle(viewType) ?? DefaultTheme.GetStyle(viewType))?.Clone();
271 /// Get a cloned built-in theme.
273 /// <param name="themeId">The built-in theme id.</param>
274 /// <exception cref="ArgumentNullException">Thrown when the given themeId is null.</exception>
275 [EditorBrowsable(EditorBrowsableState.Never)]
276 public static Theme GetBuiltinTheme(string themeId)
278 if (themeId == null) throw new ArgumentNullException("Invalid themeId");
281 int index = builtinThemes.FindIndex(x => string.Equals(x.Id, themeId, StringComparison.OrdinalIgnoreCase));
284 result = builtinThemes[index];
288 var theme = LoadBuiltinTheme(themeId);
289 builtinThemes.Add(theme);
292 return (Theme)result?.Clone();
295 private static Theme LoadBuiltinTheme(string id)
297 var loaded = new Theme()
302 if (string.IsNullOrEmpty(id)) return loaded;
304 foreach (var project in nuiThemeProjects)
306 string path = StyleManager.FrameworkResourcePath + "/Theme/" + project + "_" + id + ".xaml";
312 Tizen.Log.Info("NUI", $"Done to load \"{path}\".\n");
316 Tizen.Log.Debug("NUI", $"Could not load \"{path}\"\n");
317 Tizen.Log.Debug("NUI", "Message: " + e + "\n");
324 private static void NotifyThemeChanged()
326 ThemeChangedInternal?.Invoke(null, new ThemeChangedEventArgs(CurrentTheme?.Id));
327 ThemeChanged?.Invoke(null, new ThemeChangedEventArgs(CurrentTheme?.Id));