// Copyright 2014 The Flutter Authors. All rights reserved. // 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/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; import 'package:flutter/services.dart'; import 'package:flyinsonolite/infrastructure/scale.dart'; const Duration _kDropdownMenuDuration = Duration(milliseconds: 300); double get _kMenuItemHeight => kMinInteractiveDimension.s; double get _kDenseButtonHeight => 24.s; EdgeInsets get _kMenuItemPadding => EdgeInsets.symmetric(horizontal: 16.s); EdgeInsetsGeometry get _kAlignedButtonPadding => EdgeInsetsDirectional.only(start: 16.s, end: 4.s); const EdgeInsets _kUnalignedButtonPadding = EdgeInsets.zero; const EdgeInsets _kAlignedMenuMargin = EdgeInsets.zero; EdgeInsetsGeometry get _kUnalignedMenuMargin => EdgeInsetsDirectional.only(start: 16.s, end: 24.s); /// A builder to customize dropdown buttons. /// /// Used by [CustomDropdownButton.selectedItemBuilder]. typedef DropdownButtonBuilder = List Function(BuildContext context); class _DropdownMenuPainter extends CustomPainter { _DropdownMenuPainter({ this.color, this.elevation, this.selectedIndex, this.borderRadius, required this.resize, required this.getSelectedItemOffset, }) : _painter = BoxDecoration( // If you add an image here, you must provide a real // configuration in the paint() function and you must provide some sort // of onChanged callback here. color: color, borderRadius: borderRadius ?? const BorderRadius.all(Radius.circular(2.0)), boxShadow: kElevationToShadow[elevation], ).createBoxPainter(), super(repaint: resize); final Color? color; final int? elevation; final int? selectedIndex; final BorderRadius? borderRadius; final Animation resize; final ValueGetter getSelectedItemOffset; final BoxPainter _painter; @override void paint(Canvas canvas, Size size) { final double selectedItemOffset = getSelectedItemOffset(); final Tween top = Tween( begin: clampDouble(selectedItemOffset, 0.0, math.max(size.height - _kMenuItemHeight, 0.0)), end: 0.0, ); final Tween bottom = Tween( begin: clampDouble(top.begin! + _kMenuItemHeight, math.min(_kMenuItemHeight, size.height), size.height), end: size.height, ); final Rect rect = Rect.fromLTRB( 0.0, top.evaluate(resize), size.width, bottom.evaluate(resize)); _painter.paint(canvas, rect.topLeft, ImageConfiguration(size: rect.size)); } @override bool shouldRepaint(_DropdownMenuPainter oldPainter) { return oldPainter.color != color || oldPainter.elevation != elevation || oldPainter.selectedIndex != selectedIndex || oldPainter.borderRadius != borderRadius || oldPainter.resize != resize; } } // The widget that is the button wrapping the menu items. class _DropdownMenuItemButton extends StatefulWidget { const _DropdownMenuItemButton({ super.key, this.padding, required this.route, required this.buttonRect, required this.constraints, required this.itemIndex, required this.enableFeedback, }); final _DropdownRoute route; final EdgeInsets? padding; final Rect buttonRect; final BoxConstraints constraints; final int itemIndex; final bool enableFeedback; @override _DropdownMenuItemButtonState createState() => _DropdownMenuItemButtonState(); } class _DropdownMenuItemButtonState extends State<_DropdownMenuItemButton> { void _handleFocusChange(bool focused) { final bool inTraditionalMode; switch (FocusManager.instance.highlightMode) { case FocusHighlightMode.touch: inTraditionalMode = false; break; case FocusHighlightMode.traditional: inTraditionalMode = true; break; } if (focused && inTraditionalMode) { final _MenuLimits menuLimits = widget.route.getMenuLimits( widget.buttonRect, widget.constraints.maxHeight, widget.itemIndex, ); widget.route.scrollController!.animateTo( menuLimits.scrollOffset, curve: Curves.easeInOut, duration: const Duration(milliseconds: 100), ); } } void _handleOnTap() { final CustomDropdownMenuItem dropdownMenuItem = widget.route.items[widget.itemIndex].item!; dropdownMenuItem.onTap?.call(); Navigator.pop( context, _DropdownRouteResult(dropdownMenuItem.value), ); } static const Map _webShortcuts = { // On the web, up/down don't change focus, *except* in a