refactor!: Rename (Text) Elements, Nodes and Styles for clarity, add docs (#2700)

This occurred to me after a discussion on the [new FCS component
PR](https://github.com/flame-engine/flame/pull/2694#discussion_r1312450113).
As per usual, @spydon has opened my eyes to the ultimate truth:

We should rename loads of files, and it shall affect almost no one.

The idea is to (1) add a "Text" prefix to all text-rendering-related
classes and (2) rename the existing `Text*` to `InlineText*` (which is
what they are).

This PR is a bit big, but the changes should hopefully be simple to
review, and can be broken down into:

* Add a proper base class for the node inheritance chain, call it
TextNode (while working on Flame Markdown I realized the value this will
have to me)
* Rename the old TextNode to InlineTextNode
* Rename DocumentNode to DocumentRoot because it is not a node
* Rename Element to TextElement
* Rename the old TextElement to InlineTextElement
* Rename Style to FlameTextStyle (note: we could consider dropping the
Flame here)
* Rename the old FlameTextStyle to InlineTextStyle
* Update the docs accordingly
* Add some more diagrams and explanations to the docs, following the new
nomenclature
* I also updated our "internal" imports to use the text module to make
life so much easier (this could arguably be done in a separate PR, but I
honestly think it's easier to review together, please lmk if you prefer
me to split).

These are all breaking changes but likely won't actually affect most
users (see below).

While this is breaking, it should hopefully not affect most users,
because these are all infrastructure classes that most people aren't
using directly. If you are using the FCS components, or the renderers
`TextPaint` or `SpriteFontRenderer` directly, this should have zero
effect to you.

If you are using the Nodes, Stlyes or Elements directly, or have a
custom TextRenderer, see below.

Migrating should be a simple matter of renaming your type references:

* from TextNode to InlineTextNode
* from TextElement to InlineTextElement
* from Element to TextElement
* from FlameTextStyle to InlineTextStyle
* from Style to FlameTextStyle

Make sure to do it in the appropriate order not to cause any
double-replace issues.

If you are importing via the module `package:flame/text.dart`, which we
highly encourage, you should not have to change any import statements
whatsoever.
This commit is contained in:
Luan Nico
2023-09-02 09:59:59 -07:00
committed by GitHub
parent 99a1016f72
commit 4b420b7952
40 changed files with 492 additions and 359 deletions

View File

@ -127,6 +127,7 @@ this section is for you.
The following diagram showcases the class and inheritance structure of the text rendering pipeline:
```mermaid
%%{init: { 'theme': 'dark' } }%%
classDiagram
%% renderers
note for TextRenderer "This just the style (how).
@ -265,21 +266,21 @@ it possible to test the layout, positioning and sizing of the elements without h
font-based rendering.
## Text Elements
## Inline Text Elements
Text Elements are "pre-compiled", formatted and laid-out pieces of text with a specific styling
A `TextElement` is a "pre-compiled", formatted and laid-out piece of text with a specific styling
applied, ready to be rendered at any given position.
`TextElement` implements the `Element` interface and must implement their two methods, one that
teaches how to translate it around and another on how to draw it to the canvas:
A `InlineTextElement` implements the `TextElement` interface and must implement their two methods,
one that teaches how to translate it around and another on how to draw it to the canvas:
```dart
void translate(double dx, double dy);
void draw(Canvas canvas);
```
These methods are intended to be overwritten by the implementations of `TextElement` but probably
will not be called directly by users; because a convenient `render` method is provided:
These methods are intended to be overwritten by the implementations of `InlineTextElement`, and
probably will not be called directly by users; because a convenient `render` method is provided:
```dart
void render(
@ -291,37 +292,212 @@ will not be called directly by users; because a convenient `render` method is pr
That allows the element to be rendered at a specific position, using a given anchor.
The interface also mandates (and provides) a getter for the LineMetrics object associated with that
`TextElement`, which allows you (and the `render` implementation) to access sizing information
related to the element (width, height, ascend, etc).
The interface also mandates (and provides) a getter for the `LineMetrics` object associated with
that `InlineTextElement`, which allows you (and the `render` implementation) to access sizing
information related to the element (width, height, ascend, etc).
```dart
LineMetrics get metrics;
```
## Elements, Nodes, and Styles
## Text Elements, Text Nodes, and Text Styles
While normal renderers always work with TextElements directly, there is a bigger underlying
While normal renderers always work with a `InlineTextElement` directly, there is a bigger underlying
infrastructure that can be used to render more rich or formatter text.
Elements are a superset of TextElements that represent an arbitrary rendering block within a
rich-text document. Essentially, they are concrete and "physical": they are objects that are ready
to be rendered on a canvas.
Text Elements are a superset of Inline Text Elements that represent an arbitrary rendering block
within a rich-text document. Essentially, they are concrete and "physical": they are objects that
are ready to be rendered on a canvas.
This property distinguishes them from Nodes, which are structured pieces of text, and from Styles,
This property distinguishes them from Text Nodes, which are structured pieces of text, and from Text
Styles (called `FlameTextStyle` in code to make it easier to work alongside Flutter's `TextStyle`),
which are descriptors for how arbitrary pieces of text ought to be rendered.
So a user would use Node to describe a desired document of rich text; define Styles to apply to it;
and use that to generate an Element. Depending on the type of rendering, the Element generated will
be a TextElement, which brings us back to the normal flow of the rendering pipeline. The unique
property of the Text-type element is that it exposes a LineMetrics that can be used for advanced
rendering; while the other elements only expose a simpler `draw` method which is unaware of sizing
and positioning.
So, in the most general case, a user would use a `TextNode` to describe a desired piece of rich
text; define a `FlameTextStyle` to apply to it; and use that to generate a `TextElement`. Depending
on the type of rendering, the `TextElement` generated will be an `InlineTextElement`, which brings
us back to the normal flow of the rendering pipeline. The unique property of the Inline-Text-type
element is that it exposes a LineMetrics that can be used for advanced rendering; while the other
elements only expose a simpler `draw` method which is unaware of sizing and positioning.
However the other types of Elements, Nodes and Style must be used if the intent is to create an
entire Document, enriched with formatted text. Currently these extra features of the system are not
exposed through FCS, but can be used directly.
However, the other types of Text Elements, Text Nodes, and Text Styles must be used if the intent is
to create an entire document (multiple blocks or paragraphs), enriched with formatted text.
Currently, these extra features of the system are not exposed through FCS; but can be used directly.
An example of such usages can be seen in [this
example](https://github.com/flame-engine/flame/blob/main/examples/lib/stories/rendering/rich_text_example.dart).
### Text Nodes and the Document Root
A `DocumentRoot` is not a `TextNode` (inheritance-wise) in itself but represents a grouping of
`BlockNodes` that layout a "page" or "document" of rich text laid out in multiple blocks or
paragraphs. It represents the entire document and can receive a global Style.
The first step to define your rich-text document is to create a Node, which will likely be a
`DocumentRoot`.
It will first contain the top-most list of Block Nodes that can define headers, paragraphs or
columns.
Then each of those blocks can contain other blocks or the Inline Text Nodes, either Plain Text Nodes
or some rich-text with specific formatting.
Note that the hierarchy defined by the node structure is also used for styling purposes as per
defined in the `FlameTextStyle` class.
The actual nodes all inherit from `TextNode` and are broken down by the following diagram:
```mermaid
%%{init: { 'theme': 'dark' } }%%
graph TD
%% Config %%
classDef default fill:#282828,stroke:#F6BE00;
%% Nodes %%
TextNode("
<big><strong>TextNode</strong></big>
Can be thought of as an HTML DOM node;
each subclass can be thought of as a specific tag.
")
BlockNode("
<big><strong>BlockNode</strong></big>
#quot;div#quot;
")
InlineTextNode("
<big><strong>InlineTextNode</strong></big>
#quot;span#quot;
")
ColumnNode("
<big><strong>ColumnNode</strong></big>
column-arranged group of other Block Nodes
")
TextBlockNode("
<big><strong>TextBlockNode</strong></big>
a #quot;div#quot; with an InlineTextNode as a direct child
")
HeaderNode("
<big><strong>HeaderNode</strong></big>
#quot;h1#quot; / #quot;h2#quot; / etc
")
ParagraphNode("
<big><strong>ParagraphNode</strong></big>
#quot;p#quot;
")
GroupTextNode("
<big><strong>GroupTextNode</strong></big>
groups other TextNodes in a single line
")
PlainTextNode("
<big><strong>PlainTextNode</strong></big>
just plain text, unformatted
")
ItalicTextNode("
<big><strong>ItalicTextNode</strong></big>
#quot;i#quot; / #quot;em#quot;
")
BoldTextNode("
<big><strong>BoldTextNode</strong></big>
#quot;b#quot; / #quot;strong#quot;
")
TextNode ----> BlockNode
TextNode --------> InlineTextNode
BlockNode --> ColumnNode
BlockNode --> TextBlockNode
TextBlockNode --> HeaderNode
TextBlockNode --> ParagraphNode
InlineTextNode --> GroupTextNode
InlineTextNode --> PlainTextNode
InlineTextNode --> BoldTextNode
InlineTextNode --> ItalicTextNode
```
### (Flame) Text Styles
Text Styles can be applied to nodes to generate elements. They all inherit from `FlameTextStyle`
abstract class (which is named as is to avoid confusion with Flutter's `TextStyle`).
They follow a tree-like structure, always having `DocumentStyle` as the root; this structure is
leveraged to apply cascading style to the analogous Node structure. In fact, they are pretty similar
to, and can be thought of as, CSS definitions.
The full inheritance chain can be seen on the following diagram:
```mermaid
%%{init: { 'theme': 'dark' } }%%
classDiagram
%% Nodes %%
class FlameTextStyle {
copyWith()
merge()
}
note for FlameTextStyle "Root for all styles.
Not to be confused with Flutter's TextStyle."
class DocumentStyle {
<<for the entire Document Root>>
size
padding
background [BackgroundStyle]
specific styles [for blocks & inline]
}
class BlockStyle {
<<for Block Nodes>>
margin, padding
background [BackgroundStyle]
text [InlineTextStyle]
}
class BackgroundStyle {
<<for Block or Document>>
color
border
}
class InlineTextStyle {
<<for any nodes>>
font, color
}
FlameTextStyle <|-- DocumentStyle
FlameTextStyle <|-- BlockStyle
FlameTextStyle <|-- BackgroundStyle
FlameTextStyle <|-- InlineTextStyle
```
### Text Elements
Finally, we have the elements, that represent a combination of a node ("what") with a style ("how"),
and therefore represent a pre-compiled, laid-out piece of rich text to be rendered on the Canvas.
Inline Text Elements specifically can alternatively be thought of as a combination of a
`TextRenderer` (simplified "how") and a string (single line of "what").
That is because an `InlineTextStyle` can be converted to a specific `TextRenderer` via the
`asTextRenderer` method, which is then used to lay out each line of text into a unique
`InlineTextElement`.
When using the renderer directly, the entire layout process is skipped, and a single
`TextPainterTextElement` or `SpriteFontTextElement` is returned.
As you can see, both definitions of an Element are, essentially, equivalent, all things considered.
But it still leaves us with two paths for rendering text. Which one to pick? How to solve this
conundrum?
When in doubt, the following guidelines can help you picking the best path for you:
- for the simplest way to render text, use `TextPaint` (basic renderer implementation)
- you can use the FCS provided component `TextComponent` for that.
- for rendering Sprite Fonts, you must use `SpriteFontRenderer` (a renderer implementation that
accepts a `SpriteFont`);
- for rendering multiple lines of text, with automatic line breaks, you have two options:
- use the FCS `TextBoxComponent`, which uses any text renderer to draw each line of text as an
Element, and does its own layout and line breaking;
- use the Text Node & Style system to create your pre-laid-out Elements. Note: there is no current
FCS component for it.
- finally, in order to have formatted (or rich) text, you must use Text Nodes & Styles.

View File

@ -219,7 +219,7 @@ class KeyboardKey extends PositionComponent {
}
final String text;
late final TextElement textElement;
late final InlineTextElement textElement;
late final RRect rect;
/// The RawKeyEvents may occur very fast, and out of sync with the game loop.

View File

@ -17,7 +17,7 @@ class RichTextExample extends FlameGame {
}
class MyTextComponent extends PositionComponent {
late final Element element;
late final TextElement element;
@override
Future<void> onLoad() async {
@ -38,7 +38,7 @@ class MyTextComponent extends PositionComponent {
),
),
);
final document = DocumentNode([
final document = DocumentRoot([
HeaderNode.simple('1984', level: 1),
ParagraphNode.simple(
'Anything could be true. The so-called laws of nature were nonsense.',

View File

@ -38,7 +38,7 @@ class TextComponent<T extends TextRenderer> extends PositionComponent {
updateBounds();
}
late TextElement _textElement;
late InlineTextElement _textElement;
@internal
void updateBounds() {

View File

@ -1,10 +1,7 @@
import 'dart:math';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/src/text/elements/group_element.dart';
import 'package:flame/src/text/elements/rect_element.dart';
import 'package:flame/src/text/elements/rrect_element.dart';
import 'package:flame/src/text/styles/background_style.dart';
import 'package:flame/text.dart';
import 'package:meta/meta.dart';
@internal
@ -17,11 +14,15 @@ double collapseMargin(double margin1, double margin2) {
}
@internal
Element? makeBackground(BackgroundStyle? style, double width, double height) {
TextElement? makeBackground(
BackgroundStyle? style,
double width,
double height,
) {
if (style == null) {
return null;
}
final out = <Element>[];
final out = <TextElement>[];
final backgroundPaint = style.backgroundPaint;
final borderPaint = style.borderPaint;
final borders = style.borderWidths;

View File

@ -1,11 +1,11 @@
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/text.dart';
/// [BlockElement] is the base class for [Element]s with rectangular shape and
/// "block" placement rules.
/// [BlockElement] is the base class for [TextElement]s with rectangular shape
/// and "block" placement rules.
///
/// Within HTML, this corresponds to elements with `display: block` property,
/// such as `<div>` or `<blockquote>`.
abstract class BlockElement extends Element {
abstract class BlockElement extends TextElement {
BlockElement(this.width, this.height);
final double width;

View File

@ -1,24 +0,0 @@
import 'dart:ui';
import 'package:flame/src/text/styles/style.dart';
/// An [Element] is a basic rendering block of a rich-text document.
///
/// Elements are concrete and "physical": they are objects that are ready to be
/// rendered on a canvas. This property distinguishes them from Nodes (which are
/// structured pieces of text), and from [Style]s (which are descriptors for how
/// arbitrary pieces of text ought to be rendered).
///
/// Elements are at the final stage of the text rendering pipeline, they are
/// created during the layout step.
abstract class Element {
/// Moves the element by ([dx], [dy]) relative to its current location.
void translate(double dx, double dy);
/// Renders the element on the [canvas], at coordinates determined during the
/// layout.
///
/// In order to render the element at a different location, consider either
/// calling the [translate] method, or applying a translation transform to the
/// canvas itself.
void draw(Canvas canvas);
}

View File

@ -1,5 +1,4 @@
import 'package:flame/src/text/elements/block_element.dart';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart' hide TextStyle;
class GroupElement extends BlockElement {
@ -9,7 +8,7 @@ class GroupElement extends BlockElement {
required this.children,
}) : super(width, height);
final List<Element> children;
final List<TextElement> children;
@override
void translate(double dx, double dy) {

View File

@ -1,16 +1,15 @@
import 'dart:math';
import 'dart:ui';
import 'package:flame/src/text/common/line_metrics.dart';
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/text.dart';
class GroupTextElement extends TextElement {
GroupTextElement(List<TextElement> children)
class GroupTextElement extends InlineTextElement {
GroupTextElement(List<InlineTextElement> children)
: assert(children.isNotEmpty, 'The children list cannot be empty'),
_children = children,
_metrics = _computeMetrics(children);
final List<TextElement> _children;
final List<InlineTextElement> _children;
final LineMetrics _metrics;
@override
@ -31,7 +30,7 @@ class GroupTextElement extends TextElement {
}
}
static LineMetrics _computeMetrics(List<TextElement> elements) {
static LineMetrics _computeMetrics(List<InlineTextElement> elements) {
var width = 0.0;
var ascent = 0.0;
var descent = 0.0;

View File

@ -0,0 +1,23 @@
import 'package:flame/extensions.dart';
import 'package:flame/src/anchor.dart';
import 'package:flame/text.dart';
/// [InlineTextElement] is the base class that represents a single line of text,
/// laid out and prepared for rendering.
abstract class InlineTextElement extends TextElement {
/// The dimensions of this line.
LineMetrics get metrics;
void render(
Canvas canvas,
Vector2 position, {
Anchor anchor = Anchor.topLeft,
}) {
final box = metrics;
translate(
position.x - box.width * anchor.x,
position.y - box.height * anchor.y - box.top,
);
draw(canvas);
}
}

View File

@ -1,8 +1,8 @@
import 'dart:ui';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/text.dart';
class RectElement extends Element {
class RectElement extends TextElement {
RectElement(double width, double height, this._paint)
: _rect = Rect.fromLTWH(0, 0, width, height);

View File

@ -1,8 +1,8 @@
import 'dart:ui';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/text.dart';
class RRectElement extends Element {
class RRectElement extends TextElement {
RRectElement(
double width,
double height,

View File

@ -1,10 +1,9 @@
import 'dart:typed_data';
import 'dart:ui';
import 'package:flame/src/text/common/line_metrics.dart';
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/text.dart';
class SpriteFontTextElement extends TextElement {
class SpriteFontTextElement extends InlineTextElement {
SpriteFontTextElement({
required this.source,
required this.transforms,

View File

@ -1,24 +1,24 @@
import 'package:flame/extensions.dart';
import 'package:flame/src/anchor.dart';
import 'package:flame/src/text/common/line_metrics.dart';
import 'package:flame/src/text/elements/element.dart';
import 'dart:ui';
import 'package:flame/text.dart';
/// [TextElement] is the base class that represents a single line of text, laid
/// out and prepared for rendering.
abstract class TextElement extends Element {
/// The dimensions of this line.
LineMetrics get metrics;
/// An [TextElement] is a basic rendering block of a rich-text document.
///
/// Elements are concrete and "physical": they are objects that are ready to be
/// rendered on a canvas. This property distinguishes them from Nodes (which are
/// structured pieces of text), and from [FlameTextStyle]s (which are
/// descriptors for how arbitrary pieces of text ought to be rendered).
///
/// Elements are at the final stage of the text rendering pipeline, they are
/// created during the layout step.
abstract class TextElement {
/// Moves the element by ([dx], [dy]) relative to its current location.
void translate(double dx, double dy);
void render(
Canvas canvas,
Vector2 position, {
Anchor anchor = Anchor.topLeft,
}) {
final box = metrics;
translate(
position.x - box.width * anchor.x,
position.y - box.height * anchor.y - box.top,
);
draw(canvas);
}
/// Renders the element on the [canvas], at coordinates determined during the
/// layout.
///
/// In order to render the element at a different location, consider either
/// calling the [translate] method, or applying a translation transform to the
/// canvas itself.
void draw(Canvas canvas);
}

View File

@ -1,10 +1,9 @@
import 'dart:ui';
import 'package:flame/src/text/common/line_metrics.dart';
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart' as flutter;
class TextPainterTextElement extends TextElement {
class TextPainterTextElement extends InlineTextElement {
TextPainterTextElement(this._textPainter)
: _box = LineMetrics(
ascent: _textPainter.computeDistanceToActualBaseline(

View File

@ -1,7 +1,4 @@
import 'package:flame/src/text/elements/block_element.dart';
import 'package:flame/src/text/styles/block_style.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/text.dart';
/// [BlockNode] is a base class for all nodes with "block" placement rules; it
/// roughly corresponds to `<div/>` in HTML.
@ -14,11 +11,13 @@ import 'package:flame/src/text/styles/flame_text_style.dart';
/// Implementations include:
/// * ColumnNode
/// * TextBlockNode (which itself can be a HeaderNode or ParagraphNode)
abstract class BlockNode {
abstract class BlockNode implements TextNode<BlockStyle> {
/// The runtime style applied to this node, this will be set by [fillStyles].
@override
late BlockStyle style;
BlockElement format(double availableWidth);
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle);
@override
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle);
}

View File

@ -1,27 +1,24 @@
import 'dart:ui';
import 'package:flame/src/text/nodes/group_text_node.dart';
import 'package:flame/src/text/nodes/plain_text_node.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/src/text/nodes/inline_text_node.dart';
import 'package:flame/text.dart';
class BoldTextNode extends TextNode {
class BoldTextNode extends InlineTextNode {
BoldTextNode(this.child);
BoldTextNode.simple(String text) : child = PlainTextNode(text);
BoldTextNode.group(List<TextNode> children) : child = GroupTextNode(children);
BoldTextNode.group(List<InlineTextNode> children)
: child = GroupTextNode(children);
final TextNode child;
final InlineTextNode child;
static final defaultStyle = FlameTextStyle(fontWeight: FontWeight.bold);
static final defaultStyle = InlineTextStyle(fontWeight: FontWeight.bold);
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
textStyle = Style.merge(parentTextStyle, stylesheet.boldText)!;
child.fillStyles(stylesheet, textStyle);
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = FlameTextStyle.merge(parentTextStyle, stylesheet.boldText)!;
child.fillStyles(stylesheet, style);
}
@override

View File

@ -1,9 +1,6 @@
import 'package:flame/src/text/common/utils.dart';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/src/text/elements/group_element.dart';
import 'package:flame/src/text/nodes/block_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/text.dart';
import 'package:meta/meta.dart';
/// [ColumnNode] is a block node containing other block nodes arranged as a
@ -18,7 +15,7 @@ abstract class ColumnNode extends BlockNode {
@override
GroupElement format(double availableWidth) {
final out = <Element>[];
final out = <TextElement>[];
final blockWidth = availableWidth;
final padding = style.padding;
@ -55,7 +52,7 @@ abstract class ColumnNode extends BlockNode {
@mustCallSuper
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
for (final node in children) {
node.fillStyles(stylesheet, parentTextStyle);
}

View File

@ -1,14 +1,12 @@
import 'dart:math';
import 'package:flame/src/text/common/utils.dart';
import 'package:flame/src/text/elements/element.dart';
import 'package:flame/src/text/elements/group_element.dart';
import 'package:flame/src/text/nodes/block_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/text.dart';
import 'package:flutter/painting.dart';
class DocumentNode {
DocumentNode(this.children);
class DocumentRoot {
DocumentRoot(this.children);
final List<BlockNode> children;
@ -22,7 +20,7 @@ class DocumentNode {
style.width != null || width != null,
'Width must be either provided explicitly or set in the stylesheet',
);
final out = <Element>[];
final out = <TextElement>[];
final border = style.background?.borderWidths ?? EdgeInsets.zero;
final padding = style.padding;

View File

@ -1,19 +1,17 @@
import 'package:flame/src/text/elements/group_text_element.dart';
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/nodes/inline_text_node.dart';
import 'package:flame/text.dart';
class GroupTextNode extends TextNode {
class GroupTextNode extends InlineTextNode {
GroupTextNode(this.children);
final List<TextNode> children;
final List<InlineTextNode> children;
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
textStyle = parentTextStyle;
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = parentTextStyle;
for (final node in children) {
node.fillStyles(stylesheet, textStyle);
node.fillStyles(stylesheet, style);
}
}
@ -32,9 +30,9 @@ class _GroupTextLayoutBuilder extends TextNodeLayoutBuilder {
bool get isDone => _currentChildIndex == node.children.length;
@override
TextElement? layOutNextLine(double availableWidth) {
InlineTextElement? layOutNextLine(double availableWidth) {
assert(!isDone);
final out = <TextElement>[];
final out = <InlineTextElement>[];
var usedWidth = 0.0;
while (true) {
if (_currentChildBuilder?.isDone ?? false) {

View File

@ -1,11 +1,6 @@
import 'dart:ui';
import 'package:flame/src/text/nodes/plain_text_node.dart';
import 'package:flame/src/text/nodes/text_block_node.dart';
import 'package:flame/src/text/styles/block_style.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart' show EdgeInsets;
class HeaderNode extends TextBlockNode {
@ -17,28 +12,28 @@ class HeaderNode extends TextBlockNode {
final int level;
static BlockStyle defaultStyleH1 = BlockStyle(
text: FlameTextStyle(fontScale: 2.0, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 2.0, fontWeight: FontWeight.bold),
margin: const EdgeInsets.fromLTRB(0, 24, 0, 12),
);
static BlockStyle defaultStyleH2 = BlockStyle(
text: FlameTextStyle(fontScale: 1.5, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 1.5, fontWeight: FontWeight.bold),
margin: const EdgeInsets.fromLTRB(0, 24, 0, 8),
);
static BlockStyle defaultStyleH3 = BlockStyle(
text: FlameTextStyle(fontScale: 1.25, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 1.25, fontWeight: FontWeight.bold),
);
static BlockStyle defaultStyleH4 = BlockStyle(
text: FlameTextStyle(fontScale: 1.0, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 1.0, fontWeight: FontWeight.bold),
);
static BlockStyle defaultStyleH5 = BlockStyle(
text: FlameTextStyle(fontScale: 0.875, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 0.875, fontWeight: FontWeight.bold),
);
static BlockStyle defaultStyleH6 = BlockStyle(
text: FlameTextStyle(fontScale: 0.85, fontWeight: FontWeight.bold),
text: InlineTextStyle(fontScale: 0.85, fontWeight: FontWeight.bold),
);
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = switch (level) {
1 => stylesheet.header1,
2 => stylesheet.header2,
@ -47,7 +42,7 @@ class HeaderNode extends TextBlockNode {
5 => stylesheet.header5,
_ => stylesheet.header6,
};
final textStyle = Style.merge(parentTextStyle, style.text)!;
final textStyle = FlameTextStyle.merge(parentTextStyle, style.text)!;
super.fillStyles(stylesheet, textStyle);
}
}

View File

@ -0,0 +1,25 @@
import 'package:flame/text.dart';
/// [InlineTextNode] is a base class for all nodes with "inline" placement
/// rules; it roughly corresponds to `<span/>` in HTML.
///
/// Implementations include:
/// * PlainTextNode - just a string of plain text, no special formatting.
/// * BoldTextNode - bolded string
/// * ItalicTextNode - italic string
/// * GroupTextNode - collection of multiple [InlineTextNode]'s to be joined one
/// after the other.
abstract class InlineTextNode extends TextNode<InlineTextStyle> {
@override
late InlineTextStyle style;
@override
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle);
TextNodeLayoutBuilder get layoutBuilder;
}
abstract class TextNodeLayoutBuilder {
InlineTextElement? layOutNextLine(double availableWidth);
bool get isDone;
}

View File

@ -1,28 +1,24 @@
import 'dart:ui';
import 'package:flame/src/text/nodes/group_text_node.dart';
import 'package:flame/src/text/nodes/plain_text_node.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/src/text/nodes/inline_text_node.dart';
import 'package:flame/text.dart';
class ItalicTextNode extends TextNode {
class ItalicTextNode extends InlineTextNode {
ItalicTextNode(this.child);
ItalicTextNode.simple(String text) : child = PlainTextNode(text);
ItalicTextNode.group(List<TextNode> children)
ItalicTextNode.group(List<InlineTextNode> children)
: child = GroupTextNode(children);
final TextNode child;
final InlineTextNode child;
static final defaultStyle = FlameTextStyle(fontStyle: FontStyle.italic);
static final defaultStyle = InlineTextStyle(fontStyle: FontStyle.italic);
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
textStyle = Style.merge(parentTextStyle, stylesheet.italicText)!;
child.fillStyles(stylesheet, textStyle);
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = FlameTextStyle.merge(parentTextStyle, stylesheet.italicText)!;
child.fillStyles(stylesheet, style);
}
@override

View File

@ -1,11 +1,4 @@
import 'package:flame/src/text/nodes/group_text_node.dart';
import 'package:flame/src/text/nodes/plain_text_node.dart';
import 'package:flame/src/text/nodes/text_block_node.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/styles/block_style.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart' show EdgeInsets;
class ParagraphNode extends TextBlockNode {
@ -13,7 +6,7 @@ class ParagraphNode extends TextBlockNode {
ParagraphNode.simple(String text) : super(PlainTextNode(text));
ParagraphNode.group(List<TextNode> fragments)
ParagraphNode.group(List<InlineTextNode> fragments)
: super(GroupTextNode(fragments));
static const defaultStyle = BlockStyle(
@ -21,9 +14,9 @@ class ParagraphNode extends TextBlockNode {
);
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = stylesheet.paragraph;
final textStyle = Style.merge(parentTextStyle, style.text)!;
final textStyle = FlameTextStyle.merge(parentTextStyle, style.text)!;
super.fillStyles(stylesheet, textStyle);
}
}

View File

@ -1,17 +1,14 @@
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/renderers/text_renderer.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/nodes/inline_text_node.dart';
import 'package:flame/text.dart';
class PlainTextNode extends TextNode {
class PlainTextNode extends InlineTextNode {
PlainTextNode(this.text);
final String text;
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
textStyle = parentTextStyle;
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
style = parentTextStyle;
}
@override
@ -20,7 +17,7 @@ class PlainTextNode extends TextNode {
class _PlainTextLayoutBuilder extends TextNodeLayoutBuilder {
_PlainTextLayoutBuilder(this.node)
: renderer = node.textStyle.asTextRenderer(),
: renderer = node.style.asTextRenderer(),
words = node.text.split(' ');
final PlainTextNode node;
@ -33,8 +30,8 @@ class _PlainTextLayoutBuilder extends TextNodeLayoutBuilder {
bool get isDone => index1 > words.length;
@override
TextElement? layOutNextLine(double availableWidth) {
TextElement? tentativeLine;
InlineTextElement? layOutNextLine(double availableWidth) {
InlineTextElement? tentativeLine;
int? tentativeIndex0;
while (index1 <= words.length) {
final textPiece = words.sublist(index0, index1).join(' ');

View File

@ -1,21 +1,16 @@
import 'package:flame/src/text/common/utils.dart';
import 'package:flame/src/text/elements/block_element.dart';
import 'package:flame/src/text/elements/group_element.dart';
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/src/text/nodes/block_node.dart';
import 'package:flame/src/text/nodes/text_node.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/text.dart';
import 'package:meta/meta.dart';
abstract class TextBlockNode extends BlockNode {
TextBlockNode(this.child);
final TextNode child;
final InlineTextNode child;
@mustCallSuper
@override
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle) {
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle) {
child.fillStyles(stylesheet, parentTextStyle);
}
@ -28,7 +23,7 @@ abstract class TextBlockNode extends BlockNode {
final blockWidth = availableWidth;
final contentWidth = blockWidth - style.padding.horizontal;
final lines = <TextElement>[];
final lines = <InlineTextElement>[];
final horizontalOffset = style.padding.left;
var verticalOffset = style.padding.top;
while (!layoutBuilder.isDone) {

View File

@ -1,25 +1,7 @@
import 'package:flame/src/text/elements/text_element.dart';
import 'package:flame/src/text/styles/document_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/text.dart';
/// [TextNode] is a base class for all nodes with "inline" placement rules; it
/// roughly corresponds to `<span/>` in HTML.
///
/// Implementations include:
/// * PlainTextNode - just a string of plain text, no special formatting.
/// * BoldTextNode - bolded string
/// * ItalicTextNode - italic string
/// * GroupTextNode - collection of multiple [TextNode]'s to be joined one
/// after the other.
abstract class TextNode {
late FlameTextStyle textStyle;
abstract class TextNode<T extends FlameTextStyle> {
T get style;
void fillStyles(DocumentStyle stylesheet, FlameTextStyle parentTextStyle);
TextNodeLayoutBuilder get layoutBuilder;
}
abstract class TextNodeLayoutBuilder {
TextElement? layOutNextLine(double availableWidth);
bool get isDone;
void fillStyles(DocumentStyle stylesheet, InlineTextStyle parentTextStyle);
}

View File

@ -1,10 +1,7 @@
import 'dart:typed_data';
import 'dart:ui' hide LineMetrics;
import 'package:flame/src/text/common/line_metrics.dart';
import 'package:flame/src/text/common/sprite_font.dart';
import 'package:flame/src/text/elements/sprite_font_text_element.dart';
import 'package:flame/src/text/renderers/text_renderer.dart';
import 'package:flame/text.dart';
/// [SpriteFontRenderer] will render text using a [SpriteFont] font,
/// creating a [SpriteFontTextElement].

View File

@ -1,6 +1,5 @@
import 'package:flame/cache.dart';
import 'package:flame/src/text/elements/text_painter_text_element.dart';
import 'package:flame/src/text/renderers/text_renderer.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart';
/// [TextPaint] applies a Flutter [TextStyle] to a string of

View File

@ -3,9 +3,9 @@ import 'package:flame/src/anchor.dart';
import 'package:flame/text.dart';
/// [TextRenderer] is an abstract interface for a class that can convert an
/// arbitrary string of text into a renderable [TextElement].
/// arbitrary string of text into a renderable [InlineTextElement].
abstract class TextRenderer {
TextElement format(String text);
InlineTextElement format(String text);
LineMetrics getLineMetrics(String text) {
return format(text).metrics;

View File

@ -1,9 +1,9 @@
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart';
import 'package:meta/meta.dart';
@immutable
class BackgroundStyle extends Style {
class BackgroundStyle extends FlameTextStyle {
BackgroundStyle({
Color? color,
Paint? paint,

View File

@ -1,13 +1,11 @@
import 'package:flame/src/text/styles/background_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/text.dart';
import 'package:flutter/painting.dart' hide TextStyle;
import 'package:meta/meta.dart';
/// [BlockStyle] is a generic descriptor for a visual appearance of a block-
/// level element.
@immutable
class BlockStyle extends Style {
class BlockStyle extends FlameTextStyle {
const BlockStyle({
EdgeInsets? margin,
EdgeInsets? padding,
@ -19,7 +17,7 @@ class BlockStyle extends Style {
final EdgeInsets? _margin;
final EdgeInsets? _padding;
final BackgroundStyle? background;
final FlameTextStyle? text;
final InlineTextStyle? text;
EdgeInsets get margin => _margin ?? EdgeInsets.zero;
EdgeInsets get padding => _padding ?? EdgeInsets.zero;
@ -30,7 +28,7 @@ class BlockStyle extends Style {
margin: other._margin ?? _margin,
padding: other._padding ?? _padding,
background: other.background ?? background,
text: Style.merge(text, other.text),
text: FlameTextStyle.merge(text, other.text),
);
}
}

View File

@ -1,12 +1,5 @@
import 'package:flame/src/text/nodes/bold_text_node.dart';
import 'package:flame/src/text/nodes/header_node.dart';
import 'package:flame/src/text/nodes/italic_text_node.dart';
import 'package:flame/src/text/nodes/paragraph_node.dart';
import 'package:flame/src/text/styles/background_style.dart';
import 'package:flame/src/text/styles/block_style.dart';
import 'package:flame/src/text/styles/flame_text_style.dart';
import 'package:flame/src/text/styles/overflow.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flame/text.dart';
import 'package:flutter/painting.dart' show EdgeInsets;
/// [DocumentStyle] is a user-facing description of how to render an entire
@ -18,15 +11,15 @@ import 'package:flutter/painting.dart' show EdgeInsets;
///
/// All styles that collectively describe how to render text are organized into
/// a tree, with [DocumentStyle] at the root.
class DocumentStyle extends Style {
class DocumentStyle extends FlameTextStyle {
DocumentStyle({
this.width,
this.height,
this.padding = EdgeInsets.zero,
this.background,
FlameTextStyle? text,
FlameTextStyle? boldText,
FlameTextStyle? italicText,
InlineTextStyle? text,
InlineTextStyle? boldText,
InlineTextStyle? italicText,
BlockStyle? paragraph,
BlockStyle? header1,
BlockStyle? header2,
@ -34,20 +27,22 @@ class DocumentStyle extends Style {
BlockStyle? header4,
BlockStyle? header5,
BlockStyle? header6,
}) : _text = Style.merge(text, DocumentStyle.defaultTextStyle),
_boldText = Style.merge(boldText, BoldTextNode.defaultStyle),
_italicText = Style.merge(italicText, ItalicTextNode.defaultStyle),
_paragraph = Style.merge(paragraph, ParagraphNode.defaultStyle),
_header1 = Style.merge(header1, HeaderNode.defaultStyleH1),
_header2 = Style.merge(header2, HeaderNode.defaultStyleH2),
_header3 = Style.merge(header3, HeaderNode.defaultStyleH3),
_header4 = Style.merge(header4, HeaderNode.defaultStyleH4),
_header5 = Style.merge(header5, HeaderNode.defaultStyleH5),
_header6 = Style.merge(header6, HeaderNode.defaultStyleH6);
}) : _text = FlameTextStyle.merge(text, DocumentStyle.defaultTextStyle),
_boldText = FlameTextStyle.merge(boldText, BoldTextNode.defaultStyle),
_italicText =
FlameTextStyle.merge(italicText, ItalicTextNode.defaultStyle),
_paragraph =
FlameTextStyle.merge(paragraph, ParagraphNode.defaultStyle),
_header1 = FlameTextStyle.merge(header1, HeaderNode.defaultStyleH1),
_header2 = FlameTextStyle.merge(header2, HeaderNode.defaultStyleH2),
_header3 = FlameTextStyle.merge(header3, HeaderNode.defaultStyleH3),
_header4 = FlameTextStyle.merge(header4, HeaderNode.defaultStyleH4),
_header5 = FlameTextStyle.merge(header5, HeaderNode.defaultStyleH5),
_header6 = FlameTextStyle.merge(header6, HeaderNode.defaultStyleH6);
final FlameTextStyle? _text;
final FlameTextStyle? _boldText;
final FlameTextStyle? _italicText;
final InlineTextStyle? _text;
final InlineTextStyle? _boldText;
final InlineTextStyle? _italicText;
final BlockStyle? _paragraph;
final BlockStyle? _header1;
final BlockStyle? _header2;
@ -96,9 +91,9 @@ class DocumentStyle extends Style {
/// document page(s).
final BackgroundStyle? background;
FlameTextStyle get text => _text!;
FlameTextStyle get boldText => _boldText!;
FlameTextStyle get italicText => _italicText!;
InlineTextStyle get text => _text!;
InlineTextStyle get boldText => _boldText!;
InlineTextStyle get italicText => _italicText!;
/// Style for [ParagraphNode]s.
BlockStyle get paragraph => _paragraph!;
@ -111,7 +106,7 @@ class DocumentStyle extends Style {
BlockStyle get header5 => _header5!;
BlockStyle get header6 => _header6!;
static FlameTextStyle defaultTextStyle = FlameTextStyle(fontSize: 16.0);
static InlineTextStyle defaultTextStyle = InlineTextStyle(fontSize: 16.0);
@override
DocumentStyle copyWith(DocumentStyle other) {
@ -130,8 +125,9 @@ class DocumentStyle extends Style {
);
}
final Map<Style, Map<Style, Style>> _mergedStylesCache = {};
Style? merge(Style? style1, Style? style2) {
final Map<FlameTextStyle, Map<FlameTextStyle, FlameTextStyle>>
_mergedStylesCache = {};
FlameTextStyle? merge(FlameTextStyle? style1, FlameTextStyle? style2) {
if (style1 == null) {
return style2;
} else if (style2 == null) {

View File

@ -1,55 +1,30 @@
import 'package:flame/src/text/renderers/text_paint.dart';
import 'package:flame/src/text/renderers/text_renderer.dart';
import 'package:flame/src/text/styles/style.dart';
import 'package:flutter/rendering.dart';
import 'package:meta/meta.dart';
import 'package:flame/text.dart';
@immutable
class FlameTextStyle extends Style {
FlameTextStyle({
this.color,
this.fontFamily,
this.fontSize,
this.fontScale,
this.fontWeight,
this.fontStyle,
this.letterSpacing,
});
/// A [FlameTextStyle] is a base class for several classes that collectively
/// describe the desired visual appearance of a "rich-text" document.
///
/// The style classes mostly are collections of properties that describe how a
/// potential document should be formatted. However, they have little logic
/// beyond that. The style classes are then passed to document `Node`s so that
/// the content of a document can be formatted.
///
/// Various [FlameTextStyle] classes are organized into a tree, with
/// [DocumentStyle] at the root.
///
/// The tree of [FlameTextStyle]s is roughly equivalent to a CSS stylesheet.
abstract class FlameTextStyle {
const FlameTextStyle();
final Color? color;
final String? fontFamily;
final double? fontSize;
final double? fontScale;
final FontWeight? fontWeight;
final FontStyle? fontStyle;
final double? letterSpacing;
FlameTextStyle copyWith(covariant FlameTextStyle other);
late final TextRenderer renderer = asTextRenderer();
@override
FlameTextStyle copyWith(FlameTextStyle other) {
return FlameTextStyle(
color: color ?? other.color,
fontFamily: fontFamily ?? other.fontFamily,
fontSize: fontSize ?? other.fontSize,
fontScale: fontScale ?? other.fontScale,
fontWeight: fontWeight ?? other.fontWeight,
fontStyle: fontStyle ?? other.fontStyle,
letterSpacing: letterSpacing ?? other.letterSpacing,
);
}
@internal
TextPaint asTextRenderer() {
return TextPaint(
style: TextStyle(
color: color,
fontFamily: fontFamily,
fontSize: fontSize! * (fontScale ?? 1.0),
fontWeight: fontWeight,
fontStyle: fontStyle,
letterSpacing: letterSpacing,
),
);
static T? merge<T extends FlameTextStyle>(T? style1, T? style2) {
if (style1 == null) {
return style2;
} else if (style2 == null) {
return style1;
} else {
assert(style1.runtimeType == style2.runtimeType);
return style1.copyWith(style2) as T;
}
}
}

View File

@ -0,0 +1,53 @@
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart';
import 'package:meta/meta.dart';
@immutable
class InlineTextStyle extends FlameTextStyle {
InlineTextStyle({
this.color,
this.fontFamily,
this.fontSize,
this.fontScale,
this.fontWeight,
this.fontStyle,
this.letterSpacing,
});
final Color? color;
final String? fontFamily;
final double? fontSize;
final double? fontScale;
final FontWeight? fontWeight;
final FontStyle? fontStyle;
final double? letterSpacing;
late final TextRenderer renderer = asTextRenderer();
@override
InlineTextStyle copyWith(InlineTextStyle other) {
return InlineTextStyle(
color: color ?? other.color,
fontFamily: fontFamily ?? other.fontFamily,
fontSize: fontSize ?? other.fontSize,
fontScale: fontScale ?? other.fontScale,
fontWeight: fontWeight ?? other.fontWeight,
fontStyle: fontStyle ?? other.fontStyle,
letterSpacing: letterSpacing ?? other.letterSpacing,
);
}
@internal
TextPaint asTextRenderer() {
return TextPaint(
style: TextStyle(
color: color,
fontFamily: fontFamily,
fontSize: fontSize! * (fontScale ?? 1.0),
fontWeight: fontWeight,
fontStyle: fontStyle,
letterSpacing: letterSpacing,
),
);
}
}

View File

@ -1,30 +0,0 @@
import 'package:flame/src/text/styles/document_style.dart';
/// A [Style] is a base class for several classes that collectively describe
/// the desired visual appearance of a "rich-text" document.
///
/// The style classes mostly are collections of properties that describe how a
/// potential document should be formatted. However, they have little logic
/// beyond that. The style classes are then passed to document `Node`s so that
/// the content of a document can be formatted.
///
/// Various [Style] classes are organized into a tree, with [DocumentStyle] at
/// the root.
///
/// The tree of [Style]s is roughly equivalent to a CSS stylesheet.
abstract class Style {
const Style();
Style copyWith(covariant Style other);
static T? merge<T extends Style>(T? style1, T? style2) {
if (style1 == null) {
return style2;
} else if (style2 == null) {
return style1;
} else {
assert(style1.runtimeType == style2.runtimeType);
return style1.copyWith(style2) as T;
}
}
}

View File

@ -4,7 +4,7 @@ export 'src/text/common/glyph.dart' show Glyph;
export 'src/text/common/line_metrics.dart' show LineMetrics;
export 'src/text/common/sprite_font.dart' show SpriteFont;
export 'src/text/elements/block_element.dart' show BlockElement;
export 'src/text/elements/element.dart' show Element;
export 'src/text/elements/inline_text_element.dart' show InlineTextElement;
export 'src/text/elements/rect_element.dart' show RectElement;
export 'src/text/elements/rrect_element.dart' show RRectElement;
export 'src/text/elements/sprite_font_text_element.dart'
@ -15,9 +15,10 @@ export 'src/text/elements/text_painter_text_element.dart'
export 'src/text/nodes/block_node.dart' show BlockNode;
export 'src/text/nodes/bold_text_node.dart' show BoldTextNode;
export 'src/text/nodes/column_node.dart' show ColumnNode;
export 'src/text/nodes/document_node.dart' show DocumentNode;
export 'src/text/nodes/document_root.dart' show DocumentRoot;
export 'src/text/nodes/group_text_node.dart' show GroupTextNode;
export 'src/text/nodes/header_node.dart' show HeaderNode;
export 'src/text/nodes/inline_text_node.dart' show InlineTextNode;
export 'src/text/nodes/italic_text_node.dart' show ItalicTextNode;
export 'src/text/nodes/paragraph_node.dart' show ParagraphNode;
export 'src/text/nodes/plain_text_node.dart' show PlainTextNode;
@ -31,4 +32,4 @@ export 'src/text/styles/background_style.dart' show BackgroundStyle;
export 'src/text/styles/block_style.dart' show BlockStyle;
export 'src/text/styles/document_style.dart' show DocumentStyle;
export 'src/text/styles/flame_text_style.dart' show FlameTextStyle;
export 'src/text/styles/style.dart' show Style;
export 'src/text/styles/inline_text_style.dart' show InlineTextStyle;

View File

@ -34,12 +34,12 @@ void main() {
class _CustomTextRenderer extends TextRenderer {
@override
TextElement format(String text) {
InlineTextElement format(String text) {
return CustomTextElement();
}
}
class CustomTextElement extends TextElement {
class CustomTextElement extends InlineTextElement {
@override
LineMetrics get metrics => LineMetrics();

View File

@ -24,10 +24,10 @@ class DebugTextRenderer extends TextRenderer {
final FontStyle fontStyle;
@override
TextElement format(String text) => _DebugTextElement(this, text);
InlineTextElement format(String text) => _DebugTextElement(this, text);
}
class _DebugTextElement extends TextElement {
class _DebugTextElement extends InlineTextElement {
_DebugTextElement(this.style, this.text) {
final charWidth = style.fontSize * 1.0;
final charHeight = style.fontSize;

View File

@ -45,7 +45,7 @@ void main() {
class TextElementsComponent extends PositionComponent {
TextElementsComponent(this.elements);
final List<TextElement> elements;
final List<InlineTextElement> elements;
@override
void render(Canvas canvas) {