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