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 Tizen.NUI.BaseComponents;
21 using Tizen.NUI.Components.Extension;
22 using Tizen.NUI.Accessibility; // To use AccessibilityManager
24 namespace Tizen.NUI.Components
26 public partial class Button
28 private ImageView overlayImage;
29 private TextLabel buttonText;
30 private ImageView buttonIcon;
32 private EventHandler<StateChangedEventArgs> stateChangeHandler;
34 private bool isPressed = false;
35 private bool styleApplied = false;
38 /// Get accessibility name.
40 [EditorBrowsable(EditorBrowsableState.Never)]
41 protected override string AccessibilityGetName()
47 /// Prevents from showing child widgets in AT-SPI tree.
49 [EditorBrowsable(EditorBrowsableState.Never)]
50 protected override bool AccessibilityShouldReportZeroChildren()
56 /// The ButtonExtension instance that is injected by ButtonStyle.
58 [EditorBrowsable(EditorBrowsableState.Never)]
59 protected ButtonExtension Extension { get; set; }
62 /// Creates Button's text part.
64 /// <return>The created Button's text part.</return>
65 [EditorBrowsable(EditorBrowsableState.Never)]
66 protected virtual TextLabel CreateText()
70 HorizontalAlignment = HorizontalAlignment.Center,
71 VerticalAlignment = VerticalAlignment.Center,
72 AccessibilityHighlightable = false,
77 /// Creates Button's icon part.
79 /// <return>The created Button's icon part.</return>
80 [EditorBrowsable(EditorBrowsableState.Never)]
81 protected virtual ImageView CreateIcon()
85 AccessibilityHighlightable = false
90 /// Creates Button's overlay image part.
92 /// <return>The created Button's overlay image part.</return>
93 [EditorBrowsable(EditorBrowsableState.Never)]
94 protected virtual ImageView CreateOverlayImage()
98 PositionUsesPivotPoint = true,
99 ParentOrigin = NUI.ParentOrigin.Center,
100 PivotPoint = NUI.PivotPoint.Center,
101 WidthResizePolicy = ResizePolicyType.FillToParent,
102 HeightResizePolicy = ResizePolicyType.FillToParent,
103 AccessibilityHighlightable = false
108 /// Called when the Button is Clicked by a user
110 /// <param name="eventArgs">The click information.</param>
111 [EditorBrowsable(EditorBrowsableState.Never)]
112 protected virtual void OnClicked(ClickedEventArgs eventArgs)
117 /// Get Button style.
119 /// <returns>The default button style.</returns>
120 /// <since_tizen> 8 </since_tizen>
121 protected override ViewStyle CreateViewStyle()
123 return new ButtonStyle();
126 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
127 [EditorBrowsable(EditorBrowsableState.Never)]
128 protected override void OnUpdate()
131 Extension?.OnRelayout(this);
135 [EditorBrowsable(EditorBrowsableState.Never)]
136 protected override bool HandleControlStateOnTouch(Touch touch)
138 if (!IsEnabled || null == touch)
143 PointStateType state = touch.GetState(0);
147 case PointStateType.Down:
149 Extension?.SetTouchInfo(touch);
152 case PointStateType.Interrupted:
156 case PointStateType.Up:
158 bool clicked = isPressed && IsEnabled;
164 Extension?.SetTouchInfo(touch);
165 IsSelected = !IsSelected;
169 Extension?.SetTouchInfo(touch);
175 ClickedEventArgs eventArgs = new ClickedEventArgs();
176 OnClickedInternal(eventArgs);
184 return base.HandleControlStateOnTouch(touch);
188 /// Update Button State.
190 /// <since_tizen> 6 </since_tizen>
191 /// This will be public opened in tizen_5.5 after ACR done. Before ACR, need to be hidden as inhouse API.
192 [EditorBrowsable(EditorBrowsableState.Never)]
193 protected void UpdateState()
195 if (!styleApplied) return;
197 ControlState sourceState = ControlState;
198 ControlState targetState;
201 targetState = IsEnabled ? ControlState.Normal : ControlState.Disabled;
203 // Selected, DisabledSelected
204 if (IsSelected) targetState += ControlState.Selected;
206 // Pressed, PressedSelected
207 if (isPressed) targetState += ControlState.Pressed;
209 // Focused, FocusedPressed, FocusedPressedSelected, DisabledFocused, DisabledSelectedFocused
210 if (IsFocused) targetState += ControlState.Focused;
212 if (sourceState != targetState)
214 ControlState = targetState;
217 StateChangedEventArgs e = new StateChangedEventArgs
219 PreviousState = ControlStatesExtension.FromControlStateClass(sourceState),
220 CurrentState = ControlStatesExtension.FromControlStateClass(targetState)
222 stateChangeHandler?.Invoke(this, e);
224 Extension?.OnControlStateChanged(this, new ControlStateChangedEventArgs(sourceState, targetState));
229 /// Dispose Button and all children on it.
231 /// <param name="type">Dispose type.</param>
232 /// <since_tizen> 6 </since_tizen>
233 protected override void Dispose(DisposeTypes type)
240 if (type == DisposeTypes.Explicit)
242 Extension?.OnDispose(this);
244 if (buttonIcon != null)
246 Utility.Dispose(buttonIcon);
248 if (buttonText != null)
250 Utility.Dispose(buttonText);
252 if (overlayImage != null)
254 Utility.Dispose(overlayImage);
262 /// Initializes AT-SPI object.
264 [EditorBrowsable(EditorBrowsableState.Never)]
265 public override void OnInitialize()
268 SetAccessibilityConstructor(Role.PushButton);
270 AccessibilityHighlightable = true;
271 EnableControlStatePropagation = true;
273 AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Trait, "Button");
275 buttonText = CreateText();
276 buttonIcon = CreateIcon();
277 buttonText.Relayout += OnTextRelayout;
278 buttonIcon.Relayout += OnIconRelayout;
287 [EditorBrowsable(EditorBrowsableState.Never)]
288 protected override void OnControlStateChanged(ControlStateChangedEventArgs controlStateChangedInfo)
290 base.OnControlStateChanged(controlStateChangedInfo);
292 var stateEnabled = !controlStateChangedInfo.CurrentState.Contains(ControlState.Disabled);
294 if (IsEnabled != stateEnabled)
296 IsEnabled = stateEnabled;
299 var statePressed = controlStateChangedInfo.CurrentState.Contains(ControlState.Pressed);
301 if (isPressed != statePressed)
303 isPressed = statePressed;
308 /// Put sub items (e.g. buttonText, buttonIcon) to the right place.
310 [EditorBrowsable(EditorBrowsableState.Never)]
311 protected virtual void LayoutItems()
313 if (buttonIcon == null || buttonText == null)
318 buttonIcon.Unparent();
319 buttonText.Unparent();
320 overlayImage?.Unparent();
322 if (IconRelativeOrientation == IconOrientation.Left)
324 Layout = new LinearLayout()
326 LinearOrientation = LinearLayout.Orientation.Horizontal,
327 LinearAlignment = LinearLayout.Alignment.Center,
333 else if (IconRelativeOrientation == IconOrientation.Right)
335 Layout = new LinearLayout()
337 LinearOrientation = LinearLayout.Orientation.Horizontal,
338 LinearAlignment = LinearLayout.Alignment.Center,
344 else if (IconRelativeOrientation == IconOrientation.Top)
346 Layout = new LinearLayout()
348 LinearOrientation = LinearLayout.Orientation.Vertical,
349 LinearAlignment = LinearLayout.Alignment.Center,
355 else if (IconRelativeOrientation == IconOrientation.Bottom)
357 Layout = new LinearLayout()
359 LinearOrientation = LinearLayout.Orientation.Vertical,
360 LinearAlignment = LinearLayout.Alignment.Center,
367 if (overlayImage != null)
369 overlayImage.ExcludeLayouting = true;
374 private void OnTextOrIconUpdated()
376 if (buttonIcon == null || buttonText == null)
381 float lengthWithoutText = 0;
383 if (iconPadding == null || buttonIcon.Size.Width == 0 || buttonIcon.Size.Height == 0)
385 buttonIcon.Margin = new Extents(0);
386 lengthWithoutText = buttonIcon.Size.Width;
388 else if (iconRelativeOrientation == IconOrientation.Left || iconRelativeOrientation == IconOrientation.Right)
390 buttonIcon.Margin = new Extents(iconPadding.Start, iconPadding.End, 0, 0);
391 lengthWithoutText = iconPadding.Start + iconPadding.End + buttonIcon.Size.Width;
395 buttonIcon.Margin = new Extents(0, 0, iconPadding.Top, iconPadding.Bottom);
398 if (textPadding == null || buttonText.Size.Width == 0 || buttonText.Size.Height == 0)
400 buttonText.Margin = new Extents(0);
404 if (iconRelativeOrientation == IconOrientation.Left || iconRelativeOrientation == IconOrientation.Right)
406 buttonText.Margin = new Extents(textPadding.Start, textPadding.End, 0, 0);
407 lengthWithoutText += textPadding.Start + textPadding.End;
411 buttonText.Margin = new Extents(0, 0, textPadding.Top, textPadding.Bottom);
415 // If the button has fixed width and the text is not empty, the text should not exceed button boundary.
416 if (WidthSpecification >= 0 && !String.IsNullOrEmpty(buttonText.Text))
418 buttonText.MaximumSize = new Size2D(Math.Max(WidthSpecification - (int)lengthWithoutText, Math.Max((int)buttonText.MinimumSize.Width, 1)), HeightSpecification);
422 private void OnIconRelayout(object sender, EventArgs args)
424 OnTextOrIconUpdated();
427 private void OnTextRelayout(object sender, EventArgs args)
429 OnTextOrIconUpdated();
432 private void OnClickedInternal(ClickedEventArgs eventArgs)
434 Command?.Execute(CommandParameter);
435 OnClicked(eventArgs);
436 Extension?.OnClicked(this, eventArgs);
438 ClickEventArgs nestedEventArgs = new ClickEventArgs();
439 ClickEvent?.Invoke(this, nestedEventArgs);
440 Clicked?.Invoke(this, eventArgs);
443 internal override bool OnAccessibilityActivated()
445 using (var key = new Key())
447 key.State = Key.StateType.Down;
448 key.KeyPressedName = "Return";
454 key.State = Key.StateType.Up;