-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Added radial progress bar control #828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 10 commits
fcb4271
d6037a0
54eeeac
d6bcb3a
ef1384b
51b63de
c0a37b8
42713ef
0f5e5c3
5ea19d2
d48ddfa
c1fdbe8
49bbae2
e8fac72
480b60b
680423c
180a6af
d99d028
0f6312d
93dcfb8
a9c2d9f
94af716
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,28 @@ | ||
| <Page x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.RadialProgressBarPage" | ||
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
| xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" | ||
| xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
| mc:Ignorable="d"> | ||
|
|
||
| <Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> | ||
| <Grid VerticalAlignment="Center" | ||
| HorizontalAlignment="Center"> | ||
| <Grid.ColumnDefinitions> | ||
| <ColumnDefinition Width="50"></ColumnDefinition> | ||
| <ColumnDefinition Width="250"></ColumnDefinition> | ||
| <ColumnDefinition Width="50"></ColumnDefinition> | ||
| </Grid.ColumnDefinitions> | ||
| <controls:RadialProgressBar | ||
| x:Name="RadialProgressBar" | ||
| Grid.Column="1" | ||
| Value="@[Value:Slider:0:0-100]" | ||
| Thickness="@[Thickness:Slider:4:4-20]" | ||
| Minimum="0" | ||
| Maximum="100" | ||
| Width="@[Width:Slider:100:100-200]" | ||
| Height="@[Height:Slider:100:100-200]"/> | ||
| </Grid> | ||
| </Grid> | ||
| </Page> | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| <Page x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.RadialProgressBarPage" | ||
| xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" | ||
| xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" | ||
| xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls" | ||
| xmlns:d="http://schemas.microsoft.com/expression/blend/2008" | ||
| xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" | ||
| mc:Ignorable="d"> | ||
|
|
||
| <Grid Background="{StaticResource Brush-Grey-05}"> | ||
| <Grid HorizontalAlignment="Center" | ||
| VerticalAlignment="Center"> | ||
| <Grid.ColumnDefinitions> | ||
| <ColumnDefinition Width="50" /> | ||
| <ColumnDefinition Width="250" /> | ||
| <ColumnDefinition Width="50" /> | ||
| </Grid.ColumnDefinitions> | ||
| <controls:RadialProgressBar x:Name="RadialProgressBarControl" | ||
| Grid.Column="1" | ||
| Maximum="100" | ||
| Minimum="0" | ||
| Thickness="{Binding Thickness.Value, Mode=OneWay}" | ||
| Value="{Binding Value.Value, Mode=OneWay}" | ||
| Width="{Binding Width.Value, Mode=OneWay}" | ||
| Height="{Binding Height.Value, Mode=OneWay}"/> | ||
| </Grid> | ||
| </Grid> | ||
| </Page> |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,39 @@ | ||
| // ****************************************************************** | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // This code is licensed under the MIT License (MIT). | ||
| // THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH | ||
| // THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. | ||
| // ****************************************************************** | ||
|
|
||
| using Microsoft.Toolkit.Uwp.SampleApp.Models; | ||
|
|
||
| using Windows.UI.Xaml.Controls; | ||
| using Windows.UI.Xaml.Navigation; | ||
|
|
||
| namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages | ||
| { | ||
| public sealed partial class RadialProgressBarPage : Page | ||
| { | ||
| public RadialProgressBarPage() | ||
| { | ||
| InitializeComponent(); | ||
| } | ||
|
|
||
| protected override void OnNavigatedTo(NavigationEventArgs e) | ||
| { | ||
| base.OnNavigatedTo(e); | ||
|
|
||
| var propertyDesc = e.Parameter as PropertyDescriptor; | ||
|
|
||
| if (propertyDesc != null) | ||
| { | ||
| DataContext = propertyDesc.Expando; | ||
| } | ||
| } | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -60,6 +60,14 @@ | |
| "XamlCodeFile": "RadialGaugeCode.bind", | ||
| "Icon": "/SamplePages/RadialGauge/RadialGauge.png" | ||
| }, | ||
| { | ||
| "Name": "RadialProgressBar", | ||
| "Type": "RadialProgressBarPage", | ||
| "About": "The radial progress bar displays progress as a circle gettin filled.", | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Getting |
||
| "CodeUrl": "https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/RadialProgressBar", | ||
| "XamlCodeFile": "RadialProgressBarCode.bind", | ||
| "Icon": "/SamplePages/RadialProgressBar/RadialProgressBar.png" | ||
| }, | ||
| { | ||
| "Name": "SlidableListItem", | ||
| "Type": "SlidableListItemPage", | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,201 @@ | ||
| // ****************************************************************** | ||
| // Copyright (c) Microsoft. All rights reserved. | ||
| // This code is licensed under the MIT License (MIT). | ||
| // THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, | ||
| // INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
| // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. | ||
| // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, | ||
| // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, | ||
| // TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH | ||
| // THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE. | ||
| // ***************************************************************** | ||
|
|
||
| using System; | ||
| using Windows.Foundation; | ||
| using Windows.UI.Xaml; | ||
| using Windows.UI.Xaml.Controls.Primitives; | ||
| using Windows.UI.Xaml.Media; | ||
|
|
||
| namespace Microsoft.Toolkit.Uwp.UI.Controls | ||
| { | ||
| /// <summary> | ||
| /// An alternative impementation of a progress bar. | ||
| /// Progression is represented by a loop filling up in a clockwise fashion. | ||
| /// Like the traditional progress bar, it inherits from RangeBase, so Minimum, Maximum and Value properties work the same way. | ||
| /// </summary> | ||
| [TemplatePart(Name = OutlineFigurePartName, Type = typeof(PathFigure))] | ||
| [TemplatePart(Name = OutlineArcPartName, Type = typeof(ArcSegment))] | ||
| [TemplatePart(Name = BarFigurePartName, Type = typeof(PathFigure))] | ||
| [TemplatePart(Name = BarArcPartName, Type = typeof(ArcSegment))] | ||
| public sealed class RadialProgressBar : RangeBase | ||
| { | ||
| private const string OutlineFigurePartName = "OutlineFigurePart"; | ||
| private const string OutlineArcPartName = "OutlineArcPart"; | ||
| private const string BarFigurePartName = "BarFigurePart"; | ||
| private const string BarArcPartName = "BarArcPart"; | ||
|
|
||
| private const string DefaultForegroundColorBrushName = "SystemControlHighlightAccentBrush"; | ||
| private const string DefaultBackgroundColorBrushName = "SystemControlBackgroundBaseLowBrush"; | ||
|
|
||
| private PathFigure OutlineFigure { get; set; } | ||
|
||
|
|
||
| private PathFigure BarFigure { get; set; } | ||
|
|
||
| private ArcSegment OutlineArc { get; set; } | ||
|
|
||
| private ArcSegment BarArc { get; set; } | ||
|
|
||
| private bool AllTemplatePartsDefined | ||
| { | ||
| get { return OutlineFigure != null && OutlineArc != null && BarFigure != null && BarArc != null; } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Called when the Minimum property changes. | ||
| /// </summary> | ||
| /// <param name="oldMinimum">Old value of the Minimum property.</param> | ||
| /// <param name="newMinimum">New value of the Minimum property.</param> | ||
| protected override void OnMinimumChanged(double oldMinimum, double newMinimum) | ||
| { | ||
| base.OnMinimumChanged(oldMinimum, newMinimum); | ||
| RenderSegment(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Called when the Maximum property changes. | ||
| /// </summary> | ||
| /// <param name="oldMaximum">Old value of the Maximum property.</param> | ||
| /// <param name="newMaximum">New value of the Maximum property.</param> | ||
| protected override void OnMaximumChanged(double oldMaximum, double newMaximum) | ||
| { | ||
| base.OnMaximumChanged(oldMaximum, newMaximum); | ||
| RenderSegment(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Called when the Value property changes. | ||
| /// </summary> | ||
| /// <param name="oldValue">Old value of the Value property.</param> | ||
| /// <param name="newValue">New value of the Value property.</param> | ||
| protected override void OnValueChanged(double oldValue, double newValue) | ||
| { | ||
| base.OnValueChanged(oldValue, newValue); | ||
| RenderSegment(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Update the visual state of the control when its template is changed. | ||
| /// </summary> | ||
| protected override void OnApplyTemplate() | ||
| { | ||
| base.OnApplyTemplate(); | ||
|
|
||
| OutlineFigure = GetTemplateChild(OutlineFigurePartName) as PathFigure; | ||
| OutlineArc = GetTemplateChild(OutlineArcPartName) as ArcSegment; | ||
| BarFigure = GetTemplateChild(BarFigurePartName) as PathFigure; | ||
| BarArc = GetTemplateChild(BarArcPartName) as ArcSegment; | ||
|
|
||
| RenderAll(); | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Gets or sets the thickness of the circular ouline and segment | ||
| /// </summary> | ||
| public double Thickness | ||
| { | ||
| get { return (double)GetValue(ThicknessProperty); } | ||
| set { SetValue(ThicknessProperty, value); } | ||
| } | ||
|
|
||
| /// <summary> | ||
| /// Identifies the Thickness dependency property | ||
| /// </summary> | ||
| public static readonly DependencyProperty ThicknessProperty = DependencyProperty.Register("Thickness", typeof(double), typeof(RadialProgressBar), new PropertyMetadata(4.0, ThicknessChangedHandler)); | ||
|
||
|
|
||
| /// <summary> | ||
| /// Initializes a new instance of the <see cref="RadialProgressBar"/> class. | ||
| /// Create a default circular progress bar | ||
| /// </summary> | ||
| public RadialProgressBar() | ||
| { | ||
| this.DefaultStyleKey = typeof(RadialProgressBar); | ||
|
||
|
|
||
| Foreground = Application.Current.Resources[DefaultForegroundColorBrushName] as SolidColorBrush; | ||
|
||
| Background = Application.Current.Resources[DefaultBackgroundColorBrushName] as SolidColorBrush; | ||
|
|
||
| SizeChanged += SizeChangedHandler; | ||
| } | ||
|
|
||
| // Render outline and progress segment when thickness is changed | ||
| private static void ThicknessChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs e) | ||
| { | ||
| var sender = d as RadialProgressBar; | ||
| sender.RenderAll(); | ||
| } | ||
|
|
||
| // Render outline and progress segment when control is resized. | ||
| private void SizeChangedHandler(object sender, SizeChangedEventArgs e) | ||
| { | ||
| var self = sender as RadialProgressBar; | ||
| self.RenderAll(); | ||
| } | ||
|
|
||
| private double ComputeNormalizedRange() | ||
| { | ||
| var range = Maximum - Minimum; | ||
| var delta = Value - Minimum; | ||
| var output = range == 0.0 ? 0.0 : delta / range; | ||
| output = Math.Min(Math.Max(0.0, output), 0.9999); | ||
| return output; | ||
| } | ||
|
|
||
| // Compute size of ellipse so that the outer edge touches the bounding rectangle | ||
| private Size ComputeEllipseSize() | ||
| { | ||
| var safeThickness = Math.Max(Thickness, 0.0); | ||
| var width = Math.Max((ActualWidth - safeThickness) / 2.0, 0.0); | ||
| var height = Math.Max((ActualHeight - safeThickness) / 2.0, 0.0); | ||
| return new Size(width, height); | ||
| } | ||
|
|
||
| // Render the segment representing progress ratio. | ||
| private void RenderSegment() | ||
| { | ||
| if (!AllTemplatePartsDefined) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var normalizedRange = ComputeNormalizedRange(); | ||
|
|
||
| var angle = 2 * Math.PI * normalizedRange; | ||
| var size = ComputeEllipseSize(); | ||
| var translationFactor = Math.Max(Thickness / 2.0, 0.0); | ||
|
|
||
| double x = (Math.Sin(angle) * size.Width) + size.Width + translationFactor; | ||
| double y = (((Math.Cos(angle) * size.Height) - size.Height) * -1) + translationFactor; | ||
|
|
||
| BarArc.IsLargeArc = angle >= Math.PI; | ||
| BarArc.Point = new Point(x, y); | ||
| } | ||
|
|
||
| // Render the progress segment and the loop outline. Needs to run when control is resized or retemplated | ||
| private void RenderAll() | ||
| { | ||
| if (!AllTemplatePartsDefined) | ||
| { | ||
| return; | ||
| } | ||
|
|
||
| var size = ComputeEllipseSize(); | ||
| var segmentWidth = size.Width; | ||
| var translationFactor = Math.Max(Thickness / 2.0, 0.0); | ||
|
|
||
| OutlineFigure.StartPoint = BarFigure.StartPoint = new Point(segmentWidth + translationFactor, translationFactor); | ||
| OutlineArc.Size = BarArc.Size = new Size(segmentWidth, size.Height); | ||
| OutlineArc.Point = new Point(segmentWidth + translationFactor - 0.05, translationFactor); | ||
|
|
||
| RenderSegment(); | ||
| } | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to also add the Color enum for the Outline(Background) and Foreground so the show up as properties?