// 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/cupertino.dart'; import 'package:flutter/rendering.dart'; import 'adaptive_text_selection_toolbar.dart'; import 'debug.dart'; import 'desktop_text_selection.dart'; import 'magnifier.dart'; import 'text_selection.dart'; import 'theme.dart'; /// A widget that introduces an area for user selections with adaptive selection /// controls. /// /// This widget creates a [SelectableRegion] with platform-adaptive selection /// controls. /// /// Flutter widgets are not selectable by default. To enable selection for /// a specific screen, consider wrapping the body of the [Route] with a /// [SelectionArea]. /// /// The [SelectionArea] widget must have a [Localizations] ancestor that /// contains a [MaterialLocalizations] delegate; using the [MaterialApp] widget /// ensures that such an ancestor is present. /// /// {@tool dartpad} /// This example shows how to make a screen selectable. /// /// ** See code in examples/api/lib/material/selection_area/selection_area.0.dart ** /// {@end-tool} /// /// See also: /// * [SelectableRegion], which provides an overview of the selection system. class SelectionArea extends StatefulWidget { /// Creates a [SelectionArea]. /// /// If [selectionControls] is null, a platform specific one is used. const SelectionArea({ super.key, this.focusNode, this.selectionControls, this.contextMenuBuilder = _defaultContextMenuBuilder, this.magnifierConfiguration, this.onSelectionChanged, required this.child, }); /// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.intro} /// /// {@macro flutter.widgets.magnifier.intro} /// /// {@macro flutter.widgets.magnifier.TextMagnifierConfiguration.details} /// /// By default, builds a [CupertinoTextMagnifier] on iOS and [TextMagnifier] /// on Android, and builds nothing on all other platforms. If it is desired to /// suppress the magnifier, consider passing [TextMagnifierConfiguration.disabled]. final TextMagnifierConfiguration? magnifierConfiguration; /// {@macro flutter.widgets.Focus.focusNode} final FocusNode? focusNode; /// The delegate to build the selection handles and toolbar. /// /// If it is null, the platform specific selection control is used. final TextSelectionControls? selectionControls; /// {@macro flutter.widgets.EditableText.contextMenuBuilder} /// /// If not provided, will build a default menu based on the ambient /// [ThemeData.platform]. /// /// {@tool dartpad} /// This example shows how to build a custom context menu for any selected /// content in a SelectionArea. /// /// ** See code in examples/api/lib/material/context_menu/selectable_region_toolbar_builder.0.dart ** /// {@end-tool} /// /// See also: /// /// * [AdaptiveTextSelectionToolbar], which is built by default. final SelectableRegionContextMenuBuilder? contextMenuBuilder; /// Called when the selected content changes. final ValueChanged<SelectedContent?>? onSelectionChanged; /// The child widget this selection area applies to. /// /// {@macro flutter.widgets.ProxyWidget.child} final Widget child; static Widget _defaultContextMenuBuilder(BuildContext context, SelectableRegionState selectableRegionState) { return AdaptiveTextSelectionToolbar.selectableRegion( selectableRegionState: selectableRegionState, ); } @override State<StatefulWidget> createState() => _SelectionAreaState(); } class _SelectionAreaState extends State<SelectionArea> { FocusNode get _effectiveFocusNode { if (widget.focusNode != null) { return widget.focusNode!; } _internalNode ??= FocusNode(); return _internalNode!; } FocusNode? _internalNode; @override void dispose() { _internalNode?.dispose(); super.dispose(); } @override Widget build(BuildContext context) { assert(debugCheckHasMaterialLocalizations(context)); TextSelectionControls? controls = widget.selectionControls; switch (Theme.of(context).platform) { case TargetPlatform.android: case TargetPlatform.fuchsia: controls ??= materialTextSelectionHandleControls; break; case TargetPlatform.iOS: controls ??= cupertinoTextSelectionHandleControls; break; case TargetPlatform.linux: case TargetPlatform.windows: controls ??= desktopTextSelectionHandleControls; break; case TargetPlatform.macOS: controls ??= cupertinoDesktopTextSelectionHandleControls; break; } return SelectableRegion( selectionControls: controls, focusNode: _effectiveFocusNode, contextMenuBuilder: widget.contextMenuBuilder, magnifierConfiguration: widget.magnifierConfiguration ?? TextMagnifier.adaptiveMagnifierConfiguration, onSelectionChanged: widget.onSelectionChanged, child: widget.child, ); } }