mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: add selection_service documentation and resymbol shortcut service.
This commit is contained in:
parent
b967453047
commit
1907284534
@ -96,7 +96,7 @@ class _MyHomePageState extends State<MyHomePage> {
|
||||
);
|
||||
return FlowyEditor(
|
||||
editorState: _editorState,
|
||||
keyEventHandler: const [],
|
||||
keyEventHandlers: const [],
|
||||
shortcuts: [
|
||||
// TODO: this won't work, just a example for now.
|
||||
{
|
||||
|
@ -0,0 +1,11 @@
|
||||
import 'package:flowy_editor/document/node.dart';
|
||||
import 'package:flowy_editor/extensions/object_extensions.dart';
|
||||
import 'package:flowy_editor/render/selection/selectable.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
extension NodeExtensions on Node {
|
||||
RenderBox? get renderBox =>
|
||||
key?.currentContext?.findRenderObject()?.unwrapOrNull<RenderBox>();
|
||||
|
||||
Selectable? get selectable => key?.currentState?.unwrapOrNull<Selectable>();
|
||||
}
|
@ -1,25 +1,27 @@
|
||||
import 'package:flowy_editor/render/selection/floating_shortcut_widget.dart';
|
||||
import 'package:flowy_editor/service/floating_shortcut_service.dart';
|
||||
import 'package:flowy_editor/service/flowy_key_event_handlers/arrow_keys_handler.dart';
|
||||
import 'package:flowy_editor/service/flowy_key_event_handlers/delete_nodes_handler.dart';
|
||||
import 'package:flowy_editor/service/flowy_key_event_handlers/delete_single_text_node_handler.dart';
|
||||
import 'package:flowy_editor/service/flowy_key_event_handlers/shortcut_handler.dart';
|
||||
import 'package:flowy_editor/service/shortcut_service.dart';
|
||||
import 'package:flowy_editor/service/internal_key_event_handlers/arrow_keys_handler.dart';
|
||||
import 'package:flowy_editor/service/internal_key_event_handlers/delete_nodes_handler.dart';
|
||||
import 'package:flowy_editor/service/internal_key_event_handlers/delete_single_text_node_handler.dart';
|
||||
import 'package:flowy_editor/service/internal_key_event_handlers/shortcut_handler.dart';
|
||||
import 'package:flowy_editor/service/keyboard_service.dart';
|
||||
import 'package:flowy_editor/service/selection_service.dart';
|
||||
import 'package:flowy_editor/editor_state.dart';
|
||||
|
||||
import '../editor_state.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class FlowyEditor extends StatefulWidget {
|
||||
const FlowyEditor({
|
||||
Key? key,
|
||||
required this.editorState,
|
||||
required this.keyEventHandler,
|
||||
required this.keyEventHandlers,
|
||||
required this.shortcuts,
|
||||
}) : super(key: key);
|
||||
|
||||
final EditorState editorState;
|
||||
final List<FlowyKeyEventHandler> keyEventHandler;
|
||||
final List<FlowyKeyEventHandler> keyEventHandlers;
|
||||
|
||||
/// Shortcusts
|
||||
final FloatingShortcuts shortcuts;
|
||||
|
||||
@override
|
||||
@ -41,7 +43,7 @@ class _FlowyEditorState extends State<FlowyEditor> {
|
||||
flowyDeleteNodesHandler,
|
||||
deleteSingleTextNodeHandler,
|
||||
arrowKeysHandler,
|
||||
...widget.keyEventHandler,
|
||||
...widget.keyEventHandlers,
|
||||
],
|
||||
editorState: editorState,
|
||||
child: FloatingShortcut(
|
||||
|
@ -1,7 +1,8 @@
|
||||
import 'package:flowy_editor/render/selection/cursor_widget.dart';
|
||||
import 'package:flowy_editor/render/selection/flowy_selection_widget.dart';
|
||||
import 'package:flowy_editor/extensions/object_extensions.dart';
|
||||
import 'package:flowy_editor/service/floating_shortcut_service.dart';
|
||||
import 'package:flowy_editor/extensions/node_extensions.dart';
|
||||
import 'package:flowy_editor/service/shortcut_service.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
@ -11,58 +12,65 @@ import '../render/selection/selectable.dart';
|
||||
|
||||
/// Process selection and cursor
|
||||
mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
|
||||
/// [Pan] and [Tap] must be mutually exclusive.
|
||||
/// Pan
|
||||
Offset? panStartOffset;
|
||||
Offset? panEndOffset;
|
||||
|
||||
/// Tap
|
||||
Offset? tapOffset;
|
||||
|
||||
/// [start] and [end] are the offsets under the global coordinate system.
|
||||
void updateSelection(Offset start, Offset end);
|
||||
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
void updateCursor(Offset start);
|
||||
|
||||
/// Returns selected node(s)
|
||||
/// Returns empty list if no nodes are being selected.
|
||||
/// Returns selected [Node]s. Empty list would be returned
|
||||
/// if no nodes are being selected.
|
||||
///
|
||||
///
|
||||
/// [start] and [end] are the offsets under the global coordinate system.
|
||||
///
|
||||
/// If end is not null, it means multiple selection,
|
||||
/// otherwise single selection.
|
||||
List<Node> getSelectedNodes(Offset start, [Offset? end]);
|
||||
|
||||
/// Compute selected node triggered by [Tap]
|
||||
Node? computeSelectedNodeInOffset(
|
||||
Node node,
|
||||
Offset offset,
|
||||
);
|
||||
/// Return the [Node] or [Null] in single selection.
|
||||
///
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
Node? computeSelectedNodeInOffset(Node node, Offset offset);
|
||||
|
||||
/// Compute selected nodes triggered by [Pan]
|
||||
/// Return the [Node]s in multiple selection. Emtpy list would be returned
|
||||
/// if no nodes are in range.
|
||||
///
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
List<Node> computeSelectedNodesInRange(
|
||||
Node node,
|
||||
Offset start,
|
||||
Offset end,
|
||||
);
|
||||
|
||||
/// Pan
|
||||
/// Return [bool] to identify the [Node] is in Range or not.
|
||||
///
|
||||
/// [start] and [end] are the offsets under the global coordinate system.
|
||||
bool isNodeInSelection(
|
||||
Node node,
|
||||
Offset start,
|
||||
Offset end,
|
||||
);
|
||||
|
||||
/// Tap
|
||||
bool isNodeInOffset(
|
||||
Node node,
|
||||
Offset offset,
|
||||
);
|
||||
/// Return [bool] to identify the [Node] contains [Offset] or not.
|
||||
///
|
||||
/// [start] is the offset under the global coordinate system.
|
||||
bool isNodeInOffset(Node node, Offset offset);
|
||||
}
|
||||
|
||||
class FlowySelection extends StatefulWidget {
|
||||
const FlowySelection({
|
||||
Key? key,
|
||||
this.cursorColor = Colors.black,
|
||||
this.selectionColor = const Color.fromARGB(60, 61, 61, 213),
|
||||
required this.editorState,
|
||||
required this.child,
|
||||
}) : super(key: key);
|
||||
|
||||
final EditorState editorState;
|
||||
final Widget child;
|
||||
final Color cursorColor;
|
||||
final Color selectionColor;
|
||||
|
||||
@override
|
||||
State<FlowySelection> createState() => _FlowySelectionState();
|
||||
@ -75,6 +83,14 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
final List<OverlayEntry> _selectionOverlays = [];
|
||||
final List<OverlayEntry> _cursorOverlays = [];
|
||||
|
||||
/// [Pan] and [Tap] must be mutually exclusive.
|
||||
/// Pan
|
||||
Offset? panStartOffset;
|
||||
Offset? panEndOffset;
|
||||
|
||||
/// Tap
|
||||
Offset? tapOffset;
|
||||
|
||||
EditorState get editorState => widget.editorState;
|
||||
|
||||
@override
|
||||
@ -123,7 +139,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
for (final rect in selectionRects) {
|
||||
final overlay = OverlayEntry(
|
||||
builder: ((context) => SelectionWidget(
|
||||
color: Colors.yellow.withAlpha(100),
|
||||
color: widget.selectionColor,
|
||||
layerLink: node.layerLink,
|
||||
rect: rect,
|
||||
)),
|
||||
@ -154,7 +170,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
builder: ((context) => CursorWidget(
|
||||
key: _cursorKey,
|
||||
rect: rect,
|
||||
color: Colors.red,
|
||||
color: widget.cursorColor,
|
||||
layerLink: selectedNode.layerLink,
|
||||
)),
|
||||
);
|
||||
@ -165,16 +181,10 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
@override
|
||||
List<Node> getSelectedNodes(Offset start, [Offset? end]) {
|
||||
if (end != null) {
|
||||
return computeSelectedNodesInRange(
|
||||
editorState.document.root,
|
||||
start,
|
||||
end,
|
||||
);
|
||||
return computeSelectedNodesInRange(editorState.document.root, start, end);
|
||||
} else {
|
||||
final reuslt = computeSelectedNodeInOffset(
|
||||
editorState.document.root,
|
||||
start,
|
||||
);
|
||||
final reuslt =
|
||||
computeSelectedNodeInOffset(editorState.document.root, start);
|
||||
if (reuslt != null) {
|
||||
return [reuslt];
|
||||
}
|
||||
@ -190,13 +200,11 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (node.parent != null && node.key != null) {
|
||||
if (isNodeInOffset(node, offset)) {
|
||||
return node;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -217,9 +225,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
|
||||
@override
|
||||
bool isNodeInOffset(Node node, Offset offset) {
|
||||
assert(node.key != null);
|
||||
final renderBox =
|
||||
node.key?.currentContext?.findRenderObject() as RenderBox?;
|
||||
final renderBox = node.renderBox;
|
||||
if (renderBox != null) {
|
||||
final boxOffset = renderBox.localToGlobal(Offset.zero);
|
||||
final boxRect = boxOffset & renderBox.size;
|
||||
@ -230,9 +236,7 @@ class _FlowySelectionState extends State<FlowySelection>
|
||||
|
||||
@override
|
||||
bool isNodeInSelection(Node node, Offset start, Offset end) {
|
||||
assert(node.key != null);
|
||||
final renderBox =
|
||||
node.key?.currentContext?.findRenderObject() as RenderBox?;
|
||||
final renderBox = node.renderBox;
|
||||
if (renderBox != null) {
|
||||
final rect = Rect.fromPoints(start, end);
|
||||
final boxOffset = renderBox.localToGlobal(Offset.zero);
|
||||
|
@ -1,4 +1,4 @@
|
||||
import 'package:flowy_editor/service/floating_shortcut_service.dart';
|
||||
import 'package:flowy_editor/service/shortcut_service.dart';
|
||||
import 'package:flowy_editor/service/selection_service.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user