Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add accessor to determine a TextElement size #3130

Merged
merged 3 commits into from
Apr 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/.cspell/flame_dictionary.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ Dashbook # UI development tool for Flutter https://github.com/bluefireteam/dashb
emberquest # Ember Quest, our platformer tutorial game
Hermione # A character from the book Harry Potter
Kawabunga # Word expressing exhilaration, of unclear origins but popularized by the show Teenage Mutant Ninja Turtles
Kenobi # Eminent Jedi Master, General of the Republic Army, Obi-Wan Kenobi
Mocktail # A library for Dart that automatically creates mocks for tests https://github.com/felangel/mocktail
Nakama # An open-source server designed to power modern games and apps https://github.com/Allan-Nava/nakama-flutter
Overmind # A character in the game StarCraft
Expand Down
11 changes: 7 additions & 4 deletions packages/flame/lib/src/components/text_element_component.dart
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import 'dart:ui';

import 'package:flame/components.dart';
import 'package:flame/extensions.dart';
import 'package:flame/text.dart';

class TextElementComponent extends PositionComponent {
final Vector2? documentSize;
TextElement element;

TextElementComponent({
required this.element,
super.position,
this.documentSize,
super.size,
super.position,
super.scale,
super.angle,
super.anchor,
Expand Down Expand Up @@ -37,10 +38,12 @@ class TextElementComponent extends PositionComponent {
width: effectiveSize.x,
height: effectiveSize.y,
);
final box = element.boundingBox;
return TextElementComponent(
element: element,
position: position,
size: effectiveSize,
documentSize: effectiveSize,
size: box.bottomRight.toVector2(),
scale: scale,
angle: angle,
anchor: anchor,
Expand Down
14 changes: 13 additions & 1 deletion packages/flame/lib/src/text/elements/group_element.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:flame/extensions.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart' hide TextStyle;

class GroupElement extends BlockElement {
GroupElement({
Expand All @@ -19,4 +19,16 @@ class GroupElement extends BlockElement {
void draw(Canvas canvas) {
children.forEach((child) => child.draw(canvas));
}

@override
Rect get boundingBox {
return children.fold<Rect?>(
null,
(previousValue, element) {
final box = element.boundingBox;
return previousValue?.expandToInclude(box) ?? box;
},
) ??
Rect.zero;
}
}
3 changes: 3 additions & 0 deletions packages/flame/lib/src/text/elements/inline_text_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -20,4 +20,7 @@ abstract class InlineTextElement extends TextElement {
);
draw(canvas);
}

@override
Rect get boundingBox => metrics.toRect();
}
3 changes: 3 additions & 0 deletions packages/flame/lib/src/text/elements/rect_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,7 @@ class RectElement extends TextElement {
void draw(Canvas canvas) {
canvas.drawRect(_rect, _paint);
}

@override
Rect get boundingBox => _rect;
}
3 changes: 3 additions & 0 deletions packages/flame/lib/src/text/elements/rrect_element.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,7 @@ class RRectElement extends TextElement {
void draw(Canvas canvas) {
canvas.drawRRect(_rrect, _paint);
}

@override
Rect get boundingBox => _rrect.outerRect;
}
3 changes: 3 additions & 0 deletions packages/flame/lib/src/text/elements/text_element.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:ui';
import 'package:flame/extensions.dart';
import 'package:flame/text.dart';

/// An [TextElement] is a basic rendering block of a rich-text document.
Expand All @@ -21,4 +22,6 @@ abstract class TextElement {
/// calling the [translate] method, or applying a translation transform to the
/// canvas itself.
void draw(Canvas canvas);

Rect get boundingBox;
}
33 changes: 26 additions & 7 deletions packages/flame/test/components/element_component_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,29 +4,35 @@ import 'package:test/test.dart';

void main() {
group('ElementComponent', () {
test('size can be specified via the size parameter', () {
test('document size can be specified via the size parameter', () {
final c = TextElementComponent.fromDocument(
document: DocumentRoot([]),
size: Vector2(100, 200),
);
expect(c.size, equals(Vector2(100, 200)));
expect(c.documentSize, equals(Vector2(100, 200)));
expect(c.size, equals(Vector2.zero()));
});
test('size can be specified via the style', () {

test('document size can be specified via the style', () {
final c = TextElementComponent.fromDocument(
document: DocumentRoot([]),
style: DocumentStyle(width: 100, height: 200),
);
expect(c.size, equals(Vector2(100, 200)));
expect(c.documentSize, equals(Vector2(100, 200)));
expect(c.size, equals(Vector2.zero()));
});
test('size can be super-specified if matching', () {

test('document size can be super-specified if matching', () {
final c = TextElementComponent.fromDocument(
document: DocumentRoot([]),
style: DocumentStyle(width: 100, height: 200),
size: Vector2(100, 200),
);
expect(c.size, equals(Vector2(100, 200)));
expect(c.documentSize, equals(Vector2(100, 200)));
expect(c.size, equals(Vector2.zero()));
});
test('size must be specified', () {

test('document size must be specified', () {
expect(
() {
TextElementComponent.fromDocument(
Expand All @@ -42,6 +48,7 @@ void main() {
),
);
});

test('size cannot be over-specified if mismatched', () {
expect(
() {
Expand All @@ -60,5 +67,17 @@ void main() {
),
);
});

test('size is computed from the element bounding box', () {
final c = TextElementComponent.fromDocument(
document: DocumentRoot([
ParagraphNode.simple('line 1'),
ParagraphNode.simple('line 2'),
]),
size: Vector2(800, 160), // oversized
);
expect(c.documentSize, equals(Vector2(800, 160)));
expect(c.size, equals(Vector2(96, 44)));
});
});
}
68 changes: 68 additions & 0 deletions packages/flame/test/text/text_element_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:flame/src/text/elements/group_element.dart';
import 'package:flame/text.dart';
import 'package:flutter/rendering.dart';
import 'package:test/test.dart';

void main() {
group('text elements', () {
test('bounding box for empty group', () {
final emptyGroup = GroupElement(width: 0, height: 0, children: []);
expect(emptyGroup.boundingBox, Rect.zero);
});

test('bounding box for inline elements', () {
final document = DocumentRoot([
ParagraphNode.group([
PlainTextNode('Hello'),
]),
]);

final element1 = document.format(
DocumentStyle(
paragraph: const BlockStyle(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
),
),
width: 80,
height: 16,
);
const expected = Rect.fromLTWH(0, 0, 80, 16);

expect(element1.boundingBox, expected);
final element2 = element1.children.single as GroupElement;
expect(element2.boundingBox, expected);
final element3 = element2.children.single as InlineTextElement;
expect(element3.boundingBox, expected);
});

test('bounding box is composed', () {
final document = DocumentRoot([
ParagraphNode.group([
PlainTextNode('Hello, '),
PlainTextNode('there'),
]),
ParagraphNode.group([
ItalicTextNode.simple('General '),
BoldTextNode.simple('Kenobi'),
]),
]);

final element1 = document.format(
DocumentStyle(
paragraph: const BlockStyle(
margin: EdgeInsets.zero,
padding: EdgeInsets.zero,
),
),
width: 600,
height: 400,
);
expect(element1.boundingBox, const Rect.fromLTWH(0, 0, 224, 32));
final element2 = element1.children[0] as GroupElement;
expect(element2.boundingBox, const Rect.fromLTWH(0, 0, 192, 16));
final element3 = element1.children[1] as GroupElement;
expect(element3.boundingBox, const Rect.fromLTWH(0, 16, 224, 16));
});
});
}
Loading