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

import 'dart:math' as math;

import 'package:flutter/gestures.dart';
8
import 'package:flutter/painting.dart';
9 10 11 12 13
import 'package:vector_math/vector_math_64.dart';

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

14
const double _kQuarterTurnsInRadians = math.pi / 2.0;
15 16 17 18 19 20 21

/// 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> {
22 23 24
  /// Creates a rotated render box.
  ///
  /// The [quarterTurns] argument must not be null.
25
  RenderRotatedBox({
26 27
    required int quarterTurns,
    RenderBox? child,
28 29
  }) : assert(quarterTurns != null),
       _quarterTurns = quarterTurns {
30 31 32 33 34 35
    this.child = child;
  }

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

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

46
  @override
47
  double computeMinIntrinsicWidth(double height) {
48 49
    if (child == null)
      return 0.0;
50
    return _isVertical ? child!.getMinIntrinsicHeight(height) : child!.getMinIntrinsicWidth(height);
51 52
  }

53
  @override
54
  double computeMaxIntrinsicWidth(double height) {
55 56
    if (child == null)
      return 0.0;
57
    return _isVertical ? child!.getMaxIntrinsicHeight(height) : child!.getMaxIntrinsicWidth(height);
58 59
  }

60
  @override
61
  double computeMinIntrinsicHeight(double width) {
62 63
    if (child == null)
      return 0.0;
64
    return _isVertical ? child!.getMinIntrinsicWidth(width) : child!.getMinIntrinsicHeight(width);
65 66
  }

67
  @override
68
  double computeMaxIntrinsicHeight(double width) {
69 70
    if (child == null)
      return 0.0;
71
    return _isVertical ? child!.getMaxIntrinsicWidth(width) : child!.getMaxIntrinsicHeight(width);
72 73
  }

74
  Matrix4? _paintTransform;
75

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

91
  @override
92
  bool hitTestChildren(BoxHitTestResult result, { required Offset position }) {
93
    assert(_paintTransform != null || debugNeedsLayout || child == null);
94 95
    if (child == null || _paintTransform == null)
      return false;
96 97 98
    return result.addWithPaintTransform(
      transform: _paintTransform,
      position: position,
99 100
      hitTest: (BoxHitTestResult result, Offset? position) {
        return child!.hitTest(result, position: position!);
101 102
      },
    );
103 104 105
  }

  void _paintChild(PaintingContext context, Offset offset) {
106
    context.paintChild(child!, offset);
107 108
  }

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

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