290 lines
9.6 KiB
C#
290 lines
9.6 KiB
C#
using Barotrauma.Networking;
|
|
using Microsoft.Xna.Framework;
|
|
using Microsoft.Xna.Framework.Graphics;
|
|
using System;
|
|
using System.Text;
|
|
using System.Xml.Linq;
|
|
|
|
namespace Barotrauma.Items.Components
|
|
{
|
|
partial class ItemLabel : ItemComponent, IDrawableComponent
|
|
{
|
|
private GUITextBlock textBlock;
|
|
|
|
private Color textColor;
|
|
|
|
private float scrollAmount;
|
|
private string scrollingText;
|
|
private float scrollPadding;
|
|
private int scrollIndex;
|
|
private bool needsScrolling;
|
|
|
|
private float[] charWidths;
|
|
|
|
private Vector4 padding;
|
|
|
|
[Serialize("0,0,0,0", true, description: "The amount of padding around the text in pixels (left,top,right,bottom).")]
|
|
public Vector4 Padding
|
|
{
|
|
get { return padding; }
|
|
set
|
|
{
|
|
padding = value;
|
|
TextBlock.Padding = value * item.Scale;
|
|
}
|
|
}
|
|
|
|
private string text;
|
|
[Serialize("", true, translationTextTag: "Label.", description: "The text displayed in the label.", alwaysUseInstanceValues: true), Editable(100)]
|
|
public string Text
|
|
{
|
|
get { return text; }
|
|
set
|
|
{
|
|
if (value == text || item.Rect.Width < 5) { return; }
|
|
|
|
if (TextBlock.Rect.Width != item.Rect.Width || textBlock.Rect.Height != item.Rect.Height)
|
|
{
|
|
textBlock = null;
|
|
}
|
|
|
|
text = value;
|
|
SetDisplayText(value);
|
|
}
|
|
}
|
|
|
|
private bool ignoreLocalization;
|
|
|
|
[Editable, Serialize(false, true, "Whether or not to skip localization and always display the raw value.")]
|
|
public bool IgnoreLocalization
|
|
{
|
|
get => ignoreLocalization;
|
|
set
|
|
{
|
|
ignoreLocalization = value;
|
|
SetDisplayText(Text);
|
|
}
|
|
}
|
|
|
|
public string DisplayText
|
|
{
|
|
get;
|
|
private set;
|
|
}
|
|
|
|
[Editable, Serialize("0,0,0,255", true, description: "The color of the text displayed on the label (R,G,B,A).", alwaysUseInstanceValues: true)]
|
|
public Color TextColor
|
|
{
|
|
get { return textColor; }
|
|
set
|
|
{
|
|
if (textBlock != null) { textBlock.TextColor = value; }
|
|
textColor = value;
|
|
}
|
|
}
|
|
|
|
[Editable(0.0f, 10.0f), Serialize(1.0f, true, description: "The scale of the text displayed on the label.", alwaysUseInstanceValues: true)]
|
|
public float TextScale
|
|
{
|
|
get { return textBlock == null ? 1.0f : textBlock.TextScale; }
|
|
set
|
|
{
|
|
if (textBlock != null) { textBlock.TextScale = MathHelper.Clamp(value, 0.1f, 10.0f); }
|
|
}
|
|
}
|
|
|
|
private bool scrollable;
|
|
[Serialize(false, true, description: "Should the text scroll horizontally across the item if it's too long to be displayed all at once.")]
|
|
public bool Scrollable
|
|
{
|
|
get { return scrollable; }
|
|
set
|
|
{
|
|
scrollable = value;
|
|
IsActive = value;
|
|
TextBlock.Wrap = !scrollable;
|
|
TextBlock.TextAlignment = scrollable ? Alignment.CenterLeft : Alignment.Center;
|
|
}
|
|
}
|
|
|
|
[Serialize(20.0f, true, description: "How fast the text scrolls across the item (only valid if Scrollable is set to true).")]
|
|
public float ScrollSpeed
|
|
{
|
|
get;
|
|
set;
|
|
}
|
|
|
|
private GUITextBlock TextBlock
|
|
{
|
|
get
|
|
{
|
|
if (textBlock == null)
|
|
{
|
|
RecreateTextBlock();
|
|
}
|
|
return textBlock;
|
|
}
|
|
}
|
|
|
|
public ItemLabel(Item item, XElement element)
|
|
: base(item, element)
|
|
{
|
|
}
|
|
|
|
private void SetScrollingText()
|
|
{
|
|
if (!scrollable) { return; }
|
|
|
|
float totalWidth = textBlock.Font.MeasureString(DisplayText).X;
|
|
float textAreaWidth = Math.Max(textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z, 0);
|
|
if (totalWidth >= textAreaWidth)
|
|
{
|
|
//add enough spaces to fill the rect
|
|
//(so the text can scroll entirely out of view before we reset it back to start)
|
|
needsScrolling = true;
|
|
float spaceWidth = textBlock.Font.MeasureChar(' ').X;
|
|
scrollingText = new string(' ', (int)Math.Ceiling(textAreaWidth / spaceWidth)) + DisplayText;
|
|
}
|
|
else
|
|
{
|
|
//whole text can fit in the textblock, no need to scroll
|
|
needsScrolling = false;
|
|
scrollingText = DisplayText;
|
|
scrollPadding = 0;
|
|
scrollAmount = 0.0f;
|
|
scrollIndex = 0;
|
|
return;
|
|
}
|
|
|
|
//calculate character widths
|
|
scrollPadding = 0;
|
|
charWidths = new float[scrollingText.Length];
|
|
for (int i = 0; i < scrollingText.Length; i++)
|
|
{
|
|
float charWidth = TextBlock.Font.MeasureChar(scrollingText[i]).X;
|
|
scrollPadding = Math.Max(charWidth, scrollPadding);
|
|
charWidths[i] = charWidth;
|
|
}
|
|
|
|
scrollIndex = MathHelper.Clamp(scrollIndex, 0, DisplayText.Length);
|
|
}
|
|
|
|
private void SetDisplayText(string value)
|
|
{
|
|
DisplayText = IgnoreLocalization ? value : TextManager.Get(value, returnNull: true) ?? value;
|
|
TextBlock.Text = DisplayText;
|
|
if (Screen.Selected == GameMain.SubEditorScreen && Scrollable)
|
|
{
|
|
TextBlock.Text = ToolBox.LimitString(DisplayText, TextBlock.Font, item.Rect.Width);
|
|
}
|
|
|
|
SetScrollingText();
|
|
}
|
|
|
|
private void RecreateTextBlock()
|
|
{
|
|
textBlock = new GUITextBlock(new RectTransform(item.Rect.Size), "",
|
|
textColor: textColor, font: GUI.UnscaledSmallFont, textAlignment: scrollable ? Alignment.CenterLeft : Alignment.Center, wrap: !scrollable, style: null)
|
|
{
|
|
TextDepth = item.SpriteDepth - 0.00001f,
|
|
RoundToNearestPixel = false,
|
|
TextScale = TextScale,
|
|
Padding = padding * item.Scale
|
|
};
|
|
}
|
|
|
|
public override void Update(float deltaTime, Camera cam)
|
|
{
|
|
if (!scrollable) { return; }
|
|
|
|
if (scrollingText == null)
|
|
{
|
|
SetScrollingText();
|
|
}
|
|
|
|
if (!needsScrolling) { return; }
|
|
|
|
scrollAmount -= deltaTime * ScrollSpeed;
|
|
|
|
float currLength = 0;
|
|
StringBuilder sb = new StringBuilder();
|
|
float textAreaWidth = textBlock.Rect.Width - textBlock.Padding.X - textBlock.Padding.Z;
|
|
for (int i = scrollIndex; i < scrollingText.Length; i++)
|
|
{
|
|
//first character is out of view -> skip to next character
|
|
if (i == scrollIndex && scrollAmount < -charWidths[i])
|
|
{
|
|
scrollIndex++;
|
|
scrollAmount = 0;
|
|
if (scrollIndex >= scrollingText.Length) //reached the last character, reset
|
|
{
|
|
scrollIndex = 0;
|
|
break;
|
|
}
|
|
continue;
|
|
}
|
|
|
|
//reached the right edge, stop adding more character
|
|
if (scrollAmount + (currLength + charWidths[i] + scrollPadding) >= textAreaWidth)
|
|
{
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
currLength += charWidths[i];
|
|
sb.Append(scrollingText[i]);
|
|
}
|
|
}
|
|
|
|
TextBlock.Text = sb.ToString();
|
|
}
|
|
|
|
public override void OnScaleChanged()
|
|
{
|
|
RecreateTextBlock();
|
|
SetDisplayText(Text);
|
|
prevScale = item.Scale;
|
|
prevRect = item.Rect;
|
|
}
|
|
|
|
private float prevScale;
|
|
private Rectangle prevRect;
|
|
|
|
public void Draw(SpriteBatch spriteBatch, bool editing = false, float itemDepth = -1)
|
|
{
|
|
if (editing)
|
|
{
|
|
if (!MathUtils.NearlyEqual(prevScale, item.Scale) || prevRect != item.Rect)
|
|
{
|
|
RecreateTextBlock();
|
|
SetDisplayText(Text);
|
|
prevScale = item.Scale;
|
|
prevRect = item.Rect;
|
|
}
|
|
}
|
|
|
|
var drawPos = new Vector2(
|
|
item.DrawPosition.X - item.Rect.Width / 2.0f,
|
|
-(item.DrawPosition.Y + item.Rect.Height / 2.0f));
|
|
|
|
Rectangle worldRect = item.WorldRect;
|
|
if (worldRect.X > Screen.Selected.Cam.WorldView.Right ||
|
|
worldRect.Right < Screen.Selected.Cam.WorldView.X ||
|
|
worldRect.Y < Screen.Selected.Cam.WorldView.Y - Screen.Selected.Cam.WorldView.Height ||
|
|
worldRect.Y - worldRect.Height > Screen.Selected.Cam.WorldView.Y)
|
|
{
|
|
return;
|
|
}
|
|
|
|
textBlock.TextDepth = item.SpriteDepth - 0.0001f;
|
|
textBlock.TextOffset = drawPos - textBlock.Rect.Location.ToVector2() + (editing ? Vector2.Zero : new Vector2(scrollAmount + scrollPadding, 0.0f));
|
|
textBlock.DrawManually(spriteBatch);
|
|
}
|
|
|
|
public void ClientRead(ServerNetObject type, IReadMessage msg, float sendingTime)
|
|
{
|
|
Text = msg.ReadString();
|
|
}
|
|
}
|
|
}
|