1 using Microsoft.Xna.Framework;
3 using System.Collections.Generic;
6 using Microsoft.Xna.Framework.Input;
12 public readonly
static List<GUIComponent>
MessageBoxes =
new List<GUIComponent>();
13 private static int DefaultWidth
18 private float inGameCloseTimer = 0.0f;
19 private const float inGameCloseTime = 15f;
31 private bool IsAnimated => type ==
Type.InGame || type ==
Type.Hint || type ==
Type.Tutorial;
33 public List<GUIButton>
Buttons {
get;
private set; } =
new List<GUIButton>();
38 public Identifier
Tag {
get;
private set; }
39 public bool Closed {
get;
private set; }
54 if (
Icon ==
null) {
return; }
70 private float openState;
71 private float iconState;
72 private bool iconSwitching;
75 private readonly
Type type;
80 private readonly Func<bool> autoCloseCondition;
96 : this(headerText, text, new
LocalizedString[] {
"OK" }, relativeSize, minSize, type: type)
106 Vector2? relativeSize =
null, Point? minSize =
null, Alignment textAlignment = Alignment.TopLeft,
Type type =
Type.Default,
string tag =
"",
107 Sprite icon =
null,
string iconStyle =
"",
Sprite backgroundIcon =
null, Func<bool> autoCloseCondition =
null,
bool hideCloseButton =
false)
108 : base(new
RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas,
Anchor.
Center), style: GUIStyle.GetComponentStyle(
"GUIMessageBox." + type) != null ?
"GUIMessageBox." + type :
"GUIMessageBox")
110 int width = (int)(DefaultWidth * type
switch
112 Type.Default => 1.0f,
118 if (relativeSize.HasValue)
123 if (minSize.HasValue)
125 width = Math.Max(width, minSize.Value.X);
128 height = Math.Max(height, minSize.Value.Y);
132 if (backgroundIcon !=
null)
137 Color = Color.Transparent
141 Anchor anchor = type
switch
151 if (type ==
Type.Vote)
153 int offset = GUI.IntScale(64);
159 Tag = tag.ToIdentifier();
161 #warning TODO: These should be broken into separate methods at least
162 if (type ==
Type.Default || type ==
Type.Vote || type ==
Type.Warning)
167 headerText, font: GUIStyle.SubHeadingFont, textAlignment: Alignment.Center, wrap:
true);
168 GUIStyle.Apply(
Header,
"",
this);
169 Header.RectTransform.MinSize =
new Point(0,
Header.Rect.Height);
171 if (!text.IsNullOrWhiteSpace())
174 GUIStyle.Apply(
Text,
"",
this);
187 var buttonStyle = GUIStyle.GetComponentStyle(
"GUIButton");
188 if (buttonStyle !=
null && buttonStyle.Height.HasValue)
190 buttonSize = buttonStyle.Height.Value;
193 buttonContainer.RectTransform.NonScaledSize = buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.MaxSize =
194 new Point(buttonContainer.Rect.Width, (
int)((buttonSize + 5) * buttons.
Length));
195 buttonContainer.RectTransform.IsFixedSize =
true;
201 height += buttonContainer.Rect.Height + 20;
202 if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
211 for (
int i = 0; i < buttons.
Length; i++)
218 else if (type ==
Type.InGame || type ==
Type.Tutorial)
226 isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
229 RelativeSpacing = 0.02f
233 Icon =
new GUIImage(
new RectTransform(
new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), icon, scaleToFit:
true);
235 else if (iconStyle !=
string.Empty)
237 Icon =
new GUIImage(
new RectTransform(
new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), iconStyle, scaleToFit:
true);
242 if (!hideCloseButton)
244 var buttonContainer =
new GUIFrame(
new RectTransform(
new Vector2(0.15f, 1.0f), horizontalLayoutGroup.RectTransform), style:
null);
245 Buttons =
new List<GUIButton>(1)
248 style:
"UIToggleButton")
259 else if (GameSettings.CurrentConfig.KeyMap.Bindings[
InputType.Select].MouseButton ==
MouseButton.None)
263 if (closeInput.HasValue)
265 Buttons[0].ToolTip = TextManager.ParseInputTypes($
"{TextManager.Get("Close")} ([InputType.{closeInput.Value}])");
272 btn?.
Flash(GUIStyle.Green);
283 GUIStyle.Apply(
Header,
"",
this);
284 Header.RectTransform.MinSize =
new Point(0,
Header.Rect.Height);
286 if (!text.IsNullOrWhiteSpace())
289 GUIStyle.Apply(
Text,
"",
this);
294 if (headerText.IsNullOrWhiteSpace())
304 if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
311 if (!hideCloseButton)
316 else if (type ==
Type.Hint)
321 Point absoluteSpacing = GUIStyle.ItemFrameMargin.Multiply(1.0f / 5.0f);
324 AbsoluteSpacing = absoluteSpacing.Y,
329 isHorizontal:
true, childAnchor:
Anchor.CenterLeft)
332 RelativeSpacing = 0.02f
335 int iconMaxHeight = 0;
338 Icon =
new GUIImage(
new RectTransform(
new Vector2(0.15f, 0.95f), topHorizontalLayoutGroup.RectTransform), icon, scaleToFit:
true);
343 bool iconStyleDefined = !
string.IsNullOrEmpty(iconStyle);
345 iconStyleDefined ? iconStyle :
"GUIButtonInfo", scaleToFit:
true);
346 if (!iconStyleDefined)
353 iconMaxHeight = Math.Min((
int)(GUI.yScale * 40), iconMaxHeight);
354 int iconMinHeight = Math.Min((
int)(GUI.yScale * 40), iconMaxHeight);
360 AbsoluteSpacing = absoluteSpacing.Y,
363 var bottomContainer =
new GUIFrame(
new RectTransform(
new Vector2(0.9f, 0.3f), verticalLayoutGroup.RectTransform), style:
null)
373 Vector2 tickBoxRelativeSize =
new Vector2(1.0f, 0.5f);
374 var dontShowAgainTickBox =
new GUITickBox(
new RectTransform(tickBoxRelativeSize, tickBoxLayoutGroup.RectTransform),
375 TextManager.Get(
"hintmessagebox.dontshowagain"))
377 ToolTip = TextManager.Get(
"hintmessagebox.dontshowagaintooltip"),
380 var disableHintsTickBox =
new GUITickBox(
new RectTransform(tickBoxRelativeSize, tickBoxLayoutGroup.RectTransform),
381 TextManager.Get(
"hintmessagebox.disablehints"))
383 ToolTip = TextManager.Get(
"hintmessagebox.disablehintstooltip"),
387 Buttons =
new List<GUIButton>(1)
390 text: TextManager.Get(
"hintmessagebox.dismiss"), style:
"GUIButtonSmall")
397 GUIStyle.Apply(
Header,
"",
this);
398 Header.RectTransform.MinSize =
new Point(0,
Header.Rect.Height);
400 if (!text.IsNullOrWhiteSpace())
403 GUIStyle.Apply(
Text,
"",
this);
408 if (headerText.IsNullOrWhiteSpace())
410 Header.RectTransform.Parent =
null;
417 height = absoluteSpacing.Y;
418 int upperContainerHeight = absoluteSpacing.Y;
421 upperContainerHeight = Math.Max(upperContainerHeight,
Icon.
Rect.Height);
422 height += upperContainerHeight;
423 height += absoluteSpacing.Y;
424 int bottomContainerHeight = dontShowAgainTickBox.Rect.Height + disableHintsTickBox.Rect.Height;
425 height += bottomContainerHeight;
426 height += absoluteSpacing.Y;
427 if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
430 verticalLayoutGroup.RectTransform.NonScaledSize = GetVerticalLayoutGroupSize();
431 float upperContainerRelativeHeight = (float)upperContainerHeight / (upperContainerHeight + bottomContainerHeight);
432 topHorizontalLayoutGroup.RectTransform.RelativeSize =
new Vector2(topHorizontalLayoutGroup.RectTransform.RelativeSize.X, upperContainerRelativeHeight);
433 bottomContainer.RectTransform.RelativeSize =
new Vector2(bottomContainer.RectTransform.RelativeSize.X, 1.0f - upperContainerRelativeHeight);
434 verticalLayoutGroup.Recalculate();
435 topHorizontalLayoutGroup.Recalculate();
437 tickBoxLayoutGroup.Recalculate();
442 Point GetVerticalLayoutGroupSize()
448 this.autoCloseCondition = autoCloseCondition;
460 dontShowAgainTickBox.OnSelected = HintManager.OnDontShowAgain;
461 dontShowAgainTickBox.UserData = hintIdentifier;
465 disableHintsTickBox.OnSelected = HintManager.OnDisableHints;
466 disableHintsTickBox.UserData = hintIdentifier;
470 private static Type[] messageBoxTypes;
474 messageBoxTypes ??= (
Type[])Enum.GetValues(typeof(
Type));
476 foreach (var type
in messageBoxTypes)
479 if (type ==
Type.Hint && GUI.DisableHUD) {
continue; }
486 if (type ==
Type.Default)
494 if (messageBox.type != type) {
continue; }
501 if (messageBox.DrawOnTop) {
continue; }
503 messageBox.AddToGUIUpdateList();
511 if (icon ==
null) {
return; }
516 Color = Color.Transparent
519 if (newBackgroundIcon !=
null)
522 newBackgroundIcon =
null;
524 newBackgroundIcon = newIcon;
527 protected override void Update(
float deltaTime)
559 Vector2 initialPos, defaultPos, endPos;
560 if (type ==
Type.InGame || type ==
Type.Tutorial)
563 defaultPos =
new Vector2(0.0f, HUDLayoutSettings.InventoryAreaLower.Y -
InnerFrame.
Rect.Height - 20 * GUI.Scale);
568 initialPos =
new Vector2(GUI.IntScale(64), -
InnerFrame.
Rect.Height);
569 defaultPos =
new Vector2(initialPos.X, HUDLayoutSettings.ButtonAreaTop.Height + GUI.IntScale(64));
575 Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
580 if (!MathUtils.NearlyEqual(openState, 1.0f))
587 openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
592 inGameCloseTimer += deltaTime;
595 if (inGameCloseTimer >= inGameCloseTime)
599 else if (autoCloseCondition !=
null && autoCloseCondition())
610 openState += deltaTime * 2.0f;
611 Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
617 if (openState >= 2.0f)
624 if (newBackgroundIcon !=
null)
634 iconSwitching =
true;
640 iconSwitching =
true;
648 newBackgroundIcon.
Color = Color.Lerp(Color.Transparent, Color.White, iconState);
649 if (newBackgroundIcon.
Color.A == 255)
653 newBackgroundIcon =
null;
654 iconSwitching =
false;
657 iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
690 public static void Close(Identifier tag)
701 public static void Close(
string tag) =>
Close(tag.ToIdentifier());
715 var relativeSizeFallback = relativeSize ?? (0.7f, 0.5f);
719 relativeSize: relativeSizeFallback,
720 buttons: buttons.Select(b => b.Label).ToArray());
721 newMessageBox.InnerFrame.RectTransform.ScaleBasis =
ScaleBasis.BothHeight;
723 for (
int i = 0; i < buttons.Length; i++)
725 var capturedIndex = i;
726 newMessageBox.Buttons[i].OnClicked = (_, _) =>
728 buttons[capturedIndex].Action(newMessageBox);
733 const float throbberSize = 0.25f;
736 new RectTransform((0.9f, 0f), newMessageBox.InnerFrame.RectTransform,
Anchor.Center,
Pivot.BottomCenter) { RelativeOffset = (0f, -throbberSize * 0.5f) },
737 text: text, textAlignment: Alignment.Center, wrap:
true);
742 onDraw: static (sb, component) =>
744 GUIStyle.GenericThrobber.Draw(
746 spriteIndex: (
int)(Timing.TotalTime * 20f) % GUIStyle.GenericThrobber.FrameCount,
747 pos: component.Rect.Center.ToVector2(),
749 origin: GUIStyle.GenericThrobber.FrameSize.ToVector2() * 0.5f,
751 scale: component.Rect.Size.ToVector2() / GUIStyle.GenericThrobber.FrameSize.ToVector2());
756 return newMessageBox;
virtual void RemoveChild(GUIComponent child)
virtual void Flash(Color? color=null, float flashDuration=1.5f, bool useRectangleFlash=false, bool useCircularFlash=false, Vector2? flashRectInflate=null)
bool IsParentOf(GUIComponent component, bool recursive=true)
GUIComponent FindChild(Func< GUIComponent, bool > predicate, bool recursive=false)
virtual RichString ToolTip
RectTransform RectTransform
Sprite GetDefaultSprite()
GUIComponent that can be used to render custom content on the UI
GUIFrame(RectTransform rectT, string style="", Color? color=null)
static readonly List< GUIComponent > MessageBoxes
static void AddActiveToGUIUpdateList()
bool FlashOnAutoCloseCondition
bool DisplayInLoadingScreens
void SetBackgroundIcon(Sprite icon)
GUIMessageBox(Identifier hintIdentifier, LocalizedString text, Sprite icon)
Use to create a message box of Hint type
bool DrawOnTop
If enabled, the box is always drawn in front of all other elements.
List< GUIButton > Buttons
bool Close(GUIButton button, object obj)
static void Close(Identifier tag)
static void Close(string tag)
bool AutoClose
Close the message box automatically after enough time has passed (inGameCloseTime)
void AddButton(RectTransform rectT, string text, GUIButton.OnClickedHandler onClick)
Parent does not matter. It's overridden.
static GUIMessageBox CreateLoadingBox(LocalizedString text,(LocalizedString Label, Action< GUIMessageBox > Action)[] buttons=null, Vector2? relativeSize=null)
static GUIComponent VisibleBox
override void Update(float deltaTime)
GUIMessageBox(LocalizedString headerText, LocalizedString text, Vector2? relativeSize=null, Point? minSize=null, Type type=Type.Default)
GUIMessageBox(RichString headerText, RichString text, LocalizedString[] buttons, Vector2? relativeSize=null, Point? minSize=null, Alignment textAlignment=Alignment.TopLeft, Type type=Type.Default, string tag="", Sprite icon=null, string iconStyle="", Sprite backgroundIcon=null, Func< bool > autoCloseCondition=null, bool hideCloseButton=false)
static void AutoScaleAndNormalize(params GUITextBlock[] textBlocks)
Set the text scale of the GUITextBlocks so that they all use the same scale and can fit the text with...
static int GraphicsHeight
Defines a point in the event that GoTo actions can jump to.
Highlights an UI element of some kind. Generally used in tutorials.