2020-05-15 00:34:04 +02:00
using System.Collections.Generic ;
using System.Linq ;
using Microsoft.Xna.Framework ;
using Microsoft.Xna.Framework.Graphics ;
using MLEM.Font ;
using MLEM.Formatting.Codes ;
2020-05-15 14:22:33 +02:00
using MLEM.Misc ;
2020-05-15 00:34:04 +02:00
namespace MLEM.Formatting {
2020-05-21 12:53:42 +02:00
/// <summary>
/// A part of a <see cref="TokenizedString"/> that has a certain list of formatting codes applied.
/// </summary>
2020-05-15 14:22:33 +02:00
public class Token : GenericDataHolder {
2020-05-15 00:34:04 +02:00
2020-05-21 12:53:42 +02:00
/// <summary>
/// The formatting codes that are applied on this token.
/// </summary>
2020-05-15 00:34:04 +02:00
public readonly Code [ ] AppliedCodes ;
2020-05-21 12:53:42 +02:00
/// <summary>
/// The index in the <see cref="Substring"/> that this token starts at.
/// </summary>
2020-05-15 00:34:04 +02:00
public readonly int Index ;
2020-05-21 12:53:42 +02:00
/// <summary>
/// The index in the <see cref="RawSubstring"/> that this token starts at.
/// </summary>
2020-05-15 00:34:04 +02:00
public readonly int RawIndex ;
2020-05-21 12:53:42 +02:00
/// <summary>
/// The substring that this token contains.
/// </summary>
2020-05-17 00:10:29 +02:00
public readonly string Substring ;
2020-05-21 12:53:42 +02:00
/// <summary>
2021-05-18 16:47:38 +02:00
/// The string that is displayed by this token. If the tokenized string has been <see cref="TokenizedString.Split"/> or <see cref="TokenizedString.Truncate"/> has been used, this string will contain the newline characters.
2020-05-21 12:53:42 +02:00
/// </summary>
2021-05-18 16:47:38 +02:00
public string DisplayString = > this . ModifiedSubstring ? ? this . Substring ;
2020-05-21 12:53:42 +02:00
/// <summary>
2021-06-25 15:23:30 +02:00
/// The <see cref="DisplayString"/>, but split at newline characters
/// </summary>
public string [ ] SplitDisplayString { get ; internal set ; }
/// <summary>
2020-05-21 12:53:42 +02:00
/// The substring that this token contains, without the formatting codes removed.
/// </summary>
2020-05-15 00:34:04 +02:00
public readonly string RawSubstring ;
2020-05-17 00:10:29 +02:00
internal RectangleF [ ] Area ;
2021-05-18 16:47:38 +02:00
internal string ModifiedSubstring ;
2021-10-04 23:57:58 +02:00
internal float [ ] InnerOffsets ;
2020-05-15 00:34:04 +02:00
2020-05-21 12:53:42 +02:00
internal Token ( Code [ ] appliedCodes , int index , int rawIndex , string substring , string rawSubstring ) {
2020-05-15 00:34:04 +02:00
this . AppliedCodes = appliedCodes ;
this . Index = index ;
this . RawIndex = rawIndex ;
this . Substring = substring ;
this . RawSubstring = rawSubstring ;
2020-05-15 22:15:24 +02:00
2020-05-15 00:34:04 +02:00
foreach ( var code in appliedCodes )
code . Token = this ;
}
2020-05-21 12:53:42 +02:00
/// <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>
2021-11-27 23:35:37 +01:00
public Color GetColor ( Color defaultPick ) {
foreach ( var code in this . AppliedCodes ) {
var color = code . GetColor ( defaultPick ) ;
if ( color . HasValue )
return color . Value ;
}
return defaultPick ;
2020-05-15 00:34:04 +02:00
}
2020-05-21 12:53:42 +02:00
/// <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>
2020-05-17 00:10:29 +02:00
public GenericFont GetFont ( GenericFont defaultPick ) {
2021-11-27 23:35:37 +01:00
foreach ( var code in this . AppliedCodes ) {
var font = code . GetFont ( defaultPick ) ;
if ( font ! = null )
return font ;
}
return defaultPick ;
2020-05-15 00:34:04 +02:00
}
2020-05-21 12:53:42 +02:00
/// <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>
2020-05-15 19:56:16 +02:00
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 ) ;
}
2020-05-21 12:53:42 +02:00
/// <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>
2020-05-15 14:22:33 +02:00
public void DrawCharacter ( GameTime time , SpriteBatch batch , char c , string cString , int indexInToken , Vector2 pos , GenericFont font , Color color , float scale , float depth ) {
2020-05-15 00:34:04 +02:00
foreach ( var code in this . AppliedCodes ) {
2020-05-15 14:22:33 +02:00
if ( code . DrawCharacter ( time , batch , c , cString , indexInToken , ref pos , font , ref color , ref scale , depth ) )
2020-05-15 00:34:04 +02:00
return ;
}
// if no code drew, we have to do it ourselves
font . DrawString ( batch , cString , pos , color , 0 , Vector2 . Zero , scale , SpriteEffects . None , depth ) ;
}
2020-05-21 12:53:42 +02:00
/// <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>
2020-05-17 00:10:29 +02:00
public IEnumerable < RectangleF > GetArea ( Vector2 stringPos , float scale ) {
return this . Area . Select ( a = > new RectangleF ( stringPos + a . Location * scale , a . Size * scale ) ) ;
}
2020-05-15 00:34:04 +02:00
}
}