2 using System.Collections;
3 using System.Collections.Generic;
4 using System.Collections.ObjectModel;
7 using Tizen.NUI.Binding;
9 namespace Tizen.NUI.Xaml
11 internal static class VisualStateManager
13 internal class CommonStates
15 public const string Normal = "Normal";
16 public const string Disabled = "Disabled";
17 public const string Focused = "Focused";
20 public static readonly BindableProperty VisualStateGroupsProperty =
21 BindableProperty.CreateAttached("VisualStateGroups", typeof(VisualStateGroupList), typeof(/*VisualElement*/BaseHandle),
22 defaultValue: null, propertyChanged: VisualStateGroupsPropertyChanged,
23 defaultValueCreator: bindable => new VisualStateGroupList());
25 static void VisualStateGroupsPropertyChanged(BindableObject bindable, object oldValue, object newValue)
27 GoToState((/*VisualElement*/BaseHandle)bindable, CommonStates.Normal);
30 public static IList<VisualStateGroup> GetVisualStateGroups(/*VisualElement*/BaseHandle visualElement)
32 return (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
35 public static void SetVisualStateGroups(/*VisualElement*/BaseHandle visualElement, VisualStateGroupList value)
37 visualElement.SetValue(VisualStateGroupsProperty, value);
40 public static bool GoToState(/*VisualElement*/BaseHandle visualElement, string name)
42 if (!visualElement.IsSet(VisualStateGroupsProperty))
47 var groups = (IList<VisualStateGroup>)visualElement.GetValue(VisualStateGroupsProperty);
49 foreach (VisualStateGroup group in groups)
51 if (group.CurrentState?.Name == name)
53 // We're already in the target state; nothing else to do
57 // See if this group contains the new state
58 var target = group.GetState(name);
64 // If we've got a new state to transition to, unapply the setters from the current state
65 if (group.CurrentState != null)
67 foreach (Setter setter in group.CurrentState.Setters)
69 setter.UnApply(visualElement);
73 // Update the current state
74 group.CurrentState = target;
76 // Apply the setters from the new state
77 foreach (Setter setter in target.Setters)
79 setter.Apply(visualElement);
88 public static bool HasVisualStateGroups(this /*VisualElement*/BaseHandle element)
90 return element.IsSet(VisualStateGroupsProperty);
94 internal class VisualStateGroupList : IList<VisualStateGroup>
96 readonly IList<VisualStateGroup> _internalList;
98 void Validate(IList<VisualStateGroup> groups)
100 // If we have 1 group, no need to worry about duplicate group names
101 if (groups.Count > 1)
103 if (groups.GroupBy(vsg => vsg.Name).Any(g => g.Count() > 1))
105 throw new InvalidOperationException("VisualStateGroup Names must be unique");
109 // State names must be unique within this group list, so pull in all
110 // the states in all the groups, group them by name, and see if we have
112 if (groups.SelectMany(group => group.States)
113 .GroupBy(state => state.Name)
114 .Any(g => g.Count() > 1))
116 throw new InvalidOperationException("VisualState Names must be unique");
120 public VisualStateGroupList()
122 _internalList = new WatchAddList<VisualStateGroup>(Validate);
125 void ValidateOnStatesChanged(object sender, EventArgs eventArgs)
127 Validate(_internalList);
130 public IEnumerator<VisualStateGroup> GetEnumerator()
132 return _internalList.GetEnumerator();
135 IEnumerator IEnumerable.GetEnumerator()
137 return ((IEnumerable)_internalList).GetEnumerator();
140 public void Add(VisualStateGroup item)
142 _internalList.Add(item);
143 item.StatesChanged += ValidateOnStatesChanged;
148 foreach (var group in _internalList)
150 group.StatesChanged -= ValidateOnStatesChanged;
153 _internalList.Clear();
156 public bool Contains(VisualStateGroup item)
158 return _internalList.Contains(item);
161 public void CopyTo(VisualStateGroup[] array, int arrayIndex)
163 _internalList.CopyTo(array, arrayIndex);
166 public bool Remove(VisualStateGroup item)
168 item.StatesChanged -= ValidateOnStatesChanged;
169 return _internalList.Remove(item);
172 public int Count => _internalList.Count;
174 public bool IsReadOnly => false;
176 public int IndexOf(VisualStateGroup item)
178 return _internalList.IndexOf(item);
181 public void Insert(int index, VisualStateGroup item)
183 item.StatesChanged += ValidateOnStatesChanged;
184 _internalList.Insert(index, item);
187 public void RemoveAt(int index)
189 _internalList[index].StatesChanged -= ValidateOnStatesChanged;
190 _internalList.RemoveAt(index);
193 public VisualStateGroup this[int index]
195 get => _internalList[index];
196 set => _internalList[index] = value;
200 [RuntimeNameProperty(nameof(Name))]
201 [ContentProperty(nameof(States))]
202 internal sealed class VisualStateGroup
204 public VisualStateGroup()
206 States = new WatchAddList<VisualState>(OnStatesChanged);
209 public Type TargetType { get; set; }
210 public string Name { get; set; }
211 public IList<VisualState> States { get; }
212 public VisualState CurrentState { get; internal set; }
214 internal VisualState GetState(string name)
216 foreach (VisualState state in States)
218 if (string.CompareOrdinal(state.Name, name) == 0)
227 internal VisualStateGroup Clone()
229 var clone = new VisualStateGroup {TargetType = TargetType, Name = Name, CurrentState = CurrentState};
230 foreach (VisualState state in States)
232 clone.States.Add(state.Clone());
238 internal event EventHandler StatesChanged;
240 void OnStatesChanged(IList<VisualState> list)
242 if (list.Any(state => string.IsNullOrEmpty(state.Name)))
244 throw new InvalidOperationException("State names may not be null or empty");
247 StatesChanged?.Invoke(this, EventArgs.Empty);
251 [RuntimeNameProperty(nameof(Name))]
252 internal sealed class VisualState
256 Setters = new ObservableCollection<Setter>();
259 public string Name { get; set; }
260 public IList<Setter> Setters { get;}
261 public Type TargetType { get; set; }
263 internal VisualState Clone()
265 var clone = new VisualState { Name = Name, TargetType = TargetType };
266 foreach (var setter in Setters)
268 clone.Setters.Add(setter);
275 internal static class VisualStateGroupListExtensions
277 internal static IList<VisualStateGroup> Clone(this IList<VisualStateGroup> groups)
279 var actual = new VisualStateGroupList();
280 foreach (var group in groups)
282 actual.Add(group.Clone());
289 internal class WatchAddList<T> : IList<T>
291 readonly Action<List<T>> _onAdd;
292 readonly List<T> _internalList;
294 public WatchAddList(Action<List<T>> onAdd)
297 _internalList = new List<T>();
300 public IEnumerator<T> GetEnumerator()
302 return _internalList.GetEnumerator();
305 IEnumerator IEnumerable.GetEnumerator()
307 return ((IEnumerable)_internalList).GetEnumerator();
310 public void Add(T item)
312 _internalList.Add(item);
313 _onAdd(_internalList);
318 _internalList.Clear();
321 public bool Contains(T item)
323 return _internalList.Contains(item);
326 public void CopyTo(T[] array, int arrayIndex)
328 _internalList.CopyTo(array, arrayIndex);
331 public bool Remove(T item)
333 return _internalList.Remove(item);
336 public int Count => _internalList.Count;
338 public bool IsReadOnly => false;
340 public int IndexOf(T item)
342 return _internalList.IndexOf(item);
345 public void Insert(int index, T item)
347 _internalList.Insert(index, item);
348 _onAdd(_internalList);
351 public void RemoveAt(int index)
353 _internalList.RemoveAt(index);
356 public T this[int index]
358 get => _internalList[index];
359 set => _internalList[index] = value;