Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Creating a Circular GUI

So one of my latest side projects is developing a application detection and populating assistant. Programmatically I am absolutely fine populating the backend code for what I want accomplished. But I've run into a road block on the GUI. I need a GUI that is a Quarter circle that extends from the task bar to the bottom right of a standard windows operating system. When the user doubleclicks on the application, the circle rotates into view. I can do this with a typical windows form that has a transparent background and a fancy background image. But the square properties of the form will still apply when the user has the application open. And I do not want to block the user from higher priority apps when the circle is open.

The edges must be not be selectable

I'm not really stuck on any one specific programming language. Although, I would prefer that it not contain much 3d rendering as it is supposed to be a computing assistant and should not maintain heavy RAM/CPU consumption whilst the user is browsing around.

Secondarily, I would like the notches of the outer rings to be mobile and extend beyond the gui a mere centimeter or so.

I would not be here if I hadn't had scoured the internet for direction on this capability. But what I've found is application GUI's of this nature tend to be most used in mobile environments.

So my questions are: How can I accomplish this? What programming language can I write this in? Is this a capability currently available? Will I have to sacrifice user control for design?

like image 583
Rich Avatar asked Mar 10 '14 23:03

Rich


People also ask

How do you make a circle GUI?

To make a circular GUI all you need to do is find/upload an image of a circle, insert it into an ImageLabel then set the BackgroundTransparency to 1.

How do you make a circle GUI on Roblox studio?

trol rounded borders on UI objects. Set the CornerRadius to (1, 0). You'll achieve a perfect circle.

How do you make a circle load on Roblox?

To make Circular Progress work, you only need to change percentage between 0 and 100. You can also use tween on percentage. If it is greater than 100 (less than 0), it will stays at 100 (0). So it doesn't affect Circular Progress.


1 Answers

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.

circle gui

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:

creating the shape

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);
        }
like image 157
aegar Avatar answered Oct 02 '22 00:10

aegar