Hud refactor (#7202)

Co-authored-by: DrSmugleaf <DrSmugleaf@users.noreply.github.com>
Co-authored-by: Jezithyr <jmaster9999@gmail.com>
Co-authored-by: Jezithyr <Jezithyr@gmail.com>
Co-authored-by: Visne <39844191+Visne@users.noreply.github.com>
Co-authored-by: wrexbe <wrexbe@protonmail.com>
Co-authored-by: wrexbe <81056464+wrexbe@users.noreply.github.com>
This commit is contained in:
Jezithyr
2022-10-12 01:16:23 -07:00
committed by GitHub
parent d09fbc1849
commit 571dd4e6d5
168 changed files with 6940 additions and 7817 deletions

View File

@@ -1,31 +0,0 @@
using System;
using Content.Client.Items.UI;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
namespace Content.Client.Items.Managers
{
public interface IItemSlotManager
{
bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid? item);
void UpdateCooldown(ItemSlotButton? cooldownTexture, EntityUid? entity);
bool SetItemSlot(ItemSlotButton button, EntityUid? entity);
void HoverInSlot(ItemSlotButton button, EntityUid? entity, bool fits);
event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
bool IsHighlighted(EntityUid? uid);
/// <summary>
/// Highlight all slot controls that contain the specified entity.
/// </summary>
/// <param name="uid">The UID of the entity to highlight.</param>
/// <seealso cref="UnHighlightEntity"/>
void HighlightEntity(EntityUid uid);
/// <summary>
/// Remove highlighting for the specified entity.
/// </summary>
/// <param name="uid">The UID of the entity to unhighlight.</param>
/// <seealso cref="HighlightEntity"/>
void UnHighlightEntity(EntityUid uid);
}
}

View File

@@ -1,179 +0,0 @@
using System;
using System.Collections.Generic;
using Content.Client.Examine;
using Content.Client.Items.UI;
using Content.Client.Storage;
using Content.Client.Verbs;
using Content.Shared.Cooldown;
using Content.Shared.Hands.Components;
using Content.Shared.Input;
using Content.Shared.Interaction;
using Robust.Client.GameObjects;
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.Items.Managers
{
public sealed class ItemSlotManager : IItemSlotManager
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IEntitySystemManager _entitySystemManager = default!;
[Dependency] private readonly IEntityManager _entityManager = default!;
private readonly HashSet<EntityUid> _highlightEntities = new();
public event Action<EntitySlotHighlightedEventArgs>? EntityHighlightedUpdated;
public bool SetItemSlot(ItemSlotButton button, EntityUid? entity)
{
if (entity == null)
{
button.SpriteView.Sprite = null;
button.StorageButton.Visible = false;
}
else
{
ISpriteComponent? sprite;
if (_entityManager.TryGetComponent(entity, out HandVirtualItemComponent? virtPull)
&& _entityManager.TryGetComponent(virtPull.BlockingEntity, out ISpriteComponent? pulledSprite))
{
sprite = pulledSprite;
}
else if (!_entityManager.TryGetComponent(entity, out sprite))
{
return false;
}
button.ClearHover();
button.SpriteView.Sprite = sprite;
button.StorageButton.Visible = _entityManager.HasComponent<ClientStorageComponent>(entity);
}
button.Entity = entity ?? default;
// im lazy
button.UpdateSlotHighlighted();
return true;
}
public bool OnButtonPressed(GUIBoundKeyEventArgs args, EntityUid? item)
{
if (item == null)
return false;
if (args.Function == ContentKeyFunctions.ExamineEntity)
{
_entitySystemManager.GetEntitySystem<ExamineSystem>()
.DoExamine(item.Value);
}
else if (args.Function == EngineKeyFunctions.UseSecondary)
{
_entitySystemManager.GetEntitySystem<VerbSystem>().VerbMenu.OpenVerbMenu(item.Value);
}
else if (args.Function == ContentKeyFunctions.ActivateItemInWorld)
{
_entityManager.EntityNetManager?.SendSystemNetworkMessage(new InteractInventorySlotEvent(item.Value, altInteract: false));
}
else if (args.Function == ContentKeyFunctions.AltActivateItemInWorld)
{
_entityManager.RaisePredictiveEvent(new InteractInventorySlotEvent(item.Value, altInteract: true));
}
else
{
return false;
}
args.Handle();
return true;
}
public void UpdateCooldown(ItemSlotButton? button, EntityUid? entity)
{
var cooldownDisplay = button?.CooldownDisplay;
if (cooldownDisplay == null)
{
return;
}
if (entity == null || _entityManager.Deleted(entity) ||
!_entityManager.TryGetComponent(entity, 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, EntityUid? entity, bool fits)
{
if (entity == null || !button.MouseIsHovering)
{
button.ClearHover();
return;
}
if (!_entityManager.HasComponent<SpriteComponent>(entity))
{
return;
}
// Set green / red overlay at 50% transparency
var hoverEntity = _entityManager.SpawnEntity("hoverentity", MapCoordinates.Nullspace);
var hoverSprite = _entityManager.GetComponent<SpriteComponent>(hoverEntity);
hoverSprite.CopyFrom(_entityManager.GetComponent<SpriteComponent>(entity.Value));
hoverSprite.Color = fits ? new Color(0, 255, 0, 127) : new Color(255, 0, 0, 127);
button.HoverSpriteView.Sprite = hoverSprite;
}
public bool IsHighlighted(EntityUid? uid)
{
if (uid == null) return false;
return _highlightEntities.Contains(uid.Value);
}
public void HighlightEntity(EntityUid uid)
{
if (!_highlightEntities.Add(uid))
return;
EntityHighlightedUpdated?.Invoke(new EntitySlotHighlightedEventArgs(uid, true));
}
public void UnHighlightEntity(EntityUid uid)
{
if (!_highlightEntities.Remove(uid))
return;
EntityHighlightedUpdated?.Invoke(new EntitySlotHighlightedEventArgs(uid, false));
}
}
public readonly struct EntitySlotHighlightedEventArgs
{
public EntitySlotHighlightedEventArgs(EntityUid entity, bool newHighlighted)
{
Entity = entity;
NewHighlighted = newHighlighted;
}
public EntityUid Entity { get; }
public bool NewHighlighted { get; }
}
}

View File

@@ -1,197 +0,0 @@
using System;
using Content.Client.Cooldown;
using Content.Client.HUD;
using Content.Client.Items.Managers;
using Content.Client.Stylesheets;
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.Maths;
using Robust.Shared.Utility;
namespace Content.Client.Items.UI
{
[Virtual]
public class ItemSlotButton : Control, IEntityEventSubscriber
{
private const string HighlightShader = "SelectionOutlineInrange";
[Dependency] private readonly IItemSlotManager _itemSlotManager = default!;
public EntityUid? Entity { get; set; }
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;
private string _textureName;
private string _storageTextureName;
public ItemSlotButton(int size, string textureName, string storageTextureName, IGameHud gameHud)
{
_textureName = textureName;
_storageTextureName = storageTextureName;
IoCManager.InjectDependencies(this);
MinSize = (size, size);
AddChild(Button = new TextureRect
{
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
{
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,
});
RefreshTextures(gameHud);
}
public void RefreshTextures(IGameHud gameHud)
{
Button.Texture = gameHud.GetHudTexture(_textureName);
StorageButton.TextureNormal = gameHud.GetHudTexture(_storageTextureName);
}
protected override void EnteredTree()
{
base.EnteredTree();
_itemSlotManager.EntityHighlightedUpdated += HandleEntitySlotHighlighted;
UpdateSlotHighlighted();
}
protected override void ExitedTree()
{
base.ExitedTree();
_itemSlotManager.EntityHighlightedUpdated -= HandleEntitySlotHighlighted;
}
private void HandleEntitySlotHighlighted(EntitySlotHighlightedEventArgs entitySlotHighlightedEventArgs)
{
UpdateSlotHighlighted();
}
public void UpdateSlotHighlighted()
{
Highlight(_itemSlotManager.IsHighlighted(Entity));
}
public void ClearHover()
{
if (EntityHover)
{
ISpriteComponent? tempQualifier = HoverSpriteView.Sprite;
if (tempQualifier != null)
{
IoCManager.Resolve<IEntityManager>().DeleteEntity(tempQualifier.Owner);
}
HoverSpriteView.Sprite = null;
}
}
public virtual void Highlight(bool highlight)
{
if (highlight)
{
_highlightRect.Visible = true;
}
else
{
_highlightRect.Visible = false;
}
}
private void OnButtonPressed(GUIBoundKeyEventArgs args)
{
OnPressed?.Invoke(args);
}
private void OnStorageButtonPressed(BaseButton.ButtonEventArgs args)
{
if (args.Event.Function == EngineKeyFunctions.UIClick)
{
OnStoragePressed?.Invoke(args.Event);
}
else
{
OnPressed?.Invoke(args.Event);
}
}
private void OnButtonHover(GUIMouseHoverEventArgs args)
{
OnHover?.Invoke(args);
}
}
}

View File

@@ -1,182 +0,0 @@
using Content.Client.Resources;
using Content.Client.Stylesheets;
using Content.Shared.Hands.Components;
using Content.Shared.IdentityManagement;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using static Content.Client.IoC.StaticIoC;
using static Robust.Client.UserInterface.Controls.BoxContainer;
namespace Content.Client.Items.UI
{
public sealed class ItemStatusPanel : Control
{
[Dependency] private readonly IEntityManager _entityManager = default!;
[ViewVariables]
private readonly Label _itemNameLabel;
[ViewVariables]
private readonly BoxContainer _statusContents;
[ViewVariables]
private readonly PanelContainer _panel;
[ViewVariables]
private EntityUid? _entity;
public ItemStatusPanel(Texture texture, StyleBox.Margin cutout, StyleBox.Margin flat, Label.AlignMode textAlign)
{
IoCManager.InjectDependencies(this);
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 BoxContainer
{
Orientation = LayoutOrientation.Vertical,
SeparationOverride = 0,
Children =
{
(_statusContents = new BoxContainer
{
Orientation = LayoutOrientation.Vertical
}),
(_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);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateItemName();
}
public void Update(EntityUid? entity)
{
if (entity == null)
{
ClearOldStatus();
_entity = null;
_panel.Visible = false;
return;
}
if (entity != _entity)
{
_entity = entity.Value;
BuildNewEntityStatus();
UpdateItemName();
}
_panel.Visible = true;
}
private void UpdateItemName()
{
if (_entity == null)
return;
if (_entityManager.TryGetComponent(_entity, out HandVirtualItemComponent? virtualItem)
&& _entityManager.EntityExists(virtualItem.BlockingEntity))
{
// Uses identity because we can be blocked by pulling someone
_itemNameLabel.Text = Identity.Name(virtualItem.BlockingEntity, _entityManager);
}
else
{
_itemNameLabel.Text = Identity.Name(_entity.Value, _entityManager);
}
}
private void ClearOldStatus()
{
_statusContents.RemoveAllChildren();
}
private void BuildNewEntityStatus()
{
DebugTools.AssertNotNull(_entity);
ClearOldStatus();
var collectMsg = new ItemStatusCollectMessage();
_entityManager.EventBus.RaiseLocalEvent(_entity!.Value, collectMsg, true);
foreach (var control in collectMsg.Controls)
{
_statusContents.AddChild(control);
}
}
}
}