Merge remote-tracking branch 'upstream/stable' into ed-12-05-2025-upstream

# Conflicts:
#	.github/CODEOWNERS
#	Content.Client/Construction/UI/ConstructionMenuPresenter.cs
#	Content.Shared/Construction/Prototypes/ConstructionPrototype.cs
#	Content.Shared/Damage/Systems/SharedStaminaSystem.cs
#	Content.Shared/Lock/LockSystem.cs
#	Resources/Prototypes/Entities/Mobs/Customization/Markings/human_hair.yml
#	Resources/Prototypes/Entities/Objects/Specific/chemistry.yml
#	Resources/Prototypes/Procedural/vgroid.yml
This commit is contained in:
Ed
2025-05-12 14:25:42 +03:00
1224 changed files with 155650 additions and 65383 deletions

View File

@@ -81,4 +81,54 @@ namespace Content.Client.UserInterface.Controls
return mode;
}
}
/// <summary>
/// Helper functions for working with <see cref="FancyWindow"/>.
/// </summary>
public static class FancyWindowExt
{
/// <summary>
/// Sets information for a window (title and guidebooks) based on an entity.
/// </summary>
/// <param name="window">The window to modify.</param>
/// <param name="entityManager">Entity manager used to retrieve the information.</param>
/// <param name="entity">The entity that this window represents.</param>
/// <seealso cref="SetTitleFromEntity"/>
/// <seealso cref="SetGuidebookFromEntity"/>
public static void SetInfoFromEntity(this FancyWindow window, IEntityManager entityManager, EntityUid entity)
{
window.SetTitleFromEntity(entityManager, entity);
window.SetGuidebookFromEntity(entityManager, entity);
}
/// <summary>
/// Set a window's title to the name of an entity.
/// </summary>
/// <param name="window">The window to modify.</param>
/// <param name="entityManager">Entity manager used to retrieve the information.</param>
/// <param name="entity">The entity that this window represents.</param>
/// <seealso cref="SetInfoFromEntity"/>
public static void SetTitleFromEntity(
this FancyWindow window,
IEntityManager entityManager,
EntityUid entity)
{
window.Title = entityManager.GetComponent<MetaDataComponent>(entity).EntityName;
}
/// <summary>
/// Set a window's guidebook IDs to those of an entity.
/// </summary>
/// <param name="window">The window to modify.</param>
/// <param name="entityManager">Entity manager used to retrieve the information.</param>
/// <param name="entity">The entity that this window represents.</param>
/// <seealso cref="SetInfoFromEntity"/>
public static void SetGuidebookFromEntity(
this FancyWindow window,
IEntityManager entityManager,
EntityUid entity)
{
window.HelpGuidebookIds = entityManager.GetComponentOrNull<GuideHelpComponent>(entity)?.Guides;
}
}
}

View File

@@ -264,12 +264,6 @@ public class ListContainer : Control
_updateChildren = false;
var toRemove = new Dictionary<ListData, ListContainerButton>(_buttons);
foreach (var child in Children.ToArray())
{
if (child == _vScrollBar)
continue;
RemoveChild(child);
}
if (_data.Count > 0)
{
@@ -292,8 +286,9 @@ public class ListContainer : Control
if (Toggle && data == _selected)
button.Pressed = true;
AddChild(button);
}
AddChild(button);
button.SetPositionInParent(i - _topIndex);
button.Measure(finalSize);
}
}

View File

@@ -0,0 +1,79 @@
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
using static Robust.Client.UserInterface.Controls.Label;
namespace Content.Client.UserInterface.Controls;
/// <summary>
/// A button intended for use with a monotone color palette
/// </summary>
public sealed class MonotoneButton : ContainerButton
{
/// <summary>
/// Specifies the color of the label text when the button is pressed.
/// </summary>
[ViewVariables]
public Color AltTextColor { set; get; } = new Color(0.2f, 0.2f, 0.2f);
/// <summary>
/// The label that holds the button text.
/// </summary>
public Label Label { get; }
/// <summary>
/// The text displayed by the button.
/// </summary>
[PublicAPI, ViewVariables]
public string? Text { get => Label.Text; set => Label.Text = value; }
/// <summary>
/// How to align the text inside the button.
/// </summary>
[PublicAPI, ViewVariables]
public AlignMode TextAlign { get => Label.Align; set => Label.Align = value; }
/// <summary>
/// If true, the button will allow shrinking and clip text
/// to prevent the text from going outside the bounds of the button.
/// If false, the minimum size will always fit the contained text.
/// </summary>
[PublicAPI, ViewVariables]
public bool ClipText
{
get => Label.ClipText;
set => Label.ClipText = value;
}
public MonotoneButton()
{
Label = new Label
{
StyleClasses = { StyleClassButton }
};
AddChild(Label);
UpdateAppearance();
}
private void UpdateAppearance()
{
// Recolor the label
if (Label != null)
Label.ModulateSelfOverride = DrawMode == DrawModeEnum.Pressed ? AltTextColor : null;
// Modulate the button if disabled
Modulate = Disabled ? Color.Gray : Color.White;
}
protected override void StylePropertiesChanged()
{
base.StylePropertiesChanged();
UpdateAppearance();
}
protected override void DrawModeChanged()
{
base.DrawModeChanged();
UpdateAppearance();
}
}

View File

@@ -0,0 +1,24 @@
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.Controls;
/// <summary>
/// A check box intended for use with a monotone color palette
/// </summary>
public sealed class MonotoneCheckBox : CheckBox
{
public const string StyleClassMonotoneCheckBox = "monotoneCheckBox";
public MonotoneCheckBox()
{
TextureRect.AddStyleClass(StyleClassMonotoneCheckBox);
}
protected override void DrawModeChanged()
{
base.DrawModeChanged();
// Appearance modulations
Modulate = Disabled ? Color.Gray : Color.White;
}
}

View File

@@ -0,0 +1,6 @@
<Control xmlns="https://spacestation14.io">
<BoxContainer Orientation="Horizontal">
<Button Name="OffButton" StyleClasses="OpenRight" Text="{Loc 'ui-button-off'}" />
<Button Name="OnButton" StyleClasses="OpenLeft" Text="{Loc 'ui-button-on'}" />
</BoxContainer>
</Control>

View File

@@ -0,0 +1,48 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface.Controls;
/// <summary>
/// A simple control that displays a toggleable on/off button.
/// </summary>
[GenerateTypedNameReferences]
public sealed partial class OnOffButton : Control
{
/// <summary>
/// Whether the control is currently in the "on" state.
/// </summary>
public bool IsOn
{
get => OnButton.Pressed;
set
{
if (value)
OnButton.Pressed = true;
else
OffButton.Pressed = true;
}
}
/// <summary>
/// Raised when the user changes the state of the control.
/// </summary>
/// <remarks>
/// This does not get raised if state is changed with <see cref="set_IsOn"/>.
/// </remarks>
public event Action<bool>? StateChanged;
public OnOffButton()
{
RobustXamlLoader.Load(this);
var group = new ButtonGroup(isNoneSetAllowed: false);
OffButton.Group = group;
OnButton.Group = group;
OffButton.OnPressed += _ => StateChanged?.Invoke(false);
OnButton.OnPressed += _ => StateChanged?.Invoke(true);
}
}