Line data Source code
1 : // Copyright 2014 The Flutter Authors. 2 : // Copyright 2021 Suragch. 3 : // All rights reserved. 4 : // Use of this source code is governed by a BSD-style license that can be 5 : // found in the LICENSE file. 6 : 7 : import 'dart:math' as math; 8 : 9 : import 'package:flutter/rendering.dart'; 10 : 11 : /// Positions the toolbar to the left of [anchorLeft] if it fits, or otherwise 12 : /// to the right of [anchorRight]. 13 : /// 14 : /// See also: 15 : /// 16 : /// * [MongolTextSelectionToolbar], which uses this to position itself. 17 : class MongolTextSelectionToolbarLayoutDelegate extends SingleChildLayoutDelegate { 18 : /// Creates an instance of MongolTextSelectionToolbarLayoutDelegate. 19 1 : MongolTextSelectionToolbarLayoutDelegate({ 20 : required this.anchorLeft, 21 : required this.anchorRight, 22 : this.fitsLeft, 23 : }); 24 : 25 : /// The focal point to the left of which the toolbar attempts to position 26 : /// itself. 27 : /// 28 : /// If there is not enough room to the left before reaching the left of the 29 : /// screen, then the toolbar will position itself to the right of 30 : /// [anchorRight]. 31 : /// 32 : /// Should be provided in local coordinates. 33 : final Offset anchorLeft; 34 : 35 : /// The focal point to the right of which the toolbar attempts to position 36 : /// itself, if it doesn't fit to the left of [anchorLeft]. 37 : /// 38 : /// Should be provided in local coordinates. 39 : final Offset anchorRight; 40 : 41 : /// Whether or not the child should be considered to fit to the left of 42 : /// anchorLeft. 43 : /// 44 : /// Typically used to force the child to be drawn at anchorLeft even when it 45 : /// doesn't fit, such as when the [MongolTextSelectionToolbar] draws an 46 : /// open overflow menu. 47 : /// 48 : /// If not provided, it will be calculated. 49 : final bool? fitsLeft; 50 : 51 : // Return the value that centers height as closely as possible to position 52 : // while fitting inside of min and max. 53 1 : static double _centerOn(double position, double height, double max) { 54 : // If it overflows above, put it as far above as possible. 55 3 : if (position - height / 2.0 < 0.0) { 56 : return 0.0; 57 : } 58 : 59 : // If it overflows below, put it as far below as possible. 60 3 : if (position + height / 2.0 > max) { 61 0 : return max - height; 62 : } 63 : 64 : // Otherwise it fits while perfectly centered. 65 2 : return position - height / 2.0; 66 : } 67 : 68 1 : @override 69 : BoxConstraints getConstraintsForChild(BoxConstraints constraints) { 70 1 : return constraints.loosen(); 71 : } 72 : 73 1 : @override 74 : Offset getPositionForChild(Size size, Size childSize) { 75 1 : final fitsLeft = this.fitsLeft ?? anchorLeft.dx >= childSize.width; 76 2 : final anchor = fitsLeft ? anchorLeft : anchorRight; 77 : 78 1 : return Offset( 79 : fitsLeft 80 4 : ? math.max(0.0, anchor.dx - childSize.width) 81 1 : : anchor.dx, 82 1 : _centerOn( 83 1 : anchor.dy, 84 1 : childSize.height, 85 1 : size.height, 86 : ), 87 : ); 88 : } 89 : 90 0 : @override 91 : bool shouldRelayout(MongolTextSelectionToolbarLayoutDelegate oldDelegate) { 92 0 : return anchorLeft != oldDelegate.anchorLeft 93 0 : || anchorRight != oldDelegate.anchorRight 94 0 : || fitsLeft != oldDelegate.fitsLeft; 95 : } 96 : }