Verb confirmation (#6137)
This commit is contained in:
@@ -18,6 +18,7 @@
|
||||
Name="ExpansionIndicator"
|
||||
HorizontalAlignment="Right"
|
||||
Stretch="KeepCentered"
|
||||
StyleClasses="contextMenuExpansionTexture"
|
||||
TextureScale="0.5 0.5"
|
||||
SetWidth="{x:Static ui:ContextMenuElement.ElementHeight}"
|
||||
SetHeight="{x:Static ui:ContextMenuElement.ElementHeight}"
|
||||
|
||||
@@ -18,6 +18,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
public partial class ContextMenuElement : ContainerButton
|
||||
{
|
||||
public const string StyleClassContextMenuButton = "contextMenuButton";
|
||||
public const string StyleClassContextMenuExpansionTexture = "contextMenuExpansionTexture";
|
||||
|
||||
public const float ElementMargin = 2;
|
||||
public const float ElementHeight = 32;
|
||||
@@ -45,7 +46,7 @@ namespace Content.Client.ContextMenu.UI
|
||||
/// <summary>
|
||||
/// Convenience property to set label text.
|
||||
/// </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)
|
||||
{
|
||||
@@ -55,9 +56,6 @@ namespace Content.Client.ContextMenu.UI
|
||||
|
||||
if (text != null)
|
||||
Text = text;
|
||||
|
||||
ExpansionIndicator.Texture = IoCManager.Resolve<IResourceCache>()
|
||||
.GetTexture("/Textures/Interface/VerbIcons/group.svg.192dpi.png");
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
@@ -95,7 +93,8 @@ namespace Content.Client.ContextMenu.UI
|
||||
if (_subMenu?.Visible ?? true)
|
||||
return;
|
||||
|
||||
RemoveStylePseudoClass(StylePseudoClassHover);
|
||||
if (HasStylePseudoClass(StylePseudoClassHover))
|
||||
RemoveStylePseudoClass(StylePseudoClassHover);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,6 +446,9 @@ namespace Content.Client.Stylesheets
|
||||
};
|
||||
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[]
|
||||
{
|
||||
// Window title.
|
||||
@@ -623,6 +626,32 @@ namespace Content.Client.Stylesheets
|
||||
Element<RichTextLabel>().Class(VerbMenuElement.StyleClassVerbOtherText)
|
||||
.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)
|
||||
Element<EntityContainerButton>().Class(StyleClassStorageButton)
|
||||
.Prop(ContainerButton.StylePropertyStyleBox, buttonStorage),
|
||||
|
||||
34
Content.Client/Verbs/UI/ConfirmationMenuElement.cs
Normal file
34
Content.Client/Verbs/UI/ConfirmationMenuElement.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,7 @@ namespace Content.Client.Verbs.UI
|
||||
public const string StyleClassVerbActivationText = "ActivationVerb";
|
||||
public const string StyleClassVerbAlternativeText = "AlternativeVerb";
|
||||
public const string StyleClassVerbOtherText = "OtherVerb";
|
||||
public const string StyleClassVerbMenuConfirmationTexture = "verbMenuConfirmationTexture";
|
||||
|
||||
public const float VerbTooltipDelay = 0.5f;
|
||||
|
||||
@@ -62,6 +63,12 @@ namespace Content.Client.Verbs.UI
|
||||
TooltipDelay = VerbTooltipDelay;
|
||||
Disabled = verb.Disabled;
|
||||
Verb = verb;
|
||||
|
||||
if (verb.ConfirmationPopup)
|
||||
{
|
||||
ExpansionIndicator.SetOnlyStyleClass(StyleClassVerbMenuConfirmationTexture);
|
||||
ExpansionIndicator.Visible = true;
|
||||
}
|
||||
}
|
||||
|
||||
public VerbMenuElement(VerbCategory category, VerbType verbType) : this(category.Text, category.Icon, verbType) { }
|
||||
|
||||
@@ -170,7 +170,14 @@ namespace Content.Client.Verbs.UI
|
||||
return;
|
||||
|
||||
if (element is not VerbMenuElement verbElement)
|
||||
{
|
||||
if (element is not ConfirmationMenuElement confElement)
|
||||
return;
|
||||
|
||||
args.Handle();
|
||||
ExecuteVerb(confElement.Verb, confElement.Type);
|
||||
return;
|
||||
}
|
||||
|
||||
args.Handle();
|
||||
var verb = verbElement.Verb;
|
||||
@@ -178,25 +185,45 @@ namespace Content.Client.Verbs.UI
|
||||
if (verb == null)
|
||||
{
|
||||
// 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)
|
||||
return;
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
verb = verbCategoryElement.Verb;
|
||||
verb = verbMenuElement.Verb;
|
||||
|
||||
if (verb == null)
|
||||
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)
|
||||
_verbSystem.CloseAllMenus();
|
||||
}
|
||||
|
||||
@@ -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.ConfirmationPopup = true;
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
}
|
||||
@@ -136,6 +137,7 @@ namespace Content.Server.Administration
|
||||
verb.IconTexture = "/Textures/Interface/VerbIcons/delete_transparent.svg.192dpi.png";
|
||||
verb.Act = () => EntityManager.DeleteEntity(args.Target);
|
||||
verb.Impact = LogImpact.Medium;
|
||||
verb.ConfirmationPopup = true;
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
@@ -166,6 +168,7 @@ namespace Content.Server.Administration
|
||||
player.ContentData()?.Mind?.TransferTo(args.Target, ghostCheckOverride: true);
|
||||
};
|
||||
verb.Impact = LogImpact.High;
|
||||
verb.ConfirmationPopup = true;
|
||||
args.Verbs.Add(verb);
|
||||
}
|
||||
|
||||
|
||||
@@ -135,6 +135,11 @@ namespace Content.Shared.Verbs
|
||||
/// </remarks>
|
||||
public LogImpact Impact = LogImpact.Low;
|
||||
|
||||
/// <summary>
|
||||
/// Whether this verb requires confirmation before being executed.
|
||||
/// </summary>
|
||||
public bool ConfirmationPopup = false;
|
||||
|
||||
/// <summary>
|
||||
/// Compares two verbs based on their <see cref="Priority"/>, <see cref="Category"/>, <see cref="Text"/>,
|
||||
/// and <see cref="IconTexture"/>.
|
||||
|
||||
Reference in New Issue
Block a user