您最多选择25个主题
主题必须以中文或者字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
288 行
8.0 KiB
288 行
8.0 KiB
using System;
|
|
using System.Runtime.ConstrainedExecution;
|
|
using UIWidgets.math;
|
|
using UIWidgets.ui;
|
|
using UnityEngine;
|
|
using Canvas = UIWidgets.ui.Canvas;
|
|
|
|
namespace UIWidgets.painting
|
|
{
|
|
public class TextPainter
|
|
{
|
|
private TextSpan _text;
|
|
private TextAlign _textAlign;
|
|
private TextDirection? _textDirection;
|
|
private double _textScaleFactor;
|
|
private Paragraph _layoutTemplate;
|
|
private Paragraph _paragraph;
|
|
private bool _needsLayout = true;
|
|
private int _maxLines;
|
|
private string _ellipsis;
|
|
private double _lastMinWidth;
|
|
private double _lastMaxWidth;
|
|
|
|
public TextPainter(TextSpan text,
|
|
TextAlign textAlign = TextAlign.left,
|
|
TextDirection textDirection = TextDirection.ltr,
|
|
double textScaleFactor = 1.0,
|
|
int maxLines = 0,
|
|
string ellipsis = "")
|
|
{
|
|
_text = text;
|
|
_textAlign = textAlign;
|
|
_textDirection = textDirection;
|
|
_textScaleFactor = textScaleFactor;
|
|
_maxLines = maxLines;
|
|
_ellipsis = ellipsis;
|
|
}
|
|
|
|
|
|
public double textScaleFactor
|
|
{
|
|
get { return _textScaleFactor; }
|
|
set
|
|
{
|
|
if (_textScaleFactor == value)
|
|
return;
|
|
_textScaleFactor = value;
|
|
_paragraph = null;
|
|
_layoutTemplate = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public string ellipsis
|
|
{
|
|
get { return _ellipsis; }
|
|
set
|
|
{
|
|
if (_ellipsis == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_ellipsis = value;
|
|
_paragraph = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public TextSpan text
|
|
{
|
|
get { return _text; }
|
|
set
|
|
{
|
|
if (text.Equals(value))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (!Equals(_text == null ? null : _text.style, value == null ? null : value.style))
|
|
{
|
|
_layoutTemplate = null;
|
|
}
|
|
|
|
_text = value;
|
|
_paragraph = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public Size size
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return new Size(width, height);
|
|
}
|
|
}
|
|
|
|
public TextDirection? textDirection
|
|
{
|
|
get { return _textDirection; }
|
|
set
|
|
{
|
|
if (textDirection == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_textDirection = value;
|
|
_paragraph = null;
|
|
_layoutTemplate = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public TextAlign textAlign
|
|
{
|
|
get { return _textAlign; }
|
|
set
|
|
{
|
|
if (_textAlign == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_textAlign = value;
|
|
_paragraph = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public bool didExceedMaxLines
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return _paragraph.didExceedMaxLines;
|
|
}
|
|
}
|
|
|
|
public int maxLines
|
|
{
|
|
get { return _maxLines; }
|
|
set
|
|
{
|
|
if (_maxLines == value)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_maxLines = value;
|
|
_paragraph = null;
|
|
_needsLayout = true;
|
|
}
|
|
}
|
|
|
|
public double minIntrinsicWidth
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return _applyFloatingPointHack(_paragraph.minIntrinsicWidth);
|
|
}
|
|
}
|
|
|
|
public double maxIntrinsicWidth
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return _applyFloatingPointHack(_paragraph.maxIntrinsicWidth);
|
|
}
|
|
}
|
|
|
|
public double height
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return _applyFloatingPointHack(_paragraph.height);
|
|
}
|
|
}
|
|
|
|
public double width
|
|
{
|
|
get
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
return _applyFloatingPointHack(_paragraph.width);
|
|
}
|
|
}
|
|
|
|
public double computeDistanceToActualBaseline(TextBaseline baseline)
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
switch (baseline)
|
|
{
|
|
case TextBaseline.alphabetic:
|
|
return _paragraph.alphabeticBaseline;
|
|
case TextBaseline.ideographic:
|
|
return _paragraph.ideographicBaseline;
|
|
}
|
|
return 0.0;
|
|
}
|
|
|
|
public void layout(double minWidth = 0.0, double maxWidth = double.PositiveInfinity)
|
|
{
|
|
Debug.Assert(text != null, "TextPainter.text must be set to a non-null value before using the TextPainter.");
|
|
Debug.Assert(textDirection != null, "TextPainter.textDirection must be set to a non-null value before using the TextPainter.");
|
|
if (_needsLayout && minWidth == _lastMaxWidth && maxWidth == _lastMaxWidth)
|
|
{
|
|
return;
|
|
}
|
|
|
|
_needsLayout = false;
|
|
if (_paragraph == null)
|
|
{
|
|
var builder = new ParagraphBuilder(_createParagraphStyle());
|
|
_text.build(builder, textScaleFactor);
|
|
_paragraph = builder.build();
|
|
}
|
|
|
|
_lastMinWidth = minWidth;
|
|
_lastMaxWidth = minWidth;
|
|
_paragraph.layout(new ParagraphConstraints(maxWidth));
|
|
|
|
if (minWidth != maxWidth)
|
|
{
|
|
var newWidth = MathUtil.Clamp(maxIntrinsicWidth, minWidth, maxWidth);
|
|
if (newWidth != width)
|
|
{
|
|
_paragraph.layout(new ParagraphConstraints(newWidth));
|
|
}
|
|
}
|
|
}
|
|
|
|
public void paint(Canvas canvas, Offset offset)
|
|
{
|
|
Debug.Assert(!_needsLayout);
|
|
_paragraph.paint(canvas, offset.dx, offset.dy);
|
|
}
|
|
|
|
private ParagraphStyle _createParagraphStyle(TextDirection defaultTextDirection = TextDirection.ltr)
|
|
{
|
|
if (_text.style == null)
|
|
{
|
|
return new ParagraphStyle(
|
|
textAlign: textAlign,
|
|
textDirection: textDirection ?? defaultTextDirection,
|
|
maxLines: maxLines,
|
|
ellipsis: ellipsis
|
|
);
|
|
}
|
|
|
|
return _text.style.getParagraphStyle(textAlign, textDirection ?? defaultTextDirection,
|
|
ellipsis, maxLines, textScaleFactor);
|
|
}
|
|
|
|
public double preferredLineHeight
|
|
{
|
|
get
|
|
{
|
|
if (_layoutTemplate == null)
|
|
{
|
|
var builder = new ParagraphBuilder(
|
|
_createParagraphStyle(TextDirection.ltr)
|
|
); // direction doesn't matter, text is just a space
|
|
if (text != null && text.style != null)
|
|
{
|
|
builder.pushStyle(text.style.getTextStyle(textScaleFactor));
|
|
}
|
|
|
|
builder.addText(" ");
|
|
_layoutTemplate = builder.build();
|
|
_layoutTemplate.layout(new ParagraphConstraints(double.PositiveInfinity));
|
|
}
|
|
|
|
return _layoutTemplate.height;
|
|
}
|
|
}
|
|
|
|
private double _applyFloatingPointHack(double layoutValue)
|
|
{
|
|
return Math.Ceiling(layoutValue);
|
|
}
|
|
}
|
|
}
|