2 * Copyright(c) 2020 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 the view.
28 [EditorBrowsable(EditorBrowsableState.Never)]
29 [Binding.TypeConverter(typeof(ControlStateTypeConverter))]
30 public class ControlState : IEquatable<ControlState>
32 private static readonly Dictionary<string, ControlState> stateDictionary = new Dictionary<string, ControlState>();
37 [EditorBrowsable(EditorBrowsableState.Never)]
38 public static readonly ControlState All = Create("All");
42 [EditorBrowsable(EditorBrowsableState.Never)]
43 public static readonly ControlState Normal = Create("Normal");
47 [EditorBrowsable(EditorBrowsableState.Never)]
48 public static readonly ControlState Focused = Create("Focused");
52 [EditorBrowsable(EditorBrowsableState.Never)]
53 public static readonly ControlState Pressed = Create("Pressed");
57 [EditorBrowsable(EditorBrowsableState.Never)]
58 public static readonly ControlState Disabled = Create("Disabled");
62 [EditorBrowsable(EditorBrowsableState.Never)]
63 public static readonly ControlState Selected = Create("Selected");
65 /// SelectedPressed State.
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 public static readonly ControlState SelectedPressed = Selected + Pressed;
70 /// DisabledSelected State.
72 [EditorBrowsable(EditorBrowsableState.Never)]
73 public static readonly ControlState DisabledSelected = Disabled + Selected;
75 /// DisabledFocused State.
77 [EditorBrowsable(EditorBrowsableState.Never)]
78 public static readonly ControlState DisabledFocused = Disabled + Focused;
80 /// SelectedFocused State.
82 [EditorBrowsable(EditorBrowsableState.Never)]
83 public static readonly ControlState SelectedFocused = Selected + Focused;
87 [EditorBrowsable(EditorBrowsableState.Never)]
88 public static readonly ControlState Other = Create("Other");
90 private List<ControlState> stateList = new List<ControlState>();
91 private readonly string name = "";
94 /// Gets or sets a value indicating whether it has combined states.
96 [EditorBrowsable(EditorBrowsableState.Never)]
97 public bool IsCombined => stateList.Count > 1;
99 private ControlState() { }
101 private ControlState(string name) : this() => this.name = name;
104 /// Create an instance of the <see cref="ControlState"/> with state name.
106 /// <param name="name">The state name.</param>
107 /// <returns>The <see cref="ControlState"/> instance which has single state.</returns>
108 [EditorBrowsable(EditorBrowsableState.Never)]
109 public static ControlState Create(string name)
112 throw new ArgumentNullException(nameof(name));
113 if (string.IsNullOrWhiteSpace(name))
114 throw new ArgumentException("name cannot be empty string", nameof(name));
118 if (stateDictionary.TryGetValue(name, out ControlState state))
121 state = new ControlState(name);
122 state.stateList.Add(state);
123 stateDictionary.Add(name, state);
128 /// Create an instance of the <see cref="ControlState"/> with combined states.
130 /// <param name="states">The control state array.</param>
131 /// <returns>The <see cref="ControlState"/> instance which has combined state.</returns>
132 [EditorBrowsable(EditorBrowsableState.Never)]
133 public static ControlState Create(params ControlState[] states)
135 if (states.Length == 1)
138 ControlState newState = new ControlState();
139 for (int i = 0; i < states.Length; i++)
141 if (states[i] == Normal)
144 if (states[i] == All)
147 newState.stateList.AddRange(states[i].stateList);
150 if (newState.stateList.Count == 0)
153 newState.stateList = newState.stateList.Distinct().ToList();
155 if (newState.stateList.Count == 1)
157 return newState.stateList[0];
164 /// Determines whether a state contains a specified state.
166 /// <param name="state">The state to search for</param>
167 /// <returns>true if the state contain a specified state, otherwise, false.</returns>
168 [EditorBrowsable(EditorBrowsableState.Never)]
169 public bool Contains(ControlState state)
172 throw new ArgumentNullException(nameof(state));
175 return ReferenceEquals(this, state);
178 for (int i = 0; i < state.stateList.Count; i++)
181 for (int j = 0; j < stateList.Count; j++)
183 if (ReferenceEquals(state.stateList[i], stateList[j]))
189 if (!found) return false;
196 [EditorBrowsable(EditorBrowsableState.Never)]
197 public bool Equals(ControlState other)
199 if (other is null || stateList.Count != other.stateList.Count)
202 return Contains(other);
206 [EditorBrowsable(EditorBrowsableState.Never)]
207 public override bool Equals(object obj) => this.Equals(obj as ControlState);
210 [EditorBrowsable(EditorBrowsableState.Never)]
211 public override int GetHashCode() => (name.GetHashCode() * 397) ^ IsCombined.GetHashCode();
214 [EditorBrowsable(EditorBrowsableState.Never)]
215 public override string ToString()
218 for (int i = 0; i < stateList.Count; i++)
220 name += ((i == 0) ? "" : ", ") + stateList[i].name;
226 /// Compares whether the two ControlStates are same or not.
228 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
229 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
230 /// <returns>true if the ControlStates are equal; otherwise, false.</returns>
231 [EditorBrowsable(EditorBrowsableState.Never)]
232 public static bool operator ==(ControlState lhs, ControlState rhs)
234 // Check for null on left side.
239 // null == null = true.
243 // Only the left side is null.
246 // Equals handles case of null on right side.
247 return lhs.Equals(rhs);
251 /// Compares whether the two ControlStates are different or not.
253 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
254 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
255 /// <returns>true if the ControlStates are not equal; otherwise, false.</returns>
256 [EditorBrowsable(EditorBrowsableState.Never)]
257 public static bool operator !=(ControlState lhs, ControlState rhs) => !(lhs == rhs);
260 /// The addition operator.
262 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
263 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
264 /// <returns>The <see cref="ControlState"/> containing the result of the addition.</returns>
265 [EditorBrowsable(EditorBrowsableState.Never)]
266 public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
269 /// The substraction operator.
271 /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
272 /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
273 /// <returns>The <see cref="ControlState"/> containing the result of the substraction.</returns>
274 /// <exception cref="ArgumentNullException"> Thrown when lhs or rhs is null. </exception>
275 [EditorBrowsable(EditorBrowsableState.Never)]
276 public static ControlState operator -(ControlState lhs, ControlState rhs)
280 throw new ArgumentNullException(nameof(lhs));
282 else if (null == rhs)
284 throw new ArgumentNullException(nameof(rhs));
289 return ReferenceEquals(lhs, rhs) ? Normal : lhs;
292 var rest = lhs.stateList.Except(rhs.stateList);
293 var count = rest.Count();
305 ControlState newState = new ControlState();
306 newState.stateList.AddRange(rest);
310 class ControlStateTypeConverter : Binding.TypeConverter
312 public override object ConvertFromInvariantString(string value)
316 value = value.Trim();
318 ControlState convertedState = new ControlState();
319 string[] parts = value.Split(',');
320 foreach (string part in parts)
322 convertedState += Create(part);
324 return convertedState;
327 throw new InvalidOperationException($"Cannot convert \"{value}\" into {typeof(ControlState)}");