mouse_cursor.dart 30.6 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
// 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/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
26 27
  MouseCursor? debugDeviceActiveCursor(int device) {
    MouseCursor? result;
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
    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>{};

44 45
  // Find the first non-deferred mouse cursor, which fallbacks to
  // [SystemMouseCursors.basic].
46 47 48 49
  //
  // The `annotations` is the current annotations that the device is hovering in
  // visual order from front the back.
  // The return value is never null.
50
  MouseCursor _findFirstCursor(Iterable<MouseTrackerAnnotation> annotations) {
51 52 53
    return _DeferringMouseCursor.firstNonDeferred(
      annotations.map((MouseTrackerAnnotation annotation) => annotation.cursor),
    ) ?? SystemMouseCursors.basic;
54 55 56 57 58 59 60 61 62 63 64
  }

  // 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;
    }

65
    final MouseCursorSession? lastSession = _lastSession[device];
66
    final MouseCursor nextCursor = _findFirstCursor(details.nextAnnotations.keys);
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
    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
141
/// the screen via annotations. Later during a device update (e.g. when a mouse
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158
/// 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
159
/// [InkResponse.mouseCursor].
160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
///
/// {@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
213
  @factory
214 215 216 217
  MouseCursorSession createSession(int device);

  /// A very short description of the mouse cursor.
  ///
218
  /// The [debugDescription] should be a few words that can describe this cursor
219 220
  /// to make debug information more readable. It is returned as the [toString]
  /// when the diagnostic level is at or above [DiagnosticLevel.info].
221
  ///
222
  /// The [debugDescription] must not be null or empty string.
223 224 225 226 227 228
  String get debugDescription;

  @override
  String toString({DiagnosticLevel minLevel = DiagnosticLevel.info}) {
    final String debugDescription = this.debugDescription;
    if (minLevel.index >= DiagnosticLevel.info.index && debugDescription != null)
229
      return debugDescription;
230 231
    return super.toString(minLevel: minLevel);
  }
232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271

  /// 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].
272
  static MouseCursor? firstNonDeferred(Iterable<MouseCursor> cursors) {
273 274 275 276 277 278 279
    for (final MouseCursor cursor in cursors) {
      assert(cursor != null);
      if (cursor != MouseCursor.defer)
        return cursor;
    }
    return null;
  }
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
}

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
298
/// can be found at [MouseCursors.uncontrolled].
299
///
300
/// To use this class, use [MouseCursors.uncontrolled]. Directly
301 302 303 304 305 306 307 308 309 310 311
/// 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
312
  String get debugDescription => 'uncontrolled';
313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350
}

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.
///
351 352 353 354 355 356 357 358 359
/// Each cursor is noted with its corresponding native cursors on each platform:
///
///  * Android: API name in Java
///  * Web: CSS cursor
///  * Windows: Win32 API
///  * Linux: GDK, `gdk_cursor_new_from_name`
///  * macOS: API name in Objective C
///
/// If the platform that the application is running on is not listed for a cursor,
360
/// using this cursor falls back to [SystemMouseCursors.basic].
361
///
362 363 364 365 366 367 368
/// [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._({
369
    required this.kind,
370 371 372 373 374 375 376 377
  }) : assert(kind != null);

  /// A string that identifies the kind of the cursor.
  ///
  /// The interpretation of [kind] is platform-dependent.
  final String kind;

  @override
378
  String get debugDescription => '$runtimeType($kind)';
379 380 381 382 383 384

  @override
  @protected
  _SystemMouseCursorSession createSession(int device) => _SystemMouseCursorSession(this, device);

  @override
385
  bool operator ==(Object other) {
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408
    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
409
/// result, or fallback to the [basic] arrow. This mapping is defined by the
410 411
/// Flutter engine.
///
412 413
/// The cursors should be named based on the cursors' use cases instead of their
/// appearance, because different platforms might (although not commonly) use
414 415 416 417
/// different shapes for the same use case.
class SystemMouseCursors {
  // This class only contains static members, and should not be instantiated or
  // extended.
418
  factory SystemMouseCursors._() => throw Error();
419

420 421 422 423 424 425 426 427 428 429
  // The mapping in this class must be kept in sync with the following files in
  // the engine:
  //
  // * Android: shell/platform/android/io/flutter/plugin/mouse/MouseCursorPlugin.java
  // * Web: lib/web_ui/lib/src/engine/mouse_cursor.dart
  // * Windows: shell/platform/windows/win32_flutter_window.cc
  // * Linux: shell/platform/linux/fl_mouse_cursor_plugin.cc
  // * macOS: shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm


430 431
  /// Hide the cursor.
  ///
432 433
  /// Any cursor other than [none] or [MouseCursor.uncontrolled] unhides the
  /// cursor.
434 435
  static const SystemMouseCursor none = SystemMouseCursor._(kind: 'none');

436

437
  // STATUS
438

439 440 441
  /// The platform-dependent basic cursor.
  ///
  /// Typically the shape of an arrow.
442 443 444 445 446
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_DEFAULT, TYPE_ARROW
  ///  * Web: default
447 448
  ///  * Windows: IDC_ARROW
  ///  * Linux: default
449
  ///  * macOS: arrowCursor
450 451
  static const SystemMouseCursor basic = SystemMouseCursor._(kind: 'basic');

452
  /// A cursor that emphasizes an element being clickable, such as a hyperlink.
453 454
  ///
  /// Typically the shape of a pointing hand.
455 456 457 458 459
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_HAND
  ///  * Web: pointer
460 461
  ///  * Windows: IDC_HAND
  ///  * Linux: pointer
462
  ///  * macOS: pointingHandCursor
463 464
  static const SystemMouseCursor click = SystemMouseCursor._(kind: 'click');

465 466 467 468 469 470 471 472 473
  /// 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
474 475
  ///  * Windows: IDC_NO
  ///  * Linux: not-allowed
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495
  ///  * 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
496
  ///  * Windows: IDC_WAIT
497
  ///  * Web: wait
498
  ///  * Linux: wait
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514
  ///
  /// 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
515 516
  ///  * Windows: IDC_APPSTARTING
  ///  * Linux: progress
517 518 519 520 521 522 523 524 525 526 527 528 529 530 531
  ///
  /// 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
532
  ///  * Linux: context-menu
533 534 535 536 537 538 539 540 541 542
  ///  * 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
543
  ///  * Windows: IDC_HELP
544
  ///  * Web: help
545
  ///  * Linux: help
546 547 548
  static const SystemMouseCursor help = SystemMouseCursor._(kind: 'help');


549
  // SELECTION
550 551

  /// A cursor indicating selectable text.
552 553
  ///
  /// Typically the shape of a capital I.
554 555 556 557 558
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_TEXT
  ///  * Web: text
559 560
  ///  * Windows: IDC_IBEAM
  ///  * Linux: text
561
  ///  * macOS: IBeamCursor
562 563
  static const SystemMouseCursor text = SystemMouseCursor._(kind: 'text');

564
  /// A cursor indicating selectable vertical text.
565
  ///
566 567 568 569 570 571 572
  /// 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
573
  ///  * Linux: vertical-text
574 575 576 577 578 579 580 581 582 583 584
  ///  * 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
585
  ///  * Linux: cell
586
  static const SystemMouseCursor cell = SystemMouseCursor._(kind: 'cell');
587

588 589 590 591 592 593 594 595 596
  /// 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
597 598
  ///  * Windows: IDC_CROSS
  ///  * Linux: crosshair
599 600 601 602
  ///  * macOS: crosshairCursor
  static const SystemMouseCursor precise = SystemMouseCursor._(kind: 'precise');


603
  // DRAG-AND-DROP
604 605 606 607 608 609 610 611

  /// A cursor indicating moving something.
  ///
  /// Typically the shape of four-way arrow. May fall back to [allScroll].
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_ALL_SCROLL
612
  ///  * Windows: IDC_SIZEALL
613
  ///  * Web: move
614
  ///  * Linux: move
615 616 617
  static const SystemMouseCursor move = SystemMouseCursor._(kind: 'move');

  /// A cursor indicating something that can be dragged.
618 619
  ///
  /// Typically the shape of an open hand.
620 621 622 623 624
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_GRAB
  ///  * Web: grab
625
  ///  * Linux: grab
626
  ///  * macOS: openHandCursor
627 628
  static const SystemMouseCursor grab = SystemMouseCursor._(kind: 'grab');

629
  /// A cursor indicating something that is being dragged.
630 631
  ///
  /// Typically the shape of a closed hand.
632 633 634 635 636
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_GRABBING
  ///  * Web: grabbing
637
  ///  * Linux: grabbing
638
  ///  * macOS: closedHandCursor
639
  static const SystemMouseCursor grabbing = SystemMouseCursor._(kind: 'grabbing');
640

641 642 643 644 645 646 647 648 649
  /// 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
650 651
  ///  * Windows: IDC_NO
  ///  * Linux: no-drop
652 653 654 655 656 657 658 659 660
  ///  * 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.
661
  ///
662 663 664 665 666 667
  /// Typically the shape of an arrow with a shortcut icon at the corner.
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_ALIAS
  ///  * Web: alias
668
  ///  * Linux: alias
669 670
  ///  * macOS: dragLinkCursor
  static const SystemMouseCursor alias = SystemMouseCursor._(kind: 'alias');
671

672 673 674 675 676 677 678 679
  /// 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
680
  ///  * Linux: copy
681 682 683 684 685 686 687 688 689 690 691 692 693 694
  ///  * 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');


695
  // RESIZING AND SCROLLING
696 697 698 699 700 701 702 703

  /// A cursor indicating scrolling in any direction.
  ///
  /// Typically the shape of a dot surrounded by 4 arrows.
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_ALL_SCROLL
704
  ///  * Windows: IDC_SIZEALL
705
  ///  * Web: all-scroll
706
  ///  * Linux: all-scroll
707 708 709 710 711 712 713 714 715 716 717 718 719 720 721
  ///
  /// 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
722 723
  ///  * Windows: IDC_SIZEWE
  ///  * Linux: ew-resize
724 725 726 727 728 729 730 731 732 733 734 735
  ///  * 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
736 737
  ///  * Windows: IDC_SIZENS
  ///  * Linux: ns-resize
738 739 740 741 742 743 744 745 746 747 748 749
  ///  * 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
750 751
  ///  * Windows: IDC_SIZENWSE
  ///  * Linux: nwse-resize
752 753 754 755 756 757 758 759 760 761
  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
762
  ///  * Windows: IDC_SIZENESW
763
  ///  * Web: nesw-resize
764
  ///  * Linux: nesw-resize
765 766 767 768 769 770 771 772 773 774
  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
775 776
  ///  * Windows: IDC_SIZENS
  ///  * Linux: n-resize
777 778 779 780 781 782 783 784 785 786 787
  ///  * 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
788 789
  ///  * Windows: IDC_SIZENS
  ///  * Linux: s-resize
790 791 792 793 794 795 796 797 798 799 800
  ///  * 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
801 802
  ///  * Windows: IDC_SIZEWE
  ///  * Linux: w-resize
803 804 805 806 807 808 809 810 811 812 813
  ///  * 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
814 815
  ///  * Windows: IDC_SIZEWE
  ///  * Linux: e-resize
816 817 818 819 820 821 822 823 824 825 826
  ///  * 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
827 828
  ///  * Windows: IDC_SIZENWSE
  ///  * Linux: nw-resize
829 830 831 832 833 834 835 836 837 838
  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
839 840
  ///  * Windows: IDC_SIZENESW
  ///  * Linux: ne-resize
841 842 843 844 845 846 847 848 849 850
  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
851 852
  ///  * Windows: IDC_SIZENESW
  ///  * Linux: sw-resize
853 854 855 856 857 858 859 860 861 862
  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
863 864
  ///  * Windows: IDC_SIZENWSE
  ///  * Linux: se-resize
865 866 867 868 869 870 871 872 873 874 875
  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
876 877
  ///  * Windows: IDC_SIZEWE
  ///  * Linux: col-resize
878 879 880 881 882 883 884 885 886 887 888 889
  ///  * 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
890 891
  ///  * Windows: IDC_SIZENS
  ///  * Linux: row-resize
892 893 894 895
  ///  * macOS: resizeUpDownCursor
  static const SystemMouseCursor resizeRow = SystemMouseCursor._(kind: 'resizeRow');


896
  // OTHER OPERATIONS
897 898 899 900 901 902 903 904 905

  /// A cursor indicating zooming in.
  ///
  /// Typically a magnifying glass with a plus sign.
  ///
  /// Corresponds to:
  ///
  ///  * Android: TYPE_ZOOM_IN
  ///  * Web: zoom-in
906
  ///  * Linux: zoom-in
907 908 909 910 911 912 913
  static const SystemMouseCursor zoomIn = SystemMouseCursor._(kind: 'zoomIn');

  /// A cursor indicating zooming out.
  ///
  /// Typically a magnifying glass with a minus sign.
  ///
  /// Corresponds to:
914
  ///
915 916
  ///  * Android: TYPE_ZOOM_OUT
  ///  * Web: zoom-out
917
  ///  * Linux: zoom-out
918
  static const SystemMouseCursor zoomOut = SystemMouseCursor._(kind: 'zoomOut');
919
}