|
@@ -12,17 +12,9 @@ import 'package:zefyr/util.dart';
|
12
|
12
|
|
13
|
13
|
import 'controller.dart';
|
14
|
14
|
import 'editable_box.dart';
|
|
15
|
+import 'image.dart' show RenderEditableImage;
|
|
16
|
+import 'rich_text.dart' show RenderZefyrParagraph;
|
15
|
17
|
import 'scope.dart';
|
16
|
|
-
|
17
|
|
-RenderEditableBox _getEditableBox(HitTestResult result) {
|
18
|
|
- for (var entry in result.path) {
|
19
|
|
- if (entry.target is RenderEditableBox) {
|
20
|
|
- return entry.target as RenderEditableBox;
|
21
|
|
- }
|
22
|
|
- }
|
23
|
|
- return null;
|
24
|
|
-}
|
25
|
|
-
|
26
|
18
|
/// Selection overlay controls selection handles and other gestures.
|
27
|
19
|
class ZefyrSelectionOverlay extends StatefulWidget {
|
28
|
20
|
const ZefyrSelectionOverlay({Key key, @required this.controls})
|
|
@@ -67,6 +59,15 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
|
67
|
59
|
return isSelectionCollapsed;
|
68
|
60
|
}
|
69
|
61
|
|
|
62
|
+ RenderEditableBox _getEditableBox(HitTestResult result) {
|
|
63
|
+ for (var entry in result.path) {
|
|
64
|
+ if (entry.target is RenderEditableBox) {
|
|
65
|
+ return entry.target as RenderEditableBox;
|
|
66
|
+ }
|
|
67
|
+ }
|
|
68
|
+ return null;
|
|
69
|
+ }
|
|
70
|
+
|
70
|
71
|
void showToolbar() {
|
71
|
72
|
final toolbarOpacity = _toolbarController.view;
|
72
|
73
|
_toolbar = OverlayEntry(
|
|
@@ -86,6 +87,7 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
|
86
|
87
|
TextEditingValue get textEditingValue =>
|
87
|
88
|
_scope.controller.plainTextEditingValue;
|
88
|
89
|
|
|
90
|
+ @override
|
89
|
91
|
set textEditingValue(TextEditingValue value) {
|
90
|
92
|
final cursorPosition = value.selection.extentOffset;
|
91
|
93
|
final oldText = _scope.controller.document.toPlainText();
|
|
@@ -180,6 +182,11 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
|
180
|
182
|
position: _SelectionHandlePosition.extent,
|
181
|
183
|
selectionOverlay: this,
|
182
|
184
|
),
|
|
185
|
+ // SizedBox(
|
|
186
|
+ // height: 20,
|
|
187
|
+ // width: 30,
|
|
188
|
+ // child: Container(color: Colors.black,),
|
|
189
|
+ // ),
|
183
|
190
|
],
|
184
|
191
|
),
|
185
|
192
|
);
|
|
@@ -244,9 +251,8 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
|
244
|
251
|
WidgetsBinding.instance.hitTest(result, globalPoint);
|
245
|
252
|
|
246
|
253
|
RenderEditableProxyBox box = _getEditableBox(result);
|
247
|
|
- if (box == null) {
|
248
|
|
- box = _scope.renderContext.closestBoxForGlobalPoint(globalPoint);
|
249
|
|
- }
|
|
254
|
+
|
|
255
|
+ box ??= _scope.renderContext.closestBoxForGlobalPoint(globalPoint);
|
250
|
256
|
if (box == null) return null;
|
251
|
257
|
|
252
|
258
|
final localPoint = box.globalToLocal(globalPoint);
|
|
@@ -255,6 +261,37 @@ class _ZefyrSelectionOverlayState extends State<ZefyrSelectionOverlay>
|
255
|
261
|
offset: position.offset,
|
256
|
262
|
affinity: position.affinity,
|
257
|
263
|
);
|
|
264
|
+ // 如果是link或者image
|
|
265
|
+ if (box?.child is RenderZefyrParagraph) {
|
|
266
|
+ RenderZefyrParagraph paragraph = box.child;
|
|
267
|
+ if (_scope.controller.getStyleForSelection(selection).contains(NotusAttribute.link)) {
|
|
268
|
+ // 当前点击的是link
|
|
269
|
+ var position = paragraph.getRenderBoxPositionForOffset(localPoint);
|
|
270
|
+ // 此处加1是点击text尾,不算点中
|
|
271
|
+ final TextSpan span = paragraph.text.getSpanForPosition(TextPosition(
|
|
272
|
+ offset: position.offset + 1,
|
|
273
|
+ affinity: position.affinity,
|
|
274
|
+ ));
|
|
275
|
+ final recognizer = (span?.recognizer as TapGestureRecognizer);
|
|
276
|
+ if (recognizer != null) {
|
|
277
|
+ print('当前点击的是link');
|
|
278
|
+ // 关闭键盘 触发tap,改变光标,但不弹出键盘
|
|
279
|
+ _scope.closeKeyboard();
|
|
280
|
+ recognizer.onTap();
|
|
281
|
+ _scope.controller.updateSelection(selection, source: ChangeSource.remote);
|
|
282
|
+ return;
|
|
283
|
+ }
|
|
284
|
+ }
|
|
285
|
+ } else if (box?.child is RenderEditableImage) {
|
|
286
|
+ RenderEditableImage image = box.child;
|
|
287
|
+ if ((image.child as RenderPadding).child is RenderSemanticsGestureHandler) {
|
|
288
|
+ RenderSemanticsGestureHandler gestureBox = (image.child as RenderPadding).child;
|
|
289
|
+ _scope.closeKeyboard();
|
|
290
|
+ gestureBox.onTap();
|
|
291
|
+ _scope.controller.updateSelection(selection, source: ChangeSource.remote);
|
|
292
|
+ return;
|
|
293
|
+ }
|
|
294
|
+ }
|
258
|
295
|
if (_didCaretTap && _selection == selection) {
|
259
|
296
|
_didCaretTap = false;
|
260
|
297
|
if (isToolbarVisible) {
|
|
@@ -340,6 +377,7 @@ class _SelectionHandleDriverState extends State<SelectionHandleDriver>
|
340
|
377
|
|
341
|
378
|
final Offset paintOffset = Offset.zero;
|
342
|
379
|
final List<ui.TextBox> boxes = block.getEndpointsForSelection(selection);
|
|
380
|
+ if (boxes.isEmpty) return null;
|
343
|
381
|
final Offset start =
|
344
|
382
|
Offset(boxes.first.start, boxes.first.bottom) + paintOffset;
|
345
|
383
|
final Offset end = Offset(boxes.last.end, boxes.last.bottom) + paintOffset;
|
|
@@ -388,6 +426,8 @@ class _SelectionHandleDriverState extends State<SelectionHandleDriver>
|
388
|
426
|
}
|
389
|
427
|
|
390
|
428
|
final List<TextSelectionPoint> endpoints = getEndpointsForSelection(block);
|
|
429
|
+ if (endpoints == null || endpoints.isEmpty) return Container();
|
|
430
|
+
|
391
|
431
|
Offset point;
|
392
|
432
|
TextSelectionHandleType type;
|
393
|
433
|
|
|
@@ -568,6 +608,10 @@ class _SelectionToolbarState extends State<_SelectionToolbar> {
|
568
|
608
|
return Container();
|
569
|
609
|
}
|
570
|
610
|
final boxes = block.getEndpointsForSelection(selection);
|
|
611
|
+ print('boxes: ${boxes}');
|
|
612
|
+ if (boxes.isEmpty) {
|
|
613
|
+ return Container();
|
|
614
|
+ }
|
571
|
615
|
// Find the horizontal midpoint, just above the selected text.
|
572
|
616
|
Offset midpoint = Offset(
|
573
|
617
|
(boxes.length == 1)
|