Skip to content
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

Porting RadialGauge #45

Merged
merged 17 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions components/RadialGauge/OpenSolution.bat
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
@ECHO OFF

powershell ..\..\tooling\ProjectHeads\GenerateSingleSampleHeads.ps1 -componentPath %CD% %*
31 changes: 31 additions & 0 deletions components/RadialGauge/samples/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.

MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.

For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
8 changes: 8 additions & 0 deletions components/RadialGauge/samples/RadialGauge.Samples.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>RadialGauge</ToolkitComponentName>
</PropertyGroup>

<!-- Sets this up as a toolkit component's sample project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SampleProject.props" />
</Project>
58 changes: 58 additions & 0 deletions components/RadialGauge/samples/RadialGauge.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
---
title: RadialGauge
author: xamlbrewer
description: The Radial Gauge Control displays a value in a certain range using a needle on a circular face.
keywords: RadialGauge, Control, Input
dev_langs:
- csharp
category: Controls
subcategory: Input
discussion-id: 0
issue-id: 0
---

# RadialGauge

The [Radial Gauge](/dotnet/api/microsoft.toolkit.uwp.ui.controls.radialgauge) control displays a value in a certain range using a needle on a circular face. This control will make data visualizations and dashboards more engaging with rich style and interactivity.
The round gauges are powerful, easy to use, and highly configurable to present dashboards capable of displaying clocks, industrial panels, automotive dashboards, and even aircraft cockpits.

The Radial Gauge supports animated transitions between configuration states. The control gradually animates as it redraws changes to the needle, needle position, scale range, color range, and more.

> [!Sample RadialGaugeSample]

## Properties

| Property | Type | Description |
| -- | -- | -- |
| Column | double | Gets or sets the column of the scale |
| IsInteractive | bool | Gets or sets a value indicating whether the control accepts setting its value through interaction |
| MaxAngle | int | Gets or sets the end angle of the scale, which corresponds with the Maximum value, in degrees |
| Maximum | double | Gets or sets the maximum value of the scale |
| MinAngle | int | Gets or sets the start angle of the scale, which corresponds with the Minimum value, in degrees |
| Minimum | double | Gets or sets the minimum value of the scale |
| NeedleBrush | SolidColorBrush | Gets or sets the needle background |
| NeedleBorderBrush | SolidColorBrush | Gets or sets the needle border |
| NeedleBorderThickness | double | Gets or sets the thickness of the border |
| NeedleLength | double | Gets or sets the needle length, in percentage of the gauge radius |
| NeedleWidth | double | Gets or sets the needle width, in percentage of the gauge radius |
| NormalizedMaxAngle | double | Gets the normalized maximum angle |
| NormalizedMinAngle | double | Gets the normalized minimum angle |
| ScaleBrush | Brush | Gets or sets the scale brush |
| ScalePadding | double | Gets or sets the distance of the scale from the outside of the control, in percentage of the gauge radius |
| ScaleTickCornerRadius | double | Gets or sets the cornerradius of the scale tick
| ScaleTickBrush | SolidColorBrush | Gets or sets the scale tick brush |
| ScaleTickLength | double | Gets or sets the length of the scaleticks, in percentage of the gauge radius |
| ScaleTickWidth | double | Gets or sets the width of the scale ticks, in percentage of the gauge radius |
| ScaleWidth | double | Gets or sets the width of the scale, in percentage of the gauge radius |
| StepSize | double | Gets or sets the rounding interval for the Value |
| TickBrush | SolidColorBrush | Gets or sets the outer tick brush |
| TickCornerRadius | double | Gets or sets the cornerradius of the tick |
| TickLength | double | Gets or sets the length of the ticks, in percentage of the gauge radius |
| TickPadding | double | Gets or sets the distance of the ticks from the outside of the control, in percentage of the gauge radius |
| TickSpacing | int | Gets or sets the tick spacing, in units |
| TickWidth | double | Gets or sets the width of the ticks, in percentage of the gauge radius |
| TrailBrush | Brush | Gets or sets the trail brush |
| Unit | string | Gets or sets the displayed unit measure |
| Value | double | Gets or sets the current value |
| ValueAngle | double | Gets or sets the current angle of the needle (between MinAngle and MaxAngle). Setting the angle will update the Value |
| ValueStringFormat | string | Gets or sets the value string format |
35 changes: 35 additions & 0 deletions components/RadialGauge/samples/RadialGaugeSample.xaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!-- Licensed to the .NET Foundation under one or more agreements. The .NET Foundation licenses this file to you under the MIT license. See the LICENSE file in the project root for more information. -->
<Page x:Class="RadialGaugeExperiment.Samples.RadialGaugeSample"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:CommunityToolkit.WinUI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="using:RadialGaugeExperiment.Samples"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<StackPanel HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal">
<controls:RadialGauge x:Name="RadialGauge"
Width="280"
IsEnabled="{x:Bind Enabled, Mode=OneWay}"
IsInteractive="{x:Bind IsInteractive, Mode=OneWay}"
MaxAngle="{x:Bind (x:Int32)MaxAngle, Mode=OneWay}"
Maximum="240"
MinAngle="{x:Bind (x:Int32)MinAngle, Mode=OneWay}"
Minimum="0"
NeedleLength="{x:Bind NeedleLength, Mode=OneWay}"
NeedleWidth="{x:Bind NeedleWidth, Mode=OneWay}"
ScalePadding="{x:Bind ScalePadding, Mode=OneWay}"
ScaleTickWidth="{x:Bind ScaleTickWidth, Mode=OneWay}"
ScaleWidth="{x:Bind ScaleWidth, Mode=OneWay}"
StepSize="{x:Bind StepSize, Mode=OneWay}"
TickLength="{x:Bind TickLength, Mode=OneWay}"
TickPadding="{x:Bind TickPadding, Mode=OneWay}"
TickSpacing="{x:Bind (x:Int32)TickSpacing, Mode=OneWay}"
TickWidth="{x:Bind TickWidth, Mode=OneWay}"
ValueStringFormat="N0"
Value="{x:Bind Value, Mode=OneWay}" />
</StackPanel>
</Page>
35 changes: 35 additions & 0 deletions components/RadialGauge/samples/RadialGaugeSample.xaml.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using CommunityToolkit.WinUI.Controls;

namespace RadialGaugeExperiment.Samples;

/// <summary>
/// An example sample page of a custom control inheriting from Panel.
/// </summary>
[ToolkitSampleBoolOption("Enabled", true, Title = "IsEnabled")]
[ToolkitSampleNumericOption("Value", 120, 0, 240, 1, false, Title = "Value")]
[ToolkitSampleNumericOption("StepSize", 30, 5, 30, 1, false, Title = "StepSize")]
[ToolkitSampleBoolOption("IsInteractive", true, Title = "IsInteractive")]
[ToolkitSampleNumericOption("TickSpacing", 15, 10, 30, 1, false, Title = "TickSpacing")]
[ToolkitSampleNumericOption("ScaleWidth", 12, 4, 50, 1, false, Title = "ScaleWidth")]
[ToolkitSampleNumericOption("MinAngle", -150, -150, 360, 1, false, Title = "MinAngle")]
[ToolkitSampleNumericOption("MaxAngle", 150, 0, 360, 1, false, Title = "MaxAngle")]
[ToolkitSampleNumericOption("NeedleWidth", 4, 0, 10, 1, false, Title = "NeedleWidth")]
[ToolkitSampleNumericOption("NeedleLength", 60, 0, 100, 1, false, Title = "NeedleLength")]
[ToolkitSampleNumericOption("TickLength", 6, 0, 30, 1, false, Title = "TickLength")]
[ToolkitSampleNumericOption("TickWidth", 2, 0, 30, 1, false, Title = "TickWidth")]
[ToolkitSampleNumericOption("ScalePadding", 0, 0, 100, 1, false, Title = "ScalePadding")]
[ToolkitSampleNumericOption("TickPadding", 24, 0, 100, 1, false, Title = "TickPadding")]
[ToolkitSampleNumericOption("ScaleTickWidth", 0, 0, 20, 1, false, Title = "ScaleTickWidth")]

[ToolkitSample(id: nameof(RadialGaugeSample), "RadialGauge", description: $"A sample for showing how to create and use a {nameof(RadialGauge)} control.")]
public sealed partial class RadialGaugeSample : Page
{
public RadialGaugeSample()
{
this.InitializeComponent();
}
}
13 changes: 13 additions & 0 deletions components/RadialGauge/src/AdditionalAssemblyInfo.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System.Runtime.CompilerServices;

// These `InternalsVisibleTo` calls are intended to make it easier for
// for any internal code to be testable in all the different test projects
// used with the Labs infrastructure.
[assembly: InternalsVisibleTo("RadialGauge.Tests.Uwp")]
[assembly: InternalsVisibleTo("RadialGauge.Tests.WinAppSdk")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.Uwp")]
[assembly: InternalsVisibleTo("CommunityToolkit.Tests.WinAppSdk")]
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<Project Sdk="MSBuild.Sdk.Extras/3.0.23">
<PropertyGroup>
<ToolkitComponentName>RadialGauge</ToolkitComponentName>
<Description>This package contains RadialGauge.</Description>
<Version>0.0.1</Version>

<!-- Rns suffix is required for namespaces shared across projects. See https://github.com/CommunityToolkit/Labs-Windows/issues/152 -->
<RootNamespace>CommunityToolkit.WinUI.Controls.RadialGaugeRns</RootNamespace>
</PropertyGroup>

<ItemGroup>
<ProjectReference Include="..\..\Helpers\src\CommunityToolkit.WinUI.Helpers.csproj" />
<ProjectReference Include="..\..\Extensions\src\CommunityToolkit.WinUI.Extensions.csproj" />
</ItemGroup>

<!-- Sets this up as a toolkit component's source project -->
<Import Project="$(ToolingDirectory)\ToolkitComponent.SourceProject.props" />

<PropertyGroup>
<PackageId>$(PackageIdPrefix).$(PackageIdVariant).Controls.$(ToolkitComponentName)</PackageId>
</PropertyGroup>
</Project>
31 changes: 31 additions & 0 deletions components/RadialGauge/src/Dependencies.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!--
WinUI 2 under UWP uses TargetFramework uap10.0.*
WinUI 3 under WinAppSdk uses TargetFramework net6.0-windows10.*
However, under Uno-powered platforms, both WinUI 2 and 3 can share the same TargetFramework.

MSBuild doesn't play nicely with this out of the box, so we've made it easy for you.

For .NET Standard packages, you can use the Nuget Package Manager in Visual Studio.
For UWP / WinAppSDK / Uno packages, place the package references here.
-->
<Project>
<!-- WinUI 2 / UWP -->
<ItemGroup Condition="'$(IsUwp)' == 'true'">
<!-- <PackageReference Include="Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 2 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '2'">
<!-- <PackageReference Include="Uno.Microsoft.Toolkit.Uwp.UI.Controls.Primitives" Version="7.1.11"/> -->
</ItemGroup>

<!-- WinUI 3 / WinAppSdk -->
<ItemGroup Condition="'$(IsWinAppSdk)' == 'true'">
<!-- <PackageReference Include="CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.2"/> -->
</ItemGroup>

<!-- WinUI 3 / Uno -->
<ItemGroup Condition="'$(IsUno)' == 'true' AND '$(WinUIMajorVersion)' == '3'">
<!-- <PackageReference Include="Uno.CommunityToolkit.WinUI.UI.Controls.Primitives" Version="7.1.100-dev.15.g12261e2626"/> -->
</ItemGroup>
</Project>
9 changes: 9 additions & 0 deletions components/RadialGauge/src/MultiTarget.props
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<Project>
<PropertyGroup>
<!--
MultiTarget is a custom property that indicates which target a project is designed to be built for / run on.
Used to create project references, generate solution files, enable/disable TargetFrameworks, and build nuget packages.
-->
<MultiTarget>uwp;wasdk;</MultiTarget>
</PropertyGroup>
</Project>
119 changes: 119 additions & 0 deletions components/RadialGauge/src/RadialGauge.Input.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using VirtualKey = Windows.System.VirtualKey;
using VirtualKeyModifiers = Windows.System.VirtualKeyModifiers;

namespace CommunityToolkit.WinUI.Controls;
public partial class RadialGauge : RangeBase
{
private void RadialGauge_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
SetGaugeValueFromPoint(e.Position);
}

private void RadialGauge_Tapped(object sender, TappedRoutedEventArgs e)
{
SetGaugeValueFromPoint(e.GetPosition(this));
}

private void RadialGauge_PointerReleased(object sender, PointerRoutedEventArgs e)
{
if (IsInteractive)
{
e.Handled = true;
}
}

private void SetKeyboardAccelerators()
{
// Small step
AddKeyboardAccelerator(VirtualKeyModifiers.None, VirtualKey.Left, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Max(gauge.Minimum, gauge.Value - Math.Max(gauge.StepSize, gauge.SmallChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.None, VirtualKey.Up, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Min(gauge.Maximum, gauge.Value + Math.Max(gauge.StepSize, gauge.SmallChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.None, VirtualKey.Right, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Min(gauge.Maximum, gauge.Value + Math.Max(gauge.StepSize, gauge.SmallChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.None, VirtualKey.Down, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Max(gauge.Minimum, gauge.Value - Math.Max(gauge.StepSize, gauge.SmallChange));
kaea.Handled = true;
}
});

// Large step
AddKeyboardAccelerator(VirtualKeyModifiers.Control, VirtualKey.Left, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Max(gauge.Minimum, gauge.Value - Math.Max(gauge.StepSize, gauge.LargeChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.Control, VirtualKey.Up, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Min(gauge.Maximum, gauge.Value + Math.Max(gauge.StepSize, gauge.LargeChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.Control, VirtualKey.Right, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Min(gauge.Maximum, gauge.Value + Math.Max(gauge.StepSize, gauge.LargeChange));
kaea.Handled = true;
}
});

AddKeyboardAccelerator(VirtualKeyModifiers.Control, VirtualKey.Down, static (_, kaea) =>
{
if (kaea.Element is RadialGauge gauge)
{
gauge.Value = Math.Max(gauge.Minimum, gauge.Value - Math.Max(gauge.StepSize, gauge.LargeChange));
kaea.Handled = true;
}
});
}

private void AddKeyboardAccelerator(
VirtualKeyModifiers keyModifiers,
VirtualKey key,
TypedEventHandler<KeyboardAccelerator, KeyboardAcceleratorInvokedEventArgs> handler)
{
var accelerator = new KeyboardAccelerator()
{
Modifiers = keyModifiers,
Key = key
};
accelerator.Invoked += handler;
KeyboardAccelerators.Add(accelerator);
}
}
Loading