Merge branch 'master' into 2020-08-19-firelocks

This commit is contained in:
Víctor Aguilera Puerto
2020-09-07 12:47:52 +02:00
28 changed files with 979 additions and 289 deletions

View File

@@ -21,6 +21,17 @@
<ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" /> <ProjectReference Include="..\RobustToolbox\Robust.Client\Robust.Client.csproj" />
<ProjectReference Include="..\Content.Shared\Content.Shared.csproj" /> <ProjectReference Include="..\Content.Shared\Content.Shared.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="UserInterface\OptionsMenu.Graphics.cs">
<DependentUpon>OptionsMenu.cs</DependentUpon>
</Compile>
<Compile Update="UserInterface\OptionsMenu.KeyRebind.cs">
<DependentUpon>OptionsMenu.cs</DependentUpon>
</Compile>
<Compile Update="UserInterface\OptionsMenu.Audio.cs">
<DependentUpon>OptionsMenu.cs</DependentUpon>
</Compile>
</ItemGroup>
<Import Project="..\RobustToolbox\MSBuild\Robust.Engine.targets" /> <Import Project="..\RobustToolbox\MSBuild\Robust.Engine.targets" />
<Target Name="ContentAfterBuild" DependsOnTargets="ClientAfterBuild" AfterTargets="Build" /> <Target Name="ContentAfterBuild" DependsOnTargets="ClientAfterBuild" AfterTargets="Build" />
</Project> </Project>

View File

@@ -2,29 +2,19 @@
using Content.Client.UserInterface; using Content.Client.UserInterface;
using Robust.Client.Console; using Robust.Client.Console;
using Robust.Client.Interfaces.Input; using Robust.Client.Interfaces.Input;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.Interfaces.State; using Robust.Client.Interfaces.State;
using Robust.Shared.Input; using Robust.Shared.Input;
using Robust.Shared.Input.Binding; using Robust.Shared.Input.Binding;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client namespace Content.Client
{ {
internal sealed class EscapeMenuOwner : IEscapeMenuOwner internal sealed class EscapeMenuOwner : IEscapeMenuOwner
{ {
[Dependency] private readonly IClientConsole _clientConsole = default!; [Dependency] private readonly IClientConsole _clientConsole = default!;
[Dependency] private readonly IConfigurationManager _configurationManager = default!;
[Dependency] private readonly IInputManager _inputManager = default!; [Dependency] private readonly IInputManager _inputManager = default!;
[Dependency] private readonly IPlacementManager _placementManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IResourceCache _resourceCache = default!;
[Dependency] private readonly IStateManager _stateManager = default!; [Dependency] private readonly IStateManager _stateManager = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefinitionManager = default!;
[Dependency] private readonly IGameHud _gameHud = default!; [Dependency] private readonly IGameHud _gameHud = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!; [Dependency] private readonly ILocalizationManager _localizationManager = default!;
@@ -42,8 +32,7 @@ namespace Content.Client
if (obj.NewState is GameScreenBase) if (obj.NewState is GameScreenBase)
{ {
// Switched TO GameScreen. // Switched TO GameScreen.
_escapeMenu = new EscapeMenu(_clientConsole, _tileDefinitionManager, _placementManager, _escapeMenu = new EscapeMenu(_clientConsole, _localizationManager);
_prototypeManager, _resourceCache, _configurationManager, _localizationManager);
_escapeMenu.OnClose += () => _gameHud.EscapeButtonDown = false; _escapeMenu.OnClose += () => _gameHud.EscapeButtonDown = false;

View File

@@ -1,5 +1,4 @@
 using System;
using System;
using System.Collections.Generic; using System.Collections.Generic;
using Robust.Client.GameObjects; using Robust.Client.GameObjects;
using Robust.Shared.Animations; using Robust.Shared.Animations;
@@ -13,8 +12,6 @@ using Robust.Shared.Log;
using Robust.Shared.Maths; using Robust.Shared.Maths;
using Robust.Shared.Interfaces.Serialization; using Robust.Shared.Interfaces.Serialization;
using Robust.Client.Animations; using Robust.Client.Animations;
using Robust.Shared.Interfaces.GameObjects;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Robust.Client.GameObjects.Components.Animations; using Robust.Client.GameObjects.Components.Animations;
using System.Linq; using System.Linq;

View File

@@ -55,7 +55,7 @@ namespace Content.Client.GameObjects.Components.Storage
break; break;
//Opens the UI //Opens the UI
case OpenStorageUIMessage _: case OpenStorageUIMessage _:
OpenUI(); ToggleUI();
break; break;
case CloseStorageUIMessage _: case CloseStorageUIMessage _:
CloseUI(); CloseUI();
@@ -76,10 +76,13 @@ namespace Content.Client.GameObjects.Components.Storage
} }
/// <summary> /// <summary>
/// Opens the storage UI /// Opens the storage UI if closed. Closes it if opened.
/// </summary> /// </summary>
private void OpenUI() private void ToggleUI()
{ {
if (Window.IsOpen)
Window.Close();
else
Window.Open(); Window.Open();
} }

View File

@@ -1,5 +1,6 @@
using System; using System;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using Content.Client.UserInterface;
using Robust.Client; using Robust.Client;
using Robust.Client.Interfaces; using Robust.Client.Interfaces;
using Robust.Client.Interfaces.ResourceManagement; using Robust.Client.Interfaces.ResourceManagement;
@@ -7,7 +8,6 @@ using Robust.Client.Interfaces.UserInterface;
using Robust.Client.ResourceManagement; using Robust.Client.ResourceManagement;
using Robust.Client.UserInterface; using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.Configuration; using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Network; using Robust.Shared.Interfaces.Network;
using Robust.Shared.IoC; using Robust.Shared.IoC;
@@ -56,7 +56,7 @@ namespace Content.Client.State
_client.RunLevelChanged += RunLevelChanged; _client.RunLevelChanged += RunLevelChanged;
OptionsMenu = new OptionsMenu(_configurationManager); OptionsMenu = new OptionsMenu();
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@@ -1,24 +1,14 @@
using Robust.Client.Console; using Robust.Client.Console;
using Robust.Client.Interfaces.Placement;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.Interfaces.Map;
using Robust.Shared.IoC; using Robust.Shared.IoC;
using Robust.Shared.Localization; using Robust.Shared.Localization;
using Robust.Shared.Prototypes;
namespace Content.Client.UserInterface namespace Content.Client.UserInterface
{ {
internal sealed class EscapeMenu : SS14Window internal sealed class EscapeMenu : SS14Window
{ {
private readonly IClientConsole _console; private readonly IClientConsole _console;
private readonly ITileDefinitionManager _tileDefinitionManager;
private readonly IPlacementManager _placementManager;
private readonly IPrototypeManager _prototypeManager;
private readonly IResourceCache _resourceCache;
private readonly IConfigurationManager _configSystem;
private readonly ILocalizationManager _localizationManager; private readonly ILocalizationManager _localizationManager;
private BaseButton DisconnectButton; private BaseButton DisconnectButton;
@@ -26,20 +16,10 @@ namespace Content.Client.UserInterface
private BaseButton OptionsButton; private BaseButton OptionsButton;
private OptionsMenu optionsMenu; private OptionsMenu optionsMenu;
public EscapeMenu(IClientConsole console, public EscapeMenu(IClientConsole console, ILocalizationManager localizationManager)
ITileDefinitionManager tileDefinitionManager,
IPlacementManager placementManager,
IPrototypeManager prototypeManager,
IResourceCache resourceCache,
IConfigurationManager configSystem, ILocalizationManager localizationManager)
{ {
_configSystem = configSystem;
_localizationManager = localizationManager; _localizationManager = localizationManager;
_console = console; _console = console;
_tileDefinitionManager = tileDefinitionManager;
_placementManager = placementManager;
_prototypeManager = prototypeManager;
_resourceCache = resourceCache;
IoCManager.InjectDependencies(this); IoCManager.InjectDependencies(this);
@@ -48,7 +28,7 @@ namespace Content.Client.UserInterface
private void PerformLayout() private void PerformLayout()
{ {
optionsMenu = new OptionsMenu(_configSystem); optionsMenu = new OptionsMenu();
Resizable = false; Resizable = false;
@@ -95,10 +75,5 @@ namespace Content.Client.UserInterface
optionsMenu.Dispose(); optionsMenu.Dispose();
} }
} }
public override void Close()
{
base.Close();
}
} }
} }

View File

@@ -0,0 +1,19 @@
using System;
using System.Collections.Generic;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Input;
using Robust.Client.Input;
using Robust.Client.Interfaces.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.Timing;
using Robust.Shared.Utility;
#nullable enable
namespace Content.Client.UserInterface
{
}

View File

@@ -0,0 +1,21 @@
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.IoC;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu
{
private sealed class AudioControl : Control
{
public AudioControl(IConfigurationManager cfg)
{
AddChild(new Placeholder(IoCManager.Resolve<IResourceCache>())
{
PlaceholderText = "Pretend there's a bunch of volume sliders here."
});
}
}
}
}

View File

@@ -0,0 +1,185 @@
using Robust.Client.Graphics;
using Robust.Client.Interfaces.ResourceManagement;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu
{
private sealed class GraphicsControl : Control
{
private readonly IConfigurationManager _cfg;
private readonly Button ApplyButton;
private readonly CheckBox VSyncCheckBox;
private readonly CheckBox FullscreenCheckBox;
private readonly OptionButton LightingPresetOption;
public GraphicsControl(IConfigurationManager cfg)
{
_cfg = cfg;
var vBox = new VBoxContainer();
var contents = new VBoxContainer();
VSyncCheckBox = new CheckBox {Text = Loc.GetString("VSync")};
contents.AddChild(VSyncCheckBox);
VSyncCheckBox.OnToggled += OnCheckBoxToggled;
FullscreenCheckBox = new CheckBox {Text = Loc.GetString("Fullscreen")};
contents.AddChild(FullscreenCheckBox);
FullscreenCheckBox.OnToggled += OnCheckBoxToggled;
LightingPresetOption = new OptionButton {CustomMinimumSize = (100, 0)};
LightingPresetOption.AddItem(Loc.GetString("Very Low"));
LightingPresetOption.AddItem(Loc.GetString("Low"));
LightingPresetOption.AddItem(Loc.GetString("Medium"));
LightingPresetOption.AddItem(Loc.GetString("High"));
LightingPresetOption.OnItemSelected += OnLightingQualityChanged;
var lightingHBox = new HBoxContainer
{
Children =
{
new Label {Text = Loc.GetString("Lighting Quality:")},
new Control {CustomMinimumSize = (4, 0)},
LightingPresetOption
}
};
contents.AddChild(lightingHBox);
ApplyButton = new Button
{
Text = Loc.GetString("Apply"), TextAlign = Label.AlignMode.Center,
SizeFlagsHorizontal = SizeFlags.ShrinkEnd
};
var resourceCache = IoCManager.Resolve<IResourceCache>();
contents.AddChild(new Placeholder(resourceCache)
{
SizeFlagsVertical = SizeFlags.FillExpand,
PlaceholderText = "UI Scaling"
});
contents.AddChild(new Placeholder(resourceCache)
{
SizeFlagsVertical = SizeFlags.FillExpand,
PlaceholderText = "Viewport settings"
});
vBox.AddChild(new MarginContainer
{
MarginLeftOverride = 2,
MarginTopOverride = 2,
MarginRightOverride = 2,
SizeFlagsVertical = SizeFlags.FillExpand,
Children =
{
contents
}
});
vBox.AddChild(new StripeBack
{
HasBottomEdge = false,
HasMargins = false,
Children =
{
ApplyButton
}
});
ApplyButton.OnPressed += OnApplyButtonPressed;
VSyncCheckBox.Pressed = _cfg.GetCVar<bool>("display.vsync");
FullscreenCheckBox.Pressed = ConfigIsFullscreen;
LightingPresetOption.SelectId(GetConfigLightingQuality());
AddChild(vBox);
}
private void OnApplyButtonPressed(BaseButton.ButtonEventArgs args)
{
_cfg.SetCVar("display.vsync", VSyncCheckBox.Pressed);
SetConfigLightingQuality(LightingPresetOption.SelectedId);
_cfg.SetCVar("display.windowmode",
(int) (FullscreenCheckBox.Pressed ? WindowMode.Fullscreen : WindowMode.Windowed));
_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<bool>("display.vsync");
var isFullscreenSame = FullscreenCheckBox.Pressed == ConfigIsFullscreen;
var isLightingQualitySame = LightingPresetOption.SelectedId == GetConfigLightingQuality();
ApplyButton.Disabled = isVSyncSame && isFullscreenSame && isLightingQualitySame;
}
private bool ConfigIsFullscreen =>
_cfg.GetCVar<int>("display.windowmode") == (int) WindowMode.Fullscreen;
private int GetConfigLightingQuality()
{
var val = _cfg.GetCVar<int>("display.lightmapdivider");
var soft = _cfg.GetCVar<bool>("display.softshadows");
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("display.lightmapdivider", 8);
_cfg.SetCVar("display.softshadows", false);
break;
case 1:
_cfg.SetCVar("display.lightmapdivider", 2);
_cfg.SetCVar("display.softshadows", false);
break;
case 2:
_cfg.SetCVar("display.lightmapdivider", 2);
_cfg.SetCVar("display.softshadows", true);
break;
case 3:
_cfg.SetCVar("display.lightmapdivider", 1);
_cfg.SetCVar("display.softshadows", true);
break;
}
}
}
}
}

View File

@@ -0,0 +1,473 @@
#nullable enable
using System;
using System.Collections.Generic;
using Content.Client.UserInterface.Stylesheets;
using Content.Shared.Input;
using Robust.Client.Input;
using Robust.Client.Interfaces.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.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 HashSet<BoundKeyFunction>
{
EngineKeyFunctions.ShowDebugMonitors,
EngineKeyFunctions.HideUI,
};
[Dependency] private readonly IInputManager _inputManager = default!;
private BindButton? _currentlyRebinding;
private readonly Dictionary<BoundKeyFunction, KeyControl> _keyControls =
new Dictionary<BoundKeyFunction, KeyControl>();
private readonly List<Action> _deferCommands = new List<Action>();
public KeyRebindControl()
{
IoCManager.InjectDependencies(this);
Button resetAllButton;
var vBox = new VBoxContainer();
AddChild(new VBoxContainer
{
Children =
{
new ScrollContainer
{
SizeFlagsVertical = SizeFlags.FillExpand,
Children =
{
new MarginContainer
{
MarginLeftOverride = 2,
Children =
{
vBox
}
}
}
},
new StripeBack
{
HasBottomEdge = false,
HasMargins = false,
Children =
{
new HBoxContainer
{
Children =
{
new Control {CustomMinimumSize = (2, 0)},
new Label
{
StyleClasses = {StyleBase.StyleClassLabelSubText},
Text = "Click to change binding, right-click to clear"
},
(resetAllButton = new Button
{
Text = "Reset ALL keybinds",
StyleClasses = {StyleBase.ButtonCaution},
SizeFlagsHorizontal = SizeFlags.ShrinkEnd | SizeFlags.Expand
})
}
}
}
}
}
});
resetAllButton.OnPressed += args =>
{
_deferCommands.Add(() =>
{
_inputManager.ResetAllBindings();
_inputManager.SaveToUserData();
});
};
var first = true;
void AddHeader(string headerContents)
{
if (!first)
{
vBox.AddChild(new Control {CustomMinimumSize = (0, 8)});
}
first = false;
vBox.AddChild(new Label
{
Text = headerContents,
FontColorOverride = StyleNano.NanoGold,
StyleClasses = {StyleNano.StyleClassLabelKeyText}
});
}
void AddButton(BoundKeyFunction function, string name)
{
var control = new KeyControl(this, name, function);
vBox.AddChild(control);
_keyControls.Add(function, control);
}
AddHeader("Movement");
AddButton(EngineKeyFunctions.MoveUp, "Move up");
AddButton(EngineKeyFunctions.MoveLeft, "Move left");
AddButton(EngineKeyFunctions.MoveDown, "Move down");
AddButton(EngineKeyFunctions.MoveRight, "Move right");
AddButton(EngineKeyFunctions.Walk, "Walk");
AddHeader("Basic Interaction");
AddButton(EngineKeyFunctions.Use, "Use");
AddButton(ContentKeyFunctions.WideAttack, "Wide attack");
AddButton(ContentKeyFunctions.ActivateItemInHand, "Activate item in hand");
AddButton(ContentKeyFunctions.ActivateItemInWorld, "Activate item in world");
AddButton(ContentKeyFunctions.Drop, "Drop item");
AddButton(ContentKeyFunctions.ExamineEntity, "Examine");
AddButton(ContentKeyFunctions.SwapHands, "Swap hands");
AddButton(ContentKeyFunctions.ToggleCombatMode, "Toggle combat mode");
AddHeader("Advanced Interaction");
AddButton(ContentKeyFunctions.SmartEquipBackpack, "Smart-equip to backpack");
AddButton(ContentKeyFunctions.SmartEquipBelt, "Smart-equip to belt");
AddButton(ContentKeyFunctions.ThrowItemInHand, "Throw item");
AddButton(ContentKeyFunctions.TryPullObject, "Pull object");
AddButton(ContentKeyFunctions.MovePulledObject, "Move pulled object");
AddButton(ContentKeyFunctions.Point, "Point at location");
AddHeader("User Interface");
AddButton(ContentKeyFunctions.FocusChat, "Focus chat");
AddButton(ContentKeyFunctions.FocusOOC, "Focus chat (OOC)");
AddButton(ContentKeyFunctions.FocusAdminChat, "Focus chat (admin)");
AddButton(ContentKeyFunctions.OpenCharacterMenu, "Open character menu");
AddButton(ContentKeyFunctions.OpenContextMenu, "Open context menu");
AddButton(ContentKeyFunctions.OpenCraftingMenu, "Open crafting menu");
AddButton(ContentKeyFunctions.OpenInventoryMenu, "Open inventory");
AddButton(ContentKeyFunctions.OpenTutorial, "Open tutorial");
AddButton(ContentKeyFunctions.OpenEntitySpawnWindow, "Open entity spawn menu");
AddButton(ContentKeyFunctions.OpenSandboxWindow, "Open sandbox menu");
AddButton(ContentKeyFunctions.OpenTileSpawnWindow, "Open tile spawn menu");
AddButton(ContentKeyFunctions.OpenAdminMenu, "Open admin menu");
AddHeader("Miscellaneous");
AddButton(ContentKeyFunctions.TakeScreenshot, "Take screenshot");
AddButton(ContentKeyFunctions.TakeScreenshotNoUI, "Take screenshot (without UI)");
AddHeader("Map Editor");
AddButton(EngineKeyFunctions.EditorPlaceObject, "Place object");
AddButton(EngineKeyFunctions.EditorCancelPlace, "Cancel placement");
AddButton(EngineKeyFunctions.EditorGridPlace, "Place in grid");
AddButton(EngineKeyFunctions.EditorLinePlace, "Place line");
AddButton(EngineKeyFunctions.EditorRotateObject, "Rotate");
AddHeader("Development");
AddButton(EngineKeyFunctions.ShowDebugConsole, "Open Console");
AddButton(EngineKeyFunctions.ShowDebugMonitors, "Show Debug Monitors");
AddButton(EngineKeyFunctions.HideUI, "Hide UI");
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("Press a key...");
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, string niceName, BoundKeyFunction function)
{
Function = function;
var name = new Label
{
Text = Loc.GetString(niceName),
SizeFlagsHorizontal = SizeFlags.Expand
};
BindButton1 = new BindButton(parent, this, StyleBase.ButtonOpenRight);
BindButton2 = new BindButton(parent, this, StyleBase.ButtonOpenLeft);
ResetButton = new Button {Text = "Reset", StyleClasses = {StyleBase.ButtonCaution}};
var hBox = new HBoxContainer
{
Children =
{
new Control {CustomMinimumSize = (5, 0)},
name,
BindButton1,
BindButton2,
new Control {CustomMinimumSize = (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;
CustomMinimumSize = (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() ?? "Unbound";
}
}
}
}
}

View File

@@ -0,0 +1,45 @@
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Shared.Interfaces.Configuration;
using Robust.Shared.IoC;
using Robust.Shared.Localization;
using Robust.Shared.Maths;
#nullable enable
namespace Content.Client.UserInterface
{
public sealed partial class OptionsMenu : SS14Window
{
[Dependency] private readonly IConfigurationManager _configManager = default!;
protected override Vector2? CustomSize => (800, 450);
public OptionsMenu()
{
IoCManager.InjectDependencies(this);
Title = Loc.GetString("Game Options");
GraphicsControl graphicsControl;
KeyRebindControl rebindControl;
AudioControl audioControl;
var tabs = new TabContainer
{
Children =
{
(graphicsControl = new GraphicsControl(_configManager)),
(rebindControl = new KeyRebindControl()),
(audioControl = new AudioControl(_configManager)),
}
};
TabContainer.SetTabTitle(graphicsControl, Loc.GetString("Graphics"));
TabContainer.SetTabTitle(rebindControl, Loc.GetString("Controls"));
TabContainer.SetTabTitle(audioControl, Loc.GetString("Audio"));
Contents.AddChild(tabs);
}
}
}

View File

@@ -12,6 +12,7 @@ namespace Content.Client.UserInterface
private bool _hasTopEdge = true; private bool _hasTopEdge = true;
private bool _hasBottomEdge = true; private bool _hasBottomEdge = true;
private bool _hasMargins = true;
public const string StylePropertyBackground = "background"; public const string StylePropertyBackground = "background";
@@ -35,6 +36,16 @@ namespace Content.Client.UserInterface
} }
} }
public bool HasMargins
{
get => _hasMargins;
set
{
_hasMargins = value;
MinimumSizeChanged();
}
}
protected override Vector2 CalculateMinimumSize() protected override Vector2 CalculateMinimumSize()
{ {
var size = Vector2.Zero; var size = Vector2.Zero;
@@ -44,14 +55,16 @@ namespace Content.Client.UserInterface
size = Vector2.ComponentMax(size, child.CombinedMinimumSize); size = Vector2.ComponentMax(size, child.CombinedMinimumSize);
} }
var padSize = HasMargins ? PadSize : 0;
if (HasBottomEdge) if (HasBottomEdge)
{ {
size += (0, PadSize + EdgeSize); size += (0, padSize + EdgeSize);
} }
if (HasTopEdge) if (HasTopEdge)
{ {
size += (0, PadSize + EdgeSize); size += (0, padSize + EdgeSize);
} }
return size; return size;
@@ -61,14 +74,16 @@ namespace Content.Client.UserInterface
{ {
var box = SizeBox; var box = SizeBox;
var padSize = HasMargins ? PadSize : 0;
if (HasTopEdge) if (HasTopEdge)
{ {
box += (0, PadSize + EdgeSize, 0, 0); box += (0, padSize + EdgeSize, 0, 0);
} }
if (HasBottomEdge) if (HasBottomEdge)
{ {
box += (0, 0, 0, -(PadSize + EdgeSize)); box += (0, 0, 0, -(padSize + EdgeSize));
} }
foreach (var child in Children) foreach (var child in Children)
@@ -81,16 +96,18 @@ namespace Content.Client.UserInterface
{ {
UIBox2 centerBox = PixelSizeBox; UIBox2 centerBox = PixelSizeBox;
var padSize = HasMargins ? PadSize : 0;
if (HasTopEdge) if (HasTopEdge)
{ {
centerBox += (0, (PadSize + EdgeSize) * UIScale, 0, 0); centerBox += (0, (padSize + EdgeSize) * UIScale, 0, 0);
handle.DrawRect(new UIBox2(0, PadSize * UIScale, PixelWidth, centerBox.Top), EdgeColor); handle.DrawRect(new UIBox2(0, padSize * UIScale, PixelWidth, centerBox.Top), EdgeColor);
} }
if (HasBottomEdge) if (HasBottomEdge)
{ {
centerBox += (0, 0, 0, -((PadSize + EdgeSize) * UIScale)); centerBox += (0, 0, 0, -((padSize + EdgeSize) * UIScale));
handle.DrawRect(new UIBox2(0, centerBox.Bottom, PixelWidth, PixelHeight - PadSize * UIScale), EdgeColor); handle.DrawRect(new UIBox2(0, centerBox.Bottom, PixelWidth, PixelHeight - padSize * UIScale), EdgeColor);
} }
GetActualStyleBox()?.Draw(handle, centerBox); GetActualStyleBox()?.Draw(handle, centerBox);

View File

@@ -17,6 +17,8 @@ namespace Content.Client.UserInterface.Stylesheets
public const string ButtonOpenLeft = "OpenLeft"; public const string ButtonOpenLeft = "OpenLeft";
public const string ButtonOpenBoth = "OpenBoth"; public const string ButtonOpenBoth = "OpenBoth";
public const string ButtonCaution = "Caution";
public abstract Stylesheet Stylesheet { get; } public abstract Stylesheet Stylesheet { get; }
protected StyleRule[] BaseRules { get; } protected StyleRule[] BaseRules { get; }

View File

@@ -31,6 +31,11 @@ namespace Content.Client.UserInterface.Stylesheets
public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45"); public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45");
public static readonly Color ButtonColorDisabled = Color.FromHex("#30313c"); 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");
//Used by the APC and SMES menus //Used by the APC and SMES menus
public const string StyleClassPowerStateNone = "PowerStateNone"; public const string StyleClassPowerStateNone = "PowerStateNone";
public const string StyleClassPowerStateLow = "PowerStateLow"; public const string StyleClassPowerStateLow = "PowerStateLow";
@@ -70,30 +75,6 @@ namespace Content.Client.UserInterface.Stylesheets
var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png"); var textureInvertedTriangle = resCache.GetTexture("/Textures/Interface/Nano/inverted_triangle.svg.png");
static (StyleBox, StyleBox, StyleBox, StyleBox) ButtonPermutations(StyleBoxTexture @base)
{
var normal = new StyleBoxTexture(@base) {Modulate = ButtonColorDefault};
var hover = new StyleBoxTexture(@base) {Modulate = ButtonColorHovered};
var pressed = new StyleBoxTexture(@base) {Modulate = ButtonColorPressed};
var disabled = new StyleBoxTexture(@base) {Modulate = ButtonColorDisabled};
return (normal, hover, pressed, disabled);
}
// Button styles.
var (buttonNormal, buttonHover, buttonPressed, buttonDisabled)
= ButtonPermutations(BaseButton);
var (buttonRNormal, buttonRHover, buttonRPressed, buttonRDisabled)
= ButtonPermutations(BaseButtonOpenRight);
var (buttonLNormal, buttonLHover, buttonLPressed, buttonLDisabled)
= ButtonPermutations(BaseButtonOpenLeft);
var (buttonBNormal, buttonBHover, buttonBPressed, buttonBDisabled)
= ButtonPermutations(BaseButtonOpenBoth);
var lineEditTex = resCache.GetTexture("/Textures/Interface/Nano/lineedit.png"); var lineEditTex = resCache.GetTexture("/Textures/Interface/Nano/lineedit.png");
var lineEdit = new StyleBoxTexture var lineEdit = new StyleBoxTexture
{ {
@@ -297,80 +278,60 @@ namespace Content.Client.UserInterface.Stylesheets
new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#753131")), new StyleProperty(Control.StylePropertyModulateSelf, Color.FromHex("#753131")),
}), }),
// Regular buttons! // Shapes for the buttons.
new StyleRule(new SelectorElement(typeof(ContainerButton), new[] { ContainerButton.StyleClassButton }, null, new[] {ContainerButton.StylePseudoClassNormal}), new[] Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
{ .Prop(ContainerButton.StylePropertyStyleBox, BaseButton),
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonNormal),
}), Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
new StyleRule(new SelectorElement(typeof(ContainerButton), new[] { ContainerButton.StyleClassButton }, null, new[] {ContainerButton.StylePseudoClassHover}), new[] .Class(ButtonOpenRight)
{ .Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenRight),
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonHover),
}), Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
new StyleRule(new SelectorElement(typeof(ContainerButton), new[] { ContainerButton.StyleClassButton }, null, new[] {ContainerButton.StylePseudoClassPressed}), new[] .Class(ButtonOpenLeft)
{ .Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenLeft),
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonPressed),
}), Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
new StyleRule(new SelectorElement(typeof(ContainerButton), new[] { ContainerButton.StyleClassButton }, null, new[] {ContainerButton.StylePseudoClassDisabled}), new[] .Class(ButtonOpenBoth)
{ .Prop(ContainerButton.StylePropertyStyleBox, BaseButtonOpenBoth),
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonDisabled),
}),
new StyleRule(new SelectorElement(typeof(Label), new[] { Button.StyleClassButton }, null, null), new[] new StyleRule(new SelectorElement(typeof(Label), new[] { Button.StyleClassButton }, null, null), new[]
{ {
new StyleProperty(Label.StylePropertyAlignMode, Label.AlignMode.Center), new StyleProperty(Label.StylePropertyAlignMode, Label.AlignMode.Center),
}), }),
// Right open buttons. // Colors for the buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassNormal) .Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRNormal), .Prop(Control.StylePropertyModulateSelf, ButtonColorDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassHover) .Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRHover), .Prop(Control.StylePropertyModulateSelf, ButtonColorHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassPressed) .Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRPressed), .Prop(Control.StylePropertyModulateSelf, ButtonColorPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassDisabled) .Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRDisabled), .Prop(Control.StylePropertyModulateSelf, ButtonColorDisabled),
// Left open buttons. // Colors for the caution buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassNormal) .Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLNormal), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassHover) .Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLHover), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassPressed) .Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLPressed), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassDisabled) .Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLDisabled), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDisabled),
// "Both" open buttons
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBNormal),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBHover),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBDisabled),
new StyleRule(new SelectorChild( new StyleRule(new SelectorChild(
new SelectorElement(typeof(Button), null, null, new[] {ContainerButton.StylePseudoClassDisabled}), new SelectorElement(typeof(Button), null, null, new[] {ContainerButton.StylePseudoClassDisabled}),
@@ -649,25 +610,28 @@ namespace Content.Client.UserInterface.Stylesheets
}), }),
// Those top menu buttons. // Those top menu buttons.
Element<GameHud.TopButton>()
.Prop(Button.StylePropertyStyleBox, BaseButton),
new StyleRule( new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassNormal}), new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassNormal}),
new[] new[]
{ {
new StyleProperty(Button.StylePropertyStyleBox, buttonNormal), new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorDefault),
}), }),
new StyleRule( new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassPressed}), new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassPressed}),
new[] new[]
{ {
new StyleProperty(Button.StylePropertyStyleBox, buttonPressed), new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorPressed),
}), }),
new StyleRule( new StyleRule(
new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassHover}), new SelectorElement(typeof(GameHud.TopButton), null, null, new[] {Button.StylePseudoClassHover}),
new[] new[]
{ {
new StyleProperty(Button.StylePropertyStyleBox, buttonHover), new StyleProperty(Button.StylePropertyModulateSelf, ButtonColorHovered),
}), }),
new StyleRule( new StyleRule(
@@ -758,21 +722,25 @@ namespace Content.Client.UserInterface.Stylesheets
}), }),
// OptionButton // OptionButton
new StyleRule(new SelectorElement(typeof(OptionButton), null, null, null), new[]
{
new StyleProperty(ContainerButton.StylePropertyStyleBox, BaseButton),
}),
new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassNormal}), new[] new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassNormal}), new[]
{ {
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonNormal), new StyleProperty(Control.StylePropertyModulateSelf, ButtonColorDefault),
}), }),
new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassHover}), new[] new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassHover}), new[]
{ {
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonHover), new StyleProperty(Control.StylePropertyModulateSelf, ButtonColorHovered),
}), }),
new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassPressed}), new[] new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassPressed}), new[]
{ {
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonPressed), new StyleProperty(Control.StylePropertyModulateSelf, ButtonColorPressed),
}), }),
new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassDisabled}), new[] new StyleRule(new SelectorElement(typeof(OptionButton), null, null, new[] {ContainerButton.StylePseudoClassDisabled}), new[]
{ {
new StyleProperty(ContainerButton.StylePropertyStyleBox, buttonDisabled), new StyleProperty(Control.StylePropertyModulateSelf, ButtonColorDisabled),
}), }),
new StyleRule(new SelectorElement(typeof(TextureRect), new[] {OptionButton.StyleClassOptionTriangle}, null, null), new[] new StyleRule(new SelectorElement(typeof(TextureRect), new[] {OptionButton.StyleClassOptionTriangle}, null, null), new[]

View File

@@ -18,6 +18,11 @@ namespace Content.Client.UserInterface.Stylesheets
public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45"); public static readonly Color ButtonColorPressed = Color.FromHex("#3e6c45");
public static readonly Color ButtonColorDisabled = Color.FromHex("#30313c"); 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 override Stylesheet Stylesheet { get; }
public StyleSpace(IResourceCache resCache) : base(resCache) public StyleSpace(IResourceCache resCache) : base(resCache)
@@ -25,29 +30,6 @@ namespace Content.Client.UserInterface.Stylesheets
var notoSans10 = resCache.GetFont("/Textures/Interface/Nano/NotoSans/NotoSans-Regular.ttf", 10); var notoSans10 = resCache.GetFont("/Textures/Interface/Nano/NotoSans/NotoSans-Regular.ttf", 10);
var notoSansBold16 = resCache.GetFont("/Textures/Interface/Nano/NotoSans/NotoSans-Bold.ttf", 16); var notoSansBold16 = resCache.GetFont("/Textures/Interface/Nano/NotoSans/NotoSans-Bold.ttf", 16);
static (StyleBox, StyleBox, StyleBox, StyleBox) ButtonPermutations(StyleBoxTexture @base)
{
var normal = new StyleBoxTexture(@base) {Modulate = ButtonColorDefault};
var hover = new StyleBoxTexture(@base) {Modulate = ButtonColorHovered};
var pressed = new StyleBoxTexture(@base) {Modulate = ButtonColorPressed};
var disabled = new StyleBoxTexture(@base) {Modulate = ButtonColorDisabled};
return (normal, hover, pressed, disabled);
}
// Button styles.
var (buttonNormal, buttonHover, buttonPressed, buttonDisabled)
= ButtonPermutations(BaseButton);
var (buttonRNormal, buttonRHover, buttonRPressed, buttonRDisabled)
= ButtonPermutations(BaseButtonOpenRight);
var (buttonLNormal, buttonLHover, buttonLPressed, buttonLDisabled)
= ButtonPermutations(BaseButtonOpenLeft);
var (buttonBNormal, buttonBHover, buttonBPressed, buttonBDisabled)
= ButtonPermutations(BaseButtonOpenBoth);
Stylesheet = new Stylesheet(BaseRules.Concat(new StyleRule[] Stylesheet = new Stylesheet(BaseRules.Concat(new StyleRule[]
{ {
Element<Label>().Class(StyleClassLabelHeading) Element<Label>().Class(StyleClassLabelHeading)
@@ -63,74 +45,55 @@ namespace Content.Client.UserInterface.Stylesheets
{ {
BackgroundColor = SpaceRed, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2 BackgroundColor = SpaceRed, ContentMarginBottomOverride = 2, ContentMarginLeftOverride = 2
}), }),
// Shapes for the buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Prop(ContainerButton.StylePropertyStyleBox, BaseButton),
// Normal buttons. 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),
// Colors for the buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassNormal) .Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonNormal), .Prop(Control.StylePropertyModulateSelf, ButtonColorDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassHover) .Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonHover), .Prop(Control.StylePropertyModulateSelf, ButtonColorHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassPressed) .Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonPressed), .Prop(Control.StylePropertyModulateSelf, ButtonColorPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton) Element<ContainerButton>().Class(ContainerButton.StyleClassButton)
.Pseudo(ContainerButton.StylePseudoClassDisabled) .Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonDisabled), .Prop(Control.StylePropertyModulateSelf, ButtonColorDisabled),
// Right open buttons. // Colors for the caution buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassNormal) .Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRNormal), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDefault),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassHover) .Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRHover), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionHovered),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassPressed) .Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRPressed), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenRight) Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonCaution)
.Pseudo(ContainerButton.StylePseudoClassDisabled) .Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonRDisabled), .Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDisabled),
// Left open buttons.
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLNormal),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLHover),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenLeft)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonLDisabled),
// "Both" open buttons
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBNormal),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBHover),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBPressed),
Element<ContainerButton>().Class(ContainerButton.StyleClassButton).Class(ButtonOpenBoth)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(ContainerButton.StylePropertyStyleBox, buttonBDisabled),
Element<Label>().Class(ContainerButton.StyleClassButton) Element<Label>().Class(ContainerButton.StyleClassButton)

View File

@@ -58,6 +58,10 @@ namespace Content.IntegrationTests
{ {
} }
public void ToggleDisallowLateJoin(bool disallowLateJoin)
{
}
public EntityCoordinates GetLateJoinSpawnPoint() => EntityCoordinates.Invalid; public EntityCoordinates GetLateJoinSpawnPoint() => EntityCoordinates.Invalid;
public EntityCoordinates GetJobSpawnPoint(string jobId) => EntityCoordinates.Invalid; public EntityCoordinates GetJobSpawnPoint(string jobId) => EntityCoordinates.Invalid;
public EntityCoordinates GetObserverSpawnPoint() => EntityCoordinates.Invalid; public EntityCoordinates GetObserverSpawnPoint() => EntityCoordinates.Invalid;

View File

@@ -41,7 +41,7 @@ namespace Content.Server.GameObjects.Components.Interactable
var coordinates = mapGrid.GridTileToLocal(tile.GridIndices); var coordinates = mapGrid.GridTileToLocal(tile.GridIndices);
if (!user.InRangeUnobstructed(coordinates, popup: true)) if (!user.InRangeUnobstructed(coordinates, popup: false))
return; return;
var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId]; var tileDef = (ContentTileDefinition)_tileDefinitionManager[tile.Tile.TypeId];

View File

@@ -1,5 +1,4 @@
 using Robust.Shared.GameObjects;
using Robust.Shared.GameObjects;
using Content.Shared.GameObjects.Components; using Content.Shared.GameObjects.Components;
namespace Content.Server.GameObjects.Components namespace Content.Server.GameObjects.Components

View File

@@ -159,7 +159,6 @@ namespace Content.Server.GameTicking.GamePresets
return true; return true;
} }
public override string ModeTitle => "Suspicion"; public override string ModeTitle => "Suspicion";
public override string Description => "Suspicion on the Space Station. There are traitors on board... Can you kill them before they kill you?"; public override string Description => "Suspicion on the Space Station. There are traitors on board... Can you kill them before they kill you?";
} }

View File

@@ -411,6 +411,12 @@ namespace Content.Server.GameTicking
_netManager.ServerSendToAll(GetStatusSingle(player, status)); _netManager.ServerSendToAll(GetStatusSingle(player, status));
} }
public void ToggleDisallowLateJoin(bool disallowLateJoin)
{
DisallowLateJoin = disallowLateJoin;
UpdateLateJoinStatus();
}
public T AddGameRule<T>() where T : GameRule, new() public T AddGameRule<T>() where T : GameRule, new()
{ {
var instance = _dynamicTypeFactory.CreateInstance<T>(); var instance = _dynamicTypeFactory.CreateInstance<T>();

View File

@@ -244,6 +244,26 @@ namespace Content.Server.GameTicking
} }
} }
class ToggleDisallowLateJoinCommand: IClientCommand
{
public string Command => "toggledisallowlatejoin";
public string Description => "Allows or disallows latejoining during mid-game.";
public string Help => $"Usage: {Command} <disallow>";
public void Execute(IConsoleShell shell, IPlayerSession player, string[] args)
{
if (args.Length != 1)
{
shell.SendText(player, "Need exactly one argument.");
return;
}
var ticker = IoCManager.Resolve<IGameTicker>();
ticker.ToggleDisallowLateJoin(bool.Parse(args[0]));
}
}
class SetGamePresetCommand : IClientCommand class SetGamePresetCommand : IClientCommand
{ {
public string Command => "setgamepreset"; public string Command => "setgamepreset";

View File

@@ -30,6 +30,7 @@ namespace Content.Server.Interfaces.GameTicking
void MakeObserve(IPlayerSession player); void MakeObserve(IPlayerSession player);
void MakeJoinGame(IPlayerSession player, string jobId); void MakeJoinGame(IPlayerSession player, string jobId);
void ToggleReady(IPlayerSession player, bool ready); void ToggleReady(IPlayerSession player, bool ready);
void ToggleDisallowLateJoin(bool disallowLateJoin);
EntityCoordinates GetLateJoinSpawnPoint(); EntityCoordinates GetLateJoinSpawnPoint();
EntityCoordinates GetJobSpawnPoint(string jobId); EntityCoordinates GetJobSpawnPoint(string jobId);

View File

@@ -185,22 +185,6 @@
highPressureMultiplier: 0.45 highPressureMultiplier: 0.45
lowPressureMultiplier: 100 lowPressureMultiplier: 100
- type: entity
parent: HardsuitBase
id: Spacesuit
name: spacesuit
description: A basic space suit.
components:
- type: Sprite
sprite: Clothing/OuterClothing/space.rsi
- type: Icon
sprite: Clothing/OuterClothing/space.rsi
- type: Clothing
sprite: Clothing/OuterClothing/space.rsi
- type: PressureProtection
highPressureMultiplier: 1
lowPressureMultiplier: 100
# I don't know what the hell "td" is but whatever i'll dump it here. # I don't know what the hell "td" is but whatever i'll dump it here.
- type: entity - type: entity
parent: HardsuitBase parent: HardsuitBase

View File

@@ -1,7 +1,7 @@
- type: entity - type: entity
id: LockerQuarterMaster id: LockerQuarterMaster
parent: LockerSecureBase parent: LockerSecureBase
name: "quatermaster's locker" name: "quartermaster's locker"
components: components:
- type: Appearance - type: Appearance
visuals: visuals:

View File

@@ -0,0 +1,2 @@
sample:
filter: true

View File

@@ -1,19 +1,24 @@
version: 1 # Not used right now, whatever. version: 1 # Not used right now, whatever.
binds: binds:
- function: UIClick - function: UIClick
type: state type: State
key: MouseLeft key: MouseLeft
canFocus: true canFocus: true
- function: UIRightClick
type: State
key: MouseRight
canFocus: true
priority: 10
- function: CloseModals - function: CloseModals
type: state type: State
key: Escape key: Escape
priority: 10 priority: 10
- function: Use - function: Use
type: state type: State
key: MouseLeft key: MouseLeft
canFocus: true canFocus: true
- function: WideAttack - function: WideAttack
type: state type: State
key: Space key: Space
- function: ShowDebugMonitors - function: ShowDebugMonitors
type: Toggle type: Toggle
@@ -86,7 +91,7 @@ binds:
# TextCursorSelect HAS to be above ExamineEntity # TextCursorSelect HAS to be above ExamineEntity
# So that LineEdit receives it correctly. # So that LineEdit receives it correctly.
# TODO: Make it so that UI keybinds are somehow prioritized so this ordering stuff isn't necessary. # TODO: Make it so that UI keybinds are somehow prioritized so this ordering stuff isn't necessary.
type: state type: State
key: MouseLeft key: MouseLeft
mod1: Shift mod1: Shift
canFocus: true canFocus: true
@@ -96,37 +101,37 @@ binds:
canFocus: true canFocus: true
mod1: Shift mod1: Shift
- function: ActivateItemInWorld - function: ActivateItemInWorld
type: state type: State
key: E key: E
- function: ThrowItemInHand - function: ThrowItemInHand
type: state type: State
key: MouseLeft key: MouseLeft
canFocus: true canFocus: true
mod1: Alt mod1: Alt
- function: TryPullObject - function: TryPullObject
type: state type: State
canFocus: true canFocus: true
key: MouseLeft key: MouseLeft
mod1: Control mod1: Control
- function: MovePulledObject - function: MovePulledObject
type: state type: State
key: MouseRight key: MouseRight
mod1: Control mod1: Control
- function: OpenContextMenu - function: OpenContextMenu
type: state type: State
key: MouseRight key: MouseRight
canFocus: true canFocus: true
- function: ToggleCombatMode - function: ToggleCombatMode
type: State type: State
key: R key: R
- function: OpenCraftingMenu - function: OpenCraftingMenu
type: state type: State
key: G key: G
- function: OpenTutorial - function: OpenTutorial
type: state type: State
key: F1 key: F1
- function: OpenInventoryMenu - function: OpenInventoryMenu
type: state type: State
key: I key: I
- function: SmartEquipBackpack - function: SmartEquipBackpack
type: State type: State
@@ -137,135 +142,135 @@ binds:
key: E key: E
mod1: Shift mod1: Shift
- function: ShowDebugConsole - function: ShowDebugConsole
type: state type: State
key: Tilde key: Tilde
- function: MouseMiddle - function: MouseMiddle
type: state type: State
key: MouseMiddle key: MouseMiddle
canFocus: true canFocus: true
- function: TextCursorLeft - function: TextCursorLeft
type: state type: State
key: Left key: Left
canRepeat: true canRepeat: true
- function: TextCursorRight - function: TextCursorRight
type: state type: State
key: Right key: Right
canRepeat: true canRepeat: true
- function: TextCursorWordLeft - function: TextCursorWordLeft
type: state type: State
key: Left key: Left
mod1: Control mod1: Control
canRepeat: true canRepeat: true
- function: TextCursorWordRight - function: TextCursorWordRight
type: state type: State
key: Right key: Right
mod1: Control mod1: Control
canRepeat: true canRepeat: true
- function: TextCursorBegin - function: TextCursorBegin
type: state type: State
key: Home key: Home
- function: TextCursorEnd - function: TextCursorEnd
type: state type: State
key: End key: End
canRepeat: true canRepeat: true
- function: TextCursorSelectLeft - function: TextCursorSelectLeft
type: state type: State
key: Left key: Left
mod1: Shift mod1: Shift
canRepeat: true canRepeat: true
- function: TextCursorSelectRight - function: TextCursorSelectRight
type: state type: State
key: Right key: Right
mod1: Shift mod1: Shift
canRepeat: true canRepeat: true
- function: TextCursorSelectWordLeft - function: TextCursorSelectWordLeft
type: state type: State
key: Left key: Left
mod1: Shift mod1: Shift
mod2: Control mod2: Control
canRepeat: true canRepeat: true
- function: TextCursorSelectWordRight - function: TextCursorSelectWordRight
type: state type: State
key: Right key: Right
mod1: Shift mod1: Shift
mod2: Control mod2: Control
canRepeat: true canRepeat: true
- function: TextCursorSelectBegin - function: TextCursorSelectBegin
type: state type: State
mod1: Shift mod1: Shift
key: Home key: Home
- function: TextCursorSelectEnd - function: TextCursorSelectEnd
type: state type: State
mod1: Shift mod1: Shift
key: End key: End
canRepeat: true canRepeat: true
- function: TextBackspace - function: TextBackspace
type: state type: State
key: BackSpace key: BackSpace
canRepeat: true canRepeat: true
- function: TextSubmit - function: TextSubmit
type: state type: State
key: Return key: Return
- function: TextSubmit - function: TextSubmit
type: state type: State
key: NumpadEnter key: NumpadEnter
- function: TextSelectAll - function: TextSelectAll
type: state type: State
key: A key: A
mod1: Control mod1: Control
- function: TextCopy - function: TextCopy
type: state type: State
key: C key: C
mod1: Control mod1: Control
- function: TextCut - function: TextCut
type: state type: State
key: X key: X
mod1: Control mod1: Control
- function: TextPaste - function: TextPaste
type: state type: State
key: V key: V
mod1: Control mod1: Control
- function: TextHistoryPrev - function: TextHistoryPrev
type: state type: State
key: Up key: Up
- function: TextHistoryNext - function: TextHistoryNext
type: state type: State
key: Down key: Down
- function: TextReleaseFocus - function: TextReleaseFocus
type: state type: State
key: Escape key: Escape
priority: 15 priority: 15
- function: TextScrollToBottom - function: TextScrollToBottom
type: state type: State
key: PageDown key: PageDown
- function: TextDelete - function: TextDelete
type: state type: State
key: Delete key: Delete
canRepeat: true canRepeat: true
- function: OpenEntitySpawnWindow - function: OpenEntitySpawnWindow
type: state type: State
key: F5 key: F5
- function: OpenTileSpawnWindow - function: OpenTileSpawnWindow
type: state type: State
key: F6 key: F6
- function: OpenAdminMenu - function: OpenAdminMenu
type: state type: State
key: F7 key: F7
- function: OpenSandboxWindow - function: OpenSandboxWindow
type: state type: State
key: B key: B
- function: TakeScreenshot - function: TakeScreenshot
type: state type: State
key: F2 key: F2
- function: TakeScreenshotNoUI - function: TakeScreenshotNoUI
type: state type: State
key: F2 key: F2
mod1: Shift mod1: Shift
- function: GuiTabNavigateNext - function: GuiTabNavigateNext
type: state type: State
key: Tab key: Tab
- function: GuiTabNavigatePrev - function: GuiTabNavigatePrev
type: state type: State
key: Tab key: Tab
mod1: Shift mod1: Shift
- function: Point - function: Point

View File

@@ -77,6 +77,8 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=Fluidsynth/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Fluidsynth/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=freepats/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=hardcode/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybind/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=keybinds/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibyte/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibyte/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibytes/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Kibibytes/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Lerp/@EntryIndexedValue">True</s:Boolean> <s:Boolean x:Key="/Default/UserDictionary/Words/=Lerp/@EntryIndexedValue">True</s:Boolean>