mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
refactor: add hitTest method for selection service
This commit is contained in:
parent
1d3e5a9e8b
commit
b91c5d9c7b
@ -10,6 +10,58 @@ int _endOffsetOfNode(Node node) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension on Position {
|
||||||
|
Position? goLeft(EditorState editorState) {
|
||||||
|
if (offset == 0) {
|
||||||
|
final node = editorState.document.nodeAtPath(path)!;
|
||||||
|
final prevNode = node.previous;
|
||||||
|
if (prevNode != null) {
|
||||||
|
return Position(
|
||||||
|
path: prevNode.path, offset: _endOffsetOfNode(prevNode));
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Position(path: path, offset: offset - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
Position? goRight(EditorState editorState) {
|
||||||
|
final node = editorState.document.nodeAtPath(path)!;
|
||||||
|
final lengthOfNode = _endOffsetOfNode(node);
|
||||||
|
if (offset >= lengthOfNode) {
|
||||||
|
final nextNode = node.next;
|
||||||
|
if (nextNode != null) {
|
||||||
|
return Position(path: nextNode.path, offset: 0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return Position(path: path, offset: offset + 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Position? _goUp(EditorState editorState) {
|
||||||
|
final rects = editorState.service.selectionService.rects();
|
||||||
|
if (rects.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final first = rects.first;
|
||||||
|
final firstOffset = Offset(first.left, first.top);
|
||||||
|
final hitOffset = firstOffset - Offset(0, first.height * 0.5);
|
||||||
|
return editorState.service.selectionService.hitTest(hitOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
Position? _goDown(EditorState editorState) {
|
||||||
|
final rects = editorState.service.selectionService.rects();
|
||||||
|
if (rects.isEmpty) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final first = rects.last;
|
||||||
|
final firstOffset = Offset(first.right, first.bottom);
|
||||||
|
final hitOffset = firstOffset + Offset(0, first.height * 0.5);
|
||||||
|
return editorState.service.selectionService.hitTest(hitOffset);
|
||||||
|
}
|
||||||
|
|
||||||
KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) {
|
KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) {
|
||||||
final currentSelection = editorState.cursorSelection;
|
final currentSelection = editorState.cursorSelection;
|
||||||
if (currentSelection == null) {
|
if (currentSelection == null) {
|
||||||
@ -17,53 +69,33 @@ KeyEventResult _handleShiftKey(EditorState editorState, RawKeyEvent event) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
||||||
final leftPosition = _leftPosition(editorState, currentSelection.start);
|
final leftPosition = currentSelection.end.goLeft(editorState);
|
||||||
if (leftPosition != null) {
|
editorState.updateCursorSelection(leftPosition == null
|
||||||
editorState.updateCursorSelection(
|
? null
|
||||||
Selection(start: leftPosition, end: currentSelection.end));
|
: Selection(start: currentSelection.start, end: leftPosition));
|
||||||
}
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
||||||
final rightPosition = _rightPosition(editorState, currentSelection.end);
|
final rightPosition = currentSelection.start.goRight(editorState);
|
||||||
if (rightPosition != null) {
|
editorState.updateCursorSelection(rightPosition == null
|
||||||
editorState.updateCursorSelection(
|
? null
|
||||||
Selection(start: currentSelection.start, end: rightPosition));
|
: Selection(start: rightPosition, end: currentSelection.end));
|
||||||
}
|
return KeyEventResult.handled;
|
||||||
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
||||||
|
final position = _goUp(editorState);
|
||||||
|
editorState.updateCursorSelection(position == null
|
||||||
|
? null
|
||||||
|
: Selection(start: position, end: currentSelection.end));
|
||||||
|
return KeyEventResult.handled;
|
||||||
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
||||||
|
final position = _goDown(editorState);
|
||||||
|
editorState.updateCursorSelection(position == null
|
||||||
|
? null
|
||||||
|
: Selection(start: currentSelection.start, end: position));
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
return KeyEventResult.ignored;
|
return KeyEventResult.ignored;
|
||||||
}
|
}
|
||||||
|
|
||||||
Position? _leftPosition(EditorState editorState, Position position) {
|
|
||||||
final offset = position.offset;
|
|
||||||
if (offset == 0) {
|
|
||||||
final node = editorState.document.nodeAtPath(position.path)!;
|
|
||||||
final prevNode = node.previous;
|
|
||||||
if (prevNode != null) {
|
|
||||||
editorState.updateCursorSelection(Selection.collapsed(
|
|
||||||
Position(path: prevNode.path, offset: _endOffsetOfNode(prevNode))));
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Position(path: position.path, offset: offset - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Position? _rightPosition(EditorState editorState, Position position) {
|
|
||||||
final offset = position.offset;
|
|
||||||
final node = editorState.document.nodeAtPath(position.path)!;
|
|
||||||
final lengthOfNode = _endOffsetOfNode(node);
|
|
||||||
if (offset >= lengthOfNode) {
|
|
||||||
final nextNode = node.next;
|
|
||||||
if (nextNode != null) {
|
|
||||||
Position(path: nextNode.path, offset: 0);
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Position(path: position.path, offset: offset + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
||||||
if (event.isShiftPressed) {
|
if (event.isShiftPressed) {
|
||||||
return _handleShiftKey(editorState, event);
|
return _handleShiftKey(editorState, event);
|
||||||
@ -76,7 +108,7 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
|||||||
|
|
||||||
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
if (event.logicalKey == LogicalKeyboardKey.arrowLeft) {
|
||||||
if (currentSelection.isCollapsed) {
|
if (currentSelection.isCollapsed) {
|
||||||
final leftPosition = _leftPosition(editorState, currentSelection.start);
|
final leftPosition = currentSelection.start.goLeft(editorState);
|
||||||
if (leftPosition != null) {
|
if (leftPosition != null) {
|
||||||
editorState.updateCursorSelection(Selection.collapsed(leftPosition));
|
editorState.updateCursorSelection(Selection.collapsed(leftPosition));
|
||||||
}
|
}
|
||||||
@ -87,7 +119,7 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
|||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowRight) {
|
||||||
if (currentSelection.isCollapsed) {
|
if (currentSelection.isCollapsed) {
|
||||||
final rightPosition = _rightPosition(editorState, currentSelection.end);
|
final rightPosition = currentSelection.end.goRight(editorState);
|
||||||
if (rightPosition != null) {
|
if (rightPosition != null) {
|
||||||
editorState.updateCursorSelection(Selection.collapsed(rightPosition));
|
editorState.updateCursorSelection(Selection.collapsed(rightPosition));
|
||||||
}
|
}
|
||||||
@ -96,24 +128,14 @@ FlowyKeyEventHandler arrowKeysHandler = (editorState, event) {
|
|||||||
}
|
}
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowUp) {
|
||||||
final rects = editorState.service.selectionService.rects();
|
final position = _goUp(editorState);
|
||||||
if (rects.isEmpty) {
|
editorState.updateCursorSelection(
|
||||||
return KeyEventResult.handled;
|
position == null ? null : Selection.collapsed(position));
|
||||||
}
|
|
||||||
final first = rects.first;
|
|
||||||
final firstOffset = Offset(first.left, first.top);
|
|
||||||
final hitOffset = firstOffset - Offset(0, first.height * 0.5);
|
|
||||||
editorState.service.selectionService.hit(hitOffset);
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
} else if (event.logicalKey == LogicalKeyboardKey.arrowDown) {
|
||||||
final rects = editorState.service.selectionService.rects();
|
final position = _goDown(editorState);
|
||||||
if (rects.isEmpty) {
|
editorState.updateCursorSelection(
|
||||||
return KeyEventResult.handled;
|
position == null ? null : Selection.collapsed(position));
|
||||||
}
|
|
||||||
final first = rects.last;
|
|
||||||
final firstOffset = Offset(first.right, first.bottom);
|
|
||||||
final hitOffset = firstOffset + Offset(0, first.height * 0.5);
|
|
||||||
editorState.service.selectionService.hit(hitOffset);
|
|
||||||
return KeyEventResult.handled;
|
return KeyEventResult.handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +30,7 @@ mixin FlowySelectionService<T extends StatefulWidget> on State<T> {
|
|||||||
|
|
||||||
List<Rect> rects();
|
List<Rect> rects();
|
||||||
|
|
||||||
hit(Offset? offset);
|
Position? hitTest(Offset? offset);
|
||||||
|
|
||||||
///
|
///
|
||||||
List<Node> getNodesInSelection(Selection selection);
|
List<Node> getNodesInSelection(Selection selection);
|
||||||
@ -285,29 +285,32 @@ class _FlowySelectionState extends State<FlowySelection>
|
|||||||
|
|
||||||
tapOffset = details.globalPosition;
|
tapOffset = details.globalPosition;
|
||||||
|
|
||||||
hit(tapOffset);
|
final position = hitTest(tapOffset);
|
||||||
|
if (position == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final selection = Selection.collapsed(position);
|
||||||
|
editorState.updateCursorSelection(selection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
hit(Offset? offset) {
|
Position? hitTest(Offset? offset) {
|
||||||
if (offset == null) {
|
if (offset == null) {
|
||||||
editorState.updateCursorSelection(null);
|
editorState.updateCursorSelection(null);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
final nodes = getNodesInRange(offset);
|
final nodes = getNodesInRange(offset);
|
||||||
if (nodes.isEmpty) {
|
if (nodes.isEmpty) {
|
||||||
editorState.updateCursorSelection(null);
|
editorState.updateCursorSelection(null);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
assert(nodes.length == 1);
|
assert(nodes.length == 1);
|
||||||
final selectable = nodes.first.selectable;
|
final selectable = nodes.first.selectable;
|
||||||
if (selectable == null) {
|
if (selectable == null) {
|
||||||
editorState.updateCursorSelection(null);
|
editorState.updateCursorSelection(null);
|
||||||
return;
|
return null;
|
||||||
}
|
}
|
||||||
final position = selectable.getPositionInOffset(offset);
|
return selectable.getPositionInOffset(offset);
|
||||||
final selection = Selection.collapsed(position);
|
|
||||||
editorState.updateCursorSelection(selection);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onPanStart(DragStartDetails details) {
|
void _onPanStart(DragStartDetails details) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user