| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- import 'package:flutter/material.dart';
- import 'package:flutter/rendering.dart';
- import '../model/document/node/block.dart';
- import '../widget/selection.dart';
- import 'box.dart';
- import 'editor.dart';
- class RenderEditableTextBlock extends RenderEditableContainerBox
- implements RenderEditableBox {
- RenderEditableTextBlock({
- required Block block,
- required TextDirection textDirection,
- required EdgeInsetsGeometry padding,
- required double scrollBottomInset,
- required Decoration decoration,
- List<RenderEditableBox>? children,
- ImageConfiguration configuration = ImageConfiguration.empty,
- EdgeInsets contentPadding = EdgeInsets.zero,
- }) : _decoration = decoration,
- _configuration = configuration,
- _savePadding = padding,
- _contentPadding = contentPadding,
- super(children, textDirection, scrollBottomInset, block,
- padding.add(contentPadding));
- EdgeInsetsGeometry _savePadding;
- EdgeInsets _contentPadding;
- set contentPadding(EdgeInsets value) {
- if (_contentPadding == value) {
- return;
- }
- _contentPadding = value;
- super.padding = _savePadding.add(_contentPadding);
- }
- @override
- set padding(EdgeInsetsGeometry value) {
- super.padding = value.add(_contentPadding);
- _savePadding = value;
- }
- BoxPainter? _painter;
- Decoration _decoration;
- Decoration get decoration => _decoration;
- set decoration(Decoration value) {
- if (_decoration == value) {
- return;
- }
- _painter?.dispose();
- _painter = null;
- _decoration = value;
- markNeedsPaint();
- }
- ImageConfiguration _configuration;
- ImageConfiguration get configuration => _configuration;
- set configuration(ImageConfiguration value) {
- if (_configuration == value) {
- return;
- }
- _configuration = value;
- markNeedsPaint();
- }
- @override
- TextRange getLineBoundary(TextPosition position) {
- final child = childAtPosition(position);
- final rangeInChild = child.getLineBoundary(TextPosition(
- offset: position.offset - child.container.offset,
- affinity: position.affinity,
- ));
- return TextRange(
- start: rangeInChild.start + child.container.offset,
- end: rangeInChild.end + child.container.offset,
- );
- }
- @override
- Offset getOffsetForCaret(TextPosition position) {
- final child = childAtPosition(position);
- return child.getOffsetForCaret(TextPosition(
- offset: position.offset - child.container.offset,
- affinity: position.affinity,
- )) +
- (child.parentData as BoxParentData).offset;
- }
- @override
- TextPosition getPositionForOffset(Offset offset) {
- final child = childAtOffset(offset)!;
- final parentData = child.parentData as BoxParentData;
- final localPosition =
- child.getPositionForOffset(offset - parentData.offset);
- return TextPosition(
- offset: localPosition.offset + child.container.offset,
- affinity: localPosition.affinity,
- );
- }
- @override
- TextRange getWordBoundary(TextPosition position) {
- final child = childAtPosition(position);
- final nodeOffset = child.container.offset;
- final childWord = child
- .getWordBoundary(TextPosition(offset: position.offset - nodeOffset));
- return TextRange(
- start: childWord.start + nodeOffset,
- end: childWord.end + nodeOffset,
- );
- }
- @override
- TextPosition? getPositionAbove(TextPosition position) {
- assert(position.offset < container.length);
- final child = childAtPosition(position);
- final childLocalPosition =
- TextPosition(offset: position.offset - child.container.offset);
- final result = child.getPositionAbove(childLocalPosition);
- if (result != null) {
- return TextPosition(offset: result.offset + child.container.offset);
- }
- final sibling = childBefore(child);
- if (sibling == null) {
- return null;
- }
- final caretOffset = child.getOffsetForCaret(childLocalPosition);
- final testPosition = TextPosition(offset: sibling.container.length - 1);
- final testOffset = sibling.getOffsetForCaret(testPosition);
- final finalOffset = Offset(caretOffset.dx, testOffset.dy);
- return TextPosition(
- offset: sibling.container.offset +
- sibling.getPositionForOffset(finalOffset).offset,
- );
- }
- @override
- TextPosition? getPositionBelow(TextPosition position) {
- assert(position.offset < container.length);
- final child = childAtPosition(position);
- final childLocalPosition =
- TextPosition(offset: position.offset - child.container.offset);
- final result = child.getPositionBelow(childLocalPosition);
- if (result != null) {
- return TextPosition(offset: result.offset + child.container.offset);
- }
- final sibling = childAfter(child);
- if (sibling == null) {
- return null;
- }
- final caretOffset = child.getOffsetForCaret(childLocalPosition);
- final testOffset = sibling.getOffsetForCaret(const TextPosition(offset: 0));
- final finalOffset = Offset(caretOffset.dx, testOffset.dy);
- return TextPosition(
- offset: sibling.container.offset +
- sibling.getPositionForOffset(finalOffset).offset,
- );
- }
- @override
- double preferredLineHeight(TextPosition position) {
- final child = childAtPosition(position);
- return child.preferredLineHeight(
- TextPosition(offset: position.offset - child.container.offset),
- );
- }
- @override
- TextSelectionPoint getBaseEndpointForSelection(TextSelection selection) {
- if (selection.isCollapsed) {
- return TextSelectionPoint(
- Offset(0, preferredLineHeight(selection.extent)) +
- getOffsetForCaret(selection.extent),
- null,
- );
- }
- final baseNode = container.queryChild(selection.start, false).node;
- var baseChild = firstChild;
- while (baseChild != null) {
- if (baseChild.container == baseNode) {
- break;
- }
- baseChild = childAfter(baseChild);
- }
- assert(baseChild != null);
- final basePoint = baseChild!.getBaseEndpointForSelection(localSelection(
- baseChild.container,
- selection,
- true,
- ));
- return TextSelectionPoint(
- basePoint.point + (baseChild.parentData as BoxParentData).offset,
- basePoint.direction,
- );
- }
- @override
- TextSelectionPoint getExtentEndpointForSelection(TextSelection selection) {
- if (selection.isCollapsed) {
- return TextSelectionPoint(
- Offset(0, preferredLineHeight(selection.extent)) +
- getOffsetForCaret(selection.extent),
- null,
- );
- }
- final extentNode = container.queryChild(selection.end, false).node;
- var extentChild = firstChild;
- while (extentChild != null) {
- if (extentChild.container == extentNode) {
- break;
- }
- extentChild = childAfter(extentChild);
- }
- assert(extentChild != null);
- final extentPoint = extentChild!.getExtentEndpointForSelection(
- localSelection(extentChild.container, selection, true),
- );
- return TextSelectionPoint(
- extentPoint.point + (extentChild.parentData as BoxParentData).offset,
- extentPoint.direction,
- );
- }
- @override
- void detach() {
- _painter?.dispose();
- _painter = null;
- super.detach();
- markNeedsPaint();
- }
- @override
- void paint(PaintingContext context, Offset offset) {
- _paintDecoration(context, offset);
- defaultPaint(context, offset);
- }
- void _paintDecoration(PaintingContext context, Offset offset) {
- _painter ??= _decoration.createBoxPainter(markNeedsPaint);
- final decorationPadding = resolvedPadding! - _contentPadding;
- final filledConfiguration =
- configuration.copyWith(size: decorationPadding.deflateSize(size));
- final debugSaveCount = context.canvas.getSaveCount();
- final decorationOffset =
- offset.translate(decorationPadding.left, decorationPadding.top);
- _painter!.paint(context.canvas, decorationOffset, filledConfiguration);
- if (debugSaveCount != context.canvas.getSaveCount()) {
- throw '${_decoration.runtimeType} painter had mismatching save and restore calls.';
- }
- if (decoration.isComplex) {
- context.setIsComplexHint();
- }
- }
- @override
- bool hitTestChildren(BoxHitTestResult result, {required Offset position}) {
- return defaultHitTestChildren(result, position: position);
- }
- }
|