Fix components issue 1216 (#1194)
[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> BackgroundImageProperty</summary>
34         [EditorBrowsable(EditorBrowsableState.Never)]
35         public new static readonly BindableProperty BackgroundImageProperty = BindableProperty.Create("ControlBackgroundImage", typeof(Selector<string>), typeof(Control), null, propertyChanged: (bindable, oldValue, newValue) =>
36         {
37             var control = (Control)bindable;
38             if (null != newValue)
39             {
40                 control.BackgroundImageSelector.Clone((Selector<string>)newValue);
41             }
42         },
43         defaultValueCreator: (bindable) =>
44         {
45             var control = (Control)bindable;
46             return control.BackgroundImageSelector;
47         });
48         /// <summary>BackgroundBorderProperty</summary>
49         [EditorBrowsable(EditorBrowsableState.Never)]
50         public new static readonly BindableProperty BackgroundImageBorderProperty = BindableProperty.Create("ControlBackgroundImageBorder", typeof(Selector<Rectangle>), typeof(Control), default(Rectangle), propertyChanged: (bindable, oldValue, newValue) =>
51         {
52             var control = (Control)bindable;
53             if (null != newValue)
54             {
55                 control.backgroundImageBorderSelector.Clone((Selector<Rectangle>)newValue);
56             }
57         },
58         defaultValueCreator: (bindable) =>
59         {
60             var control = (Control)bindable;
61             return control.backgroundImageBorderSelector;
62         });
63         /// <summary> BackgroundColorProperty </summary>
64         [EditorBrowsable(EditorBrowsableState.Never)]
65         public new static readonly BindableProperty BackgroundColorProperty = BindableProperty.Create("ControlBackgroundColor", typeof(Selector<Color>), typeof(Control), null, propertyChanged: (bindable, oldValue, newValue) =>
66         {
67             var control = (Control)bindable;
68             if (null != newValue)
69             {
70                 control.BackgroundColorSelector.Clone((Selector<Color>)newValue);
71             }
72         },
73         defaultValueCreator: (bindable) =>
74         {
75             var control = (Control)bindable;
76             return control.BackgroundColorSelector;
77         });
78         /// <summary> Control style. </summary>
79         /// <since_tizen> 6 </since_tizen>
80         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
81         [EditorBrowsable(EditorBrowsableState.Never)]
82         protected string style;
83
84         private TapGestureDetector tapGestureDetector = new TapGestureDetector();
85         private bool isFocused = false;
86
87         internal ImageView backgroundImage = new ImageView();
88         internal ImageView shadowImage;
89
90         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
91         [EditorBrowsable(EditorBrowsableState.Never)]
92         public ControlStyle Style => ViewStyle as ControlStyle;
93
94         /// <summary>
95         /// Construct an empty Control.
96         /// </summary>
97         /// <since_tizen> 6 </since_tizen>
98         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
99         [EditorBrowsable(EditorBrowsableState.Never)]
100         public Control() : base()
101         {
102             Initialize(null);
103         }
104
105         /// <summary>
106         /// Construct with attributes
107         /// </summary>
108         /// <param name="attributes">Create attributes customized by user</param>
109         /// <since_tizen> 6 </since_tizen>
110         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
111         [EditorBrowsable(EditorBrowsableState.Never)]
112         public Control(ControlStyle controlStyle) : base(controlStyle)
113         {
114             Initialize(null);
115         }
116
117         /// <summary>
118         /// Construct with styleSheet
119         /// </summary>
120         /// <param name="styleSheet">StyleSheet to be applied</param>
121         /// <since_tizen> 6 </since_tizen>
122         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
123         [EditorBrowsable(EditorBrowsableState.Never)]
124         public Control(string styleSheet) : base()
125         {
126             ViewStyle viewStyle = StyleManager.Instance.GetAttributes(styleSheet);
127             if (viewStyle == null)
128             {
129                 throw new InvalidOperationException($"There is no style {styleSheet}");
130             }
131
132             ApplyStyle(viewStyle);
133             this.style = styleSheet;
134
135             Initialize(style);
136         }
137
138         private TriggerableSelector<string> _backgroundImageSelector;
139         private TriggerableSelector<string> BackgroundImageSelector
140         {
141             get
142             {
143                 if (null == _backgroundImageSelector)
144                 {
145                     _backgroundImageSelector = new TriggerableSelector<string>(backgroundImage, ImageView.ResourceUrlProperty);
146                 }
147                 return _backgroundImageSelector;
148             }
149         }
150         private TriggerableSelector<Rectangle> _backgroundImageBorderSelector;
151         private TriggerableSelector<Rectangle> backgroundImageBorderSelector
152         {
153             get
154             {
155                 if (null == _backgroundImageBorderSelector)
156                 {
157                     _backgroundImageBorderSelector = new TriggerableSelector<Rectangle>(backgroundImage, ImageView.BorderProperty);
158                 }
159                 return _backgroundImageBorderSelector;
160             }
161         }
162         private TriggerableSelector<Color> _backgroundColorSelector;
163         private TriggerableSelector<Color> BackgroundColorSelector
164         {
165             get
166             {
167                 if (null == _backgroundColorSelector)
168                 {
169                     _backgroundColorSelector = new TriggerableSelector<Color>(backgroundImage, View.BackgroundColorProperty);
170                 }
171                 return _backgroundColorSelector;
172             }
173         }
174         /// <summary>
175         /// Override view's BackgroundImage.
176         /// </summary>
177         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
178         [EditorBrowsable(EditorBrowsableState.Never)]
179         public new Selector<string> BackgroundImage
180         {
181             get => (Selector<string>)GetValue(BackgroundImageProperty);
182             set => SetValue(BackgroundImageProperty, value);
183         }
184
185         /// <summary>
186         /// Override view's BackgroundImageBorder.
187         /// </summary>
188         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
189         [EditorBrowsable(EditorBrowsableState.Never)]
190         public new Selector<Rectangle> BackgroundImageBorder
191         {
192             get => (Selector<Rectangle>)GetValue(BackgroundImageBorderProperty);
193             set => SetValue(BackgroundImageBorderProperty, value);
194         }
195         /// <summary>
196         /// Override view's BackgroundBorder.
197         /// </summary>
198         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
199         [EditorBrowsable(EditorBrowsableState.Never)]
200         public new Selector<Color> BackgroundColor
201         {
202             get => (Selector<Color>)GetValue(BackgroundColorProperty);
203             set => SetValue(BackgroundColorProperty, value);
204         }
205
206         /// <summary>
207         /// Shadow image.
208         /// </summary>
209         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
210         [EditorBrowsable(EditorBrowsableState.Never)]
211         public Selector<string> ShadowImage
212         {
213             get
214             {
215                 return Style.Shadow.ResourceUrl;
216             }
217             set
218             {
219                 Style.Shadow.ResourceUrl = value;
220             }
221         }
222
223         /// <summary>
224         /// Shadow image border.
225         /// </summary>
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 Selector<Rectangle> ShadowImageBorder
229         {
230             get
231             {
232                 return Style.Shadow.Border;
233             }
234             set
235             {
236                 Style.Shadow.Border = value;
237             }
238         }
239
240         internal void ApplyAttributes(View view, ViewStyle viewStyle)
241         {
242             view.CopyFrom(viewStyle);
243         }
244
245         /// <summary>
246         /// Whether focusable when touch
247         /// </summary>
248         /// <since_tizen> 6 </since_tizen>
249         internal bool StateFocusableOnTouchMode { get; set; }
250
251         internal bool IsFocused => (isFocused || HasFocus());
252
253         /// <summary>
254         /// Dispose Control and all children on it.
255         /// </summary>
256         /// <param name="type">Dispose type.</param>
257         /// <since_tizen> 6 </since_tizen>
258         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
259         [EditorBrowsable(EditorBrowsableState.Never)]
260         protected override void Dispose(DisposeTypes type)
261         {
262             if (disposed)
263             {
264                 return;
265             }
266
267             if (type == DisposeTypes.Explicit)
268             {
269                 StyleManager.Instance.ThemeChangedEvent -= OnThemeChangedEvent;
270                 tapGestureDetector.Detected -= OnTapGestureDetected;
271                 tapGestureDetector.Detach(this);
272             }
273
274             if (backgroundImage != null)
275             {
276                 Utility.Dispose(backgroundImage);
277             }
278             if (shadowImage != null)
279             {
280                 Utility.Dispose(shadowImage);
281             }
282
283             base.Dispose(type);
284         }
285
286         /// <summary>
287         /// Called after a key event is received by the view that has had its focus set.
288         /// </summary>
289         /// <param name="key">The key event.</param>
290         /// <returns>True if the key event should be consumed.</returns>
291         /// <since_tizen> 6 </since_tizen>
292         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
293         [EditorBrowsable(EditorBrowsableState.Never)]
294         public override bool OnKey(Key key)
295         {
296             return false;
297         }
298
299         /// <summary>
300         /// Called after the size negotiation has been finished for this control.<br />
301         /// The control is expected to assign this given size to itself or its children.<br />
302         /// 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 />
303         /// As this function is called from inside the size negotiation algorithm, you cannot call RequestRelayout (the call would just be ignored).<br />
304         /// </summary>
305         /// <param name="size">The allocated size.</param>
306         /// <param name="container">The control should add views to this container that it is not able to allocate a size for.</param>
307         /// <since_tizen> 6 </since_tizen>
308         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
309         [EditorBrowsable(EditorBrowsableState.Never)]
310         public override void OnRelayout(Vector2 size, RelayoutContainer container)
311         {
312             OnUpdate();
313         }
314
315         /// <summary>
316         /// 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.
317         /// </summary>
318         /// <since_tizen> 6 </since_tizen>
319         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
320         [EditorBrowsable(EditorBrowsableState.Never)]
321         public override void OnFocusGained()
322         {
323             isFocused = true;
324         }
325
326         /// <summary>
327         /// 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.
328         /// </summary>
329         /// <since_tizen> 6 </since_tizen>
330         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
331         [EditorBrowsable(EditorBrowsableState.Never)]
332         public override void OnFocusLost()
333         {
334             isFocused = false;
335         }
336
337         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
338         [EditorBrowsable(EditorBrowsableState.Never)]
339         public override void ApplyStyle(ViewStyle viewStyle)
340         {
341             base.ApplyStyle(viewStyle);
342
343             ControlStyle controlStyle = viewStyle as ControlStyle;
344
345             if (null != controlStyle?.Shadow)
346             {
347                 if (null == shadowImage)
348                 {
349                     shadowImage = new ImageView()
350                     {
351                         WidthResizePolicy = ResizePolicyType.FillToParent,
352                         HeightResizePolicy = ResizePolicyType.FillToParent,
353                     };
354                     this.Add(shadowImage);
355                     shadowImage.LowerToBottom();
356                 }
357
358                 shadowImage.ApplyStyle(controlStyle.Shadow);
359             }
360             if (null != controlStyle.BackgroundImage)
361             {
362                 backgroundImage.WidthResizePolicy = ResizePolicyType.FillToParent;
363                 backgroundImage.HeightResizePolicy = ResizePolicyType.FillToParent;
364                 this.Add(backgroundImage);
365             }
366         }
367
368         /// <summary>
369         /// Tap gesture callback.
370         /// </summary>
371         /// <param name="source">The sender</param>
372         /// <param name="e">The tap gesture event data</param>
373         /// <since_tizen> 6 </since_tizen>
374         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
375         [EditorBrowsable(EditorBrowsableState.Never)]
376         protected virtual void OnTapGestureDetected(object source, TapGestureDetector.DetectedEventArgs e) { }
377
378         /// <summary>
379         /// Called after a touch event is received by the owning view.<br />
380         /// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).<br />
381         /// </summary>
382         /// <param name="touch">The touch event.</param>
383         /// <returns>True if the event should be consumed.</returns>
384         /// <since_tizen> 6 </since_tizen>
385         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
386         [EditorBrowsable(EditorBrowsableState.Never)]
387         public override bool OnTouch(Touch touch)
388         {
389             return false;
390         }
391
392         /// <summary>
393         /// Update by attributes.
394         /// </summary>
395         /// <since_tizen> 6 </since_tizen>
396         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
397         [EditorBrowsable(EditorBrowsableState.Never)]
398         protected virtual void OnUpdate()
399         {
400         }
401
402         /// <summary>
403         /// Theme change callback when theme is changed, this callback will be trigger.
404         /// </summary>
405         /// <param name="sender">The sender</param>
406         /// <param name="e">The event data</param>
407         /// <since_tizen> 6 </since_tizen>
408         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
409         [EditorBrowsable(EditorBrowsableState.Never)]
410         protected virtual void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e) { }
411
412         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
413         [EditorBrowsable(EditorBrowsableState.Never)]
414         protected virtual void RegisterDetectionOfSubstyleChanges() { }
415
416         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
417         [EditorBrowsable(EditorBrowsableState.Never)]
418         protected override ViewStyle GetViewStyle()
419         {
420             return new ControlStyle();
421         }
422
423         private void Initialize(string style)
424         {
425             ControlState = ControlStates.Normal;
426
427             RegisterDetectionOfSubstyleChanges();
428
429             LeaveRequired = true;
430
431             StateFocusableOnTouchMode = false;
432
433             tapGestureDetector.Attach(this);
434             tapGestureDetector.Detected += OnTapGestureDetected;
435
436             StyleManager.Instance.ThemeChangedEvent += OnThemeChangedEvent;
437         }
438
439         private ViewStyle GetAttributes(string style)
440         {
441             ViewStyle attributes = StyleManager.Instance.GetAttributes(style);
442             if(attributes == null)
443             {
444                 throw new InvalidOperationException($"There is no style {style}");
445             }
446             this.style = style;
447             return attributes;
448         }
449     }
450 }