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 /// <since_tizen> 6 </since_tizen>
29 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
30 [EditorBrowsable(EditorBrowsableState.Never)]
31 public class Selector<T>
33 private readonly bool cloneable = typeof(T).IsAssignableFrom(typeof(ICloneable));
36 /// The list for adding state-value pair.
38 [EditorBrowsable(EditorBrowsableState.Never)]
39 public IList<StateValuePair<T>> StateValueList { get; private set; } = new List<StateValuePair<T>>();
42 /// Adds the specified state and value to the <see cref="StateValueList"/>.
44 /// <param name="state">The state.</param>
45 /// <param name="value">The value associated with state.</param>
46 [EditorBrowsable(EditorBrowsableState.Never)]
47 public void Add(ControlState state, T value) => StateValueList.Add(new StateValuePair<T>(state, value));
50 /// Adds the specified state and value to the <see cref="StateValueList"/>.
52 /// <param name="stateValuePair"></param>
53 [EditorBrowsable(EditorBrowsableState.Never)]
54 public void Add(StateValuePair<T> stateValuePair) => StateValueList.Add(stateValuePair);
56 /// <since_tizen> 6 </since_tizen>
57 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
58 public static implicit operator Selector<T>(T value)
60 return new Selector<T>(value);
63 /// Default Contructor
64 [EditorBrowsable(EditorBrowsableState.Never)]
70 [EditorBrowsable(EditorBrowsableState.Never)]
71 public Selector(T value) : this()
73 All = cloneable ? (T)((ICloneable)value)?.Clone() : value;
77 [EditorBrowsable(EditorBrowsableState.Never)]
78 public Selector(Selector<T> value) : this()
87 /// <since_tizen> 6 </since_tizen>
88 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
89 [EditorBrowsable(EditorBrowsableState.Never)]
98 /// <since_tizen> 6 </since_tizen>
99 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
100 [EditorBrowsable(EditorBrowsableState.Never)]
103 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Normal).Value;
104 set => Add(ControlState.Normal, value);
109 /// <since_tizen> 6 </since_tizen>
110 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
111 [EditorBrowsable(EditorBrowsableState.Never)]
115 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Pressed).Value;
116 set => Add(ControlState.Pressed, value);
121 /// <since_tizen> 6 </since_tizen>
122 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
123 [EditorBrowsable(EditorBrowsableState.Never)]
126 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Focused).Value;
127 set => Add(ControlState.Focused, value);
132 /// <since_tizen> 6 </since_tizen>
133 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
134 [EditorBrowsable(EditorBrowsableState.Never)]
137 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Selected).Value;
138 set => Add(ControlState.Selected, value);
143 /// <since_tizen> 6 </since_tizen>
144 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
145 [EditorBrowsable(EditorBrowsableState.Never)]
149 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Disabled).Value;
150 set => Add(ControlState.Disabled, value);
153 /// DisabledFocused State.
155 /// <since_tizen> 6 </since_tizen>
156 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
157 [EditorBrowsable(EditorBrowsableState.Never)]
158 public T DisabledFocused
160 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.DisabledFocused).Value;
161 set => Add(ControlState.DisabledFocused, value);
164 /// SelectedFocused State.
166 /// <since_tizen> 6 </since_tizen>
167 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
168 public T SelectedFocused
170 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.SelectedFocused).Value;
171 set => Add(ControlState.SelectedFocused, value);
174 /// DisabledSelected State.
176 /// <since_tizen> 6 </since_tizen>
177 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
178 [EditorBrowsable(EditorBrowsableState.Never)]
179 public T DisabledSelected
182 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.DisabledSelected).Value;
183 set => Add(ControlState.DisabledSelected, value);
189 /// <since_tizen> 6 </since_tizen>
190 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
191 [EditorBrowsable(EditorBrowsableState.Never)]
194 get => ((List<StateValuePair<T>>)StateValueList).FindLast(x => x.State == ControlState.Other).Value;
195 set => Add(ControlState.Other, value);
198 /// Get value by State.
200 /// <since_tizen> 6 </since_tizen>
201 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
202 /// <returns>True if the selector has a given state value, false otherwise.</returns>
203 [EditorBrowsable(EditorBrowsableState.Never)]
204 public bool GetValue(ControlState state, out T result)
215 int index = ((List<StateValuePair<T>>)StateValueList).FindLastIndex(x => x.State == state);
218 result = StateValueList[index].Value;
222 if (state.IsCombined)
224 index = ((List<StateValuePair<T>>)StateValueList).FindLastIndex(x => state.Contains(x.State));
227 result = StateValueList[index].Value;
232 index = ((List<StateValuePair<T>>)StateValueList).FindLastIndex(x => x.State == ControlState.Other);
235 result = StateValueList[index].Value;
243 /// Removes all elements from <see cref="StateValueList"./>
245 [EditorBrowsable(EditorBrowsableState.Never)]
249 StateValueList.Clear();
253 [EditorBrowsable(EditorBrowsableState.Never)]
254 public override string ToString()
256 string result = $"[All, {All}]";
258 foreach (var item in StateValueList)
260 result += $", {item}";
268 /// If type T implements ICloneable, it calls Clone() method to clone values, otherwise use operator=.
270 /// <since_tizen> 6 </since_tizen>
271 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
272 [EditorBrowsable(EditorBrowsableState.Never)]
273 public Selector<T> Clone()
275 var cloned = new Selector<T>();
281 /// Copy values from other selector.
283 [EditorBrowsable(EditorBrowsableState.Never)]
284 public void Clone(Selector<T> other)
288 All = (T)((ICloneable)other.All)?.Clone();
289 StateValueList = ((List<StateValuePair<T>>)other.StateValueList).ConvertAll(m => new StateValuePair<T>(m.State, (T)((ICloneable)m.Value)?.Clone()));
294 StateValueList = ((List<StateValuePair<T>>)other.StateValueList).ConvertAll(m => m);
298 internal bool HasMultiValue()
300 return StateValueList.Count > 1;
305 /// This will be attached to a View to detect ControlState change.
307 [EditorBrowsable(EditorBrowsableState.Never)]
308 public class TriggerableSelector<T>
311 /// Create an TriggerableSelector.
313 [EditorBrowsable(EditorBrowsableState.Never)]
314 public delegate T ValueGetter(View view);
316 private readonly BindableProperty targetBindableProperty;
317 private readonly ValueGetter propertyGetter;
318 private bool dirty = true;
319 private Selector<T> selector;
322 /// Create an TriggerableSelector.
324 /// <param name="targetBindableProperty">The TriggerableSelector will change this bindable property value when the view's ControlState has changed.</param>
325 /// <param name="propertyGetter">It is optional value in case the target bindable property getter is not proper to use.</param>
326 [EditorBrowsable(EditorBrowsableState.Never)]
327 public TriggerableSelector(BindableProperty targetBindableProperty, ValueGetter propertyGetter = null)
329 this.targetBindableProperty = targetBindableProperty;
330 this.propertyGetter = propertyGetter;
334 /// Return the containing selector. It can be null.
336 [EditorBrowsable(EditorBrowsableState.Never)]
337 public Selector<T> Get(View view)
339 if (!dirty) return selector;
343 if (propertyGetter != null)
345 value = propertyGetter(view);
349 value = (T)view.GetValue(targetBindableProperty);
352 Selector<T> converted = value == null ? null : new Selector<T>(value);
353 Update(view, converted);
359 /// Update containing selector from the other selector.
361 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
362 /// <param name="otherSelector">The copy target.</param>
363 /// <param name="updateView">Whether it updates the target view after update the selector or not.</param>
364 [EditorBrowsable(EditorBrowsableState.Never)]
365 public void Update(View view, Selector<T> otherSelector, bool updateView = false)
369 if (otherSelector == null)
374 selector = otherSelector.Clone();
376 if (otherSelector.HasMultiValue())
378 view.ControlStateChangeEventInternal += OnViewControlState;
381 if (updateView && otherSelector.GetValue(view.ControlState, out var value))
383 view.SetValue(targetBindableProperty, value);
388 /// Update containing selector value from a single value.
389 /// Note that, it updates lazily if possible.
390 /// If you need to udpate directly, please use <seealso cref="Update" />.
392 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
393 /// <param name="value">The copy target.</param>
394 [EditorBrowsable(EditorBrowsableState.Never)]
395 public void UpdateIfNeeds(View view, T value)
397 if (selector != null && selector.HasMultiValue())
399 Selector<T> converted = value == null ? null : new Selector<T>(value);
400 Update(view, converted);
408 /// Reset selector and listeners.
410 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
411 [EditorBrowsable(EditorBrowsableState.Never)]
412 public void Reset(View view)
414 view.ControlStateChangeEventInternal -= OnViewControlState;
420 private void OnViewControlState(object obj, View.ControlStateChangedEventArgs controlStateChangedInfo)
422 View view = obj as View;
423 if (null != view && selector.GetValue(controlStateChangedInfo.CurrentState, out var value))
425 view.SetValue(targetBindableProperty, value);
431 /// Extension class for <see cref="Selector{T}"/>.
433 [EditorBrowsable(EditorBrowsableState.Never)]
434 public static class SelectorExtensions
437 /// Adds the specified state and value to the <see cref="Selector{T}.StateValueList"/>.
439 /// <param name="list">The list for adding state-value pair.</param>
440 /// <param name="state">The state.</param>
441 /// <param name="value">The value associated with state.</param>
442 [EditorBrowsable(EditorBrowsableState.Never)]
443 public static void Add<T>(this IList<StateValuePair<T>> list, ControlState state, T value)
445 list.Add(new StateValuePair<T>(state, value));