Files
OldThink/Content.Client/White/UserInterface/Controls/RadialContainer.xaml.cs
2024-01-19 13:14:12 +03:00

283 lines
8.8 KiB
C#

using System.Linq;
using System.Numerics;
using Content.Client.Gameplay;
using Content.Client.Resources;
using Content.Client.Viewport;
using JetBrains.Annotations;
using Robust.Client.Animations;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.Utility;
using Robust.Shared.Animations;
using Robust.Shared.Console;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.White.UserInterface.Controls;
public sealed class RadialContainerCommandTest : LocalizedCommands
{
public override string Command => "radialtest";
public override void Execute(IConsoleShell shell, string argStr, string[] args)
{
var radial = new RadialContainer();
for (int i = 0; i < 24; i++)
{
var testButton = radial.AddButton("Action " + i, "/Textures/Interface/emotions.svg.192dpi.png");
testButton.Controller.OnPressed += (_) => { Logger.Debug("Press gay"); };
}
radial.CloseButton.Controller.OnPressed += (_) =>
{
Logger.Debug("Close event for your own logic");
};
radial.OpenCentered();
}
}
[GenerateTypedNameReferences, Virtual]
public partial class RadialContainer : Control
{
private bool _isOpened = false;
private Vector2 _focusSize = new Vector2(64, 64);
private Vector2 _normalSize = new Vector2(50, 50);
private float _moveAniTime = 0.3f;
private float _focusAniTime = 0.25f;
private int _maxButtons = 8;
private string _backgroundTexture = "/Textures/Interface/Default/SlotBackground.png";
public const string MoveAnimationKey = "move";
public const string InSizeAnimationKey = "insize";
public const string OutSizeAnimationKey = "outsize";
public float FocusSize
{
get => _focusSize.Y;
set => _focusSize = new Vector2(value, value);
}
public float NormalSize
{
get => _normalSize.Y;
set => _normalSize = new Vector2(value, value);
}
public float MoveAnimationTime
{
get => _moveAniTime;
set => _moveAniTime = value;
}
public float FocusAnimationTime
{
get => _focusAniTime;
set => _focusAniTime = value;
}
public bool IsAction = true;
public RadialContainer() : base()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
public void Open(Vector2 position)
{
AddToRoot();
LayoutContainer.SetPosition(this, position);
UpdateButtons();
}
public void OpenCentered()
{
AddToRoot();
if (Parent != null)
LayoutContainer.SetPosition(this, (Parent.Size/2) - (this.Size/2));
else
LayoutContainer.SetPosition(this, (UserInterfaceManager.MainViewport.Size/2) - (this.Size/2));
UpdateButtons();
}
public void OpenCenteredWithViewport()
{
if (UserInterfaceManager.ActiveScreen == null)
return;
var ent = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity;
if (ent == null)
return;
if (!IoCManager.Resolve<IEntityManager>().TryGetComponent(ent, out TransformComponent? xform))
return;
AddToRoot();
LayoutContainer.SetPosition(this, (IoCManager.Resolve<IEyeManager>().MapToScreen(xform.MapPosition).Position * 1.5f));
UpdateButtons();
}
public void Close(bool canDispose = true)
{
Parent?.RemoveChild(this);
Visible = false;
_isOpened = false;
if (canDispose)
Dispose();
}
public RadialButton AddButton(string action, string? texture = null)
{
var button = new RadialButton();
button.Content = action;
button.Controller.TextureNormal = IoCManager.Resolve<IResourceCache>().GetTexture(_backgroundTexture);
if (texture != null)
button.BackgroundTexture.Texture = IoCManager.Resolve<IResourceCache>().GetTexture(texture);
Layout.AddChild(button);
return button;
}
private void AddToRoot()
{
if (_isOpened)
return;
UserInterfaceManager.WindowRoot.AddChild(this);
_isOpened = !_isOpened;
}
private void UpdateButtons()
{
Visible = true;
var angleDegrees = 360/Layout.ChildCount;
var stepAngle = -angleDegrees + -90;
var distance = FocusSize * 1.2;
if (Layout.Children.Count() > _maxButtons)
{
for (int i = 0; i < (Layout.Children.Count() - _maxButtons); i++)
{
distance += (NormalSize/3);
}
}
foreach (var child in Layout.Children)
{
var button = (RadialButton)child;
button.ButtonSize = _normalSize;
stepAngle += angleDegrees;
var pos = GetPointFromPolar(stepAngle, distance);
PlayRadialAnimation(button, pos, MoveAnimationKey);
button.Controller.OnMouseEntered += (_) =>
{
PlaySizeAnimation(button, _focusSize, OutSizeAnimationKey, InSizeAnimationKey);
ActionLabel.Text = button.Content ?? string.Empty;
ActionLabel.Visible = IsAction;
};
button.Controller.OnMouseExited += (_) =>
{
PlaySizeAnimation(button, _normalSize, InSizeAnimationKey, OutSizeAnimationKey);
ActionLabel.Visible = false;
};
}
CloseButton.ButtonSize = _normalSize;
CloseButton.Controller.OnMouseEntered += (_) =>
{
PlaySizeAnimation(CloseButton, _focusSize, OutSizeAnimationKey, InSizeAnimationKey);
ActionLabel.Text = CloseButton.Content ?? string.Empty;
ActionLabel.Visible = true;
};
CloseButton.Controller.OnMouseExited += (_) =>
{
PlaySizeAnimation(CloseButton, _normalSize, InSizeAnimationKey, OutSizeAnimationKey);
ActionLabel.Visible = false;
};
CloseButton.Controller.OnPressed += (_) =>
{
Close();
};
}
private void PlayRadialAnimation(Control button, Vector2 pos, string playKey)
{
var anim = new Animation
{
Length = TimeSpan.FromMilliseconds(_moveAniTime * 1000),
AnimationTracks =
{
new AnimationTrackControlProperty
{
Property = nameof(RadialButton.Offset),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(new Vector2(0,0), 0f),
new AnimationTrackProperty.KeyFrame(pos, _moveAniTime)
}
}
}
};
if (!button.HasRunningAnimation(playKey))
button.PlayAnimation(anim, playKey);
}
private void PlaySizeAnimation(Control button, Vector2 size, string playKey, string? stopKey)
{
var anim = new Animation
{
Length = TimeSpan.FromMilliseconds(_focusAniTime * 1000),
AnimationTracks =
{
new AnimationTrackControlProperty
{
Property = nameof(RadialButton.ButtonSize),
InterpolationMode = AnimationInterpolationMode.Linear,
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(button.Size, 0f),
new AnimationTrackProperty.KeyFrame(size, _focusAniTime)
}
}
}
};
if (stopKey != null && button.HasRunningAnimation(stopKey))
button.StopAnimation(stopKey);
if (!button.HasRunningAnimation(playKey))
button.PlayAnimation(anim, playKey);
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
foreach (var child in Layout.Children)
{
var button = (RadialButton)child;
LayoutContainer.SetPosition(child, button.Offset - (button.Size/2));
}
LayoutContainer.SetPosition(CloseButton, CloseButton.Offset - (CloseButton.Size/2));
LayoutContainer.SetPosition(ActionBox, new Vector2(0 - (ActionLabel.Size.X), FocusSize*1.5f));
}
private static Vector2 GetPointFromPolar(double angleDegrees, double distance)
{
var angleRadians = angleDegrees * (Math.PI / 180.0);
var x = distance * Math.Cos(angleRadians);
var y = distance * Math.Sin(angleRadians);
return new Vector2((int)Math.Round(x), (int)Math.Round(y));
}
}