// 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. // @dart = 2.8 import 'dart:async'; import 'package:flutter/foundation.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/services.dart'; import 'mouse_tracking.dart'; /// A mixin for [BaseMouseTracker] that sets the mouse pointer's cursors /// on device update. /// /// See also: /// /// * [MouseTracker], which uses this mixin. mixin MouseTrackerCursorMixin on BaseMouseTracker { /// Returns the active mouse cursor of a device. /// /// The return value is the last [MouseCursor] activated onto this /// device, even if the activation failed. /// /// Only valid when asserts are enabled. In release builds, always returns /// null. @visibleForTesting MouseCursor debugDeviceActiveCursor(int device) { MouseCursor result; assert(() { result = _lastSession[device]?.cursor; return true; }()); return result; } @protected @override void handleDeviceUpdate(MouseTrackerUpdateDetails details) { super.handleDeviceUpdate(details); _handleDeviceUpdateMouseCursor(details); } final Map<int, MouseCursorSession> _lastSession = <int, MouseCursorSession>{}; // Find the first non-deferred mouse cursor, which fallbacks to // [SystemMouseCursors.basic]. // // The `annotations` is the current annotations that the device is hovering in // visual order from front the back. // The return value is never null. MouseCursor _findFirstCursor(Iterable<MouseTrackerAnnotation> annotations) { return _DeferringMouseCursor.firstNonDeferred( annotations.map((MouseTrackerAnnotation annotation) => annotation.cursor), ) ?? SystemMouseCursors.basic; } // Handles device update and changes mouse cursors. void _handleDeviceUpdateMouseCursor(MouseTrackerUpdateDetails details) { final int device = details.device; if (details.triggeringEvent is PointerRemovedEvent) { _lastSession.remove(device); return; } final MouseCursorSession lastSession = _lastSession[device]; final MouseCursor nextCursor = _findFirstCursor(details.nextAnnotations.keys); if (lastSession?.cursor == nextCursor) return; final MouseCursorSession nextSession = nextCursor.createSession(device); _lastSession[device] = nextSession; lastSession?.dispose(); nextSession.activate(); } } /// Manages the duration that a pointing device should display a specific mouse /// cursor. /// /// While [MouseCursor] classes describe the kind of cursors, [MouseCursorSession] /// classes represents a continuous use of the cursor on a pointing device. The /// [MouseCursorSession] classes can be stateful. For example, a cursor that /// needs to load resources might want to set a temporary cursor first, then /// switch to the correct cursor after the load is completed. /// /// A [MouseCursorSession] has the following lifecycle: /// /// * When a pointing device should start displaying a cursor, [MouseTracker] /// creates a session by calling [MouseCursor.createSession] on the target /// cursor, and stores it in a table associated with the device. /// * [MouseTracker] then immediately calls the session's [activate], where the /// session should fetch resources and make system calls. /// * When the pointing device should start displaying a different cursor, /// [MouseTracker] calls [dispose] on this session. After [dispose], this session /// will no longer be used in the future. abstract class MouseCursorSession { /// Create a session. /// /// All arguments must be non-null. MouseCursorSession(this.cursor, this.device) : assert(cursor != null), assert(device != null); /// The cursor that created this session. final MouseCursor cursor; /// The device ID of the pointing device. final int device; /// Override this method to do the work of changing the cursor of the device. /// /// Called right after this session is created. /// /// This method has full control over the cursor until the [dispose] call, and /// can make system calls to change the pointer cursor as many times as /// necessary (usually through [SystemChannels.mouseCursor]). It can also /// collect resources, and store the result in this object. @protected Future<void> activate(); /// Called when device stops displaying the cursor. /// /// After this call, this session instance will no longer be used in the /// future. /// /// When implementing this method in subclasses, you should release resources /// and prevent [activate] from causing side effects after disposal. @protected void dispose(); } /// An interface for mouse cursor definitions. /// /// A mouse cursor is a graphical image on the screen that echoes the movement /// of a pointing device, such as a mouse or a stylus. A [MouseCursor] object /// defines a kind of mouse cursor, such as an arrow, a pointing hand, or an /// I-beam. /// /// During the painting phase, [MouseCursor] objects are assigned to regions on /// the screen via annotations. Later during a device update (e.g. when a mouse /// moves), [MouseTracker] finds the _active cursor_ of each mouse device, which /// is the front-most region associated with the position of each mouse cursor, /// or defaults to [SystemMouseCursors.basic] if no cursors are associated with /// the position. [MouseTracker] changes the cursor of the pointer if the new /// active cursor is different from the previous active cursor, whose effect is /// defined by the session created by [createSession]. /// /// ## Cursor classes /// /// A [SystemMouseCursor] is a cursor that is natively supported by the /// platform that the program is running on. All supported system mouse cursors /// are enumerated in [SystemMouseCursors]. /// /// ## Using cursors /// /// A [MouseCursor] object is used by being assigned to a [MouseRegion] or /// another widget that exposes the [MouseRegion] API, such as /// [InkWell.mouseCursor]. /// /// {@tool snippet --template=stateless_widget_material} /// This sample creates a rectangular region that is wrapped by a [MouseRegion] /// with a system mouse cursor. The mouse pointer becomes an I-beam when /// hovering over the region. /// /// ```dart /// Widget build(BuildContext context) { /// return Center( /// child: MouseRegion( /// cursor: SystemMouseCursors.text, /// child: Container( /// width: 200, /// height: 100, /// decoration: BoxDecoration( /// color: Colors.blue, /// border: Border.all(color: Colors.yellow), /// ), /// ), /// ), /// ); /// } /// ``` /// {@end-tool} /// /// Assigning regions with mouse cursors on platforms that do not support mouse /// cursors, or when there are no mice connected, will have no effect. /// /// ## Related classes /// /// [MouseCursorSession] represents the duration when a pointing device displays /// a cursor, and defines the states and behaviors of the cursor. Every mouse /// cursor class usually has a corresponding [MouseCursorSession] class. /// /// [MouseTrackerCursorMixin] is a mixin that adds the feature of changing /// cursors to [BaseMouseTracker], which tracks the relationship between mouse /// devices and annotations. [MouseTrackerCursorMixin] is usually used as a part /// of [MouseTracker]. @immutable abstract class MouseCursor with Diagnosticable { /// Abstract const constructor. This constructor enables subclasses to provide /// const constructors so that they can be used in const expressions. const MouseCursor(); /// Associate a pointing device to this cursor. /// /// A mouse cursor class usually has a corresponding [MouseCursorSession] /// class, and instantiates such class in this method. /// /// This method is called each time a pointing device starts displaying this /// cursor. A given cursor can be displayed by multiple devices at the same /// time, in which case this method will be called separately for each device. @protected @factory MouseCursorSession createSession(int device); /// A very short description of the mouse cursor. /// /// The [debugDescription] should be a few words that can describe this cursor /// to make debug information more readable. It is returned as the [toString] /// when the diagnostic level is at or above [DiagnosticLevel.info]. /// /// The [debugDescription] must not be null or empty string. String get debugDescription; @override String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) { final String debugDescription = this.debugDescription; if (minLevel.index >= DiagnosticLevel.info.index && debugDescription != null) return debugDescription; return super.toString(minLevel: minLevel); } /// A special class that indicates that the region with this cursor defers the /// choice of cursor to the next region behind it. /// /// When an event occurs, [MouseTracker] will update each pointer's cursor by /// finding the list of regions that contain the pointer's location, from front /// to back in hit-test order. The pointer's cursor will be the first cursor in /// the list that is not a [MouseCursor.defer]. static const MouseCursor defer = _DeferringMouseCursor._(); /// A special value that doesn't change cursor by itself, but make a region /// that blocks other regions behind it from changing the cursor. /// /// When a pointer enters a region with a cursor of [uncontrolled], the pointer /// retains its previous cursor and keeps so until it moves out of the region. /// Technically, this region absorb the mouse cursor hit test without changing /// the pointer's cursor. /// /// This is useful in a region that displays a platform view, which let the /// operating system handle pointer events and change cursors accordingly. To /// achieve this, the region's cursor must not be any Flutter cursor, since /// that might overwrite the system request upon pointer entering; the cursor /// must not be null either, since that allows the widgets behind the region to /// change cursors. static const MouseCursor uncontrolled = _NoopMouseCursor._(); } class _DeferringMouseCursor extends MouseCursor { const _DeferringMouseCursor._(); @override MouseCursorSession createSession(int device) { assert(false, '_DeferringMouseCursor can not create a session'); throw UnimplementedError(); } @override String get debugDescription => 'defer'; /// Returns the first cursor that is not a [MouseCursor.defer]. static MouseCursor firstNonDeferred(Iterable<MouseCursor> cursors) { for (final MouseCursor cursor in cursors) { assert(cursor != null); if (cursor != MouseCursor.defer) return cursor; } return null; } } class _NoopMouseCursorSession extends MouseCursorSession { _NoopMouseCursorSession(_NoopMouseCursor cursor, int device) : super(cursor, device); @override Future<void> activate() async { /* Nothing */ } @override void dispose() { /* Nothing */ } } /// A mouse cursor that doesn't change the cursor when activated. /// /// Although setting a region's cursor to [NoopMouseCursor] doesn't change the /// cursor, it blocks regions behind it from changing the cursor, in contrast to /// setting the cursor to null. More information about the usage of this class /// can be found at [MouseCursors.uncontrolled]. /// /// To use this class, use [MouseCursors.uncontrolled]. Directly /// instantiating this class is not allowed. class _NoopMouseCursor extends MouseCursor { // Application code shouldn't directly instantiate this class, since its only // instance is accessible at [SystemMouseCursors.releaseControl]. const _NoopMouseCursor._(); @override @protected _NoopMouseCursorSession createSession(int device) => _NoopMouseCursorSession(this, device); @override String get debugDescription => 'uncontrolled'; } class _SystemMouseCursorSession extends MouseCursorSession { _SystemMouseCursorSession(SystemMouseCursor cursor, int device) : super(cursor, device); @override SystemMouseCursor get cursor => super.cursor as SystemMouseCursor; @override Future<void> activate() { return SystemChannels.mouseCursor.invokeMethod<void>( 'activateSystemCursor', <String, dynamic>{ 'device': device, 'kind': cursor.kind, }, ); } @override void dispose() { /* Nothing */ } } /// A mouse cursor that is natively supported on the platform that the /// application is running on. /// /// System cursors can be used without external resources, and their appearances /// match the experience of native apps. Examples of system cursors are a /// pointing arrow, a pointing hand, a double arrow for resizing, or a text /// I-beam, etc. /// /// An instance of [SystemMouseCursor] refers to one cursor from each platform /// that represents the same concept, such as being text text, being clickable, /// or being a forbidden operation. Since the set of system cursors supported by /// each platform varies, multiple instances can correspond to the same system /// cursor. /// /// [SystemMouseCursors] enumerates the complete set of system cursors supported /// by Flutter, which are hard-coded in the engine. Therefore, manually /// instantiating this class is not supported. class SystemMouseCursor extends MouseCursor { // Application code shouldn't directly instantiate system mouse cursors, since // the supported system cursors are enumerated in [SystemMouseCursors]. const SystemMouseCursor._({ @required this.kind, }) : assert(kind != null); /// A string that identifies the kind of the cursor. /// /// The interpretation of [kind] is platform-dependent. final String kind; @override String get debugDescription => '$runtimeType($kind)'; @override @protected _SystemMouseCursorSession createSession(int device) => _SystemMouseCursorSession(this, device); @override bool operator ==(dynamic other) { if (other.runtimeType != runtimeType) return false; return other is SystemMouseCursor && other.kind == kind; } @override int get hashCode => kind.hashCode; @override void debugFillProperties(DiagnosticPropertiesBuilder properties) { super.debugFillProperties(properties); properties.add(DiagnosticsProperty<String>('kind', kind, level: DiagnosticLevel.debug)); } } /// A collection of system [MouseCursor]s. /// /// System cursors are standard mouse cursors that are provided by the current /// platform. They don't require external resources. /// /// [SystemMouseCursors] is a superset of the system cursors of every platform /// that Flutter supports, therefore some of these objects might map to the same /// result, or fallback to the [basic] arrow. This mapping is defined by the /// Flutter engine. /// /// The cursor names are chosen to reflect the cursors' use cases instead of /// their shapes, because different platforms might (although not commonly) use /// different shapes for the same use case. class SystemMouseCursors { // This class only contains static members, and should not be instantiated or // extended. factory SystemMouseCursors._() => null; /// Hide the cursor. /// /// Any cursor other than [none] or [uncontrolled] unhides the cursor. static const SystemMouseCursor none = SystemMouseCursor._(kind: 'none'); //// STATUS //// /// The platform-dependent basic cursor. /// /// Typically the shape of an arrow. /// /// Corresponds to: /// /// * Android: TYPE_DEFAULT, TYPE_ARROW /// * Web: default /// * macOS: arrowCursor static const SystemMouseCursor basic = SystemMouseCursor._(kind: 'basic'); /// A cursor that emphasizes an element being clickable, such as a hyperlink. /// /// Typically the shape of a pointing hand. /// /// Corresponds to: /// /// * Android: TYPE_HAND /// * Web: pointer /// * macOS: pointingHandCursor static const SystemMouseCursor click = SystemMouseCursor._(kind: 'click'); /// A cursor indicating an operation that will not be carried out. /// /// Typically the shape of a circle with a diagonal line. May fall back to /// [noDrop]. /// /// Corresponds to: /// /// * Android: TYPE_NO_DROP /// * Web: not-allowed /// * macOS: operationNotAllowedCursor /// /// See also: /// /// * [noDrop], which indicates somewhere that the current item may not be /// dropped. static const SystemMouseCursor forbidden = SystemMouseCursor._(kind: 'forbidden'); /// A cursor indicating the status that the program is busy and therefore /// can not be interacted with. /// /// Typically the shape of an hourglass or a watch. /// /// This cursor is not available as a system cursor on macOS. Although macOS /// displays a "spinning ball" cursor when busy, it's handled by the OS and not /// exposed for applications to choose. /// /// Corresponds to: /// /// * Android: TYPE_WAIT /// * Web: wait /// /// See also: /// /// * [progress], which is similar to [wait] but the program can still be /// interacted with. static const SystemMouseCursor wait = SystemMouseCursor._(kind: 'wait'); /// A cursor indicating the status that the program is busy but can still be /// interacted with. /// /// Typically the shape of an arrow with an hourglass or a watch at the corner. /// Does *not* fall back to [wait] if unavailable. /// /// Corresponds to: /// /// * Web: progress /// /// See also: /// /// * [wait], which is similar to [progress] but the program can not be /// interacted with. static const SystemMouseCursor progress = SystemMouseCursor._(kind: 'progress'); /// A cursor indicating somewhere the user can trigger a context menu. /// /// Typically the shape of an arrow with a small menu at the corner. /// /// Corresponds to: /// /// * Android: TYPE_CONTEXT_MENU /// * Web: context-menu /// * macOS: contextualMenuCursor static const SystemMouseCursor contextMenu = SystemMouseCursor._(kind: 'contextMenu'); /// A cursor indicating help information. /// /// Typically the shape of a question mark, or an arrow therewith. /// /// Corresponds to: /// /// * Android: TYPE_HELP /// * Web: help static const SystemMouseCursor help = SystemMouseCursor._(kind: 'help'); //// SELECTION //// /// A cursor indicating selectable text. /// /// Typically the shape of a capital I. /// /// Corresponds to: /// /// * Android: TYPE_TEXT /// * Web: text /// * macOS: IBeamCursor static const SystemMouseCursor text = SystemMouseCursor._(kind: 'text'); /// A cursor indicating selectable vertical text. /// /// Typically the shape of a capital I rotated to be horizontal. May fall back /// to [text]. /// /// Corresponds to: /// /// * Android: TYPE_VERTICAL_TEXT /// * Web: vertical-text /// * macOS: IBeamCursorForVerticalLayout static const SystemMouseCursor verticalText = SystemMouseCursor._(kind: 'verticalText'); /// A cursor indicating selectable table cells. /// /// Typically the shape of a hollow plus sign. /// /// Corresponds to: /// /// * Android: TYPE_CELL /// * Web: cell static const SystemMouseCursor cell = SystemMouseCursor._(kind: 'cell'); /// A cursor indicating precise selection, such as selecting a pixel in a /// bitmap. /// /// Typically the shape of a crosshair. /// /// Corresponds to: /// /// * Android: TYPE_CROSSHAIR /// * Web: crosshair /// * macOS: crosshairCursor static const SystemMouseCursor precise = SystemMouseCursor._(kind: 'precise'); //// DRAG-AND-DROP //// /// A cursor indicating moving something. /// /// Typically the shape of four-way arrow. May fall back to [allScroll]. /// /// Corresponds to: /// /// * Android: TYPE_ALL_SCROLL /// * Web: move static const SystemMouseCursor move = SystemMouseCursor._(kind: 'move'); /// A cursor indicating something that can be dragged. /// /// Typically the shape of an open hand. /// /// Corresponds to: /// /// * Android: TYPE_GRAB /// * Web: grab /// * macOS: openHandCursor static const SystemMouseCursor grab = SystemMouseCursor._(kind: 'grab'); /// A cursor indicating something that is being dragged. /// /// Typically the shape of a closed hand. /// /// Corresponds to: /// /// * Android: TYPE_GRABBING /// * Web: grabbing /// * macOS: closedHandCursor static const SystemMouseCursor grabbing = SystemMouseCursor._(kind: 'grabbing'); /// A cursor indicating somewhere that the current item may not be dropped. /// /// Typically the shape of a hand with a [forbidden] sign at the corner. May /// fall back to [forbidden]. /// /// Corresponds to: /// /// * Android: TYPE_NO_DROP /// * Web: no-drop /// * macOS: operationNotAllowedCursor /// /// See also: /// /// * [forbidden], which indicates an action that will not be carried out. static const SystemMouseCursor noDrop = SystemMouseCursor._(kind: 'noDrop'); /// A cursor indicating that the current operation will create an alias of, or /// a shortcut of the item. /// /// Typically the shape of an arrow with a shortcut icon at the corner. /// /// Corresponds to: /// /// * Android: TYPE_ALIAS /// * Web: alias /// * macOS: dragLinkCursor static const SystemMouseCursor alias = SystemMouseCursor._(kind: 'alias'); /// A cursor indicating that the current operation will copy the item. /// /// Typically the shape of an arrow with a boxed plus sign at the corner. /// /// Corresponds to: /// /// * Android: TYPE_COPY /// * Web: copy /// * macOS: dragCopyCursor static const SystemMouseCursor copy = SystemMouseCursor._(kind: 'copy'); /// A cursor indicating that the current operation will result in the /// disappearance of the item. /// /// Typically the shape of an arrow with a cloud of smoke at the corner. /// /// Corresponds to: /// /// * macOS: disappearingItemCursor static const SystemMouseCursor disappearing = SystemMouseCursor._(kind: 'disappearing'); //// RESIZING AND SCROLLING //// /// A cursor indicating scrolling in any direction. /// /// Typically the shape of a dot surrounded by 4 arrows. /// /// Corresponds to: /// /// * Android: TYPE_ALL_SCROLL /// * Web: all-scroll /// /// See also: /// /// * [move], which indicates moving in any direction. static const SystemMouseCursor allScroll = SystemMouseCursor._(kind: 'allScroll'); /// A cursor indicating resizing an object bidirectionally from its left or /// right edge. /// /// Typically the shape of a bidirectional arrow pointing left and right. /// /// Corresponds to: /// /// * Android: TYPE_HORIZONTAL_DOUBLE_ARROW /// * Web: ew-resize /// * macOS: resizeLeftRightCursor static const SystemMouseCursor resizeLeftRight = SystemMouseCursor._(kind: 'resizeLeftRight'); /// A cursor indicating resizing an object bidirectionally from its top or /// bottom edge. /// /// Typically the shape of a bidirectional arrow pointing up and down. /// /// Corresponds to: /// /// * Android: TYPE_VERTICAL_DOUBLE_ARROW /// * Web: ns-resize /// * macOS: resizeUpDownCursor static const SystemMouseCursor resizeUpDown = SystemMouseCursor._(kind: 'resizeUpDown'); /// A cursor indicating resizing an object bidirectionally from its top left or /// bottom right corner. /// /// Typically the shape of a bidirectional arrow pointing upper left and lower right. /// /// Corresponds to: /// /// * Android: TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW /// * Web: nwse-resize static const SystemMouseCursor resizeUpLeftDownRight = SystemMouseCursor._(kind: 'resizeUpLeftDownRight'); /// A cursor indicating resizing an object bidirectionally from its top right or /// bottom left corner. /// /// Typically the shape of a bidirectional arrow pointing upper right and lower left. /// /// Corresponds to: /// /// * Android: TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW /// * Web: nesw-resize static const SystemMouseCursor resizeUpRightDownLeft = SystemMouseCursor._(kind: 'resizeUpRightDownLeft'); /// A cursor indicating resizing an object from its top edge. /// /// Typically the shape of an arrow pointing up. May fallback to [resizeUpDown]. /// /// Corresponds to: /// /// * Android: TYPE_VERTICAL_DOUBLE_ARROW /// * Web: n-resize /// * macOS: resizeUpCursor static const SystemMouseCursor resizeUp = SystemMouseCursor._(kind: 'resizeUp'); /// A cursor indicating resizing an object from its bottom edge. /// /// Typically the shape of an arrow pointing down. May fallback to [resizeUpDown]. /// /// Corresponds to: /// /// * Android: TYPE_VERTICAL_DOUBLE_ARROW /// * Web: s-resize /// * macOS: resizeDownCursor static const SystemMouseCursor resizeDown = SystemMouseCursor._(kind: 'resizeDown'); /// A cursor indicating resizing an object from its left edge. /// /// Typically the shape of an arrow pointing left. May fallback to [resizeLeftRight]. /// /// Corresponds to: /// /// * Android: TYPE_HORIZONTAL_DOUBLE_ARROW /// * Web: w-resize /// * macOS: resizeLeftCursor static const SystemMouseCursor resizeLeft = SystemMouseCursor._(kind: 'resizeLeft'); /// A cursor indicating resizing an object from its right edge. /// /// Typically the shape of an arrow pointing right. May fallback to [resizeLeftRight]. /// /// Corresponds to: /// /// * Android: TYPE_HORIZONTAL_DOUBLE_ARROW /// * Web: e-resize /// * macOS: resizeRightCursor static const SystemMouseCursor resizeRight = SystemMouseCursor._(kind: 'resizeRight'); /// A cursor indicating resizing an object from its top-left corner. /// /// Typically the shape of an arrow pointing upper left. May fallback to [resizeUpLeftDownRight]. /// /// Corresponds to: /// /// * Android: TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW /// * Web: nw-resize static const SystemMouseCursor resizeUpLeft = SystemMouseCursor._(kind: 'resizeUpLeft'); /// A cursor indicating resizing an object from its top-right corner. /// /// Typically the shape of an arrow pointing upper right. May fallback to [resizeUpRightDownLeft]. /// /// Corresponds to: /// /// * Android: TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW /// * Web: ne-resize static const SystemMouseCursor resizeUpRight = SystemMouseCursor._(kind: 'resizeUpRight'); /// A cursor indicating resizing an object from its bottom-left corner. /// /// Typically the shape of an arrow pointing lower left. May fallback to [resizeUpRightDownLeft]. /// /// Corresponds to: /// /// * Android: TYPE_TOP_RIGHT_DIAGONAL_DOUBLE_ARROW /// * Web: sw-resize static const SystemMouseCursor resizeDownLeft = SystemMouseCursor._(kind: 'resizeDownLeft'); /// A cursor indicating resizing an object from its bottom-right corner. /// /// Typically the shape of an arrow pointing lower right. May fallback to [resizeUpLeftDownRight]. /// /// Corresponds to: /// /// * Android: TYPE_TOP_LEFT_DIAGONAL_DOUBLE_ARROW /// * Web: se-resize static const SystemMouseCursor resizeDownRight = SystemMouseCursor._(kind: 'resizeDownRight'); /// A cursor indicating resizing a column, or an item horizontally. /// /// Typically the shape of arrows pointing left and right with a vertical bar /// separating them. May fallback to [resizeLeftRight]. /// /// Corresponds to: /// /// * Android: TYPE_HORIZONTAL_DOUBLE_ARROW /// * Web: col-resize /// * macOS: resizeLeftRightCursor static const SystemMouseCursor resizeColumn = SystemMouseCursor._(kind: 'resizeColumn'); /// A cursor indicating resizing a row, or an item vertically. /// /// Typically the shape of arrows pointing up and down with a horizontal bar /// separating them. May fallback to [resizeUpDown]. /// /// Corresponds to: /// /// * Android: TYPE_VERTICAL_DOUBLE_ARROW /// * Web: row-resize /// * macOS: resizeUpDownCursor static const SystemMouseCursor resizeRow = SystemMouseCursor._(kind: 'resizeRow'); //// OTHER OPERATIONS //// /// A cursor indicating zooming in. /// /// Typically a magnifying glass with a plus sign. /// /// Corresponds to: /// /// * Android: TYPE_ZOOM_IN /// * Web: zoom-in static const SystemMouseCursor zoomIn = SystemMouseCursor._(kind: 'zoomIn'); /// A cursor indicating zooming out. /// /// Typically a magnifying glass with a minus sign. /// /// Corresponds to: /// /// * Android: TYPE_ZOOM_OUT /// * Web: zoom-out static const SystemMouseCursor zoomOut = SystemMouseCursor._(kind: 'zoomOut'); }