[NUI] Enable selectors work in View : EnableControlState (#1851)
[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) => lhs.Equals(rhs);
230
231         /// <summary>
232         /// Compares whether the two ControlStates are different or not.
233         /// </summary>
234         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
235         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
236         /// <returns>true if the ControlStates are not equal; otherwise, false.</returns>
237         [EditorBrowsable(EditorBrowsableState.Never)]
238         public static bool operator !=(ControlState lhs, ControlState rhs) => !lhs.Equals(rhs);
239
240         /// <summary>
241         /// The addition operator.
242         /// </summary>
243         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
244         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
245         /// <returns>The <see cref="ControlState"/> containing the result of the addition.</returns>
246         [EditorBrowsable(EditorBrowsableState.Never)]
247         public static ControlState operator +(ControlState lhs, ControlState rhs) => Create(lhs, rhs);
248
249         /// <summary>
250         /// The substraction operator.
251         /// </summary>
252         /// <param name="lhs">A <see cref="ControlState"/> on the left hand side.</param>
253         /// <param name="rhs">A <see cref="ControlState"/> on the right hand side.</param>
254         /// <returns>The <see cref="ControlState"/> containing the result of the substraction.</returns>
255         [EditorBrowsable(EditorBrowsableState.Never)]
256         public static ControlState operator -(ControlState lhs, ControlState rhs)
257         {
258             if (!lhs.IsCombined)
259             {
260                 return ReferenceEquals(lhs, rhs) ? Normal : lhs;
261             }
262             
263             var rest = lhs.stateList.Except(rhs.stateList);
264
265             if (rest.Count() == 0)
266             {
267                 return Normal;
268             }
269
270             if (rest.Count() == 1)
271             {
272                 return rest.First();
273             }
274
275             ControlState newState = new ControlState();
276             newState.stateList.AddRange(rest);
277             return newState;
278         }
279     }
280
281     /// <summary>
282     /// The Key/Value pair structure. this is mutable to support for xaml.
283     /// </summary>
284     [EditorBrowsable(EditorBrowsableState.Never)]
285     public struct StateValuePair<T> : IEquatable<StateValuePair<T>>
286     {
287         /// <summary>
288         /// The constructor with the specified state and value.
289         /// </summary>
290         /// <param name="state">The state</param>
291         /// <param name="value">The value associated with state.</param>
292         [EditorBrowsable(EditorBrowsableState.Never)]
293         public StateValuePair(ControlState state, T value)
294         {
295             State = state;
296             Value = value;
297         }
298
299         /// <summary>
300         /// The state
301         /// </summary>
302         [EditorBrowsable(EditorBrowsableState.Never)]
303         public ControlState State { get; set; }
304         /// <summary>
305         /// The value associated with state.
306         /// </summary>
307         [EditorBrowsable(EditorBrowsableState.Never)]
308         public T Value { get; set; }
309
310         ///  <inheritdoc/>
311         [EditorBrowsable(EditorBrowsableState.Never)]
312         public bool Equals(StateValuePair<T> other) => (Value.Equals(other.Value)) && (State == other.State);
313
314         ///  <inheritdoc/>
315         [EditorBrowsable(EditorBrowsableState.Never)]
316         public override bool Equals(object obj)
317         {
318             if (!(obj is StateValuePair<T>))
319                 return false;
320
321             return Equals((StateValuePair<T>)obj);
322         }
323
324         ///  <inheritdoc/>
325         [EditorBrowsable(EditorBrowsableState.Never)]
326         public override int GetHashCode() => (State.GetHashCode() * 397) ^ Value.GetHashCode();
327
328
329         /// <summary>
330         /// Compares whether the two StateValuePair are different or not.
331         /// </summary>
332         /// <param name="lhs">A <see cref="StateValuePair{T}"/> on the left hand side.</param>
333         /// <param name="rhs">A <see cref="StateValuePair{T}"/> on the right hand side.</param>
334         /// <returns>true if the StateValuePair are equal; otherwise, false.</returns>
335         [EditorBrowsable(EditorBrowsableState.Never)]
336         public static bool operator ==(StateValuePair<T> lhs, StateValuePair<T> rhs) => lhs.Equals(rhs);
337
338         /// <summary>
339         /// Compares whether the two StateValuePair are same or not.
340         /// </summary>
341         /// <param name="lhs">A <see cref="StateValuePair{T}"/> on the left hand side.</param>
342         /// <param name="rhs">A <see cref="StateValuePair{T}"/> on the right hand side.</param>
343         /// <returns>true if the StateValuePair are not equal; otherwise, false.</returns>
344         [EditorBrowsable(EditorBrowsableState.Never)]
345         public static bool operator !=(StateValuePair<T> lhs, StateValuePair<T> rhs) => !(lhs == rhs);
346
347         ///  <inheritdoc/>
348         [EditorBrowsable(EditorBrowsableState.Never)]
349         public override string ToString() => $"[{State}, {Value}]";
350     }
351 }