feat: use numpad button.

This commit is contained in:
rabbitism
2024-03-10 01:50:20 +08:00
parent 93b55aae5e
commit dd31df874a
9 changed files with 214 additions and 83 deletions

View File

@@ -47,10 +47,5 @@
</Grid> </Grid>
</Border> </Border>
</Grid> </Grid>
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<u:IPv4Box u:NumPad.Attach="True" Width="200" ></u:IPv4Box>
<u:NumericIntUpDown u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></u:NumericIntUpDown>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@@ -0,0 +1,15 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:u="https://irihi.tech/ursa"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Ursa.Demo.Pages.NumPadDemo">
<StackPanel HorizontalAlignment="Left">
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<TextBox u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></TextBox>
<u:IPv4Box u:NumPad.Attach="True" Width="200" ></u:IPv4Box>
<u:NumericIntUpDown u:NumPad.Attach="True" Width="100" Watermark="Invoke NumPad"></u:NumericIntUpDown>
</StackPanel>
</UserControl>

View File

@@ -0,0 +1,14 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
using Avalonia.Markup.Xaml;
namespace Ursa.Demo.Pages;
public partial class NumPadDemo : UserControl
{
public NumPadDemo()
{
InitializeComponent();
}
}

View File

@@ -46,6 +46,7 @@ public class MainViewViewModel : ViewModelBase
MenuKeys.MenuKeyNavMenu => new NavMenuDemoViewModel(), MenuKeys.MenuKeyNavMenu => new NavMenuDemoViewModel(),
MenuKeys.MenuKeyNumberDisplayer => new NumberDisplayerDemoViewModel(), MenuKeys.MenuKeyNumberDisplayer => new NumberDisplayerDemoViewModel(),
MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(), MenuKeys.MenuKeyNumericUpDown => new NumericUpDownDemoViewModel(),
MenuKeys.MenuKeyNumPad => new NumPadDemoViewModel(),
MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(), MenuKeys.MenuKeyPagination => new PaginationDemoViewModel(),
MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(), MenuKeys.MenuKeyRangeSlider => new RangeSliderDemoViewModel(),
MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(), MenuKeys.MenuKeyScrollToButton => new ScrollToButtonDemoViewModel(),

View File

@@ -33,6 +33,7 @@ public class MenuViewModel: ViewModelBase
new() { MenuHeader = "Nav Menu", Key = MenuKeys.MenuKeyNavMenu, Status = "New"}, new() { MenuHeader = "Nav Menu", Key = MenuKeys.MenuKeyNavMenu, Status = "New"},
// new() { MenuHeader = "Number Displayer", Key = MenuKeys.MenuKeyNumberDisplayer, Status = "New" }, // new() { MenuHeader = "Number Displayer", Key = MenuKeys.MenuKeyNumberDisplayer, Status = "New" },
new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown }, new() { MenuHeader = "Numeric UpDown", Key = MenuKeys.MenuKeyNumericUpDown },
new() { MenuHeader = "NumPad", Key = MenuKeys.MenuKeyNumPad, Status = "New" },
new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination }, new() { MenuHeader = "Pagination", Key = MenuKeys.MenuKeyPagination },
new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider }, new() { MenuHeader = "RangeSlider", Key = MenuKeys.MenuKeyRangeSlider },
new() { MenuHeader = "Scroll To", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" }, new() { MenuHeader = "Scroll To", Key = MenuKeys.MenuKeyScrollToButton, Status = "New" },
@@ -71,6 +72,7 @@ public static class MenuKeys
public const string MenuKeyNavMenu = "NavMenu"; public const string MenuKeyNavMenu = "NavMenu";
public const string MenuKeyNumberDisplayer = "NumberDisplayer"; public const string MenuKeyNumberDisplayer = "NumberDisplayer";
public const string MenuKeyNumericUpDown = "NumericUpDown"; public const string MenuKeyNumericUpDown = "NumericUpDown";
public const string MenuKeyNumPad = "NumPad";
public const string MenuKeyPagination = "Pagination"; public const string MenuKeyPagination = "Pagination";
public const string MenuKeyRangeSlider = "RangeSlider"; public const string MenuKeyRangeSlider = "RangeSlider";
public const string MenuKeyScrollToButton = "ScrollToButton"; public const string MenuKeyScrollToButton = "ScrollToButton";

View File

@@ -0,0 +1,6 @@
namespace Ursa.Demo.ViewModels;
public class NumPadDemoViewModel
{
}

View File

@@ -9,73 +9,85 @@
<Border> <Border>
<Border.Styles> <Border.Styles>
<Style Selector="RepeatButton"> <Style Selector="RepeatButton">
<Setter Property="Command" Value="{Binding $parent[u:NumPad].InputNumber}" /> <Setter Property="Command" Value="{Binding $parent[u:NumPad].ProcessClick}" />
<Setter Property="CommandParameter" Value="{Binding $self.Content}" /> <Setter Property="CommandParameter" Value="{Binding $self.Content}" />
<Setter Property="Width" Value="48"/> <Setter Property="Width" Value="48" />
<Setter Property="Height" Value="48"/> <Setter Property="Height" Value="48" />
</Style>
<Style Selector="u|NumPadButton">
<Setter Property="NumMode" Value="{Binding $parent[u:NumPad].NumMode}" />
<Setter Property="Command" Value="{Binding $parent[u:NumPad].ProcessClick}" />
<Setter Property="Focusable" Value="False"></Setter>
<Setter Property="CommandParameter" Value="{Binding $self}" />
<Setter Property="Width" Value="54" />
<Setter Property="Height" Value="54" />
</Style> </Style>
</Border.Styles> </Border.Styles>
<Grid ColumnDefinitions="*,*,*" RowDefinitions="*,*,*,*"> <Grid ColumnDefinitions="*,*,*,*" RowDefinitions="*,*,*,*,*">
<RepeatButton <ToggleButton
Grid.Row="0" Grid.Row="0"
Grid.Column="0" Grid.Column="0"
Content="7" Width="54"
Focusable="False" /> Focusable="False"
<RepeatButton Height="54"
Padding="0"
IsChecked="{TemplateBinding NumMode,
Mode=TwoWay}">
<TextBlock>
<Run Text="Num" />
<LineBreak />
<Run Text="Lock" />
</TextBlock>
</ToggleButton>
<u:NumPadButton
Grid.Row="0" Grid.Row="0"
Grid.Column="1" Grid.Column="1"
Content="8" FunctionContent="/"
Focusable="False" /> NumContent="/"
<RepeatButton NumKey="OemQuestion" />
Grid.Row="0" <u:NumPadButton
Grid.Column="2"
Content="9"
Focusable="False" />
<RepeatButton
Grid.Row="1"
Grid.Column="0"
Content="4"
Focusable="False" />
<RepeatButton
Grid.Row="1" Grid.Row="1"
Grid.Column="1" Grid.Column="1"
Content="5" FunctionContent="Home"
Focusable="False" /> FunctionKey="Home"
<RepeatButton NumContent="7"
Grid.Row="1" NumKey="NumPad7" />
Grid.Column="2"
Content="6"
Focusable="False" />
<RepeatButton
Grid.Row="2"
Grid.Column="0"
Content="1"
Focusable="False" />
<RepeatButton
Grid.Row="2"
Grid.Column="1"
Content="2"
Focusable="False" />
<RepeatButton
Grid.Row="2"
Grid.Column="2"
Content="3"
Focusable="False" />
<RepeatButton
Grid.Row="3"
Grid.ColumnSpan="2"
Grid.Column="0"
Content="0"
Focusable="False" />
<RepeatButton
Grid.Row="3"
Grid.Column="2"
Content="."
Focusable="False" />
</Grid> </Grid>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
</ControlTheme> </ControlTheme>
<ControlTheme x:Key="{x:Type u:NumPadButton}" TargetType="u:NumPadButton">
<Setter Property="Focusable" Value="False" />
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Background" Value="{DynamicResource ButtonDefaultBackground}" />
<Setter Property="CornerRadius" Value="3"/>
<Setter Property="Template">
<ControlTemplate TargetType="u:NumPadButton">
<Border Name="PART_Background" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}">
<Panel>
<ContentPresenter
Name="PART_ContentPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding NumContent}"
IsVisible="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=NumMode}" />
<ContentPresenter
Name="PART_FunctionContentPresenter"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Content="{TemplateBinding FunctionContent}"
IsVisible="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=!NumMode}" />
</Panel>
</Border>
</ControlTemplate>
</Setter>
<Style Selector="^:pointerover /template/ Border#PART_Background">
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPointeroverBackground}"></Setter>
</Style>
<Style Selector="^:pressed /template/ Border#PART_Background">
<Setter Property="Background" Value="{DynamicResource ButtonDefaultPressedBackground}"></Setter>
</Style>
</ControlTheme>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -10,7 +10,6 @@ namespace Ursa.Controls;
public class NumPad: TemplatedControl public class NumPad: TemplatedControl
{ {
private Button? _sevenButton;
public static readonly StyledProperty<InputElement?> TargetProperty = AvaloniaProperty.Register<NumPad, InputElement?>( public static readonly StyledProperty<InputElement?> TargetProperty = AvaloniaProperty.Register<NumPad, InputElement?>(
nameof(Target)); nameof(Target));
@@ -20,6 +19,15 @@ public class NumPad: TemplatedControl
set => SetValue(TargetProperty, value); set => SetValue(TargetProperty, value);
} }
public static readonly StyledProperty<bool> NumModeProperty = AvaloniaProperty.Register<NumPad, bool>(
nameof(NumMode), defaultValue: true);
public bool NumMode
{
get => GetValue(NumModeProperty);
set => SetValue(NumModeProperty, value);
}
public static readonly AttachedProperty<bool> AttachProperty = public static readonly AttachedProperty<bool> AttachProperty =
AvaloniaProperty.RegisterAttached<NumPad, InputElement, bool>("Attach"); AvaloniaProperty.RegisterAttached<NumPad, InputElement, bool>("Attach");
@@ -28,8 +36,7 @@ public class NumPad: TemplatedControl
static NumPad() static NumPad()
{ {
TargetProperty.Changed.AddClassHandler<NumPad, InputElement?>((n, args) => n.OnTargetChanged(args)); AttachProperty.Changed.AddClassHandler<InputElement, bool>(OnAttachNumPad);
AttachProperty.Changed.AddClassHandler<InputElement, bool>((input, args)=> OnAttachNumPad(input, args));
} }
private static void OnAttachNumPad(InputElement input, AvaloniaPropertyChangedEventArgs<bool> args) private static void OnAttachNumPad(InputElement input, AvaloniaPropertyChangedEventArgs<bool> args)
@@ -44,12 +51,6 @@ public class NumPad: TemplatedControl
} }
} }
private void OnTargetChanged(AvaloniaPropertyChangedEventArgs<InputElement?> args)
{
//GotFocusEvent.RemoveHandler(OnTargetGotFocus, args.OldValue.Value);
//GotFocusEvent.AddHandler(OnTargetGotFocus, args.NewValue.Value);
}
private static void OnTargetGotFocus(object sender, GotFocusEventArgs e) private static void OnTargetGotFocus(object sender, GotFocusEventArgs e)
{ {
if (sender is not InputElement) return; if (sender is not InputElement) return;
@@ -63,23 +64,54 @@ public class NumPad: TemplatedControl
OverlayDialog.Show(numPad, new object(), options: new OverlayDialogOptions() { Buttons = DialogButton.None }); OverlayDialog.Show(numPad, new object(), options: new OverlayDialogOptions() { Buttons = DialogButton.None });
} }
private void OnSevenButtonClick(object sender, RoutedEventArgs e) private Dictionary<Key, string> _keyInputMapping = new()
{
[Key.NumPad0] = "0",
[Key.NumPad1] = "1",
[Key.NumPad2] = "2",
[Key.NumPad3] = "3",
[Key.NumPad4] = "4",
[Key.NumPad5] = "5",
[Key.NumPad6] = "6",
[Key.NumPad7] = "7",
[Key.NumPad8] = "8",
[Key.NumPad9] = "9",
[Key.OemPlus] = "+",
[Key.OemMinus] = "-",
};
public void ProcessClick(object o)
{
if (o is NumPadButton b)
{
if (b is { NumMode: true, NumKey: not null })
{ {
Target?.RaiseEvent(new TextInputEventArgs() Target?.RaiseEvent(new TextInputEventArgs()
{ {
Source = this, Source = this,
RoutedEvent = TextInputEvent, RoutedEvent = TextInputEvent,
Text = "7", Text = _keyInputMapping.TryGetValue(b.NumKey.Value, out var text)? text:string.Empty,
}); });
} }
else if (b is { NumMode: false, FunctionKey: null, NumKey: not null })
{
Target?.RaiseEvent(new TextInputEventArgs()
{
Source = this,
RoutedEvent = TextInputEvent,
Text = _keyInputMapping.TryGetValue(b.NumKey.Value, out var text)? text:string.Empty,
});
}
else
{
Target?.RaiseEvent(new KeyEventArgs()
{
Source = this,
RoutedEvent = KeyDownEvent,
Key = b.FunctionKey ?? Key.None,
});
}
}
public void InputNumber(object o)
{
Target?.RaiseEvent(new TextInputEventArgs()
{
Source = this,
RoutedEvent = TextInputEvent,
Text = o.ToString(),
});
} }
} }

View File

@@ -0,0 +1,54 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Input;
namespace Ursa.Controls;
public class NumPadButton: RepeatButton
{
public static readonly StyledProperty<Key?> NumKeyProperty = AvaloniaProperty.Register<NumPadButton, Key?>(
nameof(NumKey));
public Key? NumKey
{
get => GetValue(NumKeyProperty);
set => SetValue(NumKeyProperty, value);
}
public static readonly StyledProperty<Key?> FunctionKeyProperty = AvaloniaProperty.Register<NumPadButton, Key?>(
nameof(FunctionKey));
public Key? FunctionKey
{
get => GetValue(FunctionKeyProperty);
set => SetValue(FunctionKeyProperty, value);
}
public static readonly StyledProperty<bool> NumModeProperty = AvaloniaProperty.Register<NumPadButton, bool>(
nameof(NumMode));
public bool NumMode
{
get => GetValue(NumModeProperty);
set => SetValue(NumModeProperty, value);
}
public static readonly StyledProperty<object?> NumContentProperty = AvaloniaProperty.Register<NumPadButton, object?>(
nameof(NumContent));
public object? NumContent
{
get => GetValue(NumContentProperty);
set => SetValue(NumContentProperty, value);
}
public static readonly StyledProperty<object?> FunctionContentProperty = AvaloniaProperty.Register<NumPadButton, object?>(
nameof(FunctionContent));
public object? FunctionContent
{
get => GetValue(FunctionContentProperty);
set => SetValue(FunctionContentProperty, value);
}
}