Skip to content

Commit c31e85b

Browse files
committed
Add HaloTimePicker
1 parent 0488f7c commit c31e85b

File tree

10 files changed

+356
-2
lines changed

10 files changed

+356
-2
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
namespace DevWinUI;
2+
3+
public partial class HaloTimePicker : Control
4+
{
5+
private const string PART_Hours = "PART_Hours";
6+
private const string PART_Minutes = "PART_Minutes";
7+
private const string PART_Display = "PART_Display";
8+
9+
private HaloArcSlider hours;
10+
private HaloArcSlider minutes;
11+
private TextBlock display;
12+
13+
public event EventHandler TimeChanged;
14+
15+
public Brush MinutesArcBrush
16+
{
17+
get { return (Brush)GetValue(MinutesArcBrushProperty); }
18+
set { SetValue(MinutesArcBrushProperty, value); }
19+
}
20+
21+
public static readonly DependencyProperty MinutesArcBrushProperty =
22+
DependencyProperty.Register(nameof(MinutesArcBrush), typeof(Brush), typeof(HaloTimePicker), new PropertyMetadata(null));
23+
24+
public Brush HoursArcBrush
25+
{
26+
get { return (Brush)GetValue(HoursArcBrushProperty); }
27+
set { SetValue(HoursArcBrushProperty, value); }
28+
}
29+
30+
public static readonly DependencyProperty HoursArcBrushProperty =
31+
DependencyProperty.Register(nameof(HoursArcBrush), typeof(Brush), typeof(HaloTimePicker), new PropertyMetadata(null));
32+
33+
public int MinutesBand
34+
{
35+
get { return (int)GetValue(MinutesBandProperty); }
36+
set { SetValue(MinutesBandProperty, value); }
37+
}
38+
39+
public static readonly DependencyProperty MinutesBandProperty =
40+
DependencyProperty.Register(nameof(MinutesBand), typeof(int), typeof(HaloTimePicker), new PropertyMetadata(2));
41+
42+
public int HoursBand
43+
{
44+
get { return (int)GetValue(HoursBandProperty); }
45+
set { SetValue(HoursBandProperty, value); }
46+
}
47+
48+
public static readonly DependencyProperty HoursBandProperty =
49+
DependencyProperty.Register(nameof(HoursBand), typeof(int), typeof(HaloTimePicker), new PropertyMetadata(1));
50+
51+
public Brush MinutesBrush
52+
{
53+
get { return (Brush)GetValue(MinutesBrushProperty); }
54+
set { SetValue(MinutesBrushProperty, value); }
55+
}
56+
57+
public static readonly DependencyProperty MinutesBrushProperty =
58+
DependencyProperty.Register(nameof(MinutesBrush), typeof(Brush), typeof(HaloTimePicker), new PropertyMetadata(null));
59+
60+
public Brush HoursBrush
61+
{
62+
get { return (Brush)GetValue(HoursBrushProperty); }
63+
set { SetValue(HoursBrushProperty, value); }
64+
}
65+
66+
public static readonly DependencyProperty HoursBrushProperty =
67+
DependencyProperty.Register(nameof(HoursBrush), typeof(Brush), typeof(HaloTimePicker), new PropertyMetadata(null));
68+
69+
public TimeSpan Time
70+
{
71+
get { return (TimeSpan)GetValue(TimeProperty); }
72+
set { SetValue(TimeProperty, value); }
73+
}
74+
public static readonly DependencyProperty TimeProperty =
75+
DependencyProperty.Register(nameof(Time), typeof(TimeSpan), typeof(HaloTimePicker), new PropertyMetadata(new TimeSpan(DateTime.Now.Hour, DateTime.Now.Minute, DateTime.Now.Second), OnTimeChanged));
76+
77+
private static void OnTimeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
78+
{
79+
var ctl = (HaloTimePicker)d;
80+
if (ctl != null)
81+
{
82+
ctl.TimeChanged?.Invoke(ctl, EventArgs.Empty);
83+
}
84+
}
85+
86+
public HaloTimePicker()
87+
{
88+
DefaultStyleKey = typeof(HaloTimePicker);
89+
}
90+
91+
protected override void OnApplyTemplate()
92+
{
93+
base.OnApplyTemplate();
94+
95+
hours = GetTemplateChild(PART_Hours) as HaloArcSlider;
96+
minutes = GetTemplateChild(PART_Minutes) as HaloArcSlider;
97+
display = GetTemplateChild(PART_Display) as TextBlock;
98+
99+
BindingOperations.SetBinding(hours, HaloArcSlider.AngleProperty, new Binding
100+
{
101+
Source = this, Path = new PropertyPath("Time"),
102+
Converter = new TimeHoursConverter(this), Mode = BindingMode.TwoWay
103+
});
104+
105+
BindingOperations.SetBinding(minutes, HaloArcSlider.AngleProperty, new Binding
106+
{
107+
Source = this, Path = new PropertyPath("Time"),
108+
Converter = new TimeMinutesConverter(this), Mode = BindingMode.TwoWay
109+
});
110+
111+
BindingOperations.SetBinding(display, TextBlock.TextProperty, new Binding
112+
{
113+
Source = this, Path = new PropertyPath("Time"),
114+
Converter = new TimeDisplayConverter()
115+
});
116+
}
117+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
namespace DevWinUI;
2+
3+
internal partial class TimeDisplayConverter : IValueConverter
4+
{
5+
public object Convert(object value, Type targetType, object parameter, string language)
6+
{
7+
var span = (TimeSpan)value;
8+
9+
return String.Format(
10+
"{0:00}:{1:00}", span.Hours, span.Minutes
11+
);
12+
}
13+
14+
public object ConvertBack(object value, Type targetType, object parameter, string language)
15+
{
16+
throw new NotSupportedException();
17+
}
18+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
namespace DevWinUI;
2+
3+
internal partial class TimeHoursConverter : IValueConverter
4+
{
5+
private readonly HaloTimePicker _picker;
6+
7+
public TimeHoursConverter(HaloTimePicker picker)
8+
{
9+
_picker = picker;
10+
}
11+
12+
public object Convert(object value, Type targetType, object parameter, string language)
13+
{
14+
var hours = _picker.Time.TotalHours;
15+
return ((hours % 12) / 12) * 360;
16+
}
17+
18+
public object ConvertBack(object value, Type targetType, object parameter, string language)
19+
{
20+
var span = _picker.Time;
21+
22+
var newValue = AngleFor((double)value);
23+
var newHours = newValue / 360 * 12;
24+
25+
var offset = WrapPeriod(span, newHours);
26+
27+
return new TimeSpan(
28+
(int)newHours + offset, span.Minutes, span.Seconds
29+
);
30+
}
31+
32+
private int WrapPeriod(TimeSpan span, double newHours)
33+
{
34+
var oldHours = span.Hours % 12;
35+
var offset = (span.Hours / 12) * 12;
36+
37+
if ((oldHours > 9) ^ (newHours > 9))
38+
{
39+
if ((oldHours < 4) ^ (newHours < 4))
40+
{
41+
return (offset + 12) % 24;
42+
}
43+
}
44+
45+
return offset;
46+
}
47+
48+
private double AngleFor(double value)
49+
{
50+
return ((value % 360) + 360) % 360;
51+
}
52+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
namespace DevWinUI;
2+
3+
internal partial class TimeMinutesConverter : IValueConverter
4+
{
5+
private readonly HaloTimePicker _picker;
6+
7+
public TimeMinutesConverter(HaloTimePicker picker)
8+
{
9+
_picker = picker;
10+
}
11+
12+
public object Convert(object value, Type targetType, object parameter, string language)
13+
{
14+
var minutes = _picker.Time.TotalMinutes;
15+
return (minutes % 60 / 60) * 360;
16+
}
17+
18+
public object ConvertBack(object value, Type targetType, object parameter, string language)
19+
{
20+
var newValue = AngleFor((double)value);
21+
22+
var newMinutes = (newValue / 360) * 60;
23+
var seconds = (newMinutes * 60) % 60;
24+
25+
var hours = WrapHours(_picker.Time, newMinutes);
26+
27+
return new TimeSpan(
28+
hours, (int)newMinutes, (int)seconds
29+
);
30+
}
31+
32+
private int WrapHours(TimeSpan span, double newMinutes)
33+
{
34+
var oldMinutes = span.Minutes;
35+
36+
if ((oldMinutes > 45) && (newMinutes < 16))
37+
{
38+
return (span.Hours + 1) % 24;
39+
}
40+
41+
if ((oldMinutes < 16) && (newMinutes > 45))
42+
{
43+
return (24 + span.Hours - 1) % 24;
44+
}
45+
46+
return span.Hours;
47+
}
48+
49+
private double AngleFor(double value)
50+
{
51+
return ((value % 360) + 360) % 360;
52+
}
53+
}

dev/DevWinUI.Controls/Themes/Generic.xaml

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ Themes\Styles\Controls\Gravatar.xaml
5858
Themes\Styles\Controls\Growl.xaml
5959
Themes\Styles\Controls\HaloArcSlider.xaml
6060
Themes\Styles\Controls\HaloSlider.xaml
61+
Themes\Styles\Controls\HaloTimePicker.xaml
6162
Themes\Styles\Controls\HeaderCarousel.xaml
6263
Themes\Styles\Controls\HeaderCarouselItem.xaml
6364
Themes\Styles\Controls\HeaderTile.xaml
@@ -1459,10 +1460,11 @@ Themes\Styles\Win2D\Watermark.xaml
14591460
</Style>
14601461
<x:Double x:Key="GrowlWidth">340</x:Double>
14611462
<Style x:Key="DefaultHaloArcSliderStyle" TargetType="local:HaloArcSlider">
1463+
<Setter Property="Background" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
14621464
<Setter Property="Template">
14631465
<Setter.Value>
14641466
<ControlTemplate TargetType="local:HaloArcSlider">
1465-
<local:HaloArc x:Name="Arc" Angle="{Binding Angle, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Spread="20" Stroke="{ThemeResource CardStrokeColorDefaultSolidBrush}" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="30" Tension="0.5" Offset="{Binding Offset, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
1467+
<local:HaloArc x:Name="Arc" Angle="{Binding Angle, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Spread="20" Stroke="{TemplateBinding Background}" StrokeEndLineCap="Round" StrokeStartLineCap="Round" StrokeThickness="30" Tension="0.5" Offset="{Binding Offset, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}">
14661468
<VisualStateManager.VisualStateGroups>
14671469
<VisualStateGroup x:Name="CommonStates">
14681470
<VisualState x:Name="Sliding">
@@ -1508,6 +1510,33 @@ Themes\Styles\Win2D\Watermark.xaml
15081510
</Setter.Value>
15091511
</Setter>
15101512
</Style>
1513+
<Style x:Key="DefaultHaloTimePickerStyle" TargetType="local:HaloTimePicker">
1514+
<Setter Property="MinutesBrush" Value="{ThemeResource AccentAAFillColorDefaultBrush}" />
1515+
<Setter Property="HoursBrush" Value="{ThemeResource AccentAAFillColorTertiaryBrush}" />
1516+
<Setter Property="Background" Value="{ThemeResource TextFillColorInverseBrush}" />
1517+
<Setter Property="HoursArcBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
1518+
<Setter Property="MinutesArcBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
1519+
<Setter Property="MinutesBand" Value="2" />
1520+
<Setter Property="HoursBand" Value="1" />
1521+
<Setter Property="FontSize" Value="30" />
1522+
<Setter Property="FontWeight" Value="SemiBold" />
1523+
<Setter Property="Template">
1524+
<Setter.Value>
1525+
<ControlTemplate TargetType="local:HaloTimePicker">
1526+
<Viewbox>
1527+
<local:Halo>
1528+
<local:HaloDisc local:Halo.Band="{TemplateBinding MinutesBand}" Fill="{TemplateBinding MinutesBrush}" />
1529+
<local:HaloArcSlider x:Name="PART_Minutes" local:Halo.Band="{TemplateBinding MinutesBand}" Background="{TemplateBinding MinutesArcBrush}" />
1530+
<local:HaloDisc local:Halo.Band="{TemplateBinding HoursBand}" Fill="{TemplateBinding HoursBrush}" />
1531+
<local:HaloArcSlider x:Name="PART_Hours" local:Halo.Band="{TemplateBinding HoursBand}" Background="{TemplateBinding HoursArcBrush}" />
1532+
<local:HaloDisc Fill="{TemplateBinding Background}" />
1533+
<TextBlock x:Name="PART_Display" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="{TemplateBinding FontSize}" FontWeight="{TemplateBinding FontWeight}" />
1534+
</local:Halo>
1535+
</Viewbox>
1536+
</ControlTemplate>
1537+
</Setter.Value>
1538+
</Setter>
1539+
</Style>
15111540
<Style TargetType="local:HeaderCarousel">
15121541
<Setter Property="ItemsPanel">
15131542
<Setter.Value>
@@ -8312,6 +8341,7 @@ Themes\Styles\Win2D\Watermark.xaml
83128341
</Style>
83138342
<Style TargetType="local:HaloArcSlider" BasedOn="{StaticResource DefaultHaloArcSliderStyle}" />
83148343
<Style TargetType="local:HaloSlider" BasedOn="{StaticResource DefaultHaloSliderStyle}" />
8344+
<Style TargetType="local:HaloTimePicker" BasedOn="{StaticResource DefaultHaloTimePickerStyle}" />
83158345
<Style TargetType="local:HeaderCarouselItem" BasedOn="{StaticResource DefaultCarouselItemStyle}" />
83168346
<Style x:Key="DefaultHeaderTileStyle" TargetType="local:HeaderTile">
83178347
<Setter Property="Width" Value="232" />

dev/DevWinUI.Controls/Themes/Styles/Controls/HaloArcSlider.xaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,14 @@
66
<Style TargetType="local:HaloArcSlider" BasedOn="{StaticResource DefaultHaloArcSliderStyle}" />
77

88
<Style x:Key="DefaultHaloArcSliderStyle" TargetType="local:HaloArcSlider">
9+
<Setter Property="Background" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
910
<Setter Property="Template">
1011
<Setter.Value>
1112
<ControlTemplate TargetType="local:HaloArcSlider">
1213
<local:HaloArc x:Name="Arc"
1314
Angle="{Binding Angle, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}"
1415
Spread="20"
15-
Stroke="{ThemeResource CardStrokeColorDefaultSolidBrush}"
16+
Stroke="{TemplateBinding Background}"
1617
StrokeEndLineCap="Round"
1718
StrokeStartLineCap="Round"
1819
StrokeThickness="30"
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
3+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
4+
xmlns:local="using:DevWinUI">
5+
6+
<Style TargetType="local:HaloTimePicker" BasedOn="{StaticResource DefaultHaloTimePickerStyle}" />
7+
8+
<Style x:Key="DefaultHaloTimePickerStyle" TargetType="local:HaloTimePicker">
9+
<Setter Property="MinutesBrush" Value="{ThemeResource AccentAAFillColorDefaultBrush}" />
10+
<Setter Property="HoursBrush" Value="{ThemeResource AccentAAFillColorTertiaryBrush}" />
11+
<Setter Property="Background" Value="{ThemeResource TextFillColorInverseBrush}" />
12+
<Setter Property="HoursArcBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
13+
<Setter Property="MinutesArcBrush" Value="{ThemeResource CardStrokeColorDefaultSolidBrush}" />
14+
<Setter Property="MinutesBand" Value="2" />
15+
<Setter Property="HoursBand" Value="1" />
16+
<Setter Property="FontSize" Value="30" />
17+
<Setter Property="FontWeight" Value="SemiBold" />
18+
<Setter Property="Template">
19+
<Setter.Value>
20+
<ControlTemplate TargetType="local:HaloTimePicker">
21+
<local:Halo>
22+
<local:HaloDisc local:Halo.Band="{TemplateBinding MinutesBand}"
23+
Fill="{TemplateBinding MinutesBrush}" />
24+
<local:HaloArcSlider x:Name="PART_Minutes"
25+
local:Halo.Band="{TemplateBinding MinutesBand}"
26+
Background="{TemplateBinding MinutesArcBrush}" />
27+
28+
<local:HaloDisc local:Halo.Band="{TemplateBinding HoursBand}"
29+
Fill="{TemplateBinding HoursBrush}" />
30+
<local:HaloArcSlider x:Name="PART_Hours"
31+
local:Halo.Band="{TemplateBinding HoursBand}"
32+
Background="{TemplateBinding HoursArcBrush}" />
33+
34+
<local:HaloDisc Fill="{TemplateBinding Background}" />
35+
36+
<TextBlock x:Name="PART_Display"
37+
HorizontalAlignment="Center"
38+
VerticalAlignment="Center"
39+
FontSize="{TemplateBinding FontSize}"
40+
FontWeight="{TemplateBinding FontWeight}" />
41+
</local:Halo>
42+
</ControlTemplate>
43+
</Setter.Value>
44+
</Setter>
45+
</Style>
46+
</ResourceDictionary>
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<dev:Halo Height="150"
2+
Margin="5">
3+
<dev:HaloRingLabel dev:Halo.Band="1"
4+
FontSize="30"
5+
Text="DevWinUI" />
6+
<dev:HaloRingLabel dev:Halo.Band="1"
7+
Flip="True"
8+
FontSize="25"
9+
Text="DevWinUI" />
10+
</dev:Halo>
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<dev:Halo Height="250" Width="150"
2+
Margin="5">
3+
<dev:HaloTimePicker />
4+
</dev:Halo>

0 commit comments

Comments
 (0)