[NUI.Components] Fix focus always true issue (#1516)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Control.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.Collections.Generic;
19 using System.ComponentModel;
20 using Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Binding;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// The control component is base class of tv nui components. It's abstract class, so cann't instantiate and can only be inherited.
27     /// </summary>
28     /// <since_tizen> 6 </since_tizen>
29     /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
30     [EditorBrowsable(EditorBrowsableState.Never)]
31     public class Control : VisualView
32     {
33         /// <summary> Control style. </summary>
34         /// <since_tizen> 6 </since_tizen>
35         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
36         [EditorBrowsable(EditorBrowsableState.Never)]
37         protected string style;
38
39         private TapGestureDetector tapGestureDetector = new TapGestureDetector();
40
41         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
42         [EditorBrowsable(EditorBrowsableState.Never)]
43         public ControlStyle Style => ViewStyle as ControlStyle;
44
45         static Control() { }
46
47         /// <summary>
48         /// Construct an empty Control.
49         /// </summary>
50         /// <since_tizen> 6 </since_tizen>
51         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
52         [EditorBrowsable(EditorBrowsableState.Never)]
53         public Control() : base()
54         {
55             ViewStyle viewStyle = StyleManager.Instance.GetComponentStyle(this.GetType());
56
57             if (viewStyle != null)
58             {
59                 ApplyStyle(viewStyle);
60             }
61
62             Initialize(null);
63         }
64
65         /// <summary>
66         /// Construct with style.
67         /// </summary>
68         /// <param name="style">Create control with style.</param>
69         /// <since_tizen> 6 </since_tizen>
70         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
71         [EditorBrowsable(EditorBrowsableState.Never)]
72         public Control(ControlStyle style) : base(style)
73         {
74             Initialize(null);
75         }
76
77         /// <summary>
78         /// Construct with styleSheet
79         /// </summary>
80         /// <param name="styleSheet">StyleSheet to be applied</param>
81         /// <since_tizen> 6 </since_tizen>
82         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
83         [EditorBrowsable(EditorBrowsableState.Never)]
84         public Control(string styleSheet) : base()
85         {
86             ViewStyle viewStyle = StyleManager.Instance.GetViewStyle(styleSheet);
87             if (viewStyle == null)
88             {
89                 throw new InvalidOperationException($"There is no style {styleSheet}");
90             }
91
92             ApplyStyle(viewStyle);
93             this.style = styleSheet;
94
95             Initialize(style);
96         }
97
98         internal void ApplyAttributes(View view, ViewStyle viewStyle)
99         {
100             view.CopyFrom(viewStyle);
101         }
102
103         /// <summary>
104         /// Whether focusable when touch
105         /// </summary>
106         /// <since_tizen> 6 </since_tizen>
107         internal bool StateFocusableOnTouchMode { get; set; }
108
109         internal bool IsFocused { get; set; } = false;
110
111         /// <summary>
112         /// Dispose Control and all children on it.
113         /// </summary>
114         /// <param name="type">Dispose type.</param>
115         /// <since_tizen> 6 </since_tizen>
116         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
117         [EditorBrowsable(EditorBrowsableState.Never)]
118         protected override void Dispose(DisposeTypes type)
119         {
120             if (disposed)
121             {
122                 return;
123             }
124
125             if (type == DisposeTypes.Explicit)
126             {
127                 StyleManager.Instance.ThemeChangedEvent -= OnThemeChangedEvent;
128                 tapGestureDetector.Detected -= OnTapGestureDetected;
129                 tapGestureDetector.Detach(this);
130             }
131
132             base.Dispose(type);
133         }
134
135         /// <summary>
136         /// Called after a key event is received by the view that has had its focus set.
137         /// </summary>
138         /// <param name="key">The key event.</param>
139         /// <returns>True if the key event should be consumed.</returns>
140         /// <since_tizen> 6 </since_tizen>
141         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
142         [EditorBrowsable(EditorBrowsableState.Never)]
143         public override bool OnKey(Key key)
144         {
145             return false;
146         }
147
148         /// <summary>
149         /// Called after the size negotiation has been finished for this control.<br />
150         /// The control is expected to assign this given size to itself or its children.<br />
151         /// Should be overridden by derived classes if they need to layout views differently after certain operations like add or remove views, resize, or after changing specific properties.<br />
152         /// As this function is called from inside the size negotiation algorithm, you cannot call RequestRelayout (the call would just be ignored).<br />
153         /// </summary>
154         /// <param name="size">The allocated size.</param>
155         /// <param name="container">The control should add views to this container that it is not able to allocate a size for.</param>
156         /// <since_tizen> 6 </since_tizen>
157         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
158         [EditorBrowsable(EditorBrowsableState.Never)]
159         public override void OnRelayout(Vector2 size, RelayoutContainer container)
160         {
161             base.OnRelayout(size, container);
162             OnUpdate();
163         }
164
165         /// <summary>
166         /// Called when the control gain key input focus. Should be overridden by derived classes if they need to customize what happens when the focus is gained.
167         /// </summary>
168         /// <since_tizen> 6 </since_tizen>
169         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
170         [EditorBrowsable(EditorBrowsableState.Never)]
171         public override void OnFocusGained()
172         {
173             IsFocused = true;
174         }
175
176         /// <summary>
177         /// Called when the control loses key input focus. Should be overridden by derived classes if they need to customize what happens when the focus is lost.
178         /// </summary>
179         /// <since_tizen> 6 </since_tizen>
180         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
181         [EditorBrowsable(EditorBrowsableState.Never)]
182         public override void OnFocusLost()
183         {
184             IsFocused = false;
185         }
186
187         /// <summary>
188         /// Tap gesture callback.
189         /// </summary>
190         /// <param name="source">The sender</param>
191         /// <param name="e">The tap gesture event data</param>
192         /// <since_tizen> 6 </since_tizen>
193         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
194         [EditorBrowsable(EditorBrowsableState.Never)]
195         protected virtual void OnTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e) { }
196
197         /// <summary>
198         /// Called after a touch event is received by the owning view.<br />
199         /// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).<br />
200         /// </summary>
201         /// <param name="touch">The touch event.</param>
202         /// <returns>True if the event should be consumed.</returns>
203         /// <since_tizen> 6 </since_tizen>
204         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
205         [EditorBrowsable(EditorBrowsableState.Never)]
206         public override bool OnTouch(Touch touch)
207         {
208             // Handle Normal and Pressed states
209             PointStateType state = touch.GetState(0);
210             switch(state)
211             {
212                 case PointStateType.Down:
213                     ControlState = ControlStates.Pressed;
214                     break;
215                 case PointStateType.Interrupted:
216                 case PointStateType.Up:
217                     if (ControlState == ControlStates.Pressed)
218                     {
219                         ControlState = ControlStates.Normal;
220                     }
221                     break;
222                 default:
223                     break;
224             }
225             return false;
226         }
227
228         /// <summary>
229         /// Update by style.
230         /// </summary>
231         /// <since_tizen> 6 </since_tizen>
232         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
233         [EditorBrowsable(EditorBrowsableState.Never)]
234         protected virtual void OnUpdate()
235         {
236         }
237
238         /// <summary>
239         /// Theme change callback when theme is changed, this callback will be trigger.
240         /// </summary>
241         /// <param name="sender">The sender</param>
242         /// <param name="e">The event data</param>
243         /// <since_tizen> 6 </since_tizen>
244         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
245         [EditorBrowsable(EditorBrowsableState.Never)]
246         protected virtual void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e) { }
247
248         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
249         [EditorBrowsable(EditorBrowsableState.Never)]
250         protected virtual void RegisterDetectionOfSubstyleChanges() { }
251
252         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
253         [EditorBrowsable(EditorBrowsableState.Never)]
254         protected override ViewStyle GetViewStyle()
255         {
256             return new ControlStyle();
257         }
258
259         private void Initialize(string style)
260         {
261             ControlState = ControlStates.Normal;
262
263             RegisterDetectionOfSubstyleChanges();
264
265             LeaveRequired = true;
266
267             StateFocusableOnTouchMode = false;
268
269             tapGestureDetector.Attach(this);
270             tapGestureDetector.Detected += OnTapGestureDetected;
271
272             StyleManager.Instance.ThemeChangedEvent += OnThemeChangedEvent;
273         }
274     }
275 }