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

Feature/make radial menu great again #32653

Open
wants to merge 19 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 14 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
14 changes: 7 additions & 7 deletions Content.Client/Chat/UI/EmotesMenu.xaml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<ui:RadialMenu xmlns="https://spacestation14.io"
<ui:RadialMenu xmlns="https://spacestation14.io"
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
Fildrance marked this conversation as resolved.
Show resolved Hide resolved
BackButtonStyleClass="RadialMenuBackButton"
CloseButtonStyleClass="RadialMenuCloseButton"
Expand All @@ -8,15 +8,15 @@

<!-- Main -->
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" Radius="64" ReserveSpaceForHiddenChildren="False">
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-general'}" TargetLayer="General" Visible="False">
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-general'}" TargetLayer="General" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Clothing/Head/Soft/mimesoft.rsi/icon.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-vocal'}" TargetLayer="Vocal" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-vocal'}" TargetLayer="Vocal" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Emotes/vocal.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-hands'}" TargetLayer="Hands" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'emote-menu-category-hands'}" TargetLayer="Hands" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Clothing/Hands/Gloves/latex.rsi/icon.png"/>
</ui:RadialMenuTextureButton>
</ui:RadialMenuTextureButtonWithSector>
</ui:RadialContainer>

<!-- General -->
Expand Down
2 changes: 1 addition & 1 deletion Content.Client/Chat/UI/EmotesMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ private void AddEmoteClickAction(RadialContainer container)
}


public sealed class EmoteMenuButton : RadialMenuTextureButton
public sealed class EmoteMenuButton : RadialMenuTextureButtonWithSector
{
public ProtoId<EmotePrototype> ProtoId { get; set; }
}
2 changes: 1 addition & 1 deletion Content.Client/Ghost/GhostRoleRadioMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ private void AddGhostRoleRadioMenuButtonOnClickActions(Control control)
}
}

public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButton
public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButtonWithSector
{
public ProtoId<GhostRolePrototype> ProtoId { get; set; }
}
20 changes: 10 additions & 10 deletions Content.Client/RCD/RCDMenu.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,21 +12,21 @@

<!-- Entry layer (shows main categories) -->
<ui:RadialContainer Name="Main" VerticalExpand="True" HorizontalExpand="True" Radius="64" ReserveSpaceForHiddenChildren="False">
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-walls-and-flooring'}" TargetLayer="WallsAndFlooring" Visible="False">
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-walls-and-flooring'}" TargetLayer="WallsAndFlooring" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Radial/RCD/walls_and_flooring.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-windows-and-grilles'}" TargetLayer="WindowsAndGrilles" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-windows-and-grilles'}" TargetLayer="WindowsAndGrilles" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Radial/RCD/windows_and_grilles.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-airlocks'}" TargetLayer="Airlocks" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-airlocks'}" TargetLayer="Airlocks" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Radial/RCD/airlocks.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-electrical'}" TargetLayer="Electrical" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-electrical'}" TargetLayer="Electrical" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Radial/RCD/multicoil.png"/>
</ui:RadialMenuTextureButton>
<ui:RadialMenuTextureButton StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-lighting'}" TargetLayer="Lighting" Visible="False">
</ui:RadialMenuTextureButtonWithSector>
<ui:RadialMenuTextureButtonWithSector StyleClasses="RadialMenuButton" SetSize="64 64" ToolTip="{Loc 'rcd-component-lighting'}" TargetLayer="Lighting" Visible="False">
<TextureRect VerticalAlignment="Center" HorizontalAlignment="Center" TextureScale="2 2" TexturePath="/Textures/Interface/Radial/RCD/lighting.png"/>
</ui:RadialMenuTextureButton>
</ui:RadialMenuTextureButtonWithSector>
</ui:RadialContainer>

<!-- Walls and flooring -->
Expand Down
11 changes: 2 additions & 9 deletions Content.Client/RCD/RCDMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -99,9 +99,7 @@ public void Refresh()
// is visible in the main radial container (as these all start with Visible = false)
foreach (var child in main.Children)
{
var castChild = child as RadialMenuTextureButton;

if (castChild is not RadialMenuTextureButton)
if (child is not RadialMenuTextureButton castChild)
continue;

if (castChild.TargetLayer == proto.Category)
Expand Down Expand Up @@ -169,12 +167,7 @@ private void AddRCDMenuButtonOnClickActions(Control control)
}
}

public sealed class RCDMenuButton : RadialMenuTextureButton
public sealed class RCDMenuButton : RadialMenuTextureButtonWithSector
{
public ProtoId<RCDPrototype> ProtoId { get; set; }

public RCDMenuButton()
{

}
}
2 changes: 1 addition & 1 deletion Content.Client/Silicons/StationAi/StationAiMenu.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ private void UpdatePosition()
}
}

public sealed class StationAiMenuButton(BaseStationAiAction action) : RadialMenuTextureButton
public sealed class StationAiMenuButton(BaseStationAiAction action) : RadialMenuTextureButtonWithSector
{
public BaseStationAiAction Action = action;
}
69 changes: 55 additions & 14 deletions Content.Client/UserInterface/Controls/RadialContainer.cs
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -67,37 +67,77 @@ public RadialContainer()
{

}

protected override void Draw(DrawingHandleScreen handle)

/// <inheritdoc />
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{

const float baseRadius = 100f;
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved
const float radiusIncrement = 5f;
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved

var children = ReserveSpaceForHiddenChildren ? Children : Children.Where(x => x.Visible);

var children = ReserveSpaceForHiddenChildren
? Children
: Children.Where(x => x.Visible);

var childCount = children.Count();

// Add padding from the center at higher child counts so they don't overlap.
Radius = baseRadius + (childCount * radiusIncrement);

// Add padding from the center at higher child counts so they don't overlap.
Radius = baseRadius + (childCount * radiusIncrement);
chromiumboy marked this conversation as resolved.
Show resolved Hide resolved

var isAntiClockwise = RadialAlignment == RAlignment.AntiClockwise;

// Determine the size of the arc, accounting for clockwise and anti-clockwise arrangements
var arc = AngularRange.Y - AngularRange.X;
arc = (arc < 0) ? MathF.Tau + arc : arc;
arc = (RadialAlignment == RAlignment.AntiClockwise) ? MathF.Tau - arc : arc;
arc = arc < 0
? MathF.Tau + arc
: arc;
arc = isAntiClockwise
? MathF.Tau - arc
: arc;

// Account for both circular arrangements and arc-based arrangements
var childMod = MathHelper.CloseTo(arc, MathF.Tau, 0.01f) ? 0 : 1;
var childMod = MathHelper.CloseTo(arc, MathF.Tau, 0.01f)
? 0
: 1;

// Determine the separation between child elements
var sepAngle = arc / (childCount - childMod);
sepAngle *= (RadialAlignment == RAlignment.AntiClockwise) ? -1f : 1f;
sepAngle *= isAntiClockwise
? -1f
: 1f;

var controlCenter = finalSize * 0.5f;

// Adjust the positions of all the child elements
foreach (var (i, child) in children.Select((x, i) => (i, x)))
var query = children.Select((x, index) => (index, x));
foreach (var (childIndex, child) in query)
{
var position = new Vector2(Radius * MathF.Sin(AngularRange.X + sepAngle * i) + Width / 2f - child.Width / 2f, -Radius * MathF.Cos(AngularRange.X + sepAngle * i) + Height / 2f - child.Height / 2f);
const float angleOffset = MathF.PI * 0.5f;

var targetAngleOfChild = AngularRange.X + sepAngle * (childIndex + 0.5f) + angleOffset;

// flooring values for snapping float values to physical grid -
// it prevents gaps and overlapping between different button segments
var position = new Vector2(
MathF.Floor(Radius * MathF.Cos(targetAngleOfChild)),
MathF.Floor(-Radius * MathF.Sin(targetAngleOfChild))
) + controlCenter - child.DesiredSize * 0.5f + Position;

SetPosition(child, position);
Fildrance marked this conversation as resolved.
Show resolved Hide resolved

// radial menu buttons with sector need to also know in which sector and around which point
// they should be rendered, how much space sector should should take etc.
if (child is IRadialMenuItemWithSector tb)
{
tb.AngleSectorFrom = sepAngle * childIndex;
tb.AngleSectorTo = sepAngle * (childIndex + 1);
tb.AngleOffset = angleOffset;
tb.InnerRadius = Radius / 2;
tb.OuterRadius = Radius * 2;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the inner and outer radii are going to be set by RadialContainer, the multipliers need to be fields, no magic numbers

I'd suggest 1.5f for the the outer radius, there's too much empty space inside the sector otherwise

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

extracting property for multipliers - thats actually good idea : >
about 1.5f - ok, but bear in mind WHY we are adding those changes - we want control to be not requiring precision, so you can use it very-very fast. Making it too small make it not UX but just visual change. But having it variable - we can change it in any moment - so its fine.

tb.ParentCenter = controlCenter;
}
}

return base.ArrangeOverride(finalSize);
}

/// <summary>
Expand All @@ -109,4 +149,5 @@ public enum RAlignment : byte
Clockwise,
AntiClockwise,
}

}
Loading
Loading