Skip to content

Commit a48cf8c

Browse files
committed
Complete AnalogClockFace
1 parent daee9eb commit a48cf8c

File tree

10 files changed

+932
-169
lines changed

10 files changed

+932
-169
lines changed

BionicCode.Net/BionicCode.Controls.Net.Core.Wpf/AnalogClockFace.cs

Lines changed: 618 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
#region Info
2+
3+
// 2021/01/09 10:13
4+
// BionicCode.Controls.Net.Core.Wpf
5+
6+
#endregion
7+
8+
using System.Windows;
9+
using System.Windows.Controls;
10+
using System.Windows.Markup;
11+
using System.Windows.Media;
12+
using System.Windows.Shapes;
13+
14+
namespace BionicCode.Controls.Net.Core.Wpf
15+
{
16+
[ContentProperty("AnalogClockFace")]
17+
public class AnalogTimePicker : Control
18+
{
19+
#region AnalogClockFace dependency property
20+
21+
public static readonly DependencyProperty AnalogClockFaceProperty = DependencyProperty.Register(
22+
"AnalogClockFace",
23+
typeof(Canvas),
24+
typeof(AnalogTimePicker),
25+
new PropertyMetadata(default(Canvas), OnAnalogClockFaceChanged));
26+
27+
public AnalogClockFace AnalogClockFace { get => (AnalogClockFace) GetValue(AnalogTimePicker.AnalogClockFaceProperty); set => SetValue(AnalogTimePicker.AnalogClockFaceProperty, value); }
28+
29+
#endregion AnalogClockFace dependency property
30+
31+
#region AnalogClockFaceStyle dependency property
32+
33+
public static readonly DependencyProperty AnalogClockFaceStyleProperty = DependencyProperty.Register(
34+
"AnalogClockFaceStyle",
35+
typeof(Style),
36+
typeof(AnalogTimePicker),
37+
new PropertyMetadata(default));
38+
39+
public Style AnalogClockFaceStyle { get => (Style) GetValue(AnalogTimePicker.AnalogClockFaceStyleProperty); set => SetValue(AnalogTimePicker.AnalogClockFaceStyleProperty, value); }
40+
41+
#endregion AnalogClockFaceStyle dependency property
42+
43+
#region ClockDiameter dependency property
44+
45+
public static readonly DependencyProperty ClockDiameterProperty = DependencyProperty.Register(
46+
"ClockDiameter",
47+
typeof(double),
48+
typeof(AnalogTimePicker),
49+
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsArrange));
50+
51+
public double ClockDiameter { get => (double) GetValue(AnalogTimePicker.ClockDiameterProperty); set => SetValue(AnalogTimePicker.ClockDiameterProperty, value); }
52+
53+
#endregion ClockDiameter dependency property
54+
private bool IsClockPointerSelectionEnabled { get; set; }
55+
private Line ClockSelectionPointer { get; set; }
56+
57+
static AnalogTimePicker()
58+
{
59+
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(typeof(AnalogTimePicker), new FrameworkPropertyMetadata(typeof(AnalogTimePicker)));
60+
}
61+
62+
public AnalogTimePicker()
63+
{
64+
//this.AnalogClockFace = new AnalogClockFace() {Background = Brushes.PaleVioletRed};
65+
}
66+
67+
#region Overrides of AnalogClockFace
68+
69+
//protected virtual void OnClockFaceLoaded(object sender, RoutedEventArgs routedEventArgs)
70+
//{
71+
// double radius = this.ClockDiameter / 2;
72+
73+
// this.ClockSelectionPointer = new Line() { X1 = radius, Y1 = radius, X2 = radius, Y2 = 0, Stroke = Brushes.Orange, StrokeThickness = 2 };
74+
// this.AnalogClockFace.AddElementToClockFace(this.ClockSelectionPointer, new Point());
75+
// this.AnalogClockFace.AddElementToClockFace(new Line() { X1 = radius, Y1 = radius, X2 = 0, Y2 = radius, Stroke = Brushes.Orange, StrokeThickness = 2 }, new Point());
76+
// //selectPointer.PreviewMouseLeftButtonDown += timePicker.OnSelectPointerLeftMouseButtonDown;
77+
//}
78+
79+
#endregion
80+
81+
#region Overrides of Control
82+
83+
/// <inheritdoc />
84+
protected override Size MeasureOverride(Size constraint)
85+
{
86+
constraint = new Size(this.ClockDiameter, this.ClockDiameter);
87+
this.AnalogClockFace.Diameter = this.ClockDiameter;
88+
//this.AnalogClockFace.Measure(constraint);
89+
base.MeasureOverride(constraint);
90+
return constraint;
91+
}
92+
93+
#endregion
94+
95+
private static void OnAnalogClockFaceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
96+
{
97+
(d as AnalogTimePicker).OnAnalogClockFaceChanged();
98+
}
99+
100+
protected virtual void OnAnalogClockFaceChanged()
101+
{
102+
// this.AnalogClockFace.ClockFaceLoaded += OnClockFaceLoaded;
103+
}
104+
105+
//private void OnSelectPointerLeftMouseButtonDown(object sender, MouseButtonEventArgs e)
106+
//{
107+
// this.IsClockPointerSelectionEnabled = true;
108+
// //CaptureMouse();
109+
//}
110+
111+
//#region Overrides of UIElement
112+
113+
///// <inheritdoc />
114+
//protected override void OnPreviewMouseMove(MouseEventArgs e)
115+
//{
116+
// base.OnPreviewMouseMove(e);
117+
// if (!this.IsClockPointerSelectionEnabled)
118+
// {
119+
// return;
120+
// }
121+
122+
// Point mousePosition = e.GetPosition(this.ClockPanel);
123+
// var quadrant = mousePosition.X >= 200 && mousePosition.Y <= 200 ? 1 :
124+
// mousePosition.X < 200 && mousePosition.Y <= 200 ? 2 :
125+
// mousePosition.X < 200 && mousePosition.Y > 200 ? 3 : 4;
126+
// bool isRightQuadrantActive = quadrant == 1 || quadrant == 4;
127+
// bool isTopQuadrantActive = quadrant == 1 || quadrant == 2;
128+
// var intervalPositions = this.ClockPanel.Children
129+
// .Cast<UIElement>()
130+
// .Where(element => !object.ReferenceEquals(element, this.ClockSelectionPointer))
131+
// .Select(element => new Point(Canvas.GetLeft(element), Canvas.GetTop(element)))
132+
// .Where(cartesianPoint => isRightQuadrantActive && isTopQuadrantActive
133+
// ? cartesianPoint.X >= 200 && cartesianPoint.Y <= 200
134+
// : isRightQuadrantActive
135+
// ? cartesianPoint.X >= 200 && cartesianPoint.Y > 200 : isTopQuadrantActive ? cartesianPoint.X < 200 && cartesianPoint.Y <= 200 :
136+
// cartesianPoint.X < 200 && cartesianPoint.Y > 200);
137+
// Point closestIntervalPosition = intervalPositions.Aggregate(intervalPositions.First(), (closestIntervalPosition, intervalPosition) => Math.Abs(intervalPosition.X - mousePosition.X) < Math.Abs(closestIntervalPosition.X - mousePosition.X) && Math.Abs(intervalPosition.Y - mousePosition.Y) < Math.Abs(closestIntervalPosition.Y - mousePosition.Y) ? intervalPosition : closestIntervalPosition);
138+
139+
// this.ClockSelectionPointer.X2 = closestIntervalPosition.X;
140+
// this.ClockSelectionPointer.Y2 = closestIntervalPosition.Y;
141+
//}
142+
143+
///// <inheritdoc />
144+
//protected override void OnPreviewMouseLeftButtonUp(MouseButtonEventArgs e)
145+
//{
146+
// base.OnPreviewMouseLeftButtonUp(e);
147+
// this.IsClockPointerSelectionEnabled = false;
148+
// ReleaseMouseCapture();
149+
//}
150+
151+
//#endregion
152+
}
153+
}

BionicCode.Net/BionicCode.Controls.Net.Core.Wpf/BionicCode.Controls.Net.Core.Wpf.xml

Lines changed: 6 additions & 9 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:wpf="clr-namespace:BionicCode.Controls.Net.Core.Wpf"
4+
xmlns:converter="clr-namespace:BionicCode.Utilities.Net.Core.Wpf.Converter;assembly=BionicCode.Utilities.Net.Core.Wpf">
5+
<ResourceDictionary.MergedDictionaries>
6+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Resources/Colors.xaml" />
7+
</ResourceDictionary.MergedDictionaries>
8+
<converter:DividerValueConverter x:Key="DividerValueConverter" />
9+
10+
<Style TargetType="wpf:AnalogClockFace">
11+
<Setter Property="SelectedHour" Value="400.5"/>
12+
<Setter Property="HourHandElement">
13+
<Setter.Value>
14+
<Line X1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
15+
Y1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
16+
X2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
17+
Y2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius, Converter={StaticResource DividerValueConverter}, ConverterParameter=3}"
18+
Stroke="{StaticResource ApplicationWhiteBrush}"
19+
StrokeThickness="3"/>
20+
</Setter.Value>
21+
</Setter>
22+
<Setter Property="MinuteHandElement">
23+
<Setter.Value>
24+
<Line X1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
25+
Y1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
26+
X2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
27+
Y2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius, Converter={StaticResource DividerValueConverter}, ConverterParameter=16}"
28+
Stroke="{StaticResource ApplicationWhiteBrush}"
29+
StrokeThickness="3"/>
30+
</Setter.Value>
31+
</Setter>
32+
<Setter Property="SecondHandElement">
33+
<Setter.Value>
34+
<Line X1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
35+
Y1="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
36+
X2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius}"
37+
Y2="{Binding RelativeSource={RelativeSource AncestorType=wpf:AnalogClockFace}, Path=Radius, Converter={StaticResource DividerValueConverter}, ConverterParameter=16}"
38+
Stroke="{StaticResource ApplicationWhiteBrush}"
39+
StrokeThickness="1"/>
40+
</Setter.Value>
41+
</Setter>
42+
<Setter Property="FifteenMinuteIntervalElement">
43+
<Setter.Value>
44+
<Ellipse Height="8" Width="8" Fill="{StaticResource ApplicationWhiteBrush}"/>
45+
</Setter.Value>
46+
</Setter>
47+
<Setter Property="FiveMinuteIntervalElement">
48+
<Setter.Value>
49+
<Ellipse Height="4" Width="4" Fill="{StaticResource ApplicationWhiteBrush}"/>
50+
</Setter.Value>
51+
</Setter>
52+
<Setter Property="MinuteIntervalElement">
53+
<Setter.Value>
54+
<Ellipse Height="2" Width="2" Fill="{StaticResource ApplicationWhiteBrush}"/>
55+
</Setter.Value>
56+
</Setter>
57+
</Style>
58+
59+
</ResourceDictionary>
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:wpf="clr-namespace:BionicCode.Controls.Net.Core.Wpf">
4+
<ResourceDictionary.MergedDictionaries>
5+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Resources/Styles/ScrolBarStyle.xaml" />
6+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Resources/Colors.xaml" />
7+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Resources/Styles/SeparatorBorderStyles.xaml" />
8+
<ResourceDictionary
9+
Source="/BionicCode.Controls.Net.Core.Wpf;component/Resources/Styles/FlipSwitchToggleButtonStyle.xaml" />
10+
</ResourceDictionary.MergedDictionaries>
11+
12+
<Style TargetType="wpf:AnalogTimePicker">
13+
<Setter Property="ClockDiameter" Value="400"/>
14+
<Setter Property="AnalogClockFace">
15+
<Setter.Value>
16+
<wpf:AnalogClockFace>
17+
<!--<wpf:AnalogClockFace.MinuteIntervalElement>
18+
<Ellipse Height="2" Width="2" Fill="{StaticResource ApplicationWhiteBrush}"/>
19+
</wpf:AnalogClockFace.MinuteIntervalElement>
20+
<wpf:AnalogClockFace.FiveMinuteIntervalElement>
21+
<Ellipse Height="4" Width="4" Fill="{StaticResource ApplicationWhiteBrush}"/>
22+
</wpf:AnalogClockFace.FiveMinuteIntervalElement>
23+
<wpf:AnalogClockFace.FifteenMinuteIntervalElement>
24+
<Ellipse Height="8" Width="8" Fill="{StaticResource ApplicationWhiteBrush}"/>
25+
</wpf:AnalogClockFace.FifteenMinuteIntervalElement>-->
26+
</wpf:AnalogClockFace>
27+
</Setter.Value>
28+
</Setter>
29+
<Setter Property="Template">
30+
<Setter.Value>
31+
<ControlTemplate TargetType="wpf:AnalogTimePicker">
32+
<ContentPresenter Content="{TemplateBinding AnalogClockFace}" />
33+
</ControlTemplate>
34+
</Setter.Value>
35+
</Setter>
36+
</Style>
37+
38+
</ResourceDictionary>

BionicCode.Net/BionicCode.Controls.Net.Core.Wpf/Themes/Generic.xaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
xmlns:controls="clr-namespace:BionicCode.Controls.Net.Core.Wpf.Controls">
66
<ResourceDictionary.MergedDictionaries>
77
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Themes/TimePickerStyle.xaml" />
8+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Themes/AnalogTimePickerStyle.xaml" />
9+
<ResourceDictionary Source="/BionicCode.Controls.Net.Core.Wpf;component/Themes/AnalogClockFaceStyle.xaml" />
810
</ResourceDictionary.MergedDictionaries>
911
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Pink"/>
1012

BionicCode.Net/BionicCode.Controls.Net.Core.Wpf/Themes/TimePickerStyle.xaml

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -297,14 +297,14 @@
297297
<VisualState Name="{x:Static local:TimePicker.VisualStatePickerOpen}">
298298
<Storyboard>
299299
<DoubleAnimation Storyboard.TargetName="PickerPanel"
300-
Storyboard.TargetProperty="Height" From="0" To="480"
300+
Storyboard.TargetProperty="MaxHeight" From="0" To="1000"
301301
Duration="0:0:0.1"/>
302302
</Storyboard>
303303
</VisualState>
304304
<VisualState Name="{x:Static local:TimePicker.VisualStatePickerClosed}">
305305
<Storyboard>
306306
<DoubleAnimation Storyboard.TargetName="PickerPanel"
307-
Storyboard.TargetProperty="Height" From="320" To="0" />
307+
Storyboard.TargetProperty="MaxHeight" To="0" />
308308
</Storyboard>
309309
</VisualState>
310310
</VisualStateGroup.States>
@@ -342,7 +342,6 @@
342342
</StackPanel>
343343
</Border>
344344
<Popup x:Name="PickerPanel"
345-
Height="0"
346345
PlacementTarget="{Binding ElementName=Expander}"
347346
IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsOpen}"
348347
AllowsTransparency="True"
@@ -356,7 +355,7 @@
356355
<DropShadowEffect Opacity="0.7" Color="DimGray" />
357356
</Border.Effect>
358357

359-
<Canvas x:Name="PART_ClockCanvas"/>
358+
<ContentPresenter x:Name="PART_ClockHost" />
360359
</Border>
361360
</Popup>
362361
</StackPanel>

0 commit comments

Comments
 (0)