X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2FTizen.NUI%2Fsrc%2Fpublic%2FBaseComponents%2FStyle%2FSelector.cs;h=34c44a695e540bfcbc0c49dd2fd89ad84403ce4b;hb=7d2c1760de4801232d369153d56b8621d1038011;hp=bd2096b29d726dd02523913c86d02c53ec76f456;hpb=b3bdb643ced035e56c022ecfe4399bf352375323;p=platform%2Fcore%2Fcsapi%2Ftizenfx.git diff --git a/src/Tizen.NUI/src/public/BaseComponents/Style/Selector.cs b/src/Tizen.NUI/src/public/BaseComponents/Style/Selector.cs index bd2096b..34c44a6 100755 --- a/src/Tizen.NUI/src/public/BaseComponents/Style/Selector.cs +++ b/src/Tizen.NUI/src/public/BaseComponents/Style/Selector.cs @@ -1,5 +1,5 @@ /* - * Copyright(c) 2019 Samsung Electronics Co., Ltd. + * Copyright(c) 2021 Samsung Electronics Co., Ltd. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,27 +14,62 @@ * limitations under the License. * */ +using System; +using System.Collections.Generic; using System.ComponentModel; using Tizen.NUI.Binding; -using Tizen.NUI.Components; namespace Tizen.NUI.BaseComponents { /// /// Selector class, which is related by Control State, it is base class for other Selector. /// + /// The property type of the selector. if it's reference type, it should be of type that implement deep copy in . /// 6 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] - public class Selector : BindableObject + public class Selector { + private readonly bool cloneable = typeof(ICloneable).IsAssignableFrom(typeof(T)); + + /// + /// The list for adding . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + List> SelectorItems { get; set; } = new List>(); + + /// + /// Adds the specified state and value to the . + /// + /// The state. + /// The value associated with state. + [EditorBrowsable(EditorBrowsableState.Never)] + public void Add(ControlState state, T value) + { + SelectorItems.Add(new SelectorItem(state, value)); + All = default; + } + + /// + /// Adds the specified state and value to the . + /// + /// The selector item class that stores a state-value pair. + [EditorBrowsable(EditorBrowsableState.Never)] + public void Add(SelectorItem selectorItem) + { + // To prevent a state from having multiple values, remove existing state-value pair. + int index = SelectorItems.FindIndex(x => x.State == selectorItem.State); + if (index != -1) + SelectorItems.RemoveAt(index); + + SelectorItems.Add(selectorItem); + } + /// 6 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. public static implicit operator Selector(T value) { - Selector selector = new Selector(); - selector.All = value; - return selector; + return new Selector(value); } /// Default Contructor @@ -47,7 +82,14 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public Selector(T value) : this() { - All = value; + All = cloneable ? (T)((ICloneable)value)?.Clone() : value; + } + + /// Copy constructor + [EditorBrowsable(EditorBrowsableState.Never)] + public Selector(Selector value) : this() + { + Clone(value); } /// @@ -69,8 +111,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Normal { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Normal).Value; + set => Add(ControlState.Normal, value); } /// /// Pressed State. @@ -80,8 +122,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Pressed { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Pressed).Value; + set => Add(ControlState.Pressed, value); } /// /// Focused State. @@ -91,8 +133,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Focused { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Focused).Value; + set => Add(ControlState.Focused, value); } /// /// Selected State. @@ -102,8 +144,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Selected { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Selected).Value; + set => Add(ControlState.Selected, value); } /// /// Disabled State. @@ -113,8 +155,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Disabled { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Disabled).Value; + set => Add(ControlState.Disabled, value); } /// /// DisabledFocused State. @@ -124,8 +166,8 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T DisabledFocused { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.DisabledFocused).Value; + set => Add(ControlState.DisabledFocused, value); } /// /// SelectedFocused State. @@ -134,8 +176,8 @@ namespace Tizen.NUI.BaseComponents /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. public T SelectedFocused { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.SelectedFocused).Value; + set => Add(ControlState.SelectedFocused, value); } /// /// DisabledSelected State. @@ -145,9 +187,10 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T DisabledSelected { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.DisabledSelected).Value; + set => Add(ControlState.DisabledSelected, value); } + /// /// Other State. /// @@ -156,238 +199,353 @@ namespace Tizen.NUI.BaseComponents [EditorBrowsable(EditorBrowsableState.Never)] public T Other { - get; - set; + get => SelectorItems.Find(x => x.State == ControlState.Other).Value; + set => Add(ControlState.Other, value); } + + /// + /// Gets the number of elements. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public int Count => SelectorItems.Count; + /// /// Get value by State. /// + /// Thrown when state is null. /// 6 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. + /// True if the selector has a given state value, false otherwise. [EditorBrowsable(EditorBrowsableState.Never)] - public T GetValue(ControlStates state) + public bool GetValue(ControlState state, out T result) { - if(All != null) + if (All != null) + { + result = All; + + return true; + } + + if (state == null) + throw new ArgumentNullException(nameof(state)); + + result = default; + + int index = SelectorItems.FindIndex(x => x.State == state); + if (index >= 0) + { + result = SelectorItems[index].Value; + return true; + } + + if (null == state) + { + throw new ArgumentNullException(nameof(state)); + } + if (state.IsCombined) { - return All; + index = SelectorItems.FindIndex(x => state.Contains(x.State)); + if (index >= 0) + { + result = SelectorItems[index].Value; + return true; + } } - switch(state) + + index = SelectorItems.FindIndex(x => x.State == ControlState.Other); + if (index >= 0) { - case ControlStates.Normal: - return Normal != null? Normal : Other; - case ControlStates.Focused: - return Focused != null? Focused : Other; - case ControlStates.Pressed: - return Pressed != null? Pressed : Other; - case ControlStates.Disabled: - return Disabled != null? Disabled : Other; - case ControlStates.Selected: - return Selected != null? Selected : Other; - case ControlStates.DisabledFocused: - return DisabledFocused != null? DisabledFocused : Other; - case ControlStates.DisabledSelected: - return DisabledSelected != null? DisabledSelected : Other; - case ControlStates.SelectedFocused: - return SelectedFocused != null ? SelectedFocused : Other; - default: - return Other; + result = SelectorItems[index].Value; + return true; } + + return false; } + /// - /// Clone function. + /// Removes all elements. /// - /// 6 - /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] - public void Clone(Selector selector) + public void Clear() { - All = selector.All; - Normal = selector.Normal; - Focused = selector.Focused; - Pressed = selector.Pressed; - Disabled = selector.Disabled; - Selected = selector.Selected; - DisabledSelected = selector.DisabledSelected; - DisabledFocused = selector.DisabledFocused; - SelectedFocused = selector.SelectedFocused; - Other = selector.Other; + All = default; + SelectorItems.Clear(); } - internal void Clone(Selector other) where U : T, Tizen.NUI.Internal.ICloneable + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() { - // TODO Apply constraint to the Selector (not to Clone method) - - All = (T)(other.All)?.Clone(); - Normal = (T)(other.Normal)?.Clone(); - Focused = (T)(other.Focused)?.Clone(); - Pressed = (T)(other.Pressed)?.Clone(); - Disabled = (T)(other.Disabled)?.Clone(); - Selected = (T)(other.Selected)?.Clone(); - DisabledSelected = (T)(other.DisabledSelected)?.Clone(); - DisabledFocused = (T)(other.DisabledFocused)?.Clone(); - SelectedFocused = (T)(other.SelectedFocused)?.Clone(); - Other = (T)(other.Other)?.Clone(); - } - } + string result = $"[All, {All}]"; - /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. - [EditorBrowsable(EditorBrowsableState.Never)] - public class TriggerableSelector : Selector - { - public TriggerableSelector(View view, BindableProperty bindableProperty) - { - targetView = view; - targetBindableProperty = bindableProperty; - view.ControlStateChangeEvent += OnViewControlState; + foreach (var item in SelectorItems) + { + result += $", {item}"; + } + + return result; } /// - /// Clone function. + /// Clone itself. + /// If type T implements ICloneable, it calls Clone() method to clone values, otherwise use operator=. /// /// 6 /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API. [EditorBrowsable(EditorBrowsableState.Never)] - public new void Clone(Selector selector) + public Selector Clone() { - base.Clone(selector); + var cloned = new Selector(); + cloned.Clone(this); + return cloned; + } - if (null != targetView && null != GetValue(targetView.ControlState)) - { - targetView.SetValue(targetBindableProperty, GetValue(targetView.ControlState)); - } + /// + /// Clone with type converter. + /// + /// Thrown when converter is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public Selector Clone(Converter converter) + { + if (converter == null) throw new ArgumentNullException(nameof(converter)); + + Selector result = new Selector(); + result.All = converter(All); + result.SelectorItems = SelectorItems.ConvertAll>(m => new SelectorItem(m.State, converter(m.Value))); + + return result; } - private void OnViewControlState(View obj, ControlStates state) + /// + /// Copy values from other selector. + /// + /// Thrown when other is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void Clone(Selector other) { - if (null != obj && null != GetValue(state)) + if (null == other) + { + throw new ArgumentNullException(nameof(other)); + } + + if (cloneable) + { + All = (T)((ICloneable)other.All)?.Clone(); + SelectorItems = other.SelectorItems.ConvertAll(m => new SelectorItem(m.State, (T)((ICloneable)m.Value)?.Clone())); + } + else { - obj.SetValue(targetBindableProperty, GetValue(state)); + All = other.All; + SelectorItems = other.SelectorItems.ConvertAll(m => m); } } - private View targetView; - private BindableProperty targetBindableProperty; + internal bool HasMultiValue() + { + return SelectorItems.Count > 1; + } } /// - /// A class that helps binding a non-selector property in View to selector property in ViewStyle. + /// This will be attached to a View to detect ControlState change. /// - internal class ViewSelector where T : class, Tizen.NUI.Internal.ICloneable + [EditorBrowsable(EditorBrowsableState.Never)] + public class TriggerableSelector { + /// + /// Create an TriggerableSelector. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public delegate T ValueGetter(View view); + + private readonly BindableProperty targetBindableProperty; + private readonly ValueGetter propertyGetter; + private bool dirty = true; private Selector selector; - private View view; - private View.ControlStateChangesDelegate controlStateChanged; - internal ViewSelector(View view, View.ControlStateChangesDelegate controlStateChanged) + /// + /// Create an TriggerableSelector. + /// + /// The TriggerableSelector will change this bindable property value when the view's ControlState has changed. + /// It is optional value in case the target bindable property getter is not proper to use. + [EditorBrowsable(EditorBrowsableState.Never)] + public TriggerableSelector(BindableProperty targetBindableProperty, ValueGetter propertyGetter = null) { - if (view == null || controlStateChanged == null) - { - throw new global::System.ArgumentNullException(); - } - this.view = view; - this.controlStateChanged = controlStateChanged; - this.selector = null; + this.targetBindableProperty = targetBindableProperty; + this.propertyGetter = propertyGetter; } - internal T GetValue() + /// + /// Return the containing selector. It can be null. + /// + /// Thrown when view is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public Selector Get(View view) { - return selector == null ? null : selector.GetValue(view.ControlState); + if (!dirty) return selector; + if (null == view) + { + throw new ArgumentNullException(nameof(view)); + } + + T value = default; + + if (propertyGetter != null) + { + value = propertyGetter(view); + } + else + { + value = (T)view.GetValue(targetBindableProperty); + } + + Selector converted = value == null ? null : new Selector(value); + Update(view, converted); + + return selector; } - internal void Clone(object value) + /// + /// Update containing selector from the other selector. + /// + /// The View that is affected by this TriggerableSelector. + /// The copy target. + /// Whether it updates the target view after update the selector or not. + /// Thrown when view is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public void Update(View view, Selector otherSelector, bool updateView = false) { - bool hadMultiValue = HasMultiValue(); - var type = value?.GetType(); + Reset(view); - if (type == typeof(T)) + if (null == view) { - selector = new Selector(); - selector.All = (T)((T)value).Clone(); + throw new ArgumentNullException(nameof(view)); } - else if (type == typeof(Selector)) + + if (otherSelector == null) { - selector = new Selector(); - selector.Clone((Selector)value); + return; } - else + + selector = otherSelector.Clone(); + + if (otherSelector.HasMultiValue()) { - selector = null; + view.ControlStateChangeEventInternal += OnViewControlState; } - if (hadMultiValue != HasMultiValue()) + if (updateView && otherSelector.GetValue(view.ControlState, out var value)) { - if (hadMultiValue) view.ControlStateChangeEvent -= controlStateChanged; - else view.ControlStateChangeEvent += controlStateChanged; + view.SetValue(targetBindableProperty, value); } } - internal void Clear() + /// + /// Update containing selector value from a single value. + /// Note that, it updates lazily if possible. + /// If you need to udpate directly, please use . + /// + /// The View that is affected by this TriggerableSelector. + /// The copy target. + [EditorBrowsable(EditorBrowsableState.Never)] + public void UpdateIfNeeds(View view, T value) { - if (HasMultiValue()) + if (selector != null && selector.HasMultiValue()) { - view.ControlStateChangeEvent -= controlStateChanged; + Selector converted = value == null ? null : new Selector(value); + Update(view, converted); + return; } - selector = null; + + dirty = true; } - internal bool IsEmpty() + /// + /// Reset selector and listeners. + /// + /// The View that is affected by this TriggerableSelector. + [EditorBrowsable(EditorBrowsableState.Never)] + public void Reset(View view) { - return selector == null; + if (view != null) + { + view.ControlStateChangeEventInternal -= OnViewControlState; + } + selector?.Clear(); + selector = null; + dirty = false; } - private bool HasMultiValue() + private void OnViewControlState(object obj, View.ControlStateChangedEventArgs controlStateChangedInfo) { - return (selector != null && selector.All == null); + View view = obj as View; + if (null != view && selector.GetValue(controlStateChangedInfo.CurrentState, out var value)) + { + view.SetValue(targetBindableProperty, value); + } } } - internal static class SelectorHelper where T : class, Tizen.NUI.Internal.ICloneable + /// + /// The selector item class that stores a state-value pair. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public class SelectorItem { /// - /// For the object type of T or Selector T, convert it to Selector T and return the cloned one. - /// Otherwise, return null.
+ /// The default constructor. ///
- static internal Selector Clone(object value) - { - var type = value?.GetType(); - - if (type == typeof(Selector)) - { - var result = new Selector(); - result.Clone((Selector)value); - return result; - } - - if (type == typeof(T)) - { - return new Selector((T)((T)value).Clone()); - } + [EditorBrowsable(EditorBrowsableState.Never)] + public SelectorItem() {} - return null; + /// + /// The constructor with the specified state and value. + /// + /// The state + /// The value associated with state. + [EditorBrowsable(EditorBrowsableState.Never)] + public SelectorItem(ControlState state, T value) + { + State = state; + Value = value; } /// - /// For the object type of T or Selector T, convert it to T and return the cloned one. - /// Otherwise, return null.
+ /// The state ///
- static internal T Clone(object value, View view) - { - var type = value?.GetType(); + [EditorBrowsable(EditorBrowsableState.Never)] + public ControlState State { get; set; } - if (type == typeof(T)) - { - return (T)((T)value).Clone(); - } + /// + /// The value associated with state. + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public T Value { get; set; } - if (type == typeof(Selector) && view != null) - { - Selector selector = (Selector)value; - T valueInState = selector.GetValue(view.ControlState); + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public override string ToString() => $"[{State}, {Value}]"; + } - return (T)valueInState?.Clone(); - } + /// + /// Extension class for . + /// + [EditorBrowsable(EditorBrowsableState.Never)] + public static class SelectorExtensions + { + /// + /// Adds the specified state and value to the . + /// + /// The list for adding state-value pair. + /// The state. + /// The value associated with state. + /// Thrown when given list is null. + [EditorBrowsable(EditorBrowsableState.Never)] + public static void Add(this IList> list, ControlState state, T value) + { + if (list == null) throw new ArgumentNullException(nameof(list)); - return null; + list.Add(new SelectorItem(state, value)); } } }