using System.Collections.Generic; using System.Threading; using Content.Client.ContextMenu.UI; using Content.Client.Resources; using Content.Shared.Verbs; 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.IoC; using Robust.Shared.Maths; using Robust.Shared.Utility; using static Robust.Client.UserInterface.Controls.BoxContainer; using Timer = Robust.Shared.Timing.Timer; namespace Content.Client.Verbs { /// /// This pop-up appears when hovering over a verb category in the context menu. /// public sealed class VerbCategoryPopup : ContextMenuPopup { public VerbCategoryPopup(VerbSystem system, IEnumerable verbs, VerbType type, EntityUid target, bool drawOnlyIcons) : base() { // Do any verbs have icons? If not, don't bother leaving space for icons in the pop-up. var drawVerbIcons = false; foreach (var verb in verbs) { if (verb.Icon != null) { drawVerbIcons = true; break; } } // If no verbs have icons. we cannot draw only icons if (drawVerbIcons == false) drawOnlyIcons = false; // If we are drawing only icons, show them side by side if (drawOnlyIcons) List.Orientation = LayoutOrientation.Horizontal; foreach (var verb in verbs) { AddToMenu(new VerbButton(system, verb, type, target, drawVerbIcons)); } } } public sealed class VerbButton : BaseButton { public VerbButton(VerbSystem system, Verb verb, VerbType type, EntityUid target, bool drawIcons = true, bool categoryPrefix = false) : base() { Disabled = verb.Disabled; ToolTip = verb.Tooltip; TooltipDelay = 0.5f; var buttonContents = new BoxContainer { Orientation = LayoutOrientation.Horizontal }; // maybe draw verb icons if (drawIcons) { TextureRect icon = new() { MinSize = (ContextMenuPopup.ButtonHeight, ContextMenuPopup.ButtonHeight), Stretch = TextureRect.StretchMode.KeepCentered, TextureScale = (0.5f, 0.5f) }; // Even though we are drawing icons, the icon for this specific verb may be null. if (verb.Icon != null) { icon.Texture = verb.Icon.Frame0(); } else if (categoryPrefix && verb.Category?.Icon != null) { // we will use the category icon instead icon.Texture = verb.Category.Icon.Frame0(); } buttonContents.AddChild(icon); } // maybe add a label if (verb.Text != string.Empty || categoryPrefix) { // First add a small bit of padding buttonContents.AddChild(new Control { MinSize = (4, ContextMenuPopup.ButtonHeight) }); var label = new RichTextLabel(); var text = categoryPrefix ? verb.Category!.Text + " " + verb.Text : verb.Text; label.SetMessage(FormattedMessage.FromMarkupPermissive(text.Trim())); label.VerticalAlignment = VAlignment.Center; buttonContents.AddChild(label); // Then also add some padding after the text. buttonContents.AddChild(new Control { MinSize = (4, ContextMenuPopup.ButtonHeight) }); } AddChild(buttonContents); if (Disabled) return; // give the button functionality! OnPressed += _ => { if (verb.CloseMenu) system.ContextMenuPresenter.CloseAllMenus(); system.TryExecuteVerb(verb, target, type); }; } protected override void Draw(DrawingHandleScreen handle) { base.Draw(handle); if (Disabled) { // use transparent-black rectangle to create a darker background. handle.DrawRect(PixelSizeBox, new Color(0,0,0,155)); } else if (DrawMode == DrawModeEnum.Hover) { // Draw a lighter shade of gray when hovered over handle.DrawRect(PixelSizeBox, Color.DarkSlateGray); } } } public sealed class VerbCategoryButton : Control { private readonly VerbSystem _system; private CancellationTokenSource? _openCancel; /// /// Whether or not to hide member verb text and just show icons. /// /// /// If no members have icons, this option is ignored and text is shown anyways. Defaults to using . /// private readonly bool _drawOnlyIcons; /// /// The pop-up that appears when hovering over this verb group. /// private readonly VerbCategoryPopup _popup; public VerbCategoryButton(VerbSystem system, VerbCategory category, IEnumerable verbs, VerbType type, EntityUid target, bool? drawOnlyIcons = null) : base() { _system = system; _drawOnlyIcons = drawOnlyIcons ?? category.IconsOnly; MouseFilter = MouseFilterMode.Stop; // Contents of the button stored in this box container var box = new BoxContainer() { Orientation = LayoutOrientation.Horizontal }; // First we add the icon for the verb group var icon = new TextureRect { MinSize = (ContextMenuPopup.ButtonHeight, ContextMenuPopup.ButtonHeight), TextureScale = (0.5f, 0.5f), Stretch = TextureRect.StretchMode.KeepCentered, }; if (category.Icon != null) { icon.Texture = category.Icon.Frame0(); } box.AddChild(icon); // Some padding before the text box.AddChild(new Control { MinSize = (4, ContextMenuPopup.ButtonHeight) }); // Then we add the label var label = new RichTextLabel(); label.SetMessage(FormattedMessage.FromMarkupPermissive(category.Text)); label.HorizontalExpand = true; label.VerticalAlignment = VAlignment.Center; box.AddChild(label); // Then also add some padding after the text. box.AddChild(new Control { MinSize = (4, ContextMenuPopup.ButtonHeight) }); // Then add the little ">" icon that tells you it's a group of verbs box.AddChild(new TextureRect { Texture = IoCManager.Resolve() .GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png"), TextureScale = (0.5f, 0.5f), Stretch = TextureRect.StretchMode.KeepCentered, }); // The pop-up that appears when hovering over the button _popup = new VerbCategoryPopup(_system, verbs, type, target, _drawOnlyIcons); UserInterfaceManager.ModalRoot.AddChild(_popup); AddChild(box); } protected override void Draw(DrawingHandleScreen handle) { base.Draw(handle); if (this == UserInterfaceManager.CurrentlyHovered || _system.CurrentCategoryPopup == _popup) { handle.DrawRect(PixelSizeBox, Color.DarkSlateGray); } } /// /// Open a verb category pop-up after a short delay. /// protected override void MouseEntered() { base.MouseEntered(); _openCancel = new CancellationTokenSource(); Timer.Spawn(ContextMenuPresenter.HoverDelay, () => { _system.CurrentCategoryPopup?.Close(); _system.CurrentCategoryPopup = _popup; var upperRight = GlobalPosition + (Width + ContextMenuPopup.MarginSize, -ContextMenuPopup.MarginSize); _popup.Open(UIBox2.FromDimensions(upperRight, (1, 1)), GlobalPosition); }, _openCancel.Token); } /// /// Cancel the delayed pop-up /// protected override void MouseExited() { base.MouseExited(); _openCancel?.Cancel(); _openCancel = null; } } }