399 lines
16 KiB
C#
399 lines
16 KiB
C#
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
|
|
namespace Barotrauma
|
|
{
|
|
public class GUIMessageBox : GUIFrame
|
|
{
|
|
public static List<GUIComponent> MessageBoxes = new List<GUIComponent>();
|
|
private static int DefaultWidth
|
|
{
|
|
get { return Math.Max(400, (int)(400 * (GameMain.GraphicsWidth / GUI.ReferenceResolution.X))); }
|
|
}
|
|
|
|
private float inGameCloseTimer = 0.0f;
|
|
private const float inGameCloseTime = 15f;
|
|
|
|
public enum Type
|
|
{
|
|
Default,
|
|
InGame
|
|
}
|
|
|
|
public List<GUIButton> Buttons { get; private set; } = new List<GUIButton>();
|
|
//public GUIFrame BackgroundFrame { get; private set; }
|
|
public GUILayoutGroup Content { get; private set; }
|
|
public GUIFrame InnerFrame { get; private set; }
|
|
public GUITextBlock Header { get; private set; }
|
|
public GUITextBlock Text { get; private set; }
|
|
public string Tag { get; private set; }
|
|
public bool Closed { get; private set; }
|
|
|
|
public GUIImage Icon
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
public Color IconColor
|
|
{
|
|
get { return Icon == null ? Color.White : Icon.Color; }
|
|
set
|
|
{
|
|
if (Icon == null) { return; }
|
|
Icon.Color = value;
|
|
}
|
|
}
|
|
|
|
public GUIImage BackgroundIcon { get; private set; }
|
|
private GUIImage newBackgroundIcon;
|
|
|
|
public bool AutoClose;
|
|
|
|
private readonly bool alwaysVisible;
|
|
|
|
private float openState;
|
|
private float iconState;
|
|
private bool iconSwitching;
|
|
private bool closing;
|
|
|
|
private Type type;
|
|
|
|
public static GUIComponent VisibleBox => MessageBoxes.LastOrDefault();
|
|
|
|
public GUIMessageBox(string headerText, string text, Vector2? relativeSize = null, Point? minSize = null)
|
|
: this(headerText, text, new string[] { "OK" }, relativeSize, minSize)
|
|
{
|
|
this.Buttons[0].OnClicked = Close;
|
|
}
|
|
|
|
public GUIMessageBox(string headerText, string text, string[] 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)
|
|
: base(new RectTransform(GUI.Canvas.RelativeSize, GUI.Canvas, Anchor.Center), style: GUI.Style.GetComponentStyle("GUIMessageBox." + type) != null ? "GUIMessageBox." + type : "GUIMessageBox")
|
|
{
|
|
int width = (int)(DefaultWidth * (type == Type.Default ? 1.0f : 1.5f)), height = 0;
|
|
if (relativeSize.HasValue)
|
|
{
|
|
width = (int)(GameMain.GraphicsWidth * relativeSize.Value.X);
|
|
height = (int)(GameMain.GraphicsHeight * relativeSize.Value.Y);
|
|
}
|
|
if (minSize.HasValue)
|
|
{
|
|
width = Math.Max(width, minSize.Value.X);
|
|
if (height > 0)
|
|
{
|
|
height = Math.Max(height, minSize.Value.Y);
|
|
}
|
|
}
|
|
|
|
if (backgroundIcon != null)
|
|
{
|
|
BackgroundIcon = new GUIImage(new RectTransform(backgroundIcon.size.ToPoint(), RectTransform), backgroundIcon)
|
|
{
|
|
IgnoreLayoutGroups = true,
|
|
Color = Color.Transparent
|
|
};
|
|
}
|
|
|
|
InnerFrame = new GUIFrame(new RectTransform(new Point(width, height), RectTransform, type == Type.InGame ? Anchor.TopCenter : Anchor.Center) { IsFixedSize = false }, style: null);
|
|
GUI.Style.Apply(InnerFrame, "", this);
|
|
this.type = type;
|
|
Tag = tag;
|
|
|
|
if (type == Type.Default)
|
|
{
|
|
Content = new GUILayoutGroup(new RectTransform(new Vector2(0.9f, 0.85f), InnerFrame.RectTransform, Anchor.Center)) { AbsoluteSpacing = 5 };
|
|
|
|
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform),
|
|
headerText, font: GUI.SubHeadingFont, textAlignment: Alignment.Center, wrap: true);
|
|
GUI.Style.Apply(Header, "", this);
|
|
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
|
|
|
|
if (!string.IsNullOrWhiteSpace(text))
|
|
{
|
|
Text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), text, textAlignment: textAlignment, wrap: true);
|
|
GUI.Style.Apply(Text, "", this);
|
|
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
|
|
new Point(Text.Rect.Width, Text.Rect.Height);
|
|
Text.RectTransform.IsFixedSize = true;
|
|
}
|
|
|
|
var buttonContainer = new GUILayoutGroup(new RectTransform(new Vector2(1.0f, 0.15f), Content.RectTransform, Anchor.BottomCenter), childAnchor: Anchor.TopCenter)
|
|
{
|
|
AbsoluteSpacing = 5,
|
|
IgnoreLayoutGroups = true
|
|
};
|
|
|
|
int buttonSize = 35;
|
|
var buttonStyle = GUI.Style.GetComponentStyle("GUIButton");
|
|
if (buttonStyle != null && buttonStyle.Height.HasValue)
|
|
{
|
|
buttonSize = buttonStyle.Height.Value;
|
|
}
|
|
|
|
buttonContainer.RectTransform.NonScaledSize = buttonContainer.RectTransform.MinSize = buttonContainer.RectTransform.MaxSize =
|
|
new Point(buttonContainer.Rect.Width, (int)((buttonSize + 5) * buttons.Length));
|
|
buttonContainer.RectTransform.IsFixedSize = true;
|
|
|
|
if (height == 0)
|
|
{
|
|
height += Header.Rect.Height + Content.AbsoluteSpacing;
|
|
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
|
|
height += buttonContainer.Rect.Height + 20;
|
|
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
|
|
|
|
InnerFrame.RectTransform.NonScaledSize =
|
|
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + (int)(50 * GUI.yScale)));
|
|
Content.RectTransform.NonScaledSize =
|
|
new Point(Content.Rect.Width, height);
|
|
}
|
|
|
|
Buttons = new List<GUIButton>(buttons.Length);
|
|
for (int i = 0; i < buttons.Length; i++)
|
|
{
|
|
var button = new GUIButton(new RectTransform(new Vector2(0.6f, 1.0f / buttons.Length), buttonContainer.RectTransform), buttons[i]);
|
|
Buttons.Add(button);
|
|
}
|
|
}
|
|
else if (type == Type.InGame)
|
|
{
|
|
InnerFrame.RectTransform.AbsoluteOffset = new Point(0, GameMain.GraphicsHeight);
|
|
alwaysVisible = true;
|
|
CanBeFocused = false;
|
|
AutoClose = true;
|
|
GUI.Style.Apply(InnerFrame, "", this);
|
|
|
|
var horizontalLayoutGroup = new GUILayoutGroup(new RectTransform(new Vector2(0.98f, 0.95f), InnerFrame.RectTransform, Anchor.Center),
|
|
isHorizontal: true, childAnchor: Anchor.CenterLeft)
|
|
{
|
|
Stretch = true,
|
|
RelativeSpacing = 0.02f
|
|
};
|
|
if (icon != null)
|
|
{
|
|
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), icon, scaleToFit: true);
|
|
}
|
|
else if (iconStyle != string.Empty)
|
|
{
|
|
Icon = new GUIImage(new RectTransform(new Vector2(0.2f, 0.95f), horizontalLayoutGroup.RectTransform), iconStyle, scaleToFit: true);
|
|
}
|
|
|
|
Content = new GUILayoutGroup(new RectTransform(new Vector2(Icon != null ? 0.65f : 0.85f, 1.0f), horizontalLayoutGroup.RectTransform));
|
|
|
|
var buttonContainer = new GUIFrame(new RectTransform(new Vector2(0.15f, 1.0f), horizontalLayoutGroup.RectTransform), style: null);
|
|
Buttons = new List<GUIButton>(1)
|
|
{
|
|
new GUIButton(new RectTransform(new Vector2(0.3f, 0.5f), buttonContainer.RectTransform, Anchor.Center),
|
|
style: "UIToggleButton")
|
|
{
|
|
OnClicked = Close
|
|
}
|
|
};
|
|
|
|
Header = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), headerText, wrap: true);
|
|
GUI.Style.Apply(Header, "", this);
|
|
Header.RectTransform.MinSize = new Point(0, Header.Rect.Height);
|
|
|
|
if (!string.IsNullOrWhiteSpace(text))
|
|
{
|
|
Text = new GUITextBlock(new RectTransform(new Vector2(1.0f, 0.0f), Content.RectTransform), text, textAlignment: textAlignment, wrap: true);
|
|
GUI.Style.Apply(Text, "", this);
|
|
Content.Recalculate();
|
|
Text.RectTransform.NonScaledSize = Text.RectTransform.MinSize = Text.RectTransform.MaxSize =
|
|
new Point(Text.Rect.Width, Text.Rect.Height);
|
|
Text.RectTransform.IsFixedSize = true;
|
|
if (string.IsNullOrWhiteSpace(headerText))
|
|
{
|
|
Content.ChildAnchor = Anchor.Center;
|
|
}
|
|
}
|
|
|
|
if (height == 0)
|
|
{
|
|
height += Header.Rect.Height + Content.AbsoluteSpacing;
|
|
height += (Text == null ? 0 : Text.Rect.Height) + Content.AbsoluteSpacing;
|
|
if (minSize.HasValue) { height = Math.Max(height, minSize.Value.Y); }
|
|
|
|
InnerFrame.RectTransform.NonScaledSize =
|
|
new Point(InnerFrame.Rect.Width, (int)Math.Max(height / Content.RectTransform.RelativeSize.Y, height + (int)(50 * GUI.yScale)));
|
|
Content.RectTransform.NonScaledSize =
|
|
new Point(Content.Rect.Width, height);
|
|
}
|
|
Buttons[0].RectTransform.MaxSize = new Point((int)(0.4f * Buttons[0].Rect.Y), Buttons[0].Rect.Y);
|
|
}
|
|
|
|
MessageBoxes.Add(this);
|
|
}
|
|
|
|
public static void AddActiveToGUIUpdateList()
|
|
{
|
|
for (int i = 0; i < MessageBoxes.Count; i++)
|
|
{
|
|
if (MessageBoxes[i] is GUIMessageBox alwaysVisibleMsgBox && alwaysVisibleMsgBox.alwaysVisible)
|
|
{
|
|
alwaysVisibleMsgBox.AddToGUIUpdateList();
|
|
break;
|
|
}
|
|
}
|
|
for (int i = MessageBoxes.Count - 1; i >= 0; i--)
|
|
{
|
|
if (MessageBoxes[i].UserData as string == "verificationprompt" ||
|
|
MessageBoxes[i].UserData as string == "bugreporter")
|
|
{
|
|
continue;
|
|
}
|
|
if (!(MessageBoxes[i] is GUIMessageBox msgBox) || !msgBox.alwaysVisible)
|
|
{
|
|
MessageBoxes[i].AddToGUIUpdateList();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
public void SetBackgroundIcon(Sprite icon)
|
|
{
|
|
if (icon == null) { return; }
|
|
GUIImage newIcon = new GUIImage(new RectTransform(icon.size.ToPoint(), RectTransform), icon)
|
|
{
|
|
IgnoreLayoutGroups = true,
|
|
Color = Color.Transparent
|
|
};
|
|
|
|
if (newBackgroundIcon != null)
|
|
{
|
|
RemoveChild(newBackgroundIcon);
|
|
newBackgroundIcon = null;
|
|
}
|
|
newBackgroundIcon = newIcon;
|
|
}
|
|
|
|
protected override void Update(float deltaTime)
|
|
{
|
|
if (type != Type.InGame) { return; }
|
|
|
|
Vector2 initialPos = new Vector2(0.0f, GameMain.GraphicsHeight);
|
|
Vector2 defaultPos = new Vector2(0.0f, HUDLayoutSettings.InventoryAreaLower.Y - InnerFrame.Rect.Height - 20 * GUI.Scale);
|
|
Vector2 endPos = new Vector2(GameMain.GraphicsWidth, defaultPos.Y);
|
|
|
|
if (!closing)
|
|
{
|
|
Point step = Vector2.SmoothStep(initialPos, defaultPos, openState).ToPoint();
|
|
InnerFrame.RectTransform.AbsoluteOffset = step;
|
|
if (BackgroundIcon != null)
|
|
{
|
|
BackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (BackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - BackgroundIcon.Rect.Size.Y / 2);
|
|
if (!MathUtils.NearlyEqual(openState, 1.0f))
|
|
{
|
|
BackgroundIcon.Color = ToolBox.GradientLerp(openState, Color.Transparent, Color.White);
|
|
}
|
|
}
|
|
if (!(Screen.Selected is RoundSummaryScreen) && !MessageBoxes.Any(mb => mb.UserData is RoundSummary))
|
|
{
|
|
openState = Math.Min(openState + deltaTime * 2.0f, 1.0f);
|
|
}
|
|
|
|
if (GUI.MouseOn != InnerFrame && !InnerFrame.IsParentOf(GUI.MouseOn) && AutoClose)
|
|
{
|
|
inGameCloseTimer += deltaTime;
|
|
}
|
|
|
|
if (inGameCloseTimer >= inGameCloseTime)
|
|
{
|
|
Close();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
openState += deltaTime * 2.0f;
|
|
Point step = Vector2.SmoothStep(defaultPos, endPos, openState - 1.0f).ToPoint();
|
|
InnerFrame.RectTransform.AbsoluteOffset = step;
|
|
if (BackgroundIcon != null)
|
|
{
|
|
BackgroundIcon.Color *= 0.9f;
|
|
}
|
|
if (openState >= 2.0f)
|
|
{
|
|
if (Parent != null) { Parent.RemoveChild(this); }
|
|
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
|
}
|
|
}
|
|
|
|
if (newBackgroundIcon != null)
|
|
{
|
|
if (!iconSwitching)
|
|
{
|
|
if (BackgroundIcon != null)
|
|
{
|
|
BackgroundIcon.Color *= 0.9f;
|
|
if (BackgroundIcon.Color.A == 0)
|
|
{
|
|
BackgroundIcon = null;
|
|
iconSwitching = true;
|
|
RemoveChild(BackgroundIcon);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
iconSwitching = true;
|
|
}
|
|
iconState = 0;
|
|
}
|
|
else
|
|
{
|
|
newBackgroundIcon.SetAsFirstChild();
|
|
newBackgroundIcon.RectTransform.AbsoluteOffset = new Point(InnerFrame.Rect.Location.X - (int) (newBackgroundIcon.Rect.Size.X / 1.25f), (int)defaultPos.Y - newBackgroundIcon.Rect.Size.Y / 2);
|
|
newBackgroundIcon.Color = ToolBox.GradientLerp(iconState, Color.Transparent, Color.White);
|
|
if (newBackgroundIcon.Color.A == 255)
|
|
{
|
|
BackgroundIcon = newBackgroundIcon;
|
|
BackgroundIcon.SetAsFirstChild();
|
|
newBackgroundIcon = null;
|
|
iconSwitching = false;
|
|
}
|
|
|
|
iconState = Math.Min(iconState + deltaTime * 2.0f, 1.0f);
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
public void Close()
|
|
{
|
|
if (type == Type.InGame)
|
|
{
|
|
closing = true;
|
|
}
|
|
else
|
|
{
|
|
if (Parent != null) { Parent.RemoveChild(this); }
|
|
if (MessageBoxes.Contains(this)) { MessageBoxes.Remove(this); }
|
|
}
|
|
|
|
Closed = true;
|
|
}
|
|
|
|
public bool Close(GUIButton button, object obj)
|
|
{
|
|
Close();
|
|
return true;
|
|
}
|
|
|
|
public static void CloseAll()
|
|
{
|
|
MessageBoxes.Clear();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Parent does not matter. It's overridden.
|
|
/// </summary>
|
|
public void AddButton(RectTransform rectT, string text, GUIButton.OnClickedHandler onClick)
|
|
{
|
|
rectT.Parent = RectTransform;
|
|
Buttons.Add(new GUIButton(rectT, text) { OnClicked = onClick });
|
|
}
|
|
}
|
|
}
|