2 * Copyright(c) 2019 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.Generic;
19 using System.ComponentModel;
20 using Tizen.NUI.Binding;
21 using Tizen.NUI.Components;
23 namespace Tizen.NUI.BaseComponents
26 /// Selector class, which is related by Control State, it is base class for other Selector.
28 /// <typeparam name="T">The property type of the selector. if it's reference type, it should be of type <see cref="ICloneable"/> that implement deep copy in <see cref="ICloneable.Clone"/>.</typeparam>
29 /// <since_tizen> 6 </since_tizen>
30 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
31 [EditorBrowsable(EditorBrowsableState.Never)]
32 public class Selector<T>
34 private readonly bool cloneable = typeof(ICloneable).IsAssignableFrom(typeof(T));
37 /// The list for adding state-value pair.
39 [EditorBrowsable(EditorBrowsableState.Never)]
40 public IList<StateValuePair<T>> StateValueList { get; set; } = new List<StateValuePair<T>>();
43 /// Adds the specified state and value.
45 /// <param name="state">The state.</param>
46 /// <param name="value">The value associated with state.</param>
47 [EditorBrowsable(EditorBrowsableState.Never)]
48 public void Add(ControlState state, T value) => Add(new StateValuePair<T>(state, value));
51 /// Adds the specified state and value.
53 /// <param name="stateValuePair"></param>
54 [EditorBrowsable(EditorBrowsableState.Never)]
55 public void Add(StateValuePair<T> stateValuePair)
57 // To prevent a state from having multiple values, remove existing state-value pair.
58 int index = ((List<StateValuePair<T>>)StateValueList).FindIndex(x => x.State == stateValuePair.State);
60 StateValueList.RemoveAt(index);
62 StateValueList.Add(stateValuePair);
65 /// <since_tizen> 6 </since_tizen>
66 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
67 public static implicit operator Selector<T>(T value)
69 return new Selector<T>(value);
72 /// Default Contructor
73 [EditorBrowsable(EditorBrowsableState.Never)]
79 [EditorBrowsable(EditorBrowsableState.Never)]
80 public Selector(T value) : this()
82 All = cloneable ? (T)((ICloneable)value)?.Clone() : value;
86 [EditorBrowsable(EditorBrowsableState.Never)]
87 public Selector(Selector<T> value) : this()
95 /// <since_tizen> 6 </since_tizen>
96 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
97 [EditorBrowsable(EditorBrowsableState.Never)]
106 /// <since_tizen> 6 </since_tizen>
107 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
108 [EditorBrowsable(EditorBrowsableState.Never)]
111 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Normal).Value;
112 set => Add(ControlState.Normal, value);
117 /// <since_tizen> 6 </since_tizen>
118 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
119 [EditorBrowsable(EditorBrowsableState.Never)]
123 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Pressed).Value;
124 set => Add(ControlState.Pressed, value);
129 /// <since_tizen> 6 </since_tizen>
130 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
131 [EditorBrowsable(EditorBrowsableState.Never)]
134 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Focused).Value;
135 set => Add(ControlState.Focused, value);
140 /// <since_tizen> 6 </since_tizen>
141 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
142 [EditorBrowsable(EditorBrowsableState.Never)]
145 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Selected).Value;
146 set => Add(ControlState.Selected, value);
151 /// <since_tizen> 6 </since_tizen>
152 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
153 [EditorBrowsable(EditorBrowsableState.Never)]
157 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Disabled).Value;
158 set => Add(ControlState.Disabled, value);
161 /// DisabledFocused State.
163 /// <since_tizen> 6 </since_tizen>
164 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
165 [EditorBrowsable(EditorBrowsableState.Never)]
166 public T DisabledFocused
168 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.DisabledFocused).Value;
169 set => Add(ControlState.DisabledFocused, value);
172 /// SelectedFocused State.
174 /// <since_tizen> 6 </since_tizen>
175 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
176 public T SelectedFocused
178 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.SelectedFocused).Value;
179 set => Add(ControlState.SelectedFocused, value);
182 /// DisabledSelected State.
184 /// <since_tizen> 6 </since_tizen>
185 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
186 [EditorBrowsable(EditorBrowsableState.Never)]
187 public T DisabledSelected
190 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.DisabledSelected).Value;
191 set => Add(ControlState.DisabledSelected, value);
197 /// <since_tizen> 6 </since_tizen>
198 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
199 [EditorBrowsable(EditorBrowsableState.Never)]
202 get => ((List<StateValuePair<T>>)StateValueList).Find(x => x.State == ControlState.Other).Value;
203 set => Add(ControlState.Other, value);
207 /// Gets the number of elements.
209 [EditorBrowsable(EditorBrowsableState.Never)]
210 public int Count => StateValueList.Count;
213 /// Get value by State.
215 /// <since_tizen> 6 </since_tizen>
216 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
217 /// <returns>True if the selector has a given state value, false otherwise.</returns>
218 [EditorBrowsable(EditorBrowsableState.Never)]
219 public bool GetValue(ControlState state, out T result)
230 int index = ((List<StateValuePair<T>>)StateValueList).FindIndex(x => x.State == state);
233 result = StateValueList[index].Value;
237 if (state.IsCombined)
239 index = ((List<StateValuePair<T>>)StateValueList).FindIndex(x => state.Contains(x.State));
242 result = StateValueList[index].Value;
247 index = ((List<StateValuePair<T>>)StateValueList).FindIndex(x => x.State == ControlState.Other);
250 result = StateValueList[index].Value;
258 /// Removes all elements.
260 [EditorBrowsable(EditorBrowsableState.Never)]
264 StateValueList.Clear();
268 [EditorBrowsable(EditorBrowsableState.Never)]
269 public override string ToString()
271 string result = $"[All, {All}]";
273 foreach (var item in StateValueList)
275 result += $", {item}";
283 /// If type T implements ICloneable, it calls Clone() method to clone values, otherwise use operator=.
285 /// <since_tizen> 6 </since_tizen>
286 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public Selector<T> Clone()
290 var cloned = new Selector<T>();
296 /// Copy values from other selector.
298 [EditorBrowsable(EditorBrowsableState.Never)]
299 public void Clone(Selector<T> other)
303 All = (T)((ICloneable)other.All)?.Clone();
304 StateValueList = ((List<StateValuePair<T>>)other.StateValueList).ConvertAll(m => new StateValuePair<T>(m.State, (T)((ICloneable)m.Value)?.Clone()));
309 StateValueList = ((List<StateValuePair<T>>)other.StateValueList).ConvertAll(m => m);
313 internal bool HasMultiValue()
315 return StateValueList.Count > 1;
321 /// This will be attached to a View to detect ControlState change.
323 [EditorBrowsable(EditorBrowsableState.Never)]
324 public class TriggerableSelector<T>
327 /// Create an TriggerableSelector.
329 [EditorBrowsable(EditorBrowsableState.Never)]
330 public delegate T ValueGetter(View view);
332 private readonly BindableProperty targetBindableProperty;
333 private readonly ValueGetter propertyGetter;
334 private bool dirty = true;
335 private Selector<T> selector;
338 /// Create an TriggerableSelector.
340 /// <param name="targetBindableProperty">The TriggerableSelector will change this bindable property value when the view's ControlState has changed.</param>
341 /// <param name="propertyGetter">It is optional value in case the target bindable property getter is not proper to use.</param>
342 [EditorBrowsable(EditorBrowsableState.Never)]
343 public TriggerableSelector(BindableProperty targetBindableProperty, ValueGetter propertyGetter = null)
345 this.targetBindableProperty = targetBindableProperty;
346 this.propertyGetter = propertyGetter;
350 /// Return the containing selector. It can be null.
352 [EditorBrowsable(EditorBrowsableState.Never)]
353 public Selector<T> Get(View view)
355 if (!dirty) return selector;
359 if (propertyGetter != null)
361 value = propertyGetter(view);
365 value = (T)view.GetValue(targetBindableProperty);
368 Selector<T> converted = value == null ? null : new Selector<T>(value);
369 Update(view, converted);
375 /// Update containing selector from the other selector.
377 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
378 /// <param name="otherSelector">The copy target.</param>
379 /// <param name="updateView">Whether it updates the target view after update the selector or not.</param>
380 [EditorBrowsable(EditorBrowsableState.Never)]
381 public void Update(View view, Selector<T> otherSelector, bool updateView = false)
385 if (otherSelector == null)
390 selector = otherSelector.Clone();
392 if (otherSelector.HasMultiValue())
394 view.ControlStateChangeEventInternal += OnViewControlState;
397 if (updateView && otherSelector.GetValue(view.ControlState, out var value))
399 view.SetValue(targetBindableProperty, value);
404 /// Update containing selector value from a single value.
405 /// Note that, it updates lazily if possible.
406 /// If you need to udpate directly, please use <seealso cref="Update" />.
408 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
409 /// <param name="value">The copy target.</param>
410 [EditorBrowsable(EditorBrowsableState.Never)]
411 public void UpdateIfNeeds(View view, T value)
413 if (selector != null && selector.HasMultiValue())
415 Selector<T> converted = value == null ? null : new Selector<T>(value);
416 Update(view, converted);
424 /// Reset selector and listeners.
426 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
427 [EditorBrowsable(EditorBrowsableState.Never)]
428 public void Reset(View view)
430 view.ControlStateChangeEventInternal -= OnViewControlState;
436 private void OnViewControlState(object obj, View.ControlStateChangedEventArgs controlStateChangedInfo)
438 View view = obj as View;
439 if (null != view && selector.GetValue(controlStateChangedInfo.CurrentState, out var value))
441 view.SetValue(targetBindableProperty, value);