Files
space-station-14/Content.Client/Humanoid/LayerMarkingOrderer.xaml.cs
pathetic meowmeow 8cf744ec55 Visual nubody (humanoid appearance refactor) (#42476)
* initial visual nubody

* oops overlay

* im so pheeming rn

* conversion...

* tests

* comeback of the underwear

* oops eyes

* blabbl

* zeds

* yaml linted

* search and visible count constraints

* reordering

* preserve previously selected markings colors

* fix test

* some ui niceties

* ordering

* make DB changes backwards-compatible/downgrade-friendly

* fix things again

* fix migration

* vulpkanin markings limit increase

* wrapping

* code cleanup and more code cleanup and more code cleanup and more code cleanup and

* fix slop ports

* better sampling API

* make filter work + use the method i made for its intended purpose

* fix test fails real quick

* magic mirror cleanup, remove TODO

* don't 0-init the organ profile data

* remove deltastates

---------

Co-authored-by: Princess Cheeseballs <66055347+Pronana@users.noreply.github.com>
2026-01-20 07:07:53 +00:00

193 lines
5.7 KiB
C#

using System.Linq;
using System.Numerics;
using Content.Client.Interaction;
using Content.Client.Stylesheets;
using Content.Shared.Body;
using Content.Shared.Humanoid.Markings;
using Content.Shared.Humanoid;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.Humanoid;
[GenerateTypedNameReferences]
public sealed partial class LayerMarkingOrderer : BoxContainer
{
private readonly ProtoId<OrganCategoryPrototype> _organ;
private readonly HumanoidVisualLayers _layer;
private readonly MarkingsViewModel _markingsModel;
private readonly DragDropHelper<LayerMarkingDragged> _dragDropHelper;
private readonly List<LayerDragDropBeacon> _beacons = new();
private LayerDragDropBeacon? _dragTarget;
[Dependency] private readonly IPrototypeManager _prototype = default!;
public LayerMarkingOrderer(MarkingsViewModel markingsModel, ProtoId<OrganCategoryPrototype> organ, HumanoidVisualLayers layer)
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_markingsModel = markingsModel;
_organ = organ;
_layer = layer;
_dragDropHelper = new(OnBeginDrag, OnContinueDrag, OnEndDrag);
UpdateItems();
}
protected override void EnteredTree()
{
base.EnteredTree();
_markingsModel.MarkingsReset += UpdateItems;
_markingsModel.MarkingsChanged += MarkingsChanged;
}
protected override void ExitedTree()
{
base.ExitedTree();
_markingsModel.MarkingsReset -= UpdateItems;
_markingsModel.MarkingsChanged -= MarkingsChanged;
}
private void MarkingsChanged(ProtoId<OrganCategoryPrototype> organ, HumanoidVisualLayers layer)
{
if (_organ != organ || _layer != layer)
return;
UpdateItems();
}
private void UpdateItems()
{
Items.RemoveAllChildren();
_beacons.Clear();
if (_markingsModel.SelectedMarkings(_organ, _layer) is not { } markings)
return;
for (var idx = 0; idx < markings.Count; idx++)
{
var marking = markings[idx];
var container = new LayerMarkingItemContainer();
container.Margin = new(4);
var item = new LayerMarkingItem(_markingsModel, _organ, _layer, _prototype.Index<MarkingPrototype>(marking.MarkingId), false);
item.DefaultCursorShape = CursorShape.Hand;
item.Pressed += (args, control) => OnItemPressed(args, control, container);
item.Unpressed += OnItemUnpressed;
container.AddChild(item);
var before = new LayerDragDropBeacon(CandidatePosition.Before, idx);
var after = new LayerDragDropBeacon(CandidatePosition.After, idx);
_beacons.Add(before);
_beacons.Add(after);
Items.AddChild(before);
Items.AddChild(container);
Items.AddChild(after);
}
}
private void OnItemPressed(GUIBoundKeyEventArgs args, LayerMarkingItem control, LayerMarkingItemContainer container)
{
_dragDropHelper.MouseDown(new(control, container));
}
private void OnItemUnpressed(GUIBoundKeyEventArgs args, LayerMarkingItem control)
{
_dragDropHelper.EndDrag();
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
_dragDropHelper.Update(args.DeltaSeconds);
}
private bool OnBeginDrag()
{
var (item, container) = _dragDropHelper.Dragged;
container.Visible = false;
item.Orphan();
item.DefaultCursorShape = CursorShape.Move;
UserInterfaceManager.PopupRoot.AddChild(item);
LayoutContainer.SetPosition(item, UserInterfaceManager.MousePositionScaled.Position - new Vector2(32, 32));
return true;
}
private bool OnContinueDrag(float frameTime)
{
var (item, container) = _dragDropHelper.Dragged;
LayoutContainer.SetPosition(item, UserInterfaceManager.MousePositionScaled.Position - new Vector2(32, 32));
var closestBeacon =
_beacons.MinBy(beacon =>
(UserInterfaceManager.MousePositionScaled.Position - beacon.GlobalPosition).LengthSquared());
if (closestBeacon != _dragTarget)
{
_dragTarget?.UnbecomeTarget();
_dragTarget = closestBeacon;
_dragTarget?.BecomeTarget();
}
return true;
}
private void OnEndDrag()
{
var (item, container) = _dragDropHelper.Dragged;
container.Visible = true;
item.Orphan();
container.AddChild(item);
_dragTarget?.UnbecomeTarget();
if (_dragTarget != null)
{
_markingsModel.ChangeMarkingOrder(_organ, _layer, item.MarkingId, _dragTarget.CandidatePosition, _dragTarget.Index);
}
}
}
internal readonly record struct LayerMarkingDragged(LayerMarkingItem Item, LayerMarkingItemContainer Container);
internal sealed class LayerMarkingItemContainer : PanelContainer
{
public LayerMarkingItemContainer()
{
SetHeight = 64;
HorizontalExpand = true;
}
}
internal sealed class LayerDragDropBeacon(CandidatePosition position, int index) : PanelContainer
{
public readonly CandidatePosition CandidatePosition = position;
public readonly int Index = index;
public void BecomeTarget()
{
SetHeight = 64;
HorizontalExpand = true;
SetOnlyStyleClass(StyleClass.PanelDropTarget);
}
public void UnbecomeTarget()
{
SetHeight = float.NaN;
RemoveStyleClass(StyleClass.PanelDropTarget);
}
}