diff --git a/lib/src/generic_dropdown.dart b/lib/src/generic_dropdown.dart index 9b62817..3978794 100644 --- a/lib/src/generic_dropdown.dart +++ b/lib/src/generic_dropdown.dart @@ -2,6 +2,11 @@ import 'package:flutter/material.dart'; import './generic_dropdown_config_provider.dart'; +typedef ContentBuilder = Widget Function( + BuildContext context, VoidCallback repaint, VoidCallback close); + +typedef ToggleBuilder = Widget Function(BuildContext context, bool isOpen); + /// Determines the anchor of the dropdown. The /// anchor is relative to the toggle and is used /// to place the content when showing the dropdown. @@ -10,14 +15,34 @@ enum DropdownAnchor { /// toggle is used as anchor. topLeft, + /// The center top of the + /// toggle is used as anchor. + topCenter, + /// The top right corner of the /// toggle is used as anchor. topRight, + /// The left center of the + /// toggle is used as anchor. + leftCenter, + + /// The very center of the + /// toggle is used as anchor. + center, + + /// The right center of the + /// toggle is used as anchor. + rightCenter, + /// The bottom left corner of the /// toggle is used as anchor. bottomLeft, + /// The bottom center of the + /// toggle is used as anchor. + bottomCenter, + /// The bottom right corner of the /// toggle is used as anchor. bottomRight, @@ -35,18 +60,14 @@ enum DropdownDirection { /// left edge to the [DropdownAnchor] and opens to the top right. upRight, - /// The content will be positioned with the top - /// right edge to the [DropdownAnchor] and opens to the bottom left. - downLeft, - /// The content will be positioned with the top /// left edge to the [DropdownAnchor] and opens to the bottom right. downRight, -} -typedef ContentBuilder = Widget Function( - BuildContext context, VoidCallback repaint, VoidCallback close); -typedef ToggleBuilder = Widget Function(BuildContext context, bool isOpen); + /// The content will be positioned with the top + /// right edge to the [DropdownAnchor] and opens to the bottom left. + downLeft, +} /// A generic dropdown widget that enables arbitrary content /// with an arbitrary toggle widget. The content can be placed @@ -115,6 +136,25 @@ class _GenericDropdownState extends State { var _isOpen = false; OverlayEntry? _overlayEntry; + @override + Widget build(BuildContext context) => Row( + mainAxisSize: MainAxisSize.min, + children: [ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + Align( + alignment: Alignment.topLeft, + child: GestureDetector( + onTap: () => _isOpen ? _close() : _open(context), + child: widget.toggleBuilder(context, _isOpen), + ), + ), + ], + ), + ], + ); + @override void dispose() { _overlayEntry?.remove(); @@ -171,95 +211,228 @@ class _GenericDropdownState extends State { double? top, left, bottom, right; // Anchor TOP LEFT - if (widget.anchor == DropdownAnchor.topLeft && - widget.direction == DropdownDirection.upLeft) { - bottom = screenSize.height - togglePosition.dy + widget.offset.dy; - right = screenSize.width - togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.topLeft && - widget.direction == DropdownDirection.upRight) { - bottom = screenSize.height - togglePosition.dy + widget.offset.dy; - left = togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.topLeft && - widget.direction == DropdownDirection.downLeft) { - top = togglePosition.dy + widget.offset.dy; - right = screenSize.width - togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.topLeft && - widget.direction == DropdownDirection.downRight) { - top = togglePosition.dy + widget.offset.dy; - left = togglePosition.dx + widget.offset.dx; + if (widget.anchor == DropdownAnchor.topLeft) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx; + } + } + + // Anchor TOP CENTER + if (widget.anchor == DropdownAnchor.topCenter) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } } // Anchor TOP RIGHT - if (widget.anchor == DropdownAnchor.topRight && - widget.direction == DropdownDirection.upLeft) { - bottom = screenSize.height - togglePosition.dy + widget.offset.dy; - right = - screenSize.width - togglePosition.dx + widget.offset.dx - size.width; - } else if (widget.anchor == DropdownAnchor.topRight && - widget.direction == DropdownDirection.upRight) { - bottom = screenSize.height - togglePosition.dy + widget.offset.dy; - left = togglePosition.dx + widget.offset.dx + size.width; - } else if (widget.anchor == DropdownAnchor.topRight && - widget.direction == DropdownDirection.downLeft) { - top = togglePosition.dy + widget.offset.dy; - right = - screenSize.width - togglePosition.dx + widget.offset.dx - size.width; - } else if (widget.anchor == DropdownAnchor.topRight && - widget.direction == DropdownDirection.downRight) { - top = togglePosition.dy + widget.offset.dy; - left = togglePosition.dx + widget.offset.dx + size.width; + if (widget.anchor == DropdownAnchor.topRight) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx + size.width; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy; + left = togglePosition.dx + widget.offset.dx + size.width; + } + } + + // Anchor LEFT CENTER + if (widget.anchor == DropdownAnchor.leftCenter) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + left = togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + left = togglePosition.dx + widget.offset.dx; + } + } + + // Anchor CENTER + if (widget.anchor == DropdownAnchor.center) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } + } + + // Anchor RIGHT CENTER + if (widget.anchor == DropdownAnchor.rightCenter) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height / 2; + left = togglePosition.dx + widget.offset.dx + size.width; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height / 2; + left = togglePosition.dx + widget.offset.dx + size.width; + } } // Anchor BOTTOM LEFT - if (widget.anchor == DropdownAnchor.bottomLeft && - widget.direction == DropdownDirection.upLeft) { - bottom = screenSize.height - - togglePosition.dy + - widget.offset.dy - - size.height; - right = screenSize.width - togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.bottomLeft && - widget.direction == DropdownDirection.upRight) { - bottom = screenSize.height - - togglePosition.dy + - widget.offset.dy - - size.height; - left = togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.bottomLeft && - widget.direction == DropdownDirection.downLeft) { - top = togglePosition.dy + widget.offset.dy + size.height; - right = screenSize.width - togglePosition.dx + widget.offset.dx; - } else if (widget.anchor == DropdownAnchor.bottomLeft && - widget.direction == DropdownDirection.downRight) { - top = togglePosition.dy + widget.offset.dy + size.height; - left = togglePosition.dx + widget.offset.dx; + if (widget.anchor == DropdownAnchor.bottomLeft) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + left = togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height; + right = screenSize.width - togglePosition.dx + widget.offset.dx; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height; + left = togglePosition.dx + widget.offset.dx; + } + } + + // Anchor BOTTOM CENTER + if (widget.anchor == DropdownAnchor.bottomCenter) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width / 2; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height; + left = togglePosition.dx + widget.offset.dx + size.width / 2; + } } // Anchor BOTTOM RIGHT - if (widget.anchor == DropdownAnchor.bottomRight && - widget.direction == DropdownDirection.upLeft) { - bottom = screenSize.height - - togglePosition.dy + - widget.offset.dy - - size.height; - right = - screenSize.width - togglePosition.dx + widget.offset.dx - size.width; - } else if (widget.anchor == DropdownAnchor.bottomRight && - widget.direction == DropdownDirection.upRight) { - bottom = screenSize.height - - togglePosition.dy + - widget.offset.dy - - size.height; - left = togglePosition.dx + widget.offset.dx + size.width; - } else if (widget.anchor == DropdownAnchor.bottomRight && - widget.direction == DropdownDirection.downLeft) { - top = togglePosition.dy + widget.offset.dy + size.height; - right = - screenSize.width - togglePosition.dx + widget.offset.dx - size.width; - } else if (widget.anchor == DropdownAnchor.bottomRight && - widget.direction == DropdownDirection.downRight) { - top = togglePosition.dy + widget.offset.dy + size.height; - left = togglePosition.dx + widget.offset.dx + size.width; + if (widget.anchor == DropdownAnchor.bottomRight) { + if (widget.direction == DropdownDirection.upLeft) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.upRight) { + bottom = screenSize.height - + togglePosition.dy + + widget.offset.dy - + size.height; + left = togglePosition.dx + widget.offset.dx + size.width; + } else if (widget.direction == DropdownDirection.downLeft) { + top = togglePosition.dy + widget.offset.dy + size.height; + right = screenSize.width - + togglePosition.dx + + widget.offset.dx - + size.width; + } else if (widget.direction == DropdownDirection.downRight) { + top = togglePosition.dy + widget.offset.dy + size.height; + left = togglePosition.dx + widget.offset.dx + size.width; + } } _overlayEntry = OverlayEntry( @@ -304,23 +477,4 @@ class _GenericDropdownState extends State { Size _screenSize(BuildContext context) => _ancestor(context)?.size ?? MediaQuery.of(context).size; - - @override - Widget build(BuildContext context) => Row( - mainAxisSize: MainAxisSize.min, - children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - Align( - alignment: Alignment.topLeft, - child: GestureDetector( - onTap: () => _isOpen ? _close() : _open(context), - child: widget.toggleBuilder(context, _isOpen), - ), - ), - ], - ), - ], - ); } diff --git a/storybook/lib/main.dart b/storybook/lib/main.dart index a4100b7..81570fa 100644 --- a/storybook/lib/main.dart +++ b/storybook/lib/main.dart @@ -2,8 +2,6 @@ import 'package:flutter/material.dart'; import 'package:generic_dropdown_widget/generic_dropdown_widget.dart'; import 'package:storybook_flutter/storybook_flutter.dart'; -final rootKey = GlobalKey(); - void main() { runApp(Storybook( plugins: initializePlugins( @@ -23,13 +21,12 @@ void main() { rootScreenKey: rootKey, child: Center(key: UniqueKey(), child: child))))), // initialStory: 'Generic Dropdown', - stories: [ - _dropdown(), - _openDropdown(), - ], + stories: [_dropdown(), _openDropdown(), _dropdownAlignmentOverview()], )); } +final rootKey = GlobalKey(); + Story _dropdown() => Story( name: 'Generic Dropdown', description: 'A generic dropdown with arbirary toggle and content.', @@ -109,6 +106,95 @@ Story _dropdown() => Story( )); }); +Story _dropdownAlignmentOverview() => Story( + name: 'Generic Dropdown (alignement overview)', + description: 'An overview over all possible anchors and directions.', + builder: (context) { + return SingleChildScrollView( + scrollDirection: Axis.vertical, + child: SingleChildScrollView( + scrollDirection: Axis.horizontal, + child: Column( + children: DropdownAnchor.values + .map((anchor) => Row( + children: DropdownDirection.values + .map((direction) => SizedBox( + width: 250, + height: 200, + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: + Colors.black.withOpacity(.25))), + child: Column( + children: [ + Text( + 'anchor: ${anchor.name}', + style: Theme.of(context) + .textTheme + .bodySmall, + ), + Text( + 'direction: ${direction.name}', + style: Theme.of(context) + .textTheme + .bodySmall, + ), + Expanded( + child: Center( + child: GenericDropdown( + openOnRender: true, + contentBuilder: + (context, repaint, close) => + Container( + height: 40, + width: 80, + color: + Colors.green.withOpacity(.5), + child: const Center( + child: Text('Content')), + ), + toggleBuilder: (context, _) => + Container( + height: 60, + width: 70, + color: + Colors.amber.withOpacity(.25), + child: const Center( + child: Text('Toggle')), + ), + anchor: anchor, + offset: Offset( + context.knobs + .sliderInt( + label: 'X Offset', + initial: 0, + min: -100, + max: 100) + .toDouble(), + context.knobs + .sliderInt( + label: 'Y Offset', + initial: 0, + min: -100, + max: 100) + .toDouble(), + ), + direction: direction, + closeOnOutsideTap: false, + ), + ), + ), + ], + ), + ), + )) + .toList(growable: false))) + .toList(growable: false)), + ), + ); + }); + Story _openDropdown() => Story( name: 'Generic Dropdown (open)', description: 'A generic dropdown that opens on render.', diff --git a/test/generic_dropdown_widget_test.dart b/test/generic_dropdown_widget_test.dart index ec1f9a6..b873bb9 100644 --- a/test/generic_dropdown_widget_test.dart +++ b/test/generic_dropdown_widget_test.dart @@ -2,46 +2,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:generic_dropdown_widget/src/generic_dropdown.dart'; -Widget _wrapper(Widget child) => - MaterialApp(home: Scaffold(body: SafeArea(child: Center(child: child)))); - -class _PlacementCase { - final DropdownAnchor anchor; - final DropdownDirection direction; - final List> translation; - - const _PlacementCase( - this.anchor, - this.direction, { - required this.translation, - }); - - Offset bottomLeft(Rect toggle, Rect content) => _anchor(toggle).translate( - content.width * translation[2][0], content.height * translation[2][1]); - - Offset bottomRight(Rect toggle, Rect content) => _anchor(toggle).translate( - content.width * translation[3][0], content.height * translation[3][1]); - - Offset topLeft(Rect toggle, Rect content) => _anchor(toggle).translate( - content.width * translation[0][0], content.height * translation[0][1]); - - Offset topRight(Rect toggle, Rect content) => _anchor(toggle).translate( - content.width * translation[1][0], content.height * translation[1][1]); - - Offset _anchor(Rect toggle) { - switch (anchor) { - case DropdownAnchor.topLeft: - return toggle.topLeft; - case DropdownAnchor.topRight: - return toggle.topRight; - case DropdownAnchor.bottomLeft: - return toggle.bottomLeft; - case DropdownAnchor.bottomRight: - return toggle.bottomRight; - } - } -} - void main() { group('GenericDropdown -', () { testWidgets('should render the toggle.', (tester) async { @@ -319,6 +279,46 @@ void main() { [1, 1], ], ), + const _PlacementCase( + DropdownAnchor.topCenter, + DropdownDirection.upLeft, + translation: [ + [-1, -1], + [0, -1], + [-1, 0], + [0, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.topCenter, + DropdownDirection.upRight, + translation: [ + [0, -1], + [1, -1], + [0, 0], + [1, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.topCenter, + DropdownDirection.downLeft, + translation: [ + [-1, 0], + [0, 0], + [-1, 1], + [0, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.topCenter, + DropdownDirection.downRight, + translation: [ + [0, 0], + [1, 0], + [0, 1], + [1, 1], + ], + ), const _PlacementCase( DropdownAnchor.topRight, DropdownDirection.upLeft, @@ -359,6 +359,126 @@ void main() { [1, 1], ], ), + const _PlacementCase( + DropdownAnchor.leftCenter, + DropdownDirection.upLeft, + translation: [ + [-1, -1], + [0, -1], + [-1, 0], + [0, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.leftCenter, + DropdownDirection.upRight, + translation: [ + [0, -1], + [1, -1], + [0, 0], + [1, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.leftCenter, + DropdownDirection.downLeft, + translation: [ + [-1, 0], + [0, 0], + [-1, 1], + [0, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.leftCenter, + DropdownDirection.downRight, + translation: [ + [0, 0], + [1, 0], + [0, 1], + [1, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.center, + DropdownDirection.upLeft, + translation: [ + [-1, -1], + [0, -1], + [-1, 0], + [0, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.center, + DropdownDirection.upRight, + translation: [ + [0, -1], + [1, -1], + [0, 0], + [1, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.center, + DropdownDirection.downLeft, + translation: [ + [-1, 0], + [0, 0], + [-1, 1], + [0, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.center, + DropdownDirection.downRight, + translation: [ + [0, 0], + [1, 0], + [0, 1], + [1, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.rightCenter, + DropdownDirection.upLeft, + translation: [ + [-1, -1], + [0, -1], + [-1, 0], + [0, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.rightCenter, + DropdownDirection.upRight, + translation: [ + [0, -1], + [1, -1], + [0, 0], + [1, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.rightCenter, + DropdownDirection.downLeft, + translation: [ + [-1, 0], + [0, 0], + [-1, 1], + [0, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.rightCenter, + DropdownDirection.downRight, + translation: [ + [0, 0], + [1, 0], + [0, 1], + [1, 1], + ], + ), const _PlacementCase( DropdownAnchor.bottomLeft, DropdownDirection.upLeft, @@ -399,6 +519,46 @@ void main() { [1, 1], ], ), + const _PlacementCase( + DropdownAnchor.bottomCenter, + DropdownDirection.upLeft, + translation: [ + [-1, -1], + [0, -1], + [-1, 0], + [0, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.bottomCenter, + DropdownDirection.upRight, + translation: [ + [0, -1], + [1, -1], + [0, 0], + [1, 0], + ], + ), + const _PlacementCase( + DropdownAnchor.bottomCenter, + DropdownDirection.downLeft, + translation: [ + [-1, 0], + [0, 0], + [-1, 1], + [0, 1], + ], + ), + const _PlacementCase( + DropdownAnchor.bottomCenter, + DropdownDirection.downRight, + translation: [ + [0, 0], + [1, 0], + [0, 1], + [1, 1], + ], + ), const _PlacementCase( DropdownAnchor.bottomRight, DropdownDirection.upLeft, @@ -486,3 +646,53 @@ void main() { }); }); } + +Widget _wrapper(Widget child) => + MaterialApp(home: Scaffold(body: SafeArea(child: Center(child: child)))); + +class _PlacementCase { + final DropdownAnchor anchor; + final DropdownDirection direction; + final List> translation; + + const _PlacementCase( + this.anchor, + this.direction, { + required this.translation, + }); + + Offset bottomLeft(Rect toggle, Rect content) => _anchor(toggle).translate( + content.width * translation[2][0], content.height * translation[2][1]); + + Offset bottomRight(Rect toggle, Rect content) => _anchor(toggle).translate( + content.width * translation[3][0], content.height * translation[3][1]); + + Offset topLeft(Rect toggle, Rect content) => _anchor(toggle).translate( + content.width * translation[0][0], content.height * translation[0][1]); + + Offset topRight(Rect toggle, Rect content) => _anchor(toggle).translate( + content.width * translation[1][0], content.height * translation[1][1]); + + Offset _anchor(Rect toggle) { + switch (anchor) { + case DropdownAnchor.topLeft: + return toggle.topLeft; + case DropdownAnchor.topCenter: + return toggle.topCenter; + case DropdownAnchor.topRight: + return toggle.topRight; + case DropdownAnchor.leftCenter: + return toggle.centerLeft; + case DropdownAnchor.center: + return toggle.center; + case DropdownAnchor.rightCenter: + return toggle.centerRight; + case DropdownAnchor.bottomLeft: + return toggle.bottomLeft; + case DropdownAnchor.bottomCenter: + return toggle.bottomCenter; + case DropdownAnchor.bottomRight: + return toggle.bottomRight; + } + } +}