More work on tool history/selection

This commit is contained in:
PJB3005
2026-05-07 22:39:29 +02:00
parent 29f7f96b38
commit 69878f1208
8 changed files with 144 additions and 20 deletions
@@ -6,6 +6,7 @@ namespace Robust.Client.Editor.Styling;
public abstract class BaseEditorStylesheet : CommonEngineStylesheet
{
public const string StyleClassToolButton = "EditorToolButton";
public const string StyleClassLowBackground = "EditorLowBackground";
public const string StyleClassEditorDockerLarge = "EditorDockerLarge";
@@ -4,6 +4,7 @@ using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.Stylesheets;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.StylesheetHelpers;
namespace Robust.Client.Editor.Styling.Sheetlets;
@@ -16,12 +17,23 @@ internal sealed class ButtonSheetlet : EngineSheetlet<BaseEditorStylesheet>
var box = CreateBox(sheet);
var selectedBox = new StyleBoxTexture(box) { Modulate = sheet.ButtonBackgroundHover };
var toolButton = new StyleBoxTexture(box) { Modulate = Color.Transparent };
return
[
// Normal buttons
Element<ContainerButton>()
.Prop(ContainerButton.StylePropertyStyleBox, box),
Element<ContainerButton>().Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, selectedBox)
.Prop(ContainerButton.StylePropertyStyleBox, selectedBox),
// Tool buttons
Element<ContainerButton>()
.Class(BaseEditorStylesheet.StyleClassToolButton)
.Prop(ContainerButton.StylePropertyStyleBox, toolButton),
Element<ContainerButton>().Pseudo(ContainerButton.StylePseudoClassHover)
.Class(BaseEditorStylesheet.StyleClassToolButton)
.Prop(ContainerButton.StylePropertyStyleBox, selectedBox),
];
}
@@ -49,6 +49,26 @@ public struct MapEditorToolMakePreviewControl
}
}
[ByRefEvent]
public struct MapEditorToolCheckEqual
{
public readonly EntityUid Other;
internal bool IsEqual;
public void SetEqual()
{
if (IsEqual)
throw new InvalidOperationException("Already set!");
IsEqual = true;
}
internal MapEditorToolCheckEqual(EntityUid other)
{
Other = other;
}
}
internal sealed partial class ClientMapEditorSystem
{
private static readonly SerializationOptions ToolSerializationOptions = new()
@@ -61,9 +81,6 @@ internal sealed partial class ClientMapEditorSystem
public void SwitchToTool(EntityUid map, Action<Entity<MapEditorToolDataComponent>> ent)
{
var mapData = Comp<MapEditorClientMapDataComponent>(map);
PushActiveToolToHistory((map, mapData));
var newToolEnt = Spawn(null, new EntityCoordinates(map, Vector2.Zero));
var toolData = AddComp<MapEditorToolDataComponent>(newToolEnt);
MetaSys.SetEntityName(newToolEnt, "Tool entity");
@@ -80,10 +97,53 @@ internal sealed partial class ClientMapEditorSystem
DebugTools.Assert(validateEvent.Name != null);
toolData.ToolName = validateEvent.Name;
Log.Debug($"Selected tool: {validateEvent.Name}");
mapData.ActiveToolEntity = newToolEnt;
ActiveToolChanged?.Invoke(map, (newToolEnt, toolData));
var mapData = Comp<MapEditorClientMapDataComponent>(map);
if (mapData.ActiveToolEntity is { } active && AreToolEntitiesEqual(active, newToolEnt))
{
Log.Debug("New tool ent is equal to active.");
Del(newToolEnt);
return;
}
// Check if tool already exists in history, just pull it out in that case.
if (TryGetExistingHistoryTool((map, mapData), newToolEnt, out var foundTool))
{
Log.Debug("New tool ent is equal to history entry.");
Del(newToolEnt);
SwitchToHistoryTool(map, foundTool);
return;
}
PushActiveToolToHistory((map, mapData));
SwitchToToolEntity((map, mapData), newToolEnt);
}
public void SwitchToHistoryTool(EntityUid map, EntityUid historyTool)
{
var mapData = Comp<MapEditorClientMapDataComponent>(map);
var index = mapData.ToolEntityHistory.IndexOf(historyTool);
if (index < 0)
throw new InvalidOperationException("Tool was not in the history!");
mapData.ToolEntityHistory.RemoveAt(index);
ToolHistoryChanged?.Invoke(map, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, historyTool, index));
PushActiveToolToHistory((map, mapData));
SwitchToToolEntity((map, mapData), historyTool);
}
private void SwitchToToolEntity(Entity<MapEditorClientMapDataComponent> mapData, EntityUid newTool)
{
if (mapData.Comp.ActiveToolEntity is not null)
throw new InvalidOperationException("Already have an active tool!");
var toolData = Comp<MapEditorToolDataComponent>(newTool);
Log.Debug($"Selected tool: {toolData.ToolName}");
mapData.Comp.ActiveToolEntity = newTool;
ActiveToolChanged?.Invoke(mapData, (newTool, toolData));
}
private void PushActiveToolToHistory(Entity<MapEditorClientMapDataComponent> mapData)
@@ -127,4 +187,29 @@ internal sealed partial class ClientMapEditorSystem
return (active, Comp<MapEditorToolDataComponent>(active));
}
private bool TryGetExistingHistoryTool(
Entity<MapEditorClientMapDataComponent> mapData,
EntityUid newTool,
out EntityUid foundTool)
{
foreach (var historyEntry in mapData.Comp.ToolEntityHistory)
{
if (AreToolEntitiesEqual(historyEntry, newTool))
{
foundTool = historyEntry;
return true;
}
}
foundTool = default;
return false;
}
private bool AreToolEntitiesEqual(EntityUid a, EntityUid b)
{
var checkEqual = new MapEditorToolCheckEqual(b);
RaiseLocalEvent(a, ref checkEqual);
return checkEqual.IsEqual;
}
}
@@ -5,7 +5,7 @@
<ScrollContainer HScrollEnabled="False">
<Control Name="ActiveToolContainer" VerticalAlignment="Top">
<HBox>
<Control Name="ActiveToolPreview" SetSize="32,32" />
<Control Name="ActiveToolPreview" StyleClasses="ToolPreview" />
<RichTextLabel Name="ActiveToolName" Margin="8, 0, 0, 0" HorizontalExpand="True" />
</HBox>
<Control Name="ActiveToolInfo" />
@@ -3,6 +3,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized;
using Robust.Client.AutoGenerated;
using Robust.Client.Editor.Interface;
using Robust.Client.Editor.Styling;
using Robust.Client.MapEditor.Interface.Styling;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
@@ -67,12 +68,14 @@ internal sealed partial class ToolHistoryPanel : EditorPanel
{
_toolHistoryMirror.Insert(i, (EntityUid)changed.NewItems[i]!);
}
break;
case NotifyCollectionChangedAction.Remove:
for (var i = 0; i < changed.OldItems!.Count; i++)
{
_toolHistoryMirror.RemoveAt(changed.OldStartingIndex);
}
break;
case NotifyCollectionChangedAction.Replace:
case NotifyCollectionChangedAction.Move:
@@ -90,11 +93,18 @@ internal sealed partial class ToolHistoryPanel : EditorPanel
private Control CreateHistoryEntry(EntityUid arg)
{
var control = new Control
var control = new ContainerButton
{
MouseFilter = MouseFilterMode.Stop,
StyleClasses = { MapEditorStyleClasses.ToolHistoryEntry },
Children = { ActiveToolPanel.GetPreviewControl(arg, _entityManager, _resourceCache) }
StyleClasses = { BaseEditorStylesheet.StyleClassToolButton },
Children =
{
new Control
{
StyleClasses = { MapEditorStyleClasses.ToolPreview },
Children = { ActiveToolPanel.GetPreviewControl(arg, _entityManager, _resourceCache) }
}
}
};
control.TooltipSupplier = _ =>
{
@@ -103,6 +113,12 @@ internal sealed partial class ToolHistoryPanel : EditorPanel
tt.SetMessage(comp.ToolName);
return tt;
};
control.OnPressed += _ => SelectFromHistory(arg);
return control;
}
private void SelectFromHistory(EntityUid tool)
{
_mapEditor.SwitchToHistoryTool(_mapData, tool);
}
}
@@ -1,7 +1,6 @@
using Robust.Client.Editor.Styling;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Stylesheets;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.StylesheetHelpers;
namespace Robust.Client.MapEditor.Interface.Styling;
@@ -9,16 +8,16 @@ namespace Robust.Client.MapEditor.Interface.Styling;
[EngineSheetlet]
internal sealed class MapEditorSheetlet : EngineSheetlet<BaseEditorStylesheet>
{
private const float ToolPreviewSize = 64;
public override StyleRule[] GetRules(BaseEditorStylesheet sheet, object config)
{
return
[
Element()
.Class(MapEditorStyleClasses.ToolHistoryEntry)
.Prop(nameof(Control.Margin), new Thickness(2))
.Prop(nameof(Control.SetWidth), 32)
.Prop(nameof(Control.SetHeight), 32)
.Class(MapEditorStyleClasses.ToolPreview)
.Prop(nameof(Control.SetWidth), ToolPreviewSize)
.Prop(nameof(Control.SetHeight), ToolPreviewSize)
];
}
}
@@ -2,5 +2,5 @@
internal static class MapEditorStyleClasses
{
public const string ToolHistoryEntry = "ToolHistoryEntry";
public const string ToolPreview = "ToolPreview";
}
+13 -2
View File
@@ -1,4 +1,5 @@
using Robust.Client.MapEditor.Interface.Panels;
using System.Numerics;
using Robust.Client.MapEditor.Interface.Panels;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
@@ -35,6 +36,7 @@ internal sealed class MapEditorToolEntitySystem : EntitySystem
SubscribeLocalEvent<MapEditorToolEntityComponent, MapEditorToolValidateEvent>(ValidateTool);
SubscribeLocalEvent<MapEditorToolEntityComponent, MapEditorToolMakePreviewControl>(MakePreviewControl);
SubscribeLocalEvent<MapEditorToolEntityComponent, MapEditorToolCheckEqual>(CheckEqual);
}
public void SwitchToTool(EntityUid mapData, EntProtoId protoId)
@@ -66,11 +68,20 @@ internal sealed class MapEditorToolEntitySystem : EntitySystem
Entity<MapEditorToolEntityComponent> ent,
ref MapEditorToolMakePreviewControl args)
{
var view = new EntityPrototypeView();
var view = new EntityPrototypeView { Scale = new Vector2(2, 2) };
view.SetPrototype(ent.Comp.PrototypeId);
args.SetControl(view);
}
private void CheckEqual(Entity<MapEditorToolEntityComponent> ent, ref MapEditorToolCheckEqual args)
{
if (!TryComp(args.Other, out MapEditorToolEntityComponent? otherComp))
return;
if (ent.Comp.PrototypeId == otherComp.PrototypeId)
args.SetEqual();
}
internal static bool IsEligible(EntityPrototype prototype)
{
return !prototype.Abstract && !prototype.Abstract;