Storage UI V2 (#33045)
This commit is contained in:
@@ -59,7 +59,7 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
||||
Location = location;
|
||||
|
||||
Visible = true;
|
||||
MouseFilter = MouseFilterMode.Pass;
|
||||
MouseFilter = MouseFilterMode.Stop;
|
||||
|
||||
TooltipSupplier = SupplyTooltip;
|
||||
|
||||
@@ -105,8 +105,11 @@ public sealed class ItemGridPiece : Control, IEntityControl
|
||||
return;
|
||||
}
|
||||
|
||||
if (_storageController.IsDragging && _storageController.DraggingGhost?.Entity == Entity && _storageController.DraggingGhost != this)
|
||||
if (_storageController.IsDragging && _storageController.DraggingGhost?.Entity == Entity &&
|
||||
_storageController.DraggingGhost != this)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var adjustedShape = _entityManager.System<ItemSystem>().GetAdjustedItemShape((Entity, itemComponent), Location.Rotation, Vector2i.Zero);
|
||||
var boundingGrid = adjustedShape.GetBoundingBox();
|
||||
|
||||
@@ -3,7 +3,9 @@ using System.Linq;
|
||||
using System.Numerics;
|
||||
using Content.Client.Hands.Systems;
|
||||
using Content.Client.Items.Systems;
|
||||
using Content.Client.Storage;
|
||||
using Content.Client.Storage.Systems;
|
||||
using Content.Shared.IdentityManagement;
|
||||
using Content.Shared.Input;
|
||||
using Content.Shared.Item;
|
||||
using Content.Shared.Storage;
|
||||
@@ -11,12 +13,14 @@ using Robust.Client.Graphics;
|
||||
using Robust.Client.UserInterface;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Shared.Collections;
|
||||
using Robust.Shared.Containers;
|
||||
using Robust.Shared.Timing;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Storage.Controls;
|
||||
|
||||
public sealed class StorageContainer : BaseWindow
|
||||
public sealed class StorageWindow : BaseWindow
|
||||
{
|
||||
[Dependency] private readonly IEntityManager _entity = default!;
|
||||
private readonly StorageUIController _storageController;
|
||||
@@ -27,6 +31,20 @@ public sealed class StorageContainer : BaseWindow
|
||||
private readonly GridContainer _backgroundGrid;
|
||||
private readonly GridContainer _sidebar;
|
||||
|
||||
private Control _titleContainer;
|
||||
private Label _titleLabel;
|
||||
|
||||
// Needs to be nullable in case a piece is in default spot.
|
||||
private readonly Dictionary<EntityUid, (ItemStorageLocation? Loc, ItemGridPiece Control)> _pieces = new();
|
||||
private readonly List<Control> _controlGrid = new();
|
||||
|
||||
private ValueList<EntityUid> _contained = new();
|
||||
private ValueList<EntityUid> _toRemove = new();
|
||||
|
||||
private TextureButton? _backButton;
|
||||
|
||||
private bool _isDirty;
|
||||
|
||||
public event Action<GUIBoundKeyEventArgs, ItemGridPiece>? OnPiecePressed;
|
||||
public event Action<GUIBoundKeyEventArgs, ItemGridPiece>? OnPieceUnpressed;
|
||||
|
||||
@@ -51,9 +69,10 @@ public sealed class StorageContainer : BaseWindow
|
||||
private readonly string _sidebarFatTexturePath = "Storage/sidebar_fat";
|
||||
private Texture? _sidebarFatTexture;
|
||||
|
||||
public StorageContainer()
|
||||
public StorageWindow()
|
||||
{
|
||||
IoCManager.InjectDependencies(this);
|
||||
Resizable = false;
|
||||
|
||||
_storageController = UserInterfaceManager.GetUIController<StorageUIController>();
|
||||
|
||||
@@ -63,6 +82,7 @@ public sealed class StorageContainer : BaseWindow
|
||||
|
||||
_sidebar = new GridContainer
|
||||
{
|
||||
Name = "SideBar",
|
||||
HSeparationOverride = 0,
|
||||
VSeparationOverride = 0,
|
||||
Columns = 1
|
||||
@@ -70,21 +90,48 @@ public sealed class StorageContainer : BaseWindow
|
||||
|
||||
_pieceGrid = new GridContainer
|
||||
{
|
||||
Name = "PieceGrid",
|
||||
HSeparationOverride = 0,
|
||||
VSeparationOverride = 0
|
||||
};
|
||||
|
||||
_backgroundGrid = new GridContainer
|
||||
{
|
||||
Name = "BackgroundGrid",
|
||||
HSeparationOverride = 0,
|
||||
VSeparationOverride = 0
|
||||
};
|
||||
|
||||
_titleLabel = new Label()
|
||||
{
|
||||
HorizontalExpand = true,
|
||||
Name = "StorageLabel",
|
||||
ClipText = true,
|
||||
Text = "Dummy",
|
||||
StyleClasses =
|
||||
{
|
||||
"FancyWindowTitle",
|
||||
}
|
||||
};
|
||||
|
||||
_titleContainer = new PanelContainer()
|
||||
{
|
||||
StyleClasses =
|
||||
{
|
||||
"WindowHeadingBackground"
|
||||
},
|
||||
Children =
|
||||
{
|
||||
_titleLabel
|
||||
}
|
||||
};
|
||||
|
||||
var container = new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Vertical,
|
||||
Children =
|
||||
{
|
||||
_titleContainer,
|
||||
new BoxContainer
|
||||
{
|
||||
Orientation = BoxContainer.LayoutOrientation.Horizontal,
|
||||
@@ -130,12 +177,22 @@ public sealed class StorageContainer : BaseWindow
|
||||
if (entity == null)
|
||||
return;
|
||||
|
||||
if (UserInterfaceManager.GetUIController<StorageUIController>().WindowTitle)
|
||||
{
|
||||
_titleLabel.Text = Identity.Name(entity.Value, _entity);
|
||||
_titleContainer.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_titleContainer.Visible = false;
|
||||
}
|
||||
|
||||
BuildGridRepresentation();
|
||||
}
|
||||
|
||||
private void BuildGridRepresentation()
|
||||
{
|
||||
if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var comp) || !comp.Grid.Any())
|
||||
if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var comp) || comp.Grid.Count == 0)
|
||||
return;
|
||||
|
||||
var boundingGrid = comp.Grid.GetBoundingBox();
|
||||
@@ -145,11 +202,11 @@ public sealed class StorageContainer : BaseWindow
|
||||
#region Sidebar
|
||||
_sidebar.Children.Clear();
|
||||
_sidebar.Rows = boundingGrid.Height + 1;
|
||||
|
||||
var exitButton = new TextureButton
|
||||
{
|
||||
TextureNormal = _entity.System<StorageSystem>().OpenStorageAmount == 1
|
||||
?_exitTexture
|
||||
: _backTexture,
|
||||
Name = "ExitButton",
|
||||
TextureNormal = _exitTexture,
|
||||
Scale = new Vector2(2, 2),
|
||||
};
|
||||
exitButton.OnPressed += _ =>
|
||||
@@ -165,8 +222,10 @@ public sealed class StorageContainer : BaseWindow
|
||||
args.Handle();
|
||||
}
|
||||
};
|
||||
|
||||
var exitContainer = new BoxContainer
|
||||
{
|
||||
Name = "ExitContainer",
|
||||
Children =
|
||||
{
|
||||
new TextureRect
|
||||
@@ -182,8 +241,61 @@ public sealed class StorageContainer : BaseWindow
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_sidebar.AddChild(exitContainer);
|
||||
for (var i = 0; i < boundingGrid.Height - 1; i++)
|
||||
var offset = 1;
|
||||
|
||||
if (_entity.System<StorageSystem>().NestedStorage && boundingGrid.Height > 0)
|
||||
{
|
||||
offset += 1;
|
||||
|
||||
_backButton = new TextureButton
|
||||
{
|
||||
TextureNormal = _backTexture,
|
||||
Scale = new Vector2(2, 2),
|
||||
};
|
||||
_backButton.OnPressed += _ =>
|
||||
{
|
||||
var containerSystem = _entity.System<SharedContainerSystem>();
|
||||
|
||||
if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) &&
|
||||
_entity.TryGetComponent(container.Owner, out StorageComponent? storage))
|
||||
{
|
||||
Close();
|
||||
|
||||
if (_entity.System<SharedUserInterfaceSystem>()
|
||||
.TryGetOpenUi<StorageBoundUserInterface>(container.Owner,
|
||||
StorageComponent.StorageUiKey.Key,
|
||||
out var parentBui))
|
||||
{
|
||||
parentBui.Show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var backContainer = new BoxContainer
|
||||
{
|
||||
Name = "ExitContainer",
|
||||
Children =
|
||||
{
|
||||
new TextureRect
|
||||
{
|
||||
Texture = boundingGrid.Height > 2 ? _sidebarMiddleTexture : _sidebarBottomTexture,
|
||||
TextureScale = new Vector2(2, 2),
|
||||
Children =
|
||||
{
|
||||
_backButton,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_sidebar.AddChild(backContainer);
|
||||
}
|
||||
|
||||
var rows = boundingGrid.Height - offset;
|
||||
|
||||
for (var i = 0; i < rows; i++)
|
||||
{
|
||||
_sidebar.AddChild(new TextureRect
|
||||
{
|
||||
@@ -192,7 +304,7 @@ public sealed class StorageContainer : BaseWindow
|
||||
});
|
||||
}
|
||||
|
||||
if (boundingGrid.Height > 0)
|
||||
if (rows > 0)
|
||||
{
|
||||
_sidebar.AddChild(new TextureRect
|
||||
{
|
||||
@@ -203,7 +315,7 @@ public sealed class StorageContainer : BaseWindow
|
||||
|
||||
#endregion
|
||||
|
||||
BuildItemPieces();
|
||||
FlagDirty();
|
||||
}
|
||||
|
||||
public void BuildBackground()
|
||||
@@ -240,70 +352,127 @@ public sealed class StorageContainer : BaseWindow
|
||||
}
|
||||
}
|
||||
|
||||
public void Reclaim(ItemStorageLocation location, ItemGridPiece draggingGhost)
|
||||
{
|
||||
draggingGhost.OnPiecePressed += OnPiecePressed;
|
||||
draggingGhost.OnPieceUnpressed += OnPieceUnpressed;
|
||||
_pieces[draggingGhost.Entity] = (location, draggingGhost);
|
||||
draggingGhost.Location = location;
|
||||
var controlIndex = GetGridIndex(draggingGhost);
|
||||
_controlGrid[controlIndex].AddChild(draggingGhost);
|
||||
}
|
||||
|
||||
private int GetGridIndex(ItemGridPiece piece)
|
||||
{
|
||||
return piece.Location.Position.X + piece.Location.Position.Y * _pieceGrid.Columns;
|
||||
}
|
||||
|
||||
public void FlagDirty()
|
||||
{
|
||||
_isDirty = true;
|
||||
}
|
||||
|
||||
public void RemoveGrid(ItemGridPiece control)
|
||||
{
|
||||
control.Orphan();
|
||||
_pieces.Remove(control.Entity);
|
||||
control.OnPiecePressed -= OnPiecePressed;
|
||||
control.OnPieceUnpressed -= OnPieceUnpressed;
|
||||
}
|
||||
|
||||
public void BuildItemPieces()
|
||||
{
|
||||
if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var storageComp))
|
||||
return;
|
||||
|
||||
if (!storageComp.Grid.Any())
|
||||
if (storageComp.Grid.Count == 0)
|
||||
return;
|
||||
|
||||
var boundingGrid = storageComp.Grid.GetBoundingBox();
|
||||
var size = _emptyTexture!.Size * 2;
|
||||
var containedEntities = storageComp.Container.ContainedEntities.Reverse().ToArray();
|
||||
_contained.Clear();
|
||||
_contained.AddRange(storageComp.Container.ContainedEntities.Reverse());
|
||||
|
||||
//todo. at some point, we may want to only rebuild the pieces that have actually received new data.
|
||||
|
||||
_pieceGrid.RemoveAllChildren();
|
||||
_pieceGrid.Rows = boundingGrid.Height + 1;
|
||||
_pieceGrid.Columns = boundingGrid.Width + 1;
|
||||
for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
|
||||
// Build the grid representation
|
||||
if (_pieceGrid.Rows - 1 != boundingGrid.Height || _pieceGrid.Columns - 1 != boundingGrid.Width)
|
||||
{
|
||||
for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++)
|
||||
_pieceGrid.Rows = boundingGrid.Height + 1;
|
||||
_pieceGrid.Columns = boundingGrid.Width + 1;
|
||||
_controlGrid.Clear();
|
||||
|
||||
for (var y = boundingGrid.Bottom; y <= boundingGrid.Top; y++)
|
||||
{
|
||||
var control = new Control
|
||||
for (var x = boundingGrid.Left; x <= boundingGrid.Right; x++)
|
||||
{
|
||||
MinSize = size
|
||||
};
|
||||
|
||||
var currentPosition = new Vector2i(x, y);
|
||||
|
||||
foreach (var (itemEnt, itemPos) in storageComp.StoredItems)
|
||||
{
|
||||
if (itemPos.Position != currentPosition)
|
||||
continue;
|
||||
|
||||
if (_entity.TryGetComponent<ItemComponent>(itemEnt, out var itemEntComponent))
|
||||
var control = new Control
|
||||
{
|
||||
ItemGridPiece gridPiece;
|
||||
MinSize = size
|
||||
};
|
||||
|
||||
if (_storageController.CurrentlyDragging?.Entity is { } dragging
|
||||
&& dragging == itemEnt)
|
||||
{
|
||||
_storageController.CurrentlyDragging.Orphan();
|
||||
gridPiece = _storageController.CurrentlyDragging;
|
||||
}
|
||||
else
|
||||
{
|
||||
gridPiece = new ItemGridPiece((itemEnt, itemEntComponent), itemPos, _entity)
|
||||
{
|
||||
MinSize = size,
|
||||
Marked = Array.IndexOf(containedEntities, itemEnt) switch
|
||||
{
|
||||
0 => ItemGridPieceMarks.First,
|
||||
1 => ItemGridPieceMarks.Second,
|
||||
_ => null,
|
||||
}
|
||||
};
|
||||
gridPiece.OnPiecePressed += OnPiecePressed;
|
||||
gridPiece.OnPieceUnpressed += OnPieceUnpressed;
|
||||
}
|
||||
_controlGrid.Add(control);
|
||||
_pieceGrid.AddChild(control);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
control.AddChild(gridPiece);
|
||||
}
|
||||
_toRemove.Clear();
|
||||
|
||||
// Remove entities no longer relevant / Update existing ones
|
||||
foreach (var (ent, data) in _pieces)
|
||||
{
|
||||
if (storageComp.StoredItems.TryGetValue(ent, out var updated))
|
||||
{
|
||||
if (data.Loc.Equals(updated))
|
||||
{
|
||||
DebugTools.Assert(data.Control.Location == updated);
|
||||
continue;
|
||||
}
|
||||
|
||||
_pieceGrid.AddChild(control);
|
||||
// Update
|
||||
data.Control.Location = updated;
|
||||
var index = GetGridIndex(data.Control);
|
||||
data.Control.Orphan();
|
||||
_controlGrid[index].AddChild(data.Control);
|
||||
_pieces[ent] = (updated, data.Control);
|
||||
continue;
|
||||
}
|
||||
|
||||
_toRemove.Add(ent);
|
||||
}
|
||||
|
||||
foreach (var ent in _toRemove)
|
||||
{
|
||||
_pieces.Remove(ent, out var data);
|
||||
data.Control.Orphan();
|
||||
}
|
||||
|
||||
// Add new ones
|
||||
foreach (var (ent, loc) in storageComp.StoredItems)
|
||||
{
|
||||
if (_pieces.TryGetValue(ent, out var existing))
|
||||
{
|
||||
DebugTools.Assert(existing.Loc == loc);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_entity.TryGetComponent<ItemComponent>(ent, out var itemEntComponent))
|
||||
{
|
||||
var gridPiece = new ItemGridPiece((ent, itemEntComponent), loc, _entity)
|
||||
{
|
||||
MinSize = size,
|
||||
Marked = _contained.IndexOf(ent) switch
|
||||
{
|
||||
0 => ItemGridPieceMarks.First,
|
||||
1 => ItemGridPieceMarks.Second,
|
||||
_ => null,
|
||||
}
|
||||
};
|
||||
gridPiece.OnPiecePressed += OnPiecePressed;
|
||||
gridPiece.OnPieceUnpressed += OnPieceUnpressed;
|
||||
var controlIndex = loc.Position.X + loc.Position.Y * (boundingGrid.Width + 1);
|
||||
|
||||
_controlGrid[controlIndex].AddChild(gridPiece);
|
||||
_pieces[ent] = (loc, gridPiece);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -315,6 +484,35 @@ public sealed class StorageContainer : BaseWindow
|
||||
if (!IsOpen)
|
||||
return;
|
||||
|
||||
if (_isDirty)
|
||||
{
|
||||
_isDirty = false;
|
||||
BuildItemPieces();
|
||||
}
|
||||
|
||||
var containerSystem = _entity.System<SharedContainerSystem>();
|
||||
|
||||
if (_backButton != null)
|
||||
{
|
||||
if (StorageEntity != null && _entity.System<StorageSystem>().NestedStorage)
|
||||
{
|
||||
if (containerSystem.TryGetContainingContainer(StorageEntity.Value, out var container) &&
|
||||
_entity.HasComponent<StorageComponent>(container.Owner))
|
||||
{
|
||||
_backButton.Visible = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_backButton.Visible = false;
|
||||
}
|
||||
}
|
||||
// Hide the button.
|
||||
else
|
||||
{
|
||||
_backButton.Visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
var itemSystem = _entity.System<ItemSystem>();
|
||||
var storageSystem = _entity.System<StorageSystem>();
|
||||
var handsSystem = _entity.System<HandsSystem>();
|
||||
@@ -324,7 +522,7 @@ public sealed class StorageContainer : BaseWindow
|
||||
child.ModulateSelfOverride = Color.FromHex("#222222");
|
||||
}
|
||||
|
||||
if (UserInterfaceManager.CurrentlyHovered is StorageContainer con && con != this)
|
||||
if (UserInterfaceManager.CurrentlyHovered is StorageWindow con && con != this)
|
||||
return;
|
||||
|
||||
if (!_entity.TryGetComponent<StorageComponent>(StorageEntity, out var storageComponent))
|
||||
@@ -373,7 +571,7 @@ public sealed class StorageContainer : BaseWindow
|
||||
continue;
|
||||
|
||||
float spot = 0;
|
||||
var marked = new List<Control>();
|
||||
var marked = new ValueList<Control>();
|
||||
|
||||
foreach (var location in locations.Value)
|
||||
{
|
||||
@@ -500,14 +698,4 @@ public sealed class StorageContainer : BaseWindow
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
base.Close();
|
||||
|
||||
if (StorageEntity == null)
|
||||
return;
|
||||
|
||||
_entity.System<StorageSystem>().CloseStorageWindow(StorageEntity.Value);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user