Skip to content

Commit

Permalink
Add mouse cursor API to widgets (phase 1) (#57628)
Browse files Browse the repository at this point in the history
* Adds default cursor and/or mouseCursor property to a number of widgets.
* Adds `MaterialStateMouseCurrsor`.
  • Loading branch information
dkwingsmt committed May 28, 2020
1 parent be5b5c8 commit 60f1aa2
Show file tree
Hide file tree
Showing 44 changed files with 1,861 additions and 97 deletions.
16 changes: 15 additions & 1 deletion packages/flutter/lib/src/material/bottom_navigation_bar.dart
Expand Up @@ -6,6 +6,7 @@ import 'dart:collection' show Queue;
import 'dart:math' as math;

import 'package:flutter/widgets.dart';
import 'package:flutter/rendering.dart';
import 'package:vector_math/vector_math_64.dart' show Vector3;

import 'bottom_navigation_bar_theme.dart';
Expand Down Expand Up @@ -187,6 +188,7 @@ class BottomNavigationBar extends StatefulWidget {
this.unselectedLabelStyle,
this.showSelectedLabels = true,
this.showUnselectedLabels,
this.mouseCursor,
}) : assert(items != null),
assert(items.length >= 2),
assert(
Expand Down Expand Up @@ -314,6 +316,12 @@ class BottomNavigationBar extends StatefulWidget {
/// Whether the labels are shown for the unselected [BottomNavigationBarItem]s.
final bool showSelectedLabels;

/// The cursor for a mouse pointer when it enters or is hovering over the
/// tiles.
///
/// If this property is null, [SystemMouseCursors.click] will be used.
final MouseCursor mouseCursor;

@override
_BottomNavigationBarState createState() => _BottomNavigationBarState();
}
Expand All @@ -337,12 +345,14 @@ class _BottomNavigationTile extends StatelessWidget {
this.showSelectedLabels,
this.showUnselectedLabels,
this.indexLabel,
@required this.mouseCursor,
}) : assert(type != null),
assert(item != null),
assert(animation != null),
assert(selected != null),
assert(selectedLabelStyle != null),
assert(unselectedLabelStyle != null);
assert(unselectedLabelStyle != null),
assert(mouseCursor != null);

final BottomNavigationBarType type;
final BottomNavigationBarItem item;
Expand All @@ -359,6 +369,7 @@ class _BottomNavigationTile extends StatelessWidget {
final String indexLabel;
final bool showSelectedLabels;
final bool showUnselectedLabels;
final MouseCursor mouseCursor;

@override
Widget build(BuildContext context) {
Expand Down Expand Up @@ -452,6 +463,7 @@ class _BottomNavigationTile extends StatelessWidget {
children: <Widget>[
InkResponse(
onTap: onTap,
mouseCursor: mouseCursor,
child: Padding(
padding: EdgeInsets.only(top: topPadding, bottom: bottomPadding),
child: Column(
Expand Down Expand Up @@ -833,6 +845,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
);
break;
}
final MouseCursor effectiveMouseCursor = widget.mouseCursor ?? SystemMouseCursors.click;

final List<Widget> tiles = <Widget>[];
for (int i = 0; i < widget.items.length; i++) {
Expand All @@ -855,6 +868,7 @@ class _BottomNavigationBarState extends State<BottomNavigationBar> with TickerPr
showSelectedLabels: widget.showSelectedLabels ?? bottomTheme.showSelectedLabels,
showUnselectedLabels: widget.showUnselectedLabels ?? bottomTheme.showUnselectedLabels ?? _defaultShowUnselected,
indexLabel: localizations.tabLabel(tabIndex: i + 1, tabCount: widget.items.length),
mouseCursor: effectiveMouseCursor,
));
}
return tiles;
Expand Down
22 changes: 19 additions & 3 deletions packages/flutter/lib/src/material/button.dart
Expand Up @@ -103,9 +103,20 @@ class RawMaterialButton extends StatefulWidget {
/// [State.setState] is not allowed).
final ValueChanged<bool> onHighlightChanged;

/// {@macro flutter.material.inkwell.mousecursor}
/// {@template flutter.material.button.mouseCursor}
/// The cursor for a mouse pointer when it enters or is hovering over the
/// button.
///
/// If the property is null, [SystemMouseCursor.click] is used.
/// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
///
/// * [MaterialState.pressed].
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
///
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
/// {@endtemplate flutter.material.button.mouseCursor}
final MouseCursor mouseCursor;

/// Defines the default text style, with [Material.textStyle], for the
Expand Down Expand Up @@ -373,6 +384,10 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
final ShapeBorder effectiveShape = MaterialStateProperty.resolveAs<ShapeBorder>(widget.shape, _states);
final Offset densityAdjustment = widget.visualDensity.baseSizeAdjustment;
final BoxConstraints effectiveConstraints = widget.visualDensity.effectiveConstraints(widget.constraints);
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
_states,
);
final EdgeInsetsGeometry padding = widget.padding.add(
EdgeInsets.only(
left: densityAdjustment.dx,
Expand All @@ -382,6 +397,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
),
).clamp(EdgeInsets.zero, EdgeInsetsGeometry.infinity);


final Widget result = ConstrainedBox(
constraints: effectiveConstraints,
child: Material(
Expand All @@ -407,7 +423,7 @@ class _RawMaterialButtonState extends State<RawMaterialButton> {
onLongPress: widget.onLongPress,
enableFeedback: widget.enableFeedback,
customBorder: effectiveShape,
mouseCursor: widget.mouseCursor,
mouseCursor: effectiveMouseCursor,
child: IconTheme.merge(
data: IconThemeData(color: effectiveTextColor),
child: Container(
Expand Down
34 changes: 33 additions & 1 deletion packages/flutter/lib/src/material/checkbox.dart
Expand Up @@ -11,6 +11,7 @@ import 'package:flutter/widgets.dart';

import 'constants.dart';
import 'debug.dart';
import 'material_state.dart';
import 'theme.dart';
import 'theme_data.dart';
import 'toggleable.dart';
Expand Down Expand Up @@ -60,6 +61,7 @@ class Checkbox extends StatefulWidget {
@required this.value,
this.tristate = false,
@required this.onChanged,
this.mouseCursor,
this.activeColor,
this.checkColor,
this.focusColor,
Expand Down Expand Up @@ -107,6 +109,23 @@ class Checkbox extends StatefulWidget {
/// ```
final ValueChanged<bool> onChanged;

/// The cursor for a mouse pointer when it enters or is hovering over the
/// widget.
///
/// If [mouseCursor] is a [MaterialStateProperty<MouseCursor>],
/// [MaterialStateProperty.resolve] is used for the following [MaterialState]s:
///
/// * [MaterialState.selected].
/// * [MaterialState.hovered].
/// * [MaterialState.focused].
/// * [MaterialState.disabled].
///
/// When [value] is null and [tristate] is true, [MaterialState.selected] is
/// included as a state.
///
/// If this property is null, [MaterialStateMouseCursor.clickable] will be used.
final MouseCursor mouseCursor;

/// The color to use when this checkbox is checked.
///
/// Defaults to [ThemeData.toggleableActiveColor].
Expand Down Expand Up @@ -226,13 +245,24 @@ class _CheckboxState extends State<Checkbox> with TickerProviderStateMixin {
}
size += (widget.visualDensity ?? themeData.visualDensity).baseSizeAdjustment;
final BoxConstraints additionalConstraints = BoxConstraints.tight(size);
final MouseCursor effectiveMouseCursor = MaterialStateProperty.resolveAs<MouseCursor>(
widget.mouseCursor ?? MaterialStateMouseCursor.clickable,
<MaterialState>{
if (!enabled) MaterialState.disabled,
if (_hovering) MaterialState.hovered,
if (_focused) MaterialState.focused,
if (widget.tristate || widget.value) MaterialState.selected,
},
);

return FocusableActionDetector(
actions: _actionMap,
focusNode: widget.focusNode,
autofocus: widget.autofocus,
enabled: enabled,
onShowFocusHighlight: _handleFocusHighlightChanged,
onShowHoverHighlight: _handleHoverChanged,
mouseCursor: effectiveMouseCursor,
child: Builder(
builder: (BuildContext context) {
return _CheckboxRenderObjectWidget(
Expand Down Expand Up @@ -309,8 +339,10 @@ class _CheckboxRenderObjectWidget extends LeafRenderObjectWidget {
@override
void updateRenderObject(BuildContext context, _RenderCheckbox renderObject) {
renderObject
..value = value
// The `tristate` must be changed before `value` due to the assertion at
// the beginning of `set value`.
..tristate = tristate
..value = value
..activeColor = activeColor
..checkColor = checkColor
..inactiveColor = inactiveColor
Expand Down
7 changes: 7 additions & 0 deletions packages/flutter/lib/src/material/flat_button.dart
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

import 'button.dart';
Expand Down Expand Up @@ -104,6 +105,7 @@ class FlatButton extends MaterialButton {
@required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Expand All @@ -129,6 +131,7 @@ class FlatButton extends MaterialButton {
onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged,
mouseCursor: mouseCursor,
textTheme: textTheme,
textColor: textColor,
disabledTextColor: disabledTextColor,
Expand Down Expand Up @@ -161,6 +164,7 @@ class FlatButton extends MaterialButton {
@required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Expand Down Expand Up @@ -189,6 +193,7 @@ class FlatButton extends MaterialButton {
onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged,
mouseCursor: mouseCursor,
fillColor: buttonTheme.getFillColor(this),
textStyle: theme.textTheme.button.copyWith(color: buttonTheme.getTextColor(this)),
focusColor: buttonTheme.getFocusColor(this),
Expand Down Expand Up @@ -224,6 +229,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
@required VoidCallback onPressed,
VoidCallback onLongPress,
ValueChanged<bool> onHighlightChanged,
MouseCursor mouseCursor,
ButtonTextTheme textTheme,
Color textColor,
Color disabledTextColor,
Expand Down Expand Up @@ -251,6 +257,7 @@ class _FlatButtonWithIcon extends FlatButton with MaterialButtonWithIconMixin {
onPressed: onPressed,
onLongPress: onLongPress,
onHighlightChanged: onHighlightChanged,
mouseCursor: mouseCursor,
textTheme: textTheme,
textColor: textColor,
disabledTextColor: disabledTextColor,
Expand Down
12 changes: 5 additions & 7 deletions packages/flutter/lib/src/material/floating_action_button.dart
Expand Up @@ -142,9 +142,9 @@ class FloatingActionButton extends StatelessWidget {
this.highlightElevation,
this.disabledElevation,
@required this.onPressed,
this.mouseCursor,
this.mini = false,
this.shape,
this.mouseCursor,
this.clipBehavior = Clip.none,
this.focusNode,
this.autofocus = false,
Expand Down Expand Up @@ -183,8 +183,8 @@ class FloatingActionButton extends StatelessWidget {
this.highlightElevation,
this.disabledElevation,
@required this.onPressed,
this.mouseCursor = SystemMouseCursors.click,
this.shape,
this.mouseCursor,
this.isExtended = true,
this.materialTapTargetSize,
this.clipBehavior = Clip.none,
Expand Down Expand Up @@ -290,6 +290,9 @@ class FloatingActionButton extends StatelessWidget {
/// If this is set to null, the button will be disabled.
final VoidCallback onPressed;

/// {@macro flutter.material.button.mouseCursor}
final MouseCursor mouseCursor;

/// The z-coordinate at which to place this button relative to its parent.
///
/// This controls the size of the shadow below the floating action button.
Expand Down Expand Up @@ -378,11 +381,6 @@ class FloatingActionButton extends StatelessWidget {
/// shape as well.
final ShapeBorder shape;

/// {@macro flutter.material.inkwell.mousecursor}
///
/// If the property is null, [SystemMouseCursor.click] is used.
final MouseCursor mouseCursor;

/// {@macro flutter.widgets.Clip}
///
/// Defaults to [Clip.none], and must not be null.
Expand Down
8 changes: 8 additions & 0 deletions packages/flutter/lib/src/material/icon_button.dart
Expand Up @@ -5,6 +5,7 @@
import 'dart:math' as math;

import 'package:flutter/foundation.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/widgets.dart';

import 'constants.dart';
Expand Down Expand Up @@ -151,6 +152,7 @@ class IconButton extends StatelessWidget {
this.splashColor,
this.disabledColor,
@required this.onPressed,
this.mouseCursor = SystemMouseCursors.click,
this.focusNode,
this.autofocus = false,
this.tooltip,
Expand Down Expand Up @@ -274,6 +276,11 @@ class IconButton extends StatelessWidget {
/// If this is set to null, the button will be disabled.
final VoidCallback onPressed;

/// {@macro flutter.material.inkwell.mousecursor}
///
/// Defaults to [SystemMouseCursors.click].
final MouseCursor mouseCursor;

/// {@macro flutter.widgets.Focus.focusNode}
final FocusNode focusNode;

Expand Down Expand Up @@ -370,6 +377,7 @@ class IconButton extends StatelessWidget {
autofocus: autofocus,
canRequestFocus: onPressed != null,
onTap: onPressed,
mouseCursor: mouseCursor,
enableFeedback: enableFeedback,
child: result,
focusColor: focusColor ?? theme.focusColor,
Expand Down

0 comments on commit 60f1aa2

Please sign in to comment.