paragraph.dart 3.72 KB
Newer Older
1 2 3 4
// Copyright 2015 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

5
import 'package:flutter/painting.dart';
6 7 8

import 'box.dart';
import 'object.dart';
9

10 11 12 13 14 15 16 17 18 19
export 'package:flutter/painting.dart' show
  FontStyle,
  FontWeight,
  PlainTextSpan,
  StyledTextSpan,
  TextAlign,
  TextBaseline,
  TextDecoration,
  TextDecorationStyle,
  TextSpan,
20
  TextStyle;
21

22
/// A render object that displays a paragraph of text
23 24
class RenderParagraph extends RenderBox {

25 26 27
  RenderParagraph(
    TextSpan text
  ) : textPainter = new TextPainter(text) {
28
    assert(text != null);
29 30
  }

31
  final TextPainter textPainter;
32 33 34

  BoxConstraints _constraintsForCurrentLayout; // when null, we don't have a current layout

35
  /// The text to display
36
  TextSpan get text => textPainter.text;
37
  void set text(TextSpan value) {
38
    if (textPainter.text == value)
39
      return;
40
    textPainter.text = value;
41 42 43 44
    _constraintsForCurrentLayout = null;
    markNeedsLayout();
  }

45
  void layoutText(BoxConstraints constraints) {
46
    assert(constraints != null);
47
    assert(constraints.isNormalized);
48 49
    if (_constraintsForCurrentLayout == constraints)
      return; // already cached this layout
50
    textPainter.maxWidth = constraints.maxWidth;
51 52 53 54
    textPainter.minWidth = constraints.minWidth;
    textPainter.minHeight = constraints.minHeight;
    textPainter.maxHeight = constraints.maxHeight;
    textPainter.layout();
55 56 57 58 59
    // By default, we shrinkwrap to the intrinsic width.
    double width = constraints.constrainWidth(textPainter.maxIntrinsicWidth);
    textPainter.minWidth = width;
    textPainter.maxWidth = width;
    textPainter.layout();
60 61 62 63
    _constraintsForCurrentLayout = constraints;
  }

  double getMinIntrinsicWidth(BoxConstraints constraints) {
64
    layoutText(constraints);
65
    return constraints.constrainWidth(textPainter.minIntrinsicWidth);
66 67 68
  }

  double getMaxIntrinsicWidth(BoxConstraints constraints) {
69
    layoutText(constraints);
70
    return constraints.constrainWidth(textPainter.maxIntrinsicWidth);
71 72 73
  }

  double _getIntrinsicHeight(BoxConstraints constraints) {
74
    layoutText(constraints);
75
    return constraints.constrainHeight(textPainter.size.height);
76 77 78
  }

  double getMinIntrinsicHeight(BoxConstraints constraints) {
79
    assert(constraints.isNormalized);
80 81 82 83
    return _getIntrinsicHeight(constraints);
  }

  double getMaxIntrinsicHeight(BoxConstraints constraints) {
84
    assert(constraints.isNormalized);
85 86 87 88 89
    return _getIntrinsicHeight(constraints);
  }

  double computeDistanceToActualBaseline(TextBaseline baseline) {
    assert(!needsLayout);
90 91
    layoutText(constraints);
    return textPainter.computeDistanceToActualBaseline(baseline);
92 93
  }

Adam Barth's avatar
Adam Barth committed
94 95
  bool hitTestSelf(Point position) => true;

96
  void performLayout() {
97
    layoutText(constraints);
98
    size = constraints.constrain(textPainter.size);
99 100
  }

101
  void paint(PaintingContext context, Offset offset) {
102 103
    // Ideally we could compute the min/max intrinsic width/height with a
    // non-destructive operation. However, currently, computing these values
104
    // will destroy state inside the painter. If that happens, we need to
105 106 107 108
    // get back the correct state by calling _layout again.
    //
    // TODO(abarth): Make computing the min/max intrinsic width/height
    // a non-destructive operation.
109 110
    layoutText(constraints);
    textPainter.paint(context.canvas, offset);
111 112 113 114
  }

  // we should probably expose a way to do precise (inter-glpyh) hit testing

115 116 117 118 119
  String debugDescribeChildren(String prefix) {
    return '$prefix \u2558\u2550\u2566\u2550\u2550 text \u2550\u2550\u2550\n'
           '${text.toString("$prefix   \u2551 ")}\n'
           '$prefix   \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\n'
           '$prefix\n';
120 121
  }
}