Re-organize all projects (#4166)

This commit is contained in:
DrSmugleaf
2021-06-09 22:19:39 +02:00
committed by GitHub
parent 9f50e4061b
commit ff1a2d97ea
1773 changed files with 5258 additions and 5508 deletions

View File

@@ -1,96 +0,0 @@
using System;
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface
{
/// <summary>
/// Tooltip for actions or alerts because they are very similar.
/// </summary>
public class ActionAlertTooltip : PanelContainer
{
private const float TooltipTextMaxWidth = 350;
private readonly RichTextLabel _cooldownLabel;
private readonly IGameTiming _gameTiming;
/// <summary>
/// Current cooldown displayed in this tooltip. Set to null to show no cooldown.
/// </summary>
public (TimeSpan Start, TimeSpan End)? Cooldown { get; set; }
public ActionAlertTooltip(FormattedMessage name, FormattedMessage? desc, string? requires = null)
{
_gameTiming = IoCManager.Resolve<IGameTiming>();
SetOnlyStyleClass(StyleNano.StyleClassTooltipPanel);
VBoxContainer vbox;
AddChild(vbox = new VBoxContainer {RectClipContent = true});
var nameLabel = new RichTextLabel
{
MaxWidth = TooltipTextMaxWidth,
StyleClasses = {StyleNano.StyleClassTooltipActionTitle}
};
nameLabel.SetMessage(name);
vbox.AddChild(nameLabel);
if (desc != null && !string.IsNullOrWhiteSpace(desc.ToString()))
{
var description = new RichTextLabel
{
MaxWidth = TooltipTextMaxWidth,
StyleClasses = {StyleNano.StyleClassTooltipActionDescription}
};
description.SetMessage(desc);
vbox.AddChild(description);
}
vbox.AddChild(_cooldownLabel = new RichTextLabel
{
MaxWidth = TooltipTextMaxWidth,
StyleClasses = {StyleNano.StyleClassTooltipActionCooldown},
Visible = false
});
if (!string.IsNullOrWhiteSpace(requires))
{
var requiresLabel = new RichTextLabel
{
MaxWidth = TooltipTextMaxWidth,
StyleClasses = {StyleNano.StyleClassTooltipActionRequirements}
};
requiresLabel.SetMessage(FormattedMessage.FromMarkup("[color=#635c5c]" +
requires +
"[/color]"));
vbox.AddChild(requiresLabel);
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!Cooldown.HasValue)
{
_cooldownLabel.Visible = false;
return;
}
var timeLeft = Cooldown.Value.End - _gameTiming.CurTime;
if (timeLeft > TimeSpan.Zero)
{
var duration = Cooldown.Value.End - Cooldown.Value.Start;
_cooldownLabel.SetMessage(FormattedMessage.FromMarkup(
$"[color=#a10505]{duration.Seconds} sec cooldown ({timeLeft.Seconds + 1} sec remaining)[/color]"));
_cooldownLabel.Visible = true;
}
else
{
_cooldownLabel.Visible = false;
}
}
}
}

View File

@@ -1,517 +0,0 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.GameObjects.Components.Mobs.Actions;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.Actions;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Timing;
using static Robust.Client.UserInterface.Controls.BaseButton;
namespace Content.Client.UserInterface
{
/// <summary>
/// Action selection menu, allows filtering and searching over all possible
/// actions and populating those actions into the hotbar.
/// </summary>
public class ActionMenu : SS14Window
{
private const string ItemTag = "item";
private const string NotItemTag = "not item";
private const string InstantActionTag = "instant";
private const string ToggleActionTag = "toggle";
private const string TargetActionTag = "target";
private const string AllActionsTag = "all";
private const string GrantedActionsTag = "granted";
private const int MinSearchLength = 3;
private static readonly Regex NonAlphanumeric = new Regex(@"\W", RegexOptions.Compiled);
private static readonly Regex Whitespace = new Regex(@"\s+", RegexOptions.Compiled);
private static readonly BaseActionPrototype[] EmptyActionList = Array.Empty<BaseActionPrototype>();
/// <summary>
/// Is an action currently being dragged from this window?
/// </summary>
public bool IsDragging => _dragDropHelper.IsDragging;
// parallel list of actions currently selectable in itemList
private BaseActionPrototype[] _actionList = new BaseActionPrototype[0];
private readonly ActionManager _actionManager;
private readonly ClientActionsComponent _actionsComponent;
private readonly ActionsUI _actionsUI;
private readonly LineEdit _searchBar;
private readonly MultiselectOptionButton<string> _filterButton;
private readonly Label _filterLabel;
private readonly Button _clearButton;
private readonly GridContainer _resultsGrid;
private readonly TextureRect _dragShadow;
private readonly IGameHud _gameHud;
private readonly DragDropHelper<ActionMenuItem> _dragDropHelper;
public ActionMenu(ClientActionsComponent actionsComponent, ActionsUI actionsUI)
{
_actionsComponent = actionsComponent;
_actionsUI = actionsUI;
_actionManager = IoCManager.Resolve<ActionManager>();
_gameHud = IoCManager.Resolve<IGameHud>();
Title = Loc.GetString("Actions");
MinSize = (300, 300);
Contents.AddChild(new VBoxContainer
{
Children =
{
new HBoxContainer
{
Children =
{
(_searchBar = new LineEdit
{
StyleClasses = { StyleNano.StyleClassActionSearchBox },
HorizontalExpand = true,
PlaceHolder = Loc.GetString("Search")
}),
(_filterButton = new MultiselectOptionButton<string>()
{
Label = Loc.GetString("Filter")
})
}
},
(_clearButton = new Button
{
Text = Loc.GetString("Clear"),
}),
(_filterLabel = new Label()),
new ScrollContainer
{
//TODO: needed? MinSize = new Vector2(200.0f, 0.0f),
VerticalExpand = true,
HorizontalExpand = true,
Children =
{
(_resultsGrid = new GridContainer
{
MaxGridWidth = 300
})
}
}
}
});
// populate filters from search tags
var filterTags = new List<string>();
foreach (var action in _actionManager.EnumerateActions())
{
filterTags.AddRange(action.Filters);
}
// special one to filter to only include item actions
filterTags.Add(ItemTag);
filterTags.Add(NotItemTag);
filterTags.Add(InstantActionTag);
filterTags.Add(ToggleActionTag);
filterTags.Add(TargetActionTag);
filterTags.Add(AllActionsTag);
filterTags.Add(GrantedActionsTag);
foreach (var tag in filterTags.Distinct().OrderBy(tag => tag))
{
_filterButton.AddItem( CultureInfo.CurrentCulture.TextInfo.ToTitleCase(tag), tag);
}
UpdateFilterLabel();
_dragShadow = new TextureRect
{
MinSize = (64, 64),
Stretch = TextureRect.StretchMode.Scale,
Visible = false,
SetSize = (64, 64)
};
UserInterfaceManager.PopupRoot.AddChild(_dragShadow);
_dragDropHelper = new DragDropHelper<ActionMenuItem>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag);
}
protected override void EnteredTree()
{
base.EnteredTree();
_clearButton.OnPressed += OnClearButtonPressed;
_searchBar.OnTextChanged += OnSearchTextChanged;
_filterButton.OnItemSelected += OnFilterItemSelected;
_gameHud.ActionsButtonDown = true;
foreach (var actionMenuControl in _resultsGrid.Children)
{
var actionMenuItem = (ActionMenuItem) actionMenuControl;
actionMenuItem.OnButtonDown += OnItemButtonDown;
actionMenuItem.OnButtonUp += OnItemButtonUp;
actionMenuItem.OnPressed += OnItemPressed;
}
}
protected override void ExitedTree()
{
base.ExitedTree();
_dragDropHelper.EndDrag();
_clearButton.OnPressed -= OnClearButtonPressed;
_searchBar.OnTextChanged -= OnSearchTextChanged;
_filterButton.OnItemSelected -= OnFilterItemSelected;
_gameHud.ActionsButtonDown = false;
foreach (var actionMenuControl in _resultsGrid.Children)
{
var actionMenuItem = (ActionMenuItem) actionMenuControl;
actionMenuItem.OnButtonDown -= OnItemButtonDown;
actionMenuItem.OnButtonUp -= OnItemButtonUp;
actionMenuItem.OnPressed -= OnItemPressed;
}
}
private void OnFilterItemSelected(MultiselectOptionButton<string>.ItemPressedEventArgs args)
{
UpdateFilterLabel();
SearchAndDisplay();
}
protected override void Resized()
{
base.Resized();
// TODO: Can rework this once https://github.com/space-wizards/RobustToolbox/issues/1392 is done,
// currently no good way to let the grid know what size it has to "work with", so must manually resize
_resultsGrid.MaxGridWidth = Width;
}
private bool OnBeginActionDrag()
{
_dragShadow.Texture = _dragDropHelper.Dragged!.Action.Icon.Frame0();
// don't make visible until frameupdate, otherwise it'll flicker
LayoutContainer.SetPosition(_dragShadow, UserInterfaceManager.MousePositionScaled.Position - (32, 32));
return true;
}
private bool OnContinueActionDrag(float frameTime)
{
// keep dragged entity centered under mouse
LayoutContainer.SetPosition(_dragShadow, UserInterfaceManager.MousePositionScaled.Position - (32, 32));
// we don't set this visible until frameupdate, otherwise it flickers
_dragShadow.Visible = true;
return true;
}
private void OnEndActionDrag()
{
_dragShadow.Visible = false;
}
private void OnItemButtonDown(ButtonEventArgs args)
{
if (args.Event.Function != EngineKeyFunctions.UIClick ||
args.Button is not ActionMenuItem action)
{
return;
}
_dragDropHelper.MouseDown(action);
}
private void OnItemButtonUp(ButtonEventArgs args)
{
// note the buttonup only fires on the control that was originally
// pressed to initiate the drag, NOT the one we are currently hovering
if (args.Event.Function != EngineKeyFunctions.UIClick) return;
if (UserInterfaceManager.CurrentlyHovered is ActionSlot targetSlot)
{
if (!_dragDropHelper.IsDragging || _dragDropHelper.Dragged?.Action == null)
{
_dragDropHelper.EndDrag();
return;
}
// drag and drop
switch (_dragDropHelper.Dragged.Action)
{
// assign the dragged action to the target slot
case ActionPrototype actionPrototype:
_actionsComponent.Assignments.AssignSlot(_actionsUI.SelectedHotbar, targetSlot.SlotIndex, ActionAssignment.For(actionPrototype.ActionType));
break;
case ItemActionPrototype itemActionPrototype:
// the action menu doesn't show us if the action has an associated item,
// so when we perform the assignment, we should check if we currently have an unassigned state
// for this item and assign it tied to that item if so, otherwise assign it "itemless"
// this is not particularly efficient but we don't maintain an index from
// item action type to its action states, and this method should be pretty infrequent so it's probably fine
var assigned = false;
foreach (var (item, itemStates) in _actionsComponent.ItemActionStates())
{
foreach (var (actionType, _) in itemStates)
{
if (actionType != itemActionPrototype.ActionType) continue;
var assignment = ActionAssignment.For(actionType, item);
if (_actionsComponent.Assignments.HasAssignment(assignment)) continue;
// no assignment for this state, assign tied to the item
assigned = true;
_actionsComponent.Assignments.AssignSlot(_actionsUI.SelectedHotbar, targetSlot.SlotIndex, assignment);
break;
}
if (assigned)
{
break;
}
}
if (!assigned)
{
_actionsComponent.Assignments.AssignSlot(_actionsUI.SelectedHotbar, targetSlot.SlotIndex, ActionAssignment.For(itemActionPrototype.ActionType));
}
break;
}
_actionsUI.UpdateUI();
}
_dragDropHelper.EndDrag();
}
private void OnItemFocusExited(ActionMenuItem item)
{
// lost focus, cancel the drag if one is in progress
_dragDropHelper.EndDrag();
}
private void OnItemPressed(ButtonEventArgs args)
{
if (args.Button is not ActionMenuItem actionMenuItem) return;
switch (actionMenuItem.Action)
{
case ActionPrototype actionPrototype:
_actionsComponent.Assignments.AutoPopulate(ActionAssignment.For(actionPrototype.ActionType), _actionsUI.SelectedHotbar);
break;
case ItemActionPrototype itemActionPrototype:
_actionsComponent.Assignments.AutoPopulate(ActionAssignment.For(itemActionPrototype.ActionType), _actionsUI.SelectedHotbar);
break;
default:
Logger.ErrorS("action", "unexpected action prototype {0}", actionMenuItem.Action);
break;
}
_actionsUI.UpdateUI();
}
private void OnClearButtonPressed(ButtonEventArgs args)
{
_searchBar.Clear();
_filterButton.DeselectAll();
UpdateFilterLabel();
SearchAndDisplay();
}
private void OnSearchTextChanged(LineEdit.LineEditEventArgs obj)
{
SearchAndDisplay();
}
private void SearchAndDisplay()
{
var search = Standardize(_searchBar.Text);
// only display nothing if there are no filters selected and text is not long enough.
// otherwise we will search if even one filter is applied, regardless of length of search string
if (_filterButton.SelectedKeys.Count == 0 &&
(string.IsNullOrWhiteSpace(search) || search.Length < MinSearchLength))
{
ClearList();
return;
}
var matchingActions = _actionManager.EnumerateActions()
.Where(a => MatchesSearchCriteria(a, search, _filterButton.SelectedKeys));
PopulateActions(matchingActions);
}
private void UpdateFilterLabel()
{
if (_filterButton.SelectedKeys.Count == 0)
{
_filterLabel.Visible = false;
}
else
{
_filterLabel.Visible = true;
_filterLabel.Text = Loc.GetString("Filters: {0}", string.Join(", ", _filterButton.SelectedLabels));
}
}
private bool MatchesSearchCriteria(BaseActionPrototype action, string standardizedSearch,
IReadOnlyList<string> selectedFilterTags)
{
// check filter tag match first - each action must contain all filter tags currently selected.
// if no tags selected, don't check tags
if (selectedFilterTags.Count > 0 && selectedFilterTags.Any(filterTag => !ActionMatchesFilterTag(action, filterTag)))
{
return false;
}
// check search tag match against the search query
if (action.Keywords.Any(standardizedSearch.Contains))
{
return true;
}
if (Standardize(ActionTypeString(action)).Contains(standardizedSearch))
{
return true;
}
// allows matching by typing spaces between the enum case changes, like "xeno spit" if the
// actiontype is "XenoSpit"
if (Standardize(ActionTypeString(action), true).Contains(standardizedSearch))
{
return true;
}
if (Standardize(action.Name.ToString()).Contains(standardizedSearch))
{
return true;
}
return false;
}
private string ActionTypeString(BaseActionPrototype baseActionPrototype)
{
if (baseActionPrototype is ActionPrototype actionPrototype)
{
return actionPrototype.ActionType.ToString();
}
if (baseActionPrototype is ItemActionPrototype itemActionPrototype)
{
return itemActionPrototype.ActionType.ToString();
}
throw new InvalidOperationException();
}
private bool ActionMatchesFilterTag(BaseActionPrototype action, string tag)
{
return tag switch
{
AllActionsTag => true,
GrantedActionsTag => _actionsComponent.IsGranted(action),
ItemTag => action is ItemActionPrototype,
NotItemTag => action is ActionPrototype,
InstantActionTag => action.BehaviorType == BehaviorType.Instant,
TargetActionTag => action.IsTargetAction,
ToggleActionTag => action.BehaviorType == BehaviorType.Toggle,
_ => action.Filters.Contains(tag)
};
}
/// <summary>
/// Standardized form is all lowercase, no non-alphanumeric characters (converted to whitespace),
/// trimmed, 1 space max per whitespace gap,
/// and optional spaces between case change
/// </summary>
private static string Standardize(string rawText, bool splitOnCaseChange = false)
{
rawText ??= "";
// treat non-alphanumeric characters as whitespace
rawText = NonAlphanumeric.Replace(rawText, " ");
// trim spaces and reduce internal whitespaces to 1 max
rawText = Whitespace.Replace(rawText, " ").Trim();
if (splitOnCaseChange)
{
// insert a space when case switches from lower to upper
rawText = AddSpaces(rawText, true);
}
return rawText.ToLowerInvariant().Trim();
}
// taken from https://stackoverflow.com/a/272929 (CC BY-SA 3.0)
private static string AddSpaces(string text, bool preserveAcronyms)
{
if (string.IsNullOrWhiteSpace(text))
return string.Empty;
var newText = new StringBuilder(text.Length * 2);
newText.Append(text[0]);
for (var i = 1; i < text.Length; i++)
{
if (char.IsUpper(text[i]))
{
if ((text[i - 1] != ' ' && !char.IsUpper(text[i - 1])) ||
(preserveAcronyms && char.IsUpper(text[i - 1]) &&
i < text.Length - 1 && !char.IsUpper(text[i + 1])))
newText.Append(' ');
}
newText.Append(text[i]);
}
return newText.ToString();
}
private void PopulateActions(IEnumerable<BaseActionPrototype> actions)
{
ClearList();
_actionList = actions.ToArray();
foreach (var action in _actionList.OrderBy(act => act.Name.ToString()))
{
var actionItem = new ActionMenuItem(action, OnItemFocusExited);
_resultsGrid.Children.Add(actionItem);
actionItem.SetActionState(_actionsComponent.IsGranted(action));
actionItem.OnButtonDown += OnItemButtonDown;
actionItem.OnButtonUp += OnItemButtonUp;
actionItem.OnPressed += OnItemPressed;
}
}
private void ClearList()
{
// TODO: Not sure if this unsub is needed if children are all being cleared
foreach (var actionItem in _resultsGrid.Children)
{
((ActionMenuItem) actionItem).OnPressed -= OnItemPressed;
}
_resultsGrid.Children.Clear();
_actionList = EmptyActionList;
}
/// <summary>
/// Should be invoked when action states change, ensures
/// currently displayed actions are properly showing their revoked / granted status
/// </summary>
public void UpdateUI()
{
foreach (var actionItem in _resultsGrid.Children)
{
var actionMenuItem = ((ActionMenuItem) actionItem);
actionMenuItem.SetActionState(_actionsComponent.IsGranted(actionMenuItem.Action));
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
_dragDropHelper.Update(args.DeltaSeconds);
}
}
}

View File

@@ -1,76 +0,0 @@
using System;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Actions;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
namespace Content.Client.UserInterface
{
/// <summary>
/// An individual action visible in the action menu.
/// </summary>
public class ActionMenuItem : ContainerButton
{
// shorter than default tooltip delay so user can
// quickly explore what each action is
private const float CustomTooltipDelay = 0.2f;
public BaseActionPrototype Action { get; private set; }
private Action<ActionMenuItem> _onControlFocusExited;
public ActionMenuItem(BaseActionPrototype action, Action<ActionMenuItem> onControlFocusExited)
{
_onControlFocusExited = onControlFocusExited;
Action = action;
MinSize = (64, 64);
VerticalAlignment = VAlignment.Top;
AddChild(new TextureRect
{
HorizontalExpand = true,
VerticalExpand = true,
Stretch = TextureRect.StretchMode.Scale,
Texture = action.Icon.Frame0()
});
TooltipDelay = CustomTooltipDelay;
TooltipSupplier = SupplyTooltip;
}
protected override void ControlFocusExited()
{
base.ControlFocusExited();
_onControlFocusExited.Invoke(this);
}
private Control SupplyTooltip(Control? sender)
{
return new ActionAlertTooltip(Action.Name, Action.Description, Action.Requires);
}
/// <summary>
/// Change how this is displayed depending on if it is granted or revoked
/// </summary>
public void SetActionState(bool granted)
{
if (granted)
{
if (HasStyleClass(StyleNano.StyleClassActionMenuItemRevoked))
{
RemoveStyleClass(StyleNano.StyleClassActionMenuItemRevoked);
}
}
else
{
if (!HasStyleClass(StyleNano.StyleClassActionMenuItemRevoked))
{
AddStyleClass(StyleNano.StyleClassActionMenuItemRevoked);
}
}
}
}
}

View File

@@ -1,583 +0,0 @@
using System.Collections.Generic;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.GameObjects.Components.Mobs.Actions;
using Content.Client.UserInterface.Controls;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.Actions;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
using Robust.Shared.Log;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface
{
/// <summary>
/// The action hotbar on the left side of the screen.
/// </summary>
public sealed class ActionsUI : Container
{
private readonly ClientActionsComponent _actionsComponent;
private readonly ActionManager _actionManager;
private readonly IEntityManager _entityManager;
private readonly IGameTiming _gameTiming;
private readonly IGameHud _gameHud;
private readonly ActionSlot[] _slots;
private readonly GridContainer _slotContainer;
private readonly TextureButton _lockButton;
private readonly TextureButton _settingsButton;
private readonly Label _loadoutNumber;
private readonly Texture _lockTexture;
private readonly Texture _unlockTexture;
private readonly HBoxContainer _loadoutContainer;
private readonly TextureRect _dragShadow;
private readonly ActionMenu _menu;
/// <summary>
/// Index of currently selected hotbar
/// </summary>
public byte SelectedHotbar { get; private set; }
/// <summary>
/// Action slot we are currently selecting a target for.
/// </summary>
public ActionSlot? SelectingTargetFor { get; private set; }
/// <summary>
/// Drag drop helper for coordinating drag drops between action slots
/// </summary>
public DragDropHelper<ActionSlot> DragDropHelper { get; }
/// <summary>
/// Whether the bar is currently locked by the user. This is intended to prevent drag / drop
/// and right click clearing slots. Anything else is still doable.
/// </summary>
public bool Locked { get; private set; }
/// <summary>
/// All the action slots in order.
/// </summary>
public IEnumerable<ActionSlot> Slots => _slots;
public ActionsUI(ClientActionsComponent actionsComponent)
{
SetValue(LayoutContainer.DebugProperty, true);
_actionsComponent = actionsComponent;
_actionManager = IoCManager.Resolve<ActionManager>();
_entityManager = IoCManager.Resolve<IEntityManager>();
_gameTiming = IoCManager.Resolve<IGameTiming>();
_gameHud = IoCManager.Resolve<IGameHud>();
_menu = new ActionMenu(_actionsComponent, this);
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.End);
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.Constrain);
LayoutContainer.SetAnchorTop(this, 0f);
LayoutContainer.SetAnchorBottom(this, 0.8f);
LayoutContainer.SetMarginLeft(this, 13);
LayoutContainer.SetMarginTop(this, 110);
HorizontalAlignment = HAlignment.Left;
VerticalExpand = true;
var resourceCache = IoCManager.Resolve<IResourceCache>();
// everything needs to go within an inner panel container so the panel resizes to fit the elements.
// Because ActionsUI is being anchored by layoutcontainer, the hotbar backing would appear too tall
// if ActionsUI was the panel container
var panelContainer = new PanelContainer()
{
StyleClasses = {StyleNano.StyleClassHotbarPanel},
HorizontalAlignment = HAlignment.Left,
VerticalAlignment = VAlignment.Top
};
AddChild(panelContainer);
var hotbarContainer = new VBoxContainer
{
SeparationOverride = 3,
HorizontalAlignment = HAlignment.Left
};
panelContainer.AddChild(hotbarContainer);
var settingsContainer = new HBoxContainer
{
HorizontalExpand = true
};
hotbarContainer.AddChild(settingsContainer);
settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 });
_lockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock.svg.192dpi.png");
_unlockTexture = resourceCache.GetTexture("/Textures/Interface/Nano/lock_open.svg.192dpi.png");
_lockButton = new TextureButton
{
TextureNormal = _unlockTexture,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
Scale = (0.5f, 0.5f)
};
settingsContainer.AddChild(_lockButton);
settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 });
_settingsButton = new TextureButton
{
TextureNormal = resourceCache.GetTexture("/Textures/Interface/Nano/gear.svg.192dpi.png"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
Scale = (0.5f, 0.5f)
};
settingsContainer.AddChild(_settingsButton);
settingsContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 });
// this allows a 2 column layout if window gets too small
_slotContainer = new GridContainer
{
MaxGridHeight = CalcMaxHeight()
};
hotbarContainer.AddChild(_slotContainer);
_loadoutContainer = new HBoxContainer
{
HorizontalExpand = true,
MouseFilter = MouseFilterMode.Stop
};
hotbarContainer.AddChild(_loadoutContainer);
_loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 });
var previousHotbarIcon = new TextureRect()
{
Texture = resourceCache.GetTexture("/Textures/Interface/Nano/left_arrow.svg.192dpi.png"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
TextureScale = (0.5f, 0.5f)
};
_loadoutContainer.AddChild(previousHotbarIcon);
_loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 });
_loadoutNumber = new Label
{
Text = "1",
SizeFlagsStretchRatio = 1
};
_loadoutContainer.AddChild(_loadoutNumber);
_loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 2 });
var nextHotbarIcon = new TextureRect
{
Texture = resourceCache.GetTexture("/Textures/Interface/Nano/right_arrow.svg.192dpi.png"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
TextureScale = (0.5f, 0.5f)
};
_loadoutContainer.AddChild(nextHotbarIcon);
_loadoutContainer.AddChild(new Control { HorizontalExpand = true, SizeFlagsStretchRatio = 1 });
_slots = new ActionSlot[ClientActionsComponent.Slots];
_dragShadow = new TextureRect
{
MinSize = (64, 64),
Stretch = TextureRect.StretchMode.Scale,
Visible = false,
SetSize = (64, 64)
};
UserInterfaceManager.PopupRoot.AddChild(_dragShadow);
for (byte i = 0; i < ClientActionsComponent.Slots; i++)
{
var slot = new ActionSlot(this, _menu, actionsComponent, i);
_slotContainer.AddChild(slot);
_slots[i] = slot;
}
DragDropHelper = new DragDropHelper<ActionSlot>(OnBeginActionDrag, OnContinueActionDrag, OnEndActionDrag);
MinSize = (10, 400);
}
protected override void EnteredTree()
{
base.EnteredTree();
_lockButton.OnPressed += OnLockPressed;
_settingsButton.OnPressed += OnToggleActionsMenu;
_loadoutContainer.OnKeyBindDown += OnHotbarPaginate;
_gameHud.ActionsButtonToggled += OnToggleActionsMenuTopButton;
_gameHud.ActionsButtonDown = false;
_gameHud.ActionsButtonVisible = true;
}
protected override void ExitedTree()
{
base.ExitedTree();
StopTargeting();
_menu.Close();
_lockButton.OnPressed -= OnLockPressed;
_settingsButton.OnPressed -= OnToggleActionsMenu;
_loadoutContainer.OnKeyBindDown -= OnHotbarPaginate;
_gameHud.ActionsButtonToggled -= OnToggleActionsMenuTopButton;
_gameHud.ActionsButtonDown = false;
_gameHud.ActionsButtonVisible = false;
}
protected override void Resized()
{
base.Resized();
_slotContainer.MaxGridHeight = CalcMaxHeight();
}
private float CalcMaxHeight()
{
// TODO: Can rework this once https://github.com/space-wizards/RobustToolbox/issues/1392 is done,
// this is here because there isn't currently a good way to allow the grid to adjust its height based
// on constraints, otherwise we would use anchors to lay it out
// it looks bad to have an uneven number of slots in the columns,
// so we either do a single column or 2 equal sized columns
if (Height < 650)
{
// 2 column
return 400;
}
else
{
// 1 column
return 900;
}
}
protected override void UIScaleChanged()
{
_slotContainer.MaxGridHeight = CalcMaxHeight();
base.UIScaleChanged();
}
/// <summary>
/// Refresh the display of all the slots in the currently displayed hotbar,
/// to reflect the current component state and assignments of actions component.
/// </summary>
public void UpdateUI()
{
_menu.UpdateUI();
foreach (var actionSlot in Slots)
{
var assignedActionType = _actionsComponent.Assignments[SelectedHotbar, actionSlot.SlotIndex];
if (!assignedActionType.HasValue)
{
actionSlot.Clear();
continue;
}
if (assignedActionType.Value.TryGetAction(out var actionType))
{
UpdateActionSlot(actionType, actionSlot, assignedActionType);
}
else if (assignedActionType.Value.TryGetItemActionWithoutItem(out var itemlessActionType))
{
UpdateActionSlot(itemlessActionType, actionSlot, assignedActionType);
}
else if (assignedActionType.Value.TryGetItemActionWithItem(out var itemActionType, out var item))
{
UpdateActionSlot(item, itemActionType, actionSlot, assignedActionType);
}
else
{
Logger.ErrorS("action", "unexpected Assignment type {0}",
assignedActionType.Value.Assignment);
actionSlot.Clear();
}
}
}
private void UpdateActionSlot(ActionType actionType, ActionSlot actionSlot, ActionAssignment? assignedActionType)
{
if (_actionManager.TryGet(actionType, out var action))
{
actionSlot.Assign(action, true);
}
else
{
Logger.ErrorS("action", "unrecognized actionType {0}", assignedActionType);
actionSlot.Clear();
return;
}
if (!_actionsComponent.TryGetActionState(actionType, out var actionState) || !actionState.Enabled)
{
// action is currently disabled
// just revoked an action we were trying to target with, stop targeting
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action)
{
StopTargeting();
}
actionSlot.DisableAction();
actionSlot.Cooldown = null;
}
else
{
// action is currently granted
actionSlot.EnableAction();
actionSlot.Cooldown = actionState.Cooldown;
// if we are targeting for this action and it's now on cooldown, stop targeting if we're supposed to
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action &&
actionState.IsOnCooldown(_gameTiming) && action.DeselectOnCooldown)
{
StopTargeting();
}
}
// check if we need to toggle it
if (action.BehaviorType == BehaviorType.Toggle)
{
actionSlot.ToggledOn = actionState.ToggledOn;
}
}
private void UpdateActionSlot(ItemActionType itemlessActionType, ActionSlot actionSlot,
ActionAssignment? assignedActionType)
{
if (_actionManager.TryGet(itemlessActionType, out var action))
{
actionSlot.Assign(action);
}
else
{
Logger.ErrorS("action", "unrecognized actionType {0}", assignedActionType);
actionSlot.Clear();
}
actionSlot.Cooldown = null;
}
private void UpdateActionSlot(EntityUid item, ItemActionType itemActionType, ActionSlot actionSlot,
ActionAssignment? assignedActionType)
{
if (!_entityManager.TryGetEntity(item, out var itemEntity)) return;
if (_actionManager.TryGet(itemActionType, out var action))
{
actionSlot.Assign(action, itemEntity, true);
}
else
{
Logger.ErrorS("action", "unrecognized actionType {0}", assignedActionType);
actionSlot.Clear();
return;
}
if (!_actionsComponent.TryGetItemActionState(itemActionType, item, out var actionState))
{
// action is no longer tied to an item, this should never happen as we
// check this at the start of this method. But just to be safe
// we will restore our assignment here to the correct state
Logger.ErrorS("action", "coding error, expected actionType {0} to have" +
" a state but it didn't", assignedActionType);
_actionsComponent.Assignments.AssignSlot(SelectedHotbar, actionSlot.SlotIndex,
ActionAssignment.For(itemActionType));
actionSlot.Assign(action);
return;
}
if (!actionState.Enabled)
{
// just disabled an action we were trying to target with, stop targeting
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action)
{
StopTargeting();
}
actionSlot.DisableAction();
}
else
{
// action is currently granted
actionSlot.EnableAction();
// if we are targeting with an action now on cooldown, stop targeting if we should
if (SelectingTargetFor?.Action != null && SelectingTargetFor.Action == action &&
SelectingTargetFor.Item == itemEntity &&
actionState.IsOnCooldown(_gameTiming) && action.DeselectOnCooldown)
{
StopTargeting();
}
}
actionSlot.Cooldown = actionState.Cooldown;
// check if we need to toggle it
if (action.BehaviorType == BehaviorType.Toggle)
{
actionSlot.ToggledOn = actionState.ToggledOn;
}
}
private void OnHotbarPaginate(GUIBoundKeyEventArgs args)
{
// rather than clicking the arrows themselves, the user can click the hbox so it's more
// "forgiving" for misclicks, and we simply check which side they are closer to
if (args.Function != EngineKeyFunctions.UIClick) return;
var rightness = args.RelativePosition.X / _loadoutContainer.Width;
if (rightness > 0.5)
{
ChangeHotbar((byte) ((SelectedHotbar + 1) % ClientActionsComponent.Hotbars));
}
else
{
var newBar = SelectedHotbar == 0 ? ClientActionsComponent.Hotbars - 1 : SelectedHotbar - 1;
ChangeHotbar((byte) newBar);
}
}
private void ChangeHotbar(byte hotbar)
{
StopTargeting();
SelectedHotbar = hotbar;
_loadoutNumber.Text = (hotbar + 1).ToString();
UpdateUI();
}
/// <summary>
/// If currently targeting with this slot, stops targeting.
/// If currently targeting with no slot or a different slot, switches to
/// targeting with the specified slot.
/// </summary>
/// <param name="slot"></param>
public void ToggleTargeting(ActionSlot slot)
{
if (SelectingTargetFor == slot)
{
StopTargeting();
return;
}
StartTargeting(slot);
}
/// <summary>
/// Puts us in targeting mode, where we need to pick either a target point or entity
/// </summary>
private void StartTargeting(ActionSlot actionSlot)
{
// If we were targeting something else we should stop
StopTargeting();
SelectingTargetFor = actionSlot;
// show it as toggled on to indicate we are currently selecting a target for it
if (!actionSlot.ToggledOn)
{
actionSlot.ToggledOn = true;
}
}
/// <summary>
/// Switch out of targeting mode if currently selecting target for an action
/// </summary>
public void StopTargeting()
{
if (SelectingTargetFor == null) return;
if (SelectingTargetFor.ToggledOn)
{
SelectingTargetFor.ToggledOn = false;
}
SelectingTargetFor = null;
}
private void OnToggleActionsMenu(BaseButton.ButtonEventArgs args)
{
ToggleActionsMenu();
}
private void OnToggleActionsMenuTopButton(bool open)
{
if (open == _menu.IsOpen) return;
ToggleActionsMenu();
}
public void ToggleActionsMenu()
{
if (_menu.IsOpen)
{
_menu.Close();
}
else
{
_menu.OpenCentered();
}
}
private void OnLockPressed(BaseButton.ButtonEventArgs obj)
{
Locked = !Locked;
_lockButton.TextureNormal = Locked ? _lockTexture : _unlockTexture;
}
private bool OnBeginActionDrag()
{
// only initiate the drag if the slot has an action in it
if (Locked || DragDropHelper.Dragged?.Action == null) return false;
_dragShadow.Texture = DragDropHelper.Dragged.Action.Icon.Frame0();
LayoutContainer.SetPosition(_dragShadow, UserInterfaceManager.MousePositionScaled.Position - (32, 32));
DragDropHelper.Dragged.CancelPress();
return true;
}
private bool OnContinueActionDrag(float frameTime)
{
// stop if there's no action in the slot
if (Locked || DragDropHelper.Dragged?.Action == null) return false;
// keep dragged entity centered under mouse
LayoutContainer.SetPosition(_dragShadow, UserInterfaceManager.MousePositionScaled.Position - (32, 32));
// we don't set this visible until frameupdate, otherwise it flickers
_dragShadow.Visible = true;
return true;
}
private void OnEndActionDrag()
{
_dragShadow.Visible = false;
}
/// <summary>
/// Handle keydown / keyup for one of the slots via a keybinding, simulates mousedown/mouseup on it.
/// </summary>
/// <param name="slot">slot index to to receive the press (0 corresponds to the one labeled 1, 9 corresponds to the one labeled 0)</param>
public void HandleHotbarKeybind(byte slot, PointerInputCmdHandler.PointerInputCmdArgs args)
{
var actionSlot = _slots[slot];
actionSlot.Depress(args.State == BoundKeyState.Down);
}
/// <summary>
/// Handle hotbar change.
/// </summary>
/// <param name="hotbar">hotbar index to switch to</param>
public void HandleChangeHotbarKeybind(byte hotbar, PointerInputCmdHandler.PointerInputCmdArgs args)
{
ChangeHotbar(hotbar);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
DragDropHelper.Update(args.DeltaSeconds);
}
}
}

View File

@@ -1,169 +0,0 @@
using Content.Client.Eui;
using Content.Shared.Administration;
using Content.Shared.Chemistry;
using Content.Shared.Eui;
using JetBrains.Annotations;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
[UsedImplicitly]
public sealed class AdminAddReagentEui : BaseEui
{
[Dependency] private readonly IPrototypeManager _prototypes = default!;
private readonly Menu _window;
public AdminAddReagentEui()
{
_window = new Menu(this);
_window.OnClose += () => SendMessage(new AdminAddReagentEuiMsg.Close());
}
public override void Opened()
{
_window.OpenCentered();
}
public override void Closed()
{
_window.Close();
}
public override void HandleState(EuiStateBase state)
{
_window.HandleState((AdminAddReagentEuiState) state);
}
private void DoAdd(bool close, string reagentId, ReagentUnit amount)
{
SendMessage(new AdminAddReagentEuiMsg.DoAdd
{
Amount = amount,
ReagentId = reagentId,
CloseAfter = close
});
}
private sealed class Menu : SS14Window
{
private readonly AdminAddReagentEui _eui;
private readonly Label _volumeLabel;
private readonly LineEdit _reagentIdEdit;
private readonly LineEdit _amountEdit;
private readonly Label _errorLabel;
private readonly Button _addButton;
private readonly Button _addCloseButton;
public Menu(AdminAddReagentEui eui)
{
_eui = eui;
Title = Loc.GetString("Add reagent...");
Contents.AddChild(new VBoxContainer
{
Children =
{
new GridContainer
{
Columns = 2,
Children =
{
new Label {Text = Loc.GetString("Cur volume: ")},
(_volumeLabel = new Label()),
new Label {Text = Loc.GetString("Reagent: ")},
(_reagentIdEdit = new LineEdit {PlaceHolder = Loc.GetString("Reagent ID...")}),
new Label {Text = Loc.GetString("Amount: ")},
(_amountEdit = new LineEdit
{
PlaceHolder = Loc.GetString("A number..."),
HorizontalExpand = true
}),
},
HorizontalExpand = true,
VerticalExpand = true
},
new HBoxContainer
{
Children =
{
(_errorLabel = new Label
{
HorizontalExpand = true,
ClipText = true
}),
(_addButton = new Button {Text = Loc.GetString("Add")}),
(_addCloseButton = new Button {Text = Loc.GetString("Add & Close")})
}
}
}
});
_reagentIdEdit.OnTextChanged += _ => CheckErrors();
_amountEdit.OnTextChanged += _ => CheckErrors();
_addButton.OnPressed += _ => DoAdd(false);
_addCloseButton.OnPressed += _ => DoAdd(true);
CheckErrors();
}
private void DoAdd(bool close)
{
_eui.DoAdd(
close,
_reagentIdEdit.Text,
ReagentUnit.New(float.Parse(_amountEdit.Text)));
}
private void CheckErrors()
{
if (string.IsNullOrWhiteSpace(_reagentIdEdit.Text))
{
DoError(Loc.GetString("Must specify reagent ID"));
return;
}
if (!_eui._prototypes.HasIndex<ReagentPrototype>(_reagentIdEdit.Text))
{
DoError(Loc.GetString("'{0}' does not exist.", _reagentIdEdit.Text));
return;
}
if (string.IsNullOrWhiteSpace(_amountEdit.Text))
{
DoError(Loc.GetString("Must specify reagent amount"));
return;
}
if (!float.TryParse(_amountEdit.Text, out _))
{
DoError(Loc.GetString("Invalid amount"));
return;
}
_addButton.Disabled = false;
_addCloseButton.Disabled = false;
_errorLabel.Text = "";
void DoError(string text)
{
_errorLabel.Text = text;
_addButton.Disabled = true;
_addCloseButton.Disabled = true;
}
}
public void HandleState(AdminAddReagentEuiState state)
{
_volumeLabel.Text = Loc.GetString("{0}/{1}u", state.CurVolume, state.MaxVolume);
}
}
}
}

View File

@@ -1,146 +0,0 @@
using System.Collections.Generic;
using Content.Client.Administration;
using Content.Shared.Administration.AdminMenu;
using Content.Shared.Input;
using Robust.Client.Console;
using Robust.Client.Input;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
using Robust.Shared.Network;
namespace Content.Client.UserInterface.AdminMenu
{
internal class AdminMenuManager : IAdminMenuManager
{
[Dependency] private readonly INetManager _netManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly IClientAdminManager _clientAdminManager = default!;
[Dependency] private readonly IClientConGroupController _clientConGroupController = default!;
private AdminMenuWindow? _window;
private List<SS14Window> _commandWindows = new();
public void Initialize()
{
_netManager.RegisterNetMessage<AdminMenuPlayerListRequest>(AdminMenuPlayerListRequest.NAME);
_netManager.RegisterNetMessage<AdminMenuPlayerListMessage>(AdminMenuPlayerListMessage.NAME, HandlePlayerListMessage);
_commandWindows = new List<SS14Window>();
// Reset the AdminMenu Window on disconnect
_netManager.Disconnect += (_, _) => ResetWindow();
_inputManager.SetInputCommand(ContentKeyFunctions.OpenAdminMenu,
InputCmdHandler.FromDelegate(_ => Toggle()));
_clientAdminManager.AdminStatusUpdated += () =>
{
// when status changes, show the top button if we can open admin menu.
// if we can't or we lost admin status, close it and hide the button.
_gameHud.AdminButtonVisible = CanOpen();
if (!_gameHud.AdminButtonVisible)
{
Close();
}
};
_gameHud.AdminButtonToggled += (open) =>
{
if (open)
{
TryOpen();
}
else
{
Close();
}
};
_gameHud.AdminButtonVisible = CanOpen();
_gameHud.AdminButtonDown = false;
}
private void RequestPlayerList()
{
var message = _netManager.CreateNetMessage<AdminMenuPlayerListRequest>();
_netManager.ClientSendMessage(message);
}
private void HandlePlayerListMessage(AdminMenuPlayerListMessage msg)
{
_window?.RefreshPlayerList(msg.PlayersInfo);
}
public void ResetWindow()
{
_window?.Close();
_window = null;
foreach (var window in _commandWindows)
window?.Dispose();
_commandWindows.Clear();
}
public void OpenCommand(SS14Window window)
{
_commandWindows.Add(window);
window.OpenCentered();
}
public void Open()
{
_window ??= new AdminMenuWindow();
_window.OnPlayerListRefresh += RequestPlayerList;
_window.OpenCentered();
}
public void Close()
{
_window?.Close();
foreach (var window in _commandWindows)
window?.Dispose();
_commandWindows.Clear();
}
/// <summary>
/// Checks if the player can open the window
/// </summary>
/// <returns>True if the player is allowed</returns>
public bool CanOpen()
{
return _clientConGroupController.CanAdminMenu();
}
/// <summary>
/// Checks if the player can open the window and tries to open it
/// </summary>
public void TryOpen()
{
if (CanOpen())
Open();
}
public void Toggle()
{
if (_window != null && _window.IsOpen)
{
Close();
}
else
{
TryOpen();
}
}
}
internal interface IAdminMenuManager
{
void Initialize();
void Open();
void OpenCommand(SS14Window window);
bool CanOpen();
void TryOpen();
void Toggle();
}
}

View File

@@ -1,15 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io"
xmlns:adminMenu="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs;assembly=Content.Client"
xmlns:adminTab="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AdminTab"
xmlns:adminbusTab="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AdminbusTab"
xmlns:atmosTab="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab">
<TabContainer Name="MasterTabContainer">
<adminTab:AdminTab />
<adminbusTab:AdminbusTab />
<atmosTab:AtmosTab />
<adminMenu:RoundTab />
<adminMenu:ServerTab />
<adminMenu:PlayerTab Name="PlayerTabControl" />
</TabContainer>
</SS14Window>

View File

@@ -1,58 +0,0 @@
#nullable enable
using System.Collections.Generic;
using Content.Client.UserInterface.AdminMenu.Tabs;
using Content.Shared.Administration.AdminMenu;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface.AdminMenu
{
[GenerateTypedNameReferences]
public partial class AdminMenuWindow : SS14Window
{
[Dependency] private readonly IGameHud? _gameHud = default!;
public event PlayerTab.PlayerListRefresh? OnPlayerListRefresh
{
add => PlayerTabControl.OnPlayerListRefresh += value;
remove => PlayerTabControl.OnPlayerListRefresh -= value;
}
public AdminMenuWindow()
{
MinSize = SetSize = (500, 250);
Title = Loc.GetString("Admin Menu");
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
MasterTabContainer.SetTabTitle(0, Loc.GetString("Admin"));
MasterTabContainer.SetTabTitle(1, Loc.GetString("Adminbus"));
MasterTabContainer.SetTabTitle(2, Loc.GetString("Atmos"));
MasterTabContainer.SetTabTitle(3, Loc.GetString("Round"));
MasterTabContainer.SetTabTitle(4, Loc.GetString("Server"));
MasterTabContainer.SetTabTitle(5, Loc.GetString("Players"));
}
protected override void EnteredTree()
{
base.EnteredTree();
if (_gameHud != null)
_gameHud.AdminButtonDown = true;
}
protected override void ExitedTree()
{
base.ExitedTree();
if (_gameHud != null)
_gameHud.AdminButtonDown = false;
}
public void RefreshPlayerList(IEnumerable<AdminMenuPlayerListMessage.PlayerInfo> players)
{
PlayerTabControl.RefreshPlayerList(players);
}
}
}

View File

@@ -1,38 +0,0 @@
#nullable enable
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
namespace Content.Client.UserInterface.AdminMenu.CustomControls
{
public class CommandButton : Button
{
public string? Command { get; set; }
public CommandButton() : base()
{
OnPressed += Execute;
}
protected virtual bool CanPress()
{
return string.IsNullOrEmpty(Command) ||
IoCManager.Resolve<IClientConGroupController>().CanCommand(Command);
}
protected override void EnteredTree()
{
if (!CanPress())
{
Visible = false;
}
}
protected virtual void Execute(ButtonEventArgs obj)
{
// Default is to execute command
if (!string.IsNullOrEmpty(Command))
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(Command);
}
}
}

View File

@@ -1,13 +0,0 @@
<VBoxContainer
xmlns="https://spacestation14.io">
<Control CustomMinimumSize="0 5" />
<HBoxContainer>
<!-- <Label Text="{Loc Search}" CustomMinimumSize="100 0" /> -->
<!-- <Control CustomMinimumSize="50 0" /> -->
<LineEdit Name="FilterLineEdit" CustomMinimumSize="100 0" SizeFlagsHorizontal="FillExpand" PlaceHolder="{Loc Filter}"/>
</HBoxContainer>
<!-- <Control CustomMinimumSize="0 5" /> -->
<ItemList
Name="PlayerItemList" SelectMode="Single" SizeFlagsVertical="FillExpand" SizeFlagsHorizontal="FillExpand"
CustomMinimumSize="100 100" />
</VBoxContainer>

View File

@@ -1,79 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Players;
namespace Content.Client.UserInterface.AdminMenu.CustomControls
{
[GenerateTypedNameReferences]
public partial class PlayerListControl : VBoxContainer
{
private List<ICommonSession>? _data;
public event Action<ICommonSession?>? OnSelectionChanged;
protected override void EnteredTree()
{
// Fill the Option data
_data = IoCManager.Resolve<IPlayerManager>().Sessions.OfType<ICommonSession>().ToList();
PopulateList();
PlayerItemList.OnItemSelected += PlayerItemListOnOnItemSelected;
PlayerItemList.OnItemDeselected += PlayerItemListOnOnItemDeselected;
FilterLineEdit.OnTextChanged += FilterLineEditOnOnTextEntered;
}
private void FilterLineEditOnOnTextEntered(LineEdit.LineEditEventArgs obj)
{
PopulateList(FilterLineEdit.Text);
}
private static string GetDisplayName(ICommonSession session)
{
return $"{session.Name} ({session.AttachedEntity?.Name})";
}
private void PlayerItemListOnOnItemSelected(ItemList.ItemListSelectedEventArgs obj)
{
var selectedPlayer = (ICommonSession) obj.ItemList[obj.ItemIndex].Metadata!;
OnSelectionChanged?.Invoke(selectedPlayer);
}
private void PlayerItemListOnOnItemDeselected(ItemList.ItemListDeselectedEventArgs obj)
{
OnSelectionChanged?.Invoke(null);
}
private void PopulateList(string? filter = null)
{
// _data should never be null here
if (_data == null)
return;
PlayerItemList.Clear();
foreach (var session in _data)
{
var displayName = GetDisplayName(session);
if (!string.IsNullOrEmpty(filter) &&
!displayName.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))
{
continue;
}
PlayerItemList.Add(new ItemList.Item(PlayerItemList)
{
Metadata = session,
Text = displayName
});
}
}
public void ClearSelection()
{
PlayerItemList.ClearSelected();
}
}
}

View File

@@ -1,21 +0,0 @@
#nullable enable
using System;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
namespace Content.Client.UserInterface.AdminMenu.CustomControls
{
public class UICommandButton : CommandButton
{
public Type? WindowType { get; set; }
private SS14Window? _window;
protected override void Execute(ButtonEventArgs obj)
{
if (WindowType == null)
return;
_window = (SS14Window) IoCManager.Resolve<IDynamicTypeFactory>().CreateInstance(WindowType);
_window?.OpenCentered();
}
}
}

View File

@@ -1,35 +0,0 @@
using Content.Client.Eui;
using Content.Shared.Eui;
using JetBrains.Annotations;
using Content.Shared.Administration;
namespace Content.Client.UserInterface.AdminMenu.SetOutfit
{
[UsedImplicitly]
public sealed class SetOutfitEui : BaseEui
{
private readonly SetOutfitMenu _window;
public SetOutfitEui()
{
_window = new SetOutfitMenu();
}
public override void Opened()
{
_window.OpenCentered();
}
public override void Closed()
{
base.Closed();
_window.Close();
}
public override void HandleState(EuiStateBase state)
{
var outfitState = (SetOutfitEuiState) state;
_window.TargetEntityId = outfitState.TargetEntityId;
}
}
}

View File

@@ -1,15 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io">
<HBoxContainer HorizontalExpand="True">
<VBoxContainer HorizontalExpand="True" SizeFlagsStretchRatio="0.45">
<HBoxContainer HorizontalExpand="True" VerticalExpand="True"
SizeFlagsStretchRatio="0.1">
<LineEdit Name="SearchBar" PlaceHolder="Search" HorizontalExpand="True"
SizeFlagsStretchRatio="0.6" />
</HBoxContainer>
<ItemList Name="OutfitList" SelectMode="Single" VerticalExpand="True"
SizeFlagsStretchRatio="0.9" />
<Button Name="ConfirmButton" HorizontalExpand="True" />
</VBoxContainer>
</HBoxContainer>
</SS14Window>

View File

@@ -1,98 +0,0 @@
using Content.Shared.Roles;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.AdminMenu.SetOutfit
{
[GenerateTypedNameReferences]
public partial class SetOutfitMenu : SS14Window
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
public EntityUid? TargetEntityId { get; set; }
private StartingGearPrototype? _selectedOutfit;
public SetOutfitMenu()
{
MinSize = SetSize = (250, 320);
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
Title = Loc.GetString("Set Outfit");
ConfirmButton.Text = Loc.GetString("Confirm");
ConfirmButton.OnPressed += ConfirmButtonOnOnPressed;
SearchBar.OnTextChanged += SearchBarOnOnTextChanged;
OutfitList.OnItemSelected += OutfitListOnOnItemSelected;
OutfitList.OnItemDeselected += OutfitListOnOnItemDeselected;
PopulateList();
}
private void ConfirmButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (TargetEntityId == null || _selectedOutfit == null)
return;
var command = $"setoutfit {TargetEntityId} {_selectedOutfit.ID}";
_consoleHost.ExecuteCommand(command);
Close();
}
private void OutfitListOnOnItemSelected(ItemList.ItemListSelectedEventArgs obj)
{
_selectedOutfit = (StartingGearPrototype) obj.ItemList[obj.ItemIndex].Metadata!;
ConfirmButton.Disabled = false;
}
private void OutfitListOnOnItemDeselected(ItemList.ItemListDeselectedEventArgs obj)
{
_selectedOutfit = null;
ConfirmButton.Disabled = true;
}
private void SearchBarOnOnTextChanged(LineEdit.LineEditEventArgs obj)
{
PopulateByFilter(SearchBar.Text);
}
private void PopulateList()
{
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
{
OutfitList.Add(GetItem(gear, OutfitList));
}
}
private void PopulateByFilter(string filter)
{
OutfitList.Clear();
foreach (var gear in _prototypeManager.EnumeratePrototypes<StartingGearPrototype>())
{
if (!string.IsNullOrEmpty(filter) &&
gear.ID.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant()))
{
OutfitList.Add(GetItem(gear, OutfitList));
}
}
}
private static ItemList.Item GetItem(StartingGearPrototype gear, ItemList itemList)
{
return new(itemList)
{
Metadata = gear,
Text = gear.ID
};
}
}
}

View File

@@ -1,17 +0,0 @@
<Control
xmlns="https://spacestation14.io"
xmlns:amc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:at="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AdminTab"
Margin="4"
MinSize="50 50">
<VBoxContainer>
<GridContainer Columns="4">
<amc:UICommandButton Command="kick" Text="{Loc Kick}" WindowType="{x:Type at:KickWindow}" />
<amc:UICommandButton Command="ban" Text="{Loc Ban}" WindowType="{x:Type at:BanWindow}" />
<amc:CommandButton Command="aghost" Text="{Loc Admin Ghost}" />
<amc:UICommandButton Command="tpto" Text="{Loc Teleport}" WindowType="{x:Type at:TeleportWindow}" />
<amc:CommandButton Command="permissions" Text="{Loc Permissions Panel}" />
</GridContainer>
</VBoxContainer>
</Control>

View File

@@ -1,11 +0,0 @@
#nullable enable
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminTab
{
[GenerateTypedNameReferences]
public partial class AdminTab : Control
{
}
}

View File

@@ -1,24 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
Title="{Loc Ban}" MinSize="425 162">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Player}" MinWidth="100" />
<Control MinWidth="50" />
<LineEdit Name="PlayerNameLine" MinWidth="100" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Reason}" MinSize="100 0" />
<Control MinSize="50 0" />
<LineEdit Name="ReasonLine" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Minutes}" MinWidth="100" />
<Control MinWidth="50" />
<LineEdit Name="MinutesLine" MinWidth="100" HorizontalExpand="True" PlaceHolder="{Loc 0 minutes for a permanent ban}" />
</HBoxContainer>
<Control MinWidth="50" />
<Button Name="SubmitButton" Text="{Loc Ban}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,35 +0,0 @@
#nullable enable
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class BanWindow : SS14Window
{
protected override void EnteredTree()
{
PlayerNameLine.OnTextChanged += PlayerNameLineOnOnTextChanged;
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private void PlayerNameLineOnOnTextChanged(LineEdit.LineEditEventArgs obj)
{
SubmitButton.Disabled = string.IsNullOrEmpty(PlayerNameLine.Text);
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
// Small verification if Player Name exists
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"ban \"{PlayerNameLine.Text}\" \"{CommandParsing.Escape(ReasonLine.Text)}\" {MinutesLine.Text}");
}
}
}

View File

@@ -1,14 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
Title="{Loc Kick}" MinSize="425 272">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Reason}" MinWidth="100" />
<Control MinWidth="50" />
<LineEdit Name="ReasonLine" MinWidth="100" HorizontalExpand="True" />
</HBoxContainer>
<cc:PlayerListControl Name="PlayerList" />
<Button Name="SubmitButton" Text="{Loc Kick}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,39 +0,0 @@
#nullable enable
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Players;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class KickWindow : SS14Window
{
private ICommonSession? _selectedSession;
protected override void EnteredTree()
{
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
PlayerList.OnSelectionChanged += OnListOnOnSelectionChanged;
}
private void OnListOnOnSelectionChanged(ICommonSession? obj)
{
_selectedSession = obj;
SubmitButton.Disabled = _selectedSession == null;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedSession == null)
return;
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"kick \"{_selectedSession.Name}\" \"{CommandParsing.Escape(ReasonLine.Text)}\"");
}
}
}

View File

@@ -1,9 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io"
xmlns:cc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
Title="{Loc Teleport}" MinSize="425 230">
<VBoxContainer>
<cc:PlayerListControl Name="PlayerList" />
<Button Name="SubmitButton" Text="{Loc Teleport}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,41 +0,0 @@
#nullable enable
using JetBrains.Annotations;
using NFluidsynth;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Players;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class TeleportWindow : SS14Window
{
private ICommonSession? _selectedSession;
protected override void EnteredTree()
{
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
PlayerList.OnSelectionChanged += OnListOnOnSelectionChanged;
}
private void OnListOnOnSelectionChanged(ICommonSession? obj)
{
_selectedSession = obj;
SubmitButton.Disabled = _selectedSession == null;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_selectedSession == null)
return;
// Execute command
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"tpto \"{_selectedSession.Name}\"");
}
}
}

View File

@@ -1,14 +0,0 @@
<Control
xmlns="https://spacestation14.io"
xmlns:amc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:abt="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AdminbusTab"
Margin="4"
MinSize="50 50">
<GridContainer
Columns="4">
<amc:CommandButton Name="SpawnEntitiesButton" Text="{Loc Spawn Entities}" />
<amc:CommandButton Name="SpawnTilesButton" Text="{Loc Spawn Tiles} " />
<amc:UICommandButton Command="events" Text="{Loc Station Events}" WindowType="{x:Type abt:StationEventsWindow}" />
</GridContainer>
</Control>

View File

@@ -1,43 +0,0 @@
#nullable enable
using Robust.Client.AutoGenerated;
using Robust.Client.Placement;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminbusTab
{
[GenerateTypedNameReferences]
public partial class AdminbusTab : Control
{
protected override void EnteredTree()
{
// For the SpawnEntitiesButton and SpawnTilesButton we need to do the press manually
// TODO: This will probably need some command check at some point
SpawnEntitiesButton.OnPressed += SpawnEntitiesButtonOnOnPressed;
SpawnTilesButton.OnPressed += SpawnTilesButtonOnOnPressed;
}
private static void SpawnEntitiesButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
var manager = IoCManager.Resolve<IAdminMenuManager>();
var window = new EntitySpawnWindow(IoCManager.Resolve<IPlacementManager>(),
IoCManager.Resolve<IPrototypeManager>(),
IoCManager.Resolve<IResourceCache>());
manager.OpenCommand(window);
}
private static void SpawnTilesButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
var manager = IoCManager.Resolve<IAdminMenuManager>();
var window = new TileSpawnWindow(IoCManager.Resolve<ITileDefinitionManager>(),
IoCManager.Resolve<IPlacementManager>(),
IoCManager.Resolve<IResourceCache>());
manager.OpenCommand(window);
}
}
}

View File

@@ -1,13 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io" Title="Kick">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Event}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="EventsOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<Button Name="PauseButton" Text="{Loc Pause}" />
<Button Name="ResumeButton" Text="{Loc Resume}" />
<Button Name="SubmitButton" Text="{Loc Run}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,54 +0,0 @@
#nullable enable
using System.Linq;
using System.Collections.Generic;
using Content.Client.StationEvents;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AdminbusTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class StationEventsWindow : SS14Window
{
private List<string>? _data;
protected override void EnteredTree()
{
_data = IoCManager.Resolve<IStationEventManager>().StationEvents.ToList();
_data.Add(_data.Any() ? Loc.GetString("Not loaded") : Loc.GetString("Random"));
foreach (var stationEvent in _data)
{
EventsOptions.AddItem(stationEvent);
}
EventsOptions.OnItemSelected += eventArgs => EventsOptions.SelectId(eventArgs.Id);
PauseButton.OnPressed += PauseButtonOnOnPressed;
ResumeButton.OnPressed += ResumeButtonOnOnPressed;
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private static void PauseButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand("events pause");
}
private static void ResumeButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand("events resume");
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_data == null)
return;
var selectedEvent = _data[EventsOptions.SelectedId];
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand($"events run \"{selectedEvent}\"");
}
}
}

View File

@@ -1,11 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io" Title="{Loc Add Atmos}">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Grid}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<Button Name="SubmitButton" Text="{Loc Add Atmos}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,43 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class AddAtmosWindow : SS14Window
{
private IEnumerable<IMapGrid>? _data;
protected override void EnteredTree()
{
_data = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Index != 0);
foreach (var grid in _data)
{
var playerGrid = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity?.Transform.GridID;
GridOptions.AddItem($"{grid.Index} {(playerGrid == grid.Index ? " (Current)" : "")}");
}
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_data == null)
return;
var dataList = _data.ToList();
var selectedGrid = dataList[GridOptions.SelectedId].Index;
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand($"addatmos {selectedGrid}");
}
}
}

View File

@@ -1,31 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io" Title="{Loc Add Gas}">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Grid}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc TileX}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="TileXSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc TileY}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="TileYSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Gas}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GasOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Amount}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="AmountSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<Button Name="SubmitButton" Text="{Loc Add Gas}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,64 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.EntitySystems;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class AddGasWindow : SS14Window
{
private IEnumerable<IMapGrid>? _gridData;
private IEnumerable<GasPrototype>? _gasData;
protected override void EnteredTree()
{
// Fill out grids
_gridData = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Index != 0);
foreach (var grid in _gridData)
{
var playerGrid = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity?.Transform.GridID;
GridOptions.AddItem($"{grid.Index} {(playerGrid == grid.Index ? " (Current)" : "")}");
}
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
// Fill out gases
_gasData = EntitySystem.Get<AtmosphereSystem>().Gases;
foreach (var gas in _gasData)
{
GasOptions.AddItem($"{gas.Name} ({gas.ID})");
}
GasOptions.OnItemSelected += eventArgs => GasOptions.SelectId(eventArgs.Id);
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_gridData == null || _gasData == null)
return;
var gridList = _gridData.ToList();
var gridIndex = gridList[GridOptions.SelectedId].Index;
var gasList = _gasData.ToList();
var gasId = gasList[GasOptions.SelectedId].ID;
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"addgas {TileXSpin.Value} {TileYSpin.Value} {gridIndex} {gasId} {AmountSpin.Value}");
}
}
}

View File

@@ -1,15 +0,0 @@
<Control
xmlns="https://spacestation14.io"
xmlns:amc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:at="clr-namespace:Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab"
Margin="4"
MinSize="50 50">
<GridContainer Columns="4">
<amc:UICommandButton Text="{Loc Add Atmos}" Command="addatmos" WindowType="{x:Type at:AddAtmosWindow}" />
<amc:UICommandButton Text="{Loc Add Gas}" Command="addgas" WindowType="{x:Type at:AddGasWindow}" />
<amc:UICommandButton Text="{Loc Fill Gas}" Command="fillgas" WindowType="{x:Type at:FillGasWindow}" />
<amc:UICommandButton Text="{Loc Set Temperature}" Command="settemp"
WindowType="{x:Type at:SetTemperatureWindow}" />
</GridContainer>
</Control>

View File

@@ -1,12 +0,0 @@
#nullable enable
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab
{
[GenerateTypedNameReferences]
public partial class AtmosTab : Control
{
}
}

View File

@@ -1,21 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io" Title="{Loc Fill Gas}">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Grid}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Gas}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GasOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Amount}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="AmountSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<Button Name="SubmitButton" Text="{Loc Fill Gas}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,64 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.EntitySystems;
using Content.Shared.Atmos;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class FillGasWindow : SS14Window
{
private IEnumerable<IMapGrid>? _gridData;
private IEnumerable<GasPrototype>? _gasData;
protected override void EnteredTree()
{
// Fill out grids
_gridData = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Index != 0);
foreach (var grid in _gridData)
{
var playerGrid = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity?.Transform.GridID;
GridOptions.AddItem($"{grid.Index} {(playerGrid == grid.Index ? " (Current)" : "")}");
}
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
// Fill out gases
_gasData = EntitySystem.Get<AtmosphereSystem>().Gases;
foreach (var gas in _gasData)
{
GasOptions.AddItem($"{gas.Name} ({gas.ID})");
}
GasOptions.OnItemSelected += eventArgs => GasOptions.SelectId(eventArgs.Id);
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_gridData == null || _gasData == null)
return;
var gridList = _gridData.ToList();
var gridIndex = gridList[GridOptions.SelectedId].Index;
var gasList = _gasData.ToList();
var gasId = gasList[GasOptions.SelectedId].ID;
IoCManager.Resolve<IClientConsoleHost>().ExecuteCommand(
$"fillgas {gridIndex} {gasId} {AmountSpin.Value}");
}
}
}

View File

@@ -1,26 +0,0 @@
<SS14Window
xmlns="https://spacestation14.io" Title="{Loc Set Temperature}">
<VBoxContainer>
<HBoxContainer>
<Label Text="{Loc Grid}" MinSize="100 0" />
<Control MinSize="50 0" />
<OptionButton Name="GridOptions" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc TileX}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="TileXSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc TileY}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="TileYSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<HBoxContainer>
<Label Text="{Loc Temperature}" MinSize="100 0" />
<Control MinSize="50 0" />
<SpinBox Name="TemperatureSpin" MinSize="100 0" HorizontalExpand="True" />
</HBoxContainer>
<Button Name="SubmitButton" Text="{Loc Set Temperature}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,44 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.Player;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Map;
namespace Content.Client.UserInterface.AdminMenu.Tabs.AtmosTab
{
[GenerateTypedNameReferences]
[UsedImplicitly]
public partial class SetTemperatureWindow : SS14Window
{
private IEnumerable<IMapGrid>? _data;
protected override void EnteredTree()
{
_data = IoCManager.Resolve<IMapManager>().GetAllGrids().Where(g => (int) g.Index != 0);
foreach (var grid in _data)
{
var playerGrid = IoCManager.Resolve<IPlayerManager>().LocalPlayer?.ControlledEntity?.Transform.GridID;
GridOptions.AddItem($"{grid.Index} {(playerGrid == grid.Index ? " (Current)" : "")}");
}
GridOptions.OnItemSelected += eventArgs => GridOptions.SelectId(eventArgs.Id);
SubmitButton.OnPressed += SubmitButtonOnOnPressed;
}
private void SubmitButtonOnOnPressed(BaseButton.ButtonEventArgs obj)
{
if (_data == null)
return;
var dataList = _data.ToList();
var selectedGrid = dataList[GridOptions.SelectedId].Index;
IoCManager.Resolve<IClientConsoleHost>()
.ExecuteCommand($"settemp {TileXSpin.Value} {TileYSpin.Value} {selectedGrid} {TemperatureSpin.Value}");
}
}
}

View File

@@ -1,14 +0,0 @@
<Control xmlns="https://spacestation14.io">
<VBoxContainer>
<HBoxContainer>
<Label Name="PlayerCount" HorizontalExpand="True" SizeFlagsStretchRatio="0.7"
Text="{Loc Player Count}" />
<Button Name="RefreshButton" HorizontalExpand="True" SizeFlagsStretchRatio="0.3"
Text="{Loc Refresh}" />
</HBoxContainer>
<Control MinSize="0 5" />
<ScrollContainer HorizontalExpand="True" VerticalExpand="True">
<VBoxContainer Name="PlayerList" />
</ScrollContainer>
</VBoxContainer>
</Control>

View File

@@ -1,166 +0,0 @@
#nullable enable
using System.Collections.Generic;
using Content.Shared.Administration.AdminMenu;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface.AdminMenu.Tabs
{
[GenerateTypedNameReferences]
public partial class PlayerTab : Control
{
public delegate void PlayerListRefresh();
public event PlayerListRefresh? OnPlayerListRefresh;
public PlayerTab()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
RefreshButton.OnPressed += (_) => OnPlayerListRefresh?.Invoke();
}
protected override void EnteredTree()
{
OnPlayerListRefresh?.Invoke();
}
public void RefreshPlayerList(IEnumerable<AdminMenuPlayerListMessage.PlayerInfo> players)
{
PlayerList.RemoveAllChildren();
var playerManager = IoCManager.Resolve<IPlayerManager>();
PlayerCount.Text = $"Players: {playerManager.PlayerCount}";
var altColor = Color.FromHex("#292B38");
var defaultColor = Color.FromHex("#2F2F3B");
var header = new HBoxContainer
{
HorizontalExpand = true,
SeparationOverride = 4,
Children =
{
new Label
{
Text = "Username",
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true
},
new VSeparator(),
new Label
{
Text = "Character",
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true
},
new VSeparator(),
new Label()
{
Text = "Antagonist",
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true,
}
}
};
PlayerList.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = altColor,
},
Children =
{
header
}
});
PlayerList.AddChild(new HSeparator());
var useAltColor = false;
foreach (var player in players)
{
var hBox = new HBoxContainer
{
HorizontalExpand = true,
SeparationOverride = 4,
Children =
{
new Label
{
Text = player.Username,
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true,
ClipText = true
},
new VSeparator(),
new Label
{
Text = player.CharacterName,
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true,
ClipText = true
},
new VSeparator(),
new Label()
{
Text = player.Antag ? "YES" : "NO",
SizeFlagsStretchRatio = 2f,
HorizontalExpand = true,
ClipText = true,
}
}
};
PlayerList.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = useAltColor ? altColor : defaultColor,
},
Children =
{
hBox
}
});
useAltColor ^= true;
}
}
private static readonly Color SeparatorColor = Color.FromHex("#3D4059");
private class VSeparator : PanelContainer
{
public VSeparator()
{
MinSize = (2, 5);
AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = SeparatorColor
}
});
}
}
private class HSeparator : Control
{
public HSeparator()
{
AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = SeparatorColor,
ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2
}
});
}
}
}
}

View File

@@ -1,12 +0,0 @@
<Control
xmlns="https://spacestation14.io"
xmlns:amc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
Margin="4"
MinSize="50 50">
<GridContainer
Columns="4">
<amc:CommandButton Command="startround" Text="{Loc Start Round}" />
<amc:CommandButton Command="endround" Text="{Loc End Round}" />
<amc:CommandButton Command="restartround" Text="{Loc Restart Round}" />
</GridContainer>
</Control>

View File

@@ -1,12 +0,0 @@
#nullable enable
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.AdminMenu.Tabs
{
[GenerateTypedNameReferences]
public partial class RoundTab : Control
{
}
}

View File

@@ -1,11 +0,0 @@
<Control
xmlns="https://spacestation14.io"
xmlns:amc="clr-namespace:Content.Client.UserInterface.AdminMenu.CustomControls"
Margin="4"
MinSize="50 50">
<GridContainer
Columns="4" >
<amc:CommandButton Command="restart" Text="{Loc Reboot}"></amc:CommandButton>
<amc:CommandButton Command="shutdown" Text="{Loc Shutdown}"></amc:CommandButton>
</GridContainer>
</Control>

View File

@@ -1,12 +0,0 @@
#nullable enable
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.AdminMenu.Tabs
{
[GenerateTypedNameReferences]
public partial class ServerTab : Control
{
}
}

View File

@@ -1,94 +0,0 @@
using Content.Client.Chat;
using Content.Client.Interfaces.Chat;
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
/// <summary>
/// The status effects display on the right side of the screen.
/// </summary>
public sealed class AlertsUI : Control
{
public const float ChatSeparation = 38f;
public GridContainer Grid { get; }
public AlertsUI()
{
LayoutContainer.SetGrowHorizontal(this, LayoutContainer.GrowDirection.Begin);
LayoutContainer.SetGrowVertical(this, LayoutContainer.GrowDirection.End);
LayoutContainer.SetAnchorTop(this, 0f);
LayoutContainer.SetAnchorRight(this, 1f);
LayoutContainer.SetAnchorBottom(this, 1f);
LayoutContainer.SetMarginBottom(this, -180);
LayoutContainer.SetMarginTop(this, 250);
LayoutContainer.SetMarginRight(this, -10);
var panelContainer = new PanelContainer
{
StyleClasses = {StyleNano.StyleClassTransparentBorderedWindowPanel},
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Top
};
AddChild(panelContainer);
Grid = new GridContainer
{
MaxGridHeight = 64,
ExpandBackwards = true
};
panelContainer.AddChild(Grid);
MinSize = (64, 64);
}
protected override void EnteredTree()
{
base.EnteredTree();
var _chatManager = IoCManager.Resolve<IChatManager>();
_chatManager.OnChatBoxResized += OnChatResized;
OnChatResized(new ChatResizedEventArgs(ChatBox.InitialChatBottom));
}
protected override void ExitedTree()
{
base.ExitedTree();
var _chatManager = IoCManager.Resolve<IChatManager>();
_chatManager.OnChatBoxResized -= OnChatResized;
}
private void OnChatResized(ChatResizedEventArgs chatResizedEventArgs)
{
// resize us to fit just below the chatbox
var _chatManager = IoCManager.Resolve<IChatManager>();
if (_chatManager.CurrentChatBox != null)
{
LayoutContainer.SetMarginTop(this, chatResizedEventArgs.NewBottom + ChatSeparation);
}
else
{
LayoutContainer.SetMarginTop(this, 250);
}
}
// This makes no sense but I'm leaving it in place in case I break anything by removing it.
protected override void Resized()
{
// TODO: Can rework this once https://github.com/space-wizards/RobustToolbox/issues/1392 is done,
// this is here because there isn't currently a good way to allow the grid to adjust its height based
// on constraints, otherwise we would use anchors to lay it out
base.Resized();
Grid.MaxGridHeight = Height;
}
protected override void UIScaleChanged()
{
Grid.MaxGridHeight = Height;
base.UIScaleChanged();
}
}
}

View File

@@ -1,5 +1,6 @@
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Client.Message;
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Shared.GameObjects.Components.Atmos.GasTank;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;

View File

@@ -1,482 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.GameObjects.Components.Cargo;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Prototypes.Cargo;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.Controls.BaseButton;
namespace Content.Client.UserInterface.Cargo
{
public class CargoConsoleMenu : SS14Window
{
public CargoConsoleBoundUserInterface Owner { get; private set; }
public event Action<ButtonEventArgs>? OnItemSelected;
public event Action<ButtonEventArgs>? OnOrderApproved;
public event Action<ButtonEventArgs>? OnOrderCanceled;
private readonly List<string> _categoryStrings = new();
private Label _accountNameLabel { get; set; }
private Label _pointsLabel { get; set; }
private Label _shuttleStatusLabel { get; set; }
private Label _shuttleCapacityLabel { get; set; }
private VBoxContainer _requests { get; set; }
private VBoxContainer _orders { get; set; }
private OptionButton _categories { get; set; }
private LineEdit _searchBar { get; set; }
public VBoxContainer Products { get; set; }
public Button CallShuttleButton { get; set; }
public Button PermissionsButton { get; set; }
private string? _category = null;
public CargoConsoleMenu(CargoConsoleBoundUserInterface owner)
{
SetSize = MinSize = (400, 600);
IoCManager.InjectDependencies(this);
Owner = owner;
if (Owner.RequestOnly)
Title = Loc.GetString("Cargo Request Console");
else
Title = Loc.GetString("Cargo Shuttle Console");
var rows = new VBoxContainer();
var accountName = new HBoxContainer();
var accountNameLabel = new Label {
Text = Loc.GetString("Account Name: "),
StyleClasses = { StyleNano.StyleClassLabelKeyText }
};
_accountNameLabel = new Label {
Text = "None" //Owner.Bank.Account.Name
};
accountName.AddChild(accountNameLabel);
accountName.AddChild(_accountNameLabel);
rows.AddChild(accountName);
var points = new HBoxContainer();
var pointsLabel = new Label
{
Text = Loc.GetString("Points: "),
StyleClasses = { StyleNano.StyleClassLabelKeyText }
};
_pointsLabel = new Label
{
Text = "0" //Owner.Bank.Account.Balance.ToString()
};
points.AddChild(pointsLabel);
points.AddChild(_pointsLabel);
rows.AddChild(points);
var shuttleStatus = new HBoxContainer();
var shuttleStatusLabel = new Label
{
Text = Loc.GetString("Shuttle Status: "),
StyleClasses = { StyleNano.StyleClassLabelKeyText }
};
_shuttleStatusLabel = new Label
{
Text = Loc.GetString("Away") // Shuttle.Status
};
shuttleStatus.AddChild(shuttleStatusLabel);
shuttleStatus.AddChild(_shuttleStatusLabel);
rows.AddChild(shuttleStatus);
var shuttleCapacity = new HBoxContainer();
var shuttleCapacityLabel = new Label
{
Text = Loc.GetString("Order Capacity: "),
StyleClasses = { StyleNano.StyleClassLabelKeyText }
};
_shuttleCapacityLabel = new Label
{
Text = "0/20"
};
shuttleCapacity.AddChild(shuttleCapacityLabel);
shuttleCapacity.AddChild(_shuttleCapacityLabel);
rows.AddChild(shuttleCapacity);
var buttons = new HBoxContainer();
CallShuttleButton = new Button()
{
//Text = Loc.GetString("Call Shuttle"),
Text = Loc.GetString("Activate Telepad"), //Shuttle code pending
TextAlign = Label.AlignMode.Center,
HorizontalExpand = true
};
PermissionsButton = new Button()
{
Text = Loc.GetString("Permissions"),
TextAlign = Label.AlignMode.Center
};
buttons.AddChild(CallShuttleButton);
buttons.AddChild(PermissionsButton);
rows.AddChild(buttons);
var category = new HBoxContainer();
_categories = new OptionButton
{
Prefix = Loc.GetString("Categories: "),
HorizontalExpand = true,
SizeFlagsStretchRatio = 1
};
_searchBar = new LineEdit
{
PlaceHolder = Loc.GetString("Search"),
HorizontalExpand = true,
SizeFlagsStretchRatio = 1
};
category.AddChild(_categories);
category.AddChild(_searchBar);
rows.AddChild(category);
var products = new ScrollContainer()
{
HorizontalExpand = true,
VerticalExpand = true,
SizeFlagsStretchRatio = 6
};
Products = new VBoxContainer()
{
HorizontalExpand = true,
VerticalExpand = true
};
products.AddChild(Products);
rows.AddChild(products);
var requestsAndOrders = new PanelContainer
{
VerticalExpand = true,
SizeFlagsStretchRatio = 6,
PanelOverride = new StyleBoxFlat { BackgroundColor = Color.Black }
};
var orderScrollBox = new ScrollContainer
{
VerticalExpand = true
};
var rAndOVBox = new VBoxContainer();
var requestsLabel = new Label { Text = Loc.GetString("Requests") };
_requests = new VBoxContainer // replace with scroll box so that approval buttons can be added
{
StyleClasses = { "transparentItemList" },
VerticalExpand = true,
SizeFlagsStretchRatio = 1,
};
var ordersLabel = new Label { Text = Loc.GetString("Orders") };
_orders = new VBoxContainer
{
StyleClasses = { "transparentItemList" },
VerticalExpand = true,
SizeFlagsStretchRatio = 1,
};
rAndOVBox.AddChild(requestsLabel);
rAndOVBox.AddChild(_requests);
rAndOVBox.AddChild(ordersLabel);
rAndOVBox.AddChild(_orders);
orderScrollBox.AddChild(rAndOVBox);
requestsAndOrders.AddChild(orderScrollBox);
rows.AddChild(requestsAndOrders);
rows.AddChild(new TextureButton
{
VerticalExpand = true,
});
Contents.AddChild(rows);
CallShuttleButton.OnPressed += OnCallShuttleButtonPressed;
_searchBar.OnTextChanged += OnSearchBarTextChanged;
_categories.OnItemSelected += OnCategoryItemSelected;
}
private void OnCallShuttleButtonPressed(ButtonEventArgs args)
{
}
private void OnCategoryItemSelected(OptionButton.ItemSelectedEventArgs args)
{
SetCategoryText(args.Id);
PopulateProducts();
}
private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args)
{
PopulateProducts();
}
private void SetCategoryText(int id)
{
if (id == 0)
_category = null;
else
_category = _categoryStrings[id];
_categories.SelectId(id);
}
/// <summary>
/// Populates the list of products that will actually be shown, using the current filters.
/// </summary>
public void PopulateProducts()
{
Products.RemoveAllChildren();
if (Owner.Market == null)
{
return;
}
var search = _searchBar.Text.Trim().ToLowerInvariant();
foreach (var prototype in Owner.Market.Products)
{
// if no search or category
// else if search
// else if category and not search
if ((search.Length == 0 && _category == null) ||
(search.Length != 0 && prototype.Name.ToLowerInvariant().Contains(search)) ||
(search.Length == 0 && _category != null && prototype.Category.Equals(_category)))
{
var button = new CargoProductRow();
button.Product = prototype;
button.ProductName.Text = prototype.Name;
button.PointCost.Text = prototype.PointCost.ToString();
button.Icon.Texture = prototype.Icon.Frame0();
button.MainButton.OnPressed += (args) =>
{
OnItemSelected?.Invoke(args);
};
Products.AddChild(button);
}
}
}
/// <summary>
/// Populates the list of products that will actually be shown, using the current filters.
/// </summary>
public void PopulateCategories()
{
_categoryStrings.Clear();
_categories.Clear();
if (Owner.Market == null)
{
return;
}
_categoryStrings.Add(Loc.GetString("All"));
var search = _searchBar.Text.Trim().ToLowerInvariant();
foreach (var prototype in Owner.Market.Products)
{
if (!_categoryStrings.Contains(prototype.Category))
{
_categoryStrings.Add(Loc.GetString(prototype.Category));
}
}
_categoryStrings.Sort();
foreach (var str in _categoryStrings)
{
_categories.AddItem(str);
}
}
/// <summary>
/// Populates the list of orders and requests.
/// </summary>
public void PopulateOrders()
{
_orders.RemoveAllChildren();
_requests.RemoveAllChildren();
if (Owner.Orders == null || Owner.Market == null)
{
return;
}
foreach (var order in Owner.Orders.Orders)
{
var row = new CargoOrderRow
{
Order = order,
Icon = {Texture = Owner.Market.GetProduct(order.ProductId)?.Icon.Frame0()},
ProductName =
{
Text =
$"{Owner.Market.GetProduct(order.ProductId)?.Name} (x{order.Amount}) by {order.Requester}"
},
Description = {Text = $"Reasons: {order.Reason}"}
};
row.Cancel.OnPressed += (args) => { OnOrderCanceled?.Invoke(args); };
if (order.Approved)
{
row.Approve.Visible = false;
row.Cancel.Visible = false;
_orders.AddChild(row);
}
else
{
if (Owner.RequestOnly)
row.Approve.Visible = false;
else
row.Approve.OnPressed += (args) => { OnOrderApproved?.Invoke(args); };
_requests.AddChild(row);
}
}
}
public void Populate()
{
PopulateProducts();
PopulateCategories();
PopulateOrders();
}
public void UpdateCargoCapacity()
{
_shuttleCapacityLabel.Text = $"{Owner.ShuttleCapacity.CurrentCapacity}/{Owner.ShuttleCapacity.MaxCapacity}";
}
public void UpdateBankData()
{
_accountNameLabel.Text = Owner.BankName;
_pointsLabel.Text = Owner.BankBalance.ToString();
}
/// <summary>
/// Show/Hide Call Shuttle button and Approve buttons
/// </summary>
public void UpdateRequestOnly()
{
CallShuttleButton.Visible = !Owner.RequestOnly;
foreach (CargoOrderRow row in _requests.Children)
{
row.Approve.Visible = !Owner.RequestOnly;
}
}
}
internal class CargoProductRow : PanelContainer
{
public CargoProductPrototype? Product { get; set; }
public TextureRect Icon { get; private set; }
public Button MainButton { get; private set; }
public Label ProductName { get; private set; }
public Label PointCost { get; private set; }
public CargoProductRow()
{
HorizontalExpand = true;
MainButton = new Button
{
HorizontalExpand = true,
VerticalExpand = true
};
AddChild(MainButton);
var hBox = new HBoxContainer
{
HorizontalExpand = true
};
Icon = new TextureRect
{
MinSize = new Vector2(32.0f, 32.0f),
RectClipContent = true
};
hBox.AddChild(Icon);
ProductName = new Label
{
HorizontalExpand = true
};
hBox.AddChild(ProductName);
var panel = new PanelContainer
{
PanelOverride = new StyleBoxFlat { BackgroundColor = new Color(37, 37, 42) },
};
PointCost = new Label
{
MinSize = new Vector2(40.0f, 32.0f),
Align = Label.AlignMode.Right
};
panel.AddChild(PointCost);
hBox.AddChild(panel);
AddChild(hBox);
}
}
internal class CargoOrderRow : PanelContainer
{
public CargoOrderData? Order { get; set; }
public TextureRect Icon { get; private set; }
public Label ProductName { get; private set; }
public Label Description { get; private set; }
public BaseButton Approve { get; private set; }
public BaseButton Cancel { get; private set; }
public CargoOrderRow()
{
HorizontalExpand = true;
var hBox = new HBoxContainer
{
HorizontalExpand = true,
};
Icon = new TextureRect
{
MinSize = new Vector2(32.0f, 32.0f),
RectClipContent = true
};
hBox.AddChild(Icon);
var vBox = new VBoxContainer
{
HorizontalExpand = true,
VerticalExpand = true
};
ProductName = new Label
{
HorizontalExpand = true,
StyleClasses = { StyleNano.StyleClassLabelSubText },
ClipText = true
};
Description = new Label
{
HorizontalExpand = true,
StyleClasses = { StyleNano.StyleClassLabelSubText },
ClipText = true
};
vBox.AddChild(ProductName);
vBox.AddChild(Description);
hBox.AddChild(vBox);
Approve = new Button
{
Text = "Approve",
StyleClasses = { StyleNano.StyleClassLabelSubText }
};
hBox.AddChild(Approve);
Cancel = new Button
{
Text = "Cancel",
StyleClasses = { StyleNano.StyleClassLabelSubText }
};
hBox.AddChild(Cancel);
AddChild(hBox);
}
}
}

View File

@@ -1,60 +0,0 @@
using System.Collections.Generic;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.UserInterface.Cargo
{
class CargoConsoleOrderMenu : SS14Window
{
public LineEdit Requester { get; set; }
public LineEdit Reason { get; set; }
public SpinBox Amount { get; set; }
public Button SubmitButton { get; set; }
public CargoConsoleOrderMenu()
{
IoCManager.InjectDependencies(this);
Title = Loc.GetString("Order Form");
var vBox = new VBoxContainer();
var gridContainer = new GridContainer { Columns = 2 };
var requesterLabel = new Label { Text = Loc.GetString("Name:") };
Requester = new LineEdit();
gridContainer.AddChild(requesterLabel);
gridContainer.AddChild(Requester);
var reasonLabel = new Label { Text = Loc.GetString("Reason:") };
Reason = new LineEdit();
gridContainer.AddChild(reasonLabel);
gridContainer.AddChild(Reason);
var amountLabel = new Label { Text = Loc.GetString("Amount:") };
Amount = new SpinBox
{
HorizontalExpand = true,
Value = 1
};
Amount.SetButtons(new List<int>() { -3, -2, -1 }, new List<int>() { 1, 2, 3 });
Amount.IsValid = (n) => {
return (n > 0);
};
gridContainer.AddChild(amountLabel);
gridContainer.AddChild(Amount);
vBox.AddChild(gridContainer);
SubmitButton = new Button()
{
Text = Loc.GetString("OK"),
TextAlign = Label.AlignMode.Center,
};
vBox.AddChild(SubmitButton);
Contents.AddChild(vBox);
}
}
}

View File

@@ -1,46 +0,0 @@
using Content.Client.GameObjects.Components.Cargo;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.UserInterface.Cargo
{
public class GalacticBankSelectionMenu : SS14Window
{
private readonly ItemList _accounts;
private int _accountCount;
private string[] _accountNames = new string[] { };
private int[] _accountIds = new int[] { };
private int _selectedAccountId = -1;
public GalacticBankSelectionMenu(CargoConsoleBoundUserInterface owner)
{
MinSize = SetSize = (300, 300);
IoCManager.InjectDependencies(this);
Title = Loc.GetString("Galactic Bank Selection");
_accounts = new ItemList() { SelectMode = ItemList.ItemListSelectMode.Single };
Contents.AddChild(_accounts);
}
public void Populate(int accountCount, string[] accountNames, int[] accountIds, int selectedAccountId)
{
_accountCount = accountCount;
_accountNames = accountNames;
_accountIds = accountIds;
_selectedAccountId = selectedAccountId;
_accounts.Clear();
for (var i = 0; i < _accountCount; i++)
{
var id = _accountIds[i];
_accounts.AddItem($"ID: {id} || {_accountNames[i]}");
if (id == _selectedAccountId)
_accounts[id].Selected = true;
}
}
}
}

View File

@@ -1,298 +0,0 @@
using System.Linq;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.Interfaces;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
public class CharacterSetupGui : Control
{
private readonly VBoxContainer _charactersVBox;
private readonly Button _createNewCharacterButton;
private readonly IEntityManager _entityManager;
private readonly HumanoidProfileEditor _humanoidProfileEditor;
private readonly IClientPreferencesManager _preferencesManager;
public readonly Button CloseButton;
public readonly Button SaveButton;
public CharacterSetupGui(
IEntityManager entityManager,
IResourceCache resourceCache,
IClientPreferencesManager preferencesManager,
IPrototypeManager prototypeManager)
{
AddChild(new ParallaxControl());
_entityManager = entityManager;
_preferencesManager = preferencesManager;
var margin = new Control
{
Margin = new Thickness(20),
};
AddChild(margin);
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
var back = new StyleBoxTexture
{
Texture = panelTex,
Modulate = new Color(37, 37, 42)
};
back.SetPatchMargin(StyleBox.Margin.All, 10);
var panel = new PanelContainer
{
PanelOverride = back
};
margin.AddChild(panel);
var vBox = new VBoxContainer {SeparationOverride = 0};
margin.AddChild(vBox);
var topHBox = new HBoxContainer
{
MinSize = (0, 40),
Children =
{
new Label
{
Margin = new Thickness(8, 0, 0, 0),
Text = Loc.GetString("Character Setup"),
StyleClasses = {StyleNano.StyleClassLabelHeadingBigger},
VAlign = Label.VAlignMode.Center,
},
(SaveButton = new Button
{
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right,
Text = Loc.GetString("Save"),
StyleClasses = {StyleNano.StyleClassButtonBig},
}),
(CloseButton = new Button
{
Text = Loc.GetString("Close"),
StyleClasses = {StyleNano.StyleClassButtonBig},
})
}
};
vBox.AddChild(topHBox);
vBox.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = StyleNano.NanoGold,
ContentMarginTopOverride = 2
}
});
var hBox = new HBoxContainer
{
VerticalExpand = true,
SeparationOverride = 0
};
vBox.AddChild(hBox);
_charactersVBox = new VBoxContainer();
hBox.AddChild(new ScrollContainer
{
MinSize = (325, 0),
Margin = new Thickness(5, 5, 0, 0),
Children =
{
_charactersVBox
}
});
_createNewCharacterButton = new Button
{
Text = "Create new slot...",
};
_createNewCharacterButton.OnPressed += args =>
{
preferencesManager.CreateCharacter(HumanoidCharacterProfile.Random());
UpdateUI();
args.Event.Handle();
};
hBox.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = StyleNano.NanoGold},
MinSize = (2, 0)
});
_humanoidProfileEditor = new HumanoidProfileEditor(preferencesManager, prototypeManager, entityManager);
_humanoidProfileEditor.OnProfileChanged += ProfileChanged;
hBox.AddChild(_humanoidProfileEditor);
UpdateUI();
preferencesManager.OnServerDataLoaded += UpdateUI;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_preferencesManager.OnServerDataLoaded -= UpdateUI;
}
public void Save() => _humanoidProfileEditor.Save();
private void ProfileChanged(ICharacterProfile profile, int profileSlot)
{
_humanoidProfileEditor.UpdateControls();
UpdateUI();
}
private void UpdateUI()
{
var numberOfFullSlots = 0;
var characterButtonsGroup = new ButtonGroup();
_charactersVBox.RemoveAllChildren();
if (!_preferencesManager.ServerDataLoaded)
{
return;
}
_createNewCharacterButton.ToolTip =
$"A maximum of {_preferencesManager.Settings!.MaxCharacterSlots} characters are allowed.";
foreach (var (slot, character) in _preferencesManager.Preferences!.Characters)
{
if (character is null)
{
continue;
}
numberOfFullSlots++;
var characterPickerButton = new CharacterPickerButton(_entityManager,
_preferencesManager,
characterButtonsGroup,
character);
_charactersVBox.AddChild(characterPickerButton);
var characterIndexCopy = slot;
characterPickerButton.OnPressed += args =>
{
_humanoidProfileEditor.Profile = (HumanoidCharacterProfile) character;
_humanoidProfileEditor.CharacterSlot = characterIndexCopy;
_humanoidProfileEditor.UpdateControls();
_preferencesManager.SelectCharacter(character);
UpdateUI();
args.Event.Handle();
};
}
_createNewCharacterButton.Disabled =
numberOfFullSlots >= _preferencesManager.Settings.MaxCharacterSlots;
_charactersVBox.AddChild(_createNewCharacterButton);
}
private class CharacterPickerButton : ContainerButton
{
private IEntity _previewDummy;
public CharacterPickerButton(
IEntityManager entityManager,
IClientPreferencesManager preferencesManager,
ButtonGroup group,
ICharacterProfile profile)
{
AddStyleClass(StyleClassButton);
ToggleMode = true;
Group = group;
_previewDummy = entityManager.SpawnEntity("HumanMob_Dummy", MapCoordinates.Nullspace);
_previewDummy.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(profile);
var humanoid = profile as HumanoidCharacterProfile;
if (humanoid != null)
{
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, humanoid);
}
var isSelectedCharacter = profile == preferencesManager.Preferences?.SelectedCharacter;
if (isSelectedCharacter)
Pressed = true;
var view = new SpriteView
{
Sprite = _previewDummy.GetComponent<SpriteComponent>(),
Scale = (2, 2),
OverrideDirection = Direction.South
};
var description = profile.Name;
var highPriorityJob = humanoid?.JobPriorities.SingleOrDefault(p => p.Value == JobPriority.High).Key;
if (highPriorityJob != null)
{
var jobName = IoCManager.Resolve<IPrototypeManager>().Index<JobPrototype>(highPriorityJob).Name;
description = $"{description}\n{jobName}";
}
var descriptionLabel = new Label
{
Text = description,
ClipText = true,
HorizontalExpand = true
};
var deleteButton = new Button
{
Text = "Delete",
Visible = !isSelectedCharacter,
};
deleteButton.OnPressed += _ =>
{
Parent?.RemoveChild(this);
preferencesManager.DeleteCharacter(profile);
};
var internalHBox = new HBoxContainer
{
HorizontalExpand = true,
SeparationOverride = 0,
Children =
{
view,
descriptionLabel,
deleteButton
}
};
AddChild(internalHBox);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_previewDummy.Delete();
_previewDummy = null!;
}
}
}
}

View File

@@ -1,237 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Vector2 = Robust.Shared.Maths.Vector2;
namespace Content.Client.UserInterface.ContextMenu
{
public abstract class ContextMenuElement : Control
{
private static readonly Color HoverColor = Color.DarkSlateGray;
protected internal readonly ContextMenuPopup? ParentMenu;
protected ContextMenuElement(ContextMenuPopup? parentMenu)
{
ParentMenu = parentMenu;
MouseFilter = MouseFilterMode.Stop;
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (UserInterfaceManager.CurrentlyHovered == this)
{
handle.DrawRect(PixelSizeBox, HoverColor);
}
}
}
public sealed class SingleContextElement : ContextMenuElement
{
public event Action? OnMouseHovering;
public event Action? OnExitedTree;
public IEntity ContextEntity{ get; }
public readonly StackContextElement? Pre;
public ISpriteComponent? SpriteComp { get; }
public InteractionOutlineComponent? OutlineComponent { get; }
public int OriginalDrawDepth { get; }
public bool DrawOutline { get; set; }
public SingleContextElement(IEntity entity, StackContextElement? pre, ContextMenuPopup? parentMenu) : base(parentMenu)
{
Pre = pre;
ContextEntity = entity;
if (ContextEntity.TryGetComponent(out ISpriteComponent? sprite))
{
SpriteComp = sprite;
OriginalDrawDepth = SpriteComp.DrawDepth;
}
OutlineComponent = ContextEntity.GetComponentOrNull<InteractionOutlineComponent>();
AddChild(
new HBoxContainer
{
Children =
{
new LayoutContainer
{
Children = { new SpriteView { Sprite = SpriteComp } }
},
new Label
{
Text = Loc.GetString(UserInterfaceManager.DebugMonitors.Visible ? $"{ContextEntity.Name} ({ContextEntity.Uid})" : ContextEntity.Name)
}
}, Margin = new Thickness(0,0,10,0)
}
);
}
protected override void Draw(DrawingHandleScreen handle)
{
base.Draw(handle);
if (UserInterfaceManager.CurrentlyHovered == this)
{
OnMouseHovering?.Invoke();
}
}
protected override void ExitedTree()
{
OnExitedTree?.Invoke();
base.ExitedTree();
}
}
public sealed class StackContextElement : ContextMenuElement
{
public event Action? OnExitedTree;
public readonly TimeSpan HoverDelay = TimeSpan.FromSeconds(0.2);
public HashSet<IEntity> ContextEntities { get; }
public readonly StackContextElement? Pre;
private readonly SpriteView _spriteView;
private readonly Label _label;
public int EntitiesCount => ContextEntities.Count;
public StackContextElement(IEnumerable<IEntity> entities, StackContextElement? pre, ContextMenuPopup? parentMenu)
: base(parentMenu)
{
Pre = pre;
ContextEntities = new(entities);
_spriteView = new SpriteView
{
Sprite = ContextEntities.First().GetComponent<ISpriteComponent>()
};
_label = new Label
{
Text = Loc.GetString(ContextEntities.Count.ToString()),
StyleClasses = { StyleNano.StyleClassContextMenuCount }
};
LayoutContainer.SetAnchorPreset(_label, LayoutContainer.LayoutPreset.BottomRight);
LayoutContainer.SetGrowHorizontal(_label, LayoutContainer.GrowDirection.Begin);
LayoutContainer.SetGrowVertical(_label, LayoutContainer.GrowDirection.Begin);
AddChild(
new HBoxContainer()
{
SeparationOverride = 6,
Children =
{
new LayoutContainer { Children = { _spriteView, _label } },
new HBoxContainer()
{
SeparationOverride = 6,
Children =
{
new Label
{
Text = Loc.GetString(ContextEntities.First().Name)
},
new TextureRect
{
Texture = IoCManager.Resolve<IResourceCache>().GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png"),
TextureScale = (0.5f, 0.5f),
Stretch = TextureRect.StretchMode.KeepCentered,
}
}
}
}, Margin = new Thickness(0,0,10,0)
}
);
}
protected override void ExitedTree()
{
OnExitedTree?.Invoke();
base.ExitedTree();
}
public void RemoveEntity(IEntity entity)
{
ContextEntities.Remove(entity);
_label.Text = Loc.GetString(ContextEntities.Count.ToString());
_spriteView.Sprite = ContextEntities.FirstOrDefault(e => !e.Deleted)?.GetComponent<ISpriteComponent>();
}
}
public sealed class ContextMenuPopup : Popup
{
private static readonly Color DefaultColor = Color.FromHex("#1116");
private static readonly Color MarginColor = Color.FromHex("#222E");
private const int MaxItemsBeforeScroll = 10;
private const int MarginSizeBetweenElements = 2;
public VBoxContainer List { get; }
public int Depth { get; }
public ContextMenuPopup(int depth = 0)
{
Depth = depth;
AddChild(new ScrollContainer
{
HScrollEnabled = false,
Children = { new PanelContainer
{
Children = { (List = new VBoxContainer()) },
PanelOverride = new StyleBoxFlat { BackgroundColor = MarginColor }
}}
});
}
public void AddToMenu(ContextMenuElement element)
{
List.AddChild(new PanelContainer
{
Children = { element },
Margin = new Thickness(0,0,0, MarginSizeBetweenElements),
PanelOverride = new StyleBoxFlat {BackgroundColor = DefaultColor}
});
}
public void RemoveFromMenu(ContextMenuElement element)
{
if (element.Parent != null)
{
List.RemoveChild(element.Parent);
InvalidateMeasure();
}
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
if (List.ChildCount == 0)
{
return Vector2.Zero;
}
List.Measure(availableSize);
var listSize = List.DesiredSize;
if (List.ChildCount < MaxItemsBeforeScroll)
{
return listSize;
}
listSize.Y = MaxItemsBeforeScroll * 32 + MaxItemsBeforeScroll * MarginSizeBetweenElements;
return listSize;
}
}
}

View File

@@ -1,265 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface.ContextMenu
{
public interface IContextMenuView : IDisposable
{
Dictionary<IEntity, ContextMenuElement> Elements { get; set; }
Stack<ContextMenuPopup> Menus { get; }
event EventHandler<(GUIBoundKeyEventArgs, SingleContextElement)>? OnKeyBindDownSingle;
event EventHandler<SingleContextElement>? OnMouseEnteredSingle;
event EventHandler<SingleContextElement>? OnMouseExitedSingle;
event EventHandler<SingleContextElement>? OnMouseHoveringSingle;
event EventHandler<(GUIBoundKeyEventArgs, StackContextElement)>? OnKeyBindDownStack;
event EventHandler<StackContextElement>? OnMouseEnteredStack;
event EventHandler<ContextMenuElement>? OnExitedTree;
event EventHandler? OnCloseRootMenu;
event EventHandler<int>? OnCloseChildMenu;
void UpdateParents(ContextMenuElement element);
void RemoveEntity(IEntity element);
void AddRootMenu(List<IEntity> entities);
void AddChildMenu(IEnumerable<IEntity> entities, Vector2 position, StackContextElement? stack);
void CloseContextPopups(int depth);
void CloseContextPopups();
void OnGroupingContextMenuChanged(int obj);
}
public partial class ContextMenuView : IContextMenuView
{
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
public Stack<ContextMenuPopup> Menus { get; }
public Dictionary<IEntity, ContextMenuElement> Elements { get; set; }
public event EventHandler<(GUIBoundKeyEventArgs, SingleContextElement)>? OnKeyBindDownSingle;
public event EventHandler<SingleContextElement>? OnMouseEnteredSingle;
public event EventHandler<SingleContextElement>? OnMouseExitedSingle;
public event EventHandler<SingleContextElement>? OnMouseHoveringSingle;
public event EventHandler<(GUIBoundKeyEventArgs, StackContextElement)>? OnKeyBindDownStack;
public event EventHandler<StackContextElement>? OnMouseEnteredStack;
public event EventHandler<ContextMenuElement>? OnExitedTree;
public event EventHandler? OnCloseRootMenu;
public event EventHandler<int>? OnCloseChildMenu;
public ContextMenuView()
{
IoCManager.InjectDependencies(this);
Menus = new Stack<ContextMenuPopup>();
Elements = new Dictionary<IEntity, ContextMenuElement>();
}
public void AddRootMenu(List<IEntity> entities)
{
Elements = new Dictionary<IEntity, ContextMenuElement>(entities.Count);
var rootContextMenu = new ContextMenuPopup();
rootContextMenu.OnPopupHide += () => OnCloseRootMenu?.Invoke(this, EventArgs.Empty);
Menus.Push(rootContextMenu);
var entitySpriteStates = GroupEntities(entities);
var orderedStates = entitySpriteStates.ToList();
orderedStates.Sort((x, y) => string.CompareOrdinal(x.First().Prototype!.Name, y.First().Prototype!.Name));
AddToUI(orderedStates);
_userInterfaceManager.ModalRoot.AddChild(rootContextMenu);
var size = rootContextMenu.List.CombinedMinimumSize;
var box = UIBox2.FromDimensions(_userInterfaceManager.MousePositionScaled.Position, size);
rootContextMenu.Open(box);
}
public void AddChildMenu(IEnumerable<IEntity> entities, Vector2 position, StackContextElement? stack)
{
if (stack == null) return;
var newDepth = stack.ParentMenu?.Depth + 1 ?? 1;
var childContextMenu = new ContextMenuPopup(newDepth);
Menus.Push(childContextMenu);
var orderedStates = GroupEntities(entities, newDepth);
AddToUI(orderedStates, stack);
_userInterfaceManager.ModalRoot.AddChild(childContextMenu);
var size = childContextMenu.List.CombinedMinimumSize;
childContextMenu.Open(UIBox2.FromDimensions(position + (stack.Width, 0), size));
}
private void AddToUI(List<List<IEntity>> entities, StackContextElement? stack = null)
{
if (entities.Count == 1)
{
foreach (var entity in entities[0])
{
AddSingleContextElement(entity, stack);
}
}
else
{
foreach (var entity in entities)
{
if (entity.Count == 1)
{
AddSingleContextElement(entity[0], stack);
}
else
{
AddStackContextElement(entity, stack);
}
}
}
}
private void AddSingleContextElement(IEntity entity, StackContextElement? pre)
{
if (Menus.TryPeek(out var menu))
{
var single = new SingleContextElement(entity, pre, menu);
single.OnKeyBindDown += args => OnKeyBindDownSingle?.Invoke(this, (args, single));
single.OnMouseEntered += _ => OnMouseEnteredSingle?.Invoke(this, single);
single.OnMouseExited += _ => OnMouseExitedSingle?.Invoke(this, single);
single.OnMouseHovering += () => OnMouseHoveringSingle?.Invoke(this, single);
single.OnExitedTree += () => OnExitedTree?.Invoke(this, single);
UpdateElements(entity, single);
menu.AddToMenu(single);
}
}
private void AddStackContextElement(IEnumerable<IEntity> entities, StackContextElement? pre)
{
if (Menus.TryPeek(out var menu))
{
var stack = new StackContextElement(entities, pre, menu);
stack.OnKeyBindDown += args => OnKeyBindDownStack?.Invoke(this, (args, stack));
stack.OnMouseEntered += _ => OnMouseEnteredStack?.Invoke(this, stack);
stack.OnExitedTree += () => OnExitedTree?.Invoke(this, stack);
foreach (var entity in entities)
{
UpdateElements(entity, stack);
}
menu.AddToMenu(stack);
}
}
private void UpdateElements(IEntity entity, ContextMenuElement element)
{
if (Elements.ContainsKey(entity))
{
Elements[entity] = element;
}
else
{
Elements.Add(entity, element);
}
}
private void RemoveFromUI(ContextMenuElement element)
{
var menu = element.ParentMenu;
if (menu != null)
{
menu.RemoveFromMenu(element);
if (menu.List.ChildCount == 0)
{
OnCloseChildMenu?.Invoke(this, menu.Depth - 1);
}
}
}
public void RemoveEntity(IEntity entity)
{
var element = Elements[entity];
switch (element)
{
case SingleContextElement singleContextElement:
RemoveFromUI(singleContextElement);
UpdateBranch(entity, singleContextElement.Pre);
break;
case StackContextElement stackContextElement:
stackContextElement.RemoveEntity(entity);
if (stackContextElement.EntitiesCount == 0)
{
RemoveFromUI(stackContextElement);
}
UpdateBranch(entity, stackContextElement.Pre);
break;
default:
throw new ArgumentOutOfRangeException(nameof(element));
}
Elements.Remove(entity);
}
private void UpdateBranch(IEntity entity, StackContextElement? stack)
{
while (stack != null)
{
stack.RemoveEntity(entity);
if (stack.EntitiesCount == 0)
{
RemoveFromUI(stack);
}
stack = stack.Pre;
}
}
public void UpdateParents(ContextMenuElement element)
{
switch (element)
{
case SingleContextElement singleContextElement:
if (singleContextElement.Pre != null)
{
Elements[singleContextElement.ContextEntity] = singleContextElement.Pre;
}
break;
case StackContextElement stackContextElement:
if (stackContextElement.Pre != null)
{
foreach (var entity in stackContextElement.ContextEntities)
{
Elements[entity] = stackContextElement.Pre;
}
}
break;
default:
throw new ArgumentOutOfRangeException(nameof(element));
}
}
public void CloseContextPopups()
{
while (Menus.Count > 0)
{
Menus.Pop().Dispose();
}
Elements.Clear();
}
public void CloseContextPopups(int depth)
{
while (Menus.Count > 0 && Menus.Peek().Depth > depth)
{
Menus.Pop().Dispose();
}
}
public void Dispose()
{
CloseContextPopups();
}
}
}

View File

@@ -1,118 +0,0 @@
#nullable enable
using System;
using System.Collections.Generic;
using System.Linq;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
namespace Content.Client.UserInterface.ContextMenu
{
public partial class ContextMenuView
{
public const int GroupingTypesCount = 2;
private int GroupingContextMenuType { get; set; }
public void OnGroupingContextMenuChanged(int obj)
{
CloseContextPopups();
GroupingContextMenuType = obj;
}
private List<List<IEntity>> GroupEntities(IEnumerable<IEntity> entities, int depth = 0)
{
if (GroupingContextMenuType == 0)
{
var newEntities = entities.GroupBy(e => e, new PrototypeContextMenuComparer()).ToList();
return newEntities.Select(grp => grp.ToList()).ToList();
}
else
{
var newEntities = entities.GroupBy(e => e, new PrototypeAndStatesContextMenuComparer(depth)).ToList();
return newEntities.Select(grp => grp.ToList()).ToList();
}
}
private sealed class PrototypeAndStatesContextMenuComparer : IEqualityComparer<IEntity>
{
private static readonly List<Func<IEntity, IEntity, bool>> EqualsList = new()
{
(a, b) => a.Prototype!.ID == b.Prototype!.ID,
(a, b) =>
{
var xStates = a.GetComponent<ISpriteComponent>().AllLayers.Where(e => e.Visible).Select(s => s.RsiState.Name);
var yStates = b.GetComponent<ISpriteComponent>().AllLayers.Where(e => e.Visible).Select(s => s.RsiState.Name);
return xStates.OrderBy(t => t).SequenceEqual(yStates.OrderBy(t => t));
},
};
private static readonly List<Func<IEntity, int>> GetHashCodeList = new()
{
e => EqualityComparer<string>.Default.GetHashCode(e.Prototype!.ID),
e =>
{
var hash = 0;
foreach (var element in e.GetComponent<ISpriteComponent>().AllLayers.Where(obj => obj.Visible).Select(s => s.RsiState.Name))
{
hash ^= EqualityComparer<string>.Default.GetHashCode(element!);
}
return hash;
},
};
private static int Count => EqualsList.Count - 1;
private readonly int _depth;
public PrototypeAndStatesContextMenuComparer(int step = 0)
{
_depth = step > Count ? Count : step;
}
public bool Equals(IEntity? x, IEntity? y)
{
if (x == null)
{
return y == null;
}
return y != null && EqualsList[_depth](x, y);
}
public int GetHashCode(IEntity e)
{
return GetHashCodeList[_depth](e);
}
}
private sealed class PrototypeContextMenuComparer : IEqualityComparer<IEntity>
{
public bool Equals(IEntity? x, IEntity? y)
{
if (x == null)
{
return y == null;
}
if (y != null)
{
if (x.Prototype?.ID == y.Prototype?.ID)
{
var xStates = x.GetComponent<ISpriteComponent>().AllLayers.Where(e => e.Visible).Select(s => s.RsiState.Name);
var yStates = y.GetComponent<ISpriteComponent>().AllLayers.Where(e => e.Visible).Select(s => s.RsiState.Name);
return xStates.OrderBy(t => t).SequenceEqual(yStates.OrderBy(t => t));
}
}
return false;
}
public int GetHashCode(IEntity e)
{
var hash = EqualityComparer<string>.Default.GetHashCode(e.Prototype?.ID!);
foreach (var element in e.GetComponent<ISpriteComponent>().AllLayers.Where(obj => obj.Visible).Select(s => s.RsiState.Name))
{
hash ^= EqualityComparer<string>.Default.GetHashCode(element!);
}
return hash;
}
}
}
}

View File

@@ -1,666 +0,0 @@
using System;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Actions;
using Content.Shared.GameObjects.Components.Mobs;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface.Controls
{
/// <summary>
/// A slot in the action hotbar. Not extending BaseButton because
/// its needs diverged too much.
/// </summary>
public class ActionSlot : PanelContainer
{
// shorter than default tooltip delay so user can more easily
// see what actions they've been given
private const float CustomTooltipDelay = 0.5f;
private static readonly string EnabledColor = "#7b7e9e";
private static readonly string DisabledColor = "#950000";
/// <summary>
/// Current action in this slot.
/// </summary>
public BaseActionPrototype? Action { get; private set; }
/// <summary>
/// true if there is an action assigned to the slot
/// </summary>
public bool HasAssignment => Action != null;
private bool HasToggleSprite => Action != null && Action.IconOn != SpriteSpecifier.Invalid;
/// <summary>
/// Only applicable when an action is in this slot.
/// True if the action is currently shown as enabled, false if action disabled.
/// </summary>
public bool ActionEnabled { get; private set; }
/// <summary>
/// Is there an action in the slot that can currently be used?
/// Target-basedActions on cooldown can still be selected / deselected if they've been configured as such
/// </summary>
public bool CanUseAction => Action != null && ActionEnabled &&
(!IsOnCooldown || (Action.IsTargetAction && !Action.DeselectOnCooldown));
/// <summary>
/// Item the action is provided by, only valid if Action is an ItemActionPrototype. May be null
/// if the item action is not yet tied to an item.
/// </summary>
public IEntity? Item { get; private set; }
/// <summary>
/// Whether the action in this slot should be shown as toggled on. Separate from Depressed.
/// </summary>
public bool ToggledOn
{
get => _toggledOn;
set
{
if (_toggledOn == value) return;
_toggledOn = value;
UpdateIcons();
DrawModeChanged();
}
}
/// <summary>
/// 1-10 corresponding to the number label on the slot (10 is labeled as 0)
/// </summary>
private byte SlotNumber => (byte) (SlotIndex + 1);
public byte SlotIndex { get; }
/// <summary>
/// Current cooldown displayed in this slot. Set to null to show no cooldown.
/// </summary>
public (TimeSpan Start, TimeSpan End)? Cooldown
{
get => _cooldown;
set
{
_cooldown = value;
if (SuppliedTooltip is ActionAlertTooltip actionAlertTooltip)
{
actionAlertTooltip.Cooldown = value;
}
}
}
private (TimeSpan Start, TimeSpan End)? _cooldown;
public bool IsOnCooldown => Cooldown.HasValue && _gameTiming.CurTime < Cooldown.Value.End;
private readonly IGameTiming _gameTiming;
private readonly RichTextLabel _number;
private readonly TextureRect _bigActionIcon;
private readonly TextureRect _smallActionIcon;
private readonly SpriteView _smallItemSpriteView;
private readonly SpriteView _bigItemSpriteView;
private readonly CooldownGraphic _cooldownGraphic;
private readonly ActionsUI _actionsUI;
private readonly ActionMenu _actionMenu;
private readonly ClientActionsComponent _actionsComponent;
private bool _toggledOn;
// whether button is currently pressed down by mouse or keybind down.
private bool _depressed;
private bool _beingHovered;
/// <summary>
/// Creates an action slot for the specified number
/// </summary>
/// <param name="slotIndex">slot index this corresponds to, 0-9 (0 labeled as 1, 8, labeled "9", 9 labeled as "0".</param>
public ActionSlot(ActionsUI actionsUI, ActionMenu actionMenu, ClientActionsComponent actionsComponent, byte slotIndex)
{
_actionsComponent = actionsComponent;
_actionsUI = actionsUI;
_actionMenu = actionMenu;
_gameTiming = IoCManager.Resolve<IGameTiming>();
SlotIndex = slotIndex;
MouseFilter = MouseFilterMode.Stop;
MinSize = (64, 64);
VerticalAlignment = VAlignment.Top;
TooltipDelay = CustomTooltipDelay;
TooltipSupplier = SupplyTooltip;
_number = new RichTextLabel
{
StyleClasses = {StyleNano.StyleClassHotbarSlotNumber}
};
_number.SetMessage(SlotNumberLabel());
_bigActionIcon = new TextureRect
{
HorizontalExpand = true,
VerticalExpand = true,
Stretch = TextureRect.StretchMode.Scale,
Visible = false
};
_bigItemSpriteView = new SpriteView
{
HorizontalExpand = true,
VerticalExpand = true,
Scale = (2,2),
Visible = false,
OverrideDirection = Direction.South,
};
_smallActionIcon = new TextureRect
{
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom,
Stretch = TextureRect.StretchMode.Scale,
Visible = false
};
_smallItemSpriteView = new SpriteView
{
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom,
Visible = false
};
_cooldownGraphic = new CooldownGraphic {Progress = 0, Visible = false};
// padding to the left of the number to shift it right
var paddingBox = new HBoxContainer()
{
HorizontalExpand = true,
VerticalExpand = true,
MinSize = (64, 64)
};
paddingBox.AddChild(new Control()
{
MinSize = (4, 4),
});
paddingBox.AddChild(_number);
// padding to the left of the small icon
var paddingBoxItemIcon = new HBoxContainer()
{
HorizontalExpand = true,
VerticalExpand = true,
MinSize = (64, 64)
};
paddingBoxItemIcon.AddChild(new Control()
{
MinSize = (32, 32),
});
paddingBoxItemIcon.AddChild(new Control
{
Children =
{
_smallActionIcon,
_smallItemSpriteView
}
});
AddChild(_bigActionIcon);
AddChild(_bigItemSpriteView);
AddChild(_cooldownGraphic);
AddChild(paddingBox);
AddChild(paddingBoxItemIcon);
DrawModeChanged();
}
private Control? SupplyTooltip(Control sender)
{
return Action == null ? null :
new ActionAlertTooltip(Action.Name, Action.Description, Action.Requires) {Cooldown = Cooldown};
}
/// <summary>
/// Action attempt for performing the action in the slot
/// </summary>
public IActionAttempt? ActionAttempt()
{
IActionAttempt? attempt = Action switch
{
ActionPrototype actionPrototype => new ActionAttempt(actionPrototype),
ItemActionPrototype itemActionPrototype =>
(Item != null && Item.TryGetComponent<ItemActionsComponent>(out var itemActions)) ?
new ItemActionAttempt(itemActionPrototype, Item, itemActions) : null,
_ => null
};
return attempt;
}
protected override void MouseEntered()
{
base.MouseEntered();
_beingHovered = true;
DrawModeChanged();
if (Action is not ItemActionPrototype) return;
if (Item == null) return;
_actionsComponent.HighlightItemSlot(Item);
}
protected override void MouseExited()
{
base.MouseExited();
_beingHovered = false;
CancelPress();
DrawModeChanged();
_actionsComponent.StopHighlightingItemSlots();
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Function == EngineKeyFunctions.UIRightClick)
{
if (!_actionsUI.Locked && !_actionsUI.DragDropHelper.IsDragging && !_actionMenu.IsDragging)
{
_actionsComponent.Assignments.ClearSlot(_actionsUI.SelectedHotbar, SlotIndex, true);
_actionsUI.StopTargeting();
_actionsUI.UpdateUI();
}
return;
}
// only handle clicks, and can't do anything to this if no assignment
if (args.Function != EngineKeyFunctions.UIClick || !HasAssignment)
return;
// might turn into a drag or a full press if released
Depress(true);
_actionsUI.DragDropHelper.MouseDown(this);
DrawModeChanged();
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (args.Function != EngineKeyFunctions.UIClick)
return;
// might be finishing a drag or using the action
if (_actionsUI.DragDropHelper.IsDragging &&
_actionsUI.DragDropHelper.Dragged == this &&
UserInterfaceManager.CurrentlyHovered is ActionSlot targetSlot &&
targetSlot != this)
{
// finish the drag, swap the 2 slots
var fromIdx = SlotIndex;
var fromAssignment = _actionsComponent.Assignments[_actionsUI.SelectedHotbar, fromIdx];
var toIdx = targetSlot.SlotIndex;
var toAssignment = _actionsComponent.Assignments[_actionsUI.SelectedHotbar, toIdx];
if (fromIdx == toIdx) return;
if (!fromAssignment.HasValue) return;
_actionsComponent.Assignments.AssignSlot(_actionsUI.SelectedHotbar, toIdx, fromAssignment.Value);
if (toAssignment.HasValue)
{
_actionsComponent.Assignments.AssignSlot(_actionsUI.SelectedHotbar, fromIdx, toAssignment.Value);
}
else
{
_actionsComponent.Assignments.ClearSlot(_actionsUI.SelectedHotbar, fromIdx, false);
}
_actionsUI.UpdateUI();
}
else
{
// perform the action
if (UserInterfaceManager.CurrentlyHovered == this)
{
Depress(false);
}
}
_actionsUI.DragDropHelper.EndDrag();
DrawModeChanged();
}
protected override void ControlFocusExited()
{
// lost focus for some reason, cancel the drag if there is one.
base.ControlFocusExited();
_actionsUI.DragDropHelper.EndDrag();
DrawModeChanged();
}
/// <summary>
/// Cancel current press without triggering the action
/// </summary>
public void CancelPress()
{
_depressed = false;
DrawModeChanged();
}
/// <summary>
/// Press this button down. If it was depressed and now set to not depressed, will
/// trigger the action. Only has an effect if CanUseAction.
/// </summary>
public void Depress(bool depress)
{
// action can still be toggled if it's allowed to stay selected
if (!CanUseAction) return;
if (_depressed && !depress)
{
// fire the action
// no left-click interaction with it on cooldown or revoked
_actionsComponent.AttemptAction(this);
}
_depressed = depress;
DrawModeChanged();
}
/// <summary>
/// Updates the action assigned to this slot.
/// </summary>
/// <param name="action">action to assign</param>
/// <param name="actionEnabled">whether action should initially appear enable or disabled</param>
public void Assign(ActionPrototype action, bool actionEnabled)
{
// already assigned
if (Action != null && Action == action) return;
Action = action;
Item = null;
_depressed = false;
ToggledOn = false;
ActionEnabled = actionEnabled;
Cooldown = null;
HideTooltip();
UpdateIcons();
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
/// <summary>
/// Updates the item action assigned to this slot. The action will always be shown as disabled
/// until it is tied to a specific item.
/// </summary>
/// <param name="action">action to assign</param>
public void Assign(ItemActionPrototype action)
{
// already assigned
if (Action != null && Action == action && Item == null) return;
Action = action;
Item = null;
_depressed = false;
ToggledOn = false;
ActionEnabled = false;
Cooldown = null;
HideTooltip();
UpdateIcons();
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
/// <summary>
/// Updates the item action assigned to this slot, tied to a specific item.
/// </summary>
/// <param name="action">action to assign</param>
/// <param name="item">item the action is provided by</param>
/// <param name="actionEnabled">whether action should initially appear enable or disabled</param>
public void Assign(ItemActionPrototype action, IEntity item, bool actionEnabled)
{
// already assigned
if (Action != null && Action == action && Item == item) return;
Action = action;
Item = item;
_depressed = false;
ToggledOn = false;
ActionEnabled = false;
Cooldown = null;
HideTooltip();
UpdateIcons();
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
/// <summary>
/// Clears the action assigned to this slot
/// </summary>
public void Clear()
{
if (!HasAssignment) return;
Action = null;
Item = null;
ToggledOn = false;
_depressed = false;
Cooldown = null;
HideTooltip();
UpdateIcons();
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
/// <summary>
/// Display the action in this slot (if there is one) as enabled
/// </summary>
public void EnableAction()
{
if (ActionEnabled || !HasAssignment) return;
ActionEnabled = true;
_depressed = false;
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
/// <summary>
/// Display the action in this slot (if there is one) as disabled.
/// The slot is still clickable.
/// </summary>
public void DisableAction()
{
if (!ActionEnabled || !HasAssignment) return;
ActionEnabled = false;
_depressed = false;
DrawModeChanged();
_number.SetMessage(SlotNumberLabel());
}
private FormattedMessage SlotNumberLabel()
{
if (SlotNumber > 10) return FormattedMessage.FromMarkup("");
var number = Loc.GetString(SlotNumber == 10 ? "0" : SlotNumber.ToString());
var color = (ActionEnabled || !HasAssignment) ? EnabledColor : DisabledColor;
return FormattedMessage.FromMarkup("[color=" + color + "]" + number + "[/color]");
}
private void UpdateIcons()
{
if (!HasAssignment)
{
SetActionIcon(null);
SetItemIcon(null);
return;
}
if (HasToggleSprite && ToggledOn && Action != null)
{
SetActionIcon(Action.IconOn.Frame0());
}
else if (Action != null)
{
SetActionIcon(Action.Icon.Frame0());
}
if (Item != null)
{
SetItemIcon(Item.TryGetComponent<ISpriteComponent>(out var spriteComponent) ? spriteComponent : null);
}
else
{
SetItemIcon(null);
}
}
private void SetActionIcon(Texture? texture)
{
if (texture == null || !HasAssignment)
{
_bigActionIcon.Texture = null;
_bigActionIcon.Visible = false;
_smallActionIcon.Texture = null;
_smallActionIcon.Visible = false;
}
else
{
if (Action is ItemActionPrototype {IconStyle: ItemActionIconStyle.BigItem})
{
_bigActionIcon.Texture = null;
_bigActionIcon.Visible = false;
_smallActionIcon.Texture = texture;
_smallActionIcon.Visible = true;
}
else
{
_bigActionIcon.Texture = texture;
_bigActionIcon.Visible = true;
_smallActionIcon.Texture = null;
_smallActionIcon.Visible = false;
}
}
}
private void SetItemIcon(ISpriteComponent? sprite)
{
if (sprite == null || !HasAssignment)
{
_bigItemSpriteView.Visible = false;
_bigItemSpriteView.Sprite = null;
_smallItemSpriteView.Visible = false;
_smallItemSpriteView.Sprite = null;
}
else
{
if (Action is ItemActionPrototype actionPrototype)
{
switch (actionPrototype.IconStyle)
{
case ItemActionIconStyle.BigItem:
{
_bigItemSpriteView.Visible = true;
_bigItemSpriteView.Sprite = sprite;
_smallItemSpriteView.Visible = false;
_smallItemSpriteView.Sprite = null;
break;
}
case ItemActionIconStyle.BigAction:
{
_bigItemSpriteView.Visible = false;
_bigItemSpriteView.Sprite = null;
_smallItemSpriteView.Visible = true;
_smallItemSpriteView.Sprite = sprite;
break;
}
case ItemActionIconStyle.NoItem:
{
_bigItemSpriteView.Visible = false;
_bigItemSpriteView.Sprite = null;
_smallItemSpriteView.Visible = false;
_smallItemSpriteView.Sprite = null;
break;
}
}
}
else
{
_bigItemSpriteView.Visible = false;
_bigItemSpriteView.Sprite = null;
_smallItemSpriteView.Visible = false;
_smallItemSpriteView.Sprite = null;
}
}
}
private void DrawModeChanged()
{
// show a hover only if the action is usable or another action is being dragged on top of this
if (_beingHovered)
{
if (_actionsUI.DragDropHelper.IsDragging || _actionMenu.IsDragging ||
(HasAssignment && ActionEnabled && !IsOnCooldown))
{
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassHover);
return;
}
}
// always show the normal empty button style if no action in this slot
if (!HasAssignment)
{
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassNormal);
return;
}
// it's only depress-able if it's usable, so if we're depressed
// show the depressed style
if (_depressed)
{
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassPressed);
return;
}
// if it's toggled on, always show the toggled on style (currently same as depressed style)
if (ToggledOn)
{
// when there's a toggle sprite, we're showing that sprite instead of highlighting this slot
SetOnlyStylePseudoClass(HasToggleSprite ? ContainerButton.StylePseudoClassNormal :
ContainerButton.StylePseudoClassPressed);
return;
}
if (!ActionEnabled)
{
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassDisabled);
return;
}
SetOnlyStylePseudoClass(ContainerButton.StylePseudoClassNormal);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!Cooldown.HasValue)
{
_cooldownGraphic.Visible = false;
_cooldownGraphic.Progress = 0;
return;
}
var duration = Cooldown.Value.End - Cooldown.Value.Start;
var curTime = _gameTiming.CurTime;
var length = duration.TotalSeconds;
var progress = (curTime - Cooldown.Value.Start).TotalSeconds / length;
var ratio = (progress <= 1 ? (1 - progress) : (curTime - Cooldown.Value.End).TotalSeconds * -5);
_cooldownGraphic.Progress = MathHelper.Clamp((float)ratio, -1, 1);
_cooldownGraphic.Visible = ratio > -1f;
}
}
}

View File

@@ -1,104 +0,0 @@
using System;
using Content.Shared.Alert;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface.Controls
{
public class AlertControl : BaseButton
{
// shorter than default tooltip delay so user can more easily
// see what alerts they have
private const float CustomTooltipDelay = 0.5f;
public AlertPrototype Alert { get; }
/// <summary>
/// Current cooldown displayed in this slot. Set to null to show no cooldown.
/// </summary>
public (TimeSpan Start, TimeSpan End)? Cooldown
{
get => _cooldown;
set
{
_cooldown = value;
if (SuppliedTooltip is ActionAlertTooltip actionAlertTooltip)
{
actionAlertTooltip.Cooldown = value;
}
}
}
private (TimeSpan Start, TimeSpan End)? _cooldown;
private short? _severity;
private readonly IGameTiming _gameTiming;
private readonly AnimatedTextureRect _icon;
private readonly CooldownGraphic _cooldownGraphic;
/// <summary>
/// Creates an alert control reflecting the indicated alert + state
/// </summary>
/// <param name="alert">alert to display</param>
/// <param name="severity">severity of alert, null if alert doesn't have severity levels</param>
public AlertControl(AlertPrototype alert, short? severity)
{
_gameTiming = IoCManager.Resolve<IGameTiming>();
TooltipDelay = CustomTooltipDelay;
TooltipSupplier = SupplyTooltip;
Alert = alert;
_severity = severity;
var specifier = alert.GetIcon(_severity);
_icon = new AnimatedTextureRect
{
DisplayRect = {TextureScale = (2, 2)}
};
_icon.SetFromSpriteSpecifier(specifier);
Children.Add(_icon);
_cooldownGraphic = new CooldownGraphic();
Children.Add(_cooldownGraphic);
}
private Control SupplyTooltip(Control? sender)
{
return new ActionAlertTooltip(Alert.Name, Alert.Description) {Cooldown = Cooldown};
}
/// <summary>
/// Change the alert severity, changing the displayed icon
/// </summary>
public void SetSeverity(short? severity)
{
if (_severity != severity)
{
_severity = severity;
_icon.SetFromSpriteSpecifier(Alert.GetIcon(_severity));
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!Cooldown.HasValue)
{
_cooldownGraphic.Visible = false;
_cooldownGraphic.Progress = 0;
return;
}
var duration = Cooldown.Value.End - Cooldown.Value.Start;
var curTime = _gameTiming.CurTime;
var length = duration.TotalSeconds;
var progress = (curTime - Cooldown.Value.Start).TotalSeconds / length;
var ratio = (progress <= 1 ? (1 - progress) : (curTime - Cooldown.Value.End).TotalSeconds * -5);
_cooldownGraphic.Progress = MathHelper.Clamp((float) ratio, -1, 1);
_cooldownGraphic.Visible = ratio > -1f;
}
}
}

View File

@@ -1,14 +0,0 @@
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.Controls
{
public sealed class HighDivider : Control
{
public HighDivider()
{
Children.Add(new PanelContainer {StyleClasses = {StyleBase.ClassHighDivider}});
}
}
}

View File

@@ -1,55 +0,0 @@
using System;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
public class CooldownGraphic : Control
{
[Dependency] private readonly IPrototypeManager _protoMan = default!;
private readonly ShaderInstance _shader;
public CooldownGraphic()
{
IoCManager.InjectDependencies(this);
_shader = _protoMan.Index<ShaderPrototype>("CooldownAnimation").InstanceUnique();
}
/// <summary>
/// Progress of the cooldown animation.
/// Possible values range from 1 to -1, where 1 to 0 is a depleting circle animation and 0 to -1 is a blink animation.
/// </summary>
public float Progress { get; set; }
protected override void Draw(DrawingHandleScreen handle)
{
Span<float> x = new float[10];
Color color;
var lerp = 1f - MathF.Abs(Progress); // for future bikeshedding purposes
if (Progress >= 0f)
{
var hue = (5f / 18f) * lerp;
color = Color.FromHsv((hue, 0.75f, 0.75f, 0.50f));
}
else
{
var alpha = MathHelper.Clamp(0.5f * lerp, 0f, 0.5f);
color = new Color(1f, 1f, 1f, alpha);
}
_shader.SetParameter("progress", Progress);
handle.UseShader(_shader);
handle.DrawRect(PixelSizeBox, color);
}
}
}

View File

@@ -1,232 +0,0 @@
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared;
using Robust.Client.Credits;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.UserInterface
{
public sealed class CreditsWindow : SS14Window
{
[Dependency] private readonly IResourceCache _resourceManager = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
private static readonly Dictionary<string, int> PatronTierPriority = new()
{
["Nuclear Operative"] = 1,
["Syndicate Agent"] = 2,
["Revolutionary"] = 3
};
public CreditsWindow()
{
IoCManager.InjectDependencies(this);
Title = Loc.GetString("Credits");
var rootContainer = new TabContainer();
var patronsList = new ScrollContainer
{
HScrollEnabled = false
};
var ss14ContributorsList = new ScrollContainer
{
HScrollEnabled = false
};
var licensesList = new ScrollContainer
{
HScrollEnabled = false
};
rootContainer.AddChild(ss14ContributorsList);
rootContainer.AddChild(patronsList);
rootContainer.AddChild(licensesList);
TabContainer.SetTabTitle(patronsList, Loc.GetString("Patrons"));
TabContainer.SetTabTitle(ss14ContributorsList, Loc.GetString("Credits"));
TabContainer.SetTabTitle(licensesList, Loc.GetString("Open Source Licenses"));
PopulatePatronsList(patronsList);
PopulateCredits(ss14ContributorsList);
PopulateLicenses(licensesList);
Contents.AddChild(rootContainer);
SetSize = (650, 650);
}
private void PopulateLicenses(ScrollContainer licensesList)
{
var vBox = new VBoxContainer
{
Margin = new Thickness(2, 2, 0, 0)
};
foreach (var entry in CreditsManager.GetLicenses().OrderBy(p => p.Name))
{
vBox.AddChild(new Label {StyleClasses = {StyleBase.StyleClassLabelHeading}, Text = entry.Name});
// We split these line by line because otherwise
// the LGPL causes Clyde to go out of bounds in the rendering code.
foreach (var line in entry.License.Split("\n"))
{
vBox.AddChild(new Label {Text = line, FontColorOverride = new Color(200, 200, 200)});
}
}
licensesList.AddChild(vBox);
}
private void PopulatePatronsList(Control patronsList)
{
var vBox = new VBoxContainer
{
Margin = new Thickness(2, 2, 0, 0)
};
var patrons = LoadPatrons();
// Do not show "become a patron" button on Steam builds
// since Patreon violates Valve's rules about alternative storefronts.
if (!_cfg.GetCVar(CCVars.BrandingSteam))
{
Button patronButton;
vBox.AddChild(patronButton = new Button
{
Text = "Become a Patron",
HorizontalAlignment = HAlignment.Center
});
patronButton.OnPressed +=
_ => IoCManager.Resolve<IUriOpener>().OpenUri(UILinks.Patreon);
}
var first = true;
foreach (var tier in patrons.GroupBy(p => p.Tier).OrderBy(p => PatronTierPriority[p.Key]))
{
if (!first)
{
vBox.AddChild(new Control {MinSize = (0, 10)});
}
first = false;
vBox.AddChild(new Label {StyleClasses = {StyleBase.StyleClassLabelHeading}, Text = $"{tier.Key}"});
var msg = string.Join(", ", tier.OrderBy(p => p.Name).Select(p => p.Name));
var label = new RichTextLabel();
label.SetMessage(msg);
vBox.AddChild(label);
}
patronsList.AddChild(vBox);
}
private IEnumerable<PatronEntry> LoadPatrons()
{
var yamlStream = _resourceManager.ContentFileReadYaml(new ResourcePath("/Credits/Patrons.yml"));
var sequence = (YamlSequenceNode) yamlStream.Documents[0].RootNode;
return sequence
.Cast<YamlMappingNode>()
.Select(m => new PatronEntry(m["Name"].AsString(), m["Tier"].AsString()));
}
private void PopulateCredits(Control contributorsList)
{
Button contributeButton;
var vBox = new VBoxContainer
{
Margin = new Thickness(2, 2, 0, 0)
};
vBox.AddChild(new HBoxContainer
{
HorizontalAlignment = HAlignment.Center,
SeparationOverride = 20,
Children =
{
new Label {Text = "Want to get on this list?"},
(contributeButton = new Button {Text = "Contribute!"})
}
});
var first = true;
void AddSection(string title, string path, bool markup = false)
{
if (!first)
{
vBox.AddChild(new Control {MinSize = (0, 10)});
}
first = false;
vBox.AddChild(new Label {StyleClasses = {StyleBase.StyleClassLabelHeading}, Text = title});
var label = new RichTextLabel();
var text = _resourceManager.ContentFileReadAllText($"/Credits/{path}");
if (markup)
{
label.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
}
else
{
label.SetMessage(text);
}
vBox.AddChild(label);
}
AddSection("Space Station 14 Contributors", "GitHub.txt");
AddSection("Space Station 13 Codebases", "SpaceStation13.txt");
AddSection("Original Space Station 13 Remake Team", "OriginalRemake.txt");
AddSection("Special Thanks", "SpecialThanks.txt", true);
contributorsList.AddChild(vBox);
contributeButton.OnPressed += _ =>
IoCManager.Resolve<IUriOpener>().OpenUri(UILinks.GitHub);
}
private static IEnumerable<string> Lines(TextReader reader)
{
while (true)
{
var line = reader.ReadLine();
if (line == null)
{
yield break;
}
yield return line;
}
}
private sealed class PatronEntry
{
public string Name { get; }
public string Tier { get; }
public PatronEntry(string name, string tier)
{
Name = name;
Tier = tier;
}
}
}
}

View File

@@ -1,14 +0,0 @@
<SS14Window xmlns="https://spacestation14.io"
xmlns:voting="clr-namespace:Content.Client.Voting"
xmlns:changelog="clr-namespace:Content.Client.Changelog"
Title="{Loc 'ui-escape-title'}"
Resizable="False">
<VBoxContainer SeparationOverride="4" CustomMinimumSize="150 160">
<changelog:ChangelogButton />
<voting:VoteCallMenuButton />
<Button Name="OptionsButton" Text="{Loc 'ui-escape-options'}" />
<Button Name="DisconnectButton" Text="{Loc 'ui-escape-disconnect'}" />
<Button Name="QuitButton" Text="{Loc 'ui-escape-quit'}" />
</VBoxContainer>
</SS14Window>

View File

@@ -1,56 +0,0 @@
using Robust.Client.AutoGenerated;
using Robust.Client.Console;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client.UserInterface
{
[GenerateTypedNameReferences]
internal partial class EscapeMenu : SS14Window
{
private readonly IClientConsoleHost _consoleHost;
private readonly OptionsMenu _optionsMenu;
public EscapeMenu(IClientConsoleHost consoleHost)
{
_consoleHost = consoleHost;
RobustXamlLoader.Load(this);
_optionsMenu = new OptionsMenu();
OptionsButton.OnPressed += OnOptionsButtonClicked;
QuitButton.OnPressed += OnQuitButtonClicked;
DisconnectButton.OnPressed += OnDisconnectButtonClicked;
}
private void OnQuitButtonClicked(BaseButton.ButtonEventArgs args)
{
_consoleHost.ExecuteCommand("quit");
Dispose();
}
private void OnDisconnectButtonClicked(BaseButton.ButtonEventArgs args)
{
_consoleHost.ExecuteCommand("disconnect");
Dispose();
}
private void OnOptionsButtonClicked(BaseButton.ButtonEventArgs args)
{
_optionsMenu.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_optionsMenu.Dispose();
}
}
}
}

View File

@@ -1,747 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared;
using Content.Shared.GameObjects.Components.Mobs;
using Content.Shared.Input;
using Content.Shared.Prototypes.HUD;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Input;
using Robust.Shared.Input.Binding;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
using static Robust.Client.Input.Keyboard.Key;
using Control = Robust.Client.UserInterface.Control;
using LC = Robust.Client.UserInterface.Controls.LayoutContainer;
namespace Content.Client.UserInterface
{
/// <summary>
/// Responsible for laying out the default game HUD.
/// </summary>
public interface IGameHud
{
Control RootControl { get; }
// Escape top button.
bool EscapeButtonDown { get; set; }
Action<bool>? EscapeButtonToggled { get; set; }
// Character top button.
bool CharacterButtonDown { get; set; }
bool CharacterButtonVisible { get; set; }
Action<bool>? CharacterButtonToggled { get; set; }
// Inventory top button.
bool InventoryButtonDown { get; set; }
bool InventoryButtonVisible { get; set; }
// Crafting top button.
bool CraftingButtonDown { get; set; }
bool CraftingButtonVisible { get; set; }
Action<bool>? CraftingButtonToggled { get; set; }
// Actions top button.
bool ActionsButtonDown { get; set; }
bool ActionsButtonVisible { get; set; }
Action<bool>? ActionsButtonToggled { get; set; }
// Admin top button.
bool AdminButtonDown { get; set; }
bool AdminButtonVisible { get; set; }
Action<bool>? AdminButtonToggled { get; set; }
// Sandbox top button.
bool SandboxButtonDown { get; set; }
bool SandboxButtonVisible { get; set; }
Action<bool>? SandboxButtonToggled { get; set; }
Control HandsContainer { get; }
Control SuspicionContainer { get; }
Control BottomLeftInventoryQuickButtonContainer { get; }
Control BottomRightInventoryQuickButtonContainer { get; }
Control TopInventoryQuickButtonContainer { get; }
bool CombatPanelVisible { get; set; }
TargetingZone TargetingZone { get; set; }
Action<TargetingZone>? OnTargetingZoneChanged { get; set; }
Control VoteContainer { get; }
void AddTopNotification(TopNotification notification);
Texture GetHudTexture(string path);
bool ValidateHudTheme(int idx);
// Init logic.
void Initialize();
}
internal sealed class GameHud : IGameHud
{
private HBoxContainer _topButtonsContainer = default!;
private TopButton _buttonEscapeMenu = default!;
private TopButton _buttonInfo = default!;
private TopButton _buttonCharacterMenu = default!;
private TopButton _buttonInventoryMenu = default!;
private TopButton _buttonCraftingMenu = default!;
private TopButton _buttonActionsMenu = default!;
private TopButton _buttonAdminMenu = default!;
private TopButton _buttonSandboxMenu = default!;
private InfoWindow _infoWindow = default!;
private TargetingDoll _targetingDoll = default!;
private VBoxContainer _combatPanelContainer = default!;
private VBoxContainer _topNotificationContainer = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly INetConfigurationManager _configManager = default!;
public Control HandsContainer { get; private set; } = default!;
public Control SuspicionContainer { get; private set; } = default!;
public Control TopInventoryQuickButtonContainer { get; private set; } = default!;
public Control BottomLeftInventoryQuickButtonContainer { get; private set; } = default!;
public Control BottomRightInventoryQuickButtonContainer { get; private set; } = default!;
public bool CombatPanelVisible
{
get => _combatPanelContainer.Visible;
set => _combatPanelContainer.Visible = value;
}
public TargetingZone TargetingZone
{
get => _targetingDoll.ActiveZone;
set => _targetingDoll.ActiveZone = value;
}
public Action<TargetingZone>? OnTargetingZoneChanged { get; set; }
public void AddTopNotification(TopNotification notification)
{
_topNotificationContainer.AddChild(notification);
}
public bool ValidateHudTheme(int idx)
{
if (!_prototypeManager.TryIndex(idx.ToString(), out HudThemePrototype? _))
{
Logger.ErrorS("hud", "invalid HUD theme id {0}, using different theme",
idx);
var proto = _prototypeManager.EnumeratePrototypes<HudThemePrototype>().FirstOrDefault();
if (proto == null)
{
throw new NullReferenceException("No valid HUD prototypes!");
}
var id = int.Parse(proto.ID);
_configManager.SetCVar(CCVars.HudTheme, id);
return false;
}
return true;
}
public Texture GetHudTexture(string path)
{
var id = _configManager.GetCVar<int>("hud.theme");
var dir = string.Empty;
if (!_prototypeManager.TryIndex(id.ToString(), out HudThemePrototype? proto))
{
throw new ArgumentOutOfRangeException();
}
dir = proto.Path;
var resourcePath = (new ResourcePath("/Textures/Interface/Inventory") / dir) / path;
return _resourceCache.GetTexture(resourcePath);
}
public void Initialize()
{
RootControl = new LC { Name = "AAAAAAAAAAAAAAAAAAAAAA"};
LC.SetAnchorPreset(RootControl, LC.LayoutPreset.Wide);
var escapeTexture = _resourceCache.GetTexture("/Textures/Interface/hamburger.svg.192dpi.png");
var characterTexture = _resourceCache.GetTexture("/Textures/Interface/character.svg.192dpi.png");
var inventoryTexture = _resourceCache.GetTexture("/Textures/Interface/inventory.svg.192dpi.png");
var craftingTexture = _resourceCache.GetTexture("/Textures/Interface/hammer.svg.192dpi.png");
var actionsTexture = _resourceCache.GetTexture("/Textures/Interface/fist.svg.192dpi.png");
var adminTexture = _resourceCache.GetTexture("/Textures/Interface/gavel.svg.192dpi.png");
var infoTexture = _resourceCache.GetTexture("/Textures/Interface/info.svg.192dpi.png");
var sandboxTexture = _resourceCache.GetTexture("/Textures/Interface/sandbox.svg.192dpi.png");
_topButtonsContainer = new HBoxContainer
{
SeparationOverride = 8
};
RootControl.AddChild(_topButtonsContainer);
LC.SetAnchorAndMarginPreset(_topButtonsContainer, LC.LayoutPreset.TopLeft,
margin: 10);
// the icon textures here should all have the same image height (32) but different widths, so in order to ensure
// the buttons themselves are consistent widths we set a common custom min size
Vector2 topMinSize = (42, 64);
// Escape
_buttonEscapeMenu = new TopButton(escapeTexture, EngineKeyFunctions.EscapeMenu, _inputManager)
{
ToolTip = Loc.GetString("Open escape menu."),
MinSize = (70, 64),
StyleClasses = {StyleBase.ButtonOpenRight}
};
_topButtonsContainer.AddChild(_buttonEscapeMenu);
_buttonEscapeMenu.OnToggled += args => EscapeButtonToggled?.Invoke(args.Pressed);
// Character
_buttonCharacterMenu = new TopButton(characterTexture, ContentKeyFunctions.OpenCharacterMenu, _inputManager)
{
ToolTip = Loc.GetString("Open character menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonCharacterMenu);
_buttonCharacterMenu.OnToggled += args => CharacterButtonToggled?.Invoke(args.Pressed);
// Inventory
_buttonInventoryMenu = new TopButton(inventoryTexture, ContentKeyFunctions.OpenInventoryMenu, _inputManager)
{
ToolTip = Loc.GetString("Open inventory menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonInventoryMenu);
_buttonInventoryMenu.OnToggled += args => InventoryButtonDown = args.Pressed;
// Crafting
_buttonCraftingMenu = new TopButton(craftingTexture, ContentKeyFunctions.OpenCraftingMenu, _inputManager)
{
ToolTip = Loc.GetString("Open crafting menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonCraftingMenu);
_buttonCraftingMenu.OnToggled += args => CraftingButtonToggled?.Invoke(args.Pressed);
// Actions
_buttonActionsMenu = new TopButton(actionsTexture, ContentKeyFunctions.OpenActionsMenu, _inputManager)
{
ToolTip = Loc.GetString("Open actions menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonActionsMenu);
_buttonActionsMenu.OnToggled += args => ActionsButtonToggled?.Invoke(args.Pressed);
// Admin
_buttonAdminMenu = new TopButton(adminTexture, ContentKeyFunctions.OpenAdminMenu, _inputManager)
{
ToolTip = Loc.GetString("Open admin menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonAdminMenu);
_buttonAdminMenu.OnToggled += args => AdminButtonToggled?.Invoke(args.Pressed);
// Sandbox
_buttonSandboxMenu = new TopButton(sandboxTexture, ContentKeyFunctions.OpenSandboxWindow, _inputManager)
{
ToolTip = Loc.GetString("Open sandbox menu."),
MinSize = topMinSize,
Visible = false,
StyleClasses = {StyleBase.ButtonSquare}
};
_topButtonsContainer.AddChild(_buttonSandboxMenu);
_buttonSandboxMenu.OnToggled += args => SandboxButtonToggled?.Invoke(args.Pressed);
// Info Window
_buttonInfo = new TopButton(infoTexture, ContentKeyFunctions.OpenInfo, _inputManager)
{
ToolTip = Loc.GetString("ui-options-function-open-info"),
MinSize = topMinSize,
StyleClasses = {StyleBase.ButtonOpenLeft, TopButton.StyleClassRedTopButton},
};
_topButtonsContainer.AddChild(_buttonInfo);
_buttonInfo.OnToggled += a => ButtonInfoOnOnToggled();
_infoWindow = new InfoWindow();
_infoWindow.OnClose += () => _buttonInfo.Pressed = false;
_inputManager.SetInputCommand(ContentKeyFunctions.OpenInfo,
InputCmdHandler.FromDelegate(s => ButtonInfoOnOnToggled()));
_combatPanelContainer = new VBoxContainer
{
HorizontalAlignment = Control.HAlignment.Left,
VerticalAlignment = Control.VAlignment.Bottom,
Children =
{
(_targetingDoll = new TargetingDoll(_resourceCache))
}
};
LC.SetGrowHorizontal(_combatPanelContainer, LC.GrowDirection.Begin);
LC.SetGrowVertical(_combatPanelContainer, LC.GrowDirection.Begin);
LC.SetAnchorAndMarginPreset(_combatPanelContainer, LC.LayoutPreset.BottomRight);
LC.SetMarginBottom(_combatPanelContainer, -10f);
_targetingDoll.OnZoneChanged += args => OnTargetingZoneChanged?.Invoke(args);
var centerBottomContainer = new VBoxContainer
{
SeparationOverride = 5,
HorizontalAlignment = Control.HAlignment.Center
};
LC.SetAnchorAndMarginPreset(centerBottomContainer, LC.LayoutPreset.CenterBottom);
LC.SetGrowHorizontal(centerBottomContainer, LC.GrowDirection.Both);
LC.SetGrowVertical(centerBottomContainer, LC.GrowDirection.Begin);
LC.SetMarginBottom(centerBottomContainer, -10f);
RootControl.AddChild(centerBottomContainer);
HandsContainer = new Control
{
VerticalAlignment = Control.VAlignment.Bottom,
HorizontalAlignment = Control.HAlignment.Center
};
BottomRightInventoryQuickButtonContainer = new HBoxContainer()
{
VerticalAlignment = Control.VAlignment.Bottom,
HorizontalAlignment = Control.HAlignment.Right
};
BottomLeftInventoryQuickButtonContainer = new HBoxContainer()
{
VerticalAlignment = Control.VAlignment.Bottom,
HorizontalAlignment = Control.HAlignment.Left
};
TopInventoryQuickButtonContainer = new HBoxContainer()
{
Visible = false,
VerticalAlignment = Control.VAlignment.Bottom,
HorizontalAlignment = Control.HAlignment.Center
};
var bottomRow = new HBoxContainer()
{
HorizontalAlignment = Control.HAlignment.Center
};
bottomRow.AddChild(new Control {MinSize = (69, 0)}); //Padding (nice)
bottomRow.AddChild(BottomLeftInventoryQuickButtonContainer);
bottomRow.AddChild(HandsContainer);
bottomRow.AddChild(BottomRightInventoryQuickButtonContainer);
bottomRow.AddChild(new Control {MinSize = (1, 0)}); //Padding
centerBottomContainer.AddChild(TopInventoryQuickButtonContainer);
centerBottomContainer.AddChild(bottomRow);
SuspicionContainer = new Control
{
HorizontalAlignment = Control.HAlignment.Center
};
var rightBottomContainer = new HBoxContainer
{
SeparationOverride = 5
};
LC.SetAnchorAndMarginPreset(rightBottomContainer, LC.LayoutPreset.BottomRight);
LC.SetGrowHorizontal(rightBottomContainer, LC.GrowDirection.Begin);
LC.SetGrowVertical(rightBottomContainer, LC.GrowDirection.Begin);
LC.SetMarginBottom(rightBottomContainer, -10f);
LC.SetMarginRight(rightBottomContainer, -10f);
RootControl.AddChild(rightBottomContainer);
rightBottomContainer.AddChild(_combatPanelContainer);
RootControl.AddChild(SuspicionContainer);
LC.SetAnchorAndMarginPreset(SuspicionContainer, LC.LayoutPreset.BottomLeft,
margin: 10);
LC.SetGrowHorizontal(SuspicionContainer, LC.GrowDirection.End);
LC.SetGrowVertical(SuspicionContainer, LC.GrowDirection.Begin);
_topNotificationContainer = new VBoxContainer
{
MinSize = (600, 0)
};
RootControl.AddChild(_topNotificationContainer);
LC.SetAnchorPreset(_topNotificationContainer, LC.LayoutPreset.CenterTop);
LC.SetGrowHorizontal(_topNotificationContainer, LC.GrowDirection.Both);
LC.SetGrowVertical(_topNotificationContainer, LC.GrowDirection.End);
VoteContainer = new VBoxContainer();
RootControl.AddChild(VoteContainer);
LC.SetAnchorPreset(VoteContainer, LC.LayoutPreset.TopLeft);
LC.SetMarginLeft(VoteContainer, 180);
LC.SetMarginTop(VoteContainer, 100);
LC.SetGrowHorizontal(VoteContainer, LC.GrowDirection.End);
LC.SetGrowVertical(VoteContainer, LC.GrowDirection.End);
}
private void ButtonInfoOnOnToggled()
{
_buttonInfo.StyleClasses.Remove(TopButton.StyleClassRedTopButton);
if (_infoWindow.IsOpen)
{
if (!_infoWindow.IsAtFront())
{
_infoWindow.MoveToFront();
_buttonInfo.Pressed = true;
}
else
{
_infoWindow.Close();
_buttonInfo.Pressed = false;
}
}
else
{
_infoWindow.OpenCentered();
_buttonInfo.Pressed = true;
}
}
public Control RootControl { get; private set; } = default!;
public bool EscapeButtonDown
{
get => _buttonEscapeMenu.Pressed;
set => _buttonEscapeMenu.Pressed = value;
}
public Action<bool>? EscapeButtonToggled { get; set; }
public bool CharacterButtonDown
{
get => _buttonCharacterMenu.Pressed;
set => _buttonCharacterMenu.Pressed = value;
}
public bool CharacterButtonVisible
{
get => _buttonCharacterMenu.Visible;
set => _buttonCharacterMenu.Visible = value;
}
public Action<bool>? CharacterButtonToggled { get; set; }
public bool InventoryButtonDown
{
get => _buttonInventoryMenu.Pressed;
set
{
TopInventoryQuickButtonContainer.Visible = value;
_buttonInventoryMenu.Pressed = value;
}
}
public bool InventoryButtonVisible
{
get => _buttonInventoryMenu.Visible;
set => _buttonInventoryMenu.Visible = value;
}
public bool CraftingButtonDown
{
get => _buttonCraftingMenu.Pressed;
set => _buttonCraftingMenu.Pressed = value;
}
public bool CraftingButtonVisible
{
get => _buttonCraftingMenu.Visible;
set => _buttonCraftingMenu.Visible = value;
}
public Action<bool>? CraftingButtonToggled { get; set; }
public bool ActionsButtonDown
{
get => _buttonActionsMenu.Pressed;
set => _buttonActionsMenu.Pressed = value;
}
public bool ActionsButtonVisible
{
get => _buttonActionsMenu.Visible;
set => _buttonActionsMenu.Visible = value;
}
public Action<bool>? ActionsButtonToggled { get; set; }
public bool AdminButtonDown
{
get => _buttonAdminMenu.Pressed;
set => _buttonAdminMenu.Pressed = value;
}
public bool AdminButtonVisible
{
get => _buttonAdminMenu.Visible;
set => _buttonAdminMenu.Visible = value;
}
public Action<bool>? AdminButtonToggled { get; set; }
public bool SandboxButtonDown
{
get => _buttonSandboxMenu.Pressed;
set => _buttonSandboxMenu.Pressed = value;
}
public bool SandboxButtonVisible
{
get => _buttonSandboxMenu.Visible;
set => _buttonSandboxMenu.Visible = value;
}
public Action<bool>? SandboxButtonToggled { get; set; }
public Control VoteContainer { get; private set; } = default!;
public sealed class TopButton : ContainerButton
{
public const string StyleClassLabelTopButton = "topButtonLabel";
public const string StyleClassRedTopButton = "topButtonLabel";
private const float CustomTooltipDelay = 0.4f;
private static readonly Color ColorNormal = Color.FromHex("#7b7e9e");
private static readonly Color ColorRedNormal = Color.FromHex("#FEFEFE");
private static readonly Color ColorHovered = Color.FromHex("#9699bb");
private static readonly Color ColorRedHovered = Color.FromHex("#FFFFFF");
private static readonly Color ColorPressed = Color.FromHex("#789B8C");
private const float VertPad = 8f;
private Color NormalColor => HasStyleClass(StyleClassRedTopButton) ? ColorRedNormal : ColorNormal;
private Color HoveredColor => HasStyleClass(StyleClassRedTopButton) ? ColorRedHovered : ColorHovered;
private readonly TextureRect _textureRect;
private readonly Label _label;
private readonly BoundKeyFunction _function;
private readonly IInputManager _inputManager;
public TopButton(Texture texture, BoundKeyFunction function, IInputManager inputManager)
{
_function = function;
_inputManager = inputManager;
TooltipDelay = CustomTooltipDelay;
AddChild(
new VBoxContainer
{
Children =
{
(_textureRect = new TextureRect
{
TextureScale = (0.5f, 0.5f),
Texture = texture,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
VerticalExpand = true,
Margin = new Thickness(0, VertPad),
ModulateSelfOverride = NormalColor,
Stretch = TextureRect.StretchMode.KeepCentered
}),
(_label = new Label
{
Text = ShortKeyName(_function),
HorizontalAlignment = HAlignment.Center,
ModulateSelfOverride = NormalColor,
StyleClasses = {StyleClassLabelTopButton}
})
}
}
);
ToggleMode = true;
}
protected override void EnteredTree()
{
_inputManager.OnKeyBindingAdded += OnKeyBindingChanged;
_inputManager.OnKeyBindingRemoved += OnKeyBindingChanged;
}
protected override void ExitedTree()
{
_inputManager.OnKeyBindingAdded -= OnKeyBindingChanged;
_inputManager.OnKeyBindingRemoved -= OnKeyBindingChanged;
}
private void OnKeyBindingChanged(IKeyBinding obj)
{
_label.Text = ShortKeyName(_function);
}
private string ShortKeyName(BoundKeyFunction keyFunction)
{
// need to use shortened key names so they fit in the buttons.
return TryGetShortKeyName(keyFunction, out var name) ? Loc.GetString(name) : " ";
}
private bool TryGetShortKeyName(BoundKeyFunction keyFunction, [NotNullWhen(true)] out string? name)
{
if (_inputManager.TryGetKeyBinding(keyFunction, out var binding))
{
// can't possibly fit a modifier key in the top button, so omit it
var key = binding.BaseKey;
if (binding.Mod1 != Unknown || binding.Mod2 != Unknown ||
binding.Mod3 != Unknown)
{
name = null;
return false;
}
name = null;
name = key switch
{
Apostrophe => "'",
Comma => ",",
Delete => "Del",
Down => "Dwn",
Escape => "Esc",
Equal => "=",
Home => "Hom",
Insert => "Ins",
Left => "Lft",
Menu => "Men",
Minus => "-",
Num0 => "0",
Num1 => "1",
Num2 => "2",
Num3 => "3",
Num4 => "4",
Num5 => "5",
Num6 => "6",
Num7 => "7",
Num8 => "8",
Num9 => "9",
Pause => "||",
Period => ".",
Return => "Ret",
Right => "Rgt",
Slash => "/",
Space => "Spc",
Tab => "Tab",
Tilde => "~",
BackSlash => "\\",
BackSpace => "Bks",
LBracket => "[",
MouseButton4 => "M4",
MouseButton5 => "M5",
MouseButton6 => "M6",
MouseButton7 => "M7",
MouseButton8 => "M8",
MouseButton9 => "M9",
MouseLeft => "ML",
MouseMiddle => "MM",
MouseRight => "MR",
NumpadDecimal => "N.",
NumpadDivide => "N/",
NumpadEnter => "Ent",
NumpadMultiply => "*",
NumpadNum0 => "0",
NumpadNum1 => "1",
NumpadNum2 => "2",
NumpadNum3 => "3",
NumpadNum4 => "4",
NumpadNum5 => "5",
NumpadNum6 => "6",
NumpadNum7 => "7",
NumpadNum8 => "8",
NumpadNum9 => "9",
NumpadSubtract => "N-",
PageDown => "PgD",
PageUp => "PgU",
RBracket => "]",
SemiColon => ";",
_ => DefaultShortKeyName(keyFunction)
};
return name != null;
}
name = null;
return false;
}
private string? DefaultShortKeyName(BoundKeyFunction keyFunction)
{
var name = FormattedMessage.EscapeText(_inputManager.GetKeyFunctionButtonString(keyFunction));
return name.Length > 3 ? null : name;
}
protected override void StylePropertiesChanged()
{
// colors of children depend on style, so ensure we update when style is changed
base.StylePropertiesChanged();
UpdateChildColors();
}
private void UpdateChildColors()
{
if (_label == null || _textureRect == null) return;
switch (DrawMode)
{
case DrawModeEnum.Normal:
_textureRect.ModulateSelfOverride = NormalColor;
_label.ModulateSelfOverride = NormalColor;
break;
case DrawModeEnum.Pressed:
_textureRect.ModulateSelfOverride = ColorPressed;
_label.ModulateSelfOverride = ColorPressed;
break;
case DrawModeEnum.Hover:
_textureRect.ModulateSelfOverride = HoveredColor;
_label.ModulateSelfOverride = HoveredColor;
break;
case DrawModeEnum.Disabled:
break;
}
}
protected override void DrawModeChanged()
{
base.DrawModeChanged();
UpdateChildColors();
}
}
}
}

View File

@@ -1,142 +0,0 @@
#nullable enable
using Content.Client.GameObjects.Components.Observer;
using Robust.Client.Console;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Vector2 = Robust.Shared.Maths.Vector2;
using Robust.Shared.Localization;
namespace Content.Client.UserInterface
{
public class GhostGui : Control
{
private readonly Button _returnToBody = new() {Text = Loc.GetString("Return to body")};
private readonly Button _ghostWarp = new() {Text = Loc.GetString("Ghost Warp")};
private readonly Button _ghostRoles = new() {Text = Loc.GetString("Ghost Roles")};
private readonly GhostComponent _owner;
public GhostTargetWindow? TargetWindow { get; }
public GhostGui(GhostComponent owner)
{
IoCManager.InjectDependencies(this);
_owner = owner;
TargetWindow = new GhostTargetWindow(owner);
MouseFilter = MouseFilterMode.Ignore;
_ghostWarp.OnPressed += _ => TargetWindow.Populate();
_returnToBody.OnPressed += _ => owner.SendReturnToBodyMessage();
_ghostRoles.OnPressed += _ => IoCManager.Resolve<IClientConsoleHost>().RemoteExecuteCommand(null, "ghostroles");
AddChild(new HBoxContainer
{
Children =
{
_returnToBody,
_ghostWarp,
_ghostRoles,
}
});
Update();
}
public void Update()
{
_returnToBody.Disabled = !_owner.CanReturnToBody;
}
}
public class GhostTargetWindow : SS14Window
{
private readonly GhostComponent _owner;
private readonly VBoxContainer _buttonContainer;
public GhostTargetWindow(GhostComponent owner)
{
MinSize = SetSize = (300, 450);
Title = "Ghost Warp";
_owner = owner;
_owner.GhostRequestWarpPoint();
_owner.GhostRequestPlayerNames();
_buttonContainer = new VBoxContainer()
{
VerticalExpand = true,
SeparationOverride = 5,
};
var scrollBarContainer = new ScrollContainer()
{
VerticalExpand = true,
HorizontalExpand = true
};
scrollBarContainer.AddChild(_buttonContainer);
Contents.AddChild(scrollBarContainer);
}
public void Populate()
{
_buttonContainer.DisposeAllChildren();
AddButtonPlayers();
AddButtonLocations();
OpenCentered();
}
private void AddButtonPlayers()
{
foreach (var (key, value) in _owner.PlayerNames)
{
var currentButtonRef = new Button
{
Text = value,
TextAlign = Label.AlignMode.Right,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
MinSize = (230, 20),
ClipText = true,
};
currentButtonRef.OnPressed += (_) =>
{
_owner.SendGhostWarpRequestMessage(key);
};
_buttonContainer.AddChild(currentButtonRef);
}
}
private void AddButtonLocations()
{
foreach (var name in _owner.WarpNames)
{
var currentButtonRef = new Button
{
Text = $"Warp: {name}",
TextAlign = Label.AlignMode.Right,
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1,
MinSize = (230,20),
ClipText = true,
};
currentButtonRef.OnPressed += (_) =>
{
_owner.SendGhostWarpRequestMessage(name);
};
_buttonContainer.AddChild(currentButtonRef);
}
}
}
}

View File

@@ -1,12 +0,0 @@
using Robust.Client.UserInterface.CustomControls;
namespace Content.Client.UserInterface
{
public class GhostRoleWindow : SS14Window
{
protected override void Opened()
{
base.Opened();
}
}
}

View File

@@ -1,46 +0,0 @@
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface
{
public class HandButton : ItemSlotButton
{
private bool _activeHand;
private bool _highlighted;
public HandButton(Texture texture, Texture storageTexture, string textureName, Texture blockedTexture, HandLocation location) : base(texture, storageTexture, textureName)
{
Location = location;
AddChild(Blocked = new TextureRect
{
Texture = blockedTexture,
TextureScale = (2, 2),
MouseFilter = MouseFilterMode.Stop,
Visible = false
});
}
public HandLocation Location { get; }
public TextureRect Blocked { get; }
public void SetActiveHand(bool active)
{
_activeHand = active;
UpdateHighlight();
}
public override void Highlight(bool highlight)
{
_highlighted = highlight;
UpdateHighlight();
}
private void UpdateHighlight()
{
// always stay highlighted if active
base.Highlight(_activeHand || _highlighted);
}
}
}

View File

@@ -1,257 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Client.GameObjects.Components.Items;
using Content.Client.Utility;
using Content.Shared;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.Input;
using Robust.Client.Graphics;
using Robust.Client.Player;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Configuration;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface
{
public class HandsGui : Control
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
[Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly INetConfigurationManager _configManager = default!;
private Texture _leftHandTexture;
private Texture _middleHandTexture;
private Texture _rightHandTexture;
private readonly ItemStatusPanel _topPanel;
private readonly HBoxContainer _guiContainer;
private readonly VBoxContainer _handsColumn;
private readonly HBoxContainer _handsContainer;
public HandsGui()
{
IoCManager.InjectDependencies(this);
_configManager.OnValueChanged(CCVars.HudTheme, UpdateHudTheme, invokeImmediately: true);
AddChild(_guiContainer = new HBoxContainer
{
SeparationOverride = 0,
HorizontalAlignment = HAlignment.Center,
Children =
{
(_handsColumn = new VBoxContainer
{
Children =
{
(_topPanel = ItemStatusPanel.FromSide(HandLocation.Middle)),
(_handsContainer = new HBoxContainer{HorizontalAlignment = HAlignment.Center})
}
}),
}
});
_leftHandTexture = _gameHud.GetHudTexture("hand_l.png");
_middleHandTexture = _gameHud.GetHudTexture("hand_l.png");
_rightHandTexture = _gameHud.GetHudTexture("hand_r.png");
}
private void UpdateHudTheme(int idx)
{
if (!_gameHud.ValidateHudTheme(idx))
{
return;
}
_leftHandTexture = _gameHud.GetHudTexture("hand_l.png");
_middleHandTexture = _gameHud.GetHudTexture("hand_l.png");
_rightHandTexture = _gameHud.GetHudTexture("hand_r.png");
UpdateHandIcons();
}
private Texture HandTexture(HandLocation location)
{
switch (location)
{
case HandLocation.Left:
return _leftHandTexture;
case HandLocation.Middle:
return _middleHandTexture;
case HandLocation.Right:
return _rightHandTexture;
default:
throw new ArgumentOutOfRangeException(nameof(location), location, null);
}
}
/// <summary>
/// Adds a new hand to this control
/// </summary>
/// <param name="hand">The hand to add to this control</param>
/// <param name="buttonLocation">
/// The actual location of the button. The right hand is drawn
/// on the LEFT of the screen.
/// </param>
private void AddHand(Hand hand, HandLocation buttonLocation)
{
var textureName = "hand_l.png";
if(buttonLocation == HandLocation.Right)
{
textureName = "hand_r.png";
}
var buttonTexture = HandTexture(buttonLocation);
var storageTexture = _gameHud.GetHudTexture("back.png");
var blockedTexture = _resourceCache.GetTexture("/Textures/Interface/Inventory/blocked.png");
var button = new HandButton(buttonTexture, storageTexture, textureName, blockedTexture, buttonLocation);
var slot = hand.Name;
button.OnPressed += args => HandKeyBindDown(args, slot);
button.OnStoragePressed += args => _OnStoragePressed(args, slot);
_handsContainer.AddChild(button);
hand.Button = button;
}
public void RemoveHand(Hand hand)
{
var button = hand.Button;
if (button != null)
{
_handsContainer.RemoveChild(button);
}
}
/// <summary>
/// Gets the hands component controlling this gui
/// </summary>
/// <param name="hands"></param>
/// <returns>true if successful and false if failure</returns>
private bool TryGetHands([NotNullWhen(true)] out HandsComponent? hands)
{
hands = default;
var entity = _playerManager?.LocalPlayer?.ControlledEntity;
return entity != null && entity.TryGetComponent(out hands);
}
public void UpdateHandIcons()
{
if (Parent == null)
{
return;
}
UpdateDraw();
if (!TryGetHands(out var component))
{
return;
}
// TODO: Remove button on remove hand
var hands = component.Hands.OrderByDescending(x => x.Location).ToArray();
for (var i = 0; i < hands.Length; i++)
{
var hand = hands[i];
if (hand.Button == null)
{
AddHand(hand, hand.Location);
}
hand.Button!.Button.Texture = HandTexture(hand.Location);
hand.Button!.SetPositionInParent(i);
_itemSlotManager.SetItemSlot(hand.Button, hand.Entity);
hand.Button!.SetActiveHand(component.ActiveIndex == hand.Name);
}
}
private void HandKeyBindDown(GUIBoundKeyEventArgs args, string slotName)
{
if (!TryGetHands(out var hands))
{
return;
}
if (args.Function == ContentKeyFunctions.MouseMiddle)
{
hands.SendChangeHand(slotName);
args.Handle();
return;
}
var entity = hands.GetEntity(slotName);
if (entity == null)
{
if (args.Function == EngineKeyFunctions.UIClick && hands.ActiveIndex != slotName)
{
hands.SendChangeHand(slotName);
args.Handle();
}
return;
}
if (_itemSlotManager.OnButtonPressed(args, entity))
{
args.Handle();
return;
}
if (args.Function == EngineKeyFunctions.UIClick)
{
if (hands.ActiveIndex == slotName)
{
hands.UseActiveHand();
}
else
{
hands.AttackByInHand(slotName);
}
args.Handle();
}
}
private void _OnStoragePressed(GUIBoundKeyEventArgs args, string handIndex)
{
if (args.Function != EngineKeyFunctions.UIClick || !TryGetHands(out var hands))
{
return;
}
hands.ActivateItemInHand(handIndex);
}
private void UpdatePanels()
{
if (!TryGetHands(out var component))
{
return;
}
foreach (var hand in component.Hands)
{
_itemSlotManager.UpdateCooldown(hand.Button, hand.Entity);
}
_topPanel.Update(component.GetEntity(component.ActiveIndex));
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdatePanels();
}
}
}

View File

@@ -1,35 +0,0 @@
using Content.Shared.Preferences;
using Content.Shared.Prototypes;
using Content.Shared.Utility;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
namespace Content.Client.UserInterface
{
public partial class HumanoidProfileEditor
{
private readonly IRobustRandom _random;
private readonly IPrototypeManager _prototypeManager;
private void RandomizeEverything()
{
Profile = HumanoidCharacterProfile.Random();
UpdateSexControls();
UpdateGenderControls();
UpdateClothingControls();
UpdateAgeEdit();
UpdateNameEdit();
UpdateHairPickers();
UpdateEyePickers();
}
private void RandomizeName()
{
if (Profile == null) return;
var firstName = _random.Pick(Profile.Sex.FirstNames(_prototypeManager).Values);
var lastName = _random.Pick(_prototypeManager.Index<DatasetPrototype>("names_last"));
SetName($"{firstName} {lastName}");
UpdateNameEdit();
}
}
}

View File

@@ -1,971 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.GameObjects.Components;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.Interfaces;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.GameTicking;
using Content.Shared.Preferences;
using Content.Shared.Preferences.Appearance;
using Content.Shared.Roles;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.Utility;
using Robust.Shared.Enums;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Random;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface
{
public partial class HumanoidProfileEditor : Control
{
private static readonly StyleBoxFlat HighlightedStyle = new()
{
BackgroundColor = new Color(47, 47, 53),
ContentMarginTopOverride = 10,
ContentMarginBottomOverride = 10,
ContentMarginLeftOverride = 10,
ContentMarginRightOverride = 10
};
private readonly LineEdit _ageEdit;
private readonly LineEdit _nameEdit;
private readonly IClientPreferencesManager _preferencesManager;
private readonly Button _saveButton;
private readonly Button _sexFemaleButton;
private readonly Button _sexMaleButton;
private readonly OptionButton _genderButton;
private readonly OptionButton _clothingButton;
private readonly OptionButton _backpackButton;
private readonly HairStylePicker _hairPicker;
private readonly HairStylePicker _facialHairPicker;
private readonly EyeColorPicker _eyesPicker;
private readonly List<JobPrioritySelector> _jobPriorities;
private readonly OptionButton _preferenceUnavailableButton;
private readonly Dictionary<string, VBoxContainer> _jobCategories;
private readonly List<AntagPreferenceSelector> _antagPreferences;
private readonly IEntity _previewDummy;
private readonly SpriteView _previewSprite;
private readonly SpriteView _previewSpriteSide;
private bool _isDirty;
public int CharacterSlot;
public HumanoidCharacterProfile? Profile;
public event Action<HumanoidCharacterProfile, int>? OnProfileChanged;
public HumanoidProfileEditor(IClientPreferencesManager preferencesManager, IPrototypeManager prototypeManager,
IEntityManager entityManager)
{
_random = IoCManager.Resolve<IRobustRandom>();
_prototypeManager = prototypeManager;
_preferencesManager = preferencesManager;
var hbox = new HBoxContainer();
AddChild(hbox);
#region Left
var vBox = new VBoxContainer {Margin = new Thickness(10)};
hbox.AddChild(vBox);
var middleContainer = new HBoxContainer
{
SeparationOverride = 10
};
vBox.AddChild(middleContainer);
var leftColumn = new VBoxContainer();
middleContainer.AddChild(leftColumn);
#region Randomize
var randomizePanel = HighlightedContainer();
var randomizeEverythingButton = new Button
{
Text = Loc.GetString("Randomize everything")
};
randomizeEverythingButton.OnPressed += args => { RandomizeEverything(); };
randomizePanel.AddChild(randomizeEverythingButton);
leftColumn.AddChild(randomizePanel);
#endregion Randomize
#region Name
var namePanel = HighlightedContainer();
var nameHBox = new HBoxContainer
{
VerticalExpand = true
};
var nameLabel = new Label { Text = Loc.GetString("Name:") };
_nameEdit = new LineEdit
{
MinSize = (270, 0),
VerticalAlignment = VAlignment.Center
};
_nameEdit.OnTextChanged += args => { SetName(args.Text); };
var nameRandomButton = new Button
{
Text = Loc.GetString("Randomize"),
};
nameRandomButton.OnPressed += args => RandomizeName();
nameHBox.AddChild(nameLabel);
nameHBox.AddChild(_nameEdit);
nameHBox.AddChild(nameRandomButton);
randomizePanel.AddChild(nameHBox);
#endregion Name
var tabContainer = new TabContainer {VerticalExpand = true};
vBox.AddChild(tabContainer);
#region Appearance
var appearanceList = new VBoxContainer();
var appearanceVBox = new VBoxContainer
{
Children =
{
new ScrollContainer
{
VerticalExpand = true,
Children =
{
appearanceList
}
}
}
};
tabContainer.AddChild(appearanceVBox);
tabContainer.SetTabTitle(0, Loc.GetString("Appearance"));
var sexAndAgeRow = new HBoxContainer
{
SeparationOverride = 10
};
appearanceList.AddChild(sexAndAgeRow);
#region Sex
var sexPanel = HighlightedContainer();
var sexHBox = new HBoxContainer();
var sexLabel = new Label { Text = Loc.GetString("Sex:") };
var sexButtonGroup = new ButtonGroup();
_sexMaleButton = new Button
{
Text = Loc.GetString("Male"),
Group = sexButtonGroup
};
_sexMaleButton.OnPressed += args =>
{
SetSex(Sex.Male);
if (Profile?.Gender == Gender.Female)
{
SetGender(Gender.Male);
UpdateGenderControls();
}
};
_sexFemaleButton = new Button
{
Text = Loc.GetString("Female"),
Group = sexButtonGroup
};
_sexFemaleButton.OnPressed += _ =>
{
SetSex(Sex.Female);
if (Profile?.Gender == Gender.Male)
{
SetGender(Gender.Female);
UpdateGenderControls();
}
};
sexHBox.AddChild(sexLabel);
sexHBox.AddChild(_sexMaleButton);
sexHBox.AddChild(_sexFemaleButton);
sexPanel.AddChild(sexHBox);
sexAndAgeRow.AddChild(sexPanel);
#endregion Sex
#region Age
var agePanel = HighlightedContainer();
var ageHBox = new HBoxContainer();
var ageLabel = new Label { Text = Loc.GetString("Age:") };
_ageEdit = new LineEdit { MinSize = (40, 0) };
_ageEdit.OnTextChanged += args =>
{
if (!int.TryParse(args.Text, out var newAge))
return;
SetAge(newAge);
};
ageHBox.AddChild(ageLabel);
ageHBox.AddChild(_ageEdit);
agePanel.AddChild(ageHBox);
sexAndAgeRow.AddChild(agePanel);
#endregion Age
#region Gender
var genderPanel = HighlightedContainer();
var genderHBox = new HBoxContainer();
var genderLabel = new Label { Text = Loc.GetString("Pronouns:") };
_genderButton = new OptionButton();
_genderButton.AddItem(Loc.GetString("He / Him"), (int) Gender.Male);
_genderButton.AddItem(Loc.GetString("She / Her"), (int) Gender.Female);
_genderButton.AddItem(Loc.GetString("They / Them"), (int) Gender.Epicene);
_genderButton.AddItem(Loc.GetString("It / It"), (int) Gender.Neuter);
_genderButton.OnItemSelected += args =>
{
_genderButton.SelectId(args.Id);
SetGender((Gender) args.Id);
};
genderHBox.AddChild(genderLabel);
genderHBox.AddChild(_genderButton);
genderPanel.AddChild(genderHBox);
sexAndAgeRow.AddChild(genderPanel);
#endregion Gender
#region Hair
var hairPanel = HighlightedContainer();
var hairHBox = new HBoxContainer();
_hairPicker = new HairStylePicker
{
HorizontalAlignment = HAlignment.Center
};
_hairPicker.Populate();
_hairPicker.OnHairStylePicked += newStyle =>
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairStyleName(newStyle));
IsDirty = true;
};
_hairPicker.OnHairColorPicked += newColor =>
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithHairColor(newColor));
IsDirty = true;
};
_facialHairPicker = new HairStylePicker();
_facialHairPicker.Populate();
_facialHairPicker.OnHairStylePicked += newStyle =>
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithFacialHairStyleName(newStyle));
IsDirty = true;
};
_facialHairPicker.OnHairColorPicked += newColor =>
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithFacialHairColor(newColor));
IsDirty = true;
};
hairHBox.AddChild(_hairPicker);
hairHBox.AddChild(_facialHairPicker);
hairPanel.AddChild(hairHBox);
appearanceList.AddChild(hairPanel);
#endregion Hair
#region Clothing
var clothingPanel = HighlightedContainer();
var clothingHBox = new HBoxContainer();
var clothingLabel = new Label { Text = Loc.GetString("Clothing:") };
_clothingButton = new OptionButton();
_clothingButton.AddItem(Loc.GetString("Jumpsuit"), (int) ClothingPreference.Jumpsuit);
_clothingButton.AddItem(Loc.GetString("Jumpskirt"), (int) ClothingPreference.Jumpskirt);
_clothingButton.OnItemSelected += args =>
{
_clothingButton.SelectId(args.Id);
SetClothing((ClothingPreference) args.Id);
};
clothingHBox.AddChild(clothingLabel);
clothingHBox.AddChild(_clothingButton);
clothingPanel.AddChild(clothingHBox);
appearanceList.AddChild(clothingPanel);
#endregion Clothing
#region Backpack
var backpackPanel = HighlightedContainer();
var backpackHBox = new HBoxContainer();
var backpackLabel = new Label { Text = Loc.GetString("Backpack:") };
_backpackButton = new OptionButton();
_backpackButton.AddItem(Loc.GetString("Backpack"), (int) BackpackPreference.Backpack);
_backpackButton.AddItem(Loc.GetString("Satchel"), (int) BackpackPreference.Satchel);
_backpackButton.AddItem(Loc.GetString("Duffelbag"), (int) BackpackPreference.Duffelbag);
_backpackButton.OnItemSelected += args =>
{
_backpackButton.SelectId(args.Id);
SetBackpack((BackpackPreference) args.Id);
};
backpackHBox.AddChild(backpackLabel);
backpackHBox.AddChild(_backpackButton);
backpackPanel.AddChild(backpackHBox);
appearanceList.AddChild(backpackPanel);
#endregion Backpack
#region Eyes
var eyesPanel = HighlightedContainer();
var eyesVBox = new VBoxContainer();
var eyesLabel = new Label { Text = Loc.GetString("Eye color:") };
_eyesPicker = new EyeColorPicker();
_eyesPicker.OnEyeColorPicked += newColor =>
{
if (Profile is null)
return;
Profile = Profile.WithCharacterAppearance(
Profile.Appearance.WithEyeColor(newColor));
IsDirty = true;
};
eyesVBox.AddChild(eyesLabel);
eyesVBox.AddChild(_eyesPicker);
eyesPanel.AddChild(eyesVBox);
appearanceList.AddChild(eyesPanel);
#endregion Eyes
#endregion Appearance
#region Jobs
var jobList = new VBoxContainer();
var jobVBox = new VBoxContainer
{
Children =
{
(_preferenceUnavailableButton = new OptionButton()),
new ScrollContainer
{
VerticalExpand = true,
Children =
{
jobList
}
}
}
};
tabContainer.AddChild(jobVBox);
tabContainer.SetTabTitle(1, Loc.GetString("Jobs"));
_preferenceUnavailableButton.AddItem(
Loc.GetString("Stay in lobby if preference unavailable."),
(int) PreferenceUnavailableMode.StayInLobby);
_preferenceUnavailableButton.AddItem(
Loc.GetString("Be an {0} if preference unavailable.",
Loc.GetString(SharedGameTicker.OverflowJobName)),
(int) PreferenceUnavailableMode.SpawnAsOverflow);
_preferenceUnavailableButton.OnItemSelected += args =>
{
_preferenceUnavailableButton.SelectId(args.Id);
Profile = Profile?.WithPreferenceUnavailable((PreferenceUnavailableMode) args.Id);
IsDirty = true;
};
_jobPriorities = new List<JobPrioritySelector>();
_jobCategories = new Dictionary<string, VBoxContainer>();
var firstCategory = true;
foreach (var job in prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.Name))
{
foreach (var department in job.Departments)
{
if (!_jobCategories.TryGetValue(department, out var category))
{
category = new VBoxContainer
{
Name = department,
ToolTip = Loc.GetString("Jobs in the {0} department", department)
};
if (firstCategory)
{
firstCategory = false;
}
else
{
category.AddChild(new Control
{
MinSize = new Vector2(0, 23),
});
}
category.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
Children =
{
new Label
{
Text = Loc.GetString("{0} jobs", department)
}
}
});
_jobCategories[department] = category;
jobList.AddChild(category);
}
var selector = new JobPrioritySelector(job);
category.AddChild(selector);
_jobPriorities.Add(selector);
selector.PriorityChanged += priority =>
{
Profile = Profile?.WithJobPriority(job.ID, priority);
IsDirty = true;
foreach (var jobSelector in _jobPriorities)
{
// Sync other selectors with the same job in case of multiple department jobs
if (jobSelector.Job == selector.Job)
{
jobSelector.Priority = priority;
}
// Lower any other high priorities to medium.
if (priority == JobPriority.High)
{
if (jobSelector.Job != selector.Job && jobSelector.Priority == JobPriority.High)
{
jobSelector.Priority = JobPriority.Medium;
Profile = Profile?.WithJobPriority(jobSelector.Job.ID, JobPriority.Medium);
}
}
}
};
}
}
#endregion Jobs
#region Antags
var antagList = new VBoxContainer();
var antagVBox = new VBoxContainer
{
Children =
{
new ScrollContainer
{
VerticalExpand = true,
Children =
{
antagList
}
}
}
};
tabContainer.AddChild(antagVBox);
tabContainer.SetTabTitle(2, Loc.GetString("Antags"));
_antagPreferences = new List<AntagPreferenceSelector>();
foreach (var antag in prototypeManager.EnumeratePrototypes<AntagPrototype>().OrderBy(a => a.Name))
{
if (!antag.SetPreference)
{
continue;
}
var selector = new AntagPreferenceSelector(antag);
antagList.AddChild(selector);
_antagPreferences.Add(selector);
selector.PreferenceChanged += preference =>
{
Profile = Profile?.WithAntagPreference(antag.ID, preference);
IsDirty = true;
};
}
#endregion Antags
var rightColumn = new VBoxContainer();
middleContainer.AddChild(rightColumn);
#region Import/Export
var importExportPanelContainer = HighlightedContainer();
var importExportHBox = new HBoxContainer();
var importButton = new Button
{
Text = Loc.GetString("Import"),
Disabled = true,
ToolTip = "Not yet implemented!"
};
var exportButton = new Button
{
Text = Loc.GetString("Export"),
Disabled = true,
ToolTip = "Not yet implemented!"
};
importExportHBox.AddChild(importButton);
importExportHBox.AddChild(exportButton);
importExportPanelContainer.AddChild(importExportHBox);
rightColumn.AddChild(importExportPanelContainer);
#endregion Import/Export
#region Save
{
var panel = HighlightedContainer();
_saveButton = new Button
{
Text = Loc.GetString("Save"),
HorizontalAlignment = HAlignment.Center
};
_saveButton.OnPressed += args => { Save(); };
panel.AddChild(_saveButton);
rightColumn.AddChild(panel);
}
#endregion Save
#endregion Left
#region Right
vBox = new VBoxContainer()
{
VerticalExpand = true,
HorizontalExpand = true,
};
hbox.AddChild(vBox);
#region Preview
_previewDummy = entityManager.SpawnEntity("HumanMob_Dummy", MapCoordinates.Nullspace);
var sprite = _previewDummy.GetComponent<SpriteComponent>();
// Front
var box = new Control()
{
VerticalExpand = true,
SizeFlagsStretchRatio = 1f,
};
vBox.AddChild(box);
_previewSprite = new SpriteView
{
Sprite = sprite,
Scale = (6, 6),
OverrideDirection = Direction.South,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1
};
box.AddChild(_previewSprite);
// Side
box = new Control()
{
VerticalExpand = true,
SizeFlagsStretchRatio = 1f,
};
vBox.AddChild(box);
_previewSpriteSide = new SpriteView
{
Sprite = sprite,
Scale = (6, 6),
OverrideDirection = Direction.East,
VerticalAlignment = VAlignment.Center,
SizeFlagsStretchRatio = 1
};
box.AddChild(_previewSpriteSide);
#endregion Right
#endregion
if (preferencesManager.ServerDataLoaded)
{
LoadServerData();
}
preferencesManager.OnServerDataLoaded += LoadServerData;
IsDirty = false;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_previewDummy.Delete();
_preferencesManager.OnServerDataLoaded -= LoadServerData;
}
private void LoadServerData()
{
Profile = (HumanoidCharacterProfile) _preferencesManager.Preferences!.SelectedCharacter;
CharacterSlot = _preferencesManager.Preferences.SelectedCharacterIndex;
UpdateControls();
}
private void SetAge(int newAge)
{
Profile = Profile?.WithAge(newAge);
IsDirty = true;
}
private void SetSex(Sex newSex)
{
Profile = Profile?.WithSex(newSex);
IsDirty = true;
}
private void SetGender(Gender newGender)
{
Profile = Profile?.WithGender(newGender);
IsDirty = true;
}
private void SetName(string newName)
{
Profile = Profile?.WithName(newName);
IsDirty = true;
}
private void SetClothing(ClothingPreference newClothing)
{
Profile = Profile?.WithClothingPreference(newClothing);
IsDirty = true;
}
private void SetBackpack(BackpackPreference newBackpack)
{
Profile = Profile?.WithBackpackPreference(newBackpack);
IsDirty = true;
}
public void Save()
{
IsDirty = false;
if (Profile != null)
{
_preferencesManager.UpdateCharacter(Profile, CharacterSlot);
OnProfileChanged?.Invoke(Profile, CharacterSlot);
}
}
private bool IsDirty
{
get => _isDirty;
set
{
_isDirty = value;
UpdatePreview();
UpdateSaveButton();
}
}
private static Control HighlightedContainer()
{
return new PanelContainer
{
PanelOverride = HighlightedStyle
};
}
private void UpdateNameEdit()
{
_nameEdit.Text = Profile?.Name ?? "";
}
private void UpdateAgeEdit()
{
_ageEdit.Text = Profile?.Age.ToString() ?? "";
}
private void UpdateSexControls()
{
if (Profile?.Sex == Sex.Male)
_sexMaleButton.Pressed = true;
else
_sexFemaleButton.Pressed = true;
}
private void UpdateGenderControls()
{
if (Profile == null)
{
return;
}
_genderButton.SelectId((int) Profile.Gender);
}
private void UpdateClothingControls()
{
if (Profile == null)
{
return;
}
_clothingButton.SelectId((int) Profile.Clothing);
}
private void UpdateBackpackControls()
{
if (Profile == null)
{
return;
}
_backpackButton.SelectId((int) Profile.Backpack);
}
private void UpdateHairPickers()
{
if (Profile == null)
{
return;
}
_hairPicker.SetData(
Profile.Appearance.HairColor,
Profile.Appearance.HairStyleId,
SpriteAccessoryCategories.HumanHair,
true);
_facialHairPicker.SetData(
Profile.Appearance.FacialHairColor,
Profile.Appearance.FacialHairStyleId,
SpriteAccessoryCategories.HumanFacialHair,
true);
}
private void UpdateEyePickers()
{
if (Profile == null)
{
return;
}
_eyesPicker.SetData(Profile.Appearance.EyeColor);
}
private void UpdateSaveButton()
{
_saveButton.Disabled = Profile is null || !IsDirty;
}
private void UpdatePreview()
{
if (Profile is null)
return;
_previewDummy.GetComponent<HumanoidAppearanceComponent>().UpdateFromProfile(Profile);
LobbyCharacterPreviewPanel.GiveDummyJobClothes(_previewDummy, Profile);
}
public void UpdateControls()
{
if (Profile is null) return;
UpdateNameEdit();
UpdateSexControls();
UpdateGenderControls();
UpdateClothingControls();
UpdateBackpackControls();
UpdateAgeEdit();
UpdateHairPickers();
UpdateEyePickers();
UpdateSaveButton();
UpdateJobPriorities();
UpdateAntagPreferences();
UpdatePreview();
_preferenceUnavailableButton.SelectId((int) Profile.PreferenceUnavailable);
}
private void UpdateJobPriorities()
{
foreach (var prioritySelector in _jobPriorities)
{
var jobId = prioritySelector.Job.ID;
var priority = Profile?.JobPriorities.GetValueOrDefault(jobId, JobPriority.Never) ?? JobPriority.Never;
prioritySelector.Priority = priority;
}
}
private class JobPrioritySelector : Control
{
public JobPrototype Job { get; }
private readonly RadioOptions<int> _optionButton;
public JobPriority Priority
{
get => (JobPriority) _optionButton.SelectedValue;
set => _optionButton.SelectByValue((int) value);
}
public event Action<JobPriority>? PriorityChanged;
public JobPrioritySelector(JobPrototype job)
{
Job = job;
_optionButton = new RadioOptions<int>(RadioOptionsLayout.Horizontal)
{
FirstButtonStyle = StyleBase.ButtonOpenRight,
ButtonStyle = StyleBase.ButtonOpenBoth,
LastButtonStyle = StyleBase.ButtonOpenLeft
};
// Text, Value
_optionButton.AddItem(Loc.GetString("High"), (int) JobPriority.High);
_optionButton.AddItem(Loc.GetString("Medium"), (int) JobPriority.Medium);
_optionButton.AddItem(Loc.GetString("Low"), (int) JobPriority.Low);
_optionButton.AddItem(Loc.GetString("Never"), (int) JobPriority.Never);
_optionButton.OnItemSelected += args =>
{
_optionButton.Select(args.Id);
PriorityChanged?.Invoke(Priority);
};
var icon = new TextureRect
{
TextureScale = (2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
};
if (job.Icon != null)
{
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"),
job.Icon);
icon.Texture = specifier.Frame0();
}
AddChild(new HBoxContainer
{
Children =
{
icon,
new Label {Text = job.Name, MinSize = (175, 0)},
_optionButton
}
});
}
}
private void UpdateAntagPreferences()
{
foreach (var preferenceSelector in _antagPreferences)
{
var antagId = preferenceSelector.Antag.ID;
var preference = Profile?.AntagPreferences.Contains(antagId) ?? false;
preferenceSelector.Preference = preference;
}
}
private class AntagPreferenceSelector : Control
{
public AntagPrototype Antag { get; }
private readonly CheckBox _checkBox;
public bool Preference
{
get => _checkBox.Pressed;
set => _checkBox.Pressed = value;
}
public event Action<bool>? PreferenceChanged;
public AntagPreferenceSelector(AntagPrototype antag)
{
Antag = antag;
_checkBox = new CheckBox {Text = $"{antag.Name}"};
_checkBox.OnToggled += OnCheckBoxToggled;
AddChild(new HBoxContainer
{
Children =
{
_checkBox
}
});
}
private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
{
PreferenceChanged?.Invoke(Preference);
}
}
}
}

View File

@@ -1,13 +0,0 @@
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
namespace Content.Client.UserInterface
{
public interface IItemSlotManager
{
bool OnButtonPressed(GUIBoundKeyEventArgs args, IEntity? item);
void UpdateCooldown(ItemSlotButton? cooldownTexture, IEntity? entity);
bool SetItemSlot(ItemSlotButton button, IEntity? entity);
void HoverInSlot(ItemSlotButton button, IEntity? entity, bool fits);
}
}

View File

@@ -1,180 +0,0 @@
#nullable enable
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared;
using Robust.Client.Credits;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using YamlDotNet.RepresentationModel;
namespace Content.Client.UserInterface
{
public sealed class InfoWindow : SS14Window
{
[Dependency] private readonly IResourceCache _resourceManager = default!;
private OptionsMenu optionsMenu;
public InfoWindow()
{
IoCManager.InjectDependencies(this);
optionsMenu = new OptionsMenu();
Title = Loc.GetString("ui-info-title");
var rootContainer = new TabContainer();
var rulesList = new ScrollContainer
{
HScrollEnabled = false
};
var tutorialList = new ScrollContainer
{
HScrollEnabled = false
};
rootContainer.AddChild(rulesList);
rootContainer.AddChild(tutorialList);
TabContainer.SetTabTitle(rulesList, Loc.GetString("ui-info-tab-rules"));
TabContainer.SetTabTitle(tutorialList, Loc.GetString("ui-info-tab-tutorial"));
PopulateRules(rulesList);
PopulateTutorial(tutorialList);
Contents.AddChild(rootContainer);
SetSize = (650, 650);
}
private void PopulateRules(Control rulesList)
{
var vBox = new VBoxContainer
{
Margin = new Thickness(2, 2, 0, 0)
};
var first = true;
void AddSection(string title, string path, bool markup = false)
{
if (!first)
{
vBox.AddChild(new Control { MinSize = (0, 10) });
}
first = false;
vBox.AddChild(new Label { StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = title });
var label = new RichTextLabel();
var text = _resourceManager.ContentFileReadAllText($"/Server Info/{path}");
if (markup)
{
label.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
}
else
{
label.SetMessage(text);
}
vBox.AddChild(label);
}
AddSection(Loc.GetString("ui-info-header-rules"), "Rules.txt", true);
rulesList.AddChild(vBox);
}
private void PopulateTutorial(Control tutorialList)
{
Button controlsButton;
var vBox = new VBoxContainer
{
Margin = new Thickness(2, 2, 0, 0)
};
var first = true;
void AddSection(string title, string path, bool markup = false)
{
if (!first)
{
vBox.AddChild(new Control { MinSize = (0, 10) });
}
first = false;
vBox.AddChild(new Label { StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = title });
var label = new RichTextLabel();
var text = _resourceManager.ContentFileReadAllText($"/Server Info/{path}");
if (markup)
{
label.SetMessage(FormattedMessage.FromMarkup(text.Trim()));
}
else
{
label.SetMessage(text);
}
vBox.AddChild(label);
}
AddSection(Loc.GetString("ui-info-header-intro"), "Intro.txt");
vBox.AddChild(new HBoxContainer
{
MinSize = (0, 10),
Children =
{
new Label {StyleClasses = { StyleBase.StyleClassLabelHeading }, Text = Loc.GetString("ui-info-header-controls")},
}
});
vBox.AddChild(new HBoxContainer
{
SeparationOverride = 5,
Children =
{
new Label {Text = Loc.GetString("ui-info-text-controls")},
(controlsButton = new Button {Text = Loc.GetString("ui-info-button-controls")})
}
});
AddSection(Loc.GetString("ui-info-header-gameplay"), "Gameplay.txt", true);
AddSection(Loc.GetString("ui-info-header-sandbox"), "Sandbox.txt", true);
tutorialList.AddChild(vBox);
controlsButton.OnPressed += _ =>
optionsMenu.OpenCentered();
}
private static IEnumerable<string> Lines(TextReader reader)
{
while (true)
{
var line = reader.ReadLine();
if (line == null)
{
yield break;
}
yield return line;
}
}
}
}

View File

@@ -1,146 +0,0 @@
using System;
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public class ItemSlotButton : Control
{
private const string HighlightShader = "SelectionOutlineInrange";
public TextureRect Button { get; }
public SpriteView SpriteView { get; }
public SpriteView HoverSpriteView { get; }
public TextureButton StorageButton { get; }
public CooldownGraphic CooldownDisplay { get; }
public Action<GUIBoundKeyEventArgs>? OnPressed { get; set; }
public Action<GUIBoundKeyEventArgs>? OnStoragePressed { get; set; }
public Action<GUIMouseHoverEventArgs>? OnHover { get; set; }
public bool EntityHover => HoverSpriteView.Sprite != null;
public bool MouseIsHovering;
private readonly PanelContainer _highlightRect;
public string TextureName { get; set; }
public ItemSlotButton(Texture texture, Texture storageTexture, string textureName)
{
MinSize = (64, 64);
TextureName = textureName;
AddChild(Button = new TextureRect
{
Texture = texture,
TextureScale = (2, 2),
MouseFilter = MouseFilterMode.Stop
});
AddChild(_highlightRect = new PanelContainer
{
StyleClasses = { StyleNano.StyleClassHandSlotHighlight },
MinSize = (32, 32),
Visible = false
});
Button.OnKeyBindDown += OnButtonPressed;
AddChild(SpriteView = new SpriteView
{
Scale = (2, 2),
OverrideDirection = Direction.South
});
AddChild(HoverSpriteView = new SpriteView
{
Scale = (2, 2),
OverrideDirection = Direction.South
});
AddChild(StorageButton = new TextureButton
{
TextureNormal = storageTexture,
Scale = (0.75f, 0.75f),
HorizontalAlignment = HAlignment.Right,
VerticalAlignment = VAlignment.Bottom,
Visible = false,
});
StorageButton.OnKeyBindDown += args =>
{
if (args.Function != EngineKeyFunctions.UIClick)
{
OnButtonPressed(args);
}
};
StorageButton.OnPressed += OnStorageButtonPressed;
Button.OnMouseEntered += _ =>
{
MouseIsHovering = true;
};
Button.OnMouseEntered += OnButtonHover;
Button.OnMouseExited += _ =>
{
MouseIsHovering = false;
ClearHover();
};
AddChild(CooldownDisplay = new CooldownGraphic
{
Visible = false,
});
}
public void ClearHover()
{
if (EntityHover)
{
HoverSpriteView.Sprite?.Owner.Delete();
HoverSpriteView.Sprite = null;
}
}
public virtual void Highlight(bool highlight)
{
if (highlight)
{
_highlightRect.Visible = true;
}
else
{
_highlightRect.Visible = false;
}
}
private void OnButtonPressed(GUIBoundKeyEventArgs args)
{
OnPressed?.Invoke(args);
}
private void OnStorageButtonPressed(BaseButton.ButtonEventArgs args)
{
if (args.Event.Function == EngineKeyFunctions.UIClick)
{
OnStoragePressed?.Invoke(args.Event);
}
else
{
OnPressed?.Invoke(args.Event);
}
}
private void OnButtonHover(GUIMouseHoverEventArgs args)
{
OnHover?.Invoke(args);
}
}
}

View File

@@ -1,146 +0,0 @@
using Content.Client.GameObjects.Components.Storage;
using Content.Client.GameObjects.EntitySystems;
using Content.Shared.GameObjects.Components.Items;
using Content.Shared.Input;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface
{
public class ItemSlotManager : IItemSlotManager
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IUserInterfaceManager _uiMgr = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IEyeManager _eyeManager = default!;
[Dependency] private readonly IMapManager _mapManager = default!;
public bool SetItemSlot(ItemSlotButton button, IEntity? entity)
{
if (entity == null)
{
button.SpriteView.Sprite = null;
button.StorageButton.Visible = false;
}
else
{
if (!entity.TryGetComponent(out ISpriteComponent? sprite))
return false;
button.ClearHover();
button.SpriteView.Sprite = sprite;
button.StorageButton.Visible = entity.HasComponent<ClientStorageComponent>();
}
return true;
}
public bool OnButtonPressed(GUIBoundKeyEventArgs args, IEntity? item)
{
if (item == null)
return false;
if (args.Function == ContentKeyFunctions.ExamineEntity)
{
_entitySystemManager.GetEntitySystem<ExamineSystem>()
.DoExamine(item);
}
else if (args.Function == ContentKeyFunctions.OpenContextMenu)
{
_entitySystemManager.GetEntitySystem<VerbSystem>()
.OpenContextMenu(item, _uiMgr.ScreenToUIPosition(args.PointerLocation));
}
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
{
var inputSys = _entitySystemManager.GetEntitySystem<InputSystem>();
var func = args.Function;
var funcId = _inputManager.NetworkBindMap.KeyFunctionID(args.Function);
var mousePosWorld = _eyeManager.ScreenToMap(args.PointerLocation);
var coordinates = _mapManager.TryFindGridAt(mousePosWorld, out var grid) ? grid.MapToGrid(mousePosWorld) :
EntityCoordinates.FromMap(_entityManager, _mapManager, mousePosWorld);
var message = new FullInputCmdMessage(_gameTiming.CurTick, _gameTiming.TickFraction, funcId, BoundKeyState.Down,
coordinates, args.PointerLocation, item.Uid);
// client side command handlers will always be sent the local player session.
var session = _playerManager.LocalPlayer?.Session;
if (session == null)
return false;
inputSys.HandleInputCommand(session, func, message);
}
else
{
return false;
}
args.Handle();
return true;
}
public void UpdateCooldown(ItemSlotButton? button, IEntity? entity)
{
var cooldownDisplay = button?.CooldownDisplay;
if (cooldownDisplay == null)
{
return;
}
if (entity == null ||
!entity.TryGetComponent(out ItemCooldownComponent? cooldown) ||
!cooldown.CooldownStart.HasValue ||
!cooldown.CooldownEnd.HasValue)
{
cooldownDisplay.Visible = false;
return;
}
var start = cooldown.CooldownStart.Value;
var end = cooldown.CooldownEnd.Value;
var length = (end - start).TotalSeconds;
var progress = (_gameTiming.CurTime - start).TotalSeconds / length;
var ratio = (progress <= 1 ? (1 - progress) : (_gameTiming.CurTime - end).TotalSeconds * -5);
cooldownDisplay.Progress = MathHelper.Clamp((float) ratio, -1, 1);
cooldownDisplay.Visible = ratio > -1f;
}
public void HoverInSlot(ItemSlotButton button, IEntity? entity, bool fits)
{
if (entity == null || !button.MouseIsHovering)
{
button.ClearHover();
return;
}
if (!entity.HasComponent<SpriteComponent>())
{
return;
}
// Set green / red overlay at 50% transparency
var hoverEntity = _entityManager.SpawnEntity("hoverentity", MapCoordinates.Nullspace);
var hoverSprite = hoverEntity.GetComponent<SpriteComponent>();
hoverSprite.CopyFrom(entity.GetComponent<SpriteComponent>());
hoverSprite.Color = fits ? new Color(0, 255, 0, 127) : new Color(255, 0, 0, 127);
button.HoverSpriteView.Sprite = hoverSprite;
}
}
}

View File

@@ -1,162 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.GameObjects.Components;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.GameObjects.Components.Items;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using static Content.Client.StaticIoC;
namespace Content.Client.UserInterface
{
public class ItemStatusPanel : Control
{
[ViewVariables]
private readonly List<(IItemStatus, Control)> _activeStatusComponents = new();
[ViewVariables]
private readonly Label _itemNameLabel;
[ViewVariables]
private readonly VBoxContainer _statusContents;
[ViewVariables]
private readonly PanelContainer _panel;
[ViewVariables]
private IEntity? _entity;
public ItemStatusPanel(Texture texture, StyleBox.Margin cutout, StyleBox.Margin flat, Label.AlignMode textAlign)
{
var panel = new StyleBoxTexture
{
Texture = texture
};
panel.SetContentMarginOverride(StyleBox.Margin.Vertical, 4);
panel.SetContentMarginOverride(StyleBox.Margin.Horizontal, 6);
panel.SetPatchMargin(flat, 2);
panel.SetPatchMargin(cutout, 13);
AddChild(_panel = new PanelContainer
{
PanelOverride = panel,
ModulateSelfOverride = Color.White.WithAlpha(0.9f),
Children =
{
new VBoxContainer
{
SeparationOverride = 0,
Children =
{
(_statusContents = new VBoxContainer()),
(_itemNameLabel = new Label
{
ClipText = true,
StyleClasses = {StyleNano.StyleClassItemStatus},
Align = textAlign
})
}
}
}
});
VerticalAlignment = VAlignment.Bottom;
// TODO: Depending on if its a two-hand panel or not
MinSize = (150, 0);
}
/// <summary>
/// Creates a new instance of <see cref="ItemStatusPanel"/>
/// based on whether or not it is being created for the right
/// or left hand.
/// </summary>
/// <param name="location">
/// The location of the hand that this panel is for
/// </param>
/// <returns>the new <see cref="ItemStatusPanel"/> instance</returns>
public static ItemStatusPanel FromSide(HandLocation location)
{
string texture;
StyleBox.Margin cutOut;
StyleBox.Margin flat;
Label.AlignMode textAlign;
switch (location)
{
case HandLocation.Left:
texture = "/Textures/Interface/Nano/item_status_right.svg.96dpi.png";
cutOut = StyleBox.Margin.Left | StyleBox.Margin.Top;
flat = StyleBox.Margin.Right | StyleBox.Margin.Bottom;
textAlign = Label.AlignMode.Right;
break;
case HandLocation.Middle:
texture = "/Textures/Interface/Nano/item_status_middle.svg.96dpi.png";
cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
textAlign = Label.AlignMode.Left;
break;
case HandLocation.Right:
texture = "/Textures/Interface/Nano/item_status_left.svg.96dpi.png";
cutOut = StyleBox.Margin.Right | StyleBox.Margin.Top;
flat = StyleBox.Margin.Left | StyleBox.Margin.Bottom;
textAlign = Label.AlignMode.Left;
break;
default:
throw new ArgumentOutOfRangeException(nameof(location), location, null);
}
return new ItemStatusPanel(ResC.GetTexture(texture), cutOut, flat, textAlign);
}
public void Update(IEntity? entity)
{
if (entity == null)
{
ClearOldStatus();
_entity = null;
_panel.Visible = false;
return;
}
if (entity != _entity)
{
_entity = entity;
BuildNewEntityStatus();
_itemNameLabel.Text = entity.Name;
}
_panel.Visible = true;
}
private void ClearOldStatus()
{
_statusContents.RemoveAllChildren();
foreach (var (itemStatus, control) in _activeStatusComponents)
{
itemStatus.DestroyControl(control);
}
_activeStatusComponents.Clear();
}
private void BuildNewEntityStatus()
{
DebugTools.AssertNotNull(_entity);
ClearOldStatus();
foreach (var statusComponent in _entity!.GetAllComponents<IItemStatus>())
{
var control = statusComponent.MakeControl();
_statusContents.AddChild(control);
_activeStatusComponents.Add((statusComponent, control));
}
}
}
}

View File

@@ -1,184 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.Interfaces;
using Content.Shared.Roles;
using Robust.Client.Console;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.Utility;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Log;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface
{
public sealed class LateJoinGui : SS14Window
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClientConsoleHost _consoleHost = default!;
[Dependency] private readonly IClientGameTicker _gameTicker = default!;
public event Action<string>? SelectedId;
private readonly Dictionary<string, JobButton> _jobButtons = new();
private readonly Dictionary<string, VBoxContainer> _jobCategories = new();
public LateJoinGui()
{
MinSize = SetSize = (360, 560);
IoCManager.InjectDependencies(this);
Title = Loc.GetString("Late Join");
var jobList = new VBoxContainer();
var vBox = new VBoxContainer
{
Children =
{
new ScrollContainer
{
VerticalExpand = true,
Children =
{
jobList
}
}
}
};
Contents.AddChild(vBox);
var firstCategory = true;
foreach (var job in _prototypeManager.EnumeratePrototypes<JobPrototype>().OrderBy(j => j.Name))
{
foreach (var department in job.Departments)
{
if (!_jobCategories.TryGetValue(department, out var category))
{
category = new VBoxContainer
{
Name = department,
ToolTip = Loc.GetString("Jobs in the {0} department", department)
};
if (firstCategory)
{
firstCategory = false;
}
else
{
category.AddChild(new Control
{
MinSize = new Vector2(0, 23),
});
}
category.AddChild(new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#464966")},
Children =
{
new Label
{
Text = Loc.GetString("{0} jobs", department)
}
}
});
_jobCategories[department] = category;
jobList.AddChild(category);
}
var jobButton = new JobButton(job.ID);
var jobSelector = new HBoxContainer
{
HorizontalExpand = true
};
var icon = new TextureRect
{
TextureScale = (2, 2),
Stretch = TextureRect.StretchMode.KeepCentered
};
if (job.Icon != null)
{
var specifier = new SpriteSpecifier.Rsi(new ResourcePath("/Textures/Interface/Misc/job_icons.rsi"), job.Icon);
icon.Texture = specifier.Frame0();
}
jobSelector.AddChild(icon);
var jobLabel = new Label
{
Text = job.Name
};
jobSelector.AddChild(jobLabel);
jobButton.AddChild(jobSelector);
category.AddChild(jobButton);
jobButton.OnPressed += _ =>
{
SelectedId?.Invoke(jobButton.JobId);
};
if (!_gameTicker.JobsAvailable.Contains(job.ID))
{
jobButton.Disabled = true;
}
_jobButtons[job.ID] = jobButton;
}
}
SelectedId += jobId =>
{
Logger.InfoS("latejoin", $"Late joining as ID: {jobId}");
_consoleHost.ExecuteCommand($"joingame {CommandParsing.Escape(jobId)}");
Close();
};
_gameTicker.LobbyJobsAvailableUpdated += JobsAvailableUpdated;
}
private void JobsAvailableUpdated(IReadOnlyList<string> jobs)
{
foreach (var (id, button) in _jobButtons)
{
button.Disabled = !jobs.Contains(id);
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_gameTicker.LobbyJobsAvailableUpdated -= JobsAvailableUpdated;
_jobButtons.Clear();
_jobCategories.Clear();
}
}
}
class JobButton : ContainerButton
{
public string JobId { get; }
public JobButton(string jobId)
{
JobId = jobId;
AddStyleClass(StyleClassButton);
}
}
}

View File

@@ -1,53 +0,0 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:cui="clr-namespace:Content.Client.UserInterface.Controls"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:cuic="clr-namespace:Content.Client.UserInterface">
<cuic:ParallaxControl />
<Control HorizontalAlignment="Center" VerticalAlignment="Center">
<PanelContainer StyleClasses="AngleRect" />
<VBoxContainer MinSize="300 200">
<HBoxContainer>
<Label Margin="8 0 0 0" Text="{Loc 'connecting-title'}"
StyleClasses="LabelHeading" VAlign="Center" />
<Button Name="ExitButton" Text="{Loc 'connecting-exit'}"
HorizontalAlignment="Right" HorizontalExpand="True" />
</HBoxContainer>
<cui:HighDivider />
<VBoxContainer VerticalExpand="True" Margin="4 4 4 0">
<Control VerticalExpand="True" Margin="0 0 0 8">
<VBoxContainer Name="ConnectingStatus">
<Label Text="{Loc 'connecting-in-progress'}" Align="Center" />
<!-- Who the fuck named these cont- oh wait I did -->
<Label Name="ConnectStatus" StyleClasses="LabelSubText" Align="Center" />
</VBoxContainer>
<VBoxContainer Name="ConnectFail" Visible="False">
<Label Name="ConnectFailReason" Align="Center" />
<Button Name="RetryButton" Text="{Loc 'connecting-retry'}"
HorizontalAlignment="Center"
VerticalExpand="True" VerticalAlignment="Bottom" />
</VBoxContainer>
<VBoxContainer Name="Disconnected">
<Label Text="{Loc 'connecting-disconnected'}" Align="Center" />
<Label Name="DisconnectReason" Align="Center" />
<Button Name="ReconnectButton" Text="{Loc 'connecting-reconnect'}"
HorizontalAlignment="Center"
VerticalExpand="True" VerticalAlignment="Bottom" />
</VBoxContainer>
</Control>
<Label Name="ConnectingAddress" StyleClasses="LabelSubText" HorizontalAlignment="Center" />
</VBoxContainer>
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="#444" ContentMarginTopOverride="2" />
</PanelContainer.PanelOverride>
</PanelContainer>
<HBoxContainer Margin="12 0 4 0" VerticalAlignment="Bottom">
<Label Text="{Loc 'connecting-tip'}" StyleClasses="LabelSubText" />
<Label Text="{Loc 'connecting-version'}" StyleClasses="LabelSubText"
HorizontalAlignment="Right" HorizontalExpand="True" />
</HBoxContainer>
</VBoxContainer>
</Control>
</Control>

View File

@@ -1,62 +0,0 @@
using Content.Client.State;
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Network;
namespace Content.Client.UserInterface
{
[GenerateTypedNameReferences]
public sealed partial class LauncherConnectingGui : Control
{
private readonly LauncherConnecting _state;
public LauncherConnectingGui(LauncherConnecting state)
{
_state = state;
RobustXamlLoader.Load(this);
LayoutContainer.SetAnchorPreset(this, LayoutContainer.LayoutPreset.Wide);
Stylesheet = IoCManager.Resolve<IStylesheetManager>().SheetSpace;
ReconnectButton.OnPressed += _ => _state.RetryConnect();
RetryButton.OnPressed += _ => _state.RetryConnect();
ExitButton.OnPressed += _ => _state.Exit();
var addr = state.Address;
if (addr != null)
ConnectingAddress.Text = addr;
state.PageChanged += OnPageChanged;
state.ConnectFailReasonChanged += ConnectFailReasonChanged;
state.ConnectionStateChanged += ConnectionStateChanged;
ConnectionStateChanged(state.ConnectionState);
}
private void ConnectFailReasonChanged(string? reason)
{
ConnectFailReason.Text = reason == null
? null
: Loc.GetString("connecting-fail-reason", ("reason", reason));
}
private void OnPageChanged(LauncherConnecting.Page page)
{
ConnectingStatus.Visible = page == LauncherConnecting.Page.Connecting;
ConnectFail.Visible = page == LauncherConnecting.Page.ConnectFailed;
Disconnected.Visible = page == LauncherConnecting.Page.Disconnected;
}
private void ConnectionStateChanged(ClientConnectionState state)
{
ConnectStatus.Text = Loc.GetString($"connecting-state-{state}");
}
}
}

View File

@@ -1,159 +0,0 @@
using System.Linq;
using Content.Client.GameObjects.Components.HUD.Inventory;
using Content.Client.GameObjects.Components.Mobs;
using Content.Client.Interfaces;
using Content.Shared.GameTicking;
using Content.Shared.Preferences;
using Content.Shared.Roles;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
using static Content.Shared.GameObjects.Components.Inventory.EquipmentSlotDefines;
namespace Content.Client.UserInterface
{
public class LobbyCharacterPreviewPanel : Control
{
private readonly IClientPreferencesManager _preferencesManager;
private IEntity _previewDummy;
private readonly Label _summaryLabel;
private readonly VBoxContainer _loaded;
private readonly Label _unloaded;
public LobbyCharacterPreviewPanel(IEntityManager entityManager,
IClientPreferencesManager preferencesManager)
{
_preferencesManager = preferencesManager;
_previewDummy = entityManager.SpawnEntity("HumanMob_Dummy", MapCoordinates.Nullspace);
var header = new NanoHeading
{
Text = Loc.GetString("Character")
};
CharacterSetupButton = new Button
{
Text = Loc.GetString("Customize"),
HorizontalAlignment = HAlignment.Left
};
_summaryLabel = new Label();
var viewSouth = MakeSpriteView(_previewDummy, Direction.South);
var viewNorth = MakeSpriteView(_previewDummy, Direction.North);
var viewWest = MakeSpriteView(_previewDummy, Direction.West);
var viewEast = MakeSpriteView(_previewDummy, Direction.East);
var vBox = new VBoxContainer();
vBox.AddChild(header);
_unloaded = new Label {Text = "Your character preferences have not yet loaded, please stand by."};
_loaded = new VBoxContainer {Visible = false};
_loaded.AddChild(CharacterSetupButton);
_loaded.AddChild(_summaryLabel);
var hBox = new HBoxContainer();
hBox.AddChild(viewSouth);
hBox.AddChild(viewNorth);
hBox.AddChild(viewWest);
hBox.AddChild(viewEast);
_loaded.AddChild(hBox);
vBox.AddChild(_loaded);
vBox.AddChild(_unloaded);
AddChild(vBox);
UpdateUI();
_preferencesManager.OnServerDataLoaded += UpdateUI;
}
public Button CharacterSetupButton { get; }
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_preferencesManager.OnServerDataLoaded -= UpdateUI;
if (!disposing) return;
_previewDummy.Delete();
_previewDummy = null!;
}
private static SpriteView MakeSpriteView(IEntity entity, Direction direction)
{
return new()
{
Sprite = entity.GetComponent<ISpriteComponent>(),
OverrideDirection = direction,
Scale = (2, 2)
};
}
public void UpdateUI()
{
if (!_preferencesManager.ServerDataLoaded)
{
_loaded.Visible = false;
_unloaded.Visible = true;
}
else
{
_loaded.Visible = true;
_unloaded.Visible = false;
if (_preferencesManager.Preferences?.SelectedCharacter is not HumanoidCharacterProfile selectedCharacter)
{
_summaryLabel.Text = string.Empty;
}
else
{
_summaryLabel.Text = selectedCharacter.Summary;
var component = _previewDummy.GetComponent<HumanoidAppearanceComponent>();
component.UpdateFromProfile(selectedCharacter);
GiveDummyJobClothes(_previewDummy, selectedCharacter);
}
}
}
public static void GiveDummyJobClothes(IEntity dummy, HumanoidCharacterProfile profile)
{
var protoMan = IoCManager.Resolve<IPrototypeManager>();
var inventory = dummy.GetComponent<ClientInventoryComponent>();
var highPriorityJob = profile.JobPriorities.FirstOrDefault(p => p.Value == JobPriority.High).Key;
var job = protoMan.Index<JobPrototype>(highPriorityJob ?? SharedGameTicker.OverflowJob);
inventory.ClearAllSlotVisuals();
if (job.StartingGear != null)
{
var entityMan = IoCManager.Resolve<IEntityManager>();
var gear = protoMan.Index<StartingGearPrototype>(job.StartingGear);
foreach (var slot in AllSlots)
{
var itemType = gear.GetGear(slot, profile);
if (itemType != "")
{
var item = entityMan.SpawnEntity(itemType, MapCoordinates.Nullspace);
inventory.SetSlotVisuals(slot, item);
item.Delete();
}
}
}
}
}
}

View File

@@ -1,94 +0,0 @@
<Control xmlns="https://spacestation14.io"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:gfx="clr-namespace:Robust.Client.Graphics;assembly=Robust.Client"
xmlns:style="clr-namespace:Content.Client.UserInterface.Stylesheets"
xmlns:cui="clr-namespace:Content.Client.UserInterface"
xmlns:chat="clr-namespace:Content.Client.Chat"
xmlns:maths="clr-namespace:Robust.Shared.Maths;assembly=Robust.Shared.Maths"
xmlns:voting="clr-namespace:Content.Client.Voting">
<Control>
<!-- Parallax background -->
<cui:ParallaxControl />
<!-- One day I'll code a Margin property for controls. -->
<MarginContainer MarginBottomOverride="20" MarginLeftOverride="20" MarginRightOverride="20"
MarginTopOverride="20">
<PanelContainer StyleClasses="AngleRect" />
<VBoxContainer>
<!-- Top row -->
<HBoxContainer MinSize="0 40">
<MarginContainer MarginLeftOverride="8">
<Label StyleClasses="LabelHeadingBigger" VAlign="Center" Text="{Loc 'Lobby'}" />
</MarginContainer>
<Label Name="CServerName" StyleClasses="LabelHeadingBigger" VAlign="Center" />
<voting:VoteCallMenuButton Name="CCallVoteButton" StyleClasses="ButtonBig" />
<Button Name="COptionsButton" StyleClasses="ButtonBig" Text="{Loc 'Options'}" />
<Button Name="CLeaveButton" StyleClasses="ButtonBig" Text="{Loc 'Leave'}" />
</HBoxContainer>
<!-- Gold line -->
<PanelContainer>
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.NanoGold}"
ContentMarginTopOverride="2" />
</PanelContainer.PanelOverride>
</PanelContainer>
<!-- Middle section with the two vertical panels -->
<HBoxContainer VerticalExpand="True">
<!-- Left panel -->
<VBoxContainer Name="CLeftPanelContainer" HorizontalExpand="True">
<cui:StripeBack>
<MarginContainer MarginLeftOverride="3" MarginRightOverride="3" MarginBottomOverride="3"
MarginTopOverride="3">
<HBoxContainer SeparationOverride="6">
<Button Name="CObserveButton" Text="{Loc 'Observe'}" StyleClasses="ButtonBig" />
<Label Name="CStartTime" Align="Right"
FontColorOverride="{x:Static maths:Color.DarkGray}"
StyleClasses="LabelBig" HorizontalExpand="True" />
<Button Name="CReadyButton" ToggleMode="True" Text="{Loc 'Ready Up'}"
StyleClasses="ButtonBig" />
</HBoxContainer>
</MarginContainer>
</cui:StripeBack>
<MarginContainer VerticalExpand="True" MarginLeftOverride="3" MarginRightOverride="3"
MarginBottomOverride="3"
MarginTopOverride="3">
<chat:ChatBox Name="CChat" />
</MarginContainer>
</VBoxContainer>
<!-- Gold line -->
<PanelContainer MinSize="2 0">
<PanelContainer.PanelOverride>
<gfx:StyleBoxFlat BackgroundColor="{x:Static style:StyleNano.NanoGold}" />
</PanelContainer.PanelOverride>
</PanelContainer>
<!-- Right panel -->
<Control HorizontalExpand="True">
<VBoxContainer>
<!-- Player list -->
<cui:NanoHeading Text="{Loc 'Online Players'}" />
<MarginContainer VerticalExpand="True"
MarginRightOverride="3" MarginLeftOverride="3"
MarginBottomOverride="3" MarginTopOverride="3">
<cui:LobbyPlayerList Name="COnlinePlayerList"
HorizontalExpand="True"
VerticalExpand="True" />
</MarginContainer>
<!-- Server info -->
<cui:NanoHeading Text="{Loc 'Server Info'}" />
<MarginContainer VerticalExpand="True"
MarginRightOverride="3" MarginLeftOverride="3"
MarginBottomOverride="2" MarginTopOverride="3">
<cui:ServerInfo Name="CServerInfo" />
</MarginContainer>
</VBoxContainer>
<MarginContainer SizeFlagsHorizontal="ShrinkEnd" MarginTopOverride="8" MarginRightOverride="8">
<VBoxContainer Name="CVoteContainer" />
</MarginContainer>
</Control>
</HBoxContainer>
</VBoxContainer>
</MarginContainer>
</Control>
</Control>

View File

@@ -1,125 +0,0 @@
using Content.Client.Chat;
using Content.Client.Interfaces;
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.GameObjects;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
[GenerateTypedNameReferences]
internal sealed partial class LobbyGui : Control
{
public Label ServerName => CServerName;
public Label StartTime => CStartTime;
public Button ReadyButton => CReadyButton;
public Button ObserveButton => CObserveButton;
public Button OptionsButton => COptionsButton;
public Button LeaveButton => CLeaveButton;
public ChatBox Chat => CChat;
public VBoxContainer VoteContainer => CVoteContainer;
public LobbyPlayerList OnlinePlayerList => COnlinePlayerList;
public ServerInfo ServerInfo => CServerInfo;
public LobbyCharacterPreviewPanel CharacterPreview { get; }
public LobbyGui(IEntityManager entityManager,
IClientPreferencesManager preferencesManager)
{
RobustXamlLoader.Load(this);
ServerName.HorizontalExpand = true;
ServerName.HorizontalAlignment = HAlignment.Center;
CharacterPreview = new LobbyCharacterPreviewPanel(
entityManager,
preferencesManager)
{
HorizontalAlignment = HAlignment.Left
};
CLeftPanelContainer.AddChild(CharacterPreview);
CharacterPreview.SetPositionFirst();
}
}
public class LobbyPlayerList : Control
{
private readonly ScrollContainer _scroll;
private readonly VBoxContainer _vBox;
public LobbyPlayerList()
{
var panel = new PanelContainer()
{
PanelOverride = new StyleBoxFlat {BackgroundColor = Color.FromHex("#202028")},
};
_vBox = new VBoxContainer();
_scroll = new ScrollContainer();
_scroll.AddChild(_vBox);
panel.AddChild(_scroll);
AddChild(panel);
}
// Adds a row
public void AddItem(string name, string status)
{
var hbox = new HBoxContainer
{
HorizontalExpand = true,
};
// Player Name
hbox.AddChild(new PanelContainer()
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = Color.FromHex("#373744"),
ContentMarginBottomOverride = 2,
ContentMarginLeftOverride = 4,
ContentMarginRightOverride = 4,
ContentMarginTopOverride = 2
},
Children =
{
new Label
{
Text = name
}
},
HorizontalExpand = true
});
// Status
hbox.AddChild(new PanelContainer()
{
PanelOverride = new StyleBoxFlat
{
BackgroundColor = Color.FromHex("#373744"),
ContentMarginBottomOverride = 2,
ContentMarginLeftOverride = 4,
ContentMarginRightOverride = 4,
ContentMarginTopOverride = 2
},
Children =
{
new Label
{
Text = status
}
},
HorizontalExpand = true,
SizeFlagsStretchRatio = 0.2f,
});
_vBox.AddChild(hbox);
}
// Deletes all rows
public void Clear()
{
_vBox.RemoveAllChildren();
}
}
}

View File

@@ -1,153 +0,0 @@
using System;
using Content.Shared;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
/// <summary>
/// Wrapper for <see cref="ScalingViewport"/> that listens to configuration variables.
/// Also does NN-snapping within tolerances.
/// </summary>
public sealed class MainViewport : Control
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly ViewportManager _vpManager = default!;
public ScalingViewport Viewport { get; }
public MainViewport()
{
IoCManager.InjectDependencies(this);
Viewport = new ScalingViewport
{
AlwaysRender = true,
RenderScaleMode = ScalingViewportRenderScaleMode.CeilInt,
MouseFilter = MouseFilterMode.Stop
};
AddChild(Viewport);
}
protected override void EnteredTree()
{
base.EnteredTree();
_vpManager.AddViewport(this);
}
protected override void ExitedTree()
{
base.ExitedTree();
_vpManager.RemoveViewport(this);
}
public void UpdateCfg()
{
var stretch = _cfg.GetCVar(CCVars.ViewportStretch);
var renderScaleUp = _cfg.GetCVar(CCVars.ViewportScaleRender);
var fixedFactor = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
if (stretch)
{
var snapFactor = CalcSnappingFactor();
if (snapFactor == null)
{
// Did not find a snap, enable stretching.
Viewport.FixedStretchSize = null;
Viewport.StretchMode = ScalingViewportStretchMode.Bilinear;
if (renderScaleUp)
{
Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.CeilInt;
}
else
{
Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
Viewport.FixedRenderScale = 1;
}
return;
}
// Found snap, set fixed factor and run non-stretching code.
fixedFactor = snapFactor.Value;
}
Viewport.FixedStretchSize = Viewport.ViewportSize * fixedFactor;
Viewport.StretchMode = ScalingViewportStretchMode.Nearest;
if (renderScaleUp)
{
Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
Viewport.FixedRenderScale = fixedFactor;
}
else
{
// Snapping but forced to render scale at scale 1 so...
// At least we can NN.
Viewport.RenderScaleMode = ScalingViewportRenderScaleMode.Fixed;
Viewport.FixedRenderScale = 1;
}
}
private int? CalcSnappingFactor()
{
// Margin tolerance is tolerance of "the window is too big"
// where we add a margin to the viewport to make it fit.
var cfgToleranceMargin = _cfg.GetCVar(CCVars.ViewportSnapToleranceMargin);
// Clip tolerance is tolerance of "the window is too small"
// where we are clipping the viewport to make it fit.
var cfgToleranceClip = _cfg.GetCVar(CCVars.ViewportSnapToleranceClip);
// Calculate if the viewport, when rendered at an integer scale,
// is close enough to the control size to enable "snapping" to NN,
// potentially cutting a tiny bit off/leaving a margin.
//
// Idea here is that if you maximize the window at 1080p or 1440p
// we are close enough to an integer scale (2x and 3x resp) that we should "snap" to it.
// Just do it iteratively.
// I'm sure there's a smarter approach that needs one try with math but I'm dumb.
for (var i = 1; i <= 10; i++)
{
var toleranceMargin = i * cfgToleranceMargin;
var toleranceClip = i * cfgToleranceClip;
var scaled = (Vector2) Viewport.ViewportSize * i;
var (dx, dy) = PixelSize - scaled;
// The rule for which snap fits is that at LEAST one axis needs to be in the tolerance size wise.
// One axis MAY be larger but not smaller than tolerance.
// Obviously if it's too small it's bad, and if it's too big on both axis we should stretch up.
if (Fits(dx) && Fits(dy) || Fits(dx) && Larger(dy) || Larger(dx) && Fits(dy))
{
// Found snap that fits.
return i;
}
bool Larger(float a)
{
return a > toleranceMargin;
}
bool Fits(float a)
{
return a <= toleranceMargin && a >= -toleranceClip;
}
}
return null;
}
protected override void Resized()
{
base.Resized();
UpdateCfg();
}
}
}

View File

@@ -1,32 +0,0 @@
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public class NanoHeading : Container
{
private readonly Label _label;
private readonly PanelContainer _panel;
public NanoHeading()
{
_panel = new PanelContainer
{
Children = {(_label = new Label
{
StyleClasses = {StyleNano.StyleClassLabelHeading}
})}
};
AddChild(_panel);
HorizontalAlignment = HAlignment.Left;
}
public string? Text
{
get => _label.Text;
set => _label.Text = value;
}
}
}

View File

@@ -1,196 +0,0 @@
using Content.Client.UserInterface.Stylesheets;
using Content.Shared;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu
{
private sealed class AudioControl : Control
{
private readonly IConfigurationManager _cfg;
private readonly IClydeAudio _clydeAudio;
private readonly Button ApplyButton;
private readonly Label MasterVolumeLabel;
private readonly Slider MasterVolumeSlider;
private readonly CheckBox AmbienceCheckBox;
private readonly CheckBox LobbyMusicCheckBox;
private readonly Button ResetButton;
public AudioControl(IConfigurationManager cfg, IClydeAudio clydeAudio)
{
_cfg = cfg;
_clydeAudio = clydeAudio;
var vBox = new VBoxContainer();
var contents = new VBoxContainer
{
Margin = new Thickness(2, 2, 2, 0),
VerticalExpand = true,
};
MasterVolumeSlider = new Slider
{
MinValue = 0.0f,
MaxValue = 100.0f,
HorizontalExpand = true,
MinSize = (80, 8),
Rounded = true
};
MasterVolumeLabel = new Label
{
MinSize = (48, 0),
Align = Label.AlignMode.Right
};
contents.AddChild(new HBoxContainer
{
Children =
{
new Control {MinSize = (4, 0)},
new Label {Text = Loc.GetString("ui-options-master-volume")},
new Control {MinSize = (8, 0)},
MasterVolumeSlider,
new Control {MinSize = (8, 0)},
MasterVolumeLabel,
new Control {MinSize = (4, 0)},
}
});
// sets up ambience checkbox. i am sorry for not fixing the rest of this code.
AmbienceCheckBox = new CheckBox {Text = Loc.GetString("ui-options-ambient-hum")};
contents.AddChild(AmbienceCheckBox);
AmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.AmbienceBasicEnabled);
LobbyMusicCheckBox = new CheckBox {Text = Loc.GetString("ui-options-lobby-music")};
contents.AddChild(LobbyMusicCheckBox);
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
ApplyButton = new Button
{
Text = Loc.GetString("ui-options-apply"), TextAlign = Label.AlignMode.Center,
HorizontalAlignment = HAlignment.Right
};
vBox.AddChild(new Label
{
Text = Loc.GetString("ui-options-volume-sliders"),
FontColorOverride = StyleNano.NanoGold,
StyleClasses = {StyleNano.StyleClassLabelKeyText}
});
vBox.AddChild(contents);
ResetButton = new Button
{
Text = Loc.GetString("ui-options-reset-all"),
StyleClasses = {StyleBase.ButtonCaution},
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right
};
vBox.AddChild(new StripeBack
{
HasBottomEdge = false,
HasMargins = false,
Children =
{
new HBoxContainer
{
Align = BoxContainer.AlignMode.End,
HorizontalExpand = true,
VerticalExpand = true,
Children =
{
ResetButton,
new Control {MinSize = (2, 0)},
ApplyButton
}
}
}
});
ApplyButton.OnPressed += OnApplyButtonPressed;
ResetButton.OnPressed += OnResetButtonPressed;
MasterVolumeSlider.OnValueChanged += OnMasterVolumeSliderChanged;
AmbienceCheckBox.OnToggled += OnAmbienceCheckToggled;
LobbyMusicCheckBox.OnToggled += OnLobbyMusicCheckToggled;
AddChild(vBox);
Reset();
}
protected override void Dispose(bool disposing)
{
ApplyButton.OnPressed -= OnApplyButtonPressed;
ResetButton.OnPressed -= OnResetButtonPressed;
MasterVolumeSlider.OnValueChanged -= OnMasterVolumeSliderChanged;
AmbienceCheckBox.OnToggled -= OnAmbienceCheckToggled;
base.Dispose(disposing);
}
private void OnMasterVolumeSliderChanged(Range range)
{
MasterVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
_clydeAudio.SetMasterVolume(MasterVolumeSlider.Value / 100);
UpdateChanges();
}
private void OnAmbienceCheckToggled(BaseButton.ButtonEventArgs args)
{
UpdateChanges();
}
private void OnLobbyMusicCheckToggled(BaseButton.ButtonEventArgs args)
{
UpdateChanges();
}
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
_cfg.SetCVar(CVars.AudioMasterVolume, MasterVolumeSlider.Value / 100);
_cfg.SetCVar(CCVars.AmbienceBasicEnabled, AmbienceCheckBox.Pressed);
_cfg.SetCVar(CCVars.LobbyMusicEnabled, LobbyMusicCheckBox.Pressed);
_cfg.SaveToFile();
UpdateChanges();
}
private void OnResetButtonPressed(BaseButton.ButtonEventArgs args)
{
Reset();
}
private void Reset()
{
MasterVolumeSlider.Value = _cfg.GetCVar(CVars.AudioMasterVolume) * 100;
MasterVolumeLabel.Text =
Loc.GetString("ui-options-volume-percent", ("volume", MasterVolumeSlider.Value / 100));
AmbienceCheckBox.Pressed = _cfg.GetCVar(CCVars.AmbienceBasicEnabled);
LobbyMusicCheckBox.Pressed = _cfg.GetCVar(CCVars.LobbyMusicEnabled);
UpdateChanges();
}
private void UpdateChanges()
{
var isMasterVolumeSame =
System.Math.Abs(MasterVolumeSlider.Value - _cfg.GetCVar(CVars.AudioMasterVolume) * 100) < 0.01f;
var isAmbienceSame = AmbienceCheckBox.Pressed == _cfg.GetCVar(CCVars.AmbienceBasicEnabled);
var isLobbySame = LobbyMusicCheckBox.Pressed == _cfg.GetCVar(CCVars.LobbyMusicEnabled);
var isEverythingSame = isMasterVolumeSame && isAmbienceSame && isLobbySame;
ApplyButton.Disabled = isEverythingSame;
ResetButton.Disabled = isEverythingSame;
}
}
}
}

View File

@@ -1,335 +0,0 @@
using Content.Shared;
using Content.Shared.Prototypes.HUD;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared;
using Robust.Shared.Configuration;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu
{
private sealed class GraphicsControl : Control
{
private static readonly float[] UIScaleOptions =
{
0f,
0.75f,
1f,
1.25f,
1.50f,
1.75f,
2f
};
private readonly IConfigurationManager _cfg;
private readonly IPrototypeManager _prototypeManager;
private readonly Button ApplyButton;
private readonly CheckBox VSyncCheckBox;
private readonly CheckBox FullscreenCheckBox;
private readonly OptionButton LightingPresetOption;
private readonly OptionButton _uiScaleOption;
private readonly OptionButton _hudThemeOption;
private readonly CheckBox _viewportStretchCheckBox;
private readonly CheckBox _viewportLowResCheckBox;
private readonly Slider _viewportScaleSlider;
private readonly Control _viewportScaleBox;
private readonly Label _viewportScaleText;
public GraphicsControl(IConfigurationManager cfg, IPrototypeManager proMan)
{
_cfg = cfg;
_prototypeManager = proMan;
var vBox = new VBoxContainer();
var contents = new VBoxContainer
{
Margin = new Thickness(2, 2, 2, 0),
VerticalExpand = true,
};
VSyncCheckBox = new CheckBox {Text = Loc.GetString("ui-options-vsync")};
contents.AddChild(VSyncCheckBox);
VSyncCheckBox.OnToggled += OnCheckBoxToggled;
FullscreenCheckBox = new CheckBox {Text = Loc.GetString("ui-options-fullscreen")};
contents.AddChild(FullscreenCheckBox);
FullscreenCheckBox.OnToggled += OnCheckBoxToggled;
LightingPresetOption = new OptionButton {MinSize = (100, 0)};
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-very-low"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-low"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-medium"));
LightingPresetOption.AddItem(Loc.GetString("ui-options-lighting-high"));
LightingPresetOption.OnItemSelected += OnLightingQualityChanged;
contents.AddChild(new HBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("ui-options-lighting-label")},
new Control {MinSize = (4, 0)},
LightingPresetOption
}
});
ApplyButton = new Button
{
Text = Loc.GetString("ui-options-apply"), TextAlign = Label.AlignMode.Center,
HorizontalAlignment = HAlignment.Right
};
_uiScaleOption = new OptionButton();
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-auto",
("scale", UserInterfaceManager.DefaultUIScale)));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-75"));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-100"));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-125"));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-150"));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-175"));
_uiScaleOption.AddItem(Loc.GetString("ui-options-scale-200"));
_uiScaleOption.OnItemSelected += OnUIScaleChanged;
contents.AddChild(new HBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("ui-options-scale-label")},
new Control {MinSize = (4, 0)},
_uiScaleOption
}
});
_hudThemeOption = new OptionButton();
foreach (var gear in _prototypeManager.EnumeratePrototypes<HudThemePrototype>())
{
_hudThemeOption.AddItem(Loc.GetString(gear.Name));
}
_hudThemeOption.OnItemSelected += OnHudThemeChanged;
contents.AddChild(new HBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("ui-options-hud-theme")},
new Control {MinSize = (4, 0)},
_hudThemeOption
}
});
_viewportStretchCheckBox = new CheckBox
{
Text = Loc.GetString("ui-options-vp-stretch")
};
_viewportStretchCheckBox.OnToggled += _ =>
{
UpdateViewportScale();
UpdateApplyButton();
};
_viewportScaleSlider = new Slider
{
MinValue = 1,
MaxValue = 5,
Rounded = true,
MinWidth = 200
};
_viewportScaleSlider.OnValueChanged += _ =>
{
UpdateApplyButton();
UpdateViewportScale();
};
_viewportLowResCheckBox = new CheckBox { Text = Loc.GetString("ui-options-vp-low-res")};
_viewportLowResCheckBox.OnToggled += OnCheckBoxToggled;
contents.AddChild(new HBoxContainer
{
Children =
{
_viewportStretchCheckBox,
(_viewportScaleBox = new HBoxContainer
{
Children =
{
(_viewportScaleText = new Label
{
Margin = new Thickness(8, 0)
}),
_viewportScaleSlider,
}
})
}
});
contents.AddChild(_viewportLowResCheckBox);
vBox.AddChild(contents);
vBox.AddChild(new StripeBack
{
HasBottomEdge = false,
HasMargins = false,
Children =
{
ApplyButton
}
});
ApplyButton.OnPressed += OnApplyButtonPressed;
VSyncCheckBox.Pressed = _cfg.GetCVar(CVars.DisplayVSync);
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
LightingPresetOption.SelectId(GetConfigLightingQuality());
_uiScaleOption.SelectId(GetConfigUIScalePreset(ConfigUIScale));
_hudThemeOption.SelectId(_cfg.GetCVar(CCVars.HudTheme));
_viewportScaleSlider.Value = _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
_viewportStretchCheckBox.Pressed = _cfg.GetCVar(CCVars.ViewportStretch);
_viewportLowResCheckBox.Pressed = !_cfg.GetCVar(CCVars.ViewportScaleRender);
UpdateViewportScale();
UpdateApplyButton();
AddChild(vBox);
}
private void OnUIScaleChanged(OptionButton.ItemSelectedEventArgs args)
{
_uiScaleOption.SelectId(args.Id);
UpdateApplyButton();
}
private void OnHudThemeChanged(OptionButton.ItemSelectedEventArgs args)
{
_hudThemeOption.SelectId(args.Id);
UpdateApplyButton();
}
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
_cfg.SetCVar(CVars.DisplayVSync, VSyncCheckBox.Pressed);
SetConfigLightingQuality(LightingPresetOption.SelectedId);
if (_hudThemeOption.SelectedId != _cfg.GetCVar(CCVars.HudTheme)) // Don't unnecessarily redraw the HUD
{
_cfg.SetCVar(CCVars.HudTheme, _hudThemeOption.SelectedId);
}
_cfg.SetCVar(CVars.DisplayWindowMode,
(int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
_cfg.SetCVar(CVars.DisplayUIScale, UIScaleOptions[_uiScaleOption.SelectedId]);
_cfg.SetCVar(CCVars.ViewportStretch, _viewportStretchCheckBox.Pressed);
_cfg.SetCVar(CCVars.ViewportFixedScaleFactor, (int) _viewportScaleSlider.Value);
_cfg.SetCVar(CCVars.ViewportScaleRender, !_viewportLowResCheckBox.Pressed);
_cfg.SaveToFile();
UpdateApplyButton();
}
private void OnCheckBoxToggled(BaseButton.ButtonToggledEventArgs args)
{
UpdateApplyButton();
}
private void OnLightingQualityChanged(OptionButton.ItemSelectedEventArgs args)
{
LightingPresetOption.SelectId(args.Id);
UpdateApplyButton();
}
private void UpdateApplyButton()
{
var isVSyncSame = VSyncCheckBox.Pressed == _cfg.GetCVar(CVars.DisplayVSync);
var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
var isHudThemeSame = _hudThemeOption.SelectedId == _cfg.GetCVar(CCVars.HudTheme);
var isUIScaleSame = MathHelper.CloseTo(UIScaleOptions[_uiScaleOption.SelectedId], ConfigUIScale);
var isVPStretchSame = _viewportStretchCheckBox.Pressed == _cfg.GetCVar(CCVars.ViewportStretch);
var isVPScaleSame = (int) _viewportScaleSlider.Value == _cfg.GetCVar(CCVars.ViewportFixedScaleFactor);
var isVPResSame = _viewportLowResCheckBox.Pressed == !_cfg.GetCVar(CCVars.ViewportScaleRender);
ApplyButton.Disabled = isVSyncSame &&
isFullscreenSame &&
isLightingQualitySame &&
isUIScaleSame &&
isVPStretchSame &&
isVPScaleSame &&
isVPResSame &&
isHudThemeSame;
}
private bool ConfigIsFullscreen =>
_cfg.GetCVar(CVars.DisplayWindowMode) == (int) WindowMode.Fullscreen;
private float ConfigUIScale => _cfg.GetCVar(CVars.DisplayUIScale);
private int GetConfigLightingQuality()
{
var val = _cfg.GetCVar(CVars.DisplayLightMapDivider);
var soft = _cfg.GetCVar(CVars.DisplaySoftShadows);
if (val >= 8)
{
return 0;
}
else if ((val >= 2) && !soft)
{
return 1;
}
else if (val >= 2)
{
return 2;
}
else
{
return 3;
}
}
private void SetConfigLightingQuality(int value)
{
switch (value)
{
case 0:
_cfg.SetCVar(CVars.DisplayLightMapDivider, 8);
_cfg.SetCVar(CVars.DisplaySoftShadows, false);
break;
case 1:
_cfg.SetCVar(CVars.DisplayLightMapDivider, 2);
_cfg.SetCVar(CVars.DisplaySoftShadows, false);
break;
case 2:
_cfg.SetCVar(CVars.DisplayLightMapDivider, 2);
_cfg.SetCVar(CVars.DisplaySoftShadows, true);
break;
case 3:
_cfg.SetCVar(CVars.DisplayLightMapDivider, 1);
_cfg.SetCVar(CVars.DisplaySoftShadows, true);
break;
}
}
private static int GetConfigUIScalePreset(float value)
{
for (var i = 0; i < UIScaleOptions.Length; i++)
{
if (MathHelper.CloseTo(UIScaleOptions[i], value))
{
return i;
}
}
return 0;
}
private void UpdateViewportScale()
{
_viewportScaleBox.Visible = !_viewportStretchCheckBox.Pressed;
_viewportScaleText.Text = Loc.GetString("ui-options-vp-scale", ("scale", _viewportScaleSlider.Value));
}
}
}
}

View File

@@ -1,490 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Input;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Input;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu
{
private sealed class KeyRebindControl : Control
{
// List of key functions that must be registered as toggle instead.
private static readonly HashSet<BoundKeyFunction> ToggleFunctions = new()
{
EngineKeyFunctions.ShowDebugMonitors,
EngineKeyFunctions.HideUI,
};
[Dependency] private readonly IInputManager _inputManager = default!;
private BindButton? _currentlyRebinding;
private readonly Dictionary<BoundKeyFunction, KeyControl> _keyControls =
new();
private readonly List<Action> _deferCommands = new();
public KeyRebindControl()
{
IoCManager.InjectDependencies(this);
Button resetAllButton;
var vBox = new VBoxContainer {Margin = new Thickness(2, 0, 0, 0)};
AddChild(new VBoxContainer
{
Children =
{
new ScrollContainer
{
VerticalExpand = true,
Children = {vBox}
},
new StripeBack
{
HasBottomEdge = false,
HasMargins = false,
Children =
{
new HBoxContainer
{
Children =
{
new Control {MinSize = (2, 0)},
new Label
{
StyleClasses = {StyleBase.StyleClassLabelSubText},
Text = Loc.GetString("ui-options-binds-explanation")
},
(resetAllButton = new Button
{
Text = Loc.GetString("ui-options-binds-reset-all"),
StyleClasses = {StyleBase.ButtonCaution},
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right
})
}
}
}
}
}
});
resetAllButton.OnPressed += _ =>
{
_deferCommands.Add(() =>
{
_inputManager.ResetAllBindings();
_inputManager.SaveToUserData();
});
};
var first = true;
void AddHeader(string headerContents)
{
if (!first)
{
vBox.AddChild(new Control {MinSize = (0, 8)});
}
first = false;
vBox.AddChild(new Label
{
Text = Loc.GetString(headerContents),
FontColorOverride = StyleNano.NanoGold,
StyleClasses = {StyleNano.StyleClassLabelKeyText}
});
}
void AddButton(BoundKeyFunction function)
{
var control = new KeyControl(this, function);
vBox.AddChild(control);
_keyControls.Add(function, control);
}
AddHeader("ui-options-header-movement");
AddButton(EngineKeyFunctions.MoveUp);
AddButton(EngineKeyFunctions.MoveLeft);
AddButton(EngineKeyFunctions.MoveDown);
AddButton(EngineKeyFunctions.MoveRight);
AddButton(EngineKeyFunctions.Walk);
AddHeader("ui-options-header-interaction-basic");
AddButton(EngineKeyFunctions.Use);
AddButton(ContentKeyFunctions.WideAttack);
AddButton(ContentKeyFunctions.ActivateItemInHand);
AddButton(ContentKeyFunctions.ActivateItemInWorld);
AddButton(ContentKeyFunctions.Drop);
AddButton(ContentKeyFunctions.ExamineEntity);
AddButton(ContentKeyFunctions.SwapHands);
AddHeader("ui-options-header-interaction-adv");
AddButton(ContentKeyFunctions.SmartEquipBackpack);
AddButton(ContentKeyFunctions.SmartEquipBelt);
AddButton(ContentKeyFunctions.ThrowItemInHand);
AddButton(ContentKeyFunctions.TryPullObject);
AddButton(ContentKeyFunctions.MovePulledObject);
AddButton(ContentKeyFunctions.ReleasePulledObject);
AddButton(ContentKeyFunctions.Point);
AddHeader("ui-options-header-ui");
AddButton(ContentKeyFunctions.FocusChat);
AddButton(ContentKeyFunctions.FocusLocalChat);
AddButton(ContentKeyFunctions.FocusRadio);
AddButton(ContentKeyFunctions.FocusOOC);
AddButton(ContentKeyFunctions.FocusAdminChat);
AddButton(ContentKeyFunctions.CycleChatChannelForward);
AddButton(ContentKeyFunctions.CycleChatChannelBackward);
AddButton(ContentKeyFunctions.OpenCharacterMenu);
AddButton(ContentKeyFunctions.OpenContextMenu);
AddButton(ContentKeyFunctions.OpenCraftingMenu);
AddButton(ContentKeyFunctions.OpenInventoryMenu);
AddButton(ContentKeyFunctions.OpenInfo);
AddButton(ContentKeyFunctions.OpenActionsMenu);
AddButton(ContentKeyFunctions.OpenEntitySpawnWindow);
AddButton(ContentKeyFunctions.OpenSandboxWindow);
AddButton(ContentKeyFunctions.OpenTileSpawnWindow);
AddButton(ContentKeyFunctions.OpenAdminMenu);
AddHeader("ui-options-header-misc");
AddButton(ContentKeyFunctions.TakeScreenshot);
AddButton(ContentKeyFunctions.TakeScreenshotNoUI);
AddHeader("ui-options-header-hotbar");
AddButton(ContentKeyFunctions.Hotbar1);
AddButton(ContentKeyFunctions.Hotbar2);
AddButton(ContentKeyFunctions.Hotbar3);
AddButton(ContentKeyFunctions.Hotbar4);
AddButton(ContentKeyFunctions.Hotbar5);
AddButton(ContentKeyFunctions.Hotbar6);
AddButton(ContentKeyFunctions.Hotbar7);
AddButton(ContentKeyFunctions.Hotbar8);
AddButton(ContentKeyFunctions.Hotbar9);
AddButton(ContentKeyFunctions.Hotbar0);
AddButton(ContentKeyFunctions.Loadout1);
AddButton(ContentKeyFunctions.Loadout2);
AddButton(ContentKeyFunctions.Loadout3);
AddButton(ContentKeyFunctions.Loadout4);
AddButton(ContentKeyFunctions.Loadout5);
AddButton(ContentKeyFunctions.Loadout6);
AddButton(ContentKeyFunctions.Loadout7);
AddButton(ContentKeyFunctions.Loadout8);
AddButton(ContentKeyFunctions.Loadout9);
AddHeader("ui-options-header-map-editor");
AddButton(EngineKeyFunctions.EditorPlaceObject);
AddButton(EngineKeyFunctions.EditorCancelPlace);
AddButton(EngineKeyFunctions.EditorGridPlace);
AddButton(EngineKeyFunctions.EditorLinePlace);
AddButton(EngineKeyFunctions.EditorRotateObject);
AddHeader("ui-options-header-dev");
AddButton(EngineKeyFunctions.ShowDebugConsole);
AddButton(EngineKeyFunctions.ShowDebugMonitors);
AddButton(EngineKeyFunctions.HideUI);
foreach (var control in _keyControls.Values)
{
UpdateKeyControl(control);
}
}
private void UpdateKeyControl(KeyControl control)
{
var activeBinds = _inputManager.GetKeyBindings(control.Function);
IKeyBinding? bind1 = null;
IKeyBinding? bind2 = null;
if (activeBinds.Count > 0)
{
bind1 = activeBinds[0];
if (activeBinds.Count > 1)
{
bind2 = activeBinds[1];
}
}
control.BindButton1.Binding = bind1;
control.BindButton1.UpdateText();
control.BindButton2.Binding = bind2;
control.BindButton2.UpdateText();
control.BindButton2.Button.Disabled = activeBinds.Count == 0;
control.ResetButton.Disabled = !_inputManager.IsKeyFunctionModified(control.Function);
}
protected override void EnteredTree()
{
base.EnteredTree();
_inputManager.FirstChanceOnKeyEvent += InputManagerOnFirstChanceOnKeyEvent;
_inputManager.OnKeyBindingAdded += OnKeyBindAdded;
_inputManager.OnKeyBindingRemoved += OnKeyBindRemoved;
}
protected override void ExitedTree()
{
base.ExitedTree();
_inputManager.FirstChanceOnKeyEvent -= InputManagerOnFirstChanceOnKeyEvent;
_inputManager.OnKeyBindingAdded -= OnKeyBindAdded;
_inputManager.OnKeyBindingRemoved -= OnKeyBindRemoved;
}
private void OnKeyBindRemoved(IKeyBinding obj)
{
OnKeyBindModified(obj, true);
}
private void OnKeyBindAdded(IKeyBinding obj)
{
OnKeyBindModified(obj, false);
}
private void OnKeyBindModified(IKeyBinding bind, bool removal)
{
if (!_keyControls.TryGetValue(bind.Function, out var keyControl))
{
return;
}
if (removal && _currentlyRebinding?.KeyControl == keyControl)
{
// Don't do update if the removal was from initiating a rebind.
return;
}
UpdateKeyControl(keyControl);
if (_currentlyRebinding == keyControl.BindButton1 || _currentlyRebinding == keyControl.BindButton2)
{
_currentlyRebinding = null;
}
}
private void InputManagerOnFirstChanceOnKeyEvent(KeyEventArgs keyEvent, KeyEventType type)
{
DebugTools.Assert(IsInsideTree);
if (_currentlyRebinding == null)
{
return;
}
keyEvent.Handle();
if (type != KeyEventType.Up)
{
return;
}
var key = keyEvent.Key;
// Figure out modifiers based on key event.
// TODO: this won't allow for combinations with keys other than the standard modifier keys,
// even though the input system totally supports it.
var mods = new Keyboard.Key[3];
var i = 0;
if (keyEvent.Control && key != Keyboard.Key.Control)
{
mods[i] = Keyboard.Key.Control;
i += 1;
}
if (keyEvent.Shift && key != Keyboard.Key.Shift)
{
mods[i] = Keyboard.Key.Shift;
i += 1;
}
if (keyEvent.Alt && key != Keyboard.Key.Alt)
{
mods[i] = Keyboard.Key.Alt;
i += 1;
}
// The input system can only handle 3 modifier keys so if you hold all 4 of the modifier keys
// then system gets the shaft, I guess.
if (keyEvent.System && i != 3 && key != Keyboard.Key.LSystem && key != Keyboard.Key.RSystem)
{
mods[i] = Keyboard.Key.LSystem;
}
var function = _currentlyRebinding.KeyControl.Function;
var bindType = KeyBindingType.State;
if (ToggleFunctions.Contains(function))
{
bindType = KeyBindingType.Toggle;
}
var registration = new KeyBindingRegistration
{
Function = function,
BaseKey = key,
Mod1 = mods[0],
Mod2 = mods[1],
Mod3 = mods[2],
Priority = 0,
Type = bindType,
CanFocus = key == Keyboard.Key.MouseLeft
|| key == Keyboard.Key.MouseRight
|| key == Keyboard.Key.MouseMiddle,
CanRepeat = false
};
_inputManager.RegisterBinding(registration);
// OnKeyBindModified will cause _currentlyRebinding to be reset and the UI to update.
_inputManager.SaveToUserData();
}
private void RebindButtonPressed(BindButton button)
{
if (_currentlyRebinding != null)
{
return;
}
_currentlyRebinding = button;
_currentlyRebinding.Button.Text = Loc.GetString("ui-options-key-prompt");
if (button.Binding != null)
{
_deferCommands.Add(() =>
{
// Have to do defer this or else there will be an exception in InputManager.
// Because this IS fired from an input event.
_inputManager.RemoveBinding(button.Binding);
});
}
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_deferCommands.Count == 0)
{
return;
}
foreach (var command in _deferCommands)
{
command();
}
_deferCommands.Clear();
}
private sealed class KeyControl : Control
{
public readonly BoundKeyFunction Function;
public readonly BindButton BindButton1;
public readonly BindButton BindButton2;
public readonly Button ResetButton;
public KeyControl(KeyRebindControl parent, BoundKeyFunction function)
{
Function = function;
var name = new Label
{
Text = Loc.GetString(
$"ui-options-function-{CaseConversion.PascalToKebab(function.FunctionName)}"),
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Left
};
BindButton1 = new BindButton(parent, this, StyleBase.ButtonOpenRight);
BindButton2 = new BindButton(parent, this, StyleBase.ButtonOpenLeft);
ResetButton = new Button {Text = Loc.GetString("ui-options-bind-reset"), StyleClasses = {StyleBase.ButtonCaution}};
var hBox = new HBoxContainer
{
Children =
{
new Control {MinSize = (5, 0)},
name,
BindButton1,
BindButton2,
new Control {MinSize = (10, 0)},
ResetButton
}
};
ResetButton.OnPressed += args =>
{
parent._deferCommands.Add(() =>
{
parent._inputManager.ResetBindingsFor(function);
parent._inputManager.SaveToUserData();
});
};
AddChild(hBox);
}
}
private sealed class BindButton : Control
{
private readonly KeyRebindControl _control;
public readonly KeyControl KeyControl;
public readonly Button Button;
public IKeyBinding? Binding;
public BindButton(KeyRebindControl control, KeyControl keyControl, string styleClass)
{
_control = control;
KeyControl = keyControl;
Button = new Button {StyleClasses = {styleClass}};
UpdateText();
AddChild(Button);
Button.OnPressed += args =>
{
control.RebindButtonPressed(this);
};
Button.OnKeyBindDown += ButtonOnOnKeyBindDown;
MinSize = (200, 0);
}
private void ButtonOnOnKeyBindDown(GUIBoundKeyEventArgs args)
{
if (args.Function == EngineKeyFunctions.UIRightClick)
{
if (Binding != null)
{
_control._deferCommands.Add(() =>
{
_control._inputManager.RemoveBinding(Binding);
_control._inputManager.SaveToUserData();
});
}
args.Handle();
}
}
public void UpdateText()
{
Button.Text = Binding?.GetKeyString() ?? Loc.GetString("ui-options-unbound");
}
}
}
}
}

View File

@@ -1,46 +0,0 @@
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu : SS14Window
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IClydeAudio _clydeAudio = default!;
public OptionsMenu()
{
SetSize = MinSize = (800, 450);
IoCManager.InjectDependencies(this);
Title = Loc.GetString("ui-options-title");
GraphicsControl graphicsControl;
KeyRebindControl rebindControl;
AudioControl audioControl;
var tabs = new TabContainer
{
Children =
{
(graphicsControl = new GraphicsControl(_configManager, _prototypeManager)),
(rebindControl = new KeyRebindControl()),
(audioControl = new AudioControl(_configManager, _clydeAudio)),
}
};
TabContainer.SetTabTitle(graphicsControl, Loc.GetString("ui-options-tab-graphics"));
TabContainer.SetTabTitle(rebindControl, Loc.GetString("ui-options-tab-controls"));
TabContainer.SetTabTitle(audioControl, Loc.GetString("ui-options-tab-audio"));
Contents.AddChild(tabs);
}
}
}

View File

@@ -1,47 +0,0 @@
using Content.Client.Interfaces.Parallax;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Shared.IoC;
using Robust.Shared.Maths;
using Robust.Shared.Random;
using Robust.Shared.ViewVariables;
namespace Content.Client.UserInterface
{
/// <summary>
/// Renders the parallax background as a UI control.
/// </summary>
public sealed class ParallaxControl : Control
{
[Dependency] private readonly IParallaxManager _parallaxManager = default!;
[Dependency] private readonly IRobustRandom _random = default!;
[ViewVariables(VVAccess.ReadWrite)] public Vector2i Offset { get; set; }
public ParallaxControl()
{
IoCManager.InjectDependencies(this);
Offset = (_random.Next(0, 1000), _random.Next(0, 1000));
RectClipContent = true;
}
protected override void Draw(DrawingHandleScreen handle)
{
var tex = _parallaxManager.ParallaxTexture;
if (tex == null)
return;
var size = tex.Size;
var ourSize = PixelSize;
for (var x = -size.X + Offset.X; x < ourSize.X; x += size.X)
{
for (var y = -size.Y + Offset.Y; y < ourSize.Y; y += size.Y)
{
handle.DrawTexture(tex, (x, y));
}
}
}
}
}

View File

@@ -1,51 +0,0 @@
using Content.Shared.GameObjects.Components;
using Robust.Client.GameObjects;
using Robust.Shared.GameObjects;
namespace Content.Client.UserInterface.ParticleAccelerator
{
public class ParticleAcceleratorBoundUserInterface : BoundUserInterface
{
private ParticleAcceleratorControlMenu? _menu;
public ParticleAcceleratorBoundUserInterface(ClientUserInterfaceComponent owner, object uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
base.Open();
_menu = new ParticleAcceleratorControlMenu(this);
_menu.OnClose += Close;
_menu.OpenCentered();
}
public void SendEnableMessage(bool enable)
{
SendMessage(new ParticleAcceleratorSetEnableMessage(enable));
}
public void SendPowerStateMessage(ParticleAcceleratorPowerState state)
{
SendMessage(new ParticleAcceleratorSetPowerStateMessage(state));
}
public void SendScanPartsMessage()
{
SendMessage(new ParticleAcceleratorRescanPartsMessage());
}
protected override void UpdateState(BoundUserInterfaceState state)
{
_menu?.DataUpdate((ParticleAcceleratorUIState) state);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_menu?.Close();
}
}
}

View File

@@ -1,503 +0,0 @@
using System;
using Content.Client.UserInterface.Stylesheets;
using Content.Client.Utility;
using Content.Shared.GameObjects.Components;
using Robust.Client.Animations;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Noise;
using Robust.Shared.Prototypes;
using Robust.Shared.Timing;
namespace Content.Client.UserInterface.ParticleAccelerator
{
public sealed class ParticleAcceleratorControlMenu : BaseWindow
{
private readonly ShaderInstance _greyScaleShader;
private readonly ParticleAcceleratorBoundUserInterface Owner;
private readonly Label _drawLabel;
private readonly NoiseGenerator _drawNoiseGenerator;
private readonly Button _onButton;
private readonly Button _offButton;
private readonly Button _scanButton;
private readonly Label _statusLabel;
private readonly SpinBox _stateSpinBox;
private readonly VBoxContainer _alarmControl;
private readonly Animation _alarmControlAnimation;
private readonly PASegmentControl _endCapTexture;
private readonly PASegmentControl _fuelChamberTexture;
private readonly PASegmentControl _controlBoxTexture;
private readonly PASegmentControl _powerBoxTexture;
private readonly PASegmentControl _emitterCenterTexture;
private readonly PASegmentControl _emitterRightTexture;
private readonly PASegmentControl _emitterLeftTexture;
private float _time;
private int _lastDraw;
private int _lastReceive;
private bool _blockSpinBox;
private bool _assembled;
private bool _shouldContinueAnimating;
public ParticleAcceleratorControlMenu(ParticleAcceleratorBoundUserInterface owner)
{
SetSize = (400, 320);
_greyScaleShader = IoCManager.Resolve<IPrototypeManager>().Index<ShaderPrototype>("Greyscale").Instance();
Owner = owner;
_drawNoiseGenerator = new NoiseGenerator(NoiseGenerator.NoiseType.Fbm);
_drawNoiseGenerator.SetFrequency(0.5f);
var resourceCache = IoCManager.Resolve<IResourceCache>();
var font = resourceCache.GetFont("/Fonts/Boxfont-round/Boxfont Round.ttf", 13);
var panelTex = resourceCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
MouseFilter = MouseFilterMode.Stop;
_alarmControlAnimation = new Animation
{
Length = TimeSpan.FromSeconds(1),
AnimationTracks =
{
new AnimationTrackControlProperty
{
Property = nameof(Control.Visible),
KeyFrames =
{
new AnimationTrackProperty.KeyFrame(true, 0),
new AnimationTrackProperty.KeyFrame(false, 0.75f),
}
}
}
};
var back = new StyleBoxTexture
{
Texture = panelTex,
Modulate = Color.FromHex("#25252A"),
};
back.SetPatchMargin(StyleBox.Margin.All, 10);
var back2 = new StyleBoxTexture(back)
{
Modulate = Color.FromHex("#202023")
};
AddChild(new PanelContainer
{
PanelOverride = back,
MouseFilter = MouseFilterMode.Pass
});
_stateSpinBox = new SpinBox {Value = 0, IsValid = StrengthSpinBoxValid,};
_stateSpinBox.InitDefaultButtons();
_stateSpinBox.ValueChanged += PowerStateChanged;
_stateSpinBox.LineEditDisabled = true;
_offButton = new Button
{
ToggleMode = false,
Text = "Off",
StyleClasses = {StyleBase.ButtonOpenRight},
};
_offButton.OnPressed += args => owner.SendEnableMessage(false);
_onButton = new Button
{
ToggleMode = false,
Text = "On",
StyleClasses = {StyleBase.ButtonOpenLeft},
};
_onButton.OnPressed += args => owner.SendEnableMessage(true);
var closeButton = new TextureButton
{
StyleClasses = {"windowCloseButton"},
HorizontalAlignment = HAlignment.Right,
Margin = new Thickness(0, 0, 8, 0)
};
closeButton.OnPressed += args => Close();
var serviceManual = new Label
{
HorizontalAlignment = HAlignment.Center,
StyleClasses = {StyleBase.StyleClassLabelSubText},
Text = Loc.GetString("Refer to p.132 of service manual")
};
_drawLabel = new Label();
var imgSize = new Vector2(32, 32);
AddChild(new VBoxContainer
{
Children =
{
new Control
{
Margin = new Thickness(2, 2, 0, 0),
Children =
{
new Label
{
Text = Loc.GetString("Mark 2 Particle Accelerator"),
FontOverride = font,
FontColorOverride = StyleNano.NanoGold,
},
closeButton
}
},
new PanelContainer
{
PanelOverride = new StyleBoxFlat {BackgroundColor = StyleNano.NanoGold},
MinSize = (0, 2),
},
new Control
{
MinSize = (0, 4)
},
new HBoxContainer
{
VerticalExpand = true,
Children =
{
new VBoxContainer
{
Margin = new Thickness(4, 0, 0, 0),
HorizontalExpand = true,
Children =
{
new HBoxContainer
{
Children =
{
new Label
{
Text = Loc.GetString("Power: "),
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Left,
},
_offButton,
_onButton
}
},
new HBoxContainer
{
Children =
{
new Label
{
Text = Loc.GetString("Strength: "),
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Left,
},
_stateSpinBox
}
},
new Control
{
MinSize = (0, 10),
},
_drawLabel,
new Control
{
VerticalExpand = true,
},
(_alarmControl = new VBoxContainer
{
Children =
{
new Label
{
Text = Loc.GetString("PARTICLE STRENGTH\nLIMITER FAILURE"),
FontColorOverride = Color.Red,
Align = Label.AlignMode.Center
},
serviceManual
}
}),
}
},
new VBoxContainer
{
MinSize = (186, 0),
Children =
{
(_statusLabel = new Label
{
HorizontalAlignment = HAlignment.Center
}),
new Control
{
MinSize = (0, 20)
},
new PanelContainer
{
HorizontalAlignment = HAlignment.Center,
PanelOverride = back2,
Children =
{
new GridContainer
{
Columns = 3,
VSeparationOverride = 0,
HSeparationOverride = 0,
Children =
{
new Control {MinSize = imgSize},
(_endCapTexture = Segment("end_cap", "capc")),
new Control {MinSize = imgSize},
(_controlBoxTexture = Segment("control_box", "boxc")),
(_fuelChamberTexture = Segment("fuel_chamber", "chamberc")),
new Control {MinSize = imgSize},
new Control {MinSize = imgSize},
(_powerBoxTexture = Segment("power_box", "boxc")),
new Control {MinSize = imgSize},
(_emitterLeftTexture = Segment("emitter_left", "leftc")),
(_emitterCenterTexture = Segment("emitter_center", "centerc")),
(_emitterRightTexture = Segment("emitter_right", "rightc")),
}
}
}
},
(_scanButton = new Button
{
Text = Loc.GetString("Scan Parts"),
HorizontalAlignment = HAlignment.Center
})
}
}
}
},
new StripeBack
{
Children =
{
new Label
{
Margin = new Thickness(4, 4, 0, 4),
Text = Loc.GetString("Ensure containment field is active before operation"),
HorizontalAlignment = HAlignment.Center,
StyleClasses = {StyleBase.StyleClassLabelSubText},
}
}
},
new HBoxContainer
{
Margin = new Thickness(12, 0, 0, 0),
Children =
{
new Label
{
Text = "FOO-BAR-BAZ",
StyleClasses = {StyleBase.StyleClassLabelSubText}
}
}
},
}
});
_scanButton.OnPressed += args => Owner.SendScanPartsMessage();
_alarmControl.AnimationCompleted += s =>
{
if (_shouldContinueAnimating)
{
_alarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim");
}
else
{
_alarmControl.Visible = false;
}
};
PASegmentControl Segment(string name, string state)
{
return new(this, resourceCache, name, state);
}
}
private bool StrengthSpinBoxValid(int n)
{
return (n >= 0 && n <= 4 && !_blockSpinBox);
}
private void PowerStateChanged(object? sender, ValueChangedEventArgs e)
{
ParticleAcceleratorPowerState newState;
switch (e.Value)
{
case 0:
newState = ParticleAcceleratorPowerState.Standby;
break;
case 1:
newState = ParticleAcceleratorPowerState.Level0;
break;
case 2:
newState = ParticleAcceleratorPowerState.Level1;
break;
case 3:
newState = ParticleAcceleratorPowerState.Level2;
break;
case 4:
newState = ParticleAcceleratorPowerState.Level3;
break;
default:
return;
}
Owner.SendPowerStateMessage(newState);
}
protected override DragMode GetDragModeFor(Vector2 relativeMousePos)
{
return DragMode.Move;
}
public void DataUpdate(ParticleAcceleratorUIState uiState)
{
_assembled = uiState.Assembled;
UpdateUI(uiState.Assembled, uiState.InterfaceBlock, uiState.Enabled,
uiState.WirePowerBlock);
_statusLabel.Text = Loc.GetString($"Status: {(uiState.Assembled ? "Operational" : "Incomplete")}");
UpdatePowerState(uiState.State, uiState.Enabled, uiState.Assembled,
uiState.MaxLevel);
UpdatePreview(uiState);
_lastDraw = uiState.PowerDraw;
_lastReceive = uiState.PowerReceive;
}
private void UpdatePowerState(ParticleAcceleratorPowerState state, bool enabled, bool assembled,
ParticleAcceleratorPowerState maxState)
{
_stateSpinBox.OverrideValue(state switch
{
ParticleAcceleratorPowerState.Standby => 0,
ParticleAcceleratorPowerState.Level0 => 1,
ParticleAcceleratorPowerState.Level1 => 2,
ParticleAcceleratorPowerState.Level2 => 3,
ParticleAcceleratorPowerState.Level3 => 4,
_ => 0
});
_shouldContinueAnimating = false;
_alarmControl.StopAnimation("warningAnim");
_alarmControl.Visible = false;
if (maxState == ParticleAcceleratorPowerState.Level3 && enabled && assembled)
{
_shouldContinueAnimating = true;
_alarmControl.PlayAnimation(_alarmControlAnimation, "warningAnim");
}
}
private void UpdateUI(bool assembled, bool blocked, bool enabled, bool powerBlock)
{
_onButton.Pressed = enabled;
_offButton.Pressed = !enabled;
var cantUse = !assembled || blocked || powerBlock;
_onButton.Disabled = cantUse;
_offButton.Disabled = cantUse;
_scanButton.Disabled = blocked;
var cantChangeLevel = !assembled || blocked;
_stateSpinBox.SetButtonDisabled(cantChangeLevel);
_blockSpinBox = cantChangeLevel;
}
private void UpdatePreview(ParticleAcceleratorUIState updateMessage)
{
_endCapTexture.SetPowerState(updateMessage, updateMessage.EndCapExists);
_fuelChamberTexture.SetPowerState(updateMessage, updateMessage.FuelChamberExists);
_controlBoxTexture.SetPowerState(updateMessage, true);
_powerBoxTexture.SetPowerState(updateMessage, updateMessage.PowerBoxExists);
_emitterCenterTexture.SetPowerState(updateMessage, updateMessage.EmitterCenterExists);
_emitterLeftTexture.SetPowerState(updateMessage, updateMessage.EmitterLeftExists);
_emitterRightTexture.SetPowerState(updateMessage, updateMessage.EmitterRightExists);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (!_assembled)
{
_drawLabel.Text = Loc.GetString("Draw: N/A");
return;
}
_time += args.DeltaSeconds;
var watts = 0;
if (_lastDraw != 0)
{
var val = _drawNoiseGenerator.GetNoise(_time);
watts = (int) (_lastDraw + val * 5);
}
_drawLabel.Text = Loc.GetString("Draw: {0:##,##0}/{1:##,##0} W", watts, _lastReceive);
}
private sealed class PASegmentControl : Control
{
private readonly ParticleAcceleratorControlMenu _menu;
private readonly string _baseState;
private readonly TextureRect _base;
private readonly TextureRect _unlit;
private readonly RSI _rsi;
public PASegmentControl(ParticleAcceleratorControlMenu menu, IResourceCache cache, string name, string state)
{
_menu = menu;
_baseState = name;
_rsi = cache.GetResource<RSIResource>($"/Textures/Constructible/Specific/Engines/PA/{name}.rsi").RSI;
AddChild(_base = new TextureRect {Texture = _rsi[$"{state}"].Frame0});
AddChild(_unlit = new TextureRect());
MinSize = _rsi.Size;
}
public void SetPowerState(ParticleAcceleratorUIState state, bool exists)
{
_base.ShaderOverride = exists ? null : _menu._greyScaleShader;
_base.ModulateSelfOverride = exists ? (Color?) null : new Color(127, 127, 127);
if (!state.Enabled || !exists)
{
_unlit.Visible = false;
return;
}
_unlit.Visible = true;
var suffix = state.State switch
{
ParticleAcceleratorPowerState.Standby => "_unlitp",
ParticleAcceleratorPowerState.Level0 => "_unlitp0",
ParticleAcceleratorPowerState.Level1 => "_unlitp1",
ParticleAcceleratorPowerState.Level2 => "_unlitp2",
ParticleAcceleratorPowerState.Level3 => "_unlitp3",
_ => ""
};
if (!_rsi.TryGetState(_baseState + suffix, out var rState))
{
_unlit.Visible = false;
return;
}
_unlit.Texture = rState.Frame0;
}
}
}
}

View File

@@ -1,603 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Content.Client.Administration;
using Content.Client.Eui;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Administration;
using Content.Shared.Eui;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
using static Content.Shared.Administration.PermissionsEuiMsg;
namespace Content.Client.UserInterface.Permissions
{
[UsedImplicitly]
public sealed class PermissionsEui : BaseEui
{
private const int NoRank = -1;
[Dependency] private readonly IClientAdminManager _adminManager = default!;
private readonly Menu _menu;
private readonly List<SS14Window> _subWindows = new();
private Dictionary<int, PermissionsEuiState.AdminRankData> _ranks =
new();
public PermissionsEui()
{
IoCManager.InjectDependencies(this);
_menu = new Menu(this);
_menu.AddAdminButton.OnPressed += AddAdminPressed;
_menu.AddAdminRankButton.OnPressed += AddAdminRankPressed;
_menu.OnClose += CloseEverything;
}
public override void Closed()
{
base.Closed();
CloseEverything();
}
private void CloseEverything()
{
foreach (var subWindow in _subWindows.ToArray())
{
subWindow.Close();
}
_menu.Close();
}
private void AddAdminPressed(BaseButton.ButtonEventArgs obj)
{
OpenEditWindow(null);
}
private void AddAdminRankPressed(BaseButton.ButtonEventArgs obj)
{
OpenRankEditWindow(null);
}
private void OnEditPressed(PermissionsEuiState.AdminData admin)
{
OpenEditWindow(admin);
}
private void OpenEditWindow(PermissionsEuiState.AdminData? data)
{
var window = new EditAdminWindow(this, data);
window.SaveButton.OnPressed += _ => SaveAdminPressed(window);
window.OpenCentered();
window.OnClose += () => _subWindows.Remove(window);
if (data != null)
{
window.RemoveButton!.OnPressed += _ => RemoveButtonPressed(window);
}
_subWindows.Add(window);
}
private void OpenRankEditWindow(KeyValuePair<int, PermissionsEuiState.AdminRankData>? rank)
{
var window = new EditAdminRankWindow(this, rank);
window.SaveButton.OnPressed += _ => SaveAdminRankPressed(window);
window.OpenCentered();
window.OnClose += () => _subWindows.Remove(window);
if (rank != null)
{
window.RemoveButton!.OnPressed += _ => RemoveRankButtonPressed(window);
}
_subWindows.Add(window);
}
private void RemoveButtonPressed(EditAdminWindow window)
{
SendMessage(new RemoveAdmin {UserId = window.SourceData!.Value.UserId});
window.Close();
}
private void RemoveRankButtonPressed(EditAdminRankWindow window)
{
SendMessage(new RemoveAdminRank {Id = window.SourceId!.Value});
window.Close();
}
private void SaveAdminPressed(EditAdminWindow popup)
{
popup.CollectSetFlags(out var pos, out var neg);
int? rank = popup.RankButton.SelectedId;
if (rank == NoRank)
{
rank = null;
}
var title = string.IsNullOrWhiteSpace(popup.TitleEdit.Text) ? null : popup.TitleEdit.Text;
if (popup.SourceData is { } src)
{
SendMessage(new UpdateAdmin
{
UserId = src.UserId,
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
});
}
else
{
DebugTools.AssertNotNull(popup.NameEdit);
SendMessage(new AddAdmin
{
UserNameOrId = popup.NameEdit!.Text,
Title = title,
PosFlags = pos,
NegFlags = neg,
RankId = rank
});
}
popup.Close();
}
private void SaveAdminRankPressed(EditAdminRankWindow popup)
{
var flags = popup.CollectSetFlags();
var name = popup.NameEdit.Text;
if (popup.SourceId is { } src)
{
SendMessage(new UpdateAdminRank
{
Id = src,
Flags = flags,
Name = name
});
}
else
{
SendMessage(new AddAdminRank
{
Flags = flags,
Name = name
});
}
popup.Close();
}
public override void Opened()
{
_menu.OpenCentered();
}
public override void HandleState(EuiStateBase state)
{
var s = (PermissionsEuiState) state;
if (s.IsLoading)
{
return;
}
_ranks = s.AdminRanks;
_menu.AdminsList.RemoveAllChildren();
foreach (var admin in s.Admins)
{
var al = _menu.AdminsList;
var name = admin.UserName ?? admin.UserId.ToString();
al.AddChild(new Label {Text = name});
var titleControl = new Label {Text = admin.Title ?? Loc.GetString("none")};
if (admin.Title == null) // none
{
titleControl.StyleClasses.Add(StyleBase.StyleClassItalic);
}
al.AddChild(titleControl);
bool italic;
string rank;
var combinedFlags = admin.PosFlags;
if (admin.RankId is { } rankId)
{
italic = false;
var rankData = s.AdminRanks[rankId];
rank = rankData.Name;
combinedFlags |= rankData.Flags;
}
else
{
italic = true;
rank = Loc.GetString("none");
}
var rankControl = new Label {Text = rank};
if (italic)
{
rankControl.StyleClasses.Add(StyleBase.StyleClassItalic);
}
al.AddChild(rankControl);
var flagsText = AdminFlagsHelper.PosNegFlagsText(admin.PosFlags, admin.NegFlags);
al.AddChild(new Label
{
Text = flagsText,
HorizontalExpand = true,
HorizontalAlignment = Control.HAlignment.Center,
});
var editButton = new Button {Text = Loc.GetString("Edit")};
editButton.OnPressed += _ => OnEditPressed(admin);
al.AddChild(editButton);
if (!_adminManager.HasFlag(combinedFlags))
{
editButton.Disabled = true;
editButton.ToolTip = Loc.GetString("You do not have the required flags to edit this admin.");
}
}
_menu.AdminRanksList.RemoveAllChildren();
foreach (var kv in s.AdminRanks)
{
var rank = kv.Value;
var flagsText = string.Join(' ', AdminFlagsHelper.FlagsToNames(rank.Flags).Select(f => $"+{f}"));
_menu.AdminRanksList.AddChild(new Label {Text = rank.Name});
_menu.AdminRanksList.AddChild(new Label
{
Text = flagsText,
HorizontalExpand = true,
HorizontalAlignment = Control.HAlignment.Center,
});
var editButton = new Button {Text = Loc.GetString("Edit")};
editButton.OnPressed += _ => OnEditRankPressed(kv);
_menu.AdminRanksList.AddChild(editButton);
if (!_adminManager.HasFlag(rank.Flags))
{
editButton.Disabled = true;
editButton.ToolTip = Loc.GetString("You do not have the required flags to edit this rank.");
}
}
}
private void OnEditRankPressed(KeyValuePair<int, PermissionsEuiState.AdminRankData> rank)
{
OpenRankEditWindow(rank);
}
private sealed class Menu : SS14Window
{
private readonly PermissionsEui _ui;
public readonly GridContainer AdminsList;
public readonly GridContainer AdminRanksList;
public readonly Button AddAdminButton;
public readonly Button AddAdminRankButton;
public Menu(PermissionsEui ui)
{
_ui = ui;
Title = Loc.GetString("Permissions Panel");
var tab = new TabContainer();
AddAdminButton = new Button
{
Text = Loc.GetString("Add Admin"),
HorizontalAlignment = HAlignment.Right
};
AddAdminRankButton = new Button
{
Text = Loc.GetString("Add Admin Rank"),
HorizontalAlignment = HAlignment.Right
};
AdminsList = new GridContainer {Columns = 5, VerticalExpand = true};
var adminVBox = new VBoxContainer
{
Children = {AdminsList, AddAdminButton},
};
TabContainer.SetTabTitle(adminVBox, Loc.GetString("Admins"));
AdminRanksList = new GridContainer {Columns = 3};
var rankVBox = new VBoxContainer
{
Children = { AdminRanksList, AddAdminRankButton}
};
TabContainer.SetTabTitle(rankVBox, Loc.GetString("Admin Ranks"));
tab.AddChild(adminVBox);
tab.AddChild(rankVBox);
Contents.AddChild(tab);
}
protected override Vector2 ContentsMinimumSize => (600, 400);
}
private sealed class EditAdminWindow : SS14Window
{
public readonly PermissionsEuiState.AdminData? SourceData;
public readonly LineEdit? NameEdit;
public readonly LineEdit TitleEdit;
public readonly OptionButton RankButton;
public readonly Button SaveButton;
public readonly Button? RemoveButton;
public readonly Dictionary<AdminFlags, (Button inherit, Button sub, Button plus)> FlagButtons
= new();
public EditAdminWindow(PermissionsEui ui, PermissionsEuiState.AdminData? data)
{
SetSize = MinSize = (600, 400);
SourceData = data;
Control nameControl;
if (data is { } dat)
{
var name = dat.UserName ?? dat.UserId.ToString();
Title = Loc.GetString("Edit admin {0}", name);
nameControl = new Label {Text = name};
}
else
{
Title = Loc.GetString("Add admin");
nameControl = NameEdit = new LineEdit {PlaceHolder = Loc.GetString("Username/User ID")};
}
TitleEdit = new LineEdit {PlaceHolder = Loc.GetString("Custom title, leave blank to inherit rank title.")};
RankButton = new OptionButton();
SaveButton = new Button {Text = Loc.GetString("Save"), HorizontalAlignment = HAlignment.Right};
RankButton.AddItem(Loc.GetString("No rank"), NoRank);
foreach (var (rId, rank) in ui._ranks)
{
RankButton.AddItem(rank.Name, rId);
}
RankButton.SelectId(data?.RankId ?? NoRank);
RankButton.OnItemSelected += RankSelected;
var permGrid = new GridContainer
{
Columns = 4,
HSeparationOverride = 0,
VSeparationOverride = 0
};
foreach (var flag in AdminFlagsHelper.AllFlags)
{
// Can only grant out perms you also have yourself.
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
var disable = !ui._adminManager.HasFlag(flag);
var flagName = flag.ToString().ToUpper();
var group = new ButtonGroup();
var inherit = new Button
{
Text = "I",
StyleClasses = {StyleBase.ButtonOpenRight},
Disabled = disable,
Group = group,
};
var sub = new Button
{
Text = "-",
StyleClasses = {StyleBase.ButtonOpenBoth},
Disabled = disable,
Group = group
};
var plus = new Button
{
Text = "+",
StyleClasses = {StyleBase.ButtonOpenLeft},
Disabled = disable,
Group = group
};
if (data is { } d)
{
if ((d.NegFlags & flag) != 0)
{
sub.Pressed = true;
}
else if ((d.PosFlags & flag) != 0)
{
plus.Pressed = true;
}
else
{
inherit.Pressed = true;
}
}
else
{
inherit.Pressed = true;
}
permGrid.AddChild(new Label {Text = flagName});
permGrid.AddChild(inherit);
permGrid.AddChild(sub);
permGrid.AddChild(plus);
FlagButtons.Add(flag, (inherit, sub, plus));
}
var bottomButtons = new HBoxContainer();
if (data != null)
{
// show remove button.
RemoveButton = new Button {Text = Loc.GetString("Remove")};
bottomButtons.AddChild(RemoveButton);
}
bottomButtons.AddChild(SaveButton);
Contents.AddChild(new VBoxContainer
{
Children =
{
new HBoxContainer
{
SeparationOverride = 2,
Children =
{
new VBoxContainer
{
HorizontalExpand = true,
Children =
{
nameControl,
TitleEdit,
RankButton
}
},
permGrid
},
VerticalExpand = true
},
bottomButtons
}
});
}
private void RankSelected(OptionButton.ItemSelectedEventArgs obj)
{
RankButton.SelectId(obj.Id);
}
public void CollectSetFlags(out AdminFlags pos, out AdminFlags neg)
{
pos = default;
neg = default;
foreach (var (flag, (_, s, p)) in FlagButtons)
{
if (s.Pressed)
{
neg |= flag;
}
else if (p.Pressed)
{
pos |= flag;
}
}
}
}
private sealed class EditAdminRankWindow : SS14Window
{
public readonly int? SourceId;
public readonly LineEdit NameEdit;
public readonly Button SaveButton;
public readonly Button? RemoveButton;
public readonly Dictionary<AdminFlags, CheckBox> FlagCheckBoxes = new();
public EditAdminRankWindow(PermissionsEui ui, KeyValuePair<int, PermissionsEuiState.AdminRankData>? data)
{
MinSize = SetSize = (600, 400);
SourceId = data?.Key;
NameEdit = new LineEdit
{
PlaceHolder = Loc.GetString("Rank name"),
};
if (data != null)
{
NameEdit.Text = data.Value.Value.Name;
}
SaveButton = new Button {
Text = Loc.GetString("Save"),
HorizontalAlignment = HAlignment.Right,
HorizontalExpand = true
};
var flagsBox = new VBoxContainer();
foreach (var flag in AdminFlagsHelper.AllFlags)
{
// Can only grant out perms you also have yourself.
// Primarily intended to prevent people giving themselves +HOST with +PERMISSIONS but generalized.
var disable = !ui._adminManager.HasFlag(flag);
var flagName = flag.ToString().ToUpper();
var checkBox = new CheckBox
{
Disabled = disable,
Text = flagName
};
if (data != null && (data.Value.Value.Flags & flag) != 0)
{
checkBox.Pressed = true;
}
FlagCheckBoxes.Add(flag, checkBox);
flagsBox.AddChild(checkBox);
}
var bottomButtons = new HBoxContainer();
if (data != null)
{
// show remove button.
RemoveButton = new Button {Text = Loc.GetString("Remove")};
bottomButtons.AddChild(RemoveButton);
}
bottomButtons.AddChild(SaveButton);
Contents.AddChild(new VBoxContainer
{
Children =
{
NameEdit,
flagsBox,
bottomButtons
}
});
}
public AdminFlags CollectSetFlags()
{
AdminFlags flags = default;
foreach (var (flag, chk) in FlagCheckBoxes)
{
if (chk.Pressed)
{
flags |= flag;
}
}
return flags;
}
}
}
}

View File

@@ -1,29 +0,0 @@
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface
{
public sealed class Placeholder : PanelContainer
{
public const string StyleClassPlaceholderText = "PlaceholderText";
private readonly Label _label;
public string? PlaceholderText
{
get => _label.Text;
set => _label.Text = value;
}
public Placeholder()
{
_label = new Label
{
VerticalAlignment = VAlignment.Stretch,
Align = Label.AlignMode.Center,
VAlign = Label.VAlignMode.Center
};
_label.AddStyleClass(StyleClassPlaceholderText);
AddChild(_label);
}
}
}

View File

@@ -1,108 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Content.Client.Utility;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Localization;
using static Content.Shared.GameTicking.SharedGameTicker;
namespace Content.Client.UserInterface
{
public sealed class RoundEndSummaryWindow : SS14Window
{
private VBoxContainer RoundEndSummaryTab { get; }
private VBoxContainer PlayerManifestoTab { get; }
private TabContainer RoundEndWindowTabs { get; }
public RoundEndSummaryWindow(string gm, string roundEnd, TimeSpan roundTimeSpan, List<RoundEndPlayerInfo> info)
{
MinSize = SetSize = (520, 580);
Title = Loc.GetString("Round End Summary");
//Round End Window is split into two tabs, one about the round stats
//and the other is a list of RoundEndPlayerInfo for each player.
//This tab would be a good place for things like: "x many people died.",
//"clown slipped the crew x times.", "x shots were fired this round.", etc.
//Also good for serious info.
RoundEndSummaryTab = new VBoxContainer()
{
Name = Loc.GetString("Round Information")
};
//Tab for listing unique info per player.
PlayerManifestoTab = new VBoxContainer()
{
Name = Loc.GetString("Player Manifesto")
};
RoundEndWindowTabs = new TabContainer();
RoundEndWindowTabs.AddChild(RoundEndSummaryTab);
RoundEndWindowTabs.AddChild(PlayerManifestoTab);
Contents.AddChild(RoundEndWindowTabs);
//Gamemode Name
var gamemodeLabel = new RichTextLabel();
gamemodeLabel.SetMarkup(Loc.GetString("Round of [color=white]{0}[/color] has ended.", gm));
RoundEndSummaryTab.AddChild(gamemodeLabel);
//Round end text
if (!string.IsNullOrEmpty(roundEnd))
{
var roundEndLabel = new RichTextLabel();
roundEndLabel.SetMarkup(Loc.GetString(roundEnd));
RoundEndSummaryTab.AddChild(roundEndLabel);
}
//Duration
var roundTimeLabel = new RichTextLabel();
roundTimeLabel.SetMarkup(Loc.GetString("It lasted for [color=yellow]{0} hours, {1} minutes, and {2} seconds.",
roundTimeSpan.Hours,roundTimeSpan.Minutes,roundTimeSpan.Seconds));
RoundEndSummaryTab.AddChild(roundTimeLabel);
//Initialize what will be the list of players display.
var scrollContainer = new ScrollContainer();
scrollContainer.VerticalExpand = true;
var innerScrollContainer = new VBoxContainer();
//Put observers at the bottom of the list. Put antags on top.
var manifestSortedList = info.OrderBy(p => p.Observer).ThenBy(p => !p.Antag);
//Create labels for each player info.
foreach (var playerInfo in manifestSortedList)
{
var playerInfoText = new RichTextLabel();
if (playerInfo.PlayerICName != null)
{
if (playerInfo.Observer)
{
playerInfoText.SetMarkup(
Loc.GetString("[color=gray]{0}[/color] was [color=lightblue]{1}[/color], an observer.",
playerInfo.PlayerOOCName, playerInfo.PlayerICName));
}
else
{
//TODO: On Hover display a popup detailing more play info.
//For example: their antag goals and if they completed them sucessfully.
var icNameColor = playerInfo.Antag ? "red" : "white";
playerInfoText.SetMarkup(
Loc.GetString("[color=gray]{0}[/color] was [color={1}]{2}[/color] playing role of [color=orange]{3}[/color].",
playerInfo.PlayerOOCName, icNameColor, playerInfo.PlayerICName, Loc.GetString(playerInfo.Role)));
}
}
innerScrollContainer.AddChild(playerInfoText);
}
scrollContainer.AddChild(innerScrollContainer);
//Attach the entire ScrollContainer that holds all the playerinfo.
PlayerManifestoTab.AddChild(scrollContainer);
//Finally, display the window.
OpenCentered();
MoveToFront();
}
}
}

View File

@@ -1,340 +0,0 @@
using System;
using System.Collections.Generic;
using Robust.Client.Graphics;
using Robust.Client.Input;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.IoC;
using Robust.Shared.Map;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Robust.Shared.ViewVariables;
using SixLabors.ImageSharp.PixelFormats;
namespace Content.Client.UserInterface
{
/// <summary>
/// Viewport control that has a fixed viewport size and scales it appropriately.
/// </summary>
public sealed class ScalingViewport : Control, IViewportControl
{
[Dependency] private readonly IClyde _clyde = default!;
[Dependency] private readonly IInputManager _inputManager = default!;
// Internal viewport creation is deferred.
private IClydeViewport? _viewport;
private IEye? _eye;
private Vector2i _viewportSize;
private int _curRenderScale;
private ScalingViewportStretchMode _stretchMode = ScalingViewportStretchMode.Bilinear;
private ScalingViewportRenderScaleMode _renderScaleMode = ScalingViewportRenderScaleMode.Fixed;
private int _fixedRenderScale = 1;
private readonly List<CopyPixelsDelegate<Rgba32>> _queuedScreenshots = new();
public int CurrentRenderScale => _curRenderScale;
/// <summary>
/// The eye to render.
/// </summary>
public IEye? Eye
{
get => _eye;
set
{
_eye = value;
if (_viewport != null)
_viewport.Eye = value;
}
}
/// <summary>
/// The size, in unscaled pixels, of the internal viewport.
/// </summary>
/// <remarks>
/// The actual viewport may have render scaling applied based on parameters.
/// </remarks>
public Vector2i ViewportSize
{
get => _viewportSize;
set
{
_viewportSize = value;
InvalidateViewport();
}
}
// Do not need to InvalidateViewport() since it doesn't affect viewport creation.
[ViewVariables(VVAccess.ReadWrite)] public Vector2i? FixedStretchSize { get; set; }
[ViewVariables(VVAccess.ReadWrite)]
public ScalingViewportStretchMode StretchMode
{
get => _stretchMode;
set
{
_stretchMode = value;
InvalidateViewport();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public ScalingViewportRenderScaleMode RenderScaleMode
{
get => _renderScaleMode;
set
{
_renderScaleMode = value;
InvalidateViewport();
}
}
[ViewVariables(VVAccess.ReadWrite)]
public int FixedRenderScale
{
get => _fixedRenderScale;
set
{
_fixedRenderScale = value;
InvalidateViewport();
}
}
public ScalingViewport()
{
IoCManager.InjectDependencies(this);
RectClipContent = true;
}
protected override void KeyBindDown(GUIBoundKeyEventArgs args)
{
base.KeyBindDown(args);
if (args.Handled)
return;
_inputManager.ViewportKeyEvent(this, args);
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
{
base.KeyBindUp(args);
if (args.Handled)
return;
_inputManager.ViewportKeyEvent(this, args);
}
protected override void FrameUpdate(FrameEventArgs args)
{
EnsureViewportCreated();
}
protected override void Draw(DrawingHandleScreen handle)
{
DebugTools.AssertNotNull(_viewport);
_viewport!.Render();
if (_queuedScreenshots.Count != 0)
{
var callbacks = _queuedScreenshots.ToArray();
_viewport.RenderTarget.CopyPixelsToMemory<Rgba32>(image =>
{
foreach (var callback in callbacks)
{
callback(image);
}
});
_queuedScreenshots.Clear();
}
var drawBox = GetDrawBox();
var drawBoxGlobal = drawBox.Translated(GlobalPixelPosition);
_viewport.RenderScreenOverlaysBelow(handle, this, drawBoxGlobal);
handle.DrawTextureRect(_viewport.RenderTarget.Texture, drawBox);
_viewport.RenderScreenOverlaysAbove(handle, this, drawBoxGlobal);
}
public void Screenshot(CopyPixelsDelegate<Rgba32> callback)
{
_queuedScreenshots.Add(callback);
}
// Draw box in pixel coords to draw the viewport at.
private UIBox2i GetDrawBox()
{
DebugTools.AssertNotNull(_viewport);
var vpSize = _viewport!.Size;
var ourSize = (Vector2) PixelSize;
if (FixedStretchSize == null)
{
var (ratioX, ratioY) = ourSize / vpSize;
var ratio = Math.Min(ratioX, ratioY);
var size = vpSize * ratio;
// Size
var pos = (ourSize - size) / 2;
return (UIBox2i) UIBox2.FromDimensions(pos, size);
}
else
{
// Center only, no scaling.
var pos = (ourSize - FixedStretchSize.Value) / 2;
return (UIBox2i) UIBox2.FromDimensions(pos, FixedStretchSize.Value);
}
}
private void RegenerateViewport()
{
DebugTools.AssertNull(_viewport);
var vpSizeBase = ViewportSize;
var ourSize = PixelSize;
var (ratioX, ratioY) = ourSize / (Vector2) vpSizeBase;
var ratio = Math.Min(ratioX, ratioY);
var renderScale = 1;
switch (_renderScaleMode)
{
case ScalingViewportRenderScaleMode.CeilInt:
renderScale = (int) Math.Ceiling(ratio);
break;
case ScalingViewportRenderScaleMode.FloorInt:
renderScale = (int) Math.Floor(ratio);
break;
case ScalingViewportRenderScaleMode.Fixed:
renderScale = _fixedRenderScale;
break;
}
// Always has to be at least one to avoid passing 0,0 to the viewport constructor
renderScale = Math.Max(1, renderScale);
_curRenderScale = renderScale;
_viewport = _clyde.CreateViewport(
ViewportSize * renderScale,
new TextureSampleParameters
{
Filter = StretchMode == ScalingViewportStretchMode.Bilinear,
});
_viewport.RenderScale = (renderScale, renderScale);
_viewport.Eye = _eye;
}
protected override void Resized()
{
base.Resized();
InvalidateViewport();
}
private void InvalidateViewport()
{
_viewport?.Dispose();
_viewport = null;
}
public MapCoordinates ScreenToMap(Vector2 coords)
{
if (_eye == null)
return default;
EnsureViewportCreated();
var matrix = Matrix3.Invert(LocalToScreenMatrix());
return _viewport!.LocalToWorld(matrix.Transform(coords));
}
public Vector2 WorldToScreen(Vector2 map)
{
if (_eye == null)
return default;
EnsureViewportCreated();
var vpLocal = _viewport!.WorldToLocal(map);
var matrix = LocalToScreenMatrix();
return matrix.Transform(vpLocal);
}
private Matrix3 LocalToScreenMatrix()
{
DebugTools.AssertNotNull(_viewport);
var drawBox = GetDrawBox();
var scaleFactor = drawBox.Size / (Vector2) _viewport!.Size;
if (scaleFactor == (0, 0))
// Basically a nonsense scenario, at least make sure to return something that can be inverted.
return Matrix3.Identity;
var scale = Matrix3.CreateScale(scaleFactor);
var translate = Matrix3.CreateTranslation(GlobalPixelPosition + drawBox.TopLeft);
return scale * translate;
}
private void EnsureViewportCreated()
{
if (_viewport == null)
{
RegenerateViewport();
}
DebugTools.AssertNotNull(_viewport);
}
}
/// <summary>
/// Defines how the viewport is stretched if it does not match the size of the control perfectly.
/// </summary>
public enum ScalingViewportStretchMode
{
/// <summary>
/// Bilinear sampling is used.
/// </summary>
Bilinear = 0,
/// <summary>
/// Nearest neighbor sampling is used.
/// </summary>
Nearest,
}
/// <summary>
/// Defines how the base render scale of the viewport is selected.
/// </summary>
public enum ScalingViewportRenderScaleMode
{
/// <summary>
/// <see cref="ScalingViewport.FixedRenderScale"/> is used.
/// </summary>
Fixed = 0,
/// <summary>
/// Floor to the closest integer scale possible.
/// </summary>
FloorInt,
/// <summary>
/// Ceiling to the closest integer scale possible.
/// </summary>
CeilInt
}
}

View File

@@ -1,57 +0,0 @@
using Content.Client.Changelog;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Utility;
namespace Content.Client.UserInterface
{
public class ServerInfo : VBoxContainer
{
private readonly RichTextLabel _richTextLabel;
public ServerInfo()
{
_richTextLabel = new RichTextLabel
{
VerticalExpand = true
};
AddChild(_richTextLabel);
var buttons = new HBoxContainer();
AddChild(buttons);
var uriOpener = IoCManager.Resolve<IUriOpener>();
var discordButton = new Button {Text = Loc.GetString("Discord")};
discordButton.OnPressed += args => uriOpener.OpenUri(UILinks.Discord);
var websiteButton = new Button {Text = Loc.GetString("Website")};
websiteButton.OnPressed += args => uriOpener.OpenUri(UILinks.Website);
var reportButton = new Button { Text = Loc.GetString("Report Bugs") };
reportButton.OnPressed += args => uriOpener.OpenUri(UILinks.BugReport);
var creditsButton = new Button { Text = Loc.GetString("Credits") };
creditsButton.OnPressed += args => new CreditsWindow().Open();
var changelogButton = new ChangelogButton
{
HorizontalExpand = true,
HorizontalAlignment = HAlignment.Right
};
buttons.AddChild(discordButton);
buttons.AddChild(websiteButton);
buttons.AddChild(reportButton);
buttons.AddChild(creditsButton);
buttons.AddChild(changelogButton);
}
public void SetInfoBlob(string markup)
{
_richTextLabel.SetMessage(FormattedMessage.FromMarkup(markup));
}
}
}

View File

@@ -1,124 +0,0 @@
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public class StripeBack : Container
{
private const float PadSize = 4;
private const float EdgeSize = 2;
private static readonly Color EdgeColor = Color.FromHex("#525252ff");
private bool _hasTopEdge = true;
private bool _hasBottomEdge = true;
private bool _hasMargins = true;
public const string StylePropertyBackground = "background";
public bool HasTopEdge
{
get => _hasTopEdge;
set
{
_hasTopEdge = value;
InvalidateMeasure();
}
}
public bool HasBottomEdge
{
get => _hasBottomEdge;
set
{
_hasBottomEdge = value;
InvalidateMeasure();
}
}
public bool HasMargins
{
get => _hasMargins;
set
{
_hasMargins = value;
InvalidateMeasure();
}
}
protected override Vector2 MeasureOverride(Vector2 availableSize)
{
var padSize = HasMargins ? PadSize : 0;
var padSizeTotal = 0f;
if (HasBottomEdge)
padSizeTotal += padSize + EdgeSize;
if (HasTopEdge)
padSizeTotal += padSize + EdgeSize;
var size = Vector2.Zero;
availableSize.Y -= padSizeTotal;
foreach (var child in Children)
{
child.Measure(availableSize);
size = Vector2.ComponentMax(size, child.DesiredSize);
}
return size + (0, padSizeTotal);
}
protected override Vector2 ArrangeOverride(Vector2 finalSize)
{
var box = new UIBox2(Vector2.Zero, finalSize);
var padSize = HasMargins ? PadSize : 0;
if (HasTopEdge)
{
box += (0, padSize + EdgeSize, 0, 0);
}
if (HasBottomEdge)
{
box += (0, 0, 0, -(padSize + EdgeSize));
}
foreach (var child in Children)
{
child.Arrange(box);
}
return finalSize;
}
protected override void Draw(DrawingHandleScreen handle)
{
UIBox2 centerBox = PixelSizeBox;
var padSize = HasMargins ? PadSize : 0;
if (HasTopEdge)
{
centerBox += (0, (padSize + EdgeSize) * UIScale, 0, 0);
handle.DrawRect(new UIBox2(0, padSize * UIScale, PixelWidth, centerBox.Top), EdgeColor);
}
if (HasBottomEdge)
{
centerBox += (0, 0, 0, -((padSize + EdgeSize) * UIScale));
handle.DrawRect(new UIBox2(0, centerBox.Bottom, PixelWidth, PixelHeight - padSize * UIScale),
EdgeColor);
}
GetActualStyleBox()?.Draw(handle, centerBox);
}
private StyleBox? GetActualStyleBox()
{
return TryGetStyleProperty(StylePropertyBackground, out StyleBox? box) ? box : null;
}
}
}

View File

@@ -1,62 +0,0 @@
using System;
using Content.Client.UserInterface.Stylesheets;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface
{
public class StrippingMenu : SS14Window
{
private readonly VBoxContainer _vboxContainer;
public StrippingMenu(string title)
{
MinSize = SetSize = (400, 600);
Title = title;
_vboxContainer = new VBoxContainer()
{
VerticalExpand = true,
SeparationOverride = 5,
};
Contents.AddChild(_vboxContainer);
}
public void ClearButtons()
{
_vboxContainer.DisposeAllChildren();
}
public void AddButton(string title, string name, Action<BaseButton.ButtonEventArgs> onPressed)
{
var button = new Button()
{
Text = name,
StyleClasses = { StyleBase.ButtonOpenRight }
};
button.OnPressed += onPressed;
_vboxContainer.AddChild(new HBoxContainer()
{
HorizontalExpand = true,
SeparationOverride = 5,
Children =
{
new Label()
{
Text = $"{title}:"
},
new Control()
{
HorizontalExpand = true
},
button,
}
});
}
}
}

View File

@@ -1,12 +0,0 @@
using Robust.Client.UserInterface;
namespace Content.Client.UserInterface.Stylesheets
{
public interface IStylesheetManager
{
Stylesheet SheetNano { get; }
Stylesheet SheetSpace { get; }
void Initialize();
}
}

View File

@@ -1,220 +0,0 @@
using Content.Client.Utility;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Maths;
namespace Content.Client.UserInterface.Stylesheets
{
public abstract class StyleBase
{
public const string ClassHighDivider = "HighDivider";
public const string ClassLowDivider = "LowDivider";
public const string StyleClassLabelHeading = "LabelHeading";
public const string StyleClassLabelSubText = "LabelSubText";
public const string StyleClassItalic = "Italic";
public const string ClassAngleRect = "AngleRect";
public const string ButtonOpenRight = "OpenRight";
public const string ButtonOpenLeft = "OpenLeft";
public const string ButtonOpenBoth = "OpenBoth";
public const string ButtonSquare = "ButtonSquare";
public const string ButtonCaution = "Caution";
public abstract Stylesheet Stylesheet { get; }
protected StyleRule[] BaseRules { get; }
protected StyleBoxTexture BaseButton { get; }
protected StyleBoxTexture BaseButtonOpenRight { get; }
protected StyleBoxTexture BaseButtonOpenLeft { get; }
protected StyleBoxTexture BaseButtonOpenBoth { get; }
protected StyleBoxTexture BaseButtonSquare { get; }
protected StyleBoxTexture BaseAngleRect { get; }
protected StyleBase(IResourceCache resCache)
{
var notoSans12 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 12);
var notoSans12Italic = resCache.GetFont("/Fonts/NotoSans/NotoSans-Italic.ttf", 12);
var textureCloseButton = resCache.GetTexture("/Textures/Interface/Nano/cross.svg.png");
// Button styles.
var buttonTex = resCache.GetTexture("/Textures/Interface/Nano/button.svg.96dpi.png");
BaseButton = new StyleBoxTexture
{
Texture = buttonTex,
};
BaseButton.SetPatchMargin(StyleBox.Margin.All, 10);
BaseButton.SetPadding(StyleBox.Margin.All, 1);
BaseButton.SetContentMarginOverride(StyleBox.Margin.Vertical, 2);
BaseButton.SetContentMarginOverride(StyleBox.Margin.Horizontal, 14);
BaseButtonOpenRight = new StyleBoxTexture(BaseButton)
{
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((0, 0), (14, 24))),
};
BaseButtonOpenRight.SetPatchMargin(StyleBox.Margin.Right, 0);
BaseButtonOpenRight.SetContentMarginOverride(StyleBox.Margin.Right, 8);
BaseButtonOpenRight.SetPadding(StyleBox.Margin.Right, 2);
BaseButtonOpenLeft = new StyleBoxTexture(BaseButton)
{
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (14, 24))),
};
BaseButtonOpenLeft.SetPatchMargin(StyleBox.Margin.Left, 0);
BaseButtonOpenLeft.SetContentMarginOverride(StyleBox.Margin.Left, 8);
BaseButtonOpenLeft.SetPadding(StyleBox.Margin.Left, 1);
BaseButtonOpenBoth = new StyleBoxTexture(BaseButton)
{
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (3, 24))),
};
BaseButtonOpenBoth.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
BaseButtonOpenBoth.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
BaseButtonOpenBoth.SetPadding(StyleBox.Margin.Right, 2);
BaseButtonOpenBoth.SetPadding(StyleBox.Margin.Left, 1);
BaseButtonSquare = new StyleBoxTexture(BaseButton)
{
Texture = new AtlasTexture(buttonTex, UIBox2.FromDimensions((10, 0), (3, 24))),
};
BaseButtonSquare.SetPatchMargin(StyleBox.Margin.Horizontal, 0);
BaseButtonSquare.SetContentMarginOverride(StyleBox.Margin.Horizontal, 8);
BaseButtonSquare.SetPadding(StyleBox.Margin.Right, 2);
BaseButtonSquare.SetPadding(StyleBox.Margin.Left, 1);
BaseAngleRect = new StyleBoxTexture
{
Texture = buttonTex,
};
BaseAngleRect.SetPatchMargin(StyleBox.Margin.All, 10);
var vScrollBarGrabberNormal = new StyleBoxFlat
{
BackgroundColor = Color.Gray.WithAlpha(0.35f), ContentMarginLeftOverride = 10,
ContentMarginTopOverride = 10
};
var vScrollBarGrabberHover = new StyleBoxFlat
{
BackgroundColor = new Color(140, 140, 140).WithAlpha(0.35f), ContentMarginLeftOverride = 10,
ContentMarginTopOverride = 10
};
var vScrollBarGrabberGrabbed = new StyleBoxFlat
{
BackgroundColor = new Color(160, 160, 160).WithAlpha(0.35f), ContentMarginLeftOverride = 10,
ContentMarginTopOverride = 10
};
var hScrollBarGrabberNormal = new StyleBoxFlat
{
BackgroundColor = Color.Gray.WithAlpha(0.35f), ContentMarginTopOverride = 10
};
var hScrollBarGrabberHover = new StyleBoxFlat
{
BackgroundColor = new Color(140, 140, 140).WithAlpha(0.35f), ContentMarginTopOverride = 10
};
var hScrollBarGrabberGrabbed = new StyleBoxFlat
{
BackgroundColor = new Color(160, 160, 160).WithAlpha(0.35f), ContentMarginTopOverride = 10
};
BaseRules = new[]
{
// Default font.
new StyleRule(
new SelectorElement(null, null, null, null),
new[]
{
new StyleProperty("font", notoSans12),
}),
// Default font.
new StyleRule(
new SelectorElement(null, new[] {StyleClassItalic}, null, null),
new[]
{
new StyleProperty("font", notoSans12Italic),
}),
// Window close button base texture.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
null),
new[]
{
new StyleProperty(TextureButton.StylePropertyTexture, textureCloseButton),
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#4B596A")),
}),
// Window close button hover.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
new[] {TextureButton.StylePseudoClassHover}),
new[]
{
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#7F3636")),
}),
// Window close button pressed.
new StyleRule(
new SelectorElement(typeof(TextureButton), new[] {SS14Window.StyleClassWindowCloseButton}, null,
new[] {TextureButton.StylePseudoClassPressed}),
new[]
{
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#753131")),
}),
// Scroll bars
new StyleRule(new SelectorElement(typeof(VScrollBar), null, null, null),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberNormal),
}),
new StyleRule(
new SelectorElement(typeof(VScrollBar), null, null, new[] {ScrollBar.StylePseudoClassHover}),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberHover),
}),
new StyleRule(
new SelectorElement(typeof(VScrollBar), null, null, new[] {ScrollBar.StylePseudoClassGrabbed}),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
vScrollBarGrabberGrabbed),
}),
new StyleRule(new SelectorElement(typeof(HScrollBar), null, null, null),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberNormal),
}),
new StyleRule(
new SelectorElement(typeof(HScrollBar), null, null, new[] {ScrollBar.StylePseudoClassHover}),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberHover),
}),
new StyleRule(
new SelectorElement(typeof(HScrollBar), null, null, new[] {ScrollBar.StylePseudoClassGrabbed}),
new[]
{
new StyleProperty(ScrollBar.StylePropertyGrabber,
hScrollBarGrabberGrabbed),
}),
};
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,168 +0,0 @@
using System.Linq;
using Content.Client.Utility;
using Robust.Client.Graphics;
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Maths;
using static Robust.Client.UserInterface.StylesheetHelpers;
namespace Content.Client.UserInterface.Stylesheets
{
public class StyleSpace : StyleBase
{
public static readonly Color SpaceRed = Color.FromHex("#9b2236");
public static readonly Color ButtonColorDefault = Color.FromHex("#464966");
public static readonly Color ButtonColorHovered = Color.FromHex("#575b7f");
public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45");
public static readonly Color ButtonColorDisabled = Color.FromHex("#30313c");
public static readonly Color ButtonColorCautionDefault = Color.FromHex("#ab3232");
public static readonly Color ButtonColorCautionHovered = Color.FromHex("#cf2f2f");
public static readonly Color ButtonColorCautionPressed = Color.FromHex("#3e6c45");
public static readonly Color ButtonColorCautionDisabled = Color.FromHex("#602a2a");
public override Stylesheet Stylesheet { get; }
public StyleSpace(IResourceCache resCache) : base(resCache)
{
var notoSans10 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Regular.ttf", 10);
var notoSansBold16 = resCache.GetFont("/Fonts/NotoSans/NotoSans-Bold.ttf", 16);
var progressBarBackground = new StyleBoxFlat
{
BackgroundColor = new Color(0.25f, 0.25f, 0.25f)
};
progressBarBackground.SetContentMarginOverride(StyleBox.Margin.Vertical, 5);
var progressBarForeground = new StyleBoxFlat
{
BackgroundColor = new Color(0.25f, 0.50f, 0.25f)
};
progressBarForeground.SetContentMarginOverride(StyleBox.Margin.Vertical, 5);
var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png");
Stylesheet = new Stylesheet(BaseRules.Concat(new StyleRule[]
{
Element<Label>().Class(StyleClassLabelHeading)
.Prop(Label.StylePropertyFont, notoSansBold16)
.Prop(Label.StylePropertyFontColor, SpaceRed),
Element<Label>().Class(StyleClassLabelSubText)
.Prop(Label.StylePropertyFont, notoSans10)
.Prop(Label.StylePropertyFontColor, Color.DarkGray),
Element<PanelContainer>().Class(ClassHighDivider)
.Prop(PanelContainer.StylePropertyPanel, new StyleBoxFlat
{
BackgroundColor = SpaceRed, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2
}),
Element<PanelContainer>().Class(ClassLowDivider)
.Prop(PanelContainer.StylePropertyPanel, new StyleBoxFlat
{
BackgroundColor = Color.FromHex("#444"),
ContentMarginLeftOverride = 2,
ContentMarginBottomOverride = 2
}),
// Shapes for the buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButton),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Class(ButtonOpenRight)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenRight),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Class(ButtonOpenLeft)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenLeft),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Class(ButtonOpenBoth)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenBoth),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Class(ButtonSquare)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButtonSquare),
// Colors for the buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(Control.StylePropertyModulateSelf, ButtonColorDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(Control.StylePropertyModulateSelf, ButtonColorHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(Control.StylePropertyModulateSelf, ButtonColorPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(Control.StylePropertyModulateSelf, ButtonColorDisabled),
// Colors for the caution buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDisabled),
Element<Label>().Class(ContainerButton.StyleClassButton)
.Prop(Label.StylePropertyAlignMode, Label.AlignMode.Center),
Element<PanelContainer>().Class(ClassAngleRect)
.Prop(PanelContainer.StylePropertyPanel, BaseAngleRect)
.Prop(Control.StylePropertyModulateSelf, Color.FromHex("#202030")),
Child()
.Parent(Element<Button>().Class(ContainerButton.StylePseudoClassDisabled))
.Child(Element<Label>())
.Prop("font-color", Color.FromHex("#E5E5E581")),
Element<ProgressBar>()
.Prop(ProgressBar.StylePropertyBackground, progressBarBackground)
.Prop(ProgressBar.StylePropertyForeground, progressBarForeground),
// OptionButton
Element<OptionButton>()
.Prop(ContainerButton.StylePropertyStyleBox, BaseButton),
Element<OptionButton>().Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(Control.StylePropertyModulateSelf, ButtonColorDefault),
Element<OptionButton>().Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(Control.StylePropertyModulateSelf, ButtonColorHovered),
Element<OptionButton>().Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(Control.StylePropertyModulateSelf, ButtonColorPressed),
Element<OptionButton>().Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(Control.StylePropertyModulateSelf, ButtonColorDisabled),
Element<TextureRect>().Class(OptionButton.StyleClassOptionTriangle)
.Prop(TextureRect.StylePropertyTexture, textureInvertedTriangle),
Element<Label>().Class(OptionButton.StyleClassOptionButton)
.Prop(Label.StylePropertyAlignMode, Label.AlignMode.Center),
}).ToList());
}
}
}

View File

@@ -1,23 +0,0 @@
using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.IoC;
namespace Content.Client.UserInterface.Stylesheets
{
public sealed class StylesheetManager : IStylesheetManager
{
[Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
public Stylesheet SheetNano { get; private set; } = default!;
public Stylesheet SheetSpace { get; private set; } = default!;
public void Initialize()
{
SheetNano = new StyleNano(_resourceCache).Stylesheet;
SheetSpace = new StyleSpace(_resourceCache).Stylesheet;
_userInterfaceManager.Stylesheet = SheetNano;
}
}
}

View File

@@ -1,7 +0,0 @@
<Control xmlns="https://spacestation14.io">
<VBoxContainer SeparationOverride="0">
<Button Name="RoleButton">
<Label Name="TimerLabel" SizeFlagsHorizontal="ShrinkEnd" SizeFlagsVertical="ShrinkEnd" />
</Button>
</VBoxContainer>
</Control>

View File

@@ -1,126 +0,0 @@
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Linq;
using Content.Client.GameObjects.Components.Suspicion;
using Content.Client.GameObjects.EntitySystems;
using Content.Shared.Interfaces;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
using Robust.Shared.Timing;
using static Robust.Client.UserInterface.Controls.BaseButton;
namespace Content.Client.UserInterface.Suspicion
{
[GenerateTypedNameReferences]
public partial class SuspicionGui : Control
{
[Dependency] private readonly IPlayerManager _playerManager = default!;
[Dependency] private readonly IGameTiming _timing = default!;
private string? _previousRoleName;
private bool _previousAntagonist;
public SuspicionGui()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
RoleButton.OnPressed += RoleButtonPressed;
RoleButton.MinSize = (200, 60);
}
private void RoleButtonPressed(ButtonEventArgs obj)
{
if (!TryGetComponent(out var role))
{
return;
}
if (!role.Antagonist ?? false)
{
return;
}
var allies = string.Join(", ", role.Allies.Select(tuple => tuple.name));
role.Owner.PopupMessage(
Loc.GetString(
"suspicion-ally-count-display",
("allyCount", role.Allies.Count),
("allyNames", allies)
)
);
}
private bool TryGetComponent([NotNullWhen(true)] out SuspicionRoleComponent? suspicion)
{
suspicion = default;
if (_playerManager.LocalPlayer?.ControlledEntity == null)
{
return false;
}
return _playerManager.LocalPlayer.ControlledEntity.TryGetComponent(out suspicion);
}
public void UpdateLabel()
{
if (!TryGetComponent(out var suspicion))
{
Visible = false;
return;
}
if (suspicion.Role == null || suspicion.Antagonist == null)
{
Visible = false;
return;
}
var endTime = EntitySystem.Get<SuspicionEndTimerSystem>().EndTime;
if (endTime == null)
{
TimerLabel.Visible = false;
}
else
{
var diff = endTime.Value - _timing.CurTime;
if (diff < TimeSpan.Zero)
{
diff = TimeSpan.Zero;
}
TimerLabel.Visible = true;
TimerLabel.Text = $"{diff:mm\\:ss}";
}
if (_previousRoleName == suspicion.Role && _previousAntagonist == suspicion.Antagonist)
{
return;
}
_previousRoleName = suspicion.Role;
_previousAntagonist = suspicion.Antagonist.Value;
var buttonText = CultureInfo.CurrentCulture.TextInfo.ToTitleCase(_previousRoleName);
buttonText = Loc.GetString(buttonText);
RoleButton.Text = buttonText;
RoleButton.ModulateSelfOverride = _previousAntagonist ? Color.Red : Color.Green;
Visible = true;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateLabel();
}
}
}

Some files were not shown because too many files have changed in this diff Show More