7fcde28e8cff01018f120c6f7e067c3946de1f6f
[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 using System.Windows.Input;
23
24 namespace Tizen.NUI.Components
25 {
26     /// <summary>
27     /// The control component is base class of tv nui components. It's abstract class, so cann't instantiate and can only be inherited.
28     /// </summary>
29     /// <since_tizen> 6 </since_tizen>
30     /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
31     [EditorBrowsable(EditorBrowsableState.Never)]
32     public class Control : VisualView
33     {
34         /// Internal used.
35         [EditorBrowsable(EditorBrowsableState.Never)]
36         public static readonly BindableProperty CommandProperty = BindableProperty.Create("Command", typeof(ICommand), typeof(Control), null, propertyChanged: (bo, o, n) => ((Control)bo).OnCommandChanged());
37
38         /// Internal used.
39         [EditorBrowsable(EditorBrowsableState.Never)]
40         public static readonly BindableProperty CommandParameterProperty = BindableProperty.Create("CommandParameter", typeof(object), typeof(Button), null,
41             propertyChanged: (bindable, oldvalue, newvalue) => ((Button)bindable).CommandCanExecuteChanged(bindable, EventArgs.Empty));
42
43         /// <summary> Control style. </summary>
44         /// <since_tizen> 6 </since_tizen>
45         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
46         [EditorBrowsable(EditorBrowsableState.Never)]
47         protected string StyleName { get; set; }
48
49         private TapGestureDetector tapGestureDetector = new TapGestureDetector();
50
51         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
52         [EditorBrowsable(EditorBrowsableState.Never)]
53         public ControlStyle Style => ViewStyle as ControlStyle;
54
55         static Control() { }
56
57         /// <summary>
58         /// Construct an empty Control.
59         /// </summary>
60         /// <since_tizen> 6 </since_tizen>
61         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
62         [EditorBrowsable(EditorBrowsableState.Never)]
63         public Control() : base()
64         {
65             var cur_type = this.GetType();
66             ViewStyle viewStyle = null;
67
68             do
69             {
70                 if (cur_type.Equals(typeof(Tizen.NUI.Components.Control))) break;
71                 viewStyle = StyleManager.Instance.GetComponentStyle(cur_type);
72                 cur_type = cur_type.BaseType;
73             }
74             while (viewStyle == null);
75
76             if (viewStyle != null)
77             {
78                 ApplyStyle(viewStyle);
79             }
80
81             Initialize();
82         }
83
84         /// <summary>
85         /// Construct with style.
86         /// </summary>
87         /// <param name="style">Create control with style.</param>
88         /// <since_tizen> 6 </since_tizen>
89         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         public Control(ControlStyle style) : base(style)
92         {
93             Initialize();
94         }
95
96         /// <summary>
97         /// Construct with styleSheet
98         /// </summary>
99         /// <param name="styleSheet">StyleSheet to be applied</param>
100         /// <since_tizen> 6 </since_tizen>
101         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
102         [EditorBrowsable(EditorBrowsableState.Never)]
103         public Control(string styleSheet) : base()
104         {
105             ViewStyle viewStyle = StyleManager.Instance.GetViewStyle(styleSheet);
106             if (viewStyle == null)
107             {
108                 throw new InvalidOperationException($"There is no style {styleSheet}");
109             }
110
111             ApplyStyle(viewStyle);
112             this.StyleName = styleSheet;
113
114             Initialize();
115         }
116
117         /// Internal used.
118         [EditorBrowsable(EditorBrowsableState.Never)]
119         public ICommand Command
120         {
121             get { return (ICommand)GetValue(CommandProperty); }
122             set { SetValue(CommandProperty, value); }
123         }
124
125         /// Internal used.
126         [EditorBrowsable(EditorBrowsableState.Never)]
127         public object CommandParameter
128         {
129             get { return GetValue(CommandParameterProperty); }
130             set { SetValue(CommandParameterProperty, value); }
131         }
132
133         /// <summary>
134         /// Whether focusable when touch
135         /// </summary>
136         /// <since_tizen> 6 </since_tizen>
137         internal bool StateFocusableOnTouchMode { get; set; }
138
139         internal bool IsFocused { get; set; } = false;
140
141         internal void CommandCanExecuteChanged(object sender, EventArgs eventArgs)
142         {
143             ICommand cmd = Command;
144             if (cmd != null)
145                 cmd.CanExecute(CommandParameter);
146         }
147
148         internal void OnCommandChanged()
149         {
150             if (Command != null)
151             {
152                 Command.CanExecuteChanged += CommandCanExecuteChanged;
153                 CommandCanExecuteChanged(this, EventArgs.Empty);
154             }
155         }
156
157         /// <summary>
158         /// Dispose Control and all children on it.
159         /// </summary>
160         /// <param name="type">Dispose type.</param>
161         /// <since_tizen> 6 </since_tizen>
162         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
163         [EditorBrowsable(EditorBrowsableState.Never)]
164         protected override void Dispose(DisposeTypes type)
165         {
166             if (disposed)
167             {
168                 return;
169             }
170
171             if (type == DisposeTypes.Explicit)
172             {
173                 StyleManager.Instance.ThemeChangedEvent -= OnThemeChangedEvent;
174                 tapGestureDetector.Detected -= OnTapGestureDetected;
175                 tapGestureDetector.Detach(this);
176             }
177
178             base.Dispose(type);
179         }
180
181         /// <summary>
182         /// Called after a key event is received by the view that has had its focus set.
183         /// </summary>
184         /// <param name="key">The key event.</param>
185         /// <returns>True if the key event should be consumed.</returns>
186         /// <since_tizen> 6 </since_tizen>
187         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
188         [EditorBrowsable(EditorBrowsableState.Never)]
189         public override bool OnKey(Key key)
190         {
191             return false;
192         }
193
194         /// <summary>
195         /// Called after the size negotiation has been finished for this control.<br />
196         /// The control is expected to assign this given size to itself or its children.<br />
197         /// 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 />
198         /// As this function is called from inside the size negotiation algorithm, you cannot call RequestRelayout (the call would just be ignored).<br />
199         /// </summary>
200         /// <param name="size">The allocated size.</param>
201         /// <param name="container">The control should add views to this container that it is not able to allocate a size for.</param>
202         /// <since_tizen> 6 </since_tizen>
203         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
204         [EditorBrowsable(EditorBrowsableState.Never)]
205         public override void OnRelayout(Vector2 size, RelayoutContainer container)
206         {
207             base.OnRelayout(size, container);
208             OnUpdate();
209         }
210
211         /// <summary>
212         /// 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.
213         /// </summary>
214         /// <since_tizen> 6 </since_tizen>
215         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
216         [EditorBrowsable(EditorBrowsableState.Never)]
217         public override void OnFocusGained()
218         {
219             IsFocused = true;
220         }
221
222         /// <summary>
223         /// 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.
224         /// </summary>
225         /// <since_tizen> 6 </since_tizen>
226         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
227         [EditorBrowsable(EditorBrowsableState.Never)]
228         public override void OnFocusLost()
229         {
230             IsFocused = false;
231         }
232
233         /// <summary>
234         /// Tap gesture callback.
235         /// </summary>
236         /// <param name="source">The sender</param>
237         /// <param name="e">The tap gesture event data</param>
238         /// <since_tizen> 6 </since_tizen>
239         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
240         [EditorBrowsable(EditorBrowsableState.Never)]
241         protected virtual void OnTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e) { }
242
243         /// <summary>
244         /// Called after a touch event is received by the owning view.<br />
245         /// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).<br />
246         /// </summary>
247         /// <param name="touch">The touch event.</param>
248         /// <returns>True if the event should be consumed.</returns>
249         /// <since_tizen> 6 </since_tizen>
250         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
251         [EditorBrowsable(EditorBrowsableState.Never)]
252         public override bool OnTouch(Touch touch)
253         {
254             // Handle Normal and Pressed states
255             PointStateType state = touch.GetState(0);
256             switch(state)
257             {
258                 case PointStateType.Down:
259                     ControlState = ControlStates.Pressed;
260                     break;
261                 case PointStateType.Interrupted:
262                 case PointStateType.Up:
263                     if (ControlState == ControlStates.Pressed)
264                     {
265                         ControlState = ControlStates.Normal;
266                     }
267                     break;
268                 default:
269                     break;
270             }
271             return false;
272         }
273
274         /// <summary>
275         /// Update by style.
276         /// </summary>
277         /// <since_tizen> 6 </since_tizen>
278         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
279         [EditorBrowsable(EditorBrowsableState.Never)]
280         protected virtual void OnUpdate()
281         {
282         }
283
284         /// <summary>
285         /// Theme change callback when theme is changed, this callback will be trigger.
286         /// </summary>
287         /// <param name="sender">The sender</param>
288         /// <param name="e">The event data</param>
289         /// <since_tizen> 6 </since_tizen>
290         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
291         [EditorBrowsable(EditorBrowsableState.Never)]
292         protected virtual void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e) { }
293
294         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
295         [EditorBrowsable(EditorBrowsableState.Never)]
296         protected virtual void RegisterDetectionOfSubstyleChanges() { }
297
298         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
299         [EditorBrowsable(EditorBrowsableState.Never)]
300         protected override ViewStyle CreateViewStyle()
301         {
302             return new ControlStyle();
303         }
304
305         private void Initialize()
306         {
307             ControlState = ControlStates.Normal;
308
309             RegisterDetectionOfSubstyleChanges();
310
311             LeaveRequired = true;
312
313             StateFocusableOnTouchMode = false;
314
315             tapGestureDetector.Attach(this);
316             tapGestureDetector.Detected += OnTapGestureDetected;
317
318             StyleManager.Instance.ThemeChangedEvent += OnThemeChangedEvent;
319         }
320     }
321 }