1
0
Fork 0
mirror of https://github.com/Ellpeck/MLEM.git synced 2024-05-23 17:13:38 +02:00

added link formatting codes!

This commit is contained in:
Ellpeck 2020-05-15 22:15:24 +02:00
parent 9ce01bc6f2
commit 7f0a8289e3
7 changed files with 79 additions and 7 deletions

View file

@ -61,7 +61,7 @@ namespace Demos {
IsHidden = true
});
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' source code for more in-depth explanations of their functionality."));
selection.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Select the demo you want to see below using your mouse, touch input, your keyboard or a controller. Check the demos' <c CornflowerBlue><l https://github.com/Ellpeck/MLEM/tree/master/Demos>source code</l></c> for more in-depth explanations of their functionality or the <c CornflowerBlue><l https://github.com/Ellpeck/MLEM/wiki>wiki</l></c> for tutorials."));
selection.AddChild(new VerticalSpace(5));
foreach (var demo in Demos) {
selection.AddChild(new Button(Anchor.AutoCenter, new Vector2(1, 10), demo.Key, demo.Value.Item1) {

View file

@ -2,11 +2,14 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text.RegularExpressions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Extensions;
using MLEM.Font;
using MLEM.Formatting;
using MLEM.Formatting.Codes;
using MLEM.Input;
using MLEM.Misc;
using MLEM.Textures;
using MLEM.Ui.Style;
@ -25,6 +28,7 @@ namespace MLEM.Ui.Elements {
public StyleProp<FormatSettings> FormatSettings;
public readonly TextFormatter Formatter;
public TokenizedString TokenizedText { get; private set; }
public Token HoveredToken { get; private set; }
public StyleProp<Color> TextColor;
public StyleProp<float> TextScale;
@ -42,6 +46,7 @@ namespace MLEM.Ui.Elements {
public TextCallback GetTextCallback;
[Obsolete("Use the new text formatting system in MLEM.Formatting instead")]
public TextModifier RenderedTextModifier = text => text;
[Obsolete("Use the new text formatting system in MLEM.Formatting instead")]
public TimeSpan TimeIntoAnimation;
public Paragraph(Anchor anchor, float width, TextCallback textCallback, bool centerText = false)
@ -59,7 +64,17 @@ namespace MLEM.Ui.Elements {
this.AutoAdjustWidth = centerText;
this.CanBeSelected = false;
this.CanBeMoused = false;
this.Formatter = new TextFormatter(() => this.BoldFont, () => this.ItalicFont);
this.Formatter.Codes.Add(new Regex("<l ([^>]+)>"), (f, m, r) => new LinkCode(m, r, 1 / 16F, 0.85F, t => t == this.HoveredToken, l => {
if (!this.Input.IsPressed(MouseButton.Left))
return;
try {
Process.Start(l.Match.Groups[1].Value);
} catch (Exception) {
// ignored
}
}));
}
protected override Vector2 CalcActualSize(RectangleF parentArea) {
@ -76,6 +91,8 @@ namespace MLEM.Ui.Elements {
this.TokenizedText = this.Formatter.Tokenize(this.RegularFont, this.text);
this.TokenizedText.Split(this.RegularFont, size.X - this.ScaledPadding.Width, sc);
this.CanBeMoused = this.TokenizedText.AllCodes.OfType<LinkCode>().Any();
var dims = this.TokenizedText.Measure(this.RegularFont) * sc;
return new Vector2(this.AutoAdjustWidth ? dims.X + this.ScaledPadding.Width : size.X, dims.Y + this.ScaledPadding.Height);
}
@ -91,7 +108,11 @@ namespace MLEM.Ui.Elements {
if (this.GetTextCallback != null)
this.Text = this.GetTextCallback(this);
this.TimeIntoAnimation += time.ElapsedGameTime;
this.TokenizedText?.Update(time);
if (this.TokenizedText != null) {
this.TokenizedText.Update(time);
this.HoveredToken = this.TokenizedText.GetTokenUnderPos(this.RegularFont, this.DisplayArea.Location, this.Input.MousePosition.ToVector2(), this.TextScale * this.Scale);
}
}
public override void Draw(GameTime time, SpriteBatch batch, float alpha, BlendState blendState, SamplerState samplerState, Matrix matrix) {

View file

@ -0,0 +1,29 @@
using System;
using System.Text.RegularExpressions;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using MLEM.Font;
namespace MLEM.Formatting.Codes {
public class LinkCode : UnderlineCode {
private readonly Action<LinkCode> onSelected;
private readonly Func<Token, bool> isSelected;
public LinkCode(Match match, Regex regex, float thickness, float yOffset, Func<Token, bool> isSelected, Action<LinkCode> onSelected) : base(match, regex, thickness, yOffset) {
this.onSelected = onSelected;
this.isSelected = isSelected;
}
public override void Update(GameTime time) {
if (this.isSelected(this.Token))
this.onSelected(this);
}
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(this.Token) && base.DrawCharacter(time, batch, c, cString, indexInToken, ref pos, font, ref color, ref scale, depth);
}
}
}

View file

@ -20,8 +20,9 @@ namespace MLEM.Formatting.Codes {
// don't underline spaces at the end of lines
if (c == ' ' && this.Token.Substring.Length > indexInToken + 1 && this.Token.Substring[indexInToken + 1] == '\n')
return false;
var width = font.MeasureString(cString).X * scale;
batch.Draw(batch.GetBlankTexture(), new RectangleF(pos.X, pos.Y + this.yOffset * font.LineHeight - this.thickness * scale, width, this.thickness * scale), color);
var size = font.MeasureString(cString) * scale;
var thicc = size.Y * this.thickness;
batch.Draw(batch.GetBlankTexture(), new RectangleF(pos.X, pos.Y + this.yOffset * size.Y - thicc, size.X, thicc), color);
return false;
}

View file

@ -19,8 +19,8 @@ namespace MLEM.Formatting {
this.Codes.Add(new Regex("<b>"), (f, m, r) => new FontCode(m, r, boldFont?.Invoke()));
this.Codes.Add(new Regex("<i>"), (f, m, r) => new FontCode(m, r, italicFont?.Invoke()));
this.Codes.Add(new Regex(@"<s(?: #([0-9\w]{6,8}) (([+-.0-9]*)))?>"), (f, m, r) => new ShadowCode(m, r, m.Groups[1].Success ? ColorExtensions.FromHex(m.Groups[1].Value) : Color.Black, new Vector2(float.TryParse(m.Groups[2].Value, out var offset) ? offset : 2)));
this.Codes.Add(new Regex("<u>"), (f, m, r) => new UnderlineCode(m, r, 2, 0.85F));
this.Codes.Add(new Regex("</(b|i|s|u)>"), (f, m, r) => new FontCode(m, r, null));
this.Codes.Add(new Regex("<u>"), (f, m, r) => new UnderlineCode(m, r, 1 / 16F, 0.85F));
this.Codes.Add(new Regex("</(b|i|s|u|l)>"), (f, m, r) => new FontCode(m, r, null));
// color codes
foreach (var c in typeof(Color).GetProperties()) {

View file

@ -22,7 +22,7 @@ namespace MLEM.Formatting {
this.RawIndex = rawIndex;
this.Substring = substring;
this.RawSubstring = rawSubstring;
foreach (var code in appliedCodes)
code.Token = this;
}

View file

@ -61,6 +61,27 @@ namespace MLEM.Formatting {
code.Update(time);
}
public Token GetTokenUnderPos(GenericFont font, Vector2 stringPos, Vector2 target, float scale) {
var innerOffset = new Vector2();
foreach (var token in this.Tokens) {
var split = token.Substring.Split('\n');
for (var i = 0; i < split.Length; i++) {
var size = font.MeasureString(split[i]) * scale;
var lineArea = new RectangleF(stringPos + innerOffset, size);
if (lineArea.Contains(target))
return token;
if (i < split.Length - 1) {
innerOffset.X = 0;
innerOffset.Y += font.LineHeight * scale;
} else {
innerOffset.X += size.X;
}
}
}
return null;
}
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) {