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