error.dart 6.07 KB
Newer Older
Ian Hickson's avatar
Ian Hickson committed
1
// Copyright 2014 The Flutter Authors. All rights reserved.
2 3 4
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

Adam Barth's avatar
Adam Barth committed
5
import 'dart:ui' as ui show Paragraph, ParagraphBuilder, ParagraphConstraints, ParagraphStyle, TextStyle;
6

7 8
import 'package:flutter/foundation.dart';

9 10
import 'box.dart';
import 'object.dart';
11 12 13

const double _kMaxWidth = 100000.0;
const double _kMaxHeight = 100000.0;
14

15 16 17 18 19 20 21 22 23 24 25 26
/// A render object used as a placeholder when an error occurs.
///
/// The box will be painted in the color given by the
/// [RenderErrorBox.backgroundColor] static property.
///
/// A message can be provided. To simplify the class and thus help reduce the
/// likelihood of this class itself being the source of errors, the message
/// cannot be changed once the object has been created. If provided, the text
/// will be painted on top of the background, using the styles given by the
/// [RenderErrorBox.textStyle] and [RenderErrorBox.paragraphStyle] static
/// properties.
///
27 28 29
/// Again to help simplify the class, if the parent has left the constraints
/// unbounded, this box tries to be 100000.0 pixels wide and high, to
/// approximate being infinitely high but without using infinities.
30
class RenderErrorBox extends RenderBox {
31
  /// Creates a RenderErrorBox render object.
32 33 34 35 36 37 38 39 40 41 42 43 44 45
  ///
  /// A message can optionally be provided. If a message is provided, an attempt
  /// will be made to render the message when the box paints.
  RenderErrorBox([ this.message = '' ]) {
    try {
      if (message != '') {
        // This class is intentionally doing things using the low-level
        // primitives to avoid depending on any subsystems that may have ended
        // up in an unstable state -- after all, this class is mainly used when
        // things have gone wrong.
        //
        // Generally, the much better way to draw text in a RenderObject is to
        // use the TextPainter class. If you're looking for code to crib from,
        // see the paragraph.dart file and the RenderParagraph class.
46
        final ui.ParagraphBuilder builder = ui.ParagraphBuilder(paragraphStyle);
47
        builder.pushStyle(textStyle);
48
        builder.addText(message);
49
        _paragraph = builder.build();
50 51
      } else {
        _paragraph = null;
52
      }
53
    } catch (error) {
54 55 56
      // If an error happens here we're in a terrible state, so we really should
      // just forget about it and let the developer deal with the already-reported
      // errors. It's unlikely that these errors are going to help with that.
57
    }
58 59 60 61 62
  }

  /// The message to attempt to display at paint time.
  final String message;

63
  late final ui.Paragraph? _paragraph;
64

65
  @override
66
  double computeMaxIntrinsicWidth(double height) {
67
    return _kMaxWidth;
68 69
  }

70
  @override
71
  double computeMaxIntrinsicHeight(double width) {
72
    return _kMaxHeight;
73 74
  }

75
  @override
76 77
  bool get sizedByParent => true;

78
  @override
79
  bool hitTestSelf(Offset position) => true;
Adam Barth's avatar
Adam Barth committed
80

81
  @override
82 83
  @protected
  Size computeDryLayout(covariant BoxConstraints constraints) {
84
    return constraints.constrain(const Size(_kMaxWidth, _kMaxHeight));
85 86
  }

87 88 89 90 91 92 93 94 95 96 97
  /// The distance to place around the text.
  ///
  /// This is intended to ensure that if the [RenderErrorBox] is placed at the top left
  /// of the screen, under the system's status bar, the error text is still visible in
  /// the area below the status bar.
  ///
  /// The padding is ignored if the error box is smaller than the padding.
  ///
  /// See also:
  ///
  ///  * [minimumWidth], which controls how wide the box must be before the
98
  ///    horizontal padding is applied.
99 100 101 102 103 104 105 106
  static EdgeInsets padding = const EdgeInsets.fromLTRB(64.0, 96.0, 64.0, 12.0);

  /// The width below which the horizontal padding is not applied.
  ///
  /// If the left and right padding would reduce the available width to less than
  /// this value, then the text is rendered flush with the left edge.
  static double minimumWidth = 200.0;

107
  /// The color to use when painting the background of [RenderErrorBox] objects.
108 109 110 111 112 113 114 115 116 117 118 119
  ///
  /// Defaults to red in debug mode, a light gray otherwise.
  static Color backgroundColor = _initBackgroundColor();

  static Color _initBackgroundColor() {
    Color result = const Color(0xF0C0C0C0);
    assert(() {
      result = const Color(0xF0900000);
      return true;
    }());
    return result;
  }
120 121

  /// The text style to use when painting [RenderErrorBox] objects.
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
  ///
  /// Defaults to a yellow monospace font in debug mode, and a dark gray
  /// sans-serif font otherwise.
  static ui.TextStyle textStyle = _initTextStyle();

  static ui.TextStyle _initTextStyle() {
    ui.TextStyle result = ui.TextStyle(
      color: const Color(0xFF303030),
      fontFamily: 'sans-serif',
      fontSize: 18.0,
    );
    assert(() {
      result = ui.TextStyle(
        color: const Color(0xFFFFFF66),
        fontFamily: 'monospace',
        fontSize: 14.0,
        fontWeight: FontWeight.bold,
      );
      return true;
    }());
    return result;
  }
144 145

  /// The paragraph style to use when painting [RenderErrorBox] objects.
146
  static ui.ParagraphStyle paragraphStyle = ui.ParagraphStyle(
147 148
    textDirection: TextDirection.ltr,
    textAlign: TextAlign.left,
149 150
  );

151
  @override
152
  void paint(PaintingContext context, Offset offset) {
153
    try {
154
      context.canvas.drawRect(offset & size, Paint() .. color = backgroundColor);
155
      if (_paragraph != null) {
156 157 158 159 160 161
        double width = size.width;
        double left = 0.0;
        double top = 0.0;
        if (width > padding.left + minimumWidth + padding.right) {
          width -= padding.left + padding.right;
          left += padding.left;
162
        }
163 164
        _paragraph.layout(ui.ParagraphConstraints(width: width));
        if (size.height > padding.top + _paragraph.height + padding.bottom) {
165 166
          top += padding.top;
        }
167
        context.canvas.drawParagraph(_paragraph, offset + Offset(left, top));
168
      }
169 170 171 172
    } catch (error) {
      // If an error happens here we're in a terrible state, so we really should
      // just forget about it and let the developer deal with the already-reported
      // errors. It's unlikely that these errors are going to help with that.
173
    }
174 175
  }
}