[Transfer] Collapsible ghost roles menu (#800)

This commit is contained in:
BIGZi0348
2024-12-02 20:16:33 +03:00
committed by GitHub
10 changed files with 140 additions and 44 deletions

View File

@@ -0,0 +1,9 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical"
Margin="8 0 8 0">
<BoxContainer Name="Buttons"
Orientation="Vertical"
SeparationOverride="5">
<!-- Buttons are added here by code -->
</BoxContainer>
</BoxContainer>

View File

@@ -10,20 +10,17 @@ using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{ {
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class GhostRolesEntry : BoxContainer public sealed partial class GhostRoleButtonsBox : BoxContainer // WD Edit ahead of wizden upstream
{ {
private SpriteSystem _spriteSystem; private SpriteSystem _spriteSystem;
public event Action<GhostRoleInfo>? OnRoleSelected; public event Action<GhostRoleInfo>? OnRoleSelected;
public event Action<GhostRoleInfo>? OnRoleFollow; public event Action<GhostRoleInfo>? OnRoleFollow;
public GhostRolesEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem) public GhostRoleButtonsBox(bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem) // WD Edit ahead of wizden upstream
{ {
RobustXamlLoader.Load(this); RobustXamlLoader.Load(this);
_spriteSystem = spriteSystem; _spriteSystem = spriteSystem;
Title.Text = name;
Description.SetMessage(description);
foreach (var role in roles) foreach (var role in roles)
{ {
var button = new GhostRoleEntryButtons(role); var button = new GhostRoleEntryButtons(role);
@@ -45,7 +42,7 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{ {
TextureScale = new Vector2(0.4f, 0.4f), TextureScale = new Vector2(0.4f, 0.4f),
Stretch = TextureRect.StretchMode.KeepCentered, Stretch = TextureRect.StretchMode.KeepCentered,
Texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ("/Textures/Interface/Nano/lock.svg.192dpi.png"))), Texture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new("/Textures/Interface/Nano/lock.svg.192dpi.png"))),
HorizontalExpand = true, HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right, HorizontalAlignment = HAlignment.Right,
}); });

View File

@@ -1,15 +1,15 @@
<BoxContainer xmlns="https://spacestation14.io" <BoxContainer xmlns="https://spacestation14.io"
Orientation="Horizontal"> Orientation="Horizontal"
HorizontalAlignment="Stretch">
<Button Name="RequestButton" <Button Name="RequestButton"
Access="Public" Access="Public"
Text="{Loc 'ghost-roles-window-request-role-button'}" Text="{Loc 'ghost-roles-window-request-role-button'}"
StyleClasses="OpenRight" StyleClasses="OpenRight"
HorizontalAlignment="Left" HorizontalExpand="True"
SetWidth="300"/> SizeFlagsStretchRatio="3"/>
<Button Name="FollowButton" <Button Name="FollowButton"
Access="Public" Access="Public"
Text="{Loc 'ghost-roles-window-follow-role-button'}" Text="{Loc 'ghost-roles-window-follow-role-button'}"
StyleClasses="OpenLeft" StyleClasses="OpenLeft"
HorizontalAlignment="Right" HorizontalExpand="True"/>
SetWidth="150"/>
</BoxContainer> </BoxContainer>

View File

@@ -0,0 +1,8 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical">
<Label Name="Title"
StyleClasses="LabelKeyText"/>
<PanelContainer StyleClasses="HighDivider" />
<RichTextLabel Name="Description"
Margin="0 4"/>
</BoxContainer>

View File

@@ -0,0 +1,18 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{
[GenerateTypedNameReferences]
public sealed partial class GhostRoleInfoBox : BoxContainer
{
public GhostRoleInfoBox(string name, string description)
{
RobustXamlLoader.Load(this);
Title.Text = name;
Description.SetMessage(description);
}
}
}

View File

@@ -1,16 +0,0 @@
<BoxContainer xmlns="https://spacestation14.io"
Orientation="Vertical"
HorizontalExpand="True"
Margin="0 0 8 8">
<Label Name="Title"
StyleClasses="LabelKeyText"/>
<PanelContainer StyleClasses="HighDivider" />
<RichTextLabel Name="Description"
Margin="0 4"/>
<BoxContainer Name="Buttons"
HorizontalAlignment="Left"
Orientation="Vertical"
SeparationOverride="5">
<!-- Buttons are added here by code -->
</BoxContainer>
</BoxContainer>

View File

@@ -5,12 +5,11 @@ using Content.Shared.Eui;
using Content.Shared.Ghost.Roles; using Content.Shared.Ghost.Roles;
using JetBrains.Annotations; using JetBrains.Annotations;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{ {
[UsedImplicitly] [UsedImplicitly]
public sealed class GhostRolesEui : BaseEui public sealed class GhostRolesEui : BaseEui // WD Edit ahead of wizden upstream
{ {
private readonly GhostRolesWindow _window; private readonly GhostRolesWindow _window;
private GhostRoleRulesWindow? _windowRules = null; private GhostRoleRulesWindow? _windowRules = null;
@@ -77,6 +76,13 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
if (state is not GhostRolesEuiState ghostState) if (state is not GhostRolesEuiState ghostState)
return; return;
// We must save BodyVisible state, so all Collapsible boxes will not close
// on adding new ghost role.
// Save the current state of each Collapsible box being visible or not
_window.SaveCollapsibleBoxesStates();
// Clearing the container before adding new roles
_window.ClearEntries(); _window.ClearEntries();
var entityManager = IoCManager.Resolve<IEntityManager>(); var entityManager = IoCManager.Resolve<IEntityManager>();
@@ -84,28 +90,32 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>(); var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
var requirementsManager = IoCManager.Resolve<JobRequirementsManager>(); var requirementsManager = IoCManager.Resolve<JobRequirementsManager>();
// TODO: role.Requirements value doesn't work at all as an equality key, this must be fixed
// Grouping roles
var groupedRoles = ghostState.GhostRoles.GroupBy( var groupedRoles = ghostState.GhostRoles.GroupBy(
role => (role.Name, role.Description, role.Requirements)); role => (role.Name, role.Description, role.Requirements));
// Add a new entry for each role group
foreach (var group in groupedRoles) foreach (var group in groupedRoles)
{ {
var name = group.Key.Name; var name = group.Key.Name;
var description = group.Key.Description; var description = group.Key.Description;
bool hasAccess = true; var hasAccess = requirementsManager.CheckRoleRequirements(
FormattedMessage? reason; group.Key.Requirements,
null,
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason)) out var reason);
{
hasAccess = false;
}
// Adding a new role
_window.AddEntry(name, description, hasAccess, reason, group, spriteSystem); _window.AddEntry(name, description, hasAccess, reason, group, spriteSystem);
} }
// Restore the Collapsible box state if it is saved
_window.RestoreCollapsibleBoxesStates();
// Close the rules window if it is no longer needed
var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId); var closeRulesWindow = ghostState.GhostRoles.All(role => role.Identifier != _windowRulesId);
if (closeRulesWindow) if (closeRulesWindow)
{
_windowRules?.Close(); _windowRules?.Close();
} }
} }
}
} }

View File

@@ -1,31 +1,100 @@
using System.Linq;
using Content.Shared.Ghost.Roles; using Content.Shared.Ghost.Roles;
using Robust.Client.AutoGenerated; using Robust.Client.AutoGenerated;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility; using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
{ {
[GenerateTypedNameReferences] [GenerateTypedNameReferences]
public sealed partial class GhostRolesWindow : DefaultWindow public sealed partial class GhostRolesWindow : DefaultWindow // WD Edit ahead of wizden upstream
{ {
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked; public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
public event Action<GhostRoleInfo>? OnRoleFollow; public event Action<GhostRoleInfo>? OnRoleFollow;
private Dictionary<(string name, string description), Collapsible> _collapsibleBoxes = new();
private HashSet<(string name, string description)> _uncollapsedStates = new();
public GhostRolesWindow()
{
RobustXamlLoader.Load(this);
}
public void ClearEntries() public void ClearEntries()
{ {
NoRolesMessage.Visible = true; NoRolesMessage.Visible = true;
EntryContainer.DisposeAllChildren(); EntryContainer.DisposeAllChildren();
_collapsibleBoxes.Clear();
}
public void SaveCollapsibleBoxesStates()
{
_uncollapsedStates.Clear();
foreach (var (key, collapsible) in _collapsibleBoxes)
{
if (collapsible.BodyVisible)
{
_uncollapsedStates.Add(key);
}
}
}
public void RestoreCollapsibleBoxesStates()
{
foreach (var (key, collapsible) in _collapsibleBoxes)
{
collapsible.BodyVisible = _uncollapsedStates.Contains(key);
}
} }
public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem) public void AddEntry(string name, string description, bool hasAccess, FormattedMessage? reason, IEnumerable<GhostRoleInfo> roles, SpriteSystem spriteSystem)
{ {
NoRolesMessage.Visible = false; NoRolesMessage.Visible = false;
var entry = new GhostRolesEntry(name, description, hasAccess, reason, roles, spriteSystem); var ghostRoleInfos = roles.ToList();
entry.OnRoleSelected += OnRoleRequestButtonClicked; var rolesCount = ghostRoleInfos.Count;
entry.OnRoleFollow += OnRoleFollow;
EntryContainer.AddChild(entry); var info = new GhostRoleInfoBox(name, description);
var buttons = new GhostRoleButtonsBox(hasAccess, reason, ghostRoleInfos, spriteSystem);
buttons.OnRoleSelected += OnRoleRequestButtonClicked;
buttons.OnRoleFollow += OnRoleFollow;
EntryContainer.AddChild(info);
if (rolesCount > 1)
{
var buttonHeading = new CollapsibleHeading(Loc.GetString("ghost-roles-window-available-button", ("rolesCount", rolesCount)));
buttonHeading.AddStyleClass(ContainerButton.StyleClassButton);
buttonHeading.Label.HorizontalAlignment = HAlignment.Center;
buttonHeading.Label.HorizontalExpand = true;
var body = new CollapsibleBody
{
Margin = new Thickness(0, 5, 0, 0),
};
// TODO: Add Requirements to this key when it'll be fixed and work as an equality key in GhostRolesEui
var key = (name, description);
var collapsible = new Collapsible(buttonHeading, body)
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
Margin = new Thickness(0, 0, 0, 8),
};
body.AddChild(buttons);
EntryContainer.AddChild(collapsible);
_collapsibleBoxes.Add(key, collapsible);
}
else
{
EntryContainer.AddChild(buttons);
}
} }
} }
} }

View File

@@ -22,6 +22,7 @@ ghost-target-window-current-button = Warp: {$name}
ghost-target-window-warp-to-most-followed = Warp to Most Followed ghost-target-window-warp-to-most-followed = Warp to Most Followed
ghost-roles-window-title = Ghost Roles ghost-roles-window-title = Ghost Roles
ghost-roles-window-available-button = Available ({$rolesCount})
ghost-roles-window-join-raffle-button = Join raffle ghost-roles-window-join-raffle-button = Join raffle
ghost-roles-window-raffle-in-progress-button = ghost-roles-window-raffle-in-progress-button =
Join raffle ({$time} left, { $players -> Join raffle ({$time} left, { $players ->

View File

@@ -23,7 +23,7 @@ ghost-target-window-title = Телепорт призрака
ghost-target-window-current-button = Телепорт в: { $name } ghost-target-window-current-button = Телепорт в: { $name }
ghost-roles-window-title = Роли призраков ghost-roles-window-title = Роли призраков
ghost-roles-window-available-button = Доступно ({$rolesCount})
ghost-roles-window-join-raffle-button = Начать лотерею ghost-roles-window-join-raffle-button = Начать лотерею
ghost-roles-window-raffle-in-progress-button = ghost-roles-window-raffle-in-progress-button =
Участвовать ({$time} осталось, { $players -> Участвовать ({$time} осталось, { $players ->