Files
RobustToolbox/Robust.Shared/Input/InputContextContainer.cs
2020-11-26 00:16:55 +01:00

213 lines
7.9 KiB
C#

using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
namespace Robust.Shared.Input
{
/// <summary>
/// Contains a set of created <see cref="InputCmdContext"/>s.
/// </summary>
public interface IInputContextContainer
{
/// <summary>
/// The current "active" context that should be used for filtering key binds.
/// </summary>
IInputCmdContext ActiveContext { get; }
/// <summary>
/// This event is raised when ever the Active Context is changed.
/// </summary>
event EventHandler<ContextChangedEventArgs> ContextChanged;
/// <summary>
/// Adds a new unique context to the set.
/// </summary>
/// <param name="uniqueName">Unique name of the new context.</param>
/// <param name="parentName">Unique name of the parent context. Tee parent context must already exist in the set.</param>
/// <returns>Instance of the newly created context.</returns>
IInputCmdContext New(string uniqueName, string parentName);
/// <summary>
/// Adds a new unique context to the set.
/// </summary>
/// <param name="uniqueName">Unique name of the new context.</param>
/// <param name="parent">Context to set, as the parent context, of the newly created context.</param>
/// <returns>Instance of the newly created context.</returns>
IInputCmdContext New(string uniqueName, IInputCmdContext parent);
/// <summary>
/// Checks if a context with a unique name exists in the set.
/// </summary>
/// <param name="uniqueName">Unique Name to search for.</param>
/// <returns>If a context exists with the given unique name in the set.</returns>
bool Exists(string uniqueName);
/// <summary>
/// Returns the context with the given unique name from the set.
/// </summary>
/// <param name="uniqueName">Unique name of the context to search for.</param>
/// <returns>Context with the given unique name in the set.</returns>
IInputCmdContext GetContext(string uniqueName);
/// <summary>
/// Tries to find a context with a given unique name.
/// </summary>
/// <param name="uniqueName">Unique name of the context to search for.</param>
/// <param name="context">The context with the given unique name (if any).</param>
/// <returns>If a context with a given unique name exists in the set.</returns>
bool TryGetContext(string uniqueName, [NotNullWhen(true)] out IInputCmdContext? context);
/// <summary>
/// Removes the context with the given unique name.
/// </summary>
/// <param name="uniqueName">Unique name of context to remove.</param>
void Remove(string uniqueName);
/// <summary>
/// Sets the context with the given unique name as the Active context.
/// </summary>
/// <param name="uniqueName">Unique name of the context to set as active.</param>
void SetActiveContext(string uniqueName);
}
/// <inheritdoc />
internal class InputContextContainer : IInputContextContainer
{
/// <summary>
/// Default 'root' context unique name that always exists in the set.
/// </summary>
public const string DefaultContextName = "common";
/// <inheritdoc />
public event EventHandler<ContextChangedEventArgs>? ContextChanged;
private readonly Dictionary<string, InputCmdContext> _contexts = new();
private InputCmdContext _activeContext = default!;
/// <inheritdoc />
public IInputCmdContext ActiveContext
{
get => _activeContext;
private set
{
var args = new ContextChangedEventArgs(_activeContext, value);
_activeContext = (InputCmdContext) value;
ContextChanged?.Invoke(this, args);
}
}
/// <summary>
/// Creates a new instance of <see cref="InputCmdContext"/>.
/// </summary>
public InputContextContainer()
{
_contexts.Add(DefaultContextName, new InputCmdContext());
SetActiveContext(DefaultContextName);
}
/// <inheritdoc />
public IInputCmdContext New(string uniqueName, string parentName)
{
if (string.IsNullOrWhiteSpace(uniqueName))
throw new ArgumentException("String is null or whitespace.", nameof(uniqueName));
if (string.IsNullOrWhiteSpace(parentName))
throw new ArgumentException("String is null or whitespace.", nameof(parentName));
if (!_contexts.TryGetValue(parentName, out var parentContext))
throw new ArgumentException("Parent does not exist.", nameof(parentName));
if (_contexts.ContainsKey(uniqueName))
throw new ArgumentException($"Context with name {uniqueName} already exists.", nameof(uniqueName));
var newContext = new InputCmdContext(parentContext);
_contexts.Add(uniqueName, newContext);
return newContext;
}
/// <inheritdoc />
public IInputCmdContext New(string uniqueName, IInputCmdContext parent)
{
if (string.IsNullOrWhiteSpace(uniqueName))
throw new ArgumentException("String is null or whitespace.", nameof(uniqueName));
if (_contexts.ContainsKey(uniqueName))
throw new ArgumentException($"Context with name {uniqueName} already exists.", nameof(uniqueName));
if (parent == null)
throw new ArgumentNullException(nameof(parent));
var newContext = new InputCmdContext(parent);
_contexts.Add(uniqueName, newContext);
return newContext;
}
/// <inheritdoc />
public bool Exists(string uniqueName)
{
return _contexts.ContainsKey(uniqueName);
}
/// <inheritdoc />
public IInputCmdContext GetContext(string uniqueName)
{
return _contexts[uniqueName];
}
/// <inheritdoc />
public bool TryGetContext(string uniqueName, [NotNullWhen(true)] out IInputCmdContext? context)
{
if (_contexts.TryGetValue(uniqueName, out var ctext))
{
context = ctext;
return true;
}
context = default;
return false;
}
/// <inheritdoc />
public void Remove(string uniqueName)
{
if (uniqueName == DefaultContextName)
throw new ArgumentException("The default context cannot be removed.", nameof(uniqueName));
_contexts.Remove(uniqueName);
}
/// <inheritdoc />
public void SetActiveContext(string uniqueName)
{
ActiveContext = _contexts[uniqueName];
}
}
/// <summary>
/// Event arguments for an input context change.
/// </summary>
public class ContextChangedEventArgs : EventArgs
{
/// <summary>
/// The new context that became active.
/// </summary>
public IInputCmdContext? NewContext { get; }
/// <summary>
/// The old context that used to be active.
/// </summary>
public IInputCmdContext? OldContext { get; }
/// <summary>
/// Constructs a new instance of <see cref="ContextChangedEventArgs"/>/
/// </summary>
/// <param name="oldContext">The old context that used to be active.</param>
/// <param name="newContext">The new context that became active.</param>
public ContextChangedEventArgs(IInputCmdContext? oldContext, IInputCmdContext? newContext)
{
OldContext = oldContext;
NewContext = newContext;
}
}
}