mirror of
https://github.com/space-syndicate/space-station-14.git
synced 2026-10-09 10:21:18 +03:00
* 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
192 lines
5.7 KiB
C#
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);
|
|
}
|
|
}
|