2 * Copyright(c) 2020-2021 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.
19 using System.Collections.Generic;
20 using System.ComponentModel;
23 namespace Tizen.NUI.BaseComponents
26 /// Class for describing the states of control.
27 /// If a non-control view class would want to get the control state, please refer <see cref="View.EnableControlState"/>.
29 /// <since_tizen> 9 </since_tizen>
30 [Binding.TypeConverter(typeof(ControlStateTypeConverter))]
31 public class ControlState : IEquatable<ControlState>
33 private static readonly Dictionary<string, ControlState> stateDictionary = new Dictionary<string, ControlState>();
36 /// The All state is used in a selector class. It represents all states, so if this state is defined in a selector, the other states are ignored.
38 /// <since_tizen> 9 </since_tizen>
39 public static readonly ControlState All = Create("All");
43 /// <since_tizen> 9 </since_tizen>
44 public static readonly ControlState Normal = Create("Normal");
48 /// <since_tizen> 9 </since_tizen>
49 public static readonly ControlState Focused = Create("Focused");
53 /// <since_tizen> 9 </since_tizen>
54 public static readonly ControlState Pressed = Create("Pressed");
58 /// <since_tizen> 9 </since_tizen>
59 public static readonly ControlState Disabled = Create("Disabled");
63 /// <since_tizen> 9 </since_tizen>
64 public static readonly ControlState Selected = Create("Selected");
66 /// SelectedPressed State.
68 [EditorBrowsable(EditorBrowsableState.Never)]
69 public static readonly ControlState SelectedPressed = Selected + Pressed;
71 /// DisabledSelected State.
73 [EditorBrowsable(EditorBrowsableState.Never)]
74 public static readonly ControlState DisabledSelected = Disabled + Selected;
76 /// DisabledFocused State.
78 [EditorBrowsable(EditorBrowsableState.Never)]
79 public static readonly ControlState DisabledFocused = Disabled + Focused;
81 /// SelectedFocused State.
83 [EditorBrowsable(EditorBrowsableState.Never)]
84 public static readonly ControlState SelectedFocused = Selected + Focused;
86 /// This is used in a selector class. It represents all other states except for states that are already defined in a selector.
88 /// <since_tizen> 9 </since_tizen>
89 public static readonly ControlState Other = Create("Other");
91 private List<ControlState> stateList = new List<ControlState>();
92 private readonly string name = "";
95 /// Gets or sets a value indicating whether it has combined states.
97 [EditorBrowsable(EditorBrowsableState.Never)]
98 public bool IsCombined => stateList.Count > 1;
100 private ControlState() { }
102 private ControlState(string name) : this() => this.name = name;
105 /// Create an instance of the <see cref="ControlState"/> with state name.
107 /// <param name="name">The state name.</param>
108 /// <returns>The <see cref="ControlState"/> instance which has single state.</returns>
109 /// <exception cref="ArgumentNullException">Thrown when the given name is null.</exception>
110 /// <exception cref="ArgumentException">Thrown when the given name is invalid.</exception>
111 /// <since_tizen> 9 </since_tizen>
112 public static ControlState Create(string name)
115 throw new ArgumentNullException(nameof(name));
116 if (string.IsNullOrWhiteSpace(name))
117 throw new ArgumentException("name cannot be empty string", nameof(name));
121 if (stateDictionary.TryGetValue(name, out ControlState state))
124 state = new ControlState(name);
125 state.stateList.Add(state);
126 stateDictionary.Add(name, state);
131 /// Create an instance of the <see cref="ControlState"/> with combined states.
133 /// <param name="states">The control state array.</param>
134 /// <returns>The <see cref="ControlState"/> instance which has combined state.</returns>
135 [EditorBrowsable(EditorBrowsableState.Never)]
136 public static ControlState Create(params ControlState[] states)
138 if (states.Length == 1)
141 ControlState newState = new ControlState();
142 for (int i = 0; i < states.Length; i++)
144 if (states[i] == Normal)
147 if (states[i] == All)
150 newState.stateList.AddRange(states[i].stateList);
153 if (newState.stateList.Count == 0)
156 newState.stateList = newState.stateList.Distinct().ToList();
158 if (newState.stateList.Count == 1)
160 return newState.stateList[0];
167 /// Determines whether a state contains a specified state.
169 /// <param name="state">The state to search for</param>
170 /// <returns>true if the state contain a specified state, otherwise, false.</returns>
171 /// <exception cref="ArgumentNullException">Thrown when the given state is null.</exception>
172 /// <since_tizen> 9 </since_tizen>
173 public bool Contains(ControlState state)
176 throw new ArgumentNullException(nameof(state));
179 return ReferenceEquals(this, state);
182 for (int i = 0; i < state.stateList.Count; i++)
185 for (int j = 0; j < stateList.Count; j++)
187 if (ReferenceEquals(state.stateList[i], stateList[j]))
193 if (!found) return false;
200 [EditorBrowsable(EditorBrowsableState.Never)]
201 public bool Equals(ControlState other)
203 if (other is null || stateList.Count != other.stateList.Count)
206 return Contains(other);
210 /// <since_tizen> 9 </since_tizen>
211 public override bool Equals(object other) => this.Equals(other as ControlState);
214 [EditorBrowsable(EditorBrowsableState.Never)]
215 public override int GetHashCode() => (name.GetHashCode() * 397) ^ IsCombined.GetHashCode();
218 [EditorBrowsable(EditorBrowsableState.Never)]
219 public override string ToString()
222 for (int i = 0; i < stateList.Count; i++)
224 name += ((i == 0) ? "" : ", ") + stateList[i].name;
230 /// Compares whether the two ControlStates are same or not.
232 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
233 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
234 /// <returns>true if the ControlStates are equal; otherwise, false.</returns>
235 /// <since_tizen> 9 </since_tizen>
236 public static bool operator ==(ControlState lhs, ControlState rhs)
238 // Check for null on left side.
243 // null == null = true.
247 // Only the left side is null.
250 // Equals handles case of null on right side.
251 return lhs.Equals(rhs);
255 /// Compares whether the two ControlStates are different or not.
257 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
258 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
259 /// <returns>true if the ControlStates are not equal; otherwise, false.</returns>
260 /// <since_tizen> 9 </since_tizen>
261 public static bool operator !=(ControlState lhs, ControlState rhs) => !(lhs == rhs);
264 /// The addition operator.
266 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
267 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
268 /// <returns>The <see cref="ControlState"/> containing the result of the addition.</returns>
269 /// <since_tizen> 9 </since_tizen>
270 public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
273 /// The substraction operator.
275 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
276 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
277 /// <returns>The <see cref="ControlState"/> containing the result of the substraction.</returns>
278 /// <exception cref="ArgumentNullException"> Thrown when lhs or rhs is null. </exception>
279 [EditorBrowsable(EditorBrowsableState.Never)]
280 public static ControlState operator -(ControlState lhs, ControlState rhs)
284 throw new ArgumentNullException(nameof(lhs));
286 else if (null == rhs)
288 throw new ArgumentNullException(nameof(rhs));
293 return ReferenceEquals(lhs, rhs) ? Normal : lhs;
296 var rest = lhs.stateList.Except(rhs.stateList);
297 var count = rest.Count();
309 ControlState newState = new ControlState();
310 newState.stateList.AddRange(rest);
314 class ControlStateTypeConverter : Binding.TypeConverter
316 public override object ConvertFromInvariantString(string value)
320 value = value.Trim();
322 ControlState convertedState = new ControlState();
323 string[] parts = value.Split(',');
324 foreach (string part in parts)
326 convertedState += Create(part);
328 return convertedState;
331 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(ControlState)}");