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