123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600 |
- // 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 'dart:ui' show lerpDouble;
- import 'package:flutter/foundation.dart';
- import 'package:flutter/material.dart';
- import 'package:flyinsonolite/controls/custom/custombuttonstylebutton.dart';
- import 'package:flyinsonolite/infrastructure/scale.dart';
- /// A Material Design "Text Button".
- ///
- /// Use text buttons on toolbars, in dialogs, or inline with other
- /// content but offset from that content with padding so that the
- /// button's presence is obvious. Text buttons do not have visible
- /// borders and must therefore rely on their position relative to
- /// other content for context. In dialogs and cards, they should be
- /// grouped together in one of the bottom corners. Avoid using text
- /// buttons where they would blend in with other content, for example
- /// in the middle of lists.
- ///
- /// A text button is a label [child] displayed on a (zero elevation)
- /// [Material] widget. The label's [Text] and [Icon] widgets are
- /// displayed in the [style]'s [ButtonStyle.foregroundColor]. The
- /// button reacts to touches by filling with the [style]'s
- /// [ButtonStyle.backgroundColor].
- ///
- /// The text button's default style is defined by [defaultStyleOf].
- /// The style of this text button can be overridden with its [style]
- /// parameter. The style of all text buttons in a subtree can be
- /// overridden with the [TextButtonTheme] and the style of all of the
- /// text buttons in an app can be overridden with the [Theme]'s
- /// [ThemeData.textButtonTheme] property.
- ///
- /// The static [styleFrom] method is a convenient way to create a
- /// text button [ButtonStyle] from simple values.
- ///
- /// If the [onPressed] and [onLongPress] callbacks are null, then this
- /// button will be disabled, it will not react to touch.
- ///
- /// {@tool dartpad}
- /// This sample shows how to render a disabled TextButton, an enabled TextButton
- /// and lastly a TextButton with gradient background.
- ///
- /// ** See code in examples/api/lib/material/text_button/text_button.0.dart **
- /// {@end-tool}
- ///
- /// {@tool dartpad}
- /// This sample demonstrates using the [statesController] parameter to create a button
- /// that adds support for [MaterialState.selected].
- ///
- /// ** See code in examples/api/lib/material/text_button/text_button.1.dart **
- /// {@end-tool}
- ///
- /// See also:
- ///
- /// * [CustomElevatedButton], a filled button whose material elevates when pressed.
- /// * [FilledButton], a filled button that doesn't elevate when pressed.
- /// * [FilledButton.tonal], a filled button variant that uses a secondary fill color.
- /// * [OutlinedButton], a button with an outlined border and no fill color.
- /// * <https://material.io/design/components/buttons.html>
- /// * <https://m3.material.io/components/buttons>
- class CustomTextButton extends CustomButtonStyleButton {
- /// Create a TextButton.
- ///
- /// The [autofocus] and [clipBehavior] arguments must not be null.
- const CustomTextButton({
- super.key,
- required super.onPressed,
- super.onLongPress,
- super.onHover,
- super.onFocusChange,
- super.style,
- super.focusNode,
- super.autofocus = false,
- super.clipBehavior = Clip.none,
- super.statesController,
- required Widget super.child,
- });
- /// Create a text button from a pair of widgets that serve as the button's
- /// [icon] and [label].
- ///
- /// The icon and label are arranged in a row and padded by 8 logical pixels
- /// at the ends, with an 8 pixel gap in between.
- ///
- /// The [icon] and [label] arguments must not be null.
- factory CustomTextButton.icon({
- Key? key,
- required VoidCallback? onPressed,
- VoidCallback? onLongPress,
- ValueChanged<bool>? onHover,
- ValueChanged<bool>? onFocusChange,
- ButtonStyle? style,
- FocusNode? focusNode,
- bool? autofocus,
- Clip? clipBehavior,
- MaterialStatesController? statesController,
- required Widget icon,
- required Widget label,
- }) = _TextButtonWithIcon;
- /// A static convenience method that constructs a text button
- /// [ButtonStyle] given simple values.
- ///
- /// The [foregroundColor] and [disabledForegroundColor] colors are used
- /// to create a [MaterialStateProperty] [ButtonStyle.foregroundColor], and
- /// a derived [ButtonStyle.overlayColor].
- ///
- /// The [backgroundColor] and [disabledBackgroundColor] colors are
- /// used to create a [MaterialStateProperty] [ButtonStyle.backgroundColor].
- ///
- /// Similarly, the [enabledMouseCursor] and [disabledMouseCursor]
- /// parameters are used to construct [ButtonStyle.mouseCursor].
- ///
- /// All of the other parameters are either used directly or used to
- /// create a [MaterialStateProperty] with a single value for all
- /// states.
- ///
- /// All parameters default to null. By default this method returns
- /// a [ButtonStyle] that doesn't override anything.
- ///
- /// For example, to override the default text and icon colors for a
- /// [CustomTextButton], as well as its overlay color, with all of the
- /// standard opacity adjustments for the pressed, focused, and
- /// hovered states, one could write:
- ///
- /// ```dart
- /// TextButton(
- /// style: TextButton.styleFrom(foregroundColor: Colors.green),
- /// child: const Text('Give Kate a mix tape'),
- /// onPressed: () {
- /// // ...
- /// },
- /// ),
- /// ```
- static ButtonStyle styleFrom({
- Color? foregroundColor,
- Color? backgroundColor,
- Color? disabledForegroundColor,
- Color? disabledBackgroundColor,
- Color? shadowColor,
- Color? surfaceTintColor,
- double? elevation,
- TextStyle? textStyle,
- EdgeInsetsGeometry? padding,
- Size? minimumSize,
- Size? fixedSize,
- Size? maximumSize,
- BorderSide? side,
- OutlinedBorder? shape,
- MouseCursor? enabledMouseCursor,
- MouseCursor? disabledMouseCursor,
- VisualDensity? visualDensity,
- MaterialTapTargetSize? tapTargetSize,
- Duration? animationDuration,
- bool? enableFeedback,
- AlignmentGeometry? alignment,
- InteractiveInkFeatureFactory? splashFactory,
- @Deprecated('Use foregroundColor instead. '
- 'This feature was deprecated after v3.1.0.')
- Color? primary,
- @Deprecated('Use disabledForegroundColor instead. '
- 'This feature was deprecated after v3.1.0.')
- Color? onSurface,
- }) {
- final Color? foreground = foregroundColor ?? primary;
- final Color? disabledForeground =
- disabledForegroundColor ?? onSurface?.withOpacity(0.38);
- final MaterialStateProperty<Color?>? foregroundColorProp =
- (foreground == null && disabledForeground == null)
- ? null
- : _TextButtonDefaultColor(foreground, disabledForeground);
- final MaterialStateProperty<Color?>? backgroundColorProp =
- (backgroundColor == null && disabledBackgroundColor == null)
- ? null
- : disabledBackgroundColor == null
- ? CustomButtonStyleButton.allOrNull<Color?>(backgroundColor)
- : _TextButtonDefaultColor(
- backgroundColor, disabledBackgroundColor);
- final MaterialStateProperty<Color?>? overlayColor =
- (foreground == null) ? null : _TextButtonDefaultOverlay(foreground);
- final MaterialStateProperty<MouseCursor>? mouseCursor =
- (enabledMouseCursor == null && disabledMouseCursor == null)
- ? null
- : _TextButtonDefaultMouseCursor(
- enabledMouseCursor!, disabledMouseCursor!);
- return ButtonStyle(
- textStyle: CustomButtonStyleButton.allOrNull<TextStyle>(textStyle),
- foregroundColor: foregroundColorProp,
- backgroundColor: backgroundColorProp,
- overlayColor: overlayColor,
- shadowColor: CustomButtonStyleButton.allOrNull<Color>(shadowColor),
- surfaceTintColor:
- CustomButtonStyleButton.allOrNull<Color>(surfaceTintColor),
- elevation: CustomButtonStyleButton.allOrNull<double>(elevation),
- padding: CustomButtonStyleButton.allOrNull<EdgeInsetsGeometry>(padding),
- minimumSize: CustomButtonStyleButton.allOrNull<Size>(minimumSize),
- fixedSize: CustomButtonStyleButton.allOrNull<Size>(fixedSize),
- maximumSize: CustomButtonStyleButton.allOrNull<Size>(maximumSize),
- side: CustomButtonStyleButton.allOrNull<BorderSide>(side),
- shape: CustomButtonStyleButton.allOrNull<OutlinedBorder>(shape),
- mouseCursor: mouseCursor,
- visualDensity: visualDensity,
- tapTargetSize: tapTargetSize,
- animationDuration: animationDuration,
- enableFeedback: enableFeedback,
- alignment: alignment,
- splashFactory: splashFactory,
- );
- }
- /// Defines the button's default appearance.
- ///
- /// {@template flutter.material.text_button.default_style_of}
- /// The button [child]'s [Text] and [Icon] widgets are rendered with
- /// the [ButtonStyle]'s foreground color. The button's [InkWell] adds
- /// the style's overlay color when the button is focused, hovered
- /// or pressed. The button's background color becomes its [Material]
- /// color and is transparent by default.
- ///
- /// All of the [ButtonStyle]'s defaults appear below.
- ///
- /// In this list "Theme.foo" is shorthand for
- /// `Theme.of(context).foo`. Color scheme values like
- /// "onSurface(0.38)" are shorthand for
- /// `onSurface.withOpacity(0.38)`. [MaterialStateProperty] valued
- /// properties that are not followed by a sublist have the same
- /// value for all states, otherwise the values are as specified for
- /// each state and "others" means all other states.
- ///
- /// The `textScaleFactor` is the value of
- /// `MediaQuery.of(context).textScaleFactor` and the names of the
- /// EdgeInsets constructors and `EdgeInsetsGeometry.lerp` have been
- /// abbreviated for readability.
- ///
- /// The color of the [ButtonStyle.textStyle] is not used, the
- /// [ButtonStyle.foregroundColor] color is used instead.
- /// {@endtemplate}
- ///
- /// ## Material 2 defaults
- ///
- /// * `textStyle` - Theme.textTheme.button
- /// * `backgroundColor` - transparent
- /// * `foregroundColor`
- /// * disabled - Theme.colorScheme.onSurface(0.38)
- /// * others - Theme.colorScheme.primary
- /// * `overlayColor`
- /// * hovered - Theme.colorScheme.primary(0.04)
- /// * focused or pressed - Theme.colorScheme.primary(0.12)
- /// * `shadowColor` - Theme.shadowColor
- /// * `elevation` - 0
- /// * `padding`
- /// * `textScaleFactor <= 1` - all(8)
- /// * `1 < textScaleFactor <= 2` - lerp(all(8), horizontal(8))
- /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4))
- /// * `3 < textScaleFactor` - horizontal(4)
- /// * `minimumSize` - Size(64, 36)
- /// * `fixedSize` - null
- /// * `maximumSize` - Size.infinite
- /// * `side` - null
- /// * `shape` - RoundedRectangleBorder(borderRadius: BorderRadius.circular(4))
- /// * `mouseCursor`
- /// * disabled - SystemMouseCursors.basic
- /// * others - SystemMouseCursors.click
- /// * `visualDensity` - theme.visualDensity
- /// * `tapTargetSize` - theme.materialTapTargetSize
- /// * `animationDuration` - kThemeChangeDuration
- /// * `enableFeedback` - true
- /// * `alignment` - Alignment.center
- /// * `splashFactory` - InkRipple.splashFactory
- ///
- /// The default padding values for the [TextButton.icon] factory are slightly different:
- ///
- /// * `padding`
- /// * `textScaleFactor <= 1` - all(8)
- /// * `1 < textScaleFactor <= 2 `- lerp(all(8), horizontal(4))
- /// * `2 < textScaleFactor` - horizontal(4)
- ///
- /// The default value for `side`, which defines the appearance of the button's
- /// outline, is null. That means that the outline is defined by the button
- /// shape's [OutlinedBorder.side]. Typically the default value of an
- /// [OutlinedBorder]'s side is [BorderSide.none], so an outline is not drawn.
- ///
- /// ## Material 3 defaults
- ///
- /// If [ThemeData.useMaterial3] is set to true the following defaults will
- /// be used:
- ///
- /// {@template flutter.material.text_button.material3_defaults}
- /// * `textStyle` - Theme.textTheme.labelLarge
- /// * `backgroundColor` - transparent
- /// * `foregroundColor`
- /// * disabled - Theme.colorScheme.onSurface(0.38)
- /// * others - Theme.colorScheme.primary
- /// * `overlayColor`
- /// * hovered - Theme.colorScheme.primary(0.08)
- /// * focused or pressed - Theme.colorScheme.primary(0.12)
- /// * others - null
- /// * `shadowColor` - null
- /// * `surfaceTintColor` - null
- /// * `elevation` - 0
- /// * `padding`
- /// * `textScaleFactor <= 1` - all(8)
- /// * `1 < textScaleFactor <= 2` - lerp(all(8), horizontal(8))
- /// * `2 < textScaleFactor <= 3` - lerp(horizontal(8), horizontal(4))
- /// * `3 < textScaleFactor` - horizontal(4)
- /// * `minimumSize` - Size(64, 40)
- /// * `fixedSize` - null
- /// * `maximumSize` - Size.infinite
- /// * `side` - null
- /// * `shape` - StadiumBorder()
- /// * `mouseCursor`
- /// * disabled - SystemMouseCursors.basic
- /// * others - SystemMouseCursors.click
- /// * `visualDensity` - theme.visualDensity
- /// * `tapTargetSize` - theme.materialTapTargetSize
- /// * `animationDuration` - kThemeChangeDuration
- /// * `enableFeedback` - true
- /// * `alignment` - Alignment.center
- /// * `splashFactory` - Theme.splashFactory
- /// {@endtemplate}
- @override
- ButtonStyle defaultStyleOf(BuildContext context) {
- final ThemeData theme = Theme.of(context);
- final ColorScheme colorScheme = theme.colorScheme;
- return Theme.of(context).useMaterial3
- ? _TextButtonDefaultsM3(context)
- : styleFrom(
- foregroundColor: colorScheme.primary,
- disabledForegroundColor: colorScheme.onSurface.withOpacity(0.38),
- backgroundColor: Colors.transparent,
- disabledBackgroundColor: Colors.transparent,
- shadowColor: theme.shadowColor,
- elevation: 0,
- textStyle: theme.textTheme.labelLarge,
- padding: _scaledPadding(context),
- minimumSize: Size(64.s, 36.s),
- maximumSize: Size.infinite,
- shape: RoundedRectangleBorder(
- borderRadius: BorderRadius.all(Radius.circular(4.s))),
- enabledMouseCursor: SystemMouseCursors.click,
- disabledMouseCursor: SystemMouseCursors.basic,
- visualDensity: theme.visualDensity,
- tapTargetSize: theme.materialTapTargetSize,
- animationDuration: kThemeChangeDuration,
- enableFeedback: true,
- alignment: Alignment.center,
- splashFactory: InkRipple.splashFactory,
- );
- }
- /// Returns the [TextButtonThemeData.style] of the closest
- /// [TextButtonTheme] ancestor.
- @override
- ButtonStyle? themeStyleOf(BuildContext context) {
- return TextButtonTheme.of(context).style;
- }
- }
- EdgeInsetsGeometry _scaledPadding(BuildContext context) {
- return CustomButtonStyleButton.scaledPadding(
- EdgeInsets.all(8.s),
- EdgeInsets.symmetric(horizontal: 8.s),
- EdgeInsets.symmetric(horizontal: 4.s),
- MediaQuery.maybeOf(context)?.textScaleFactor ?? 1,
- );
- }
- @immutable
- class _TextButtonDefaultColor extends MaterialStateProperty<Color?> {
- _TextButtonDefaultColor(this.color, this.disabled);
- final Color? color;
- final Color? disabled;
- @override
- Color? resolve(Set<MaterialState> states) {
- if (states.contains(MaterialState.disabled)) {
- return disabled;
- }
- return color;
- }
- @override
- String toString() {
- return '{disabled: $disabled, otherwise: $color}';
- }
- }
- @immutable
- class _TextButtonDefaultOverlay extends MaterialStateProperty<Color?> {
- _TextButtonDefaultOverlay(this.primary);
- final Color primary;
- @override
- Color? resolve(Set<MaterialState> states) {
- if (states.contains(MaterialState.hovered)) {
- return primary.withOpacity(0.04);
- }
- if (states.contains(MaterialState.focused) ||
- states.contains(MaterialState.pressed)) {
- return primary.withOpacity(0.12);
- }
- return null;
- }
- @override
- String toString() {
- return '{hovered: ${primary.withOpacity(0.04)}, focused,pressed: ${primary.withOpacity(0.12)}, otherwise: null}';
- }
- }
- @immutable
- class _TextButtonDefaultMouseCursor extends MaterialStateProperty<MouseCursor>
- with Diagnosticable {
- _TextButtonDefaultMouseCursor(this.enabledCursor, this.disabledCursor);
- final MouseCursor enabledCursor;
- final MouseCursor disabledCursor;
- @override
- MouseCursor resolve(Set<MaterialState> states) {
- if (states.contains(MaterialState.disabled)) {
- return disabledCursor;
- }
- return enabledCursor;
- }
- }
- class _TextButtonWithIcon extends CustomTextButton {
- _TextButtonWithIcon({
- super.key,
- required super.onPressed,
- super.onLongPress,
- super.onHover,
- super.onFocusChange,
- super.style,
- super.focusNode,
- bool? autofocus,
- Clip? clipBehavior,
- super.statesController,
- required Widget icon,
- required Widget label,
- }) : assert(icon != null),
- assert(label != null),
- super(
- autofocus: autofocus ?? false,
- clipBehavior: clipBehavior ?? Clip.none,
- child: _TextButtonWithIconChild(icon: icon, label: label),
- );
- @override
- ButtonStyle defaultStyleOf(BuildContext context) {
- final EdgeInsetsGeometry scaledPadding =
- CustomButtonStyleButton.scaledPadding(
- EdgeInsets.all(8.s),
- EdgeInsets.symmetric(horizontal: 4.s),
- EdgeInsets.symmetric(horizontal: 4.s),
- MediaQuery.maybeOf(context)?.textScaleFactor ?? 1,
- );
- return super.defaultStyleOf(context).copyWith(
- padding: MaterialStatePropertyAll<EdgeInsetsGeometry>(scaledPadding),
- );
- }
- }
- class _TextButtonWithIconChild extends StatelessWidget {
- const _TextButtonWithIconChild({
- required this.label,
- required this.icon,
- });
- final Widget label;
- final Widget icon;
- @override
- Widget build(BuildContext context) {
- final double scale = MediaQuery.maybeOf(context)?.textScaleFactor ?? 1;
- final double gap =
- scale <= 1 ? 8 : lerpDouble(8, 4, math.min(scale - 1, 1))!;
- return Row(
- mainAxisSize: MainAxisSize.min,
- children: <Widget>[icon, SizedBox(width: gap), Flexible(child: label)],
- );
- }
- }
- // BEGIN GENERATED TOKEN PROPERTIES - TextButton
- // Do not edit by hand. The code between the "BEGIN GENERATED" and
- // "END GENERATED" comments are generated from data in the Material
- // Design token database by the script:
- // dev/tools/gen_defaults/bin/gen_defaults.dart.
- // Token database version: v0_132
- class _TextButtonDefaultsM3 extends ButtonStyle {
- _TextButtonDefaultsM3(this.context)
- : super(
- animationDuration: kThemeChangeDuration,
- enableFeedback: true,
- alignment: Alignment.center,
- );
- final BuildContext context;
- late final ColorScheme _colors = Theme.of(context).colorScheme;
- @override
- MaterialStateProperty<TextStyle?> get textStyle =>
- MaterialStatePropertyAll<TextStyle?>(
- Theme.of(context).textTheme.labelLarge);
- @override
- MaterialStateProperty<Color?>? get backgroundColor =>
- const MaterialStatePropertyAll<Color>(Colors.transparent);
- @override
- MaterialStateProperty<Color?>? get foregroundColor =>
- MaterialStateProperty.resolveWith((Set<MaterialState> states) {
- if (states.contains(MaterialState.disabled)) {
- return _colors.onSurface.withOpacity(0.38);
- }
- return _colors.primary;
- });
- @override
- MaterialStateProperty<Color?>? get overlayColor =>
- MaterialStateProperty.resolveWith((Set<MaterialState> states) {
- if (states.contains(MaterialState.hovered)) {
- return _colors.primary.withOpacity(0.08);
- }
- if (states.contains(MaterialState.focused)) {
- return _colors.primary.withOpacity(0.12);
- }
- if (states.contains(MaterialState.pressed)) {
- return _colors.primary.withOpacity(0.12);
- }
- return null;
- });
- @override
- MaterialStateProperty<Color>? get shadowColor =>
- const MaterialStatePropertyAll<Color>(Colors.transparent);
- @override
- MaterialStateProperty<Color>? get surfaceTintColor =>
- const MaterialStatePropertyAll<Color>(Colors.transparent);
- @override
- MaterialStateProperty<double>? get elevation =>
- const MaterialStatePropertyAll<double>(0.0);
- @override
- MaterialStateProperty<EdgeInsetsGeometry>? get padding =>
- MaterialStatePropertyAll<EdgeInsetsGeometry>(_scaledPadding(context));
- @override
- MaterialStateProperty<Size>? get minimumSize =>
- MaterialStatePropertyAll<Size>(Size(64.s, 40.s));
- // No default fixedSize
- @override
- MaterialStateProperty<Size>? get maximumSize =>
- const MaterialStatePropertyAll<Size>(Size.infinite);
- // No default side
- @override
- MaterialStateProperty<OutlinedBorder>? get shape =>
- const MaterialStatePropertyAll<OutlinedBorder>(StadiumBorder());
- @override
- MaterialStateProperty<MouseCursor?>? get mouseCursor =>
- MaterialStateProperty.resolveWith((Set<MaterialState> states) {
- if (states.contains(MaterialState.disabled)) {
- return SystemMouseCursors.basic;
- }
- return SystemMouseCursors.click;
- });
- @override
- VisualDensity? get visualDensity => Theme.of(context).visualDensity;
- @override
- MaterialTapTargetSize? get tapTargetSize =>
- Theme.of(context).materialTapTargetSize;
- @override
- InteractiveInkFeatureFactory? get splashFactory =>
- Theme.of(context).splashFactory;
- }
- // END GENERATED TOKEN PROPERTIES - TextButton
|