PDA UI refactor and cartridges (#11335)

* Work on cartridges

* Work on PDA UI

* Work on PDA UIs program list

* Work on PDA UI borders

* Add DeviceNetworkingComponent to the pda base prototype

* Fix submodule version

* Fix cartridge loader ui key

* Fix pda menu xaml

* Implement relaying ui messages

* Finish implementing the notekeeper cartridge

* Fix submodule version

* Fix errors from merging master

* Fix test failing

* Implement setting preinstalled programs

* Add some documentation to CartridgeLoaderSystem

* Add more doc comments

* Add localization to program names

* Implement review suggestions

* Fix background programs receiving events twice when active
This commit is contained in:
Julian Giebel
2022-11-08 21:00:20 +01:00
committed by GitHub
parent 1151ca42e5
commit e11cf969fa
79 changed files with 2323 additions and 94 deletions

View File

@@ -0,0 +1,19 @@
namespace Content.Client.PDA;
/// <summary>
/// Used for specifying the pda windows border colors
/// </summary>
[RegisterComponent]
public sealed class PDABorderColorComponent : Component
{
[DataField("borderColor", required: true)]
public string? BorderColor;
[DataField("accentHColor")]
public string? AccentHColor;
[DataField("accentVColor")]
public string? AccentVColor;
}

View File

@@ -1,17 +1,20 @@
using Content.Client.Message;
using Content.Client.CartridgeLoader;
using Content.Shared.CartridgeLoader;
using Content.Shared.CCVar;
using Content.Shared.Containers.ItemSlots;
using Content.Shared.CrewManifest;
using Content.Shared.PDA;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
namespace Content.Client.PDA
{
[UsedImplicitly]
public sealed class PDABoundUserInterface : BoundUserInterface
public sealed class PDABoundUserInterface : CartridgeLoaderBoundUserInterface
{
[Dependency] private readonly IEntityManager? _entityManager = default!;
[Dependency] private readonly IConfigurationManager _configManager = default!;
private PDAMenu? _menu;
@@ -67,54 +70,52 @@ namespace Content.Client.PDA
SendMessage(new PDAShowRingtoneMessage());
};
_menu.OnProgramItemPressed += ActivateCartridge;
_menu.OnInstallButtonPressed += InstallCartridge;
_menu.OnUninstallButtonPressed += UninstallCartridge;
_menu.ProgramCloseButton.OnPressed += _ => DeactivateActiveCartridge();
var borderColorComponent = GetBorderColorComponent();
if (borderColorComponent == null)
return;
_menu.BorderColor = borderColorComponent.BorderColor;
_menu.AccentHColor = borderColorComponent.AccentHColor;
_menu.AccentVColor = borderColorComponent.AccentVColor;
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (_menu == null)
{
if (state is not PDAUpdateState updateState)
return;
}
switch (state)
{
case PDAUpdateState msg:
{
_menu.FlashLightToggleButton.Pressed = msg.FlashlightEnabled;
if (msg.PDAOwnerInfo.ActualOwnerName != null)
{
_menu.PdaOwnerLabel.SetMarkup(Loc.GetString("comp-pda-ui-owner",
("ActualOwnerName", msg.PDAOwnerInfo.ActualOwnerName)));
}
if (msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null)
{
_menu.IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui",
("Owner",msg.PDAOwnerInfo.IdOwner ?? Loc.GetString("comp-pda-ui-unknown")),
("JobTitle",msg.PDAOwnerInfo.JobTitle ?? Loc.GetString("comp-pda-ui-unassigned"))));
}
else
{
_menu.IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui-blank"));
}
_menu.StationNameLabel.SetMarkup(Loc.GetString("comp-pda-ui-station", ("Station",msg.StationName ?? Loc.GetString("comp-pda-ui-unknown"))));
_menu.EjectIdButton.Visible = msg.PDAOwnerInfo.IdOwner != null || msg.PDAOwnerInfo.JobTitle != null;
_menu.EjectPenButton.Visible = msg.HasPen;
_menu.ActivateUplinkButton.Visible = msg.HasUplink;
_menu.ActivateMusicButton.Visible = msg.CanPlayMusic;
break;
}
}
_menu?.UpdateState(updateState);
}
protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title)
{
_menu?.ProgramView.AddChild(cartridgeUIFragment);
_menu?.ToProgramView(title ?? Loc.GetString("comp-pda-io-program-fallback-title"));
}
protected override void DetachCartridgeUI(Control cartridgeUIFragment)
{
if (_menu is null)
return;
_menu.ToHomeScreen();
_menu.HideProgramHeader();
_menu.ProgramView.RemoveChild(cartridgeUIFragment);
}
protected override void UpdateAvailablePrograms(List<(EntityUid, CartridgeComponent)> programs)
{
_menu?.UpdateAvailablePrograms(programs);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
@@ -123,5 +124,10 @@ namespace Content.Client.PDA
_menu?.Dispose();
}
private PDABorderColorComponent? GetBorderColorComponent()
{
return _entityManager?.GetComponentOrNull<PDABorderColorComponent>(Owner.Owner);
}
}
}

View File

@@ -1,12 +1,32 @@
<DefaultWindow xmlns="https://spacestation14.io"
Title="{Loc 'comp-pda-ui-menu-title'}"
MinSize="576 256"
SetSize="576 256">
<TabContainer Name="MasterTabContainer">
<pda:PDAWindow xmlns="https://spacestation14.io"
xmlns:pda="clr-namespace:Content.Client.PDA"
xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"
MinSize="576 450"
SetSize="576 450">
<!-- This: (Margin="1 1 3 0") is necessary so the navigation bar doesn't sticks into the black content border. -->
<BoxContainer Name="NavigationBar" HorizontalExpand="True" MinHeight="32" Margin="1 1 3 0">
<pda:PDANavigationButton Name="HomeButton" SetWidth="32" CurrentTabBorderThickness="0 0 2 0" IsCurrent="True"/>
<pda:PDANavigationButton Name="ProgramListButton" Access="Public" MinWidth="100" LabelText="{Loc 'comp-pda-io-program-list-button'}"/>
<pda:PDANavigationButton Name="SettingsButton" MinWidth="100" LabelText="{Loc 'comp-pda-io-settings-button'}"/>
<pda:PDANavigationButton Name="ProgramTitle" Access="Public" BorderThickness="0 0 0 2" CurrentTabBorderThickness="2 0 0 2"
ActiveBgColor="#202023" Visible="False"/>
<pda:PDANavigationButton HorizontalExpand="True"/>
<pda:PDANavigationButton Name="ProgramCloseButton" Access="Public" IconScale="0.5 0.5" BorderThickness="0 0 2 2"
Visible="False" IsActive="False" SetWidth="32"/>
<pda:PDANavigationButton Name="FlashLightToggleButton" Access="Public" ToggleMode="True" ActiveFgColor="#EAEFBB" SetWidth="32"/>
<pda:PDANavigationButton Name="EjectPenButton" Access="Public" SetWidth="32"/>
<pda:PDANavigationButton Name="EjectIdButton" Access="Public" SetWidth="32"/>
</BoxContainer>
<BoxContainer Name="ViewContainer" HorizontalExpand="True" VerticalExpand="True" Access="Public">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
MinSize="50 50">
MinSize="50 50"
Margin="8">
<RichTextLabel Name="PdaOwnerLabel" Access="Public" />
<RichTextLabel Name="IdInfoLabel"
Access="Public"
@@ -16,37 +36,53 @@
<RichTextLabel Name="StationNameLabel"
Access="Public"
HorizontalExpand="True" />
<Button Name="EjectIdButton"
Access="Public"
Text="{Loc 'comp-pda-ui-eject-id-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Name="EjectPenButton"
Access="Public"
Text="{Loc 'comp-pda-ui-eject-pen-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
<Button Name="AccessRingtoneButton"
Access="Public"
Text="{Loc 'comp-pda-ui-ringtone-button'}"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
</BoxContainer>
</PanelContainer>
<Button Name="FlashLightToggleButton"
Access="Public"
Text="{Loc 'comp-pda-ui-toggle-flashlight-button'}"
ToggleMode="True" />
<Button Name="CrewManifestButton"
Access="Public"
Text="{Loc 'crew-manifest-button-label'}"
Visible="False" />
<Button Name="ActivateUplinkButton"
Access="Public"
Text="{Loc 'pda-bound-user-interface-uplink-tab-title'}" />
<Button Name="ActivateMusicButton"
Access="Public"
Text="{Loc 'pda-bound-user-interface-music-button'}" />
</BoxContainer>
</TabContainer>
</DefaultWindow>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
MinSize="50 50"
Name="ProgramList"
Margin="4"/>
</ScrollContainer>
<ScrollContainer HorizontalExpand="True" VerticalExpand="True" HScrollEnabled="True">
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
MinSize="50 50"
Name="Settings">
<pda:PDASettingsButton Name="AccessRingtoneButton"
Access="Public"
Text="{Loc 'comp-pda-ui-ringtone-button'}"
Description="{Loc 'comp-pda-ui-ringtone-button-description'}"/>
<pda:PDASettingsButton Name="CrewManifestButton"
Access="Public"
Text="{Loc 'crew-manifest-button-label'}"
Description="{Loc 'crew-manifest-button-description'}"
Visible="False" />
<pda:PDASettingsButton Name="ActivateUplinkButton"
Access="Public"
Text="{Loc 'pda-bound-user-interface-uplink-tab-title'}"
Description="{Loc 'pda-bound-user-interface-uplink-tab-description'}"/>
<pda:PDASettingsButton Name="ActivateMusicButton"
Access="Public"
Text="{Loc 'pda-bound-user-interface-music-button'}"
Description="{Loc 'pda-bound-user-interface-music-button-description'}"/>
</BoxContainer>
</ScrollContainer>
<BoxContainer Orientation="Vertical"
VerticalExpand="True"
HorizontalExpand="True"
Name="ProgramView"
Access="Public">
</BoxContainer>
</BoxContainer>
<BoxContainer Name="ContentFooter" HorizontalExpand="True" SetHeight="28" Margin="1 0 2 1">
<controls:StripeBack HasBottomEdge="False" HasMargins="False" HorizontalExpand="True">
<Label Text="Robust#OS ™" VerticalAlignment="Center" Margin="6 0" StyleClasses="PDAContentFooterText"/>
<Label Name="AddressLabel" VerticalAlignment="Center" HorizontalAlignment="Right" Margin="6 0" StyleClasses="PDAContentFooterText"/>
</controls:StripeBack>
</BoxContainer>
</pda:PDAWindow>

View File

@@ -1,18 +1,252 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Content.Client.Message;
using Content.Shared.CartridgeLoader;
using Content.Shared.PDA;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Localization;
using Robust.Shared.Utility;
namespace Content.Client.PDA
{
[GenerateTypedNameReferences]
public sealed partial class PDAMenu : DefaultWindow
public sealed partial class PDAMenu : PDAWindow
{
public const int HomeView = 0;
public const int ProgramListView = 1;
public const int SettingsView = 2;
public const int ProgramContentView = 3;
private int _currentView = 0;
public event Action<EntityUid>? OnProgramItemPressed;
public event Action<EntityUid>? OnUninstallButtonPressed;
public event Action<EntityUid>? OnInstallButtonPressed;
public PDAMenu()
{
RobustXamlLoader.Load(this);
MasterTabContainer.SetTabTitle(0, Loc.GetString("pda-bound-user-interface-main-menu-tab-title"));
ViewContainer.OnChildAdded += control => control.Visible = false;
HomeButton.IconTexture = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/home.png"));
FlashLightToggleButton.IconTexture = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/light.png"));
EjectPenButton.IconTexture = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/pencil.png"));
EjectIdButton.IconTexture = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/eject.png"));
ProgramCloseButton.IconTexture = new SpriteSpecifier.Texture(new ResourcePath("/Textures/Interface/Nano/cross.svg.png"));
HomeButton.OnPressed += _ => ToHomeScreen();
ProgramListButton.OnPressed += _ =>
{
HomeButton.IsCurrent = false;
ProgramListButton.IsCurrent = true;
SettingsButton.IsCurrent = false;
ProgramTitle.IsCurrent = false;
ChangeView(ProgramListView);
};
SettingsButton.OnPressed += _ =>
{
HomeButton.IsCurrent = false;
ProgramListButton.IsCurrent = false;
SettingsButton.IsCurrent = true;
ProgramTitle.IsCurrent = false;
ChangeView(SettingsView);
};
ProgramTitle.OnPressed += _ =>
{
HomeButton.IsCurrent = false;
ProgramListButton.IsCurrent = false;
SettingsButton.IsCurrent = false;
ProgramTitle.IsCurrent = true;
ChangeView(ProgramContentView);
};
ProgramCloseButton.OnPressed += _ =>
{
HideProgramHeader();
ToHomeScreen();
};
HideAllViews();
ToHomeScreen();
}
public void UpdateState(PDAUpdateState state)
{
FlashLightToggleButton.IsActive = state.FlashlightEnabled;
if (state.PDAOwnerInfo.ActualOwnerName != null)
{
PdaOwnerLabel.SetMarkup(Loc.GetString("comp-pda-ui-owner",
("ActualOwnerName", state.PDAOwnerInfo.ActualOwnerName)));
}
if (state.PDAOwnerInfo.IdOwner != null || state.PDAOwnerInfo.JobTitle != null)
{
IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui",
("Owner",state.PDAOwnerInfo.IdOwner ?? Loc.GetString("comp-pda-ui-unknown")),
("JobTitle",state.PDAOwnerInfo.JobTitle ?? Loc.GetString("comp-pda-ui-unassigned"))));
}
else
{
IdInfoLabel.SetMarkup(Loc.GetString("comp-pda-ui-blank"));
}
StationNameLabel.SetMarkup(Loc.GetString("comp-pda-ui-station", ("Station",state.StationName ?? Loc.GetString("comp-pda-ui-unknown"))));
AddressLabel.Text = state.Address?.ToUpper() ?? " - ";
EjectIdButton.IsActive = state.PDAOwnerInfo.IdOwner != null || state.PDAOwnerInfo.JobTitle != null;
EjectPenButton.IsActive = state.HasPen;
ActivateUplinkButton.Visible = state.HasUplink;
ActivateMusicButton.Visible = state.CanPlayMusic;
}
public void UpdateAvailablePrograms(List<(EntityUid, CartridgeComponent)> programs)
{
ProgramList.RemoveAllChildren();
if (programs.Count == 0)
{
ProgramList.AddChild(new Label()
{
Text = Loc.GetString("comp-pda-io-no-programs-available"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
VerticalExpand = true
});
return;
}
var row = CreateProgramListRow();
var itemCount = 1;
ProgramList.AddChild(row);
foreach (var (uid, component) in programs)
{
//Create a new row every second program item starting from the first
if (itemCount % 2 != 0)
{
row = CreateProgramListRow();
ProgramList.AddChild(row);
}
var item = new PDAProgramItem();
if (component.Icon is not null)
item.Icon.SetFromSpriteSpecifier(component.Icon);
item.OnPressed += _ => OnProgramItemPressed?.Invoke(uid);
switch (component.InstallationStatus)
{
case InstallationStatus.Cartridge:
item.InstallButton.Visible = true;
item.InstallButton.Text = Loc.GetString("cartridge-bound-user-interface-install-button");
item.InstallButton.OnPressed += _ => OnInstallButtonPressed?.Invoke(uid);
break;
case InstallationStatus.Installed:
item.InstallButton.Visible = true;
item.InstallButton.Text = Loc.GetString("cartridge-bound-user-interface-uninstall-button");
item.InstallButton.OnPressed += _ => OnUninstallButtonPressed?.Invoke(uid);
break;
}
item.ProgramName.Text = Loc.GetString(component.ProgramName);
item.SetHeight = 20;
row.AddChild(item);
itemCount++;
}
//Add a filler item to the last row when it only contains one item
if (itemCount % 2 == 0)
row.AddChild(new Control() { HorizontalExpand = true });
}
/// <summary>
/// Changes the current view to the home screen (view 0) and sets the tabs `IsCurrent` flag accordingly
/// </summary>
public void ToHomeScreen()
{
HomeButton.IsCurrent = true;
ProgramListButton.IsCurrent = false;
SettingsButton.IsCurrent = false;
ProgramTitle.IsCurrent = false;
ChangeView(HomeView);
}
/// <summary>
/// Hides the program title and close button.
/// </summary>
public void HideProgramHeader()
{
ProgramTitle.IsCurrent = false;
ProgramTitle.Visible = false;
ProgramCloseButton.Visible = false;
ProgramListButton.Visible = true;
SettingsButton.Visible = true;
}
/// <summary>
/// Changes the current view to the program content view (view 3), sets the program title and sets the tabs `IsCurrent` flag accordingly
/// </summary>
public void ToProgramView(string title)
{
HomeButton.IsCurrent = false;
ProgramListButton.IsCurrent = false;
SettingsButton.IsCurrent = false;
ProgramTitle.IsCurrent = false;
ProgramTitle.IsCurrent = true;
ProgramTitle.Visible = true;
ProgramCloseButton.Visible = true;
ProgramListButton.Visible = false;
SettingsButton.Visible = false;
ProgramTitle.LabelText = title;
ChangeView(ProgramContentView);
}
/// <summary>
/// Changes the current view to the given view number
/// </summary>
public void ChangeView(int view)
{
if (ViewContainer.ChildCount <= view)
return;
ViewContainer.GetChild(_currentView).Visible = false;
ViewContainer.GetChild(view).Visible = true;
_currentView = view;
}
private BoxContainer CreateProgramListRow()
{
return new BoxContainer()
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true
};
}
private void HideAllViews()
{
var views = ViewContainer.Children;
foreach (var view in views)
{
view.Visible = false;
}
}
}
}

View File

@@ -0,0 +1,5 @@
<pda:PDANavigationButton xmlns="https://spacestation14.io" xmlns:pda="clr-namespace:Content.Client.PDA">
<PanelContainer Name="Background"/>
<AnimatedTextureRect Margin="0 0 0 2" Visible="False" Name="Icon" HorizontalAlignment="Center" VerticalAlignment="Center"/>
<Label Visible="True" Name="Label" Margin="8 0 8 2" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</pda:PDANavigationButton>

View File

@@ -0,0 +1,108 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Utility;
namespace Content.Client.PDA;
[GenerateTypedNameReferences]
public sealed partial class PDANavigationButton : ContainerButton
{
private bool _isCurrent;
private bool _isActive = true;
private Thickness _borderThickness = new(0, 0, 0, 2);
private Thickness _currentTabBorderThickness = new(2, 0, 2, 0);
private readonly StyleBoxFlat _styleBox = new()
{
BackgroundColor = Color.FromHex("#202023"),
BorderColor = Color.FromHex("#5a5a5a"),
BorderThickness = new Thickness(0, 0, 0, 2)
};
public string InactiveBgColor { get; set; } = "#202023";
public string ActiveBgColor { get; set; } = "#25252a";
public string InactiveFgColor { get; set; } = "#5a5a5a";
public string ActiveFgColor { get; set; } = "#FFFFFF";
public SpriteSpecifier? IconTexture
{
set
{
Icon.Visible = value != null;
Label.Visible = value == null;
if (value is not null)
Icon.SetFromSpriteSpecifier(value);
}
}
public Vector2 IconScale
{
get => Icon.DisplayRect.TextureScale;
set => Icon.DisplayRect.TextureScale = value;
}
public string? LabelText
{
get => Label.Text;
set => Label.Text = value;
}
/// <summary>
/// Sets the border thickness when the tab is not the currently active one
/// </summary>
public Thickness BorderThickness
{
get => _borderThickness;
set
{
_borderThickness = value;
_styleBox.BorderThickness = _isCurrent ? _currentTabBorderThickness : value;
}
}
/// <summary>
/// Sets the border thickness when this tab is the currently active tab
/// </summary>
public Thickness CurrentTabBorderThickness
{
get => _currentTabBorderThickness;
set
{
_currentTabBorderThickness = value;
_styleBox.BorderThickness = _isCurrent ? value : _borderThickness;
}
}
public bool IsCurrent
{
get => _isCurrent;
set
{
_isCurrent = value;
_styleBox.BackgroundColor = Color.FromHex(value ? ActiveBgColor : InactiveBgColor);
_styleBox.BorderThickness = value ? CurrentTabBorderThickness : BorderThickness;
}
}
public bool IsActive
{
get => _isActive;
set
{
_isActive = value;
Icon.Modulate = Color.FromHex(value ? ActiveFgColor : InactiveFgColor);
Label.FontColorOverride = Color.FromHex(value ? ActiveFgColor : InactiveFgColor);
}
}
public PDANavigationButton()
{
RobustXamlLoader.Load(this);
Background.PanelOverride = _styleBox;
}
}

View File

@@ -0,0 +1,17 @@
<pda:PDAProgramItem HorizontalExpand="True" MinHeight="60" Margin="4"
xmlns:pda="clr-namespace:Content.Client.PDA"
xmlns="https://spacestation14.io">
<PanelContainer Name="Panel"/>
<BoxContainer Orientation="Horizontal" HorizontalExpand="True" VerticalExpand="True">
<BoxContainer Orientation="Vertical" VerticalExpand="True" MinWidth="60">
<AnimatedTextureRect HorizontalAlignment="Center" VerticalAlignment="Center" VerticalExpand="True" Name="Icon" Access="Public"/>
</BoxContainer>
<BoxContainer Orientation="Vertical" VerticalExpand="True" HorizontalExpand="True">
<Label Name="ProgramName" Access="Public" VerticalExpand="True"/>
<BoxContainer HorizontalExpand="True" SetHeight="28" Margin="0 0 4 4">
<BoxContainer HorizontalExpand="True"/>
<Button Name="InstallButton" Access="Public" Visible="False" SetWidth="90" HorizontalAlignment="Right" VerticalExpand="True"></Button>
</BoxContainer>
</BoxContainer>
</BoxContainer>
</pda:PDAProgramItem>

View File

@@ -0,0 +1,42 @@
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.Input;
namespace Content.Client.PDA;
[GenerateTypedNameReferences]
public sealed partial class PDAProgramItem : ContainerButton
{
public const string StylePropertyBgColor = "backgroundColor";
public const string NormalBgColor = "#313138";
public const string HoverColor = "#3E6C45";
private readonly StyleBoxFlat _styleBox = new()
{
BackgroundColor = Color.FromHex("#25252a"),
};
public Color BackgroundColor
{
get => _styleBox.BackgroundColor;
set => _styleBox.BackgroundColor = value;
}
public PDAProgramItem()
{
RobustXamlLoader.Load(this);
Panel.PanelOverride = _styleBox;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (TryGetStyleProperty<Color>(StylePropertyBgColor, out var bgColor))
BackgroundColor = bgColor;
}
}

View File

@@ -0,0 +1,11 @@
<pda:PDASettingsButton xmlns="https://spacestation14.io"
xmlns:pda="clr-namespace:Content.Client.PDA"
HorizontalExpand="True"
MinHeight="48"
Margin="5 4 6 0">
<PanelContainer Name="Panel"/>
<BoxContainer Orientation="Vertical" HorizontalExpand="True" VerticalExpand="True" Margin="8 4 0 4">
<Label Name="OptionName"/>
<Label Name="OptionDescription"/>
</BoxContainer>
</pda:PDASettingsButton>

View File

@@ -0,0 +1,69 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.PDA;
[GenerateTypedNameReferences]
public sealed partial class PDASettingsButton : ContainerButton
{
public const string StylePropertyFgColor = "foregroundColor";
public const string StylePropertyBgColor = "backgroundColor";
public const string NormalBgColor = "#313138";
public const string HoverColor = "#3E6C45";
public const string PressedColor = "#3E6C45";
public const string DisabledFgColor = "#5a5a5a";
public const string EnabledFgColor = "#FFFFFF";
private readonly StyleBoxFlat _styleBox = new()
{
BackgroundColor = Color.FromHex("#25252a")
};
public string? Text
{
get => OptionName.Text;
set => OptionName.Text = value;
}
public string? Description
{
get => OptionDescription.Text;
set => OptionDescription.Text = value;
}
public Color BackgroundColor
{
get => _styleBox.BackgroundColor;
set => _styleBox.BackgroundColor = value;
}
public Color? ForegroundColor
{
get => OptionName.FontColorOverride;
set
{
OptionName.FontColorOverride = value;
OptionDescription.FontColorOverride = value;
}
}
public PDASettingsButton()
{
RobustXamlLoader.Load(this);
Panel.PanelOverride = _styleBox;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (TryGetStyleProperty<Color>(StylePropertyBgColor, out var bgColor))
BackgroundColor = bgColor;
if (TryGetStyleProperty<Color>(StylePropertyFgColor, out var fgColor))
ForegroundColor = fgColor;
}
}

View File

@@ -0,0 +1,31 @@
<pda:PDAWindow xmlns="https://spacestation14.io"
xmlns:pda="clr-namespace:Content.Client.PDA"
MouseFilter="Stop">
<PanelContainer Name="Background" Access="Public" StyleClasses="PDABackgroundRect" />
<!-- The negative markin fixes a gap between the window edges and the decorative panel -->
<PanelContainer Name="AccentH" Margin="-1 170 -2 170" Access="Public" StyleClasses="PDABackground" />
<PanelContainer Name="AccentV" Margin="220 -1 220 -1" Access="Public" StyleClasses="PDABackground" />
<PanelContainer Name="Border" StyleClasses="PDABorderRect" />
<BoxContainer Orientation="Vertical" HorizontalExpand="True">
<!--Heading-->
<BoxContainer SetHeight="26" Margin="4 2 8 0" Orientation="Horizontal">
<Control HorizontalExpand="True"/>
<TextureButton Name="CloseButton" StyleClasses="windowCloseButton"
VerticalAlignment="Center" Margin="0 4 4 0"/>
</BoxContainer>
<!--Content-->
<Control Margin="18 0" RectClipContent="True" VerticalExpand="true"
HorizontalExpand="True">
<PanelContainer Name="ContentBorder" StyleClasses="PDABackground"/>
<Control Margin="3 3">
<PanelContainer Name="ContentBackground" StyleClasses="PDAContentBackground"/>
<BoxContainer Access="Public" Name="ContentsContainer" Orientation="Vertical" StyleClasses="PDAContent"/>
</Control>
</Control>
<!--Footer-->
<BoxContainer Orientation="Horizontal" SetHeight="28">
<Label Text="Personal Digital Assistant" StyleClasses="PDAWindowFooterText" Margin="32 0 0 6"/>
</BoxContainer>
</BoxContainer>
</pda:PDAWindow>

View File

@@ -0,0 +1,56 @@
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.PDA;
[Virtual]
[GenerateTypedNameReferences]
public partial class PDAWindow : BaseWindow
{
public string? BorderColor
{
get => Background.ActualModulateSelf.ToHex();
set => Background.ModulateSelfOverride = Color.FromHex(value, Color.White);
}
public string? AccentHColor
{
get => AccentH.ActualModulateSelf.ToHex();
set
{
AccentH.ModulateSelfOverride = Color. FromHex(value, Color.White);
AccentH.Visible = value != null;
}
}
public string? AccentVColor
{
get => AccentV.ActualModulateSelf.ToHex();
set
{
AccentV.ModulateSelfOverride = Color. FromHex(value, Color.White);
AccentV.Visible = value != null;
}
}
public PDAWindow()
{
RobustXamlLoader.Load(this);
CloseButton.OnPressed += _ => Close();
XamlChildren = ContentsContainer.Children;
AccentH.Visible = false;
AccentV.Visible = false;
}
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{
return DragMode.Move;
}
}