feat: add clock tick.
This commit is contained in:
20
demo/Ursa.Demo/Pages/ClockDemo.axaml
Normal file
20
demo/Ursa.Demo/Pages/ClockDemo.axaml
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<UserControl
|
||||||
|
x:Class="Ursa.Demo.Pages.ClockDemo"
|
||||||
|
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"
|
||||||
|
d:DesignHeight="450"
|
||||||
|
d:DesignWidth="800"
|
||||||
|
mc:Ignorable="d">
|
||||||
|
<Grid>
|
||||||
|
<u:ClockTicks
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
VerticalAlignment="Stretch"
|
||||||
|
HourTickWidth="4"
|
||||||
|
MinuteTickWidth="1"
|
||||||
|
HourTickForeground="Black"
|
||||||
|
MinuteTickForeground="Red" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
13
demo/Ursa.Demo/Pages/ClockDemo.axaml.cs
Normal file
13
demo/Ursa.Demo/Pages/ClockDemo.axaml.cs
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
|
||||||
|
namespace Ursa.Demo.Pages;
|
||||||
|
|
||||||
|
public partial class ClockDemo : UserControl
|
||||||
|
{
|
||||||
|
public ClockDemo()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
6
demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs
Normal file
6
demo/Ursa.Demo/ViewModels/ClockDemoViewModel.cs
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
namespace Ursa.Demo.ViewModels;
|
||||||
|
|
||||||
|
public class ClockDemoViewModel
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
@@ -30,6 +30,7 @@ public class MainViewViewModel : ViewModelBase
|
|||||||
MenuKeys.MenuKeyButtonGroup => new ButtonGroupDemoViewModel(),
|
MenuKeys.MenuKeyButtonGroup => new ButtonGroupDemoViewModel(),
|
||||||
MenuKeys.MenuKeyBreadcrumb => new BreadcrumbDemoViewModel(),
|
MenuKeys.MenuKeyBreadcrumb => new BreadcrumbDemoViewModel(),
|
||||||
MenuKeys.MenuKeyClassInput => new ClassInputDemoViewModel(),
|
MenuKeys.MenuKeyClassInput => new ClassInputDemoViewModel(),
|
||||||
|
MenuKeys.MenuKeyClock => new ClockDemoViewModel(),
|
||||||
MenuKeys.MenuKeyDialog => new DialogDemoViewModel(),
|
MenuKeys.MenuKeyDialog => new DialogDemoViewModel(),
|
||||||
MenuKeys.MenuKeyDivider => new DividerDemoViewModel(),
|
MenuKeys.MenuKeyDivider => new DividerDemoViewModel(),
|
||||||
MenuKeys.MenuKeyDisableContainer => new DisableContainerDemoViewModel(),
|
MenuKeys.MenuKeyDisableContainer => new DisableContainerDemoViewModel(),
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ public class MenuViewModel: ViewModelBase
|
|||||||
new() { MenuHeader = "Breadcrumb", Key = MenuKeys.MenuKeyBreadcrumb, Status = "New" },
|
new() { MenuHeader = "Breadcrumb", Key = MenuKeys.MenuKeyBreadcrumb, Status = "New" },
|
||||||
new() { MenuHeader = "Button Group", Key = MenuKeys.MenuKeyButtonGroup, Status = "Updated" },
|
new() { MenuHeader = "Button Group", Key = MenuKeys.MenuKeyButtonGroup, Status = "Updated" },
|
||||||
new() { MenuHeader = "Class Input", Key = MenuKeys.MenuKeyClassInput },
|
new() { MenuHeader = "Class Input", Key = MenuKeys.MenuKeyClassInput },
|
||||||
|
new() { MenuHeader = "Clock", Key = MenuKeys.MenuKeyClock, Status = "New" },
|
||||||
new() { MenuHeader = "Dialog", Key = MenuKeys.MenuKeyDialog },
|
new() { MenuHeader = "Dialog", Key = MenuKeys.MenuKeyDialog },
|
||||||
new() { MenuHeader = "Disable Container", Key = MenuKeys.MenuKeyDisableContainer },
|
new() { MenuHeader = "Disable Container", Key = MenuKeys.MenuKeyDisableContainer },
|
||||||
new() { MenuHeader = "Divider", Key = MenuKeys.MenuKeyDivider },
|
new() { MenuHeader = "Divider", Key = MenuKeys.MenuKeyDivider },
|
||||||
@@ -59,6 +60,7 @@ public static class MenuKeys
|
|||||||
public const string MenuKeyButtonGroup = "ButtonGroup";
|
public const string MenuKeyButtonGroup = "ButtonGroup";
|
||||||
public const string MenuKeyBreadcrumb= "Breadcrumb";
|
public const string MenuKeyBreadcrumb= "Breadcrumb";
|
||||||
public const string MenuKeyClassInput = "Class Input";
|
public const string MenuKeyClassInput = "Class Input";
|
||||||
|
public const string MenuKeyClock = "Clock";
|
||||||
public const string MenuKeyDialog = "Dialog";
|
public const string MenuKeyDialog = "Dialog";
|
||||||
public const string MenuKeyDivider = "Divider";
|
public const string MenuKeyDivider = "Divider";
|
||||||
public const string MenuKeyDisableContainer = "DisableContainer";
|
public const string MenuKeyDisableContainer = "DisableContainer";
|
||||||
|
|||||||
39
src/Ursa/Controls/Clock/Clock.cs
Normal file
39
src/Ursa/Controls/Clock/Clock.cs
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls.Metadata;
|
||||||
|
using Avalonia.Controls.Primitives;
|
||||||
|
|
||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
[TemplatePart(PART_ClockTicks, typeof(ClockTicks))]
|
||||||
|
public class Clock: TemplatedControl
|
||||||
|
{
|
||||||
|
public const string PART_ClockTicks = "PART_ClockTicks";
|
||||||
|
|
||||||
|
public static readonly StyledProperty<TimeSpan> TimeProperty = AvaloniaProperty.Register<Clock, TimeSpan>(
|
||||||
|
nameof(Time));
|
||||||
|
|
||||||
|
public TimeSpan Time
|
||||||
|
{
|
||||||
|
get => GetValue(TimeProperty);
|
||||||
|
set => SetValue(TimeProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> ShowHourTicksProperty =
|
||||||
|
ClockTicks.ShowHourTicksProperty.AddOwner<Clock>();
|
||||||
|
|
||||||
|
public bool ShowHourTicks
|
||||||
|
{
|
||||||
|
get => GetValue(ShowHourTicksProperty);
|
||||||
|
set => SetValue(ShowHourTicksProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> ShowMinuteTicksProperty =
|
||||||
|
ClockTicks.ShowMinuteTicksProperty.AddOwner<Clock>();
|
||||||
|
|
||||||
|
public bool ShowMinuteTicks
|
||||||
|
{
|
||||||
|
get => GetValue(ShowMinuteTicksProperty);
|
||||||
|
set => SetValue(ShowMinuteTicksProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
127
src/Ursa/Controls/Clock/ClockTicks.cs
Normal file
127
src/Ursa/Controls/Clock/ClockTicks.cs
Normal file
@@ -0,0 +1,127 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Media;
|
||||||
|
|
||||||
|
namespace Ursa.Controls;
|
||||||
|
|
||||||
|
public class ClockTicks: Control
|
||||||
|
{
|
||||||
|
private Matrix _hourRotationMatrix = Matrix.CreateRotation(Math.PI / 6);
|
||||||
|
private Matrix _minuteRotationMatrix = Matrix.CreateRotation(Math.PI / 30);
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> ShowHourTicksProperty = AvaloniaProperty.Register<ClockTicks, bool>(
|
||||||
|
nameof(ShowHourTicks), true);
|
||||||
|
|
||||||
|
public bool ShowHourTicks
|
||||||
|
{
|
||||||
|
get => GetValue(ShowHourTicksProperty);
|
||||||
|
set => SetValue(ShowHourTicksProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<bool> ShowMinuteTicksProperty = AvaloniaProperty.Register<ClockTicks, bool>(
|
||||||
|
nameof(ShowMinuteTicks), true);
|
||||||
|
|
||||||
|
public bool ShowMinuteTicks
|
||||||
|
{
|
||||||
|
get => GetValue(ShowMinuteTicksProperty);
|
||||||
|
set => SetValue(ShowMinuteTicksProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<IBrush?> HourTickForegroundProperty = AvaloniaProperty.Register<ClockTicks, IBrush?>(
|
||||||
|
nameof(HourTickForeground));
|
||||||
|
|
||||||
|
public IBrush? HourTickForeground
|
||||||
|
{
|
||||||
|
get => GetValue(HourTickForegroundProperty);
|
||||||
|
set => SetValue(HourTickForegroundProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<IBrush?> MinuteTickForegroundProperty = AvaloniaProperty.Register<ClockTicks, IBrush?>(
|
||||||
|
nameof(MinuteTickForeground));
|
||||||
|
|
||||||
|
public IBrush? MinuteTickForeground
|
||||||
|
{
|
||||||
|
get => GetValue(MinuteTickForegroundProperty);
|
||||||
|
set => SetValue(MinuteTickForegroundProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<double> HourTickLengthProperty = AvaloniaProperty.Register<ClockTicks, double>(
|
||||||
|
nameof(HourTickLength), 10);
|
||||||
|
|
||||||
|
public double HourTickLength
|
||||||
|
{
|
||||||
|
get => GetValue(HourTickLengthProperty);
|
||||||
|
set => SetValue(HourTickLengthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<double> MinuteTickLengthProperty = AvaloniaProperty.Register<ClockTicks, double>(
|
||||||
|
nameof(MinuteTickLength), 5);
|
||||||
|
|
||||||
|
public double MinuteTickLength
|
||||||
|
{
|
||||||
|
get => GetValue(MinuteTickLengthProperty);
|
||||||
|
set => SetValue(MinuteTickLengthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<double> HourTickWidthProperty = AvaloniaProperty.Register<ClockTicks, double>(
|
||||||
|
nameof(HourTickWidth), 2);
|
||||||
|
|
||||||
|
public double HourTickWidth
|
||||||
|
{
|
||||||
|
get => GetValue(HourTickWidthProperty);
|
||||||
|
set => SetValue(HourTickWidthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static readonly StyledProperty<double> MinuteTickWidthProperty = AvaloniaProperty.Register<ClockTicks, double>(
|
||||||
|
nameof(MinuteTickWidth), 1);
|
||||||
|
|
||||||
|
public double MinuteTickWidth
|
||||||
|
{
|
||||||
|
get => GetValue(MinuteTickWidthProperty);
|
||||||
|
set => SetValue(MinuteTickWidthProperty, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
static ClockTicks()
|
||||||
|
{
|
||||||
|
AffectsRender<ClockTicks>(ShowHourTicksProperty);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Render(DrawingContext context)
|
||||||
|
{
|
||||||
|
base.Render(context);
|
||||||
|
var size = Math.Min(Bounds.Width, Bounds.Height);
|
||||||
|
var center = size / 2;
|
||||||
|
IPen hourTickPen = new Pen(HourTickForeground, HourTickWidth);
|
||||||
|
IPen minuteTickPen = new Pen(MinuteTickForeground, MinuteTickWidth);
|
||||||
|
double hourTickLength = Math.Min(center, HourTickLength);
|
||||||
|
double minuteTickLength = Math.Min(center, MinuteTickLength);
|
||||||
|
context.PushTransform(Matrix.CreateTranslation(center, center));
|
||||||
|
if (ShowHourTicks)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 12; i++)
|
||||||
|
{
|
||||||
|
DrawTick(context, hourTickPen, center, hourTickLength);
|
||||||
|
context.PushTransform(_hourRotationMatrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ShowMinuteTicks)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < 60; i++)
|
||||||
|
{
|
||||||
|
if (i % 5 != 0)
|
||||||
|
{
|
||||||
|
DrawTick(context, minuteTickPen, center, minuteTickLength);
|
||||||
|
}
|
||||||
|
context.PushTransform(_minuteRotationMatrix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DrawTick(DrawingContext context, IPen pen, double center, double length)
|
||||||
|
{
|
||||||
|
var start = new Point(0, -center);
|
||||||
|
var end = new Point(0, length-center);
|
||||||
|
context.DrawLine(pen, start, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user