CatStation/Content.Client/Humanoid/LayerMarkingOrderer.xaml.cs
Pieter-Jan Briers 5168b5f3d4
IoC source gen compatibility (#43863)
* IoC source gen compatibility

Can be merged before or after https://github.com/space-wizards/RobustToolbox/pull/6549 doesn't really matter.

* Missed a spot
2026-05-09 03:29:58 +00:00

192 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 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);
}
}