[NUI] Introduce Button extentions and styles (#1515)
[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                 targetState = isPressed ? ControlStates.Pressed : (IsFocused ? (IsSelected ? ControlStates.SelectedFocused : ControlStates.Focused) : (IsSelected ? ControlStates.Selected : ControlStates.Normal));
848             }
849             else
850             {
851                 targetState = IsSelected ? ControlStates.DisabledSelected : (IsFocused ? ControlStates.DisabledFocused : ControlStates.Disabled);
852             }
853
854             if (SetControlState(targetState, touchInfo))
855             {
856                 OnUpdate();
857
858                 StateChangedEventArgs e = new StateChangedEventArgs
859                 {
860                     PreviousState = sourceState,
861                     CurrentState = targetState
862                 };
863                 stateChangeHander?.Invoke(this, e);
864
865                 Extension?.OnControlStateChanged(this, sourceState, touchInfo);
866             }
867         }
868
869         /// <summary>
870         /// It is hijack by using protected, style copy problem when class inherited from Button.
871         /// </summary>
872         /// <since_tizen> 6 </since_tizen>
873         private void Initialize()
874         {
875             var style = (ButtonStyle)Style;
876
877             Extension = style.CreateExtension();
878
879             CreateComponents();
880
881             if (ButtonOverlayImage != null)
882             {
883                 Add(ButtonOverlayImage);
884                 ButtonOverlayImage.ApplyStyle(style.Overlay);
885             }
886
887             if (ButtonIcon != null)
888             {
889                 Add(ButtonIcon);
890                 ButtonIcon.ApplyStyle(style.Icon);
891                 ButtonIcon.Relayout += OnIconRelayout;
892             }
893
894             if (null != ButtonText)
895             {
896                 Add(ButtonText);
897                 ButtonText.ApplyStyle(style.Text);
898             }
899
900             UpdateState();
901
902             LayoutDirectionChanged += OnLayoutDirectionChanged;
903         }
904
905         private void CreateComponents()
906         {
907             ButtonOverlayImage = CreateOverlayImage();
908             ButtonIcon = CreateIcon();
909             ButtonText = CreateText();
910
911             if (Extension == null)
912             {
913                 return;
914             }
915
916             // Update component with extension
917             ButtonOverlayImage = Extension.OnCreateOverlayImage(this, ButtonOverlayImage);
918             ButtonIcon = Extension.OnCreateIcon(this, ButtonIcon);
919             ButtonText = Extension.OnCreateText(this, ButtonText);
920         }
921
922         /// <summary>
923         /// Measure text, it can be override.
924         /// </summary>
925         /// <since_tizen> 6 </since_tizen>
926         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
927         [EditorBrowsable(EditorBrowsableState.Never)]
928         protected virtual void MeasureText()
929         {
930             if (Style.IconRelativeOrientation == null || ButtonIcon == null || ButtonText == null)
931             {
932                 return;
933             }
934             ButtonText.WidthResizePolicy = ResizePolicyType.Fixed;
935             ButtonText.HeightResizePolicy = ResizePolicyType.Fixed;
936             int textPaddingStart = Style.TextPadding.Start;
937             int textPaddingEnd = Style.TextPadding.End;
938             int textPaddingTop = Style.TextPadding.Top;
939             int textPaddingBottom = Style.TextPadding.Bottom;
940
941             int iconPaddingStart = Style.IconPadding.Start;
942             int iconPaddingEnd = Style.IconPadding.End;
943             int iconPaddingTop = Style.IconPadding.Top;
944             int iconPaddingBottom = Style.IconPadding.Bottom;
945
946             if (IconRelativeOrientation == IconOrientation.Top || IconRelativeOrientation == IconOrientation.Bottom)
947             {
948                 ButtonText.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd;
949                 ButtonText.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom - iconPaddingTop - iconPaddingBottom - ButtonIcon.SizeHeight;
950             }
951             else
952             {
953                 ButtonText.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd - iconPaddingStart - iconPaddingEnd - ButtonIcon.SizeWidth;
954                 ButtonText.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom;
955             }
956         }
957         /// <summary>
958         /// Layout child, it can be override.
959         /// </summary>
960         /// <since_tizen> 6 </since_tizen>
961         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
962         [EditorBrowsable(EditorBrowsableState.Never)]
963         protected virtual void LayoutChild()
964         {
965             if (Style.IconRelativeOrientation == null || ButtonIcon == null || ButtonText == null)
966             {
967                 return;
968             }
969
970             var buttonIcon = ButtonIcon;
971             var buttonText = ButtonText;
972
973             int textPaddingStart = Style.TextPadding.Start;
974             int textPaddingEnd = Style.TextPadding.End;
975             int textPaddingTop = Style.TextPadding.Top;
976             int textPaddingBottom = Style.TextPadding.Bottom;
977
978             int iconPaddingStart = Style.IconPadding.Start;
979             int iconPaddingEnd = Style.IconPadding.End;
980             int iconPaddingTop = Style.IconPadding.Top;
981             int iconPaddingBottom = Style.IconPadding.Bottom;
982
983             switch (IconRelativeOrientation)
984             {
985                 case IconOrientation.Top:
986                     buttonIcon.PositionUsesPivotPoint = true;
987                     buttonIcon.ParentOrigin = NUI.ParentOrigin.TopCenter;
988                     buttonIcon.PivotPoint = NUI.PivotPoint.TopCenter;
989                     buttonIcon.Position2D = new Position2D(0, iconPaddingTop);
990
991                     buttonText.PositionUsesPivotPoint = true;
992                     buttonText.ParentOrigin = NUI.ParentOrigin.BottomCenter;
993                     buttonText.PivotPoint = NUI.PivotPoint.BottomCenter;
994                     buttonText.Position2D = new Position2D(0, -textPaddingBottom);
995                     break;
996                 case IconOrientation.Bottom:
997                     buttonIcon.PositionUsesPivotPoint = true;
998                     buttonIcon.ParentOrigin = NUI.ParentOrigin.BottomCenter;
999                     buttonIcon.PivotPoint = NUI.PivotPoint.BottomCenter;
1000                     buttonIcon.Position2D = new Position2D(0, -iconPaddingBottom);
1001
1002                     buttonText.PositionUsesPivotPoint = true;
1003                     buttonText.ParentOrigin = NUI.ParentOrigin.TopCenter;
1004                     buttonText.PivotPoint = NUI.PivotPoint.TopCenter;
1005                     buttonText.Position2D = new Position2D(0, textPaddingTop);
1006                     break;
1007                 case IconOrientation.Left:
1008                     if (LayoutDirection == ViewLayoutDirectionType.LTR)
1009                     {
1010                         buttonIcon.PositionUsesPivotPoint = true;
1011                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1012                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
1013                         buttonIcon.Position2D = new Position2D(iconPaddingStart, 0);
1014
1015                         buttonText.PositionUsesPivotPoint = true;
1016                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
1017                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
1018                         buttonText.Position2D = new Position2D(-textPaddingEnd, 0);
1019                     }
1020                     else
1021                     {
1022                         buttonIcon.PositionUsesPivotPoint = true;
1023                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
1024                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
1025                         buttonIcon.Position2D = new Position2D(-iconPaddingStart, 0);
1026
1027                         buttonText.PositionUsesPivotPoint = true;
1028                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1029                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
1030                         buttonText.Position2D = new Position2D(textPaddingEnd, 0);
1031                     }
1032
1033                     break;
1034                 case IconOrientation.Right:
1035                     if (LayoutDirection == ViewLayoutDirectionType.RTL)
1036                     {
1037                         buttonIcon.PositionUsesPivotPoint = true;
1038                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1039                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
1040                         buttonIcon.Position2D = new Position2D(iconPaddingEnd, 0);
1041
1042                         buttonText.PositionUsesPivotPoint = true;
1043                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
1044                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
1045                         buttonText.Position2D = new Position2D(-textPaddingStart, 0);
1046                     }
1047                     else
1048                     {
1049                         buttonIcon.PositionUsesPivotPoint = true;
1050                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
1051                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
1052                         buttonIcon.Position2D = new Position2D(-iconPaddingEnd, 0);
1053
1054                         buttonText.PositionUsesPivotPoint = true;
1055                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
1056                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
1057                         buttonText.Position2D = new Position2D(textPaddingStart, 0);
1058                     }
1059                     break;
1060                 default:
1061                     break;
1062             }
1063             if (string.IsNullOrEmpty(buttonText.Text))
1064             {
1065                 buttonIcon.ParentOrigin = NUI.ParentOrigin.Center;
1066                 buttonIcon.PivotPoint = NUI.PivotPoint.Center;
1067             }
1068         }
1069         /// <summary>
1070         /// Theme change callback when theme is changed, this callback will be trigger.
1071         /// </summary>
1072         /// <param name="sender">The sender</param>
1073         /// <param name="e">The event data</param>
1074         /// <since_tizen> 8 </since_tizen>
1075         protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
1076         {
1077             ButtonStyle buttonStyle = StyleManager.Instance.GetViewStyle(style) as ButtonStyle;
1078             if (buttonStyle != null)
1079             {
1080                 Style.CopyFrom(buttonStyle);
1081                 UpdateUIContent();
1082             }
1083         }
1084
1085         private void UpdateUIContent()
1086         {
1087             MeasureText();
1088             LayoutChild();
1089
1090             Sensitive = isEnabled;
1091         }
1092
1093         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
1094         {
1095             MeasureText();
1096             LayoutChild();
1097         }
1098
1099         private void OnClickInternal(ClickEventArgs eventArgs)
1100         {
1101             OnClick(eventArgs);
1102             Extension?.OnClick(this, eventArgs);
1103             ClickEvent?.Invoke(this, eventArgs);
1104         }
1105
1106         private void OnIconRelayout(object sender, EventArgs e)
1107         {
1108             MeasureText();
1109             LayoutChild();
1110         }
1111
1112         /// <summary>
1113         /// ClickEventArgs is a class to record button click event arguments which will sent to user.
1114         /// </summary>
1115         /// <since_tizen> 6 </since_tizen>
1116         public class ClickEventArgs : EventArgs
1117         {
1118         }
1119         /// <summary>
1120         /// StateChangeEventArgs is a class to record button state change event arguments which will sent to user.
1121         /// </summary>
1122         /// <since_tizen> 6 </since_tizen>
1123         public class StateChangedEventArgs : EventArgs
1124         {
1125             /// <summary> previous state of Button </summary>
1126             /// <since_tizen> 6 </since_tizen>
1127             public ControlStates PreviousState;
1128             /// <summary> current state of Button </summary>
1129             /// <since_tizen> 6 </since_tizen>
1130             public ControlStates CurrentState;
1131         }
1132
1133         /// <summary>
1134         /// A Selector class that describes Buttons state by actions.
1135         /// </summary>
1136         [EditorBrowsable(EditorBrowsableState.Never)]
1137         public class ActionSelector<T>
1138         {
1139             /// <summary>
1140             /// Value used when the Button is created.
1141             /// </summary>
1142             [EditorBrowsable(EditorBrowsableState.Never)]
1143             public T OnCreate { get; set; }
1144
1145             /// <summary>
1146             /// Value used when the Button is selected.
1147             /// </summary>
1148             [EditorBrowsable(EditorBrowsableState.Never)]
1149             public T OnSelect { get; set; }
1150
1151             /// <summary>
1152             /// Value used when the Button is unselected.
1153             /// </summary>
1154             [EditorBrowsable(EditorBrowsableState.Never)]
1155             public T OnUnselect { get; set; }
1156
1157             /// <summary>
1158             /// Value used when the Button is disabled.
1159             /// </summary>
1160             [EditorBrowsable(EditorBrowsableState.Never)]
1161             public T OnDisable { get; set; }
1162
1163             /// <summary>
1164             /// Value used when the Button is disabled in selected state.
1165             /// </summary>
1166             [EditorBrowsable(EditorBrowsableState.Never)]
1167             public T OnDisableSelected { get; set; }
1168
1169             /// <summary>
1170             /// Value used when the Button is pressed.
1171             /// </summary>
1172             [EditorBrowsable(EditorBrowsableState.Never)]
1173             public T OnPress { get; set; }
1174
1175             /// <summary>
1176             /// Value used when the Button is pressed in selected state.
1177             /// </summary>
1178             [EditorBrowsable(EditorBrowsableState.Never)]
1179             public T OnPressSelected { get; set; }
1180         }
1181
1182         /// <summary>
1183         /// Get current text part to the attached ButtonExtension.
1184         /// </summary>
1185         /// <remarks>
1186         /// It returns null if the passed extension is invaild.
1187         /// </remarks>
1188         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1189         /// <return>The button's text part.</return>
1190         [EditorBrowsable(EditorBrowsableState.Never)]
1191         public TextLabel GetCurrentText(ButtonExtension extension)
1192         {
1193             return (extension == Extension) ? ButtonText : null;
1194         }
1195
1196         /// <summary>
1197         /// Get current icon part to the attached ButtonExtension.
1198         /// </summary>
1199         /// <remarks>
1200         /// It returns null if the passed extension is invaild.
1201         /// </remarks>
1202         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1203         /// <return>The button's icon part.</return>
1204         [EditorBrowsable(EditorBrowsableState.Never)]
1205         public ImageView GetCurrentIcon(ButtonExtension extension)
1206         {
1207             return (extension == Extension) ? ButtonIcon : null;
1208         }
1209
1210         /// <summary>
1211         /// Get current overlay image part to the attached ButtonExtension.
1212         /// </summary>
1213         /// <remarks>
1214         /// It returns null if the passed extension is invaild.
1215         /// </remarks>
1216         /// <param name="extension">The extension instance that is currently attached to this Button.</param>
1217         /// <return>The button's overlay image part.</return>
1218         [EditorBrowsable(EditorBrowsableState.Never)]
1219         public ImageView GetCurrentOverlayImage(ButtonExtension extension)
1220         {
1221             return (extension == Extension) ? ButtonOverlayImage : null;
1222         }
1223     }
1224 }