Unstable 0.17.0.0
This commit is contained in:
@@ -0,0 +1,187 @@
|
||||
#nullable enable
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text.RegularExpressions;
|
||||
using Microsoft.Xna.Framework;
|
||||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace Barotrauma.Steam
|
||||
{
|
||||
public partial class WorkshopMenu
|
||||
{
|
||||
private readonly struct BBWord
|
||||
{
|
||||
[Flags]
|
||||
public enum TagType
|
||||
{
|
||||
None = 0x0,
|
||||
Bold = 0x1,
|
||||
Italic = 0x2,
|
||||
Header = 0x4,
|
||||
List = 0x8,
|
||||
NewLine = 0x10
|
||||
}
|
||||
|
||||
public readonly string Text;
|
||||
public readonly Vector2 Size;
|
||||
public readonly TagType TagTypes;
|
||||
|
||||
public readonly GUIFont Font;
|
||||
|
||||
public BBWord(string text, TagType tagTypes)
|
||||
{
|
||||
Text = text;
|
||||
TagTypes = tagTypes;
|
||||
Font = tagTypes.HasFlag(TagType.Header)
|
||||
? GUIStyle.LargeFont
|
||||
: tagTypes.HasFlag(TagType.Bold)
|
||||
? GUIStyle.SubHeadingFont
|
||||
: GUIStyle.Font;
|
||||
Size = Font.MeasureString(Text);
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly Regex bbTagRegex = new Regex(@"\[(.+?)\]",
|
||||
RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
|
||||
|
||||
private static GUICustomComponent CreateBBCodeElement(string bbCode, GUIListBox container)
|
||||
{
|
||||
Point cachedContainerSize = Point.Zero;
|
||||
List<BBWord> bbWords = new List<BBWord>();
|
||||
Stack<BBWord.TagType> tagStack = new Stack<BBWord.TagType>();
|
||||
|
||||
void recalculate()
|
||||
{
|
||||
if (cachedContainerSize == container.Content.RectTransform.NonScaledSize) { return; }
|
||||
|
||||
bbWords.Clear();
|
||||
cachedContainerSize = container.Content.RectTransform.NonScaledSize;
|
||||
|
||||
var matches = new Stack<Match>(bbTagRegex.Matches(bbCode).Reverse());
|
||||
Match? nextTag = null;
|
||||
matches.TryPop(out nextTag);
|
||||
int wordStart = 0;
|
||||
BBWord.TagType currTagType;
|
||||
for (int i = 0; i < bbCode.Length; i++)
|
||||
{
|
||||
char currChar = bbCode[i];
|
||||
currTagType = tagStack.TryPeek(out var t) ? t : BBWord.TagType.None;
|
||||
|
||||
bool charIsCJK = TextManager.IsCJK($"{currChar}");
|
||||
bool wordEnd = char.IsWhiteSpace(currChar) || charIsCJK;
|
||||
int reachedTagLength = 0;
|
||||
if (nextTag is { Index: int tagIndex, Length: int tagLength }
|
||||
&& i == tagIndex)
|
||||
{
|
||||
reachedTagLength = tagLength;
|
||||
string tagStr = nextTag.Value.Replace("[", "").Replace("]", "").Trim();
|
||||
bool isClosing = tagStr.StartsWith("/");
|
||||
tagStr = tagStr.Replace("/", "").Trim().ToLowerInvariant();
|
||||
BBWord.TagType tagType = tagStr switch
|
||||
{
|
||||
"b" => BBWord.TagType.Bold,
|
||||
"i" => BBWord.TagType.Italic,
|
||||
"h1" => BBWord.TagType.Header,
|
||||
_ => BBWord.TagType.None
|
||||
};
|
||||
|
||||
if (tagType != BBWord.TagType.None)
|
||||
{
|
||||
if (isClosing)
|
||||
{
|
||||
if (currTagType == tagType)
|
||||
{
|
||||
tagStack.Pop();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
tagStack.Push(tagType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (wordEnd || reachedTagLength > 0)
|
||||
{
|
||||
string word = bbCode[wordStart..i];
|
||||
if (charIsCJK) { word = bbCode[wordStart..(i + 1)]; }
|
||||
else if (char.IsWhiteSpace(currChar) && currChar != '\n') { word += " "; }
|
||||
|
||||
if (!word.IsNullOrEmpty())
|
||||
{
|
||||
bbWords.Add(new BBWord(word, currTagType));
|
||||
}
|
||||
else if (currChar == '\n')
|
||||
{
|
||||
bbWords.Add(new BBWord("", BBWord.TagType.NewLine));
|
||||
}
|
||||
|
||||
if (reachedTagLength > 0)
|
||||
{
|
||||
i += reachedTagLength - 1;
|
||||
nextTag = matches.TryPop(out var tag) ? tag : null;
|
||||
}
|
||||
|
||||
wordStart = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
currTagType = tagStack.TryPeek(out var ft) ? ft : BBWord.TagType.None;
|
||||
string finalWord = bbCode[wordStart..];
|
||||
if (!finalWord.IsNullOrEmpty())
|
||||
{
|
||||
bbWords.Add(new BBWord(finalWord, currTagType));
|
||||
}
|
||||
}
|
||||
|
||||
void draw(SpriteBatch spriteBatch, GUICustomComponent component)
|
||||
{
|
||||
recalculate();
|
||||
Vector2 currPos = Vector2.Zero;
|
||||
Vector2 rectPos = component.Rect.Location.ToVector2();
|
||||
for (int i = 0; i < bbWords.Count; i++)
|
||||
{
|
||||
var bbWord = bbWords[i];
|
||||
if (currPos.X > 0.0f
|
||||
&& currPos.X + bbWord.Size.X >= component.Rect.Width)
|
||||
{
|
||||
//wrap because we went over width limit
|
||||
currPos = (0.0f, currPos.Y + bbWord.Size.Y);
|
||||
}
|
||||
|
||||
bbWord.Font.DrawString(
|
||||
spriteBatch,
|
||||
bbWord.Text,
|
||||
(currPos + rectPos).ToPoint().ToVector2(),
|
||||
GUIStyle.TextColorNormal,
|
||||
forceUpperCase: ForceUpperCase.No,
|
||||
italics: bbWord.TagTypes.HasFlag(BBWord.TagType.Italic));
|
||||
bool breakLine
|
||||
= bbWord.TagTypes.HasFlag(BBWord.TagType.NewLine)
|
||||
|| (i < bbWords.Count - 1 &&
|
||||
bbWords[i + 1].TagTypes.HasFlag(BBWord.TagType.Header) !=
|
||||
bbWord.TagTypes.HasFlag(BBWord.TagType.Header));
|
||||
if (breakLine)
|
||||
{
|
||||
//break line because of a header change or newline was found
|
||||
currPos = (0.0f, currPos.Y + bbWord.Size.Y);
|
||||
}
|
||||
else
|
||||
{
|
||||
currPos.X += bbWord.Size.X;
|
||||
}
|
||||
}
|
||||
|
||||
component.RectTransform.NonScaledSize
|
||||
= (component.RectTransform.NonScaledSize.X,
|
||||
(int)(currPos.Y + bbWords.LastOrDefault().Size.Y));
|
||||
component.RectTransform.RelativeSize
|
||||
= component.RectTransform.NonScaledSize.ToVector2() / component.Parent.Rect.Size.ToVector2();
|
||||
}
|
||||
|
||||
return new GUICustomComponent(new RectTransform(Vector2.One, container.Content.RectTransform),
|
||||
onDraw: draw);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user