[NUI] Merge Button action state and support experimental theme by profile. (#1525)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Button.cs
1 /*
2  * Copyright(c) 2020 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.ComponentModel;
19 using Tizen.NUI.BaseComponents;
20 using Tizen.NUI.Binding;
21 using Tizen.NUI.Components.Extension;
22
23 namespace Tizen.NUI.Components
24 {
25     /// <summary>
26     /// Button is one kind of common component, a button clearly describes what action will occur when the user selects it.
27     /// Button may contain text or an icon.
28     /// </summary>
29     /// <since_tizen> 6 </since_tizen>
30     public class Button : Control
31     {
32         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
33         [EditorBrowsable(EditorBrowsableState.Never)]
34         public static readonly BindableProperty IconRelativeOrientationProperty = BindableProperty.Create(nameof(IconRelativeOrientation), typeof(IconOrientation?), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
35         {
36             var instance = (Button)bindable;
37             if (newValue != null)
38             {
39                 instance.privateIconRelativeOrientation = (IconOrientation?)newValue;
40             }
41         },
42         defaultValueCreator: (bindable) =>
43         {
44             var instance = (Button)bindable;
45             return instance.privateIconRelativeOrientation;
46         });
47         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
48         [EditorBrowsable(EditorBrowsableState.Never)]
49         public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(Button), true, propertyChanged: (bindable, oldValue, newValue) =>
50         {
51             var instance = (Button)bindable;
52             if (newValue != null)
53             {
54                 instance.privateIsEnabled = (bool)newValue;
55             }
56         },
57         defaultValueCreator: (bindable) =>
58         {
59             var instance = (Button)bindable;
60             return instance.privateIsEnabled;
61         });
62         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
63         [EditorBrowsable(EditorBrowsableState.Never)]
64         public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(Button), true, propertyChanged: (bindable, oldValue, newValue) =>
65         {
66             var instance = (Button)bindable;
67             if (newValue != null)
68             {
69                 instance.privateIsSelected = (bool)newValue;
70             }
71         },
72         defaultValueCreator: (bindable) =>
73         {
74             var instance = (Button)bindable;
75             return instance.privateIsSelected;
76         });
77         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
78         [EditorBrowsable(EditorBrowsableState.Never)]
79         public static readonly BindableProperty IsSelectableProperty = BindableProperty.Create(nameof(IsSelectable), typeof(bool), typeof(Button), true, propertyChanged: (bindable, oldValue, newValue) =>
80         {
81             var instance = (Button)bindable;
82             if (newValue != null)
83             {
84                 instance.privateIsSelectable = (bool)newValue;
85             }
86         },
87         defaultValueCreator: (bindable) =>
88         {
89             var instance = (Button)bindable;
90             return instance.privateIsSelectable;
91         });
92         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
93         [EditorBrowsable(EditorBrowsableState.Never)]
94         public static readonly BindableProperty IconPaddingProperty = BindableProperty.Create(nameof(IconPadding), typeof(Extents), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
95         {
96             var instance = (Button)bindable;
97             if (null != newValue && null != instance.Style?.IconPadding)
98             {
99                 instance.Style.IconPadding.CopyFrom((Extents)newValue);
100                 instance.UpdateUIContent();
101             }
102         },
103         defaultValueCreator: (bindable) =>
104         {
105             var instance = (Button)bindable;
106             return instance.Style?.IconPadding;
107         });
108         /// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
109         [EditorBrowsable(EditorBrowsableState.Never)]
110         public static readonly BindableProperty TextPaddingProperty = BindableProperty.Create(nameof(TextPadding), typeof(Extents), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
111         {
112             var instance = (Button)bindable;
113             if (null != newValue && null != instance.Style?.TextPadding)
114             {
115                 instance.Style.TextPadding.CopyFrom((Extents)newValue);
116                 instance.UpdateUIContent();
117             }
118         },
119         defaultValueCreator: (bindable) =>
120         {
121             var instance = (Button)bindable;
122             return instance.Style?.TextPadding;
123         });
124
125         private EventHandler<StateChangedEventArgs> stateChangeHander;
126
127         private bool isSelected = false;
128         private bool isEnabled = true;
129         private bool isPressed = false;
130
131         /// <summary>
132         /// Button's overlay image part.
133         /// </summary>
134         [EditorBrowsable(EditorBrowsableState.Never)]
135         protected ImageView ButtonOverlayImage { get; set; }
136
137         /// <summary>
138         /// Button's text part.
139         /// </summary>
140         [EditorBrowsable(EditorBrowsableState.Never)]
141         protected TextLabel ButtonText { get; set; }
142
143         /// <summary>
144         /// Button's icon part.
145         /// </summary>
146         [EditorBrowsable(EditorBrowsableState.Never)]
147         protected ImageView ButtonIcon { get; set; }
148
149         /// <summary>
150         /// The last touch information triggering selected state change.
151         /// </summary>
152         [EditorBrowsable(EditorBrowsableState.Never)]
153         protected Touch SelectionChangedByTouch { get; set; }
154
155         /// <summary>
156         /// The ButtonExtension instance that is injected by ButtonStyle.
157         /// </summary>
158         [EditorBrowsable(EditorBrowsableState.Never)]
159         protected ButtonExtension Extension { get; set; }
160
161         /// <summary>
162         /// Creates Button's text part.
163         /// </summary>
164         /// <return>The created Button's text part.</return>
165         [EditorBrowsable(EditorBrowsableState.Never)]
166         protected virtual TextLabel CreateText()
167         {
168             return new TextLabel();
169         }
170
171         /// <summary>
172         /// Creates Button's icon part.
173         /// </summary>
174         /// <return>The created Button's icon part.</return>
175         [EditorBrowsable(EditorBrowsableState.Never)]
176         protected virtual ImageView CreateIcon()
177         {
178             return new ImageView();
179         }
180
181         /// <summary>
182         /// Creates Button's overlay image part.
183         /// </summary>
184         /// <return>The created Button's overlay image part.</return>
185         [EditorBrowsable(EditorBrowsableState.Never)]
186         protected virtual ImageView CreateOverlayImage()
187         {
188             return new ImageView();
189         }
190
191         /// <summary>
192         /// Called when the Button is Clicked by a user
193         /// </summary>
194         /// <param name="eventArgs">The click information.</param>
195         [EditorBrowsable(EditorBrowsableState.Never)]
196         protected virtual void OnClick(ClickEventArgs eventArgs)
197         {
198         }
199
200         static Button() { }
201
202         /// <summary>
203         /// Creates a new instance of a Button.
204         /// </summary>
205         /// <since_tizen> 6 </since_tizen>
206         public Button() : base()
207         {
208             Initialize();
209         }
210
211         /// <summary>
212         /// Creates a new instance of a Button with style.
213         /// </summary>
214         /// <param name="style">Create Button by special style defined in UX.</param>
215         /// <since_tizen> 8 </since_tizen>
216         public Button(string style) : base(style)
217         {
218             Initialize();
219         }
220
221         /// <summary>
222         /// Creates a new instance of a Button with style.
223         /// </summary>
224         /// <param name="buttonStyle">Create Button by style customized by user.</param>
225         /// <since_tizen> 8 </since_tizen>
226         public Button(ButtonStyle buttonStyle) : base(buttonStyle)
227         {
228             Initialize();
229         }
230
231         /// <summary>
232         /// An event for the button clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
233         /// </summary>
234         /// <since_tizen> 6 </since_tizen>
235         public event EventHandler<ClickEventArgs> ClickEvent;
236         /// <summary>
237         /// An event for the button state changed signal which can be used to subscribe or unsubscribe the event handler provided by the user.<br />
238         /// </summary>
239         /// <since_tizen> 6 </since_tizen>
240         public event EventHandler<StateChangedEventArgs> StateChangedEvent
241         {
242             add
243             {
244                 stateChangeHander += value;
245             }
246             remove
247             {
248                 stateChangeHander -= value;
249             }
250         }
251         /// <summary>
252         /// Icon orientation.
253         /// </summary>
254         /// <since_tizen> 6 </since_tizen>
255         public enum IconOrientation
256         {
257             /// <summary>
258             /// Top.
259             /// </summary>
260             /// <since_tizen> 6 </since_tizen>
261             Top,
262             /// <summary>
263             /// Bottom.
264             /// </summary>
265             /// <since_tizen> 6 </since_tizen>
266             Bottom,
267             /// <summary>
268             /// Left.
269             /// </summary>
270             /// <since_tizen> 6 </since_tizen>
271             Left,
272             /// <summary>
273             /// Right.
274             /// </summary>
275             /// <since_tizen> 6 </since_tizen>
276             Right,
277         }
278
279         /// <summary>
280         /// Style of the button.
281         /// </summary>
282         /// <since_tizen> 8 </since_tizen>
283         public new ButtonStyle Style => ViewStyle as ButtonStyle;
284
285         /// <summary>
286         /// The text of Button.
287         /// </summary>
288         /// <since_tizen> 6 </since_tizen>
289         public string Text
290         {
291             get
292             {
293                 return Style?.Text?.Text?.GetValue(ControlState);
294             }
295             set
296             {
297                 if (null != Style?.Text)
298                 {
299                     Style.Text.Text = value;
300                 }
301             }
302         }
303
304         /// <summary>
305         /// Flag to decide Button can be selected or not.
306         /// </summary>
307         /// <since_tizen> 6 </since_tizen>
308         public bool IsSelectable
309         {
310             get
311             {
312                 return (bool)GetValue(IsSelectableProperty);
313             }
314             set
315             {
316                 SetValue(IsSelectableProperty, value);
317             }
318         }
319
320         private bool privateIsSelectable
321         {
322             get
323             {
324                 return Style?.IsSelectable ?? false;
325             }
326             set
327             {
328                 Style.IsSelectable = value;
329             }
330         }
331
332         /// <summary>
333         /// Translate text string in Button.
334         /// </summary>
335         /// <since_tizen> 6 </since_tizen>
336         public string TranslatableText
337         {
338             get
339             {
340                 return Style?.Text?.TranslatableText?.All;
341             }
342             set
343             {
344                 if (null != Style?.Text)
345                 {
346                     Style.Text.TranslatableText = value;
347                 }
348             }
349         }
350
351         /// <summary>
352         /// Text point size in Button.
353         /// </summary>
354         /// <since_tizen> 6 </since_tizen>
355         public float PointSize
356         {
357             get
358             {
359                 return Style?.Text?.PointSize?.All ?? 0;
360             }
361             set
362             {
363                 if (null != Style?.Text)
364                 {
365                     Style.Text.PointSize = value;
366                 }
367             }
368         }
369
370         /// <summary>
371         /// Text font family in Button.
372         /// </summary>
373         /// <since_tizen> 6 </since_tizen>
374         public string FontFamily
375         {
376             get
377             {
378                 return Style?.Text?.FontFamily.All;
379             }
380             set
381             {
382                 if (null != Style?.Text)
383                 {
384                     Style.Text.FontFamily = value;
385                 }
386             }
387         }
388         /// <summary>
389         /// Text color in Button.
390         /// </summary>
391         /// <since_tizen> 6 </since_tizen>
392         public Color TextColor
393         {
394             get
395             {
396                 return Style?.Text?.TextColor?.All;
397             }
398             set
399             {
400                 if (null != Style?.Text)
401                 {
402                     Style.Text.TextColor = value;
403                 }
404             }
405         }
406         /// <summary>
407         /// Text horizontal alignment in Button.
408         /// </summary>
409         /// <since_tizen> 6 </since_tizen>
410         public HorizontalAlignment TextAlignment
411         {
412             get
413             {
414                 return Style?.Text?.HorizontalAlignment ?? HorizontalAlignment.Center;
415             }
416             set
417             {
418                 if (null != Style?.Text)
419                 {
420                     Style.Text.HorizontalAlignment = value;
421                 }
422             }
423         }
424         /// <summary>
425         /// Icon image's resource url in Button.
426         /// </summary>
427         /// <since_tizen> 6 </since_tizen>
428         public string IconURL
429         {
430             get
431             {
432                 return Style?.Icon?.ResourceUrl?.All;
433             }
434             set
435             {
436                 if (null != Style?.Icon)
437                 {
438                     Style.Icon.ResourceUrl = value;
439                 }
440             }
441         }
442
443         private StringSelector textSelector = new StringSelector();
444         /// <summary>
445         /// Text string selector in Button.
446         /// </summary>
447         /// <since_tizen> 6 </since_tizen>
448         public StringSelector TextSelector
449         {
450             get
451             {
452                 return textSelector;
453             }
454             set
455             {
456                 textSelector.Clone(value);
457             }
458         }
459
460         private StringSelector translatableTextSelector = new StringSelector();
461         /// <summary>
462         /// Translateable text string selector in Button.
463         /// </summary>
464         /// <since_tizen> 6 </since_tizen>
465         public StringSelector TranslatableTextSelector
466         {
467             get
468             {
469                 return translatableTextSelector;
470             }
471             set
472             {
473                 translatableTextSelector.Clone(value);
474             }
475         }
476
477         private ColorSelector textColorSelector = new ColorSelector();
478         /// <summary>
479         /// Text color selector in Button.
480         /// </summary>
481         /// <since_tizen> 6 </since_tizen>
482         public ColorSelector TextColorSelector
483         {
484             get
485             {
486                 return textColorSelector;
487             }
488             set
489             {
490                 textColorSelector.Clone(value);
491             }
492         }
493
494         private FloatSelector pointSizeSelector = new FloatSelector();
495         /// <summary>
496         /// Text font size selector in Button.
497         /// </summary>
498         /// <since_tizen> 6 </since_tizen>
499         public FloatSelector PointSizeSelector
500         {
501             get
502             {
503                 return pointSizeSelector;
504             }
505             set
506             {
507                 pointSizeSelector.Clone(value);
508             }
509         }
510
511         private StringSelector iconURLSelector = new StringSelector();
512         /// <summary>
513         /// Icon image's resource url selector in Button.
514         /// </summary>
515         /// <since_tizen> 6 </since_tizen>
516         public StringSelector IconURLSelector
517         {
518             get
519             {
520                 return iconURLSelector;
521             }
522             set
523             {
524                 iconURLSelector.Clone(value);
525             }
526         }
527
528         /// <summary>
529         /// Flag to decide selected state in Button.
530         /// </summary>
531         /// <since_tizen> 6 </since_tizen>
532         public bool IsSelected
533         {
534             get
535             {
536                 return (bool)GetValue(IsSelectedProperty);
537             }
538             set
539             {
540                 SetValue(IsSelectedProperty, value);
541             }
542         }
543         private bool privateIsSelected
544         {
545             get
546             {
547                 return isSelected;
548             }
549             set
550             {
551                 isSelected = value;
552
553                 UpdateState(SelectionChangedByTouch);
554
555                 SelectionChangedByTouch = null;
556             }
557         }
558
559         /// <summary>
560         /// Flag to decide enable or disable in Button.
561         /// </summary>
562         /// <since_tizen> 6 </since_tizen>
563         public bool IsEnabled
564         {
565             get
566             {
567                 return (bool)GetValue(IsEnabledProperty);
568             }
569             set
570             {
571                 SetValue(IsEnabledProperty, value);
572             }
573         }
574         private bool privateIsEnabled
575         {
576             get
577             {
578                 return isEnabled;
579             }
580             set
581             {
582                 isEnabled = value;
583                 UpdateState();
584             }
585         }
586
587         /// <summary>
588         /// Icon relative orientation in Button, work only when show icon and text.
589         /// </summary>
590         /// <since_tizen> 6 </since_tizen>
591         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
592         [EditorBrowsable(EditorBrowsableState.Never)]
593         public IconOrientation? IconRelativeOrientation
594         {
595             get
596             {
597                 return (IconOrientation?)GetValue(IconRelativeOrientationProperty);
598             }
599             set
600             {
601                 SetValue(IconRelativeOrientationProperty, value);
602             }
603         }
604         private IconOrientation? privateIconRelativeOrientation
605         {
606             get
607             {
608                 return Style?.IconRelativeOrientation;
609             }
610             set
611             {
612                 if(Style != null && Style.IconRelativeOrientation != value)
613                 {
614                     Style.IconRelativeOrientation = value;
615                     UpdateUIContent();
616                 }
617             }
618         }
619
620         /// <summary>
621         /// Icon padding in Button, work only when show icon and text.
622         /// </summary>
623         /// <since_tizen> 6 </since_tizen>
624         public Extents IconPadding
625         {
626             get => (Extents)GetValue(IconPaddingProperty);
627             set => SetValue(IconPaddingProperty, value);
628         }
629
630         /// <summary>
631         /// Text padding in Button, work only when show icon and text.
632         /// </summary>
633         /// <since_tizen> 6 </since_tizen>
634         public Extents TextPadding
635         {
636             get => (Extents) GetValue(TextPaddingProperty);
637             set => SetValue(TextPaddingProperty, value);
638         }
639
640         /// <summary>
641         /// Dispose Button and all children on it.
642         /// </summary>
643         /// <param name="type">Dispose type.</param>
644         /// <since_tizen> 6 </since_tizen>
645         protected override void Dispose(DisposeTypes type)
646         {
647             if (disposed)
648             {
649                 return;
650             }
651
652             if (type == DisposeTypes.Explicit)
653             {
654                 Extension?.OnDispose(this);
655
656                 if (ButtonIcon != null)
657                 {
658                     Utility.Dispose(ButtonIcon);
659                 }
660                 if (ButtonText != null)
661                 {
662                     Utility.Dispose(ButtonText);
663                 }
664                 if (ButtonOverlayImage != null)
665                 {
666                     Utility.Dispose(ButtonOverlayImage);
667                 }
668             }
669
670             base.Dispose(type);
671         }
672         /// <summary>
673         /// Called after a key event is received by the view that has had its focus set.
674         /// </summary>
675         /// <param name="key">The key event.</param>
676         /// <returns>True if the key event should be consumed.</returns>
677         /// <since_tizen> 6 </since_tizen>
678         public override bool OnKey(Key key)
679         {
680             if (null == key) return false;
681             if (key.State == Key.StateType.Down)
682             {
683                 if (key.KeyPressedName == "Return")
684                 {
685                     isPressed = true;
686                     UpdateState();
687                 }
688             }
689             else if (key.State == Key.StateType.Up)
690             {
691                 if (key.KeyPressedName == "Return")
692                 {
693                     bool clicked = isPressed && isEnabled;
694
695                     isPressed = false;
696
697                     if (Style.IsSelectable != null && Style.IsSelectable == true)
698                     {
699                         IsSelected = !IsSelected;
700                     }
701                     else
702                     {
703                         UpdateState();
704                     }
705
706                     if (clicked)
707                     {
708                         ClickEventArgs eventArgs = new ClickEventArgs();
709                         OnClickInternal(eventArgs);
710                     }
711                 }
712             }
713             return base.OnKey(key);
714         }
715
716         /// <summary>
717         /// 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.
718         /// </summary>
719         /// <since_tizen> 6 </since_tizen>
720         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
721         [EditorBrowsable(EditorBrowsableState.Never)]
722         public override void OnFocusGained()
723         {
724             base.OnFocusGained();
725             UpdateState();
726         }
727
728         /// <summary>
729         /// 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.
730         /// </summary>
731         /// <since_tizen> 6 </since_tizen>
732         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
733         [EditorBrowsable(EditorBrowsableState.Never)]
734         public override void OnFocusLost()
735         {
736             base.OnFocusLost();
737             UpdateState();
738         }
739
740         /// <summary>
741         /// Called after a touch event is received by the owning view.<br />
742         /// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).<br />
743         /// </summary>
744         /// <param name="touch">The touch event.</param>
745         /// <returns>True if the event should be consumed.</returns>
746         /// <since_tizen> 6 </since_tizen>
747         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
748         [EditorBrowsable(EditorBrowsableState.Never)]
749         public override bool OnTouch(Touch touch)
750         {
751             if (null == touch) return false;
752             PointStateType state = touch.GetState(0);
753
754             switch(state)
755             {
756                 case PointStateType.Down:
757                     isPressed = true;
758                     UpdateState(touch);
759                     return true;
760                 case PointStateType.Interrupted:
761                     isPressed = false;
762                     UpdateState();
763                     return true;
764                 case PointStateType.Up:
765                 {
766                     bool clicked = isPressed && isEnabled;
767
768                     isPressed = false;
769
770                     if (Style.IsSelectable != null && Style.IsSelectable == true)
771                     {
772                         SelectionChangedByTouch = touch;
773                         IsSelected = !IsSelected;
774                     }
775                     else
776                     {
777                         UpdateState(touch);
778                     }
779
780                     if (clicked)
781                     {
782                         ClickEventArgs eventArgs = new ClickEventArgs();
783                         OnClickInternal(eventArgs);
784                     }
785
786                     return true;
787                 }
788                 default:
789                     break;
790             }
791             return base.OnTouch(touch);
792         }
793
794         /// <summary>
795         /// Apply style to button.
796         /// </summary>
797         /// <param name="viewStyle">The style to apply.</param>
798         /// <since_tizen> 8 </since_tizen>
799         public override void ApplyStyle(ViewStyle viewStyle)
800         {
801             base.ApplyStyle(viewStyle);
802
803             ButtonStyle buttonStyle = viewStyle as ButtonStyle;
804
805             if (null != buttonStyle)
806             {
807                 ButtonOverlayImage?.ApplyStyle(buttonStyle.Overlay);
808                 ButtonText?.ApplyStyle(buttonStyle.Text);
809                 ButtonIcon?.ApplyStyle(buttonStyle.Icon);
810             }
811         }
812
813         /// <summary>
814         /// Get Button style.
815         /// </summary>
816         /// <returns>The default button style.</returns>
817         /// <since_tizen> 8 </since_tizen>
818         protected override ViewStyle GetViewStyle()
819         {
820             return new ButtonStyle();
821         }
822
823         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
824         [EditorBrowsable(EditorBrowsableState.Never)]
825         protected override void OnUpdate()
826         {
827             base.OnUpdate();
828             UpdateUIContent();
829
830             Extension?.OnRelayout(this);
831         }
832
833         /// <summary>
834         /// Update Button State.
835         /// </summary>
836         /// <param name="touchInfo">The touch information in case the state has changed by touching.</param>
837         /// <since_tizen> 6 </since_tizen>
838         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
839         [EditorBrowsable(EditorBrowsableState.Never)]
840         protected void UpdateState(Touch touchInfo = null)
841         {
842             ControlStates sourceState = ControlState;
843             ControlStates targetState;
844
845             if (isEnabled)
846             {
847                 // Normal
848                 targetState = ControlStates.Normal;
849
850                 // Selected
851                 targetState |= (IsSelected ? ControlStates.Selected : 0);
852
853                 // Pressed, PressedSelected, Focused, SelectedFocused
854                 targetState |= (isPressed ? ControlStates.Pressed : (IsFocused ? ControlStates.Focused : 0));
855             }
856             else
857             {
858                 // Disabled
859                 targetState = ControlStates.Disabled;
860
861                 // DisabledSelected, DisabledFocused
862                 targetState |= (IsSelected ? ControlStates.Selected : (IsFocused ? ControlStates.Focused : 0));
863             }
864
865             if (SetControlState(targetState, touchInfo))
866             {
867                 OnUpdate();
868
869                 StateChangedEventArgs e = new StateChangedEventArgs
870                 {
871                     PreviousState = sourceState,
872                     CurrentState = targetState
873                 };
874                 stateChangeHander?.Invoke(this, e);
875
876                 Extension?.OnControlStateChanged(this, sourceState, touchInfo);
877             }
878         }
879
880         /// <summary>
881         /// It is hijack by using protected, style copy problem when class inherited from Button.
882         /// </summary>
883         /// <since_tizen> 6 </since_tizen>
884         private void Initialize()
885         {
886             var style = (ButtonStyle)Style;
887
888             Extension = style.CreateExtension();
889
890             CreateComponents();
891
892             if (ButtonOverlayImage != null)
893             {
894                 Add(ButtonOverlayImage);
895                 ButtonOverlayImage.ApplyStyle(style.Overlay);
896             }
897
898             if (ButtonIcon != null)
899             {
900                 Add(ButtonIcon);
901                 ButtonIcon.ApplyStyle(style.Icon);
902                 ButtonIcon.Relayout += OnIconRelayout;
903             }
904
905             if (null != ButtonText)
906             {
907                 Add(ButtonText);
908                 ButtonText.ApplyStyle(style.Text);
909             }
910
911             UpdateState();
912
913             LayoutDirectionChanged += OnLayoutDirectionChanged;
914         }
915
916         private void CreateComponents()
917         {
918             ButtonOverlayImage = CreateOverlayImage();
919             ButtonIcon = CreateIcon();
920             ButtonText = CreateText();
921
922             if (Extension == null)
923             {
924                 return;
925             }
926
927             // Update component with extension
928             ButtonOverlayImage = Extension.OnCreateOverlayImage(this, ButtonOverlayImage);
929             ButtonIcon = Extension.OnCreateIcon(this, ButtonIcon);
930             ButtonText = Extension.OnCreateText(this, ButtonText);
931         }
932
933         /// <summary>
934         /// Measure text, it can be override.
935         /// </summary>
936         /// <since_tizen> 6 </since_tizen>
937         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
938         [EditorBrowsable(EditorBrowsableState.Never)]
939         protected virtual void MeasureText()
940         {
941             if (Style.IconRelativeOrientation == null || ButtonIcon == null || ButtonText == null)
942             {
943                 return;
944             }
945             ButtonText.WidthResizePolicy = ResizePolicyType.Fixed;
946             ButtonText.HeightResizePolicy = ResizePolicyType.Fixed;
947             int textPaddingStart = Style.TextPadding.Start;
948             int textPaddingEnd = Style.TextPadding.End;
949             int textPaddingTop = Style.TextPadding.Top;
950             int textPaddingBottom = Style.TextPadding.Bottom;
951
952             int iconPaddingStart = Style.IconPadding.Start;
953             int iconPaddingEnd = Style.IconPadding.End;
954             int iconPaddingTop = Style.IconPadding.Top;
955             int iconPaddingBottom = Style.IconPadding.Bottom;
956
957             if (IconRelativeOrientation == IconOrientation.Top || IconRelativeOrientation == IconOrientation.Bottom)
958             {
959                 ButtonText.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd;
960                 ButtonText.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom - iconPaddingTop - iconPaddingBottom - ButtonIcon.SizeHeight;
961             }
962             else
963             {
964                 ButtonText.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd - iconPaddingStart - iconPaddingEnd - ButtonIcon.SizeWidth;
965                 ButtonText.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom;
966             }
967         }
968         /// <summary>
969         /// Layout child, it can be override.
970         /// </summary>
971         /// <since_tizen> 6 </since_tizen>
972         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
973         [EditorBrowsable(EditorBrowsableState.Never)]
974         protected virtual void LayoutChild()
975         {
976             if (Style.IconRelativeOrientation == null || ButtonIcon == null || ButtonText == null)
977             {
978                 return;
979             }
980
981             var buttonIcon = ButtonIcon;
982             var buttonText = ButtonText;
983
984             int textPaddingStart = Style.TextPadding.Start;
985             int textPaddingEnd = Style.TextPadding.End;
986             int textPaddingTop = Style.TextPadding.Top;
987             int textPaddingBottom = Style.TextPadding.Bottom;
988
989             int iconPaddingStart = Style.IconPadding.Start;
990             int iconPaddingEnd = Style.IconPadding.End;
991             int iconPaddingTop = Style.IconPadding.Top;
992             int iconPaddingBottom = Style.IconPadding.Bottom;
993
994             switch (IconRelativeOrientation)
995             {
996                 case IconOrientation.Top:
997                     buttonIcon.PositionUsesPivotPoint = true;
998                     buttonIcon.ParentOrigin = NUI.ParentOrigin.TopCenter;
999                     buttonIcon.PivotPoint = NUI.PivotPoint.TopCenter;
1000                     buttonIcon.Position2D = new Position2D(0, iconPaddingTop);
1001
1002                     buttonText.PositionUsesPivotPoint = true;
1003                     buttonText.ParentOrigin = NUI.ParentOrigin.BottomCenter;
1004                     buttonText.PivotPoint = NUI.PivotPoint.BottomCenter;
1005                     buttonText.Position2D = new Position2D(0, -textPaddingBottom);
1006                     break;
1007                 case IconOrientation.Bottom:
1008                     buttonIcon.PositionUsesPivotPoint = true;
1009                     buttonIcon.ParentOrigin = NUI.ParentOrigin.BottomCenter;
1010                     buttonIcon.PivotPoint = NUI.PivotPoint.BottomCenter;
1011                     buttonIcon.Position2D = new Position2D(0, -iconPaddingBottom);
1012
1013                     buttonText.PositionUsesPivotPoint = true;
1014                     buttonText.ParentOrigin = NUI.ParentOrigin.TopCenter;
1015                     buttonText.PivotPoint = NUI.PivotPoint.TopCenter;
1016                     buttonText.Position2D = new Position2D(0, textPaddingTop);
1017                     break;
1018                 case IconOrientation.Left:
1019                     if (LayoutDirection == ViewLayoutDirectionType.LTR)
1020                     {
1021                         buttonIcon.PositionUsesPivotPoint = true;
1022                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1023                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
1024                         buttonIcon.Position2D = new Position2D(iconPaddingStart, 0);
1025
1026                         buttonText.PositionUsesPivotPoint = true;
1027                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
1028                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
1029                         buttonText.Position2D = new Position2D(-textPaddingEnd, 0);
1030                     }
1031                     else
1032                     {
1033                         buttonIcon.PositionUsesPivotPoint = true;
1034                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
1035                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
1036                         buttonIcon.Position2D = new Position2D(-iconPaddingStart, 0);
1037
1038                         buttonText.PositionUsesPivotPoint = true;
1039                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1040                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
1041                         buttonText.Position2D = new Position2D(textPaddingEnd, 0);
1042                     }
1043
1044                     break;
1045                 case IconOrientation.Right:
1046                     if (LayoutDirection == ViewLayoutDirectionType.RTL)
1047                     {
1048                         buttonIcon.PositionUsesPivotPoint = true;
1049                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1050                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
1051                         buttonIcon.Position2D = new Position2D(iconPaddingEnd, 0);
1052
1053                         buttonText.PositionUsesPivotPoint = true;
1054                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
1055                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
1056                         buttonText.Position2D = new Position2D(-textPaddingStart, 0);
1057                     }
1058                     else
1059                     {
1060                         buttonIcon.PositionUsesPivotPoint = true;
1061                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
1062                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
1063                         buttonIcon.Position2D = new Position2D(-iconPaddingEnd, 0);
1064
1065                         buttonText.PositionUsesPivotPoint = true;
1066                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1067                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
1068                         buttonText.Position2D = new Position2D(textPaddingStart, 0);
1069                     }
1070                     break;
1071                 default:
1072                     break;
1073             }
1074             if (string.IsNullOrEmpty(buttonText.Text))
1075             {
1076                 buttonIcon.ParentOrigin = NUI.ParentOrigin.Center;
1077                 buttonIcon.PivotPoint = NUI.PivotPoint.Center;
1078             }
1079         }
1080         /// <summary>
1081         /// Theme change callback when theme is changed, this callback will be trigger.
1082         /// </summary>
1083         /// <param name="sender">The sender</param>
1084         /// <param name="e">The event data</param>
1085         /// <since_tizen> 8 </since_tizen>
1086         protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
1087         {
1088             ButtonStyle buttonStyle = StyleManager.Instance.GetViewStyle(style) as ButtonStyle;
1089             if (buttonStyle != null)
1090             {
1091                 Style.CopyFrom(buttonStyle);
1092                 UpdateUIContent();
1093             }
1094         }
1095
1096         private void UpdateUIContent()
1097         {
1098             MeasureText();
1099             LayoutChild();
1100
1101             Sensitive = isEnabled;
1102         }
1103
1104         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
1105         {
1106             MeasureText();
1107             LayoutChild();
1108         }
1109
1110         private void OnClickInternal(ClickEventArgs eventArgs)
1111         {
1112             OnClick(eventArgs);
1113             Extension?.OnClick(this, eventArgs);
1114             ClickEvent?.Invoke(this, eventArgs);
1115         }
1116
1117         private void OnIconRelayout(object sender, EventArgs e)
1118         {
1119             MeasureText();
1120             LayoutChild();
1121         }
1122
1123         /// <summary>
1124         /// ClickEventArgs is a class to record button click event arguments which will sent to user.
1125         /// </summary>
1126         /// <since_tizen> 6 </since_tizen>
1127         public class ClickEventArgs : EventArgs
1128         {
1129         }
1130         /// <summary>
1131         /// StateChangeEventArgs is a class to record button state change event arguments which will sent to user.
1132         /// </summary>
1133         /// <since_tizen> 6 </since_tizen>
1134         public class StateChangedEventArgs : EventArgs
1135         {
1136             /// <summary> previous state of Button </summary>
1137             /// <since_tizen> 6 </since_tizen>
1138             public ControlStates PreviousState;
1139             /// <summary> current state of Button </summary>
1140             /// <since_tizen> 6 </since_tizen>
1141             public ControlStates CurrentState;
1142         }
1143
1144         /// <summary>
1145         /// Get current text part to the attached ButtonExtension.
1146         /// </summary>
1147         /// <remarks>
1148         /// It returns null if the passed extension is invaild.
1149         /// </remarks>
1150         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1151         /// <return>The button's text part.</return>
1152         [EditorBrowsable(EditorBrowsableState.Never)]
1153         public TextLabel GetCurrentText(ButtonExtension extension)
1154         {
1155             return (extension == Extension) ? ButtonText : null;
1156         }
1157
1158         /// <summary>
1159         /// Get current icon part to the attached ButtonExtension.
1160         /// </summary>
1161         /// <remarks>
1162         /// It returns null if the passed extension is invaild.
1163         /// </remarks>
1164         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1165         /// <return>The button's icon part.</return>
1166         [EditorBrowsable(EditorBrowsableState.Never)]
1167         public ImageView GetCurrentIcon(ButtonExtension extension)
1168         {
1169             return (extension == Extension) ? ButtonIcon : null;
1170         }
1171
1172         /// <summary>
1173         /// Get current overlay image part to the attached ButtonExtension.
1174         /// </summary>
1175         /// <remarks>
1176         /// It returns null if the passed extension is invaild.
1177         /// </remarks>
1178         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1179         /// <return>The button's overlay image part.</return>
1180         [EditorBrowsable(EditorBrowsableState.Never)]
1181         public ImageView GetCurrentOverlayImage(ButtonExtension extension)
1182         {
1183             return (extension == Extension) ? ButtonOverlayImage : null;
1184         }
1185     }
1186 }