[NUI] Remove bindings between Style and View (#1788)
[platform/core/csapi/tizenfx.git] / src / Tizen.NUI.Components / Controls / Button.Internal.cs
1 using System;
2 using System.ComponentModel;
3 using Tizen.NUI.BaseComponents;
4 using Tizen.NUI.Components.Extension;
5
6 namespace Tizen.NUI.Components
7 {
8     public partial class Button
9     {
10         private ImageView overlayImage;
11         private TextLabel buttonText;
12         private ImageView buttonIcon;
13
14         private EventHandler<StateChangedEventArgs> stateChangeHandler;
15
16         private bool isPressed = false;
17         private bool styleApplied = false;
18
19         /// <summary>
20         /// The ButtonExtension instance that is injected by ButtonStyle.
21         /// </summary>
22         [EditorBrowsable(EditorBrowsableState.Never)]
23         protected ButtonExtension Extension { get; set; }
24
25         /// <summary>
26         /// Creates Button's text part.
27         /// </summary>
28         /// <return>The created Button's text part.</return>
29         [EditorBrowsable(EditorBrowsableState.Never)]
30         protected virtual TextLabel CreateText()
31         {
32             return new TextLabel();
33         }
34
35         /// <summary>
36         /// Creates Button's icon part.
37         /// </summary>
38         /// <return>The created Button's icon part.</return>
39         [EditorBrowsable(EditorBrowsableState.Never)]
40         protected virtual ImageView CreateIcon()
41         {
42             return new ImageView();
43         }
44
45         /// <summary>
46         /// Creates Button's overlay image part.
47         /// </summary>
48         /// <return>The created Button's overlay image part.</return>
49         [EditorBrowsable(EditorBrowsableState.Never)]
50         protected virtual ImageView CreateOverlayImage()
51         {
52             return new ImageView();
53         }
54
55         /// <summary>
56         /// Called when the Button is Clicked by a user
57         /// </summary>
58         /// <param name="eventArgs">The click information.</param>
59         [EditorBrowsable(EditorBrowsableState.Never)]
60         protected virtual void OnClick(ClickEventArgs eventArgs)
61         {
62         }
63
64         /// <summary>
65         /// Get Button style.
66         /// </summary>
67         /// <returns>The default button style.</returns>
68         /// <since_tizen> 8 </since_tizen>
69         protected override ViewStyle CreateViewStyle()
70         {
71             return new ButtonStyle();
72         }
73
74         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
75         [EditorBrowsable(EditorBrowsableState.Never)]
76         protected override void OnUpdate()
77         {
78             base.OnUpdate();
79             UpdateUIContent();
80
81             Extension?.OnRelayout(this);
82         }
83
84         /// <summary>
85         /// Update Button State.
86         /// </summary>
87         /// <param name="touchInfo">The touch information in case the state has changed by touching.</param>
88         /// <since_tizen> 6 </since_tizen>
89         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
90         [EditorBrowsable(EditorBrowsableState.Never)]
91         protected void UpdateState()
92         {
93             if (!styleApplied) return;
94
95             ControlState sourceState = ControlState;
96             ControlState targetState;
97
98             // Normal, Disabled
99             targetState = IsEnabled ? ControlState.Normal : ControlState.Disabled;
100
101             // Selected, DisabledSelected
102             if (IsSelected) targetState += ControlState.Selected;
103
104             // Pressed, PressedSelected
105             if (isPressed) targetState += ControlState.Pressed;
106
107             // Focused, FocusedPressed, FocusedPressedSelected, DisabledFocused, DisabledSelectedFocused
108             if (IsFocused) targetState += ControlState.Focused;
109
110             if (sourceState != targetState)
111             {
112                 ControlState = targetState;
113                 OnUpdate();
114
115                 StateChangedEventArgs e = new StateChangedEventArgs
116                 {
117                     PreviousState = ControlStatesExtension.FromControlStateClass(sourceState),
118                     CurrentState = ControlStatesExtension.FromControlStateClass(targetState)
119                 };
120                 stateChangeHandler?.Invoke(this, e);
121
122                 Extension?.OnControlStateChanged(this, new ControlStateChangedEventArgs(sourceState, targetState));
123             }
124         }
125
126         /// <summary>
127         /// Measure text, it can be override.
128         /// </summary>
129         /// <since_tizen> 6 </since_tizen>
130         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
131         [EditorBrowsable(EditorBrowsableState.Never)]
132         protected virtual void MeasureText()
133         {
134             if (Icon == null || TextLabel == null)
135             {
136                 return;
137             }
138             TextLabel.WidthResizePolicy = ResizePolicyType.Fixed;
139             TextLabel.HeightResizePolicy = ResizePolicyType.Fixed;
140             int textPaddingStart = buttonStyle.TextPadding.Start;
141             int textPaddingEnd = buttonStyle.TextPadding.End;
142             int textPaddingTop = buttonStyle.TextPadding.Top;
143             int textPaddingBottom = buttonStyle.TextPadding.Bottom;
144
145             int iconPaddingStart = buttonStyle.IconPadding.Start;
146             int iconPaddingEnd = buttonStyle.IconPadding.End;
147             int iconPaddingTop = buttonStyle.IconPadding.Top;
148             int iconPaddingBottom = buttonStyle.IconPadding.Bottom;
149
150             if (IconRelativeOrientation == IconOrientation.Top || IconRelativeOrientation == IconOrientation.Bottom)
151             {
152                 TextLabel.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd;
153                 TextLabel.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom - iconPaddingTop - iconPaddingBottom - Icon.SizeHeight;
154             }
155             else
156             {
157                 TextLabel.SizeWidth = SizeWidth - textPaddingStart - textPaddingEnd - iconPaddingStart - iconPaddingEnd - Icon.SizeWidth;
158                 TextLabel.SizeHeight = SizeHeight - textPaddingTop - textPaddingBottom;
159             }
160         }
161
162         /// <summary>
163         /// Layout child, it can be override.
164         /// </summary>
165         /// <since_tizen> 6 </since_tizen>
166         /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
167         [EditorBrowsable(EditorBrowsableState.Never)]
168         protected virtual void LayoutChild()
169         {
170             if (Icon == null || TextLabel == null)
171             {
172                 return;
173             }
174
175             var buttonIcon = Icon;
176             var buttonText = TextLabel;
177
178             int textPaddingStart = buttonStyle.TextPadding.Start;
179             int textPaddingEnd = buttonStyle.TextPadding.End;
180             int textPaddingTop = buttonStyle.TextPadding.Top;
181             int textPaddingBottom = buttonStyle.TextPadding.Bottom;
182
183             int iconPaddingStart = buttonStyle.IconPadding.Start;
184             int iconPaddingEnd = buttonStyle.IconPadding.End;
185             int iconPaddingTop = buttonStyle.IconPadding.Top;
186             int iconPaddingBottom = buttonStyle.IconPadding.Bottom;
187
188             switch (IconRelativeOrientation)
189             {
190                 case IconOrientation.Top:
191                     buttonIcon.PositionUsesPivotPoint = true;
192                     buttonIcon.ParentOrigin = NUI.ParentOrigin.TopCenter;
193                     buttonIcon.PivotPoint = NUI.PivotPoint.TopCenter;
194                     buttonIcon.Position2D = new Position2D(0, iconPaddingTop);
195
196                     buttonText.PositionUsesPivotPoint = true;
197                     buttonText.ParentOrigin = NUI.ParentOrigin.BottomCenter;
198                     buttonText.PivotPoint = NUI.PivotPoint.BottomCenter;
199                     buttonText.Position2D = new Position2D(0, -textPaddingBottom);
200                     break;
201                 case IconOrientation.Bottom:
202                     buttonIcon.PositionUsesPivotPoint = true;
203                     buttonIcon.ParentOrigin = NUI.ParentOrigin.BottomCenter;
204                     buttonIcon.PivotPoint = NUI.PivotPoint.BottomCenter;
205                     buttonIcon.Position2D = new Position2D(0, -iconPaddingBottom);
206
207                     buttonText.PositionUsesPivotPoint = true;
208                     buttonText.ParentOrigin = NUI.ParentOrigin.TopCenter;
209                     buttonText.PivotPoint = NUI.PivotPoint.TopCenter;
210                     buttonText.Position2D = new Position2D(0, textPaddingTop);
211                     break;
212                 case IconOrientation.Left:
213                     if (LayoutDirection == ViewLayoutDirectionType.LTR)
214                     {
215                         buttonIcon.PositionUsesPivotPoint = true;
216                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
217                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
218                         buttonIcon.Position2D = new Position2D(iconPaddingStart, 0);
219
220                         buttonText.PositionUsesPivotPoint = true;
221                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
222                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
223                         buttonText.Position2D = new Position2D(-textPaddingEnd, 0);
224                     }
225                     else
226                     {
227                         buttonIcon.PositionUsesPivotPoint = true;
228                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
229                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
230                         buttonIcon.Position2D = new Position2D(-iconPaddingStart, 0);
231
232                         buttonText.PositionUsesPivotPoint = true;
233                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
234                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
235                         buttonText.Position2D = new Position2D(textPaddingEnd, 0);
236                     }
237
238                     break;
239                 case IconOrientation.Right:
240                     if (LayoutDirection == ViewLayoutDirectionType.RTL)
241                     {
242                         buttonIcon.PositionUsesPivotPoint = true;
243                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterLeft;
244                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterLeft;
245                         buttonIcon.Position2D = new Position2D(iconPaddingEnd, 0);
246
247                         buttonText.PositionUsesPivotPoint = true;
248                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterRight;
249                         buttonText.PivotPoint = NUI.PivotPoint.CenterRight;
250                         buttonText.Position2D = new Position2D(-textPaddingStart, 0);
251                     }
252                     else
253                     {
254                         buttonIcon.PositionUsesPivotPoint = true;
255                         buttonIcon.ParentOrigin = NUI.ParentOrigin.CenterRight;
256                         buttonIcon.PivotPoint = NUI.PivotPoint.CenterRight;
257                         buttonIcon.Position2D = new Position2D(-iconPaddingEnd, 0);
258
259                         buttonText.PositionUsesPivotPoint = true;
260                         buttonText.ParentOrigin = NUI.ParentOrigin.CenterLeft;
261                         buttonText.PivotPoint = NUI.PivotPoint.CenterLeft;
262                         buttonText.Position2D = new Position2D(textPaddingStart, 0);
263                     }
264                     break;
265                 default:
266                     break;
267             }
268             if (string.IsNullOrEmpty(buttonText.Text))
269             {
270                 buttonIcon.ParentOrigin = NUI.ParentOrigin.Center;
271                 buttonIcon.PivotPoint = NUI.PivotPoint.Center;
272             }
273         }
274
275         /// <summary>
276         /// Theme change callback when theme is changed, this callback will be trigger.
277         /// </summary>
278         /// <param name="sender">The sender</param>
279         /// <param name="e">The event data</param>
280         [EditorBrowsable(EditorBrowsableState.Never)]
281         protected override void OnThemeChangedEvent(object sender, StyleManager.ThemeChangeEventArgs e)
282         {
283             ButtonStyle buttonStyle = StyleManager.Instance.GetViewStyle(StyleName) as ButtonStyle;
284             if (buttonStyle != null)
285             {
286                 ApplyStyle(buttonStyle);
287                 UpdateUIContent();
288             }
289         }
290
291         /// <summary>
292         /// Dispose Button and all children on it.
293         /// </summary>
294         /// <param name="type">Dispose type.</param>
295         /// <since_tizen> 6 </since_tizen>
296         protected override void Dispose(DisposeTypes type)
297         {
298             if (disposed)
299             {
300                 return;
301             }
302
303             if (type == DisposeTypes.Explicit)
304             {
305                 Extension?.OnDispose(this);
306
307                 if (Icon != null)
308                 {
309                     Utility.Dispose(Icon);
310                 }
311                 if (TextLabel != null)
312                 {
313                     Utility.Dispose(TextLabel);
314                 }
315                 if (OverlayImage != null)
316                 {
317                     Utility.Dispose(OverlayImage);
318                 }
319             }
320
321             base.Dispose(type);
322         }
323
324         /// <inheritdoc/>
325         [EditorBrowsable(EditorBrowsableState.Never)]
326         protected override void OnControlStateChanged(ControlStateChangedEventArgs controlStateChangedInfo)
327         {
328             base.OnControlStateChanged(controlStateChangedInfo);
329
330             var stateEnabled = !controlStateChangedInfo.CurrentState.Contains(ControlState.Disabled);
331
332             if (IsEnabled != stateEnabled)
333             {
334                 IsEnabled = stateEnabled;
335             }
336
337             var statePressed = controlStateChangedInfo.CurrentState.Contains(ControlState.Pressed);
338
339             if (isPressed != statePressed)
340             {
341                 isPressed = statePressed;
342             }
343         }
344
345         /// <summary>
346         /// It is hijack by using protected, style copy problem when class inherited from Button.
347         /// </summary>
348         /// <since_tizen> 6 </since_tizen>
349         private void Initialize()
350         {
351             EnableControlStatePropagation = true;
352             UpdateState();
353             LayoutDirectionChanged += OnLayoutDirectionChanged;
354         }
355
356         private void UpdateUIContent()
357         {
358             MeasureText();
359             LayoutChild();
360
361             Sensitive = IsEnabled;
362         }
363
364         private void OnLayoutDirectionChanged(object sender, LayoutDirectionChangedEventArgs e)
365         {
366             MeasureText();
367             LayoutChild();
368         }
369
370         private void OnClickInternal(ClickEventArgs eventArgs)
371         {
372             Command?.Execute(CommandParameter);
373             OnClick(eventArgs);
374             Extension?.OnClick(this, eventArgs);
375             ClickEvent?.Invoke(this, eventArgs);
376         }
377
378         private void OnIconRelayout(object sender, EventArgs e)
379         {
380             MeasureText();
381             LayoutChild();
382         }
383
384     }
385 }