From 00783adf915a07209220f3c8c84b7695b56c52bd Mon Sep 17 00:00:00 2001 From: AtlasAutocode Date: Fri, 7 Jun 2024 15:20:06 -0600 Subject: [PATCH] Subscript and Superscript --- .../quill_controller_configurations.dart | 8 ++- lib/src/widgets/editor/editor.dart | 1 + lib/src/widgets/quill/text_line.dart | 60 +++++++++++++++++-- 3 files changed, 64 insertions(+), 5 deletions(-) diff --git a/lib/src/models/config/quill_controller_configurations.dart b/lib/src/models/config/quill_controller_configurations.dart index ae38841a..95126178 100644 --- a/lib/src/models/config/quill_controller_configurations.dart +++ b/lib/src/models/config/quill_controller_configurations.dart @@ -1,8 +1,14 @@ class QuillControllerConfigurations { - const QuillControllerConfigurations({this.onClipboardPaste}); + const QuillControllerConfigurations( + {this.onClipboardPaste, this.requireScriptFontFeatures = false}); /// Callback when the user pastes and data has not already been processed /// /// Return true if the paste operation was handled final Future Function()? onClipboardPaste; + + /// Render subscript and superscript text using Open Type FontFeatures + /// + /// Default is false to use built-in script rendering that is independent of font capabilities + final bool requireScriptFontFeatures; } diff --git a/lib/src/widgets/editor/editor.dart b/lib/src/widgets/editor/editor.dart index a5635967..0fba7806 100644 --- a/lib/src/widgets/editor/editor.dart +++ b/lib/src/widgets/editor/editor.dart @@ -173,6 +173,7 @@ class QuillEditorState extends State void initState() { super.initState(); widget.configurations.controller.editorFocusNode ??= widget.focusNode; + widget.configurations.controller.editorFocusNode?.requestFocus(); _editorKey = configurations.editorKey ?? GlobalKey(); _selectionGestureDetectorBuilder = _QuillEditorSelectionGestureDetectorBuilder( diff --git a/lib/src/widgets/quill/text_line.dart b/lib/src/widgets/quill/text_line.dart index e03e5ae8..0375273d 100644 --- a/lib/src/widgets/quill/text_line.dart +++ b/lib/src/widgets/quill/text_line.dart @@ -322,19 +322,71 @@ class _TextLineState extends State { return textStyle; } - TextSpan _getTextSpanFromNode( + /// Processes subscript and superscript attributed text. + /// + /// Reduces text fontSize and shifts down or up. Increases fontWeight to maintain balance with normal text. + /// Outputs characters individually to allow correct caret positioning and text selection. + InlineSpan _scriptSpan(String text, bool superScript, TextStyle style, + DefaultStyles defaultStyles) { + assert(text.isNotEmpty); + // + final lineStyle = style.fontSize == null || style.fontWeight == null + ? _getLineStyle(defaultStyles) + : null; + final fontWeight = FontWeight.lerp( + style.fontWeight ?? lineStyle?.fontWeight ?? FontWeight.normal, + FontWeight.w900, + 0.25); + final fontSize = style.fontSize ?? lineStyle?.fontSize ?? 16; + final y = (superScript ? -0.4 : 0.14) * fontSize; + final charStyle = style.copyWith( + fontFeatures: [], + fontWeight: fontWeight, + fontSize: fontSize * 0.7); + // + final offset = Offset(0, y); + final children = []; + for (final c in text.characters) { + children.add(WidgetSpan( + child: Transform.translate( + offset: offset, + child: Text( + c, + style: charStyle, + )))); + } + // + if (children.length > 1) { + return TextSpan(children: children); + } + return children[0]; + } + + InlineSpan _getTextSpanFromNode( DefaultStyles defaultStyles, Node node, Style lineStyle) { final textNode = node as leaf.QuillText; final nodeStyle = textNode.style; final isLink = nodeStyle.containsKey(Attribute.link.key) && nodeStyle.attributes[Attribute.link.key]!.value != null; - final recognizer = _getRecognizer(node, isLink); + final style = _getInlineTextStyle( + textNode, defaultStyles, nodeStyle, lineStyle, isLink); + + if (widget.controller.configurations.requireScriptFontFeatures == false && + textNode.value.isNotEmpty) { + if (nodeStyle.containsKey(Attribute.script.key)) { + final attr = nodeStyle.attributes[Attribute.script.key]; + if (attr == Attribute.superscript || attr == Attribute.subscript) { + return _scriptSpan(textNode.value, attr == Attribute.superscript, + style, defaultStyles); + } + } + } + final recognizer = _getRecognizer(node, isLink); return TextSpan( text: textNode.value, - style: _getInlineTextStyle( - textNode, defaultStyles, nodeStyle, lineStyle, isLink), + style: style, recognizer: recognizer, mouseCursor: (recognizer != null) ? SystemMouseCursors.click : null, );