/*
* Copyright(c) 2021 Samsung Electronics Co., Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
using System;
using System.ComponentModel;
using System.Diagnostics;
using Tizen.NUI.BaseComponents;
using Tizen.NUI.Binding;
using Tizen.NUI.Accessibility;
namespace Tizen.NUI.Components
{
///
/// ClickedEventArgs is a class to record button click event arguments which will sent to user.
///
/// 8
public class ClickedEventArgs : EventArgs
{
}
///
/// SelectedChangedEventArgs is a class to record item selected arguments which will sent to user.
///
/// 8
public class SelectedChangedEventArgs : EventArgs
{
/// Selected state
/// 8
public bool IsSelected { get; set; }
}
///
/// Button is one kind of common component, a button clearly describes what action will occur when the user selects it.
/// Button may contain text or an icon.
///
/// 6
public partial class Button : Control
{
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty IconRelativeOrientationProperty = BindableProperty.Create(nameof(IconRelativeOrientation), typeof(IconOrientation?), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
var newIconOrientation = (IconOrientation?)newValue;
if (instance.iconRelativeOrientation != newIconOrientation)
{
instance.iconRelativeOrientation = newIconOrientation;
instance.LayoutItems();
}
},
defaultValueCreator: (bindable) => ((Button)bindable).iconRelativeOrientation
);
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty IsEnabledProperty = BindableProperty.Create(nameof(IsEnabled), typeof(bool), typeof(Button), true, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
if (newValue != null)
{
bool newEnabled = (bool)newValue;
if (instance.isEnabled != newEnabled)
{
instance.isEnabled = newEnabled;
instance.Sensitive = newEnabled;
instance.UpdateState();
}
}
},
defaultValueCreator: (bindable) => ((Button)bindable).isEnabled);
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty IsSelectedProperty = BindableProperty.Create(nameof(IsSelected), typeof(bool), typeof(Button), false, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
if (newValue != null)
{
bool newSelected = (bool)newValue;
if (instance.isSelected != newSelected)
{
instance.isSelected = newSelected;
if (instance.isSelectable)
{
instance.UpdateState();
}
if (Accessibility.Accessibility.IsEnabled && instance.IsHighlighted)
{
instance.EmitAccessibilityStatesChangedEvent(AccessibilityStates.Checked, newSelected);
}
}
}
},
defaultValueCreator: (bindable) =>
{
var instance = (Button)bindable;
return instance.isSelectable && instance.isSelected;
});
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty IsSelectableProperty = BindableProperty.Create(nameof(IsSelectable), typeof(bool), typeof(Button), true, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
if (newValue != null)
{
bool newSelectable = (bool)newValue;
if (instance.isSelectable != newSelectable)
{
instance.isSelectable = newSelectable;
instance.UpdateState();
}
}
},
defaultValueCreator: (bindable) => ((Button)bindable).isSelectable);
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty IconPaddingProperty = BindableProperty.Create(nameof(IconPadding), typeof(Extents), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
if (instance.buttonIcon == null)
{
return;
}
instance.buttonIcon.Padding = (Extents)newValue;
},
defaultValueCreator: (bindable) => ((Button)bindable).buttonIcon?.Padding);
/// This will be public opened in tizen_6.0 after ACR done. Before ACR, need to be hidden as inhouse API.
[EditorBrowsable(EditorBrowsableState.Never)]
public static readonly BindableProperty TextPaddingProperty = BindableProperty.Create(nameof(TextPadding), typeof(Extents), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
if (instance.buttonText == null)
{
return;
}
instance.buttonText.Padding = (Extents)newValue;
},
defaultValueCreator: (bindable) => ((Button)bindable).buttonText?.Padding);
/// The bindable property of ItemAlignment.
[EditorBrowsable(EditorBrowsableState.Never)]
internal static readonly BindableProperty ItemAlignmentProperty = BindableProperty.Create(nameof(ItemAlignment), typeof(LinearLayout.Alignment), typeof(Button), LinearLayout.Alignment.Center, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
var newAlignment = (LinearLayout.Alignment)newValue;
if (instance.itemAlignment != newAlignment)
{
instance.itemAlignment = newAlignment;
instance.LayoutItems();
}
},
defaultValueCreator: (bindable) => ((Button)bindable).itemAlignment);
/// The bindable property of ItemSpacing.
[EditorBrowsable(EditorBrowsableState.Never)]
internal static readonly BindableProperty ItemSpacingProperty = BindableProperty.Create(nameof(ItemSpacing), typeof(Size2D), typeof(Button), null, propertyChanged: (bindable, oldValue, newValue) =>
{
var instance = (Button)bindable;
instance.itemSpacing = (Size2D)newValue;
instance.UpdateSizeAndSpacing();
},
defaultValueCreator: (bindable) => ((Button)bindable).itemSpacing);
private IconOrientation? iconRelativeOrientation = IconOrientation.Left;
private bool isSelected = false;
private bool isSelectable = false;
private bool isEnabled = true;
private Size2D itemSpacing;
private LinearLayout.Alignment itemAlignment = LinearLayout.Alignment.Center;
static Button() { }
///
/// Creates a new instance of a Button.
///
/// 6
public Button() : base()
{
}
///
/// Creates a new instance of a Button with style.
///
/// Create Button by special style defined in UX.
/// 8
public Button(string style) : base(style)
{
}
///
/// Creates a new instance of a Button with style.
///
/// Create Button by style customized by user.
/// 8
public Button(ButtonStyle buttonStyle) : base(buttonStyle)
{
}
///
/// Calculates current states for the button
///
[EditorBrowsable(EditorBrowsableState.Never)]
protected override AccessibilityStates AccessibilityCalculateStates(ulong states)
{
var accessibilityStates = base.AccessibilityCalculateStates(states);
FlagSetter(ref accessibilityStates, AccessibilityStates.Checked, this.IsSelected);
FlagSetter(ref accessibilityStates, AccessibilityStates.Enabled, this.IsEnabled);
return accessibilityStates;
}
///
/// An event for the button clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.
///
/// 6
[Obsolete("Deprecated in API8; Will be removed in API10. Please use Clicked event instead.")]
public event EventHandler ClickEvent;
///
/// An event for the button clicked signal which can be used to subscribe or unsubscribe the event handler provided by the user.
///
/// 8
public event EventHandler Clicked;
///
/// An event for the button state changed signal which can be used to subscribe or unsubscribe the event handler provided by the user.
///
/// 6
[Obsolete("Deprecated in API8; Will be removed in API10. Please use View.ControlStateChangedEvent")]
public event EventHandler StateChangedEvent
{
add
{
stateChangeHandler += value;
}
remove
{
stateChangeHandler -= value;
}
}
///
/// Icon orientation.
///
/// 6
public enum IconOrientation
{
///
/// Top.
///
/// 6
Top,
///
/// Bottom.
///
/// 6
Bottom,
///
/// Left.
///
/// 6
Left,
///
/// Right.
///
/// 6
Right,
}
///
/// Button's icon part.
///
/// 8
public ImageView Icon
{
get => buttonIcon;
internal set
{
buttonIcon = value;
}
}
///
/// Button's overlay image part.
///
/// 8
public ImageView OverlayImage
{
get
{
if (null == overlayImage)
{
overlayImage = CreateOverlayImage();
if (null != Extension)
{
overlayImage = Extension.OnCreateOverlayImage(this, overlayImage);
}
if (null != overlayImage)
{
overlayImage.ExcludeLayouting = true;
Add(overlayImage);
}
}
return overlayImage;
}
internal set
{
overlayImage = value;
}
}
///
/// Button's text part.
///
/// 8
public TextLabel TextLabel
{
get => buttonText;
internal set
{
buttonText = value;
AccessibilityManager.Instance.SetAccessibilityAttribute(this, AccessibilityManager.AccessibilityAttribute.Label, buttonText.Text);
}
}
///
/// The last applied style object copy.
///
///
/// Modifying contents in style may cause unexpected behaviour.
///
/// 8
public ButtonStyle Style => (ButtonStyle)(ViewStyle as ButtonStyle)?.Clone();
///
/// The text of Button.
///
/// 6
public string Text
{
get
{
return GetValue(TextProperty) as string;
}
set
{
SetValue(TextProperty, value);
NotifyPropertyChanged();
}
}
private string InternalText
{
get
{
return TextLabel.Text;
}
set
{
TextLabel.Text = value;
if (Accessibility.Accessibility.IsEnabled && IsHighlighted && String.IsNullOrEmpty(AccessibilityName) && GetAccessibilityNameSignal().Empty())
{
EmitAccessibilityEvent(AccessibilityPropertyChangeEvent.Name);
}
}
}
///
/// Flag to decide Button can be selected or not.
///
/// 6
public bool IsSelectable
{
get
{
return (bool)GetValue(IsSelectableProperty);
}
set
{
SetValue(IsSelectableProperty, value);
}
}
///
/// Translate text string in Button.
///
/// 6
public string TranslatableText
{
get
{
return GetValue(TranslatableTextProperty) as string;
}
set
{
SetValue(TranslatableTextProperty, value);
NotifyPropertyChanged();
}
}
private string InternalTranslatableText
{
get
{
return TextLabel.TranslatableText;
}
set
{
TextLabel.TranslatableText = value;
}
}
///
/// Text point size in Button.
///
/// 6
public float PointSize
{
get
{
return (float)GetValue(PointSizeProperty);
}
set
{
SetValue(PointSizeProperty, value);
NotifyPropertyChanged();
}
}
private float InternalPointSize
{
get
{
return TextLabel.PointSize;
}
set
{
TextLabel.PointSize = value;
}
}
///
/// Text font family in Button.
///
/// 6
public string FontFamily
{
get
{
return GetValue(FontFamilyProperty) as string;
}
set
{
SetValue(FontFamilyProperty, value);
NotifyPropertyChanged();
}
}
private string InternalFontFamily
{
get
{
return TextLabel.FontFamily;
}
set
{
TextLabel.FontFamily = value;
}
}
///
/// Text color in Button.
///
/// 6
public Color TextColor
{
get
{
return GetValue(TextColorProperty) as Color;
}
set
{
SetValue(TextColorProperty, value);
NotifyPropertyChanged();
}
}
private Color InternalTextColor
{
get
{
return TextLabel.TextColor;
}
set
{
TextLabel.TextColor = value;
}
}
///
/// Text horizontal alignment in Button.
///
/// 6
public HorizontalAlignment TextAlignment
{
get
{
return (HorizontalAlignment)GetValue(TextAlignmentProperty);
}
set
{
SetValue(TextAlignmentProperty, value);
NotifyPropertyChanged();
}
}
private HorizontalAlignment InternalTextAlignment
{
get
{
return TextLabel.HorizontalAlignment;
}
set
{
TextLabel.HorizontalAlignment = value;
}
}
///
/// Icon image's resource url in Button.
///
/// 6
public string IconURL
{
get
{
return GetValue(IconURLProperty) as string;
}
set
{
SetValue(IconURLProperty, value);
NotifyPropertyChanged();
}
}
private string InternalIconURL
{
get
{
return Icon.ResourceUrl;
}
set
{
Icon.ResourceUrl = value;
}
}
///
/// Icon image's size in Button.
///
[EditorBrowsable(EditorBrowsableState.Never)]
public Size IconSize
{
get
{
return GetValue(IconSizeProperty) as Size;
}
set
{
SetValue(IconSizeProperty, value);
NotifyPropertyChanged();
}
}
private Size InternalIconSize
{
get => Icon.Size;
set => Icon.Size = value;
}
///
/// Text string selector in Button.
/// Getter returns copied selector value if exist, null otherwise.
/// Thrown when setting null value.
///
/// 6
public StringSelector TextSelector
{
get
{
return GetValue(TextSelectorProperty) as StringSelector;
}
set
{
SetValue(TextSelectorProperty, value);
NotifyPropertyChanged();
}
}
private StringSelector InternalTextSelector
{
get => buttonText?.TextSelector == null ? null : new StringSelector(buttonText.TextSelector);
set
{
if (value == null || buttonText == null)
{
throw new NullReferenceException("Button.TextSelector is null");
}
else
{
buttonText.TextSelector = value;
}
}
}
///
/// Translatable text string selector in Button.
/// Getter returns copied selector value if exist, null otherwise.
///
/// Thrown when setting null value.
/// 6
public StringSelector TranslatableTextSelector
{
get
{
return GetValue(TranslatableTextSelectorProperty) as StringSelector;
}
set
{
SetValue(TranslatableTextSelectorProperty, value);
NotifyPropertyChanged();
}
}
private StringSelector InternalTranslatableTextSelector
{
get => (buttonText?.TranslatableTextSelector == null) ? null : new StringSelector(buttonText.TranslatableTextSelector);
set
{
if (value == null || buttonText == null)
{
throw new NullReferenceException("Button.TranslatableTextSelector is null");
}
else
{
buttonText.TranslatableTextSelector = value;
}
}
}
///
/// Text color selector in Button.
/// Getter returns copied selector value if exist, null otherwise.
///
/// Thrown when setting null value.
/// 6
public ColorSelector TextColorSelector
{
get
{
return GetValue(TextColorSelectorProperty) as ColorSelector;
}
set
{
SetValue(TextColorSelectorProperty, value);
NotifyPropertyChanged();
}
}
private ColorSelector InternalTextColorSelector
{
get => buttonText?.TextColorSelector == null ? null : new ColorSelector(buttonText.TextColorSelector);
set
{
if (value == null || buttonText == null)
{
throw new NullReferenceException("Button.TextColorSelectorProperty is null");
}
else
{
buttonText.TextColorSelector = value;
}
}
}
///
/// Text font size selector in Button.
/// Getter returns copied selector value if exist, null otherwise.
///
/// Thrown when setting null value.
/// 6
public FloatSelector PointSizeSelector
{
get
{
return GetValue(PointSizeSelectorProperty) as FloatSelector;
}
set
{
SetValue(PointSizeSelectorProperty, value);
NotifyPropertyChanged();
}
}
private FloatSelector InternalPointSizeSelector
{
get => buttonText?.PointSizeSelector == null ? null : new FloatSelector(buttonText.PointSizeSelector);
set
{
if (value == null || buttonText == null)
{
throw new NullReferenceException("Button.PointSizeSelector is null");
}
else
{
buttonText.PointSizeSelector = value;
}
}
}
///
/// Icon image's resource url selector in Button.
/// Getter returns copied selector value if exist, null otherwise.
///
/// Thrown when setting null value.
/// 6
public StringSelector IconURLSelector
{
get
{
return GetValue(IconURLSelectorProperty) as StringSelector;
}
set
{
SetValue(IconURLSelectorProperty, value);
NotifyPropertyChanged();
}
}
private StringSelector InternalIconURLSelector
{
get => buttonIcon?.ResourceUrlSelector == null ? null : new StringSelector(buttonIcon.ResourceUrlSelector);
set
{
if (value == null || buttonIcon == null)
{
throw new NullReferenceException("Button.IconURLSelector is null");
}
else
{
buttonIcon.ResourceUrlSelector = value;
}
}
}
///
/// Flag to decide selected state in Button.
///
/// 6
public bool IsSelected
{
get
{
return (bool)GetValue(IsSelectedProperty);
}
set
{
SetValue(IsSelectedProperty, value);
}
}
///
/// Flag to decide enable or disable in Button.
///
/// 6
public bool IsEnabled
{
get
{
return (bool)GetValue(IsEnabledProperty);
}
set
{
SetValue(IsEnabledProperty, value);
}
}
///
/// Icon relative orientation in Button, work only when show icon and text.
///
/// 8
public IconOrientation? IconRelativeOrientation
{
get
{
return (IconOrientation?)GetValue(IconRelativeOrientationProperty) ?? IconOrientation.Left;
}
set
{
SetValue(IconRelativeOrientationProperty, value);
}
}
///
/// Icon padding in Button. It is shortcut of Icon.Padding.
///
/// 6
public Extents IconPadding
{
get => (Extents)GetValue(IconPaddingProperty) ?? new Extents();
set => SetValue(IconPaddingProperty, value);
}
///
/// Text padding in Button. It is shortcut of TextLabel.Padding.
///
/// 6
public Extents TextPadding
{
get => (Extents)GetValue(TextPaddingProperty) ?? new Extents();
set => SetValue(TextPaddingProperty, value);
}
///
/// The item (text or icon or both) alignment.
///
/// 9
public LinearLayout.Alignment ItemAlignment
{
get => (LinearLayout.Alignment)GetValue(ItemAlignmentProperty);
set => SetValue(ItemAlignmentProperty, value);
}
///
/// The space between icon and text.
/// The value is applied when there exist icon and text both.
/// The width value is used when the items are arranged horizontally. Otherwise, the height value is used.
///
/// 9
public Size2D ItemSpacing
{
get => (Size2D)GetValue(ItemSpacingProperty);
set => SetValue(ItemSpacingProperty, value);
}
///
/// Called after a key event is received by the view that has had its focus set.
///
/// The key event.
/// True if the key event should be consumed.
/// 6
public override bool OnKey(Key key)
{
if (!IsEnabled || null == key)
{
return false;
}
if (key.State == Key.StateType.Down)
{
if (key.KeyPressedName == "Return")
{
isPressed = true;
UpdateState();
}
}
else if (key.State == Key.StateType.Up)
{
if (key.KeyPressedName == "Return")
{
bool clicked = isPressed && IsEnabled;
isPressed = false;
if (IsSelectable)
{
IsSelected = !IsSelected;
}
else
{
UpdateState();
}
if (clicked)
{
ClickedEventArgs eventArgs = new ClickedEventArgs();
OnClickedInternal(eventArgs);
}
}
}
return base.OnKey(key);
}
///
/// Called when the control gain key input focus. Should be overridden by derived classes if they need to customize what happens when the focus is gained.
///
/// 8
public override void OnFocusGained()
{
base.OnFocusGained();
UpdateState();
}
///
/// Called when the control loses key input focus. Should be overridden by derived classes if they need to customize what happens when the focus is lost.
///
/// 8
public override void OnFocusLost()
{
base.OnFocusLost();
UpdateState();
}
///
/// Called after a touch event is received by the owning view.
/// CustomViewBehaviour.REQUIRES_TOUCH_EVENTS must be enabled during construction. See CustomView(ViewWrapperImpl.CustomViewBehaviour behaviour).
///
/// The touch event.
/// True if the event should be consumed.
/// 8
[Obsolete("Deprecated in API8; Will be removed in API10. Please use OnClicked instead.")]
#pragma warning disable CS0809 // Obsolete member overrides non-obsolete member, It will be removed in API10
public override bool OnTouch(Touch touch)
#pragma warning restore CS0809 // Obsolete member overrides non-obsolete member, It will be removed in API10
{
return base.OnTouch(touch);
}
///
/// Apply style to button.
///
/// The style to apply.
/// 8
public override void ApplyStyle(ViewStyle viewStyle)
{
Debug.Assert(buttonIcon != null && buttonText != null);
styleApplied = false;
base.ApplyStyle(viewStyle);
if (viewStyle is ButtonStyle buttonStyle)
{
Extension = buttonStyle.CreateExtension();
if (buttonStyle.Overlay != null)
{
OverlayImage?.ApplyStyle(buttonStyle.Overlay);
}
if (Extension != null)
{
buttonIcon.Unparent();
buttonIcon = Extension.OnCreateIcon(this, buttonIcon);
buttonText.Unparent();
buttonText = Extension.OnCreateText(this, buttonText);
LayoutItems();
}
if (buttonStyle.Text != null)
{
buttonText.ThemeChangeSensitive = false;
buttonText.ApplyStyle(buttonStyle.Text);
}
if (buttonStyle.Icon != null)
{
buttonIcon.ApplyStyle(buttonStyle.Icon);
}
}
styleApplied = true;
UpdateState();
}
///
/// ClickEventArgs is a class to record button click event arguments which will sent to user.
///
/// 6
[Obsolete("Deprecated in API8; Will be removed in API10. Please use ClickedEventArgs instead.")]
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
public class ClickEventArgs : EventArgs
{
}
///
/// StateChangeEventArgs is a class to record button state change event arguments which will sent to user.
///
/// 6
[Obsolete("Deprecated in API8; Will be removed in API10. Please use View.ControlStateChangedEventArgs")]
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1034:NestedTypesShouldNotBeVisible")]
public class StateChangedEventArgs : EventArgs
{
/// previous state of Button
/// 6
/// It will be removed in API10
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:Do not declare visible instance fields")]
[Obsolete("Deprecated in API8; Will be removed in API10")]
public ControlStates PreviousState;
/// current state of Button
/// 6
/// It will be removed in API10
[global::System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:Do not declare visible instance fields")]
[Obsolete("Deprecated in API8; Will be removed in API10")]
public ControlStates CurrentState;
}
}
}