Files
RobustToolbox/Robust.Client/UserInterface/Controllers/Implementations/TileSpawningUIController.cs
T
83c2a1be11 [Dependency] source generator part 2 (#6550)
* [Dependency] source generator

No more reflection, no more codegen at runtime

Also various changes to Roslyn helpers to make this easier to write.

Requires all types with dependencies to be partial and not have readonly dependency fields. An analyzer enforces this at warning level, the previous injection strategies have remained in the code *for now* as a fallback.

No fallback is available for [field: Dependency] properties, due to a Roslyn bug.

Code Fixes exist. We love Roslyn

* Apply dependencies generator changes to all code

* Release notes

* Preprocessor got hands

* Handle nullable dependencies

These are bad but gotta deal with it.

* Apply suggestions from code review

Co-authored-by: Moony <moony@hellomouse.net>

* Fine, let's not use collection expressions

---------

Co-authored-by: Moony <moony@hellomouse.net>
2026-05-08 12:38:33 +02:00

246 lines
7.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using Robust.Client.Graphics;
using Robust.Client.Placement;
using Robust.Client.Placement.Modes;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Enums;
using Robust.Shared.Graphics;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Utility;
using static Robust.Client.UserInterface.Controls.BaseButton;
namespace Robust.Client.UserInterface.Controllers.Implementations;
public sealed partial class TileSpawningUIController : UIController
{
[Dependency] private IPlacementManager _placement = default!;
[Dependency] private IResourceCache _resources = default!;
[Dependency] private ITileDefinitionManager _tiles = default!;
private TileSpawnWindow? _window;
private bool _init;
private readonly List<ITileDefinition> _shownTiles = new();
private bool _clearingTileSelections;
private bool _eraseTile;
private bool _mirrorableTile; // Tracks if the chosen tile even can be mirrored.
private bool _mirroredTile;
public override void Initialize()
{
DebugTools.Assert(_init == false);
_init = true;
_placement.PlacementChanged += ClearTileSelection;
_placement.DirectionChanged += OnDirectionChanged;
_placement.MirroredChanged += OnMirroredChanged;
}
private void StartTilePlacement(int tileType)
{
var newObjInfo = new PlacementInformation
{
PlacementOption = nameof(AlignTileAny),
TileType = tileType,
Range = 400,
IsTile = true
};
_placement.BeginPlacing(newObjInfo);
}
private void OnTileEraseToggled(ButtonToggledEventArgs args)
{
if (_window == null || _window.Disposed)
return;
_placement.Clear();
if (args.Pressed)
{
_eraseTile = true;
StartTilePlacement(0);
}
else
_eraseTile = false;
args.Button.Pressed = args.Pressed;
}
private void OnTileMirroredToggled(ButtonToggledEventArgs args)
{
if (_window == null || _window.Disposed)
return;
_placement.Mirrored = args.Pressed;
_mirroredTile = _placement.Mirrored;
args.Button.Pressed = args.Pressed;
}
public void ToggleWindow()
{
EnsureWindow();
if (_window!.IsOpen)
{
_window.Close();
}
else
{
_window.Open();
UpdateEntityDirectionLabel();
UpdateMirroredButton();
_window.SearchBar.GrabKeyboardFocus();
}
}
private void EnsureWindow()
{
if (_window is { Disposed: false })
return;
_window = UIManager.CreateWindow<TileSpawnWindow>();
LayoutContainer.SetAnchorPreset(_window, LayoutContainer.LayoutPreset.CenterLeft);
_window.ClearButton.OnPressed += OnTileClearPressed;
_window.SearchBar.OnTextChanged += OnTileSearchChanged;
_window.TileList.OnItemSelected += OnTileItemSelected;
_window.TileList.OnItemDeselected += OnTileItemDeselected;
_window.EraseButton.Pressed = _eraseTile;
_window.EraseButton.OnToggled += OnTileEraseToggled;
_window.MirroredButton.Disabled = !_mirrorableTile;
_window.RotationLabel.FontColorOverride = _mirrorableTile ? Color.White : Color.Gray;
_window.MirroredButton.Pressed = _mirroredTile;
_window.MirroredButton.OnToggled += OnTileMirroredToggled;
BuildTileList();
}
public void CloseWindow()
{
if (_window == null || _window.Disposed) return;
_window?.Close();
}
private void ClearTileSelection(object? sender, EventArgs e)
{
if (_window == null || _window.Disposed) return;
_clearingTileSelections = true;
_window.TileList.ClearSelected();
_clearingTileSelections = false;
_window.EraseButton.Pressed = false;
_window.MirroredButton.Pressed = _placement.Mirrored;
}
private void OnTileClearPressed(ButtonEventArgs args)
{
if (_window == null || _window.Disposed) return;
_window.TileList.ClearSelected();
_placement.Clear();
_window.SearchBar.Clear();
BuildTileList(string.Empty);
_window.ClearButton.Disabled = true;
}
private void OnTileSearchChanged(LineEdit.LineEditEventArgs args)
{
if (_window == null || _window.Disposed) return;
_window.TileList.ClearSelected();
_placement.Clear();
BuildTileList(args.Text);
_window.ClearButton.Disabled = string.IsNullOrEmpty(args.Text);
}
private void OnTileItemSelected(ItemList.ItemListSelectedEventArgs args)
{
var definition = _shownTiles[args.ItemIndex];
StartTilePlacement(definition.TileId);
UpdateMirroredButton();
}
private void OnTileItemDeselected(ItemList.ItemListDeselectedEventArgs args)
{
if (_clearingTileSelections)
{
return;
}
_placement.Clear();
}
private void OnDirectionChanged(object? sender, EventArgs e)
{
UpdateEntityDirectionLabel();
}
private void UpdateEntityDirectionLabel()
{
if (_window == null || _window.Disposed)
return;
_window.RotationLabel.Text = _placement.Direction.ToString();
}
private void OnMirroredChanged(object? sender, EventArgs e)
{
UpdateMirroredButton();
}
private void UpdateMirroredButton()
{
if (_window == null || _window.Disposed)
return;
if (_placement.CurrentPermission != null && _placement.CurrentPermission.IsTile)
{
var allowed = _tiles[_placement.CurrentPermission.TileType].AllowRotationMirror;
_mirrorableTile = allowed;
_window.MirroredButton.Disabled = !_mirrorableTile;
_window.RotationLabel.FontColorOverride = _mirrorableTile ? Color.White : Color.Gray;
}
_mirroredTile = _placement.Mirrored;
_window.MirroredButton.Pressed = _mirroredTile;
}
private void BuildTileList(string? searchStr = null)
{
if (_window == null || _window.Disposed) return;
_window.TileList.Clear();
IEnumerable<ITileDefinition> tileDefs = _tiles.Where(def => !def.EditorHidden);
if (!string.IsNullOrEmpty(searchStr))
{
tileDefs = tileDefs.Where(s =>
Loc.GetString(s.Name).Contains(searchStr, StringComparison.CurrentCultureIgnoreCase) ||
s.ID.Contains(searchStr, StringComparison.OrdinalIgnoreCase));
}
tileDefs = tileDefs.OrderBy(d => Loc.GetString(d.Name));
_shownTiles.Clear();
_shownTiles.AddRange(tileDefs);
foreach (var entry in _shownTiles)
{
Texture? texture = null;
var path = entry.Sprite?.ToString();
if (path != null)
{
texture = _resources.GetResource<TextureResource>(path);
}
_window.TileList.AddItem(Loc.GetString(entry.Name), texture);
}
}
}