mirror of
https://github.com/Ellpeck/MLEM.git
synced 2024-11-26 06:28:35 +01:00
added the ability to display images in paragraphs
This commit is contained in:
parent
e39394bce3
commit
35ee509eac
4 changed files with 96 additions and 53 deletions
|
@ -11,6 +11,7 @@ using MLEM.Startup;
|
||||||
using MLEM.Textures;
|
using MLEM.Textures;
|
||||||
using MLEM.Ui;
|
using MLEM.Ui;
|
||||||
using MLEM.Ui.Elements;
|
using MLEM.Ui.Elements;
|
||||||
|
using MLEM.Ui.Format;
|
||||||
using MLEM.Ui.Style;
|
using MLEM.Ui.Style;
|
||||||
|
|
||||||
namespace Demos {
|
namespace Demos {
|
||||||
|
@ -33,6 +34,7 @@ namespace Demos {
|
||||||
public override void LoadContent() {
|
public override void LoadContent() {
|
||||||
this.testTexture = LoadContent<Texture2D>("Textures/Test");
|
this.testTexture = LoadContent<Texture2D>("Textures/Test");
|
||||||
this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8);
|
this.testPatch = new NinePatch(new TextureRegion(this.testTexture, 0, 8, 24, 24), 8);
|
||||||
|
var tree = new TextureRegion(LoadContent<Texture2D>("Textures/Tree"));
|
||||||
base.LoadContent();
|
base.LoadContent();
|
||||||
|
|
||||||
// create a new style
|
// create a new style
|
||||||
|
@ -90,9 +92,16 @@ namespace Demos {
|
||||||
});
|
});
|
||||||
|
|
||||||
root.AddChild(new VerticalSpace(3));
|
root.AddChild(new VerticalSpace(3));
|
||||||
|
|
||||||
// a paragraph with formatting codes. To see them all or to add more, check the TextFormatting class
|
// a paragraph with formatting codes. To see them all or to add more, check the TextFormatting class
|
||||||
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain [Blue]formatting codes[White], including colors and [Italic]text styles[Regular]. The names of all [Orange]MonoGame Colors[White] can be used, as well as the codes [Italic]Italic[Regular] and [Bold]Bold[Regular]. \n[Italic]Even [CornflowerBlue]Cornflower Blue[White] works!"));
|
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Paragraphs can also contain [Blue]formatting codes[White], including colors and [Italic]text styles[Regular]. The names of all [Orange]MonoGame Colors[White] can be used, as well as the codes [Italic]Italic[Regular] and [Bold]Bold[Regular]. \n[Italic]Even [CornflowerBlue]Cornflower Blue[White] works!"));
|
||||||
|
|
||||||
|
// adding some custom image formatting codes
|
||||||
|
// note that all added formatting codes need to be lowercase, while their casing doesn't matter when used
|
||||||
|
TextFormatting.FormattingCodes["grass"] = new FormattingCode(image.Texture);
|
||||||
|
TextFormatting.FormattingCodes["tree"] = new FormattingCode(tree);
|
||||||
|
root.AddChild(new Paragraph(Anchor.AutoLeft, 1, "Additionally, you can create custom formatting codes that contain [Grass] images! Note that these images have to be square, or [Tree] bad things happen."));
|
||||||
|
|
||||||
root.AddChild(new VerticalSpace(3));
|
root.AddChild(new VerticalSpace(3));
|
||||||
root.AddChild(new Paragraph(Anchor.AutoCenter, 1, "Text input:", true));
|
root.AddChild(new Paragraph(Anchor.AutoCenter, 1, "Text input:", true));
|
||||||
root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 10)) {
|
root.AddChild(new TextField(Anchor.AutoLeft, new Vector2(1, 10)) {
|
||||||
|
@ -170,8 +179,7 @@ namespace Demos {
|
||||||
PositionOffset = new Vector2(0, 1)
|
PositionOffset = new Vector2(0, 1)
|
||||||
});
|
});
|
||||||
|
|
||||||
var region = new TextureRegion(LoadContent<Texture2D>("Textures/Tree"));
|
root.AddChild(ElementHelper.ImageButton(Anchor.AutoLeft, new Vector2(1, 10), tree, "Button with image")).PositionOffset = new Vector2(0, 1);
|
||||||
root.AddChild(ElementHelper.ImageButton(Anchor.AutoLeft, new Vector2(1, 10), region, "Button with image")).PositionOffset = new Vector2(0, 1);
|
|
||||||
|
|
||||||
// Below are some querying examples that help you find certain elements easily
|
// Below are some querying examples that help you find certain elements easily
|
||||||
|
|
||||||
|
|
|
@ -77,44 +77,8 @@ namespace MLEM.Ui.Elements {
|
||||||
if (this.codeLocations.Count <= 0) {
|
if (this.codeLocations.Count <= 0) {
|
||||||
this.regularFont.DrawString(batch, this.splitText, pos, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
this.regularFont.DrawString(batch, this.splitText, pos, this.TextColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
||||||
} else {
|
} else {
|
||||||
// if we have formatting codes, we need to go through each index and see how it should be drawn
|
// if we have formatting codes, we should do it
|
||||||
var characterCounter = 0;
|
this.regularFont.DrawFormattedString(batch, pos, this.splitText, this.codeLocations, this.TextColor * alpha, sc, this.boldFont, this.italicFont);
|
||||||
var currColor = this.TextColor;
|
|
||||||
var currFont = this.regularFont;
|
|
||||||
|
|
||||||
var innerOffset = new Vector2();
|
|
||||||
foreach (var c in this.splitText) {
|
|
||||||
// check if the current character's index has a formatting code
|
|
||||||
this.codeLocations.TryGetValue(characterCounter, out var code);
|
|
||||||
if (code != null) {
|
|
||||||
// if so, apply it
|
|
||||||
if (code.IsColorCode) {
|
|
||||||
currColor = code.Color;
|
|
||||||
} else {
|
|
||||||
switch (code.Style) {
|
|
||||||
case TextStyle.Regular:
|
|
||||||
currFont = this.regularFont;
|
|
||||||
break;
|
|
||||||
case TextStyle.Bold:
|
|
||||||
currFont = this.boldFont;
|
|
||||||
break;
|
|
||||||
case TextStyle.Italic:
|
|
||||||
currFont = this.italicFont;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
characterCounter++;
|
|
||||||
|
|
||||||
var cSt = c.ToString();
|
|
||||||
if (c == '\n') {
|
|
||||||
innerOffset.X = 0;
|
|
||||||
innerOffset.Y += this.regularFont.LineHeight * sc;
|
|
||||||
} else {
|
|
||||||
currFont.DrawString(batch, cSt, pos + innerOffset, currColor * alpha, 0, Vector2.Zero, sc, SpriteEffects.None, 0);
|
|
||||||
innerOffset.X += this.regularFont.MeasureString(cSt).X * sc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
base.Draw(time, batch, alpha);
|
base.Draw(time, batch, alpha);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,20 +1,40 @@
|
||||||
|
using System;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using MLEM.Textures;
|
||||||
|
|
||||||
namespace MLEM.Ui.Format {
|
namespace MLEM.Ui.Format {
|
||||||
public class FormattingCode {
|
public class FormattingCode {
|
||||||
|
|
||||||
|
public readonly Type CodeType;
|
||||||
public readonly Color Color;
|
public readonly Color Color;
|
||||||
public readonly TextStyle Style;
|
public readonly TextStyle Style;
|
||||||
public readonly bool IsColorCode;
|
public readonly TextureRegion Icon;
|
||||||
|
|
||||||
public FormattingCode(Color color) {
|
public FormattingCode(Color color) {
|
||||||
this.Color = color;
|
this.Color = color;
|
||||||
this.IsColorCode = true;
|
this.CodeType = Type.Color;
|
||||||
}
|
}
|
||||||
|
|
||||||
public FormattingCode(TextStyle style) {
|
public FormattingCode(TextStyle style) {
|
||||||
this.Style = style;
|
this.Style = style;
|
||||||
this.IsColorCode = false;
|
this.CodeType = Type.Style;
|
||||||
|
}
|
||||||
|
|
||||||
|
public FormattingCode(TextureRegion icon) {
|
||||||
|
this.Icon = icon;
|
||||||
|
this.CodeType = Type.Icon;
|
||||||
|
}
|
||||||
|
|
||||||
|
public string GetReplacementString() {
|
||||||
|
return this.CodeType == Type.Icon ? TextFormatting.OneEmString : string.Empty;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum Type {
|
||||||
|
|
||||||
|
Color,
|
||||||
|
Style,
|
||||||
|
Icon
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,13 +2,17 @@ using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
using Microsoft.Xna.Framework;
|
using Microsoft.Xna.Framework;
|
||||||
|
using Microsoft.Xna.Framework.Graphics;
|
||||||
|
using MLEM.Extensions;
|
||||||
|
using MLEM.Font;
|
||||||
|
using MLEM.Textures;
|
||||||
|
|
||||||
namespace MLEM.Ui.Format {
|
namespace MLEM.Ui.Format {
|
||||||
public static class TextFormatting {
|
public static class TextFormatting {
|
||||||
|
|
||||||
private static Regex formatRegex;
|
|
||||||
|
|
||||||
public static readonly Dictionary<string, FormattingCode> FormattingCodes = new Dictionary<string, FormattingCode>();
|
public static readonly Dictionary<string, FormattingCode> FormattingCodes = new Dictionary<string, FormattingCode>();
|
||||||
|
public static string OneEmString = " ";
|
||||||
|
private static Regex formatRegex;
|
||||||
|
|
||||||
static TextFormatting() {
|
static TextFormatting() {
|
||||||
SetFormatIndicators('[', ']');
|
SetFormatIndicators('[', ']');
|
||||||
|
@ -33,22 +37,69 @@ namespace MLEM.Ui.Format {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static string RemoveFormatting(this string s) {
|
public static string RemoveFormatting(this string s) {
|
||||||
return formatRegex.Replace(s, string.Empty);
|
return formatRegex.Replace(s, match => FromMatch(match).GetReplacementString());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Dictionary<int, FormattingCode> GetFormattingCodes(this string s, bool indicesIgnoreCode = true) {
|
public static Dictionary<int, FormattingCode> GetFormattingCodes(this string s) {
|
||||||
var codes = new Dictionary<int, FormattingCode>();
|
var codes = new Dictionary<int, FormattingCode>();
|
||||||
var codeLengths = 0;
|
var codeLengths = 0;
|
||||||
foreach (Match match in formatRegex.Matches(s)) {
|
foreach (Match match in formatRegex.Matches(s)) {
|
||||||
var rawCode = match.Value.Substring(1, match.Value.Length - 2).ToLowerInvariant();
|
var code = FromMatch(match);
|
||||||
codes[match.Index - codeLengths] = FormattingCodes[rawCode];
|
codes[match.Index - codeLengths] = code;
|
||||||
// if indices of formatting codes should ignore the codes themselves, then the lengths of all
|
codeLengths += match.Length - code.GetReplacementString().Length;
|
||||||
// of the codes we have sound so far needs to be subtracted from the found code's index
|
|
||||||
if (indicesIgnoreCode)
|
|
||||||
codeLengths += match.Length;
|
|
||||||
}
|
}
|
||||||
return codes;
|
return codes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void DrawFormattedString(this IGenericFont regularFont, SpriteBatch batch, Vector2 pos, string text, Dictionary<int, FormattingCode> codeLocations, Color color, float scale, IGenericFont boldFont = null, IGenericFont italicFont = null, float depth = 0) {
|
||||||
|
var characterCounter = 0;
|
||||||
|
var currColor = color;
|
||||||
|
var currFont = regularFont;
|
||||||
|
|
||||||
|
var innerOffset = new Vector2();
|
||||||
|
foreach (var c in text) {
|
||||||
|
// check if the current character's index has a formatting code
|
||||||
|
codeLocations.TryGetValue(characterCounter, out var code);
|
||||||
|
if (code != null) {
|
||||||
|
// if so, apply it
|
||||||
|
if (code.CodeType == FormattingCode.Type.Color) {
|
||||||
|
currColor = code.Color.CopyAlpha(color);
|
||||||
|
} else if (code.CodeType == FormattingCode.Type.Style) {
|
||||||
|
switch (code.Style) {
|
||||||
|
case TextStyle.Regular:
|
||||||
|
currFont = regularFont;
|
||||||
|
break;
|
||||||
|
case TextStyle.Bold:
|
||||||
|
currFont = boldFont ?? regularFont;
|
||||||
|
break;
|
||||||
|
case TextStyle.Italic:
|
||||||
|
currFont = italicFont ?? regularFont;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else if (code.CodeType == FormattingCode.Type.Icon) {
|
||||||
|
var iconSc = new Vector2(1F / code.Icon.Width, 1F / code.Icon.Height) * regularFont.LineHeight * scale;
|
||||||
|
batch.Draw(code.Icon, pos + innerOffset, color, 0, Vector2.Zero, iconSc, SpriteEffects.None, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
characterCounter++;
|
||||||
|
|
||||||
|
var cSt = c.ToString();
|
||||||
|
if (c == '\n') {
|
||||||
|
innerOffset.X = 0;
|
||||||
|
innerOffset.Y += regularFont.LineHeight * scale;
|
||||||
|
} else {
|
||||||
|
currFont.DrawString(batch, cSt, pos + innerOffset, currColor, 0, Vector2.Zero, scale, SpriteEffects.None, depth);
|
||||||
|
// we measure the string with the regular font here so that previously split
|
||||||
|
// strings don't get too long with a bolder font. This shouldn't effect visuals too much
|
||||||
|
innerOffset.X += regularFont.MeasureString(cSt).X * scale;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static FormattingCode FromMatch(Capture match) {
|
||||||
|
var rawCode = match.Value.Substring(1, match.Value.Length - 2).ToLowerInvariant();
|
||||||
|
return FormattingCodes[rawCode];
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
Reference in a new issue