123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370 |
- using System.Collections.Generic;
- using FontStashSharp.Interfaces;
- using Hebron.Runtime;
- #if MONOGAME || FNA
- using Microsoft.Xna.Framework;
- using Microsoft.Xna.Framework.Graphics;
- #elif STRIDE
- using Stride.Core.Mathematics;
- using Stride.Graphics;
- #else
- using System.Drawing;
- using System.Numerics;
- using Color = Veldrid.RgbaFloat;
- #endif
- namespace FontStashSharp.RichText
- {
- public class RichTextLayout
- {
- private SpriteFontBase _font;
- private string _text = string.Empty;
- private int? _width;
- private Point _size;
- private bool _dirty = true;
- private readonly Dictionary<int, Point> _measures = new Dictionary<int, Point>();
- private readonly LayoutBuilder _layoutBuilder = new LayoutBuilder();
- private readonly FSRenderContext _renderContext = new FSRenderContext();
- public SpriteFontBase Font
- {
- get
- {
- return _font;
- }
- set
- {
- if (value == _font)
- {
- return;
- }
- _font = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- public string Text
- {
- get
- {
- return _text;
- }
- set
- {
- if (value == _text)
- {
- return;
- }
- _text = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- public int VerticalSpacing
- {
- get
- {
- return _layoutBuilder.VerticalSpacing;
- }
- set
- {
- if (value == _layoutBuilder.VerticalSpacing)
- {
- return;
- }
- _layoutBuilder.VerticalSpacing = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- public int? Width
- {
- get
- {
- return _width;
- }
- set
- {
- if (value == _width)
- {
- return;
- }
- _width = value;
- InvalidateLayout();
- }
- }
- public List<TextLine> Lines
- {
- get
- {
- Update();
- return _layoutBuilder.Lines;
- }
- }
- public Point Size
- {
- get
- {
- Update();
- return _size;
- }
- }
- public bool CalculateGlyphs
- {
- get
- {
- return _layoutBuilder.CalculateGlyphs;
- }
- set
- {
- if (value == _layoutBuilder.CalculateGlyphs)
- {
- return;
- }
- _layoutBuilder.CalculateGlyphs = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- public bool SupportsCommands
- {
- get
- {
- return _layoutBuilder.SupportsCommands;
- }
- set
- {
- if (value == _layoutBuilder.SupportsCommands)
- {
- return;
- }
- _layoutBuilder.SupportsCommands = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- public bool IgnoreColorCommand { get; set; } = false;
- public char CommandPrefix
- {
- get => _layoutBuilder.CommandPrefix;
- set
- {
- if (value == _layoutBuilder.CommandPrefix)
- {
- return;
- }
- _layoutBuilder.CommandPrefix = value;
- InvalidateLayout();
- InvalidateMeasures();
- }
- }
- private static int GetMeasureKey(int? width)
- {
- return width != null ? width.Value : -1;
- }
- private void Update()
- {
- if (!_dirty)
- {
- return;
- }
- _size = _layoutBuilder.Layout(Text, Font, Width);
- var key = GetMeasureKey(Width);
- _measures[key] = _size;
- _dirty = false;
- }
- public Point Measure(int? width)
- {
- var result =Utility.PointZero;
- var key = GetMeasureKey(width);
- if (_measures.TryGetValue(key, out result))
- {
- return result;
- }
- result = _layoutBuilder.Layout(Text, Font, width, true);
- _measures[key] = result;
- return result;
- }
- public TextLine GetLineByCursorPosition(int cursorPosition)
- {
- Update();
- if (Lines.Count == 0)
- {
- return null;
- }
- if (cursorPosition < 0)
- {
- return Lines[0];
- }
- for (var i = 0; i < Lines.Count; ++i)
- {
- var s = Lines[i];
- if (s.TextStartIndex <= cursorPosition && cursorPosition < s.TextStartIndex + s.Count)
- {
- return s;
- }
- }
- return Lines[Lines.Count - 1];
- }
- public TextLine GetLineByY(int y)
- {
- if (string.IsNullOrEmpty(_text) || y < 0)
- {
- return null;
- }
- Update();
- var py = 0;
- for (var i = 0; i < Lines.Count; ++i)
- {
- var s = Lines[i];
- if (py <= y && y < py + s.Size.Y)
- {
- return s;
- }
- py += s.Size.Y;
- py += VerticalSpacing;
- }
- return null;
- }
- public TextChunkGlyph? GetGlyphInfoByIndex(int charIndex)
- {
- var strings = Lines;
- foreach (var si in strings)
- {
- if (charIndex >= si.Count)
- {
- charIndex -= si.Count;
- }
- else
- {
- return si.GetGlyphInfoByIndex(charIndex);
- }
- }
- return null;
- }
- private void Draw(Vector2 position, Color color, Vector2? sourceScale,
- float rotation, Vector2 origin, float layerDepth, TextHorizontalAlignment horizontalAlignment)
- {
- Update();
- var scale = sourceScale ?? Utility.DefaultScale;
- _renderContext.Prepare(position, scale, rotation, origin, layerDepth);
- var pos = Utility.Vector2Zero;
- foreach (var line in Lines)
- {
- pos.X = 0;
- if (horizontalAlignment == TextHorizontalAlignment.Center)
- {
- pos.X -= line.Size.X / 2;
- }
- else if (horizontalAlignment == TextHorizontalAlignment.Right)
- {
- pos.X -= line.Size.X;
- }
- foreach (var chunk in line.Chunks)
- {
- var chunkColor = color;
- if (!IgnoreColorCommand && chunk.Color != null)
- {
- chunkColor = chunk.Color.Value;
- }
- chunk.Draw(_renderContext, pos + new Vector2(0, chunk.VerticalOffset), chunkColor);
- pos.X += chunk.Size.X;
- }
- pos.Y += line.Size.Y;
- pos.Y += VerticalSpacing;
- }
- }
- public void Draw(IFontStashRenderer renderer, Vector2 position, Color color,
- Vector2? sourceScale = null, float rotation = 0,
- Vector2 origin = default(Vector2), float layerDepth = 0.0f,
- TextHorizontalAlignment horizontalAlignment = TextHorizontalAlignment.Left)
- {
- _renderContext.SetRenderer(renderer);
- Draw(position, color, sourceScale, rotation, origin, layerDepth, horizontalAlignment);
- }
- public void Draw(IFontStashRenderer2 renderer, Vector2 position, Color color,
- Vector2? sourceScale = null, float rotation = 0,
- Vector2 origin = default(Vector2), float layerDepth = 0.0f,
- TextHorizontalAlignment horizontalAlignment = TextHorizontalAlignment.Left)
- {
- _renderContext.SetRenderer(renderer);
- Draw(position, color, sourceScale, rotation, origin, layerDepth, horizontalAlignment);
- }
- #if MONOGAME || FNA || STRIDE
- public void Draw(SpriteBatch batch, Vector2 position, Color color,
- Vector2? scale = null, float rotation = 0, Vector2 origin = default(Vector2),
- float layerDepth = 0.0f, TextHorizontalAlignment horizontalAlignment = TextHorizontalAlignment.Left)
- {
- var renderer = SpriteBatchRenderer.Instance;
- renderer.Batch = batch;
- Draw(renderer, position, color, scale, rotation, origin, layerDepth, horizontalAlignment);
- }
- #endif
- private void InvalidateLayout()
- {
- _dirty = true;
- }
- private void InvalidateMeasures()
- {
- _measures.Clear();
- }
- }
- }
|