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