Verb confirmation (#6137)

This commit is contained in:
ShadowCommander
2022-01-13 06:28:17 -08:00
committed by GitHub
parent 007caf26b7
commit 4f80dfda0d
8 changed files with 117 additions and 12 deletions

View File

@@ -18,6 +18,7 @@
Name="ExpansionIndicator" Name="ExpansionIndicator"
HorizontalAlignment="Right" HorizontalAlignment="Right"
Stretch="KeepCentered" Stretch="KeepCentered"
StyleClasses="contextMenuExpansionTexture"
TextureScale="0.5 0.5" TextureScale="0.5 0.5"
SetWidth="{x:Static ui:ContextMenuElement.ElementHeight}" SetWidth="{x:Static ui:ContextMenuElement.ElementHeight}"
SetHeight="{x:Static ui:ContextMenuElement.ElementHeight}" SetHeight="{x:Static ui:ContextMenuElement.ElementHeight}"

View File

@@ -18,6 +18,7 @@ namespace Content.Client.ContextMenu.UI
public partial class ContextMenuElement : ContainerButton public partial class ContextMenuElement : ContainerButton
{ {
public const string StyleClassContextMenuButton = "contextMenuButton"; public const string StyleClassContextMenuButton = "contextMenuButton";
public const string StyleClassContextMenuExpansionTexture = "contextMenuExpansionTexture";
public const float ElementMargin = 2; public const float ElementMargin = 2;
public const float ElementHeight = 32; public const float ElementHeight = 32;
@@ -45,7 +46,7 @@ namespace Content.Client.ContextMenu.UI
/// <summary> /// <summary>
/// Convenience property to set label text. /// Convenience property to set label text.
/// </summary> /// </summary>
public string Text { set => Label.SetMessage(FormattedMessage.FromMarkupPermissive(value.Trim())); } public virtual string Text { set => Label.SetMessage(FormattedMessage.FromMarkupPermissive(value.Trim())); }
public ContextMenuElement(string? text = null) public ContextMenuElement(string? text = null)
{ {
@@ -55,9 +56,6 @@ namespace Content.Client.ContextMenu.UI
if (text != null) if (text != null)
Text = text; Text = text;
ExpansionIndicator.Texture = IoCManager.Resolve<IResourceCache>()
.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png");
} }
protected override void Dispose(bool disposing) protected override void Dispose(bool disposing)
@@ -95,6 +93,7 @@ namespace Content.Client.ContextMenu.UI
if (_subMenu?.Visible ?? true) if (_subMenu?.Visible ?? true)
return; return;
if (HasStylePseudoClass(StylePseudoClassHover))
RemoveStylePseudoClass(StylePseudoClassHover); RemoveStylePseudoClass(StylePseudoClassHover);
} }
} }

View File

@@ -446,6 +446,9 @@ namespace Content.Client.Stylesheets
}; };
insetBack.SetPatchMargin(StyleBox.Margin.All, 10); insetBack.SetPatchMargin(StyleBox.Margin.All, 10);
var contextMenuExpansionTexture = resCache.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png");
var verbMenuConfirmationTexture = resCache.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png");
Stylesheet = new Stylesheet(BaseRules.Concat(new[] Stylesheet = new Stylesheet(BaseRules.Concat(new[]
{ {
// Window title. // Window title.
@@ -623,6 +626,32 @@ namespace Content.Client.Stylesheets
Element<RichTextLabel>().Class(VerbMenuElement.StyleClassVerbOtherText) Element<RichTextLabel>().Class(VerbMenuElement.StyleClassVerbOtherText)
.Prop(Label.StylePropertyFont, notoSans12), .Prop(Label.StylePropertyFont, notoSans12),
Element<TextureRect>().Class(ContextMenuElement.StyleClassContextMenuExpansionTexture)
.Prop(TextureRect.StylePropertyTexture, contextMenuExpansionTexture),
Element<TextureRect>().Class(VerbMenuElement.StyleClassVerbMenuConfirmationTexture)
.Prop(TextureRect.StylePropertyTexture, verbMenuConfirmationTexture),
// Context menu confirm buttons
Element<ContextMenuElement>().Class(ConfirmationMenuElement.StyleClassConfirmationContextMenuButton)
.Prop(ContainerButton.StylePropertyStyleBox, buttonContext),
Element<ContextMenuElement>().Class(ConfirmationMenuElement.StyleClassConfirmationContextMenuButton)
.Pseudo(ContainerButton.StylePseudoClassNormal)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDefault),
Element<ContextMenuElement>().Class(ConfirmationMenuElement.StyleClassConfirmationContextMenuButton)
.Pseudo(ContainerButton.StylePseudoClassHover)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionHovered),
Element<ContextMenuElement>().Class(ConfirmationMenuElement.StyleClassConfirmationContextMenuButton)
.Pseudo(ContainerButton.StylePseudoClassPressed)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionPressed),
Element<ContextMenuElement>().Class(ConfirmationMenuElement.StyleClassConfirmationContextMenuButton)
.Pseudo(ContainerButton.StylePseudoClassDisabled)
.Prop(Control.StylePropertyModulateSelf, ButtonColorCautionDisabled),
// Thin buttons (No padding nor vertical margin) // Thin buttons (No padding nor vertical margin)
Element<EntityContainerButton>().Class(StyleClassStorageButton) Element<EntityContainerButton>().Class(StyleClassStorageButton)
.Prop(ContainerButton.StylePropertyStyleBox, buttonStorage), .Prop(ContainerButton.StylePropertyStyleBox, buttonStorage),

View File

@@ -0,0 +1,34 @@
using Content.Client.ContextMenu.UI;
using Content.Shared.Verbs;
using Robust.Shared.Maths;
using Robust.Shared.Utility;
namespace Content.Client.Verbs.UI;
public partial class ConfirmationMenuElement : ContextMenuElement
{
public const string StyleClassConfirmationContextMenuButton = "confirmationContextMenuButton";
public readonly Verb Verb;
public readonly VerbType Type;
public override string Text
{
set
{
var message = new FormattedMessage();
message.PushColor(Color.White);
message.AddMarkupPermissive(value.Trim());
Label.SetMessage(message);
}
}
public ConfirmationMenuElement(Verb verb, string? text, VerbType type) : base(text)
{
Verb = verb;
Type = type;
Icon.Visible = false;
SetOnlyStyleClass(StyleClassConfirmationContextMenuButton);
}
}

View File

@@ -16,6 +16,7 @@ namespace Content.Client.Verbs.UI
public const string StyleClassVerbActivationText = "ActivationVerb"; public const string StyleClassVerbActivationText = "ActivationVerb";
public const string StyleClassVerbAlternativeText = "AlternativeVerb"; public const string StyleClassVerbAlternativeText = "AlternativeVerb";
public const string StyleClassVerbOtherText = "OtherVerb"; public const string StyleClassVerbOtherText = "OtherVerb";
public const string StyleClassVerbMenuConfirmationTexture = "verbMenuConfirmationTexture";
public const float VerbTooltipDelay = 0.5f; public const float VerbTooltipDelay = 0.5f;
@@ -62,6 +63,12 @@ namespace Content.Client.Verbs.UI
TooltipDelay = VerbTooltipDelay; TooltipDelay = VerbTooltipDelay;
Disabled = verb.Disabled; Disabled = verb.Disabled;
Verb = verb; Verb = verb;
if (verb.ConfirmationPopup)
{
ExpansionIndicator.SetOnlyStyleClass(StyleClassVerbMenuConfirmationTexture);
ExpansionIndicator.Visible = true;
}
} }
public VerbMenuElement(VerbCategory category, VerbType verbType) : this(category.Text, category.Icon, verbType) { } public VerbMenuElement(VerbCategory category, VerbType verbType) : this(category.Text, category.Icon, verbType) { }

View File

@@ -170,33 +170,60 @@ namespace Content.Client.Verbs.UI
return; return;
if (element is not VerbMenuElement verbElement) if (element is not VerbMenuElement verbElement)
{
if (element is not ConfirmationMenuElement confElement)
return; return;
args.Handle();
ExecuteVerb(confElement.Verb, confElement.Type);
return;
}
args.Handle(); args.Handle();
var verb = verbElement.Verb; var verb = verbElement.Verb;
if (verb == null) if (verb == null)
{ {
// The user probably clicked on a verb category. // The user probably clicked on a verb category.
// We will act as if they clicked on the first verb in that category. // If there's only one verb in the category, then it will act as if they clicked on that verb.
// Otherwise it opens the category menu.
if (verbElement.SubMenu == null || verbElement.SubMenu.ChildCount == 0) if (verbElement.SubMenu == null || verbElement.SubMenu.ChildCount == 0)
return; return;
if (verbElement.SubMenu.MenuBody.ChildCount != 1 if (verbElement.SubMenu.MenuBody.ChildCount != 1
|| verbElement.SubMenu.MenuBody.Children.First() is not VerbMenuElement verbCategoryElement) || verbElement.SubMenu.MenuBody.Children.First() is not VerbMenuElement verbMenuElement)
{ {
OpenSubMenu(verbElement); OpenSubMenu(verbElement);
return; return;
} }
verb = verbCategoryElement.Verb; verb = verbMenuElement.Verb;
if (verb == null) if (verb == null)
return; return;
} }
_verbSystem.ExecuteVerb(CurrentTarget, verb, verbElement.Type); if (verb.ConfirmationPopup)
{
if (verbElement.SubMenu == null)
{
var popupElement = new ConfirmationMenuElement(verb, "Confirm", verbElement.Type);
verbElement.SubMenu = new ContextMenuPopup(this, verbElement);
AddElement(verbElement.SubMenu, popupElement);
}
OpenSubMenu(verbElement);
}
else
{
ExecuteVerb(verb, verbElement.Type);
}
}
private void ExecuteVerb(Verb verb, VerbType verbType)
{
_verbSystem.ExecuteVerb(CurrentTarget, verb, verbType);
if (verb.CloseMenu) if (verb.CloseMenu)
_verbSystem.CloseAllMenus(); _verbSystem.CloseAllMenus();
} }

View File

@@ -116,6 +116,7 @@ namespace Content.Server.Administration
} }
}; };
verb.Impact = LogImpact.Extreme; // if you're just outright killing a person, I guess that deserves to be extreme? verb.Impact = LogImpact.Extreme; // if you're just outright killing a person, I guess that deserves to be extreme?
verb.ConfirmationPopup = true;
args.Verbs.Add(verb); args.Verbs.Add(verb);
} }
} }
@@ -136,6 +137,7 @@ namespace Content.Server.Administration
verb.IconTexture = "/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png"; verb.IconTexture = "/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png";
verb.Act = () => EntityManager.DeleteEntity(args.Target); verb.Act = () => EntityManager.DeleteEntity(args.Target);
verb.Impact = LogImpact.Medium; verb.Impact = LogImpact.Medium;
verb.ConfirmationPopup = true;
args.Verbs.Add(verb); args.Verbs.Add(verb);
} }
@@ -166,6 +168,7 @@ namespace Content.Server.Administration
player.ContentData()?.Mind?.TransferTo(args.Target, ghostCheckOverride: true); player.ContentData()?.Mind?.TransferTo(args.Target, ghostCheckOverride: true);
}; };
verb.Impact = LogImpact.High; verb.Impact = LogImpact.High;
verb.ConfirmationPopup = true;
args.Verbs.Add(verb); args.Verbs.Add(verb);
} }

View File

@@ -135,6 +135,11 @@ namespace Content.Shared.Verbs
/// </remarks> /// </remarks>
public LogImpact Impact = LogImpact.Low; public LogImpact Impact = LogImpact.Low;
/// <summary>
/// Whether this verb requires confirmation before being executed.
/// </summary>
public bool ConfirmationPopup = false;
/// <summary> /// <summary>
/// Compares two verbs based on their <see cref="Priority"/>, <see cref="Category"/>, <see cref="Text"/>, /// Compares two verbs based on their <see cref="Priority"/>, <see cref="Category"/>, <see cref="Text"/>,
/// and <see cref="IconTexture"/>. /// and <see cref="IconTexture"/>.