Collapsible ghost roles menu (#32717)
* Make ghost roles collapsible * Save `BodyVisible` state of each `Collapsible` box * Make ghost role collapsible only when group has more than 1 role * Make it a little prettier * Make only ghost role buttons collapsible * Apply requested changes * Typo * Small cleanup * Store in list, instead of iterating * Make unique ids more unique * Move it out of the cycle * Make _collapsibleBoxes into dictionary and use key instead of Collapsible boxes names Added TODO. So after the problem will be fixed in `GhostRolesEui`, it should be mirrored and fixed here too. * Put TODO in GhostRolesEui. I guess Issue must be made for this * Use HashSet instead of Dictionary as suggested. Invert the HashSet, so being present means it uncollapsed I decided to invert HashSet to _uncollapsedStates, because players surely will have more collapsed buttons than opened, so we optimise memory usage a little bit. * Remove extra space from ghost roles window * Add buttons stretching. Size 3:1
This commit is contained in:
@@ -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>
|
||||
@@ -10,20 +10,17 @@ using Robust.Shared.Utility;
|
||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
{
|
||||
[GenerateTypedNameReferences]
|
||||
public sealed partial class GhostRolesEntry : BoxContainer
|
||||
public sealed partial class GhostRoleButtonsBox : BoxContainer
|
||||
{
|
||||
private SpriteSystem _spriteSystem;
|
||||
public event Action<GhostRoleInfo>? OnRoleSelected;
|
||||
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)
|
||||
{
|
||||
RobustXamlLoader.Load(this);
|
||||
_spriteSystem = spriteSystem;
|
||||
|
||||
Title.Text = name;
|
||||
Description.SetMessage(description);
|
||||
|
||||
foreach (var role in roles)
|
||||
{
|
||||
var button = new GhostRoleEntryButtons(role);
|
||||
@@ -1,15 +1,15 @@
|
||||
<BoxContainer xmlns="https://spacestation14.io"
|
||||
Orientation="Horizontal">
|
||||
Orientation="Horizontal"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Button Name="RequestButton"
|
||||
Access="Public"
|
||||
Text="{Loc 'ghost-roles-window-request-role-button'}"
|
||||
StyleClasses="OpenRight"
|
||||
HorizontalAlignment="Left"
|
||||
SetWidth="300"/>
|
||||
HorizontalExpand="True"
|
||||
SizeFlagsStretchRatio="3"/>
|
||||
<Button Name="FollowButton"
|
||||
Access="Public"
|
||||
Text="{Loc 'ghost-roles-window-follow-role-button'}"
|
||||
StyleClasses="OpenLeft"
|
||||
HorizontalAlignment="Right"
|
||||
SetWidth="150"/>
|
||||
HorizontalExpand="True"/>
|
||||
</BoxContainer>
|
||||
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -5,7 +5,6 @@ using Content.Shared.Eui;
|
||||
using Content.Shared.Ghost.Roles;
|
||||
using JetBrains.Annotations;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
{
|
||||
@@ -77,6 +76,13 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
|
||||
if (state is not GhostRolesEuiState ghostState)
|
||||
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();
|
||||
|
||||
var entityManager = IoCManager.Resolve<IEntityManager>();
|
||||
@@ -84,28 +90,32 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
var spriteSystem = sysManager.GetEntitySystem<SpriteSystem>();
|
||||
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(
|
||||
role => (role.Name, role.Description, role.Requirements));
|
||||
|
||||
// Add a new entry for each role group
|
||||
foreach (var group in groupedRoles)
|
||||
{
|
||||
var name = group.Key.Name;
|
||||
var description = group.Key.Description;
|
||||
bool hasAccess = true;
|
||||
FormattedMessage? reason;
|
||||
|
||||
if (!requirementsManager.CheckRoleRequirements(group.Key.Requirements, null, out reason))
|
||||
{
|
||||
hasAccess = false;
|
||||
}
|
||||
var hasAccess = requirementsManager.CheckRoleRequirements(
|
||||
group.Key.Requirements,
|
||||
null,
|
||||
out var reason);
|
||||
|
||||
// Adding a new role
|
||||
_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);
|
||||
if (closeRulesWindow)
|
||||
{
|
||||
_windowRules?.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
using System.Linq;
|
||||
using Content.Shared.Ghost.Roles;
|
||||
using Robust.Client.AutoGenerated;
|
||||
using Robust.Client.GameObjects;
|
||||
using Robust.Client.UserInterface.Controls;
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
using Robust.Client.UserInterface.XAML;
|
||||
using Robust.Shared.Utility;
|
||||
|
||||
namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
@@ -12,20 +15,86 @@ namespace Content.Client.UserInterface.Systems.Ghost.Controls.Roles
|
||||
public event Action<GhostRoleInfo>? OnRoleRequestButtonClicked;
|
||||
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()
|
||||
{
|
||||
NoRolesMessage.Visible = true;
|
||||
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)
|
||||
{
|
||||
NoRolesMessage.Visible = false;
|
||||
|
||||
var entry = new GhostRolesEntry(name, description, hasAccess, reason, roles, spriteSystem);
|
||||
entry.OnRoleSelected += OnRoleRequestButtonClicked;
|
||||
entry.OnRoleFollow += OnRoleFollow;
|
||||
EntryContainer.AddChild(entry);
|
||||
var ghostRoleInfos = roles.ToList();
|
||||
var rolesCount = ghostRoleInfos.Count;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ ghost-target-window-current-button = Warp: {$name}
|
||||
ghost-target-window-warp-to-most-followed = Warp to Most Followed
|
||||
|
||||
ghost-roles-window-title = Ghost Roles
|
||||
ghost-roles-window-available-button = Available ({$rolesCount})
|
||||
ghost-roles-window-join-raffle-button = Join raffle
|
||||
ghost-roles-window-raffle-in-progress-button =
|
||||
Join raffle ({$time} left, { $players ->
|
||||
|
||||
Reference in New Issue
Block a user