2 * Copyright(c) 2021 Samsung Electronics Co., Ltd.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
19 using System.ComponentModel;
20 using System.Diagnostics;
21 using Tizen.NUI.BaseComponents;
22 using Tizen.NUI.Components.Extension;
23 using Tizen.NUI.Accessibility; // To use AccessibilityManager
25 namespace Tizen.NUI.Components
27 public partial class Button
29 private ImageView overlayImage;
30 private TextLabel buttonText;
31 private ImageView buttonIcon;
34 private EventHandler<StateChangedEventArgs> stateChangeHandler;
36 private bool isPressed = false;
37 private bool styleApplied = false;
40 /// Get accessibility name.
42 [EditorBrowsable(EditorBrowsableState.Never)]
43 protected override string AccessibilityGetName()
49 /// Prevents from showing child widgets in AT-SPI tree.
51 [EditorBrowsable(EditorBrowsableState.Never)]
52 protected override bool AccessibilityShouldReportZeroChildren()
58 /// The ButtonExtension instance that is injected by ButtonStyle.
60 [EditorBrowsable(EditorBrowsableState.Never)]
61 protected ButtonExtension Extension { get; set; }
64 /// Creates Button's text part.
66 /// <return>The created Button's text part.</return>
67 [EditorBrowsable(EditorBrowsableState.Never)]
68 protected virtual TextLabel CreateText()
72 HorizontalAlignment = HorizontalAlignment.Center,
73 VerticalAlignment = VerticalAlignment.Center,
74 AccessibilityHighlightable = false
79 /// Creates Button's icon part.
81 /// <return>The created Button's icon part.</return>
82 [EditorBrowsable(EditorBrowsableState.Never)]
83 protected virtual ImageView CreateIcon()
87 AccessibilityHighlightable = false
92 /// Creates Button's overlay image part.
94 /// <return>The created Button's overlay image part.</return>
95 [EditorBrowsable(EditorBrowsableState.Never)]
96 protected virtual ImageView CreateOverlayImage()
100 PositionUsesPivotPoint = true,
101 ParentOrigin = NUI.ParentOrigin.Center,
102 PivotPoint = NUI.PivotPoint.Center,
103 WidthResizePolicy = ResizePolicyType.FillToParent,
104 HeightResizePolicy = ResizePolicyType.FillToParent,
105 AccessibilityHighlightable = false
110 /// Called when the Button is Clicked by a user
112 /// <param name="eventArgs">The click information.</param>
113 [EditorBrowsable(EditorBrowsableState.Never)]
114 protected virtual void OnClicked(ClickedEventArgs eventArgs)
119 /// Get Button style.
121 /// <returns>The default button style.</returns>
122 /// <since_tizen> 8 </since_tizen>
123 protected override ViewStyle CreateViewStyle()
125 return new ButtonStyle();
128 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
129 [EditorBrowsable(EditorBrowsableState.Never)]
130 protected override void OnUpdate()
133 Extension?.OnRelayout(this);
137 [EditorBrowsable(EditorBrowsableState.Never)]
138 protected override bool HandleControlStateOnTouch(Touch touch)
140 if (!IsEnabled || null == touch)
145 PointStateType state = touch.GetState(0);
149 case PointStateType.Down:
151 Extension?.SetTouchInfo(touch);
154 case PointStateType.Interrupted:
158 case PointStateType.Up:
160 bool clicked = isPressed && IsEnabled;
166 Extension?.SetTouchInfo(touch);
167 IsSelected = !IsSelected;
171 Extension?.SetTouchInfo(touch);
177 ClickedEventArgs eventArgs = new ClickedEventArgs();
178 OnClickedInternal(eventArgs);
186 return base.HandleControlStateOnTouch(touch);
190 /// Update Button State.
192 /// <since_tizen> 6 </since_tizen>
193 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
194 [EditorBrowsable(EditorBrowsableState.Never)]
195 protected void UpdateState()
197 if (!styleApplied) return;
199 ControlState sourceState = ControlState;
200 ControlState targetState;
203 targetState = IsEnabled ? ControlState.Normal : ControlState.Disabled;
205 // Selected, DisabledSelected
206 if (IsSelected) targetState += ControlState.Selected;
208 // Pressed, PressedSelected
209 if (isPressed) targetState += ControlState.Pressed;
211 // Focused, FocusedPressed, FocusedPressedSelected, DisabledFocused, DisabledSelectedFocused
212 if (IsFocused) targetState += ControlState.Focused;
214 if (sourceState != targetState)
216 ControlState = targetState;
219 StateChangedEventArgs e = new StateChangedEventArgs
221 PreviousState = ControlStatesExtension.FromControlStateClass(sourceState),
222 CurrentState = ControlStatesExtension.FromControlStateClass(targetState)
224 stateChangeHandler?.Invoke(this, e);
226 Extension?.OnControlStateChanged(this, new ControlStateChangedEventArgs(sourceState, targetState));
231 /// Dispose Button and all children on it.
233 /// <param name="type">Dispose type.</param>
234 /// <since_tizen> 6 </since_tizen>
235 protected override void Dispose(DisposeTypes type)
242 if (type == DisposeTypes.Explicit)
244 Extension?.OnDispose(this);
246 if (buttonIcon != null)
248 Utility.Dispose(buttonIcon);
250 if (buttonText != null)
252 Utility.Dispose(buttonText);
254 if (overlayImage != null)
256 Utility.Dispose(overlayImage);
264 /// Initializes AT-SPI object.
266 [EditorBrowsable(EditorBrowsableState.Never)]
267 public override void OnInitialize()
270 SetAccessibilityConstructor(Role.PushButton);
272 AccessibilityHighlightable = true;
273 EnableControlStatePropagation = true;
275 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "Button");
277 buttonText = CreateText();
278 buttonIcon = CreateIcon();
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 public override void OnRelayout(Vector2 size, RelayoutContainer container)
290 Debug.Assert(size != null);
292 if (size.Equals(this.size))
297 this.size = new Vector2(size);
299 UpdateSizeAndSpacing();
303 [EditorBrowsable(EditorBrowsableState.Never)]
304 protected override void OnControlStateChanged(ControlStateChangedEventArgs controlStateChangedInfo)
306 base.OnControlStateChanged(controlStateChangedInfo);
308 var stateEnabled = !controlStateChangedInfo.CurrentState.Contains(ControlState.Disabled);
310 if (IsEnabled != stateEnabled)
312 IsEnabled = stateEnabled;
315 var statePressed = controlStateChangedInfo.CurrentState.Contains(ControlState.Pressed);
317 if (isPressed != statePressed)
319 isPressed = statePressed;
324 /// Put sub items (e.g. buttonText, buttonIcon) to the right place.
326 [EditorBrowsable(EditorBrowsableState.Never)]
327 protected virtual void LayoutItems()
329 if (buttonIcon == null || buttonText == null)
334 buttonIcon.Unparent();
335 buttonText.Unparent();
336 overlayImage?.Unparent();
338 if (IconRelativeOrientation == IconOrientation.Left)
340 Layout = new LinearLayout()
342 LinearOrientation = LinearLayout.Orientation.Horizontal,
343 LinearAlignment = itemAlignment,
344 CellPadding = itemSpacing ?? new Size2D(0, 0)
350 else if (IconRelativeOrientation == IconOrientation.Right)
352 Layout = new LinearLayout()
354 LinearOrientation = LinearLayout.Orientation.Horizontal,
355 LinearAlignment = itemAlignment,
356 CellPadding = itemSpacing ?? new Size2D(0, 0)
362 else if (IconRelativeOrientation == IconOrientation.Top)
364 Layout = new LinearLayout()
366 LinearOrientation = LinearLayout.Orientation.Vertical,
367 LinearAlignment = itemAlignment,
368 CellPadding = itemSpacing ?? new Size2D(0, 0)
374 else if (IconRelativeOrientation == IconOrientation.Bottom)
376 Layout = new LinearLayout()
378 LinearOrientation = LinearLayout.Orientation.Vertical,
379 LinearAlignment = itemAlignment,
380 CellPadding = itemSpacing ?? new Size2D(0, 0)
387 if (overlayImage != null)
389 overlayImage.ExcludeLayouting = true;
394 private void UpdateSizeAndSpacing()
396 if (size == null || buttonIcon == null || buttonText == null)
401 LinearLayout layout = Layout as LinearLayout;
408 float lengthWithoutText = 0;
409 Size2D cellPadding = null;
410 Extents iconMargin = buttonIcon.Margin ?? new Extents(0);
411 Extents textMargin = buttonText.Margin ?? new Extents(0);
413 if (buttonIcon.Size.Width != 0 && buttonIcon.Size.Height != 0)
415 lengthWithoutText = buttonIcon.Size.Width;
417 if (!String.IsNullOrEmpty(buttonText.Text))
419 cellPadding = itemSpacing;
421 if (iconRelativeOrientation == IconOrientation.Left || iconRelativeOrientation == IconOrientation.Right)
423 lengthWithoutText += (itemSpacing?.Width ?? 0) + iconMargin.Start + iconMargin.End + textMargin.Start + textMargin.End;
427 lengthWithoutText += (itemSpacing?.Height ?? 0) + iconMargin.Top + iconMargin.Bottom + textMargin.Top + textMargin.Bottom;
432 layout.CellPadding = cellPadding ?? new Size2D(0, 0);
434 // If the button has fixed width and the text is not empty, the text should not exceed button boundary.
435 if (WidthSpecification != LayoutParamPolicies.WrapContent && !String.IsNullOrEmpty(buttonText.Text))
437 buttonText.MaximumSize = new Size2D((int)Math.Max(size.Width - lengthWithoutText, Math.Max(buttonText.MinimumSize.Width, 1)), (int)size.Height);
441 private void OnClickedInternal(ClickedEventArgs eventArgs)
443 Command?.Execute(CommandParameter);
444 OnClicked(eventArgs);
445 Extension?.OnClicked(this, eventArgs);
447 ClickEventArgs nestedEventArgs = new ClickEventArgs();
448 ClickEvent?.Invoke(this, nestedEventArgs);
449 Clicked?.Invoke(this, eventArgs);
452 internal override bool OnAccessibilityActivated()
454 using (var key = new Key())
456 key.State = Key.StateType.Down;
457 key.KeyPressedName = "Return";
463 key.State = Key.StateType.Up;