rotated_box.dart 3.76 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.

5 6
// @dart = 2.8

7 8
import 'dart:math' as math;

9
import 'package:flutter/foundation.dart';
10
import 'package:flutter/gestures.dart';
11
import 'package:flutter/painting.dart';
12 13 14 15 16
import 'package:vector_math/vector_math_64.dart';

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

17
const double _kQuarterTurnsInRadians = math.pi / 2.0;
18 19 20 21 22 23 24

/// Rotates its child by a integral number of quarter turns.
///
/// Unlike [RenderTransform], which applies a transform just prior to painting,
/// this object applies its rotation prior to layout, which means the entire
/// rotated box consumes only as much space as required by the rotated child.
class RenderRotatedBox extends RenderBox with RenderObjectWithChildMixin<RenderBox> {
25 26 27
  /// Creates a rotated render box.
  ///
  /// The [quarterTurns] argument must not be null.
28
  RenderRotatedBox({
29
    @required int quarterTurns,
30
    RenderBox child,
31 32
  }) : assert(quarterTurns != null),
       _quarterTurns = quarterTurns {
33 34 35 36 37 38
    this.child = child;
  }

  /// The number of clockwise quarter turns the child should be rotated.
  int get quarterTurns => _quarterTurns;
  int _quarterTurns;
39
  set quarterTurns(int value) {
40 41 42 43 44 45 46 47 48
    assert(value != null);
    if (_quarterTurns == value)
      return;
    _quarterTurns = value;
    markNeedsLayout();
  }

  bool get _isVertical => quarterTurns % 2 == 1;

49
  @override
50
  double computeMinIntrinsicWidth(double height) {
51 52 53
    if (child == null)
      return 0.0;
    return _isVertical ? child.getMinIntrinsicHeight(height) : child.getMinIntrinsicWidth(height);
54 55
  }

56
  @override
57
  double computeMaxIntrinsicWidth(double height) {
58 59 60
    if (child == null)
      return 0.0;
    return _isVertical ? child.getMaxIntrinsicHeight(height) : child.getMaxIntrinsicWidth(height);
61 62
  }

63
  @override
64
  double computeMinIntrinsicHeight(double width) {
65 66 67
    if (child == null)
      return 0.0;
    return _isVertical ? child.getMinIntrinsicWidth(width) : child.getMinIntrinsicHeight(width);
68 69
  }

70
  @override
71
  double computeMaxIntrinsicHeight(double width) {
72 73 74
    if (child == null)
      return 0.0;
    return _isVertical ? child.getMaxIntrinsicWidth(width) : child.getMaxIntrinsicHeight(width);
75 76 77 78
  }

  Matrix4 _paintTransform;

79
  @override
80 81 82 83
  void performLayout() {
    _paintTransform = null;
    if (child != null) {
      child.layout(_isVertical ? constraints.flipped : constraints, parentUsesSize: true);
84 85
      size = _isVertical ? Size(child.size.height, child.size.width) : child.size;
      _paintTransform = Matrix4.identity()
86 87 88 89 90 91 92 93
        ..translate(size.width / 2.0, size.height / 2.0)
        ..rotateZ(_kQuarterTurnsInRadians * (quarterTurns % 4))
        ..translate(-child.size.width / 2.0, -child.size.height / 2.0);
    } else {
      performResize();
    }
  }

94
  @override
95
  bool hitTestChildren(BoxHitTestResult result, { Offset position }) {
96
    assert(_paintTransform != null || debugNeedsLayout || child == null);
97 98
    if (child == null || _paintTransform == null)
      return false;
99 100 101 102 103 104 105
    return result.addWithPaintTransform(
      transform: _paintTransform,
      position: position,
      hitTest: (BoxHitTestResult result, Offset position) {
        return child.hitTest(result, position: position);
      },
    );
106 107 108 109 110 111
  }

  void _paintChild(PaintingContext context, Offset offset) {
    context.paintChild(child, offset);
  }

112
  @override
113 114 115 116 117
  void paint(PaintingContext context, Offset offset) {
    if (child != null)
      context.pushTransform(needsCompositing, offset, _paintTransform, _paintChild);
  }

118
  @override
119 120 121 122 123 124
  void applyPaintTransform(RenderBox child, Matrix4 transform) {
    if (_paintTransform != null)
      transform.multiply(_paintTransform);
    super.applyPaintTransform(child, transform);
  }
}