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.ComponentModel;
19 using Tizen.NUI.Binding;
20 using Tizen.NUI.Components;
22 namespace Tizen.NUI.BaseComponents
25 /// Selector class, which is related by Control State, it is base class for other Selector.
27 /// <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>
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> : StateValueCollection<T>
33 private readonly bool isCloneable = typeof(ICloneable).IsAssignableFrom(typeof(T));
34 /// <since_tizen> 6 </since_tizen>
35 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
36 public static implicit operator Selector<T>(T value)
38 return new Selector<T>(value);
41 /// Default Contructor
42 [EditorBrowsable(EditorBrowsableState.Never)]
48 [EditorBrowsable(EditorBrowsableState.Never)]
49 public Selector(T value) : this()
51 All = isCloneable ? (T)((ICloneable)value)?.Clone() : value;
55 [EditorBrowsable(EditorBrowsableState.Never)]
56 public Selector(Selector<T> value) : this()
61 internal Selector(SelectorChangedCallback<T> cb) : this()
66 internal Selector(SelectorChangedCallback<T> cb, T value) : this(value)
71 internal Selector(SelectorChangedCallback<T> cb, Selector<T> value) : this(value)
76 internal delegate void SelectorChangedCallback<T>(Selector<T> value);
77 private SelectorChangedCallback<T> callback = null;
82 /// <since_tizen> 6 </since_tizen>
83 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
84 [EditorBrowsable(EditorBrowsableState.Never)]
93 /// <since_tizen> 6 </since_tizen>
94 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
95 [EditorBrowsable(EditorBrowsableState.Never)]
100 return Find(x => x.State == ControlState.Normal).Value;
104 Add(ControlState.Normal, value);
105 callback?.Invoke(this);
111 /// <since_tizen> 6 </since_tizen>
112 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
113 [EditorBrowsable(EditorBrowsableState.Never)]
118 return Find(x => x.State == ControlState.Pressed).Value;
122 Add(ControlState.Pressed, value);
123 callback?.Invoke(this);
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)]
136 return Find(x => x.State == ControlState.Focused).Value;
140 Add(ControlState.Focused, value);
141 callback?.Invoke(this);
147 /// <since_tizen> 6 </since_tizen>
148 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
149 [EditorBrowsable(EditorBrowsableState.Never)]
154 return Find(x => x.State == ControlState.Selected).Value;
158 Add(ControlState.Selected, value);
159 callback?.Invoke(this);
165 /// <since_tizen> 6 </since_tizen>
166 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
167 [EditorBrowsable(EditorBrowsableState.Never)]
172 return Find(x => x.State == ControlState.Disabled).Value;
176 Add(ControlState.Disabled, value);
177 callback?.Invoke(this);
181 /// DisabledFocused State.
183 /// <since_tizen> 6 </since_tizen>
184 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
185 [EditorBrowsable(EditorBrowsableState.Never)]
186 public T DisabledFocused
190 return Find(x => x.State == ControlState.DisabledFocused).Value;
194 Add(ControlState.DisabledFocused, value);
195 callback?.Invoke(this);
199 /// SelectedFocused State.
201 /// <since_tizen> 6 </since_tizen>
202 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
203 public T SelectedFocused
207 return Find(x => x.State == ControlState.SelectedFocused).Value;
211 Add(ControlState.SelectedFocused, value);
212 callback?.Invoke(this);
216 /// DisabledSelected State.
218 /// <since_tizen> 6 </since_tizen>
219 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
220 [EditorBrowsable(EditorBrowsableState.Never)]
221 public T DisabledSelected
225 return Find(x => x.State == ControlState.DisabledSelected).Value;
229 Add(ControlState.DisabledSelected, value);
230 callback?.Invoke(this);
237 /// <since_tizen> 6 </since_tizen>
238 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
239 [EditorBrowsable(EditorBrowsableState.Never)]
244 return Find(x => x.State == ControlState.Other).Value;
248 Add(ControlState.Other, value);
249 callback?.Invoke(this);
253 /// Get value by State.
255 /// <since_tizen> 6 </since_tizen>
256 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
257 /// <returns>True if the selector has a given state value, false otherwise.</returns>
258 [EditorBrowsable(EditorBrowsableState.Never)]
259 public bool GetValue(ControlState state, out T result)
270 int index = StateValueList.FindIndex(x => x.State == state);
273 result = StateValueList[index].Value;
277 if (state.IsCombined)
279 index = StateValueList.FindIndex(x => state.Contains(x.State));
282 result = StateValueList[index].Value;
287 index = StateValueList.FindIndex(x => x.State == ControlState.Other);
290 result = StateValueList[index].Value;
298 [EditorBrowsable(EditorBrowsableState.Never)]
299 public override void Clear()
306 [EditorBrowsable(EditorBrowsableState.Never)]
307 public override string ToString()
309 string result = $"[All, {All}]";
311 foreach (var item in StateValueList)
313 result += $", {item}";
321 /// If type T implements ISelectorItem, it calls Clone() method to clone values, otherwise use operator=.
323 /// <since_tizen> 6 </since_tizen>
324 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
325 [EditorBrowsable(EditorBrowsableState.Never)]
326 public Selector<T> Clone()
328 var cloned = new Selector<T>();
334 /// Copy values from other selector.
336 [EditorBrowsable(EditorBrowsableState.Never)]
337 public void Clone(Selector<T> other)
343 All = (T)((ICloneable)other.All)?.Clone();
344 foreach (var item in other.StateValueList)
346 AddWithoutCheck(new StateValuePair<T>(item.State, (T)((ICloneable)item.Value)?.Clone()));
352 foreach (var item in other.StateValueList)
354 AddWithoutCheck(item);
359 internal bool HasMultiValue()
361 return StateValueList.Count > 1;
366 /// This will be attached to a View to detect ControlState change.
368 [EditorBrowsable(EditorBrowsableState.Never)]
369 public class TriggerableSelector<T>
372 /// Create an TriggerableSelector.
374 [EditorBrowsable(EditorBrowsableState.Never)]
375 public delegate T ValueGetter(View view);
377 private readonly BindableProperty targetBindableProperty;
378 private readonly ValueGetter propertyGetter;
379 private bool dirty = true;
380 private Selector<T> selector;
383 /// Create an TriggerableSelector.
385 /// <param name="targetBindableProperty">The TriggerableSelector will change this bindable property value when the view's ControlState has changed.</param>
386 /// <param name="propertyGetter">It is optional value in case the target bindable property getter is not proper to use.</param>
387 [EditorBrowsable(EditorBrowsableState.Never)]
388 public TriggerableSelector(BindableProperty targetBindableProperty, ValueGetter propertyGetter = null)
390 this.targetBindableProperty = targetBindableProperty;
391 this.propertyGetter = propertyGetter;
395 /// Return the containing selector. It can be null.
397 [EditorBrowsable(EditorBrowsableState.Never)]
398 public Selector<T> Get(View view)
400 if (!dirty) return selector;
404 if (propertyGetter != null)
406 value = propertyGetter(view);
410 value = (T)view.GetValue(targetBindableProperty);
413 Selector<T> converted = value == null ? null : new Selector<T>(value);
414 Update(view, converted);
420 /// Update containing selector from the other selector.
422 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
423 /// <param name="otherSelector">The copy target.</param>
424 /// <param name="updateView">Whether it updates the target view after update the selector or not.</param>
425 [EditorBrowsable(EditorBrowsableState.Never)]
426 public void Update(View view, Selector<T> otherSelector, bool updateView = false)
430 if (otherSelector == null)
435 selector = otherSelector.Clone();
437 if (otherSelector.HasMultiValue())
439 view.ControlStateChangeEventInternal += OnViewControlState;
442 if (updateView && otherSelector.GetValue(view.ControlState, out var value))
444 view.SetValue(targetBindableProperty, value);
449 /// Update containing selector value from a single value.
450 /// Note that, it updates lazily if possible.
451 /// If you need to udpate directly, please use <seealso cref="Update" />.
453 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
454 /// <param name="value">The copy target.</param>
455 [EditorBrowsable(EditorBrowsableState.Never)]
456 public void UpdateIfNeeds(View view, T value)
458 if (selector != null && selector.HasMultiValue())
460 Selector<T> converted = value == null ? null : new Selector<T>(value);
461 Update(view, converted);
469 /// Reset selector and listeners.
471 /// <param name="view">The View that is affected by this TriggerableSelector.</param>
472 [EditorBrowsable(EditorBrowsableState.Never)]
473 public void Reset(View view)
475 view.ControlStateChangeEventInternal -= OnViewControlState;
481 private void OnViewControlState(object obj, View.ControlStateChangedEventArgs controlStateChangedInfo)
483 View view = obj as View;
484 if (null != view && selector.GetValue(controlStateChangedInfo.CurrentState, out var value))
486 view.SetValue(targetBindableProperty, value);