Re-organize all projects (#4166)
This commit is contained in:
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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)}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}\"");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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!;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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}});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Robust.Client.UserInterface.CustomControls;
|
||||
|
||||
namespace Content.Client.UserInterface
|
||||
{
|
||||
public class GhostRoleWindow : SS14Window
|
||||
{
|
||||
protected override void Opened()
|
||||
{
|
||||
base.Opened();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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,
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using Robust.Client.UserInterface;
|
||||
|
||||
namespace Content.Client.UserInterface.Stylesheets
|
||||
{
|
||||
public interface IStylesheetManager
|
||||
{
|
||||
Stylesheet SheetNano { get; }
|
||||
Stylesheet SheetSpace { get; }
|
||||
|
||||
void Initialize();
|
||||
}
|
||||
}
|
||||
@@ -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
@@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
@@ -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
Reference in New Issue
Block a user