feat: add style.

This commit is contained in:
rabbitism
2023-02-24 23:57:41 +08:00
parent 573e3ada21
commit db4db9f1fe
9 changed files with 167 additions and 48 deletions

View File

@@ -10,7 +10,7 @@
mc:Ignorable="d"> mc:Ignorable="d">
<StackPanel HorizontalAlignment="Left"> <StackPanel HorizontalAlignment="Left">
<u:IPv4Box Name="box" Width="200" /> <u:IPv4Box Name="box" Width="200" />
<u:IPv4Box /> <u:IPv4Box Width="200" IsEnabled="False" />
<TextBlock Text="IP: " /> <TextBlock Text="IP: " />
<TextBlock Text="{Binding #box.IPAddress}" /> <TextBlock Text="{Binding #box.IPAddress}" />
</StackPanel> </StackPanel>

View File

@@ -10,78 +10,96 @@
</Design.PreviewWith> </Design.PreviewWith>
<ControlTheme x:Key="{x:Type u:IPv4Box}" TargetType="{x:Type u:IPv4Box}"> <ControlTheme x:Key="{x:Type u:IPv4Box}" TargetType="{x:Type u:IPv4Box}">
<Setter Property="u:IPv4Box.Focusable" Value="True" /> <Setter Property="u:IPv4Box.Focusable" Value="True" />
<Setter Property="u:IPv4Box.ShowLeadingZero" Value="True" />
<Setter Property="u:IPv4Box.TextAlignment" Value="Center" />
<Setter Property="u:IPv4Box.HorizontalAlignment" Value="Left" /> <Setter Property="u:IPv4Box.HorizontalAlignment" Value="Left" />
<Setter Property="u:IPv4Box.CornerRadius" Value="{DynamicResource IPv4BoxCornerRadius}" />
<Setter Property="u:IPv4Box.Background" Value="{DynamicResource IPv4BoxBackground}" />
<Setter Property="u:IPv4Box.MinHeight" Value="{DynamicResource IPv4BoxDefaultMinHeight}" />
<Setter Property="u:IPv4Box.BorderThickness" Value="{DynamicResource IPv4BoxBorderThickness}" />
<Setter Property="u:IPv4Box.SelectionBrush" Value="{DynamicResource IPv4BoxSelectionBrush}" />
<Setter Property="u:IPv4Box.SelectionForegroundBrush" Value="{DynamicResource IPv4BoxSelectionForeground}" />
<Setter Property="u:IPv4Box.CaretBrush" Value="{DynamicResource IPv4BoxCaretBrush}" />
<Setter Property="u:IPv4Box.Template"> <Setter Property="u:IPv4Box.Template">
<ControlTemplate TargetType="u:IPv4Box"> <ControlTemplate TargetType="u:IPv4Box">
<Border <Border
Name="PART_Border" Name="PART_Border"
MinHeight="30" Background="{TemplateBinding Background}"
HorizontalAlignment="{TemplateBinding HorizontalAlignment}" BorderBrush="{TemplateBinding BorderBrush}"
Background="Transparent" BorderThickness="{TemplateBinding BorderThickness}"
BorderBrush="Black" CornerRadius="{TemplateBinding CornerRadius}">
BorderThickness="1"
CornerRadius="3">
<Grid Width="{TemplateBinding Width}" ColumnDefinitions="1*, Auto, 1*, Auto, 1*, Auto, 1*"> <Grid Width="{TemplateBinding Width}" ColumnDefinitions="1*, Auto, 1*, Auto, 1*, Auto, 1*">
<TextPresenter <TextPresenter
Name="{x:Static u:IPv4Box.PART_FirstTextPresenter}" Name="{x:Static u:IPv4Box.PART_FirstTextPresenter}"
Grid.Column="0" Grid.Column="0"
MinWidth="5" MinWidth="8"
VerticalAlignment="Center" VerticalAlignment="Center"
CaretBrush="{TemplateBinding CaretBrush}"
Cursor="IBeam" Cursor="IBeam"
SelectionBrush="Blue" SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionForegroundBrush="White" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="123" TextAlignment="{TemplateBinding TextAlignment}" />
TextAlignment="Center" />
<TextBlock <TextBlock
Grid.Column="1" Grid.Column="1"
Margin="0,4" Margin="0,4"
VerticalAlignment="Bottom" VerticalAlignment="Center"
Focusable="False" Focusable="False"
Text="." /> Text="." />
<TextPresenter <TextPresenter
Name="{x:Static u:IPv4Box.PART_SecondTextPresenter}" Name="{x:Static u:IPv4Box.PART_SecondTextPresenter}"
Grid.Column="2" Grid.Column="2"
MinWidth="5" MinWidth="8"
VerticalAlignment="Center" VerticalAlignment="Center"
CaretBrush="{TemplateBinding CaretBrush}"
Cursor="IBeam" Cursor="IBeam"
SelectionBrush="Blue" SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionForegroundBrush="White" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
Text="123" TextAlignment="{TemplateBinding TextAlignment}" />
TextAlignment="Center" />
<TextBlock <TextBlock
Grid.Column="3" Grid.Column="3"
Margin="0,4" Margin="0,4"
VerticalAlignment="Bottom" VerticalAlignment="Center"
Text="." /> Text="." />
<TextPresenter <TextPresenter
Name="{x:Static u:IPv4Box.PART_ThirdTextPresenter}" Name="{x:Static u:IPv4Box.PART_ThirdTextPresenter}"
Grid.Column="4" Grid.Column="4"
MinWidth="5" MinWidth="8"
VerticalAlignment="Center" VerticalAlignment="Center"
CaretBrush="{TemplateBinding CaretBrush}"
Cursor="IBeam" Cursor="IBeam"
SelectionBrush="Blue" SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionForegroundBrush="White" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
TextAlignment="Center" /> TextAlignment="{TemplateBinding TextAlignment}" />
<TextBlock <TextBlock
Grid.Column="5" Grid.Column="5"
Margin="0,4" Margin="0,4"
VerticalAlignment="Bottom" VerticalAlignment="Center"
Text="." /> Text="." />
<TextPresenter <TextPresenter
Name="{x:Static u:IPv4Box.PART_FourthTextPresenter}" Name="{x:Static u:IPv4Box.PART_FourthTextPresenter}"
Grid.Column="6" Grid.Column="6"
MinWidth="5" MinWidth="8"
VerticalAlignment="Center" VerticalAlignment="Center"
CaretBrush="{TemplateBinding CaretBrush}"
Cursor="IBeam" Cursor="IBeam"
SelectionBrush="Blue" SelectionBrush="{TemplateBinding SelectionBrush}"
SelectionForegroundBrush="White" SelectionForegroundBrush="{TemplateBinding SelectionForegroundBrush}"
TextAlignment="Center" /> TextAlignment="{TemplateBinding TextAlignment}" />
</Grid> </Grid>
</Border> </Border>
</ControlTemplate> </ControlTemplate>
</Setter> </Setter>
<Style Selector="^:focus-within /template/ Border#PART_Border"> <Style Selector="^:pointerover /template/ Border#PART_Border">
<Setter Property="BorderBrush" Value="Red" /> <Setter Property="Border.Background" Value="{DynamicResource IPv4BoxPointeroverBackground}" />
</Style>
<Style Selector="^:pressed /template/ Border#PART_Border">
<Setter Property="Border.Background" Value="{DynamicResource IPv4BoxPressedBackground}" />
</Style>
<Style Selector="^:focus-within">
<Setter Property="Border.BorderBrush" Value="{DynamicResource IPv4BoxFocusBorderBrush}" />
</Style>
<Style Selector="^:disabled">
<Setter Property="Border.Background" Value="{DynamicResource IPv4BoxDisabledBackground}" />
</Style> </Style>
</ControlTheme> </ControlTheme>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -0,0 +1,12 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="IPv4BoxBackground" Opacity="0.12" Color="White" />
<SolidColorBrush x:Key="IPv4BoxPointeroverBackground" Opacity="0.16" Color="White" />
<SolidColorBrush x:Key="IPv4BoxPressedBackground" Opacity="0.2" Color="White" />
<SolidColorBrush x:Key="IPv4BoxBorderBrush" Color="Transparent" />
<SolidColorBrush x:Key="IPv4BoxDisabledBackground" Opacity="0.04" Color="#E6E8EA" />
<SolidColorBrush x:Key="IPv4BoxFocusBorderBrush" Color="#FF54A9FF" />
<SolidColorBrush x:Key="IPv4BoxSelectionBrush" Color="#FF54A9FF" />
<SolidColorBrush x:Key="IPv4BoxSelectionForeground" Color="White" />
<SolidColorBrush x:Key="IPv4BoxCaretBrush" Color="White" />
</ResourceDictionary>

View File

@@ -3,5 +3,6 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="Badge.axaml" /> <ResourceInclude Source="Badge.axaml" />
<ResourceInclude Source="Banner.axaml" /> <ResourceInclude Source="Banner.axaml" />
<ResourceInclude Source="IPv4Box.axaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -0,0 +1,12 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<SolidColorBrush x:Key="IPv4BoxBackground" Opacity="0.05" Color="#FF2E3238" />
<SolidColorBrush x:Key="IPv4BoxPointeroverBackground" Opacity="0.09" Color="#FF2E3238" />
<SolidColorBrush x:Key="IPv4BoxPressedBackground" Opacity="0.13" Color="#FF2E3238" />
<SolidColorBrush x:Key="IPv4BoxBorderBrush" Color="Transparent" />
<SolidColorBrush x:Key="IPv4BoxDisabledBackground" Opacity="0.04" Color="#2E3238" />
<SolidColorBrush x:Key="IPv4BoxFocusBorderBrush" Color="#FF0077FA" />
<SolidColorBrush x:Key="IPv4BoxSelectionBrush" Color="#FF0077FA" />
<SolidColorBrush x:Key="IPv4BoxSelectionForeground" Color="White" />
<SolidColorBrush x:Key="IPv4BoxCaretBrush" Color="Black" />
</ResourceDictionary>

View File

@@ -3,5 +3,6 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="Badge.axaml" /> <ResourceInclude Source="Badge.axaml" />
<ResourceInclude Source="Banner.axaml" /> <ResourceInclude Source="Banner.axaml" />
<ResourceInclude Source="IPv4Box.axaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -0,0 +1,8 @@
<ResourceDictionary xmlns="https://github.com/avaloniaui" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<!-- Add Resources Here -->
<x:Double x:Key="IPv4BoxDefaultMinHeight">32</x:Double>
<x:Double x:Key="IPv4BoxSmallMinHeight">24</x:Double>
<x:Double x:Key="IPv4BoxLargeMinHeight">40</x:Double>
<Thickness x:Key="IPv4BoxBorderThickness">1</Thickness>
<CornerRadius x:Key="IPv4BoxCornerRadius">3</CornerRadius>
</ResourceDictionary>

View File

@@ -3,5 +3,6 @@
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceInclude Source="Badge.axaml" /> <ResourceInclude Source="Badge.axaml" />
<ResourceInclude Source="Banner.axaml" /> <ResourceInclude Source="Banner.axaml" />
<ResourceInclude Source="IPv4Box.axaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
</ResourceDictionary> </ResourceDictionary>

View File

@@ -8,6 +8,7 @@ using Avalonia.Controls.Primitives;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Input.Platform; using Avalonia.Input.Platform;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Media.TextFormatting; using Avalonia.Media.TextFormatting;
namespace Ursa.Controls; namespace Ursa.Controls;
@@ -43,6 +44,60 @@ public class IPv4Box: TemplatedControl
set => SetValue(IPAddressProperty, value); set => SetValue(IPAddressProperty, value);
} }
public static readonly StyledProperty<TextAlignment> TextAlignmentProperty =
TextBox.TextAlignmentProperty.AddOwner<IPv4Box>();
public TextAlignment TextAlignment
{
get => GetValue(TextAlignmentProperty);
set => SetValue(TextAlignmentProperty, value);
}
public static readonly StyledProperty<IBrush?> SelectionBrushProperty =
TextBox.SelectionBrushProperty.AddOwner<IPv4Box>();
public IBrush? SelectionBrush
{
get => GetValue(SelectionBrushProperty);
set => SetValue(SelectionBrushProperty, value);
}
public static readonly StyledProperty<IBrush?> SelectionForegroundBrushProperty =
TextBox.SelectionForegroundBrushProperty.AddOwner<IPv4Box>();
public IBrush? SelectionForegroundBrush
{
get => GetValue(SelectionForegroundBrushProperty);
set => SetValue(SelectionForegroundBrushProperty, value);
}
public static readonly StyledProperty<IBrush?> CaretBrushProperty = TextBox.CaretBrushProperty.AddOwner<IPv4Box>();
public IBrush? CaretBrush
{
get => GetValue(CaretBrushProperty);
set => SetValue(CaretBrushProperty, value);
}
public static readonly StyledProperty<bool> ShowLeadingZeroProperty = AvaloniaProperty.Register<IPv4Box, bool>(
nameof(ShowLeadingZero));
public bool ShowLeadingZero
{
get => GetValue(ShowLeadingZeroProperty);
set => SetValue(ShowLeadingZeroProperty, value);
}
static IPv4Box()
{
ShowLeadingZeroProperty.Changed.AddClassHandler<IPv4Box>((o, e) => o.OnFormatChange(e));
}
private void OnFormatChange(AvaloniaPropertyChangedEventArgs arg)
{
bool showLeadingZero = arg.GetNewValue<bool>();
ParseBytes(showLeadingZero);
}
protected override void OnApplyTemplate(TemplateAppliedEventArgs e) protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
{ {
base.OnApplyTemplate(e); base.OnApplyTemplate(e);
@@ -62,7 +117,7 @@ public class IPv4Box: TemplatedControl
bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e)); bool Match(List<KeyGesture> gestures) => gestures.Any(g => g.Matches(e));
if (e.Key == Key.Enter) if (e.Key == Key.Enter)
{ {
ParseBytes(); ParseBytes(ShowLeadingZero);
SetIPAddress(); SetIPAddress();
return; return;
} }
@@ -83,7 +138,6 @@ public class IPv4Box: TemplatedControl
} }
MoveToNextPresenter(_currentActivePresenter, true); MoveToNextPresenter(_currentActivePresenter, true);
_currentActivePresenter?.ShowCaret(); _currentActivePresenter?.ShowCaret();
SetIPAddress();
e.Handled = true; e.Handled = true;
} }
else if (e.Key == Key.Back) else if (e.Key == Key.Back)
@@ -104,6 +158,7 @@ public class IPv4Box: TemplatedControl
} }
else else
{ {
ClearSelection(_currentActivePresenter);
_currentActivePresenter.CaretIndex++; _currentActivePresenter.CaretIndex++;
} }
} }
@@ -125,6 +180,7 @@ public class IPv4Box: TemplatedControl
} }
else else
{ {
ClearSelection(_currentActivePresenter);
_currentActivePresenter.CaretIndex--; _currentActivePresenter.CaretIndex--;
} }
} }
@@ -223,10 +279,18 @@ public class IPv4Box: TemplatedControl
{ {
if (presenter?.Bounds.Contains(position)??false) if (presenter?.Bounds.Contains(position)??false)
{ {
presenter?.ShowCaret(); if (e.ClickCount == 1)
_currentActivePresenter = presenter; {
var caretPosition = position.WithX(position.X - presenter.Bounds.X); presenter?.ShowCaret();
presenter?.MoveCaretToPoint(caretPosition); _currentActivePresenter = presenter;
var caretPosition = position.WithX(position.X - presenter.Bounds.X);
presenter?.MoveCaretToPoint(caretPosition);
}
else if (e.ClickCount == 2)
{
SelectAll(presenter);
presenter.CaretIndex = presenter.Text?.Length??0;
}
} }
else else
{ {
@@ -246,26 +310,33 @@ public class IPv4Box: TemplatedControl
ClearSelection(pre); ClearSelection(pre);
} }
_currentActivePresenter = null; _currentActivePresenter = null;
ParseBytes(); ParseBytes(ShowLeadingZero);
SetIPAddress(); SetIPAddress();
} }
private void ParseBytes() private void ParseBytes(bool showLeadingZero)
{ {
string format = showLeadingZero ? "D3" : "";
_firstByte = byte.TryParse(_firstText?.Text, out byte b1) ? b1 : (byte)0; _firstByte = byte.TryParse(_firstText?.Text, out byte b1) ? b1 : (byte)0;
_secondByte = byte.TryParse(_secondText?.Text, out byte b2) ? b2 : (byte)0; _secondByte = byte.TryParse(_secondText?.Text, out byte b2) ? b2 : (byte)0;
_thirdByte = byte.TryParse(_thirdText?.Text, out byte b3) ? b3 : (byte)0; _thirdByte = byte.TryParse(_thirdText?.Text, out byte b3) ? b3 : (byte)0;
_fourthByte = byte.TryParse(_fourthText?.Text, out byte b4) ? b4 : (byte)0; _fourthByte = byte.TryParse(_fourthText?.Text, out byte b4) ? b4 : (byte)0;
if (_firstText != null) _firstText.Text = _firstByte.ToString(); if (_firstText != null) _firstText.Text = _firstByte.ToString(format);
if (_secondText != null) _secondText.Text = _secondByte.ToString(); if (_secondText != null) _secondText.Text = _secondByte.ToString(format);
if (_thirdText != null) _thirdText.Text = _thirdByte.ToString(); if (_thirdText != null) _thirdText.Text = _thirdByte.ToString(format);
if (_fourthText != null) _fourthText.Text = _fourthByte.ToString(); if (_fourthText != null) _fourthText.Text = _fourthByte.ToString(format);
} }
protected override void OnGotFocus(GotFocusEventArgs e) protected override void OnGotFocus(GotFocusEventArgs e)
{ {
_currentActivePresenter = _firstText; _currentActivePresenter = _firstText;
_currentActivePresenter?.ShowCaret(); if (_currentActivePresenter is null)
{
base.OnGotFocus(e);
return;
}
_currentActivePresenter.ShowCaret();
_currentActivePresenter.CaretIndex = 0;
base.OnGotFocus(e); base.OnGotFocus(e);
} }
@@ -347,9 +418,4 @@ public class IPv4Box: TemplatedControl
presenter.Text = newText; presenter.Text = newText;
} }
} }
public async void Cut()
{
}
} }