A cross-platform UI framework for .NET
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

263 lines
9.0 KiB

using System;
using Avalonia.Controls.Primitives;
using Avalonia.Input;
using Avalonia.Interactivity;
namespace Avalonia.Controls
{
public enum Location
{
Left,
Right
}
/// <summary>
/// Represents a spinner control that includes two Buttons.
/// </summary>
public class ButtonSpinner : Spinner
{
/// <summary>
/// Defines the <see cref="AllowSpin"/> property.
/// </summary>
public static readonly StyledProperty<bool> AllowSpinProperty =
AvaloniaProperty.Register<ButtonSpinner, bool>(nameof(AllowSpin), true);
/// <summary>
/// Defines the <see cref="ShowButtonSpinner"/> property.
/// </summary>
public static readonly StyledProperty<bool> ShowButtonSpinnerProperty =
AvaloniaProperty.Register<ButtonSpinner, bool>(nameof(ShowButtonSpinner), true);
/// <summary>
/// Defines the <see cref="ButtonSpinnerLocation"/> property.
/// </summary>
public static readonly StyledProperty<Location> ButtonSpinnerLocationProperty =
AvaloniaProperty.Register<ButtonSpinner, Location>(nameof(ButtonSpinnerLocation), Location.Right);
private Button _decreaseButton;
/// <summary>
/// Gets or sets the DecreaseButton template part.
/// </summary>
private Button DecreaseButton
{
get { return _decreaseButton; }
set
{
if (_decreaseButton != null)
{
_decreaseButton.Click -= OnButtonClick;
}
_decreaseButton = value;
if (_decreaseButton != null)
{
_decreaseButton.Click += OnButtonClick;
}
}
}
private Button _increaseButton;
/// <summary>
/// Gets or sets the IncreaseButton template part.
/// </summary>
private Button IncreaseButton
{
get
{
return _increaseButton;
}
set
{
if (_increaseButton != null)
{
_increaseButton.Click -= OnButtonClick;
}
_increaseButton = value;
if (_increaseButton != null)
{
_increaseButton.Click += OnButtonClick;
}
}
}
/// <summary>
/// Initializes static members of the <see cref="ButtonSpinner"/> class.
/// </summary>
static ButtonSpinner()
{
AllowSpinProperty.Changed.Subscribe(AllowSpinChanged);
PseudoClass<ButtonSpinner, Location>(ButtonSpinnerLocationProperty, location => location == Location.Left, ":left");
PseudoClass<ButtonSpinner, Location>(ButtonSpinnerLocationProperty, location => location == Location.Right, ":right");
}
/// <summary>
/// Gets or sets a value indicating whether the <see cref="ButtonSpinner"/> should allow to spin.
/// </summary>
public bool AllowSpin
{
get { return GetValue(AllowSpinProperty); }
set { SetValue(AllowSpinProperty, value); }
}
/// <summary>
/// Gets or sets a value indicating whether the spin buttons should be shown.
/// </summary>
public bool ShowButtonSpinner
{
get { return GetValue(ShowButtonSpinnerProperty); }
set { SetValue(ShowButtonSpinnerProperty, value); }
}
/// <summary>
/// Gets or sets current location of the <see cref="ButtonSpinner"/>.
/// </summary>
public Location ButtonSpinnerLocation
{
get { return GetValue(ButtonSpinnerLocationProperty); }
set { SetValue(ButtonSpinnerLocationProperty, value); }
}
/// <inheritdoc />
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
{
IncreaseButton = e.NameScope.Find<Button>("PART_IncreaseButton");
DecreaseButton = e.NameScope.Find<Button>("PART_DecreaseButton");
SetButtonUsage();
}
/// <inheritdoc />
protected override void OnPointerReleased(PointerReleasedEventArgs e)
{
base.OnPointerReleased(e);
Point mousePosition;
if (IncreaseButton != null && IncreaseButton.IsEnabled == false)
{
mousePosition = e.GetPosition(IncreaseButton);
if (mousePosition.X > 0 && mousePosition.X < IncreaseButton.Width &&
mousePosition.Y > 0 && mousePosition.Y < IncreaseButton.Height)
{
e.Handled = true;
}
}
if (DecreaseButton != null && DecreaseButton.IsEnabled == false)
{
mousePosition = e.GetPosition(DecreaseButton);
if (mousePosition.X > 0 && mousePosition.X < DecreaseButton.Width &&
mousePosition.Y > 0 && mousePosition.Y < DecreaseButton.Height)
{
e.Handled = true;
}
}
}
/// <inheritdoc />
protected override void OnKeyDown(KeyEventArgs e)
{
switch (e.Key)
{
case Key.Up:
{
if (AllowSpin)
{
OnSpin(new SpinEventArgs(SpinEvent, SpinDirection.Increase));
e.Handled = true;
}
break;
}
case Key.Down:
{
if (AllowSpin)
{
OnSpin(new SpinEventArgs(SpinEvent, SpinDirection.Decrease));
e.Handled = true;
}
break;
}
case Key.Enter:
{
//Do not Spin on enter Key when spinners have focus
if (((IncreaseButton != null) && (IncreaseButton.IsFocused))
|| ((DecreaseButton != null) && DecreaseButton.IsFocused))
{
e.Handled = true;
}
break;
}
}
}
/// <inheritdoc />
protected override void OnPointerWheelChanged(PointerWheelEventArgs e)
{
base.OnPointerWheelChanged(e);
if (!e.Handled && AllowSpin)
{
if (e.Delta.Y != 0)
{
var spinnerEventArgs = new SpinEventArgs(SpinEvent, (e.Delta.Y < 0) ? SpinDirection.Decrease : SpinDirection.Increase, true);
OnSpin(spinnerEventArgs);
e.Handled = spinnerEventArgs.Handled;
}
}
}
protected override void OnValidSpinDirectionChanged(ValidSpinDirections oldValue, ValidSpinDirections newValue)
{
SetButtonUsage();
}
/// <summary>
/// Called when the <see cref="AllowSpin"/> property value changed.
/// </summary>
/// <param name="oldValue">The old value.</param>
/// <param name="newValue">The new value.</param>
protected virtual void OnAllowSpinChanged(bool oldValue, bool newValue)
{
SetButtonUsage();
}
/// <summary>
/// Called when the <see cref="AllowSpin"/> property value changed.
/// </summary>
/// <param name="e">The event args.</param>
private static void AllowSpinChanged(AvaloniaPropertyChangedEventArgs e)
{
if (e.Sender is ButtonSpinner spinner)
{
var oldValue = (bool)e.OldValue;
var newValue = (bool)e.NewValue;
spinner.OnAllowSpinChanged(oldValue, newValue);
}
}
/// <summary>
/// Disables or enables the buttons based on the valid spin direction.
/// </summary>
private void SetButtonUsage()
{
if (IncreaseButton != null)
{
IncreaseButton.IsEnabled = AllowSpin && ((ValidSpinDirection & ValidSpinDirections.Increase) == ValidSpinDirections.Increase);
}
if (DecreaseButton != null)
{
DecreaseButton.IsEnabled = AllowSpin && ((ValidSpinDirection & ValidSpinDirections.Decrease) == ValidSpinDirections.Decrease);
}
}
/// <summary>
/// Called when user clicks one of the spin buttons.
/// </summary>
/// <param name="sender">The event sender.</param>
/// <param name="e">The event args.</param>
private void OnButtonClick(object sender, RoutedEventArgs e)
{
if (AllowSpin)
{
var direction = sender == IncreaseButton ? SpinDirection.Increase : SpinDirection.Decrease;
OnSpin(new SpinEventArgs(SpinEvent, direction));
}
}
}
}