[NUI] remove input method dependency from View.ControlState (#1585)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI / src / public / BaseComponents / Style / Selector.cs
1 /*
2  * Copyright(c) 2019 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 using System;
18 using System.ComponentModel;
19 using Tizen.NUI.Binding;
20 using Tizen.NUI.Components;
21
22 namespace Tizen.NUI.BaseComponents
23 {
24     /// <summary>
25     /// Selector class, which is related by Control State, it is base class for other Selector.
26     /// </summary>
27     /// <since_tizen> 6 </since_tizen>
28     /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
29     [EditorBrowsable(EditorBrowsableState.Never)]
30     public class Selector<T> : BindableObject
31     {
32         /// <since_tizen> 6 </since_tizen>
33         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
34         public static implicit operator Selector<T>(T value)
35         {
36             Selector<T> selector = new Selector<T>();
37             selector.All = value;
38             return selector;
39         }
40
41         /// Default Contructor
42         [EditorBrowsable(EditorBrowsableState.Never)]
43         public Selector()
44         {
45         }
46
47         /// Contructor with T
48         [EditorBrowsable(EditorBrowsableState.Never)]
49         public Selector(T value) : this()
50         {
51             All = value;
52         }
53
54         /// <summary>
55         /// All State.
56         /// </summary>
57         /// <since_tizen> 6 </since_tizen>
58         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
59         [EditorBrowsable(EditorBrowsableState.Never)]
60         public T All
61         {
62             get;
63             set;
64         }
65         /// <summary>
66         /// Normal State.
67         /// </summary>
68         /// <since_tizen> 6 </since_tizen>
69         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
70         [EditorBrowsable(EditorBrowsableState.Never)]
71         public T Normal
72         {
73             get;
74             set;
75         }
76         /// <summary>
77         /// Pressed State.
78         /// </summary>
79         /// <since_tizen> 6 </since_tizen>
80         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         public T Pressed
83         {
84             get;
85             set;
86         }
87         /// <summary>
88         /// Focused State.
89         /// </summary>
90         /// <since_tizen> 6 </since_tizen>
91         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
92         [EditorBrowsable(EditorBrowsableState.Never)]
93         public T Focused
94         {
95             get;
96             set;
97         }
98         /// <summary>
99         /// Selected State.
100         /// </summary>
101         /// <since_tizen> 6 </since_tizen>
102         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
103         [EditorBrowsable(EditorBrowsableState.Never)]
104         public T Selected
105         {
106             get;
107             set;
108         }
109         /// <summary>
110         /// Disabled State.
111         /// </summary>
112         /// <since_tizen> 6 </since_tizen>
113         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
114         [EditorBrowsable(EditorBrowsableState.Never)]
115         public T Disabled
116         {
117             get;
118             set;
119         }
120         /// <summary>
121         /// DisabledFocused State.
122         /// </summary>
123         /// <since_tizen> 6 </since_tizen>
124         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
125         [EditorBrowsable(EditorBrowsableState.Never)]
126         public T DisabledFocused
127         {
128             get;
129             set;
130         }
131         /// <summary>
132         /// SelectedFocused State.
133         /// </summary>
134         /// <since_tizen> 6 </since_tizen>
135         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
136         public T SelectedFocused
137         {
138             get;
139             set;
140         }
141         /// <summary>
142         /// DisabledSelected State.
143         /// </summary>
144         /// <since_tizen> 6 </since_tizen>
145         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
146         [EditorBrowsable(EditorBrowsableState.Never)]
147         public T DisabledSelected
148         {
149             get;
150             set;
151         }
152
153         /// <summary>
154         /// Other State.
155         /// </summary>
156         /// <since_tizen> 6 </since_tizen>
157         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
158         [EditorBrowsable(EditorBrowsableState.Never)]
159         public T Other
160         {
161             get;
162             set;
163         }
164         /// <summary>
165         /// Get value by State.
166         /// </summary>
167         /// <since_tizen> 6 </since_tizen>
168         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
169         [EditorBrowsable(EditorBrowsableState.Never)]
170         public T GetValue(ControlStates state)
171         {
172             if(All != null)
173             {
174                 return All;
175             }
176             switch(state)
177             {
178                 case ControlStates.Normal:
179                     return Normal != null? Normal : Other;
180                 case ControlStates.Focused:
181                     return Focused != null? Focused : Other;
182                 case ControlStates.Pressed:
183                     return Pressed != null? Pressed : Other;
184                 case ControlStates.Disabled:
185                     return Disabled != null? Disabled : Other;
186                 case ControlStates.Selected:
187                     return Selected != null? Selected : Other;
188                 case ControlStates.DisabledFocused:
189                     return DisabledFocused != null? DisabledFocused : (Disabled != null ? Disabled : Other);
190                 case ControlStates.DisabledSelected:
191                     return DisabledSelected != null ? DisabledSelected : (Disabled != null ? Disabled : Other);
192                 case ControlStates.SelectedFocused:
193                     return SelectedFocused != null ? SelectedFocused : (Selected != null ? Selected : Other);
194                 default:
195                 {
196                     // TODO Handle combined states
197                     return Other;
198                 }
199             }
200         }
201         /// <summary>
202         /// Clone function.
203         /// </summary>
204         /// <since_tizen> 6 </since_tizen>
205         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
206         [EditorBrowsable(EditorBrowsableState.Never)]
207         public void Clone(Selector<T> selector)
208         {
209             All = selector.All;
210             Normal = selector.Normal;
211             Focused = selector.Focused;
212             Pressed = selector.Pressed;
213             Disabled = selector.Disabled;
214             Selected = selector.Selected;
215             DisabledSelected = selector.DisabledSelected;
216             DisabledFocused = selector.DisabledFocused;
217             SelectedFocused = selector.SelectedFocused;
218             Other = selector.Other;
219         }
220
221         internal void Clone<U>(Selector<U> other) where U : T, Tizen.NUI.Internal.ICloneable
222         {
223             // TODO Apply constraint to the Selector (not to Clone method)
224
225             All = (T)(other.All)?.Clone();
226             Normal = (T)(other.Normal)?.Clone();
227             Focused = (T)(other.Focused)?.Clone();
228             Pressed = (T)(other.Pressed)?.Clone();
229             Disabled = (T)(other.Disabled)?.Clone();
230             Selected = (T)(other.Selected)?.Clone();
231             DisabledSelected = (T)(other.DisabledSelected)?.Clone();
232             DisabledFocused = (T)(other.DisabledFocused)?.Clone();
233             SelectedFocused = (T)(other.SelectedFocused)?.Clone();
234             Other = (T)(other.Other)?.Clone();
235         }
236
237         internal bool HasMultiValue()
238         {
239             return All == null;
240         }
241     }
242
243     /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
244     [EditorBrowsable(EditorBrowsableState.Never)]
245     public class TriggerableSelector<T> : Selector<T>
246     {
247         public TriggerableSelector(View view, BindableProperty bindableProperty)
248         {
249             targetView = view;
250             targetBindableProperty = bindableProperty;
251             view.ControlStateChangeEventInternal += OnViewControlState;
252         }
253
254         /// <summary>
255         /// Clone function.
256         /// </summary>
257         /// <since_tizen> 6 </since_tizen>
258         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
259         [EditorBrowsable(EditorBrowsableState.Never)]
260         public new void Clone(Selector<T> selector)
261         {
262             base.Clone(selector);
263
264             if (null != targetView && null != GetValue(targetView.ControlState))
265             {
266                 targetView.SetValue(targetBindableProperty, GetValue(targetView.ControlState));
267             }
268         }
269
270         private void OnViewControlState(object obj, View.ControlStateChangedEventArgs controlStateChangedInfo)
271         {
272             View view = obj as View;
273             if (null != view && null != GetValue(controlStateChangedInfo.CurrentState))
274             {
275                 view.SetValue(targetBindableProperty, GetValue(controlStateChangedInfo.CurrentState));
276             }
277         }
278
279         private View targetView;
280         private BindableProperty targetBindableProperty;
281     }
282
283     /// <summary>
284     /// A class that helps binding a non-selector property in View to selector property in ViewStyle.
285     /// </summary>
286     internal class ViewSelector<T>
287     {
288         protected Selector<T> selector;
289         protected View view;
290         protected EventHandler<View.ControlStateChangedEventArgs> controlStateChanged;
291
292         internal ViewSelector(View view, EventHandler<View.ControlStateChangedEventArgs> controlStateChanged)
293         {
294             if (view == null || controlStateChanged == null)
295             {
296                 throw new global::System.ArgumentNullException();
297             }
298             this.view = view;
299             this.controlStateChanged = controlStateChanged;
300             this.selector = null;
301         }
302
303         internal T GetValue()
304         {
305             return selector == null ? default(T) : selector.GetValue(view.ControlState);
306         }
307
308         internal void Set(object value)
309         {
310             bool hadMultiValue = HasMultiValue();
311             var type = value?.GetType();
312
313             if (type == typeof(T))
314             {
315                 CopyValueToSelector((T)value);
316             }
317             else if (type == typeof(Selector<T>))
318             {
319                 CopySelectorToSelector((Selector<T>)value);
320             }
321             else if (type == Nullable.GetUnderlyingType(typeof(T)))
322             {
323                 CopyValueToSelector((T)value);
324             }
325             else
326             {
327                 selector = null;
328             }
329
330             if (hadMultiValue != HasMultiValue())
331             {
332                 if (hadMultiValue) view.ControlStateChangeEventInternal -= controlStateChanged;
333                 else view.ControlStateChangeEventInternal += controlStateChanged;
334             }
335         }
336
337         protected virtual void CopyValueToSelector(T value)
338         {
339             selector = new Selector<T>();
340             selector.All = value;
341         }
342
343         protected virtual void CopySelectorToSelector(Selector<T> value)
344         {
345             selector = new Selector<T>();
346             selector.Clone(value);
347         }
348
349         internal void Clear()
350         {
351             if (HasMultiValue())
352             {
353                 view.ControlStateChangeEventInternal -= controlStateChanged;
354             }
355             selector = null;
356         }
357
358         internal bool IsEmpty()
359         {
360             return selector == null;
361         }
362
363         protected bool HasMultiValue()
364         {
365             return (selector != null && selector.All == null);
366         }
367     }
368
369     /// <summary>
370     /// ViewSelector class for ICloneable type
371     /// </summary>
372     internal class CloneableViewSelector<T> : ViewSelector<T> where T : Tizen.NUI.Internal.ICloneable
373     {
374         internal CloneableViewSelector(View view, EventHandler<View.ControlStateChangedEventArgs> controlStateChanged) : base(view, controlStateChanged)
375         {
376         }
377
378         protected override void CopyValueToSelector(T value)
379         {
380             selector = new Selector<T>();
381             selector.All = (T)((T)value).Clone();
382         }
383
384         protected override void CopySelectorToSelector(Selector<T> value)
385         {
386             selector = new Selector<T>();
387             selector.Clone<T>((Selector<T>)value);
388         }
389     }
390
391     internal static class SelectorHelper
392     {
393         /// <summary>
394         /// For the object type of T or Selector T, convert it to Selector T and return the cloned one.
395         /// Otherwise, return null. <br/>
396         /// </summary>
397         static internal Selector<T> CopyCloneable<T>(object value) where T : class, Tizen.NUI.Internal.ICloneable
398         {
399             var type = value?.GetType();
400
401             if (type == typeof(Selector<T>))
402             {
403                 var result = new Selector<T>();
404                 result.Clone<T>((Selector<T>)value);
405                 return result;
406             }
407
408             if (type == typeof(T))
409             {
410                 return new Selector<T>((T)((T)value).Clone());
411             }
412
413             return null;
414         }
415
416         /// <summary>
417         /// For the value type of T or Selector T, convert it to Selector T and return the cloned one.
418         /// Otherwise, return null. <br/>
419         /// </summary>
420         static internal Selector<T> CopyValue<T>(object value)
421         {
422             var type = value?.GetType();
423
424             if (type == typeof(Selector<T>))
425             {
426                 var result = new Selector<T>();
427                 result.Clone((Selector<T>)value);
428                 return result;
429             }
430
431             if (type == typeof(T))
432             {
433                 return new Selector<T>((T)value);
434             }
435
436             return null;
437         }
438     }
439 }