1
0

ConfirmButton.cs 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. using Robust.Client.UserInterface.Controls;
  2. using Robust.Shared.Timing;
  3. namespace Content.Client.UserInterface.Controls;
  4. /// <summary>
  5. /// A Button that requires a second click to actually invoke its OnPressed action. <br/>
  6. /// When clicked once it will change rendering modes to be prefixed by <see cref="ConfirmPrefix"/>
  7. /// and displays <see cref="ConfirmationText"/> on the button instead of <see cref="Text"/>.<br/>
  8. /// <br/>
  9. /// After the first click <see cref="CooldownTime"/> needs to elapse before it can be clicked again to confirm.<br/>
  10. /// When the button doesn't get clicked a second time before <see cref="ResetTime"/> passes it changes back to its normal state.<br/>
  11. /// </summary>
  12. /// <remarks>
  13. /// Colors for the different states need to be set in the stylesheet
  14. /// </remarks>
  15. public sealed class ConfirmButton : Button
  16. {
  17. [Dependency] private readonly IGameTiming _gameTiming = default!;
  18. public const string ConfirmPrefix = "confirm-";
  19. private TimeSpan? _nextReset;
  20. private TimeSpan? _nextCooldown;
  21. private string? _confirmationText;
  22. private string? _text;
  23. /// <summary>
  24. /// Fired when the button was pressed and confirmed
  25. /// </summary>
  26. public new event Action<ButtonEventArgs>? OnPressed;
  27. /// <inheritdoc cref="Button.Text"/>
  28. /// <remarks>
  29. /// Hides the buttons text property to be able to sanely replace the button text with
  30. /// <see cref="_confirmationText"/> when asking for confirmation
  31. /// </remarks>
  32. public new string? Text
  33. {
  34. get => _text;
  35. set
  36. {
  37. _text = value;
  38. base.Text = IsConfirming ? _confirmationText : value;
  39. }
  40. }
  41. /// <summary>
  42. /// The text displayed on the button when waiting for a second click
  43. /// </summary>
  44. [ViewVariables(VVAccess.ReadWrite)]
  45. public string ConfirmationText
  46. {
  47. get => _confirmationText ?? Loc.GetString("generic-confirm");
  48. set => _confirmationText = value;
  49. }
  50. /// <summary>
  51. /// The time until the button reverts to normal
  52. /// </summary>
  53. [ViewVariables(VVAccess.ReadWrite)]
  54. public TimeSpan ResetTime { get; set; } = TimeSpan.FromSeconds(2);
  55. /// <summary>
  56. /// The time until the button accepts a second click. This is to prevent accidentally confirming the button
  57. /// </summary>
  58. [ViewVariables(VVAccess.ReadWrite)]
  59. public TimeSpan CooldownTime { get; set; } = TimeSpan.FromSeconds(.5);
  60. [ViewVariables]
  61. public bool IsConfirming = false;
  62. public ConfirmButton()
  63. {
  64. IoCManager.InjectDependencies(this);
  65. base.OnPressed += HandleOnPressed;
  66. }
  67. protected override void FrameUpdate(FrameEventArgs args)
  68. {
  69. if (IsConfirming && _gameTiming.CurTime > _nextReset)
  70. {
  71. IsConfirming = false;
  72. base.Text = Text;
  73. DrawModeChanged();
  74. }
  75. if (Disabled && _gameTiming.CurTime > _nextCooldown)
  76. Disabled = false;
  77. }
  78. protected override void DrawModeChanged()
  79. {
  80. if (IsConfirming)
  81. {
  82. switch (DrawMode)
  83. {
  84. case DrawModeEnum.Normal:
  85. SetOnlyStylePseudoClass(ConfirmPrefix + StylePseudoClassNormal);
  86. break;
  87. case DrawModeEnum.Pressed:
  88. SetOnlyStylePseudoClass(ConfirmPrefix + StylePseudoClassPressed);
  89. break;
  90. case DrawModeEnum.Hover:
  91. SetOnlyStylePseudoClass(ConfirmPrefix + StylePseudoClassHover);
  92. break;
  93. case DrawModeEnum.Disabled:
  94. SetOnlyStylePseudoClass(ConfirmPrefix + StylePseudoClassDisabled);
  95. break;
  96. default:
  97. throw new ArgumentOutOfRangeException();
  98. }
  99. return;
  100. }
  101. base.DrawModeChanged();
  102. }
  103. private void HandleOnPressed(ButtonEventArgs buttonEvent)
  104. {
  105. //Prevent accidental confirmations from double clicking
  106. if (IsConfirming && _nextCooldown > _gameTiming.CurTime)
  107. return;
  108. switch (IsConfirming)
  109. {
  110. case false:
  111. _nextCooldown = _gameTiming.CurTime + CooldownTime;
  112. _nextReset = _gameTiming.CurTime + ResetTime;
  113. Disabled = true;
  114. break;
  115. case true:
  116. OnPressed?.Invoke(buttonEvent);
  117. break;
  118. }
  119. base.Text = IsConfirming ? Text : ConfirmationText;
  120. IsConfirming = !IsConfirming;
  121. }
  122. }