Follow formatting NUI
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / ControlState.cs
1 /*
2  * Copyright(c) 2020 Samsung Electronics Co., Ltd.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  *
16  */
17
18 using System;
19 using System.Collections.Generic;
20 using System.ComponentModel;
21 using System.Linq;
22
23 namespace Tizen.NUI.BaseComponents
24 {
25     /// <summary>
26     /// Class for describing the states of the view.
27     /// </summary>
28     [EditorBrowsable(EditorBrowsableState.Never)]
29     public class ControlState : IEquatable<ControlState>
30     {
31         private static readonly Dictionary<string, ControlState> stateDictionary = new Dictionary<string, ControlState>();
32         //Default States
33         /// <summary>
34         /// All State.
35         /// </summary>
36         [EditorBrowsable(EditorBrowsableState.Never)]
37         public static readonly ControlState All = Create("All");
38         /// <summary>
39         /// Normal State.
40         /// </summary>
41         [EditorBrowsable(EditorBrowsableState.Never)]
42         public static readonly ControlState Normal = Create("Normal");
43         /// <summary>
44         /// Focused State.
45         /// </summary>
46         [EditorBrowsable(EditorBrowsableState.Never)]
47         public static readonly ControlState Focused = Create("Focused");
48         /// <summary>
49         /// Pressed State.
50         /// </summary>
51         [EditorBrowsable(EditorBrowsableState.Never)]
52         public static readonly ControlState Pressed = Create("Pressed");
53         /// <summary>
54         /// Disabled State.
55         /// </summary>
56         [EditorBrowsable(EditorBrowsableState.Never)]
57         public static readonly ControlState Disabled = Create("Disabled");
58         /// <summary>
59         /// Selected State.
60         /// </summary>
61         [EditorBrowsable(EditorBrowsableState.Never)]
62         public static readonly ControlState Selected = Create("Selected");
63         /// <summary>
64         /// DisabledSelected State.
65         /// </summary>
66         [EditorBrowsable(EditorBrowsableState.Never)]
67         public static readonly ControlState DisabledSelected = Disabled + Selected;
68         /// <summary>
69         /// DisabledFocused State.
70         /// </summary>
71         [EditorBrowsable(EditorBrowsableState.Never)]
72         public static readonly ControlState DisabledFocused = Disabled + Focused;
73         /// <summary>
74         /// SelectedFocused State.
75         /// </summary>
76         [EditorBrowsable(EditorBrowsableState.Never)]
77         public static readonly ControlState SelectedFocused = Selected + Focused;
78         /// <summary>
79         /// Other State.
80         /// </summary>
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         public static readonly ControlState Other = Create("Other");
83
84         private List<ControlState> stateList = new List<ControlState>();
85         private readonly string name = "";
86
87         /// <summary>
88         /// Gets or sets a value indicating whether it has combined states.
89         /// </summary>
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         public bool IsCombined => stateList.Count > 1;
92
93         /// <summary>
94         /// Default Contructor. Please use <see cref="Create(string)"/> or <see cref="Create(ControlState[])"/> instead.
95         /// </summary>
96         // Do not open this constructor. This is only for xaml support.
97         [EditorBrowsable(EditorBrowsableState.Never)]
98         public ControlState() { }
99
100         private ControlState(string name) : this() => this.name = name;
101
102         /// <summary>
103         /// Create an instance of the <see cref="ControlState"/> with state name.
104         /// </summary>
105         /// <param name="name">The state name.</param>
106         /// <returns>The <see cref="ControlState"/> instance which has single state.</returns>
107         [EditorBrowsable(EditorBrowsableState.Never)]
108         public static ControlState Create(string name)
109         {
110             if (name == null)
111                 throw new ArgumentNullException(nameof(name));
112             if (string.IsNullOrWhiteSpace(name))
113                 throw new ArgumentException("name cannot be empty string", nameof(name));
114
115             if (stateDictionary.TryGetValue(name, out ControlState state))
116                 return state;
117
118             state = new ControlState(name);
119             state.stateList.Add(state);
120             stateDictionary.Add(name, state);
121             return state;
122         }
123
124         /// <summary>
125         /// Create an instance of the <see cref="ControlState"/> with combined states.
126         /// </summary>
127         /// <param name="states">The control state array.</param>
128         /// <returns>The <see cref="ControlState"/> instance which has combined state.</returns>
129         [EditorBrowsable(EditorBrowsableState.Never)]
130         public static ControlState Create(params ControlState[] states)
131         {
132             if (states.Length == 1)
133                 return states[0];
134
135             ControlState newState = new ControlState();
136             for (int i = 0; i < states.Length; i++)
137             {
138                 if (states[i] == Normal)
139                     continue;
140
141                 if (states[i] == All)
142                     return All;
143
144                 newState.stateList.AddRange(states[i].stateList);
145             }
146
147             if (newState.stateList.Count == 0)
148                 return Normal;
149
150             newState.stateList = newState.stateList.Distinct().ToList();
151
152             if (newState.stateList.Count == 1)
153             {
154                 return newState.stateList[0];
155             }
156
157             return newState;
158         }
159
160         /// <summary>
161         /// Determines whether a state contains a specified state.
162         /// </summary>
163         /// <param name="state">The state to search for</param>
164         /// <returns>true if the state contain a specified state, otherwise, false.</returns>
165         [EditorBrowsable(EditorBrowsableState.Never)]
166         public bool Contains(ControlState state)
167         {
168             if (state == null)
169                 throw new ArgumentNullException(nameof(state));
170
171             if (!IsCombined)
172                 return ReferenceEquals(this, state);
173
174             bool found;
175             for (int i = 0; i < state.stateList.Count; i++)
176             {
177                 found = false;
178                 for (int j = 0; j < stateList.Count; j++)
179                 {
180                     if (ReferenceEquals(state.stateList[i], stateList[j]))
181                     {
182                         found = true;
183                         break;
184                     }
185                 }
186                 if (!found) return false;
187             }
188
189             return true;
190         }
191
192         ///  <inheritdoc/>
193         [EditorBrowsable(EditorBrowsableState.Never)]
194         public bool Equals(ControlState other)
195         {
196             if (other is null || stateList.Count != other.stateList.Count)
197                 return false;
198
199             return Contains(other);
200         }
201
202         ///  <inheritdoc/>
203         [EditorBrowsable(EditorBrowsableState.Never)]
204         public override bool Equals(object obj) => this.Equals(obj as ControlState);
205
206         ///  <inheritdoc/>
207         [EditorBrowsable(EditorBrowsableState.Never)]
208         public override int GetHashCode() => (name.GetHashCode() * 397) ^ IsCombined.GetHashCode();
209
210         ///  <inheritdoc/>
211         [EditorBrowsable(EditorBrowsableState.Never)]
212         public override string ToString()
213         {
214             string name = "";
215             for (int i = 0; i < stateList.Count; i++)
216             {
217                 name += ((i == 0) ? "" : ", ") + stateList[i].name;
218             }
219             return name;
220         }
221
222         /// <summary>
223         /// Compares whether the two ControlStates are same or not.
224         /// </summary>
225         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
226         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
227         /// <returns>true if the ControlStates are equal; otherwise, false.</returns>
228         [EditorBrowsable(EditorBrowsableState.Never)]
229         public static bool operator ==(ControlState lhs, ControlState rhs)
230         {
231             // Check for null on left side.
232             if (lhs is null)
233             {
234                 if (rhs is null)
235                 {
236                     // null == null = true.
237                     return true;
238                 }
239
240                 // Only the left side is null.
241                 return false;
242             }
243             // Equals handles case of null on right side.
244             return lhs.Equals(rhs);
245         }
246
247         /// <summary>
248         /// Compares whether the two ControlStates are different or not.
249         /// </summary>
250         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
251         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
252         /// <returns>true if the ControlStates are not equal; otherwise, false.</returns>
253         [EditorBrowsable(EditorBrowsableState.Never)]
254         public static bool operator !=(ControlState lhs, ControlState rhs) => !(lhs == rhs);
255
256         /// <summary>
257         /// The addition operator.
258         /// </summary>
259         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
260         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
261         /// <returns>The <see cref="ControlState"/> containing the result of the addition.</returns>
262         [EditorBrowsable(EditorBrowsableState.Never)]
263         public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
264
265         /// <summary>
266         /// The substraction operator.
267         /// </summary>
268         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
269         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
270         /// <returns>The <see cref="ControlState"/> containing the result of the substraction.</returns>
271         [EditorBrowsable(EditorBrowsableState.Never)]
272         public static ControlState operator -(ControlState lhs, ControlState rhs)
273         {
274             if (!lhs.IsCombined)
275             {
276                 return ReferenceEquals(lhs, rhs) ? Normal : lhs;
277             }
278
279             var rest = lhs.stateList.Except(rhs.stateList);
280
281             if (rest.Count() == 0)
282             {
283                 return Normal;
284             }
285
286             if (rest.Count() == 1)
287             {
288                 return rest.First();
289             }
290
291             ControlState newState = new ControlState();
292             newState.stateList.AddRange(rest);
293             return newState;
294         }
295     }
296
297     /// <summary>
298     /// The Key/Value pair structure. this is mutable to support for xaml.
299     /// </summary>
300     [EditorBrowsable(EditorBrowsableState.Never)]
301     public struct StateValuePair<T> : IEquatable<StateValuePair<T>>
302     {
303         /// <summary>
304         /// The constructor with the specified state and value.
305         /// </summary>
306         /// <param name="state">The state</param>
307         /// <param name="value">The value associated with state.</param>
308         [EditorBrowsable(EditorBrowsableState.Never)]
309         public StateValuePair(ControlState state, T value)
310         {
311             State = state;
312             Value = value;
313         }
314
315         /// <summary>
316         /// The state
317         /// </summary>
318         [EditorBrowsable(EditorBrowsableState.Never)]
319         public ControlState State { get; set; }
320         /// <summary>
321         /// The value associated with state.
322         /// </summary>
323         [EditorBrowsable(EditorBrowsableState.Never)]
324         public T Value { get; set; }
325
326         ///  <inheritdoc/>
327         [EditorBrowsable(EditorBrowsableState.Never)]
328         public bool Equals(StateValuePair<T> other) => (Value.Equals(other.Value)) && (State == other.State);
329
330         ///  <inheritdoc/>
331         [EditorBrowsable(EditorBrowsableState.Never)]
332         public override bool Equals(object obj)
333         {
334             if (!(obj is StateValuePair<T>))
335                 return false;
336
337             return Equals((StateValuePair<T>)obj);
338         }
339
340         ///  <inheritdoc/>
341         [EditorBrowsable(EditorBrowsableState.Never)]
342         public override int GetHashCode() => (State.GetHashCode() * 397) ^ Value.GetHashCode();
343
344
345         /// <summary>
346         /// Compares whether the two StateValuePair are different or not.
347         /// </summary>
348         /// <param name="lhs">A <see cref="StateValuePair{T}"/> on the left hand side.</param>
349         /// <param name="rhs">A <see cref="StateValuePair{T}"/> on the right hand side.</param>
350         /// <returns>true if the StateValuePair are equal; otherwise, false.</returns>
351         [EditorBrowsable(EditorBrowsableState.Never)]
352         public static bool operator ==(StateValuePair<T> lhs, StateValuePair<T> rhs) => lhs.Equals(rhs);
353
354         /// <summary>
355         /// Compares whether the two StateValuePair are same or not.
356         /// </summary>
357         /// <param name="lhs">A <see cref="StateValuePair{T}"/> on the left hand side.</param>
358         /// <param name="rhs">A <see cref="StateValuePair{T}"/> on the right hand side.</param>
359         /// <returns>true if the StateValuePair are not equal; otherwise, false.</returns>
360         [EditorBrowsable(EditorBrowsableState.Never)]
361         public static bool operator !=(StateValuePair<T> lhs, StateValuePair<T> rhs) => !(lhs == rhs);
362
363         ///  <inheritdoc/>
364         [EditorBrowsable(EditorBrowsableState.Never)]
365         public override string ToString() => $"[{State}, {Value}]";
366     }
367 }