mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Styling for text fragments
This is a completion of Eric's WIP patch: https://codereview.chromium.org/1179663005/ Low level support for creating a paragraph that contains runs of styled text. The styles may be nested. The Paragraph and RenderParagraph classes have been replaced by Inline and RenderInline. Styled text is defined with a tree of InlineText and InlineStyle objects. R=abarth@chromium.org Review URL: https://codereview.chromium.org/1177833012.
This commit is contained in:
parent
a7aa951329
commit
61b71a6f32
@ -75,8 +75,12 @@ porchetta bacon kevin meatball meatloaf pig beef ribs chicken. Brisket ribeye
|
||||
andouille leberkas capicola meatloaf. Chicken pig ball tip pork picanha bresaola
|
||||
alcatra. Pork pork belly alcatra, flank chuck drumstick biltong doner jowl.
|
||||
Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
|
||||
RenderParagraph paragraph = new RenderParagraph(text: meatyString, color: const Color(0xFF009900));
|
||||
padding = new RenderPadding(padding: const EdgeDims.all(10.0), child: paragraph);
|
||||
var text = new InlineStyle(
|
||||
new TextStyle(color: const Color(0xFF009900)),
|
||||
[new InlineText(meatyString)]);
|
||||
padding = new RenderPadding(
|
||||
padding: const EdgeDims.all(10.0),
|
||||
child: new RenderParagraph(text));
|
||||
column.add(padding);
|
||||
|
||||
// Bottom cell
|
||||
|
||||
@ -20,7 +20,7 @@ void main() {
|
||||
var table = new RenderFlex(direction: FlexDirection.vertical);
|
||||
|
||||
void addRow(FlexJustifyContent justify) {
|
||||
RenderParagraph paragraph = new RenderParagraph(text: "${justify}");
|
||||
RenderParagraph paragraph = new RenderParagraph(new InlineText("${justify}"));
|
||||
table.add(new RenderPadding(child: paragraph, padding: new EdgeDims.only(top: 20.0)));
|
||||
var row = new RenderFlex(direction: FlexDirection.horizontal);
|
||||
row.add(new RenderSolidColorBox(const Color(0xFFFFCCCC), desiredSize: new Size(80.0, 60.0)));
|
||||
|
||||
@ -31,9 +31,12 @@ andouille leberkas capicola meatloaf. Chicken pig ball tip pork picanha bresaola
|
||||
alcatra. Pork pork belly alcatra, flank chuck drumstick biltong doner jowl.
|
||||
Pancetta meatball tongue tenderloin rump tail jowl boudin.""";
|
||||
|
||||
var text = new InlineStyle(
|
||||
new TextStyle(color: const Color(0xFF009900)),
|
||||
[new InlineText(meatyString)]);
|
||||
child = new RenderDecoratedBox(
|
||||
decoration: new BoxDecoration(backgroundColor: const Color(0xFFFFFFFF)),
|
||||
child: new RenderParagraph(text: meatyString, color: const Color(0xFF009900))
|
||||
child: new RenderParagraph(text)
|
||||
);
|
||||
flexRoot.add(child);
|
||||
child.parentData.flex = 1;
|
||||
|
||||
@ -80,13 +80,14 @@ class RenderTouchDemo extends RenderBox {
|
||||
AppView app;
|
||||
|
||||
void main() {
|
||||
var para = new RenderParagraph(text: "Touch me!");
|
||||
var paragraph = new RenderParagraph(new InlineText("Touch me!"));
|
||||
var stack = new RenderStack(children: [
|
||||
new RenderTouchDemo(),
|
||||
para,
|
||||
paragraph,
|
||||
]);
|
||||
// Make the paragraph not fill the whole screen so it doesn't eat events.
|
||||
para.parentData..top = 40.0
|
||||
..left = 20.0;
|
||||
// Prevent the RenderParagraph from filling the whole screen so
|
||||
// that it doesn't eat events.
|
||||
paragraph.parentData..top = 40.0
|
||||
..left = 20.0;
|
||||
app = new AppView(root: stack);
|
||||
}
|
||||
|
||||
@ -93,8 +93,6 @@ class EditableText extends Component {
|
||||
// // style: _cursorStyle
|
||||
// ));
|
||||
|
||||
return new Paragraph(
|
||||
text: hack
|
||||
);
|
||||
return new Text(hack);
|
||||
}
|
||||
}
|
||||
|
||||
@ -7,11 +7,6 @@ import 'dart:sky' as sky;
|
||||
import 'box.dart';
|
||||
import 'object.dart';
|
||||
|
||||
class RenderInline extends RenderObject {
|
||||
RenderInline(this.data);
|
||||
String data;
|
||||
}
|
||||
|
||||
enum FontWeight {
|
||||
light, // 300
|
||||
regular, // 400
|
||||
@ -69,6 +64,29 @@ class TextStyle {
|
||||
return value;
|
||||
}
|
||||
|
||||
void _applyToCSSStyle(sky.CSSStyleDeclaration cssStyle) {
|
||||
if (color != null) {
|
||||
cssStyle['color'] = 'rgba(${color.red}, ${color.green}, ${color.blue}, ${color.alpha / 255.0})';
|
||||
}
|
||||
if (fontSize != null) {
|
||||
cssStyle['font-size'] = "${fontSize}px";
|
||||
}
|
||||
if (fontWeight != null) {
|
||||
cssStyle['font-weight'] = const {
|
||||
FontWeight.light: '300',
|
||||
FontWeight.regular: '400',
|
||||
FontWeight.medium: '500',
|
||||
}[fontWeight];
|
||||
}
|
||||
if (textAlign != null) {
|
||||
cssStyle['text-align'] = const {
|
||||
TextAlign.left: 'left',
|
||||
TextAlign.right: 'right',
|
||||
TextAlign.center: 'center',
|
||||
}[textAlign];
|
||||
}
|
||||
}
|
||||
|
||||
String toString([String prefix = '']) {
|
||||
List<String> result = [];
|
||||
if (color != null)
|
||||
@ -76,15 +94,63 @@ class TextStyle {
|
||||
if (fontSize != null)
|
||||
result.add('${prefix}fontSize: $fontSize');
|
||||
if (fontWeight != null)
|
||||
result.add('${prefix}fontWeight: fontWeight');
|
||||
result.add('${prefix}fontWeight: $fontWeight');
|
||||
if (textAlign != null)
|
||||
result.add('${prefix}textAlign: textAlign');
|
||||
result.add('${prefix}textAlign: $textAlign');
|
||||
if (result.isEmpty)
|
||||
return '${prefix}<no style specified>';
|
||||
return result.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
class InlineBase {
|
||||
sky.Node _toDOM(sky.Document owner);
|
||||
String toString([String prefix = '']);
|
||||
}
|
||||
|
||||
class InlineText extends InlineBase {
|
||||
InlineText(this.text) {
|
||||
assert(text != null);
|
||||
}
|
||||
|
||||
final String text;
|
||||
|
||||
sky.Node _toDOM(sky.Document owner) {
|
||||
return owner.createText(text);
|
||||
}
|
||||
|
||||
String toString([String prefix = '']) => '${prefix}InlineText: "${text}"';
|
||||
}
|
||||
|
||||
class InlineStyle extends InlineBase {
|
||||
InlineStyle(this.style, this.children) {
|
||||
assert(style != null && children != null);
|
||||
}
|
||||
|
||||
final TextStyle style;
|
||||
final List<InlineBase> children;
|
||||
|
||||
sky.Node _toDOM(sky.Document owner) {
|
||||
sky.Element parent = owner.createElement('t');
|
||||
style._applyToCSSStyle(parent.style);
|
||||
for (InlineBase child in children) {
|
||||
parent.appendChild(child._toDOM(owner));
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
String toString([String prefix = '']) {
|
||||
List<String> result = [];
|
||||
result.add('${prefix}InlineStyle:');
|
||||
var indent = '${prefix} ';
|
||||
result.add('${style.toString(indent)}');
|
||||
for (InlineBase child in children) {
|
||||
result.add(child.toString(indent));
|
||||
}
|
||||
return result.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
// Unfortunately, using full precision floating point here causes bad layouts
|
||||
// because floating point math isn't associative. If we add and subtract
|
||||
// padding, for example, we'll get different values when we estimate sizes and
|
||||
@ -98,36 +164,24 @@ double _applyFloatingPointHack(double layoutValue) {
|
||||
|
||||
class RenderParagraph extends RenderBox {
|
||||
|
||||
RenderParagraph({
|
||||
String text,
|
||||
Color color,
|
||||
TextStyle style
|
||||
}) : _style = style {
|
||||
RenderParagraph(InlineBase inlineValue) {
|
||||
_layoutRoot.rootElement = _document.createElement('p');
|
||||
this.text = text;
|
||||
inline = inlineValue;
|
||||
}
|
||||
|
||||
final sky.Document _document = new sky.Document();
|
||||
final sky.LayoutRoot _layoutRoot = new sky.LayoutRoot();
|
||||
|
||||
String get text => (_layoutRoot.rootElement.firstChild as sky.Text).data;
|
||||
void set text (String value) {
|
||||
_layoutRoot.rootElement.setChild(_document.createText(value));
|
||||
InlineBase _inline;
|
||||
BoxConstraints _constraintsForCurrentLayout;
|
||||
|
||||
String get inline => _inline;
|
||||
void set inline (InlineBase value) {
|
||||
_inline = value;
|
||||
_layoutRoot.rootElement.setChild(_inline._toDOM(_document));
|
||||
markNeedsLayout();
|
||||
}
|
||||
|
||||
TextStyle _style;
|
||||
TextStyle get style => _style;
|
||||
void set style (TextStyle value) {
|
||||
if (_style != value) {
|
||||
// TODO(hansmuller): decide if a new layout or paint is needed
|
||||
markNeedsLayout();
|
||||
_style = value;
|
||||
}
|
||||
}
|
||||
|
||||
BoxConstraints _constraintsForCurrentLayout;
|
||||
|
||||
sky.Element _layout(BoxConstraints constraints) {
|
||||
_layoutRoot.maxWidth = constraints.maxWidth;
|
||||
_layoutRoot.minWidth = constraints.minWidth;
|
||||
@ -182,31 +236,6 @@ class RenderParagraph extends RenderBox {
|
||||
if (_constraintsForCurrentLayout != constraints && constraints != null)
|
||||
_layout(constraints);
|
||||
|
||||
if (style != null) {
|
||||
var cssStyle = _layoutRoot.rootElement.style;
|
||||
if (style.color != null) {
|
||||
Color c = style.color;
|
||||
cssStyle['color'] =
|
||||
'rgba(${c.red}, ${c.green}, ${c.blue}, ${c.alpha / 255.0})';
|
||||
}
|
||||
if (style.fontSize != null) {
|
||||
cssStyle['font-size'] = "${style.fontSize}px";
|
||||
}
|
||||
if (style.fontWeight != null) {
|
||||
cssStyle['font-weight'] = const {
|
||||
FontWeight.light: '300',
|
||||
FontWeight.regular: '400',
|
||||
FontWeight.medium: '500',
|
||||
}[style.fontWeight];
|
||||
}
|
||||
if (style.textAlign != null) {
|
||||
cssStyle['text-align'] = const {
|
||||
TextAlign.left: 'left',
|
||||
TextAlign.right: 'right',
|
||||
TextAlign.center: 'center',
|
||||
}[style.textAlign];
|
||||
}
|
||||
}
|
||||
_layoutRoot.paint(canvas);
|
||||
}
|
||||
|
||||
@ -214,9 +243,7 @@ class RenderParagraph extends RenderBox {
|
||||
|
||||
String debugDescribeSettings(String prefix) {
|
||||
String result = '${super.debugDescribeSettings(prefix)}';
|
||||
if (style != null)
|
||||
result += '${prefix}style:\n' + style.toString('$prefix ') + '\n';
|
||||
result += '${prefix}text: ${text}\n';
|
||||
result += '${prefix}inline: ${inline}\n';
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -345,25 +345,22 @@ class Flexible extends ParentDataNode {
|
||||
: super(child, new FlexBoxParentData()..flex = flex, key: key);
|
||||
}
|
||||
|
||||
class Paragraph extends RenderObjectWrapper {
|
||||
|
||||
Paragraph({ String key, this.text, this.style }) : super(key: key);
|
||||
class Inline extends RenderObjectWrapper {
|
||||
Inline({ Object key, this.text }) : super(key: key);
|
||||
|
||||
RenderParagraph get root => super.root;
|
||||
RenderParagraph createNode() => new RenderParagraph(text: text, style: style);
|
||||
RenderParagraph createNode() => new RenderParagraph(text);
|
||||
|
||||
final String text;
|
||||
final TextStyle style;
|
||||
final InlineBase text;
|
||||
|
||||
void syncRenderObject(Widget old) {
|
||||
super.syncRenderObject(old);
|
||||
root.text = text;
|
||||
root.style = style;
|
||||
root.inline = text;
|
||||
}
|
||||
|
||||
void insert(RenderObjectWrapper child, dynamic slot) {
|
||||
assert(false);
|
||||
// Paragraph does not support having children currently
|
||||
// Inline does not support having children currently
|
||||
}
|
||||
|
||||
}
|
||||
@ -373,7 +370,11 @@ class Text extends Component {
|
||||
final String data;
|
||||
final TextStyle style;
|
||||
bool get interchangeable => true;
|
||||
Widget build() => new Paragraph(text: data, style: style);
|
||||
Widget build() {
|
||||
InlineBase text = new InlineText(data);
|
||||
if (style != null) text = new InlineStyle(style, [text]);
|
||||
return new Inline(text: text);
|
||||
}
|
||||
}
|
||||
|
||||
class Image extends RenderObjectWrapper {
|
||||
|
||||
@ -31,7 +31,7 @@ PAINT FOR FRAME #2 ----------------------------------------------
|
||||
2 | | | | | | | TestDisplayList() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | paintChild RenderImage at Point(8.0, 8.0)
|
||||
2 | | | | | | | | TestDisplayList() constructor: 800.0 x 600.0
|
||||
2 | | | | | | paintChild RenderPadding at Point(40.0, 20.0)
|
||||
2 | | | | | | paintChild RenderPadding at Point(40.0, 16.0)
|
||||
2 | | | | | | | TestDisplayList() constructor: 800.0 x 600.0
|
||||
2 | | | | | | | paintChild RenderParagraph at Point(24.0, 0.0)
|
||||
2 | | | | | | | | TestDisplayList() constructor: 800.0 x 600.0
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user