// 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 'package:flutter/widgets.dart'; import 'colors.dart'; import 'constants.dart'; import 'text_button.dart'; import 'theme.dart'; enum _TextSelectionToolbarItemPosition { /// The first item among multiple in the menu. first, /// One of several items, not the first or last. middle, /// The last item among multiple in the menu. last, /// The only item in the menu. only, } /// A button styled like a Material native Android text selection menu button. class TextSelectionToolbarTextButton extends StatelessWidget { /// Creates an instance of TextSelectionToolbarTextButton. const TextSelectionToolbarTextButton({ super.key, required this.child, required this.padding, this.onPressed, }); // These values were eyeballed to match the native text selection menu on a // Pixel 2 running Android 10. static const double _kMiddlePadding = 9.5; static const double _kEndPadding = 14.5; /// {@template flutter.material.TextSelectionToolbarTextButton.child} /// The child of this button. /// /// Usually a [Text]. /// {@endtemplate} final Widget child; /// {@template flutter.material.TextSelectionToolbarTextButton.onPressed} /// Called when this button is pressed. /// {@endtemplate} final VoidCallback? onPressed; /// The padding between the button's edge and its child. /// /// In a standard Material [TextSelectionToolbar], the padding depends on the /// button's position within the toolbar. /// /// See also: /// /// * [getPadding], which calculates the standard padding based on the /// button's position. /// * [ButtonStyle.padding], which is where this padding is applied. final EdgeInsets padding; /// Returns the standard padding for a button at index out of a total number /// of buttons. /// /// Standard Material [TextSelectionToolbar]s have buttons with different /// padding depending on their position in the toolbar. static EdgeInsets getPadding(int index, int total) { assert(total > 0 && index >= 0 && index < total); final _TextSelectionToolbarItemPosition position = _getPosition(index, total); return EdgeInsets.only( left: _getLeftPadding(position), right: _getRightPadding(position), ); } static double _getLeftPadding(_TextSelectionToolbarItemPosition position) { if (position == _TextSelectionToolbarItemPosition.first || position == _TextSelectionToolbarItemPosition.only) { return _kEndPadding; } return _kMiddlePadding; } static double _getRightPadding(_TextSelectionToolbarItemPosition position) { if (position == _TextSelectionToolbarItemPosition.last || position == _TextSelectionToolbarItemPosition.only) { return _kEndPadding; } return _kMiddlePadding; } static _TextSelectionToolbarItemPosition _getPosition(int index, int total) { if (index == 0) { return total == 1 ? _TextSelectionToolbarItemPosition.only : _TextSelectionToolbarItemPosition.first; } if (index == total - 1) { return _TextSelectionToolbarItemPosition.last; } return _TextSelectionToolbarItemPosition.middle; } @override Widget build(BuildContext context) { // TODO(hansmuller): Should be colorScheme.onSurface final ThemeData theme = Theme.of(context); final bool isDark = theme.colorScheme.brightness == Brightness.dark; final Color foregroundColor = isDark ? Colors.white : Colors.black87; return TextButton( style: TextButton.styleFrom( foregroundColor: foregroundColor, shape: const RoundedRectangleBorder(), minimumSize: const Size(kMinInteractiveDimension, kMinInteractiveDimension), padding: padding, ), onPressed: onPressed, child: child, ); } }