mirror of
https://github.com/DeltaV-Station/Delta-v.git
synced 2026-10-06 22:37:27 +00:00
* Fix the sensor monitoring console forcing a GC every 3 seconds (#38146) * Optimize sensor monitoring window graph drawing * Add shared static Vector2 pool for all GraphView instances * Address requested changes * remove lock * Update submodule to 264.0.0 (#38629) * Toy/Plushie Inhands and Wearables (#38514) * Fixed dependency injection and some other issues in a few places. * More issue fixes * patchfor broken NetworkConfiguratorLinkMenu (#38632) fix * Fix solutions flickering when transferring contents (#34838) * Use Solution clones when applying SolutionComponent states * Revert "Use Solution clones when applying SolutionComponent states" This reverts commit 013fd111cf92b22562e00f98a7aaa49bc4b4ed62. * Make Solution implement ICloneable and rename Clone method. * Copy CanReact value when cloning a Solution * Convert to IRobustCloneable * Fix typos in guidebook: Buisness → Business (#38636) * Fix typo in `MinorAntagonists.xml` Buisness → Business * Fix typo in `YourFirstCharacter.xml` Buisness → Business * Various Headphones Fixes and Tweaks (#38479) * sprites, wearables * neck * icon-on sprite * Cleanup prototype instantiation in `DamageTest` (#38639) Cleanup prototype instantiation in DamageTest * Cleanup prototype instantiation in `ExplosionSystem` (#38642) Cleanup prototype instantiation in ExplosionSystem * AddBodyPartCommand localization. (#38612) commit * fix ItemSlotsSystem debug assert (#38655) * Allow the Command & Super door remotes to use the access of their user. (Re-creation of PR due to changes to game balance) (#35536) * Added directional beacons (#38284) * Added directional beacons Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Fixed names Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * Power stat and nuke codes commands get some LEC love. (#38585) * commit * requested changes. * Dsay Dirty and Follow commands converted to LEC and localized. (#38666) * commit * whoopwhoopwhoop * Retro laser sprite fix (#38676) * Fixed everything except the icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fixed icon Signed-off-by: Nox38 <nebulousnox38@gmail.com> --------- Signed-off-by: Nox38 <nebulousnox38@gmail.com> * fix water coolers (#38681) * Monochromacy typo fix (#38686) * fixes the typo * Fixed cloning looking for the trait, not the component, RE https://github.com/space-wizards/space-station-14/pull/38686#issuecomment-3025093504 * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Validate `CloningSettingsPrototype`s (#38688) * Validate CloningSettingsPrototypes * Update Content.IntegrationTests/Tests/Cloning/CloningSettingsPrototypeTest.cs Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Check EventComponents too --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Add test of objective-related console commands (#36400) * Add test of objective add/list/remove commands * Not sure why we're validating test prototypes, but sure * We don't need a map * Improvements and fixups for New Status Effect API (#38660) * Predict healing and bloodstream (#38690) * initial commit * reapply 38126 * fix rootable * someone missed an important minus sign here * try this * fix * fix * reenable crit hits * cleanup * fix status time dirtying * fix * camelCase * Healing and bloodstream prediction fixes. * Resolving Wizard casting recall on nuke disk making it impossible to disarm (#38661) * Resolving Wizard Recall on Nuke disk making it impossible to disarm - Adding a DisarmBomb case to nuke status update loop - Changing a few methods and parameters to properly follow formatting standards - Updating some names to follow camelCase * Updating missed tag * Reverting DataField change Should prevent this preventative bugfix being a breaking change. * Switch HSV to the default colorspace for character customization (#38434) * Made HSV default for character editor * Adds/fixes comments to HSV defaulting * Added dropbox fix, potentially cursed * Revert "Added dropbox fix, potentially cursed" This reverts commit a709883366fbee813e839742125e70844672af29. --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Fix: Don't deploy foldables when clicking on items inside containers (#38709) * Fix * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Pressure Relief Valve (#36708) * initial system (this math is probably WRONG) * General code cleanup and OnExamined support (holy moly this code sucks) * UICode and related events foundation TODO: - Actually write the XAML UI and the underlying system - Un-shitcode the entire thing - Actually test everything... * Working UI code TODO: Make predicted, as this certainly isn't predicted. Even though I said it was. It isn't. * Remove one TODO for unshitcoding the examine code * Add reminder yea * Make predicted (defenitely isn't) (also defenitely isn't a copypaste from pressure pump code) * It's predicted! TODO: - Give it snazzy predicted visuals! - Have a different field for pressure entry, lest it gets bulldozed every UI update. * Improve gas pressure relief valve UI TODO: Reminder to reduce amount of dirties using deltafields * Implement DirtyField prediction * Entity<T> cleanup A lot of Entity<T> conversions and lukewarm cleanup. Also got caught copy pasting code in 4K UHD but it's not like you couldn't tell. * More cleanup and comments * Remove TODO comment on bulldozing window title * """refactoring""" - Move appearance out of shared and finally fix it. Pointless to predict appearance in this instance. - More Entity<T> conversions because I like them. - Move UI creation handling over entirely to the ActivatableUI system. - Fix a hardcoded locale string (why????). * Add visuals * Revert debugging variable replacememt yea * Revert skissue * Remove unused using directives and remove TODO * Localize, cleanup, document * Fix adminlogging discrepancy * Add ability to construct, add guidebook entry * Clear up comment * Add guidebook tooltip to valve * Convert GasPressureReliefValveBoundUserInterface declaration into primary constructor * Adds more input handling and adds autofill on open * Un-deepfry input validator shitcode Genuinely what was I smoking * improve visuals logic * Refactor again - Update math to the correct implementation - Moved code that could be re-used in the future into a helper method under AtmosphereSystem.Gases.cs * I'm sorry but I hate warnings * Remove unused using directive in AtmosphereSystem.Gases.cs * Review and cleanup * Lukewarm UI glossup * Maintainer for the upstream project btw * Remove redundant state sets and messy logic * Unduplicate valve updater code * Redo UI (im sorry Slarti) * run tests * Test refactored UI messaging * Second round of UI improvements - God please find a way to improve this system. Feels bad. * Update loop implementation * Further predict UI * Clear up SetToCurrentThreshold * cleanup * Update to master + pipe layers and bug fixes want to run tests * fixes * Deploy rename pipebomb * Documentation and requested changes * Rename the method that wiggled away * Undo rounding changes * Fix comment * Rename and cleanup * Apply suggestions from code review --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Fix TextLinkTag (#32203) * Adjust uplink buy button to be under item icon (#38596) * Adjusted uplink buy button to be under item icon * Put the discount subtext under the icon * Indent fixes, added margin --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * Scurrets - Audio Improvements (#38482) * Scurret audio tuning * Add new sfx * Update sneezing sfx * YAML support * Rename a folder * make telesci wreck easier (#37569) rel * Validate `ShaderPrototype` IDs (#38728) * Convert all shader prototype string literals to protoids in overlays * Convert more shader prototype literal strings to protoids * Convert ValidatePrototypeId to ProtoId * Later * [BUGFIX] Fixed revenant malfunction ability not working properly only MediBots and Stasis bed (#38664) * fixed * clean up * orks fix smart * review fix 1 * more requested changes * less cursed * more descriptive description * better wording * Tiny Tiny Cleanup of the EyeClosingSystem. (#38734) Update EyeClosingSystem.cs * Fix human skin tone distribution (#38701) * fix: Use PredictedQueueDel for gib spell (#38729) * fix: don't default to uncharged sprite state for cells (#38730) * Fix Hristov description - remove inaccurate technical specs (#38746) - Removes inaccurate 'armor piercing 14.5mm shells' reference - Replaces it with a more funny description, matching the style of the other snipers and guns - Keeps ammunition type '.60 anti-materiel ammo' specification - Fixes issue #38590 Co-authored-by: Arthur Fiorese de Andrade <aandrade@cmcxs.gov.br> * feat: allow mopping evaporating puddles (#38743) * Validate remaining `ProtoId` strings (#38747) Validate remaining ProtoId strings * Validate `ProtoId`s in tests (#38745) * Convert string literals to protoids in Content.Tests * Convert string literals to protoids or consts in Content.IntegrationTests * Fix linter failures Tricksy static using misled me * Cleanup warning in StomachSystem (#38748) you did not see this * Vox scars (#38592) * Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl * Revert "Added vox scars n'stuff, renamed vox_tattoos.ftl to just vox.ftl" This reverts commit c73da55ba3b39ddf93b493aecd85604c54dd8a15. * locale key fix * Changed top surgery scar names to be more generalized * Adjusted face scars * Formatting fixes --------- Co-authored-by: TrixxedHeart <46364955+TrixxedBit@users.noreply.github.com> * UnlockNode command to LEC. (#38751) * commit * Update UnlockNodeCommand.cs * commit * move command locale to its own file. * Update Content.Server/Xenoarchaeology/Artifact/UnlockNodeCommand.cs --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Typofixes for figurine dialogue (#38737) * Typofixes for figurine dialogue * Forgot two * Janitor Tool: Wire Brush (#38667) * Wow! It's -brush- * spacing. * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Update Resources/Prototypes/Entities/Objects/Specific/Janitorial/janitor.yml Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * fixed changes --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> * Minor escape menu UX improvements (#38650) * fix: spellbooks can have infinite charges (#38376) * fix: spellbooks can have infinite charges * refactor: indicate infinite spellbook charges with null Not sure if I like this much better...
452 lines
16 KiB
C#
452 lines
16 KiB
C#
using Content.Client.Stylesheets;
|
||
using Content.Client.UserInterface.Controls;
|
||
using Content.Shared.Access;
|
||
using Robust.Client.AutoGenerated;
|
||
using Robust.Client.Graphics;
|
||
using Robust.Client.UserInterface;
|
||
using Robust.Client.UserInterface.Controls;
|
||
using Robust.Client.UserInterface.XAML;
|
||
using Robust.Shared.Prototypes;
|
||
using System.Linq;
|
||
using System.Numerics;
|
||
|
||
namespace Content.Client.Access.UI;
|
||
|
||
[GenerateTypedNameReferences]
|
||
public sealed partial class GroupedAccessLevelChecklist : BoxContainer
|
||
{
|
||
private static readonly ProtoId<AccessGroupPrototype> GeneralAccessGroup = "General";
|
||
|
||
[Dependency] private readonly IPrototypeManager _protoManager = default!;
|
||
|
||
private bool _isMonotone;
|
||
private string? _labelStyleClass;
|
||
|
||
// Access data
|
||
private HashSet<ProtoId<AccessGroupPrototype>> _accessGroups = new();
|
||
private HashSet<ProtoId<AccessLevelPrototype>> _accessLevels = new();
|
||
private HashSet<ProtoId<AccessLevelPrototype>> _activeAccessLevels = new();
|
||
|
||
// Button groups
|
||
private readonly ButtonGroup _accessGroupsButtons = new();
|
||
|
||
// Temp values
|
||
private int _accessGroupTabIndex = 0;
|
||
private bool _canInteract = false;
|
||
private List<AccessLevelPrototype> _accessLevelsForTab = new();
|
||
private readonly List<AccessLevelEntry> _accessLevelEntries = new();
|
||
private readonly Dictionary<AccessGroupPrototype, List<AccessLevelPrototype>> _groupedAccessLevels = new();
|
||
|
||
// Events
|
||
public event Action<HashSet<ProtoId<AccessLevelPrototype>>, bool>? OnAccessLevelsChangedEvent;
|
||
|
||
/// <summary>
|
||
/// Creates a UI control for changing access levels.
|
||
/// Access levels are organized under a list of tabs by their associated access group.
|
||
/// </summary>
|
||
public GroupedAccessLevelChecklist()
|
||
{
|
||
RobustXamlLoader.Load(this);
|
||
IoCManager.InjectDependencies(this);
|
||
}
|
||
|
||
private void ArrangeAccessControls()
|
||
{
|
||
// Create a list of known access groups with which to populate the UI
|
||
_groupedAccessLevels.Clear();
|
||
|
||
foreach (var accessGroup in _accessGroups)
|
||
{
|
||
if (!_protoManager.TryIndex(accessGroup, out var accessGroupProto))
|
||
continue;
|
||
|
||
_groupedAccessLevels.Add(accessGroupProto, new());
|
||
}
|
||
|
||
// Ensure that the 'general' access group is added to handle
|
||
// misc. access levels that aren't associated with any group
|
||
if (_protoManager.TryIndex(GeneralAccessGroup, out var generalAccessProto))
|
||
_groupedAccessLevels.TryAdd(generalAccessProto, new());
|
||
|
||
// Assign known access levels with their associated groups
|
||
foreach (var accessLevel in _accessLevels)
|
||
{
|
||
if (!_protoManager.TryIndex(accessLevel, out var accessLevelProto))
|
||
continue;
|
||
|
||
var assigned = false;
|
||
|
||
foreach (var (accessGroup, accessLevels) in _groupedAccessLevels)
|
||
{
|
||
if (!accessGroup.Tags.Contains(accessLevelProto.ID))
|
||
continue;
|
||
|
||
assigned = true;
|
||
_groupedAccessLevels[accessGroup].Add(accessLevelProto);
|
||
}
|
||
|
||
if (!assigned && generalAccessProto != null)
|
||
_groupedAccessLevels[generalAccessProto].Add(accessLevelProto);
|
||
}
|
||
|
||
// Remove access groups that have no assigned access levels
|
||
foreach (var (group, accessLevels) in _groupedAccessLevels)
|
||
{
|
||
if (accessLevels.Count == 0)
|
||
_groupedAccessLevels.Remove(group);
|
||
}
|
||
}
|
||
|
||
private bool TryRebuildAccessGroupControls()
|
||
{
|
||
AccessGroupList.DisposeAllChildren();
|
||
AccessLevelChecklist.DisposeAllChildren();
|
||
|
||
// No access level prototypes were assigned to any of the access level groups.
|
||
// Either the turret controller has no assigned access levels or their names were invalid.
|
||
if (_groupedAccessLevels.Count == 0)
|
||
return false;
|
||
|
||
// Reorder the access groups alphabetically
|
||
var orderedAccessGroups = _groupedAccessLevels.Keys.OrderBy(x => x.GetAccessGroupName()).ToList();
|
||
|
||
// Add group access buttons to the UI
|
||
foreach (var accessGroup in orderedAccessGroups)
|
||
{
|
||
var accessGroupButton = CreateAccessGroupButton();
|
||
|
||
// Button styling
|
||
if (_groupedAccessLevels.Count > 1)
|
||
{
|
||
if (AccessGroupList.ChildCount == 0)
|
||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenLeft);
|
||
else if (_groupedAccessLevels.Count > 1 && AccessGroupList.ChildCount == (_groupedAccessLevels.Count - 1))
|
||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenRight);
|
||
else
|
||
accessGroupButton.AddStyleClass(StyleBase.ButtonOpenBoth);
|
||
}
|
||
|
||
accessGroupButton.Pressed = _accessGroupTabIndex == orderedAccessGroups.IndexOf(accessGroup);
|
||
|
||
// Label text and styling
|
||
if (_labelStyleClass != null)
|
||
accessGroupButton.Label.SetOnlyStyleClass(_labelStyleClass);
|
||
|
||
var accessLevelPrototypes = _groupedAccessLevels[accessGroup];
|
||
var prefix = accessLevelPrototypes.All(x => _activeAccessLevels.Contains(x))
|
||
? "»"
|
||
: accessLevelPrototypes.Any(x => _activeAccessLevels.Contains(x))
|
||
? "›"
|
||
: " ";
|
||
|
||
var text = Loc.GetString(
|
||
"turret-controls-window-access-group-label",
|
||
("prefix", prefix),
|
||
("label", accessGroup.GetAccessGroupName())
|
||
);
|
||
|
||
accessGroupButton.Text = text;
|
||
|
||
// Button events
|
||
accessGroupButton.OnPressed += _ => OnAccessGroupChanged(accessGroupButton.GetPositionInParent());
|
||
|
||
AccessGroupList.AddChild(accessGroupButton);
|
||
}
|
||
|
||
// Adjust the current tab index so it remains in range
|
||
if (_accessGroupTabIndex >= _groupedAccessLevels.Count)
|
||
_accessGroupTabIndex = _groupedAccessLevels.Count - 1;
|
||
|
||
return true;
|
||
}
|
||
|
||
/// <summary>
|
||
/// Rebuilds the checkbox list for the access level controls.
|
||
/// </summary>
|
||
public void RebuildAccessLevelsControls()
|
||
{
|
||
AccessLevelChecklist.DisposeAllChildren();
|
||
_accessLevelEntries.Clear();
|
||
|
||
// No access level prototypes were assigned to any of the access level groups
|
||
// Either turret controller has no assigned access levels, or their names were invalid
|
||
if (_groupedAccessLevels.Count == 0)
|
||
return;
|
||
|
||
// Reorder the access groups alphabetically
|
||
var orderedAccessGroups = _groupedAccessLevels.Keys.OrderBy(x => x.GetAccessGroupName()).ToList();
|
||
|
||
// Get the access levels associated with the current tab
|
||
var selectedAccessGroupTabProto = orderedAccessGroups[_accessGroupTabIndex];
|
||
_accessLevelsForTab = _groupedAccessLevels[selectedAccessGroupTabProto];
|
||
_accessLevelsForTab = _accessLevelsForTab.OrderBy(x => x.GetAccessLevelName()).ToList();
|
||
|
||
// Add an 'all' checkbox as the first child of the list if it has more than one access level
|
||
// Toggling this checkbox on will mark all other boxes below it on/off
|
||
var allCheckBox = CreateAccessLevelCheckbox();
|
||
allCheckBox.Text = Loc.GetString("turret-controls-window-all-checkbox");
|
||
|
||
if (_labelStyleClass != null)
|
||
allCheckBox.Label.SetOnlyStyleClass(_labelStyleClass);
|
||
|
||
// Add the 'all' checkbox events
|
||
allCheckBox.OnPressed += args =>
|
||
{
|
||
SetCheckBoxPressedState(_accessLevelEntries, allCheckBox.Pressed);
|
||
|
||
var accessLevels = new HashSet<ProtoId<AccessLevelPrototype>>();
|
||
|
||
foreach (var accessLevel in _accessLevelsForTab)
|
||
{
|
||
accessLevels.Add(accessLevel);
|
||
}
|
||
|
||
OnAccessLevelsChangedEvent?.Invoke(accessLevels, allCheckBox.Pressed);
|
||
};
|
||
|
||
AccessLevelChecklist.AddChild(allCheckBox);
|
||
|
||
// Hide the 'all' checkbox if the tab has only one access level
|
||
var allCheckBoxVisible = _accessLevelsForTab.Count > 1;
|
||
|
||
allCheckBox.Visible = allCheckBoxVisible;
|
||
allCheckBox.Disabled = !_canInteract;
|
||
|
||
// Add any remaining missing access level buttons to the UI
|
||
foreach (var accessLevel in _accessLevelsForTab)
|
||
{
|
||
// Create the entry
|
||
var accessLevelEntry = new AccessLevelEntry(_isMonotone);
|
||
|
||
accessLevelEntry.AccessLevel = accessLevel;
|
||
accessLevelEntry.CheckBox.Text = accessLevel.GetAccessLevelName();
|
||
accessLevelEntry.CheckBox.Pressed = _activeAccessLevels.Contains(accessLevel);
|
||
accessLevelEntry.CheckBox.Disabled = !_canInteract;
|
||
|
||
if (_labelStyleClass != null)
|
||
accessLevelEntry.CheckBox.Label.SetOnlyStyleClass(_labelStyleClass);
|
||
|
||
// Set the checkbox linkage lines
|
||
var isEndOfList = _accessLevelsForTab.IndexOf(accessLevel) == (_accessLevelsForTab.Count - 1);
|
||
|
||
var lines = new List<(Vector2, Vector2)>
|
||
{
|
||
(new Vector2(0.5f, 0f), new Vector2(0.5f, isEndOfList ? 0.5f : 1f)),
|
||
(new Vector2(0.5f, 0.5f), new Vector2(1f, 0.5f)),
|
||
};
|
||
|
||
accessLevelEntry.UpdateCheckBoxLink(lines);
|
||
accessLevelEntry.CheckBoxLink.Visible = allCheckBoxVisible;
|
||
accessLevelEntry.CheckBoxLink.Modulate = !_canInteract ? Color.Gray : Color.White;
|
||
|
||
// Add checkbox events
|
||
accessLevelEntry.CheckBox.OnPressed += args =>
|
||
{
|
||
// If the checkbox and its siblings are checked, check the 'all' checkbox too
|
||
allCheckBox.Pressed = AreAllCheckBoxesPressed(_accessLevelEntries.Select(x => x.CheckBox));
|
||
|
||
OnAccessLevelsChangedEvent?.Invoke([accessLevelEntry.AccessLevel], accessLevelEntry.CheckBox.Pressed);
|
||
};
|
||
|
||
AccessLevelChecklist.AddChild(accessLevelEntry);
|
||
_accessLevelEntries.Add(accessLevelEntry);
|
||
}
|
||
|
||
// Press the 'all' checkbox if all others are pressed
|
||
allCheckBox.Pressed = AreAllCheckBoxesPressed(_accessLevelEntries.Select(x => x.CheckBox));
|
||
}
|
||
|
||
private bool AreAllCheckBoxesPressed(IEnumerable<CheckBox> checkBoxes)
|
||
{
|
||
foreach (var checkBox in checkBoxes)
|
||
{
|
||
if (!checkBox.Pressed)
|
||
return false;
|
||
}
|
||
|
||
return true;
|
||
}
|
||
|
||
private void SetCheckBoxPressedState(List<AccessLevelEntry> accessLevelEntries, bool pressed)
|
||
{
|
||
foreach (var accessLevelEntry in accessLevelEntries)
|
||
{
|
||
accessLevelEntry.CheckBox.Pressed = pressed;
|
||
}
|
||
}
|
||
|
||
|
||
/// <summary>
|
||
/// Provides the UI with a list of access groups using which list of tabs should be populated.
|
||
/// </summary>
|
||
public void SetAccessGroups(HashSet<ProtoId<AccessGroupPrototype>> accessGroups)
|
||
{
|
||
_accessGroups = accessGroups;
|
||
|
||
ArrangeAccessControls();
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Provides the UI with a list of access levels with which it can populate the currently selected tab.
|
||
/// </summary>
|
||
public void SetAccessLevels(HashSet<ProtoId<AccessLevelPrototype>> accessLevels)
|
||
{
|
||
_accessLevels = accessLevels;
|
||
|
||
ArrangeAccessControls();
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets which access level checkboxes should be marked on the UI.
|
||
/// </summary>
|
||
public void SetActiveAccessLevels(HashSet<ProtoId<AccessLevelPrototype>> activeAccessLevels)
|
||
{
|
||
_activeAccessLevels = activeAccessLevels;
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets whether the local player can interact with the checkboxes.
|
||
/// </summary>
|
||
public void SetLocalPlayerAccessibility(bool canInteract)
|
||
{
|
||
_canInteract = canInteract;
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Sets whether the UI should use monotone buttons and checkboxes.
|
||
/// </summary>
|
||
public void SetMonotone(bool monotone)
|
||
{
|
||
_isMonotone = monotone;
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
/// <summary>
|
||
/// Applies the specified style to the labels on the UI buttons and checkboxes.
|
||
/// </summary>
|
||
public void SetLabelStyleClass(string? styleClass)
|
||
{
|
||
_labelStyleClass = styleClass;
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
private void OnAccessGroupChanged(int newTabIndex)
|
||
{
|
||
if (newTabIndex == _accessGroupTabIndex)
|
||
return;
|
||
|
||
_accessGroupTabIndex = newTabIndex;
|
||
|
||
if (TryRebuildAccessGroupControls())
|
||
RebuildAccessLevelsControls();
|
||
}
|
||
|
||
private Button CreateAccessGroupButton()
|
||
{
|
||
var button = _isMonotone ? new MonotoneButton() : new Button();
|
||
|
||
button.ToggleMode = true;
|
||
button.Group = _accessGroupsButtons;
|
||
button.Label.HorizontalAlignment = HAlignment.Left;
|
||
|
||
return button;
|
||
}
|
||
|
||
private CheckBox CreateAccessLevelCheckbox()
|
||
{
|
||
var checkbox = _isMonotone ? new MonotoneCheckBox() : new CheckBox();
|
||
|
||
checkbox.Margin = new Thickness(0, 0, 0, 3);
|
||
checkbox.ToggleMode = true;
|
||
checkbox.ReservesSpace = false;
|
||
|
||
return checkbox;
|
||
}
|
||
|
||
private sealed class AccessLevelEntry : BoxContainer
|
||
{
|
||
public ProtoId<AccessLevelPrototype> AccessLevel;
|
||
public readonly CheckBox CheckBox;
|
||
public readonly LineRenderer CheckBoxLink;
|
||
|
||
public AccessLevelEntry(bool monotone)
|
||
{
|
||
HorizontalExpand = true;
|
||
|
||
CheckBoxLink = new LineRenderer
|
||
{
|
||
SetWidth = 22,
|
||
VerticalExpand = true,
|
||
Margin = new Thickness(0, -1),
|
||
ReservesSpace = false,
|
||
};
|
||
|
||
AddChild(CheckBoxLink);
|
||
|
||
CheckBox = monotone ? new MonotoneCheckBox() : new CheckBox();
|
||
CheckBox.ToggleMode = true;
|
||
CheckBox.Margin = new Thickness(0f, 0f, 0f, 3f);
|
||
|
||
AddChild(CheckBox);
|
||
}
|
||
|
||
public void UpdateCheckBoxLink(List<(Vector2, Vector2)> lines)
|
||
{
|
||
CheckBoxLink.Lines = lines;
|
||
}
|
||
}
|
||
|
||
private sealed class LineRenderer : Control
|
||
{
|
||
/// <summary>
|
||
/// List of lines to render (their start and end x-y coordinates).
|
||
/// Position (0,0) is the top left corner of the control and
|
||
/// position (1,1) is the bottom right corner.
|
||
/// </summary>
|
||
/// <remarks>
|
||
/// The color of the lines is inherited from the control.
|
||
/// </remarks>
|
||
public List<(Vector2, Vector2)> Lines;
|
||
|
||
public LineRenderer()
|
||
{
|
||
Lines = new List<(Vector2, Vector2)>();
|
||
}
|
||
|
||
public LineRenderer(List<(Vector2, Vector2)> lines)
|
||
{
|
||
Lines = lines;
|
||
}
|
||
|
||
protected override void Draw(DrawingHandleScreen handle)
|
||
{
|
||
foreach (var line in Lines)
|
||
{
|
||
var start = PixelPosition +
|
||
new Vector2(PixelWidth * line.Item1.X, PixelHeight * line.Item1.Y);
|
||
|
||
var end = PixelPosition +
|
||
new Vector2(PixelWidth * line.Item2.X, PixelHeight * line.Item2.Y);
|
||
|
||
handle.DrawLine(start, end, ActualModulateSelf);
|
||
}
|
||
}
|
||
}
|
||
}
|