Creating a Circular GUI
I wrote out some code doing something close to what you described.
I’m not sure to understand how you do want the circle to appear, so I just let a part of it always visible.And I didn’t get the part about the mobile outer ring.
Creating and placing the window
The XAML is very simple, it just needs a grid to host the circle’s pieces, and some attributes to remove window decorations and taskbar icon:
<Window x:Class="circle.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Circle" Width="250" Height="250" AllowsTransparency="True" Background="Transparent" MouseDown="WindowClicked" ShowInTaskbar="False" WindowStyle="None"> <Grid Name="Container"/></Window>
To place the window in the bottom right corner, you can use SystemParameters.WorkArea in the constructor:
public MainWindow(){ InitializeComponent(); var desktopDim = SystemParameters.WorkArea; Left = desktopDim.Right - Width; Top = desktopDim.Bottom - Height;}
Creating the shape
I build the circle as a bunch of circle pieces that I generate from code behind:
private Path CreateCirclePart() { var circle = new CombinedGeometry { GeometryCombineMode = GeometryCombineMode.Exclude, Geometry1 = new EllipseGeometry { Center = _center, RadiusX = _r2, RadiusY = _r2 }, Geometry2 = new EllipseGeometry { Center = _center, RadiusX = _r1, RadiusY = _r1 } }; var sideLength = _r2 / Math.Cos((Math.PI/180) * (ItemAngle / 2.0)); var x = _center.X - Math.Abs(sideLength * Math.Cos(ItemAngle * Math.PI / 180)); var y = _center.Y - Math.Abs(sideLength * Math.Sin(ItemAngle * Math.PI / 180)); var triangle = new PathGeometry( new PathFigureCollection(new List<PathFigure>{ new PathFigure( _center, new List<PathSegment> { new LineSegment(new Point(_center.X - Math.Abs(sideLength),_center.Y), true), new LineSegment(new Point(x,y), true) }, true) })); var path = new Path { Fill = new SolidColorBrush(Colors.Cyan), Stroke = new SolidColorBrush(Colors.Black), StrokeThickness = 1, RenderTransformOrigin = new Point(1, 1), RenderTransform = new RotateTransform(0), Data = new CombinedGeometry { GeometryCombineMode = GeometryCombineMode.Intersect, Geometry1 = circle, Geometry2 = triangle } }; return path; }
First step is to build two concentric circles and to combine them in a CombinedGeometry with CombineMode set to exclude. Then I create a triangle just tall enough to contain the section of the ring that I want, and I keep the intersection of these shapes.
Seeing it with the second CombineMode set to xor may clarify:
Building the circle
The code above uses some instance fields that make it generic: you can change the number of pieces in the circle or their radius; it will always fill the corner.
I then populate a list with the required number of shape, and add them to the grid:
private const double MenuWidth = 80;private const int ItemCount = 6;private const double AnimationDelayInSeconds = 0.3;private readonly Point _center;private readonly double _r1, _r2;private const double ItemSpacingAngle = 2;private const double ItemAngle = (90.0 - (ItemCount - 1) * ItemSpacingAngle) / ItemCount;private readonly List<Path> _parts = new List<Path>();private bool _isOpen;public MainWindow(){ InitializeComponent(); // window in the lower right desktop corner var desktopDim = SystemParameters.WorkArea; Left = desktopDim.Right - Width; Top = desktopDim.Bottom - Height; _center = new Point(Width, Height); _r2 = Width; _r1 = _r2 - MenuWidth; Loaded += (s, e) => CreateMenu();}private void CreateMenu(){ for (var i = 0; i < ItemCount; ++i) { var part = CreateCirclePart(); _parts.Add(part); Container.Children.Add(part); }}
ItemSpacingAngle define the blank between two consecutive pieces.
Animating the circle
The final step is to unfold the circle. Using a rotateAnimation over the path rendertransform make it easy.Remember this part of the CreateCirclePart function:
RenderTransformOrigin = new Point(1, 1),RenderTransform = new RotateTransform(0),
The RenderTransform tells that the animation we want to perform is a rotation, and RenderTransformOrigin set the rotation origin to the lower right corner of the shape (unit is percent).We can now animate it on click event:
private void WindowClicked(object sender, MouseButtonEventArgs e) { for (var i = 0; i < ItemCount; ++i) { if (!_isOpen) UnfoldPart(_parts[i], i); else FoldPart(_parts[i], i); } _isOpen = !_isOpen; } private void UnfoldPart(Path part, int pos) { var newAngle = pos * (ItemAngle + ItemSpacingAngle); var rotateAnimation = new DoubleAnimation(newAngle, TimeSpan.FromSeconds(AnimationDelayInSeconds)); var tranform = (RotateTransform)part.RenderTransform; tranform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation); } private void FoldPart(Path part, int pos) { var rotateAnimation = new DoubleAnimation(0, TimeSpan.FromSeconds(AnimationDelayInSeconds)); var tranform = (RotateTransform)part.RenderTransform; tranform.BeginAnimation(RotateTransform.AngleProperty, rotateAnimation); }
Not actually answering this, but I liked your question enough that I wanted to get a minimal proof of concept together for fun and I really enjoyed doing it so i thought I'd share my xaml with you:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ed="http://schemas.microsoft.com/expression/2010/drawing" x:Class="WpfApplication1.Window2" Title="Window2" Height="150" Width="150" Topmost="True" MouseLeftButtonDown="Window2_OnMouseLeftButtonDown" AllowsTransparency="True" OpacityMask="White" WindowStyle="None" Background="Transparent" > <Grid> <ed:Arc ArcThickness="40" ArcThicknessUnit="Pixel" EndAngle="0" Fill="Blue" HorizontalAlignment="Left" Height="232" Margin="33,34,-115,-116" Stretch="None" StartAngle="270" VerticalAlignment="Top" Width="232" RenderTransformOrigin="0.421,0.471"/> <Button HorizontalAlignment="Left" VerticalAlignment="Top" Width="41" Margin="51.515,71.385,0,0" Click="Button_Click" RenderTransformOrigin="0.5,0.5"> <Button.Template> <ControlTemplate> <Path Data="M50.466307,88.795148 L61.75233,73.463763 89.647286,102.42368 81.981422,113.07109 z" Fill="DarkBlue" HorizontalAlignment="Left" Height="39.606" Stretch="Fill" VerticalAlignment="Top" Width="39.181"/> </ControlTemplate> </Button.Template> </Button> </Grid></Window>
And it looks like this: