mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-12-27 02:29:23 +01:00
document raw content and text formatting
This commit is contained in:
parent
89646b1c67
commit
e9cc9b7d99
26 changed files with 275 additions and 6 deletions
|
@ -57,6 +57,7 @@ namespace MLEM.Content {
|
|||
return reader;
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
protected override void ReloadAsset<T>(string originalAssetName, T currentAsset) {
|
||||
this.Read(originalAssetName, currentAsset);
|
||||
}
|
||||
|
@ -80,6 +81,7 @@ namespace MLEM.Content {
|
|||
throw new ContentLoadException($"Asset {assetName} not found");
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public override void Unload() {
|
||||
foreach (var d in this.disposableAssets)
|
||||
d.Dispose();
|
||||
|
@ -87,6 +89,7 @@ namespace MLEM.Content {
|
|||
base.Unload();
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public void Initialize() {
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using Microsoft.Xna.Framework.Content;
|
||||
|
||||
namespace MLEM.Content {
|
||||
/// <summary>
|
||||
|
@ -11,14 +12,14 @@ namespace MLEM.Content {
|
|||
/// Returns if the given type can be loaded by this content reader
|
||||
/// </summary>
|
||||
/// <param name="t">The type of asset</param>
|
||||
/// <returns>If <see cref="t"/> can be loaded by this content reader</returns>
|
||||
/// <returns>If the type can be loaded by this content reader</returns>
|
||||
public abstract bool CanRead(Type t);
|
||||
|
||||
/// <summary>
|
||||
/// Reads the content file from disk and returns it.
|
||||
/// </summary>
|
||||
/// <param name="manager">The <see cref="RawContentManager"/> that is loading the asset</param>
|
||||
/// <param name="assetPath">The full path to the asset, starting from the <see cref="RawContentManager.RootDirectory"/></param>
|
||||
/// <param name="assetPath">The full path to the asset, starting from the <see cref="ContentManager.RootDirectory"/></param>
|
||||
/// <param name="stream">A stream that leads to this asset</param>
|
||||
/// <param name="t">The type of asset to load</param>
|
||||
/// <param name="existing">If this asset is being reloaded, this value contains the previous version of the asset.</param>
|
||||
|
@ -50,9 +51,8 @@ namespace MLEM.Content {
|
|||
/// Reads the content file that is represented by our generic type from disk.
|
||||
/// </summary>
|
||||
/// <param name="manager">The <see cref="RawContentManager"/> that is loading the asset</param>
|
||||
/// <param name="assetPath">The full path to the asset, starting from the <see cref="RawContentManager.RootDirectory"/></param>
|
||||
/// <param name="assetPath">The full path to the asset, starting from the <see cref="ContentManager.RootDirectory"/></param>
|
||||
/// <param name="stream">A stream that leads to this asset</param>
|
||||
/// <param name="t">The type of asset to load</param>
|
||||
/// <param name="existing">If this asset is being reloaded, this value contains the previous version of the asset.</param>
|
||||
/// <returns>The loaded asset</returns>
|
||||
protected abstract T Read(RawContentManager manager, string assetPath, Stream stream, T existing);
|
||||
|
|
|
@ -3,12 +3,15 @@ using System.IO;
|
|||
using Microsoft.Xna.Framework.Media;
|
||||
|
||||
namespace MLEM.Content {
|
||||
/// <inheritdoc />
|
||||
public class SongReader : RawContentReader<Song> {
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Song Read(RawContentManager manager, string assetPath, Stream stream, Song existing) {
|
||||
return Song.FromUri(Path.GetFileNameWithoutExtension(assetPath), new Uri(assetPath));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string[] GetFileExtensions() {
|
||||
return new[] {"ogg", "wav", "mp3"};
|
||||
}
|
||||
|
|
|
@ -3,12 +3,15 @@ using System.IO;
|
|||
using Microsoft.Xna.Framework.Audio;
|
||||
|
||||
namespace MLEM.Content {
|
||||
/// <inheritdoc />
|
||||
public class SoundEffectReader : RawContentReader<SoundEffect> {
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override SoundEffect Read(RawContentManager manager, string assetPath, Stream stream, SoundEffect existing) {
|
||||
return SoundEffect.FromStream(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string[] GetFileExtensions() {
|
||||
return new[] {"ogg", "wav", "mp3"};
|
||||
}
|
||||
|
|
|
@ -2,8 +2,10 @@ using System.IO;
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MLEM.Content {
|
||||
/// <inheritdoc />
|
||||
public class Texture2DReader : RawContentReader<Texture2D> {
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override Texture2D Read(RawContentManager manager, string assetPath, Stream stream, Texture2D existing) {
|
||||
if (existing != null) {
|
||||
existing.Reload(stream);
|
||||
|
@ -13,6 +15,7 @@ namespace MLEM.Content {
|
|||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string[] GetFileExtensions() {
|
||||
return new[] {"png", "bmp", "gif", "jpg", "tif", "dds"};
|
||||
}
|
||||
|
|
|
@ -3,16 +3,20 @@ using System.IO;
|
|||
using System.Xml.Serialization;
|
||||
|
||||
namespace MLEM.Content {
|
||||
/// <inheritdoc />
|
||||
public class XmlReader : RawContentReader {
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool CanRead(Type t) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object Read(RawContentManager manager, string assetPath, Stream stream, Type t, object existing) {
|
||||
return new XmlSerializer(t).Deserialize(stream);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string[] GetFileExtensions() {
|
||||
return new[] {"xml"};
|
||||
}
|
||||
|
|
|
@ -3,6 +3,9 @@ using System.Globalization;
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing with <see cref="Color"/> objects
|
||||
/// </summary>
|
||||
public static class ColorExtensions {
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -4,6 +4,9 @@ using Microsoft.Xna.Framework;
|
|||
using Microsoft.Xna.Framework.Graphics;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing with <see cref="GraphicsDevice"/> and <see cref="GraphicsDeviceManager"/>
|
||||
/// </summary>
|
||||
public static class GraphicsExtensions {
|
||||
|
||||
private static int lastWidth;
|
||||
|
|
|
@ -3,6 +3,9 @@ using Microsoft.Xna.Framework;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing with <see cref="float"/>, <see cref="Vector2"/>, <see cref="Vector3"/>, <see cref="Vector4"/>, <see cref="Point"/>, <see cref="Rectangle"/> and <see cref="RectangleF"/>
|
||||
/// </summary>
|
||||
public static class NumberExtensions {
|
||||
|
||||
/// <inheritdoc cref="Math.Floor(decimal)"/>
|
||||
|
|
|
@ -3,6 +3,9 @@ using System.Collections.Generic;
|
|||
using System.Linq;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing with <see cref="Random"/>
|
||||
/// </summary>
|
||||
public static class RandomExtensions {
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -2,8 +2,15 @@ using System;
|
|||
using Microsoft.Xna.Framework.Audio;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing wiht <see cref="SoundEffectInstance"/>
|
||||
/// </summary>
|
||||
public static class SoundExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Stops and plays a sound effect instance in one call
|
||||
/// </summary>
|
||||
/// <param name="sound">The sound to stop and play</param>
|
||||
[Obsolete("When using the .NET Core version of MonoGame, the replay issue has been fixed. Just call Play() instead.")]
|
||||
public static void Replay(this SoundEffectInstance sound) {
|
||||
sound.Stop();
|
||||
|
|
|
@ -4,6 +4,9 @@ using MLEM.Misc;
|
|||
using MLEM.Textures;
|
||||
|
||||
namespace MLEM.Extensions {
|
||||
/// <summary>
|
||||
/// A set of extensions for dealing with <see cref="SpriteBatch"/>
|
||||
/// </summary>
|
||||
public static class SpriteBatchExtensions {
|
||||
|
||||
private static Texture2D blankTexture;
|
||||
|
|
|
@ -171,11 +171,26 @@ namespace MLEM.Font {
|
|||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// An enum that represents the text alignment options for <see cref="GenericFont.DrawString(SpriteBatch,string,Vector2,TextAlign,Color)"/>
|
||||
/// </summary>
|
||||
public enum TextAlign {
|
||||
|
||||
/// <summary>
|
||||
/// The text is aligned as normal
|
||||
/// </summary>
|
||||
Left,
|
||||
/// <summary>
|
||||
/// The position passed represents the center of the resulting string in the x axis
|
||||
/// </summary>
|
||||
Center,
|
||||
/// <summary>
|
||||
/// The position passed represents the right edge of the resulting string
|
||||
/// </summary>
|
||||
Right,
|
||||
/// <summary>
|
||||
/// The position passed represents the center of the resulting string, both in the x and y axes
|
||||
/// </summary>
|
||||
CenterBothAxes
|
||||
|
||||
}
|
||||
|
|
|
@ -8,6 +8,9 @@ namespace MLEM.Font {
|
|||
/// <inheritdoc/>
|
||||
public class GenericSpriteFont : GenericFont {
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="SpriteFont"/> that is being wrapped by this generic font
|
||||
/// </summary>
|
||||
public readonly SpriteFont Font;
|
||||
/// <inheritdoc/>
|
||||
public override GenericFont Bold { get; }
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class AnimatedCode : Code {
|
||||
|
||||
/// <inheritdoc />
|
||||
public AnimatedCode(Match match, Regex regex) : base(match, regex) {
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool EndsHere(Code other) {
|
||||
return other is AnimatedCode;
|
||||
}
|
||||
|
|
|
@ -5,43 +5,88 @@ using MLEM.Font;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <summary>
|
||||
/// An instance of a formatting code that can be used for a <see cref="TextFormatter"/>.
|
||||
/// To add a new formatting code, see <see cref="TextFormatter.Codes"/>
|
||||
/// </summary>
|
||||
public class Code : GenericDataHolder {
|
||||
|
||||
/// <summary>
|
||||
/// The regex that this code was created from
|
||||
/// </summary>
|
||||
public readonly Regex Regex;
|
||||
/// <summary>
|
||||
/// The match that this code encompasses
|
||||
/// </summary>
|
||||
public readonly Match Match;
|
||||
/// <summary>
|
||||
/// The token that this formatting code is a part of
|
||||
/// </summary>
|
||||
public Token Token { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new formatting code based on a formatting code regex and its match.
|
||||
/// </summary>
|
||||
/// <param name="match">The match</param>
|
||||
/// <param name="regex">The regex</param>
|
||||
protected Code(Match match, Regex regex) {
|
||||
this.Match = match;
|
||||
this.Regex = regex;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns whether this formatting code should end when the passed formatting code starts.
|
||||
/// If this method returns true, a new <see cref="Token"/> is started at its position.
|
||||
/// </summary>
|
||||
/// <param name="other">The code that is started here</param>
|
||||
/// <returns>If this code should end</returns>
|
||||
public virtual bool EndsHere(Code other) {
|
||||
return other.GetType() == this.GetType();
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Formatting.Token.GetColor"/>
|
||||
public virtual Color? GetColor(Color defaultPick) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Formatting.Token.GetFont"/>
|
||||
public virtual GenericFont GetFont(GenericFont defaultPick) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update this formatting code's animations etc.
|
||||
/// </summary>
|
||||
/// <param name="time">The game's time</param>
|
||||
public virtual void Update(GameTime time) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the string that this formatting code should be replaced with.
|
||||
/// Usually, you'll just want an empty string here, but some formatting codes (like <see cref="ImageCode"/>) require their space to be filled by spaces.
|
||||
/// </summary>
|
||||
/// <param name="font">The font that is used</param>
|
||||
/// <returns>The replacement string for this formatting code</returns>
|
||||
public virtual string GetReplacementString(GenericFont font) {
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Formatting.Token.DrawCharacter"/>
|
||||
public virtual bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="Formatting.Token.DrawSelf"/>
|
||||
public virtual void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new formatting code from the given regex and regex match.
|
||||
/// <seealso cref="TextFormatter.Codes"/>
|
||||
/// </summary>
|
||||
/// <param name="formatter">The text formatter that created this code</param>
|
||||
/// <param name="match">The match for the code's regex</param>
|
||||
/// <param name="regex">The regex used to create this code</param>
|
||||
public delegate Code Constructor(TextFormatter formatter, Match match, Regex regex);
|
||||
|
||||
}
|
||||
|
|
|
@ -2,14 +2,17 @@ using System.Text.RegularExpressions;
|
|||
using Microsoft.Xna.Framework;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class ColorCode : Code {
|
||||
|
||||
private readonly Color? color;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ColorCode(Match match, Regex regex, Color? color) : base(match, regex) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Color? GetColor(Color defaultPick) {
|
||||
return this.color;
|
||||
}
|
||||
|
|
|
@ -3,18 +3,22 @@ using System.Text.RegularExpressions;
|
|||
using MLEM.Font;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class FontCode : Code {
|
||||
|
||||
private readonly Func<GenericFont, GenericFont> font;
|
||||
|
||||
/// <inheritdoc />
|
||||
public FontCode(Match match, Regex regex, Func<GenericFont, GenericFont> font) : base(match, regex) {
|
||||
this.font = font;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override GenericFont GetFont(GenericFont defaultPick) {
|
||||
return this.font?.Invoke(defaultPick);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool EndsHere(Code other) {
|
||||
return other is FontCode;
|
||||
}
|
||||
|
|
|
@ -9,20 +9,24 @@ using MLEM.Misc;
|
|||
using MLEM.Textures;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class ImageCode : Code {
|
||||
|
||||
private readonly SpriteAnimation image;
|
||||
private string replacement;
|
||||
private float gapSize;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ImageCode(Match match, Regex regex, SpriteAnimation image) : base(match, regex) {
|
||||
this.image = image;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool EndsHere(Code other) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string GetReplacementString(GenericFont font) {
|
||||
if (this.replacement == null) {
|
||||
// use non-breaking space so that the image won't be line-splitted
|
||||
|
@ -33,10 +37,12 @@ namespace MLEM.Formatting.Codes {
|
|||
return this.replacement;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(GameTime time) {
|
||||
this.image.Update(time);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||
var position = pos + new Vector2(this.gapSize - font.LineHeight, 0) / 2 * scale;
|
||||
batch.Draw(this.image.CurrentRegion, new RectangleF(position, new Vector2(font.LineHeight * scale)), Color.White.CopyAlpha(color));
|
||||
|
@ -44,12 +50,22 @@ namespace MLEM.Formatting.Codes {
|
|||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A set of extensions that allow easily adding image formatting codes to a text formatter.
|
||||
/// </summary>
|
||||
public static class ImageCodeExtensions {
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new image formatting code to the given text formatter
|
||||
/// </summary>
|
||||
/// <param name="formatter">The formatter to add the code to</param>
|
||||
/// <param name="name">The name of the formatting code. The regex for this code will be between angle brackets.</param>
|
||||
/// <param name="image">The image to render at the code's position</param>
|
||||
public static void AddImage(this TextFormatter formatter, string name, TextureRegion image) {
|
||||
formatter.AddImage(name, new SpriteAnimation(1, image));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="AddImage(MLEM.Formatting.TextFormatter,string,MLEM.Textures.TextureRegion)"/>
|
||||
public static void AddImage(this TextFormatter formatter, string name, SpriteAnimation image) {
|
||||
formatter.Codes.Add(new Regex($"<i {name}>"), (f, m, r) => new ImageCode(m, r, image));
|
||||
}
|
||||
|
|
|
@ -5,18 +5,25 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
using MLEM.Font;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class LinkCode : UnderlineCode {
|
||||
|
||||
private readonly Func<Token, bool> isSelected;
|
||||
|
||||
/// <inheritdoc />
|
||||
public LinkCode(Match match, Regex regex, float thickness, float yOffset, Func<Token, bool> isSelected) : base(match, regex, thickness, yOffset) {
|
||||
this.isSelected = isSelected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this link formatting code is currently selected or hovered over, based on the selection function.
|
||||
/// </summary>
|
||||
/// <returns>True if this code is currently selected</returns>
|
||||
public virtual bool IsSelected() {
|
||||
return this.isSelected(this.Token);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||
// since we inherit from UnderlineCode, we can just call base if selected
|
||||
return this.IsSelected() && base.DrawCharacter(time, batch, c, cString, indexInToken, ref pos, font, ref color, ref scale, depth);
|
||||
|
|
|
@ -5,16 +5,19 @@ using MLEM.Extensions;
|
|||
using MLEM.Font;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class ShadowCode : FontCode {
|
||||
|
||||
private readonly Color color;
|
||||
private readonly Vector2 offset;
|
||||
|
||||
/// <inheritdoc />
|
||||
public ShadowCode(Match match, Regex regex, Color color, Vector2 offset) : base(match, regex, null) {
|
||||
this.color = color;
|
||||
this.offset = offset;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||
font.DrawString(batch, cString, pos + this.offset * scale, this.color.CopyAlpha(color), 0, Vector2.Zero, scale, SpriteEffects.None, depth);
|
||||
// we return false since we still want regular drawing to occur
|
||||
|
|
|
@ -6,16 +6,19 @@ using MLEM.Font;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class UnderlineCode : FontCode {
|
||||
|
||||
private readonly float thickness;
|
||||
private readonly float yOffset;
|
||||
|
||||
/// <inheritdoc />
|
||||
public UnderlineCode(Match match, Regex regex, float thickness, float yOffset) : base(match, regex, null) {
|
||||
this.thickness = thickness;
|
||||
this.yOffset = yOffset;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||
// don't underline spaces at the end of lines
|
||||
if (c == ' ' && this.Token.DisplayString.Length > indexInToken + 1 && this.Token.DisplayString[indexInToken + 1] == '\n')
|
||||
|
|
|
@ -5,21 +5,29 @@ using Microsoft.Xna.Framework.Graphics;
|
|||
using MLEM.Font;
|
||||
|
||||
namespace MLEM.Formatting.Codes {
|
||||
/// <inheritdoc />
|
||||
public class WobblyCode : AnimatedCode {
|
||||
|
||||
private readonly float modifier;
|
||||
private readonly float heightModifier;
|
||||
/// <summary>
|
||||
/// The time that this wobbly animation has been running for.
|
||||
/// To reset its animation progress, reset this value.
|
||||
/// </summary>
|
||||
public TimeSpan TimeIntoAnimation;
|
||||
|
||||
/// <inheritdoc />
|
||||
public WobblyCode(Match match, Regex regex, float modifier, float heightModifier) : base(match, regex) {
|
||||
this.modifier = modifier;
|
||||
this.heightModifier = heightModifier;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Update(GameTime time) {
|
||||
this.TimeIntoAnimation += time.ElapsedGameTime;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, ref Vector2 pos, GenericFont font, ref Color color, ref float scale, float depth) {
|
||||
var offset = new Vector2(0, (float) Math.Sin(this.Token.Index + indexInToken + this.TimeIntoAnimation.TotalSeconds * this.modifier) * font.LineHeight * this.heightModifier * scale);
|
||||
pos += offset;
|
||||
|
|
|
@ -10,10 +10,21 @@ using MLEM.Formatting.Codes;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Formatting {
|
||||
/// <summary>
|
||||
/// A text formatter is used for drawing text using <see cref="GenericFont"/> that contains different colors, bold/italic sections and animations.
|
||||
/// To format a string of text, use the codes as specified in the constructor. To tokenize and render a formatted string, use <see cref="Tokenize"/>.
|
||||
/// </summary>
|
||||
public class TextFormatter : GenericDataHolder {
|
||||
|
||||
/// <summary>
|
||||
/// The formatting codes that this text formatter uses.
|
||||
/// The <see cref="Regex"/> defines how the formatting code should be matched.
|
||||
/// </summary>
|
||||
public readonly Dictionary<Regex, Code.Constructor> Codes = new Dictionary<Regex, Code.Constructor>();
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new text formatter with a set of default formatting codes.
|
||||
/// </summary>
|
||||
public TextFormatter() {
|
||||
// font codes
|
||||
this.Codes.Add(new Regex("<b>"), (f, m, r) => new FontCode(m, r, fnt => fnt.Bold));
|
||||
|
@ -37,6 +48,12 @@ namespace MLEM.Formatting {
|
|||
this.Codes.Add(new Regex("</a>"), (f, m, r) => new AnimatedCode(m, r));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tokenizes a string, returning a tokenized string that is ready for splitting, measuring and drawing.
|
||||
/// </summary>
|
||||
/// <param name="font">The font to use for tokenization. Note that this font needs to be the same that will later be used for splitting, measuring and/or drawing.</param>
|
||||
/// <param name="s">The string to tokenize</param>
|
||||
/// <returns></returns>
|
||||
public TokenizedString Tokenize(GenericFont font, string s) {
|
||||
var tokens = new List<Token>();
|
||||
var codes = new List<Code>();
|
||||
|
|
|
@ -8,18 +8,39 @@ using MLEM.Formatting.Codes;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Formatting {
|
||||
/// <summary>
|
||||
/// A part of a <see cref="TokenizedString"/> that has a certain list of formatting codes applied.
|
||||
/// </summary>
|
||||
public class Token : GenericDataHolder {
|
||||
|
||||
/// <summary>
|
||||
/// The formatting codes that are applied on this token.
|
||||
/// </summary>
|
||||
public readonly Code[] AppliedCodes;
|
||||
/// <summary>
|
||||
/// The index in the <see cref="Substring"/> that this token starts at.
|
||||
/// </summary>
|
||||
public readonly int Index;
|
||||
/// <summary>
|
||||
/// The index in the <see cref="RawSubstring"/> that this token starts at.
|
||||
/// </summary>
|
||||
public readonly int RawIndex;
|
||||
/// <summary>
|
||||
/// The substring that this token contains.
|
||||
/// </summary>
|
||||
public readonly string Substring;
|
||||
/// <summary>
|
||||
/// The string that is displayed by this token. If the tokenized string has been split, this string will contain the newline characters.
|
||||
/// </summary>
|
||||
public string DisplayString => this.SplitSubstring ?? this.Substring;
|
||||
/// <summary>
|
||||
/// The substring that this token contains, without the formatting codes removed.
|
||||
/// </summary>
|
||||
public readonly string RawSubstring;
|
||||
internal RectangleF[] Area;
|
||||
internal string SplitSubstring;
|
||||
|
||||
public Token(Code[] appliedCodes, int index, int rawIndex, string substring, string rawSubstring) {
|
||||
internal Token(Code[] appliedCodes, int index, int rawIndex, string substring, string rawSubstring) {
|
||||
this.AppliedCodes = appliedCodes;
|
||||
this.Index = index;
|
||||
this.RawIndex = rawIndex;
|
||||
|
@ -30,19 +51,53 @@ namespace MLEM.Formatting {
|
|||
code.Token = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the color that this token will be rendered with
|
||||
/// </summary>
|
||||
/// <param name="defaultPick">The default color, if none is specified</param>
|
||||
/// <returns>The color to render with</returns>
|
||||
public Color? GetColor(Color defaultPick) {
|
||||
return this.AppliedCodes.Select(c => c.GetColor(defaultPick)).FirstOrDefault(c => c.HasValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the font that this token will be rendered with
|
||||
/// </summary>
|
||||
/// <param name="defaultPick">The default font, if none is specified</param>
|
||||
/// <returns>The font to render with</returns>
|
||||
public GenericFont GetFont(GenericFont defaultPick) {
|
||||
return this.AppliedCodes.Select(c => c.GetFont(defaultPick)).FirstOrDefault(f => f != null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws the token itself, including all of the <see cref="Code"/> instances that this token contains.
|
||||
/// Note that, to draw the token's actual string, <see cref="DrawCharacter"/> is used.
|
||||
/// </summary>
|
||||
/// <param name="time">The time</param>
|
||||
/// <param name="batch">The sprite batch to use</param>
|
||||
/// <param name="pos">The position to draw the token at</param>
|
||||
/// <param name="font">The font to use to draw</param>
|
||||
/// <param name="color">The color to draw with</param>
|
||||
/// <param name="scale">The scale to draw at</param>
|
||||
/// <param name="depth">The depth to draw at</param>
|
||||
public void DrawSelf(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||
foreach (var code in this.AppliedCodes)
|
||||
code.DrawSelf(time, batch, pos, font, color, scale, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Draws a given character using this token's formatting options.
|
||||
/// </summary>
|
||||
/// <param name="time">The time</param>
|
||||
/// <param name="batch">The sprite batch to use</param>
|
||||
/// <param name="c">The character to draw</param>
|
||||
/// <param name="cString">A single-character string that contains the character to draw</param>
|
||||
/// <param name="indexInToken">The index within this token that the character is at</param>
|
||||
/// <param name="pos">The position to draw the token at</param>
|
||||
/// <param name="font">The font to use to draw</param>
|
||||
/// <param name="color">The color to draw with</param>
|
||||
/// <param name="scale">The scale to draw at</param>
|
||||
/// <param name="depth">The depth to draw at</param>
|
||||
public void DrawCharacter(GameTime time, SpriteBatch batch, char c, string cString, int indexInToken, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||
foreach (var code in this.AppliedCodes) {
|
||||
if (code.DrawCharacter(time, batch, c, cString, indexInToken, ref pos, font, ref color, ref scale, depth))
|
||||
|
@ -53,6 +108,14 @@ namespace MLEM.Formatting {
|
|||
font.DrawString(batch, cString, pos, color, 0, Vector2.Zero, scale, SpriteEffects.None, depth);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list of rectangles that encompass this token's area.
|
||||
/// Note that more than one rectangle is only returned if the string has been split.
|
||||
/// This can be used to invoke events when the mouse is hovered over the token, for example.
|
||||
/// </summary>
|
||||
/// <param name="stringPos">The position that the string is drawn at</param>
|
||||
/// <param name="scale">The scale that the string is drawn at</param>
|
||||
/// <returns>A set of rectangles that this token contains</returns>
|
||||
public IEnumerable<RectangleF> GetArea(Vector2 stringPos, float scale) {
|
||||
return this.Area.Select(a => new RectangleF(stringPos + a.Location * scale, a.Size * scale));
|
||||
}
|
||||
|
|
|
@ -9,16 +9,36 @@ using MLEM.Formatting.Codes;
|
|||
using MLEM.Misc;
|
||||
|
||||
namespace MLEM.Formatting {
|
||||
/// <summary>
|
||||
/// A tokenized string that was created using a <see cref="TextFormatter"/>
|
||||
/// </summary>
|
||||
public class TokenizedString : GenericDataHolder {
|
||||
|
||||
/// <summary>
|
||||
/// The raw string that was used to create this tokenized string.
|
||||
/// </summary>
|
||||
public readonly string RawString;
|
||||
/// <summary>
|
||||
/// The <see cref="RawString"/>, but with formatting codes stripped out.
|
||||
/// </summary>
|
||||
public readonly string String;
|
||||
/// <summary>
|
||||
/// The string that is actually displayed by this tokenized string.
|
||||
/// If this string has been <see cref="Split"/>, this string will contain the newline characters.
|
||||
/// </summary>
|
||||
public string DisplayString => this.splitString ?? this.String;
|
||||
/// <summary>
|
||||
/// The tokens that this tokenized string contains.
|
||||
/// </summary>
|
||||
public readonly Token[] Tokens;
|
||||
/// <summary>
|
||||
/// All of the formatting codes that are applied over this tokenized string.
|
||||
/// Note that, to get a formatting code for a certain token, use <see cref="Token.AppliedCodes"/>
|
||||
/// </summary>
|
||||
public readonly Code[] AllCodes;
|
||||
private string splitString;
|
||||
|
||||
public TokenizedString(GenericFont font, string rawString, string strg, Token[] tokens) {
|
||||
internal TokenizedString(GenericFont font, string rawString, string strg, Token[] tokens) {
|
||||
this.RawString = rawString;
|
||||
this.String = strg;
|
||||
this.Tokens = tokens;
|
||||
|
@ -27,6 +47,13 @@ namespace MLEM.Formatting {
|
|||
this.CalculateTokenAreas(font);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Splits this tokenized string, inserting newline characters if the width of the string is bigger than the maximum width.
|
||||
/// <seealso cref="GenericFont.SplitString"/>
|
||||
/// </summary>
|
||||
/// <param name="font">The font to use for width calculations</param>
|
||||
/// <param name="width">The maximum width</param>
|
||||
/// <param name="scale">The scale to use fr width calculations</param>
|
||||
public void Split(GenericFont font, float width, float scale) {
|
||||
// a split string has the same character count as the input string
|
||||
// but with newline characters added
|
||||
|
@ -57,19 +84,33 @@ namespace MLEM.Formatting {
|
|||
this.CalculateTokenAreas(font);
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GenericFont.MeasureString(string)"/>
|
||||
public Vector2 Measure(GenericFont font) {
|
||||
return font.MeasureString(this.DisplayString);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the formatting codes in this formatted string, causing animations to animate etc.
|
||||
/// </summary>
|
||||
/// <param name="time">The game's time</param>
|
||||
public void Update(GameTime time) {
|
||||
foreach (var code in this.AllCodes)
|
||||
code.Update(time);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the token under the given position.
|
||||
/// This can be used for hovering effects when the mouse is over a token, etc.
|
||||
/// </summary>
|
||||
/// <param name="stringPos">The position that the string is drawn at</param>
|
||||
/// <param name="target">The position to use for checking the token</param>
|
||||
/// <param name="scale">The scale that the string is drawn at</param>
|
||||
/// <returns>The token under the target position</returns>
|
||||
public Token GetTokenUnderPos(Vector2 stringPos, Vector2 target, float scale) {
|
||||
return this.Tokens.FirstOrDefault(t => t.GetArea(stringPos, scale).Any(r => r.Contains(target)));
|
||||
}
|
||||
|
||||
/// <inheritdoc cref="GenericFont.DrawString(SpriteBatch,string,Vector2,Color,float,Vector2,float,SpriteEffects,float)"/>
|
||||
public void Draw(GameTime time, SpriteBatch batch, Vector2 pos, GenericFont font, Color color, float scale, float depth) {
|
||||
var innerOffset = new Vector2();
|
||||
foreach (var token in this.Tokens) {
|
||||
|
|
Loading…
Reference in a new issue