Skip to content
This repository was archived by the owner on Apr 29, 2021. It is now read-only.

Commit 17c0b41

Browse files
authored
Merge pull request #139 from UnityTech/textselection
Textselection
2 parents 3efb8ff + c57b265 commit 17c0b41

File tree

8 files changed

+207
-8
lines changed

8 files changed

+207
-8
lines changed

Runtime/gestures/hover.cs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
using Unity.UIWidgets.foundation;
2+
3+
namespace Unity.UIWidgets.gestures {
4+
5+
public delegate void PointerHoverEnterCallback(PointerHoverEvent evt);
6+
7+
public delegate void PointerHoverLeaveCallback();
8+
9+
public class HoverRecognizer : DiagnosticableTree {
10+
public HoverRecognizer(object debugOwner = null) {
11+
this.debugOwner = debugOwner;
12+
}
13+
14+
readonly object debugOwner;
15+
16+
public PointerHoverEnterCallback OnPointerEnter;
17+
18+
public PointerHoverLeaveCallback OnPointerLeave;
19+
20+
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {
21+
base.debugFillProperties(properties);
22+
properties.add(new DiagnosticsProperty<object>("debugOwner", this.debugOwner,
23+
defaultValue: Diagnostics.kNullDefaultValue));
24+
}
25+
}
26+
}

Runtime/gestures/hover.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Runtime/painting/basic_types.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ namespace Unity.UIWidgets.painting {
55
public enum RenderComparison {
66
identical,
77
metadata,
8+
function,
89
paint,
910
layout,
1011
}

Runtime/painting/text_span.cs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,15 @@ public class TextSpan : DiagnosticableTree, IEquatable<TextSpan> {
1515
public readonly string text;
1616
public readonly List<TextSpan> children;
1717
public readonly GestureRecognizer recognizer;
18+
public readonly HoverRecognizer hoverRecognizer;
1819

1920
public TextSpan(string text = "", TextStyle style = null, List<TextSpan> children = null,
20-
GestureRecognizer recognizer = null) {
21+
GestureRecognizer recognizer = null, HoverRecognizer hoverRecognizer = null) {
2122
this.text = text;
2223
this.style = style;
2324
this.children = children;
2425
this.recognizer = recognizer;
26+
this.hoverRecognizer = hoverRecognizer;
2527
}
2628

2729
public void build(ParagraphBuilder builder, float textScaleFactor = 1.0f) {
@@ -46,6 +48,20 @@ public void build(ParagraphBuilder builder, float textScaleFactor = 1.0f) {
4648
}
4749
}
4850

51+
public bool hasHoverRecognizer {
52+
get {
53+
bool need = false;
54+
this.visitTextSpan((text) => {
55+
if (text.hoverRecognizer != null) {
56+
need = true;
57+
return false;
58+
}
59+
return true;
60+
});
61+
return need;
62+
}
63+
}
64+
4965
bool visitTextSpan(Visitor visitor) {
5066
if (!string.IsNullOrEmpty(this.text)) {
5167
if (!visitor.Invoke(this)) {
@@ -153,6 +169,11 @@ public RenderComparison compareTo(TextSpan other) {
153169
RenderComparison result = Equals(this.recognizer, other.recognizer)
154170
? RenderComparison.identical
155171
: RenderComparison.metadata;
172+
173+
if (!Equals(this.hoverRecognizer, other.hoverRecognizer)) {
174+
result = RenderComparison.function > result ? RenderComparison.function : result;
175+
}
176+
156177
if (this.style != null) {
157178
var candidate = this.style.compareTo(other.style);
158179
if (candidate > result) {

Runtime/rendering/paragraph.cs

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ public RenderParagraph(TextSpan text,
5959
this._selection = null;
6060
this.onSelectionChanged = onSelectionChanged;
6161
this.selectionColor = selectionColor;
62+
63+
this._resetHoverHandler();
6264
}
6365

6466
public Action onSelectionChanged;
@@ -86,6 +88,9 @@ public TextSpan text {
8688
case RenderComparison.identical:
8789
case RenderComparison.metadata:
8890
return;
91+
case RenderComparison.function:
92+
this._textPainter.text = value;
93+
break;
8994
case RenderComparison.paint:
9095
this._textPainter.text = value;
9196
this.markNeedsPaint();
@@ -95,6 +100,8 @@ public TextSpan text {
95100
this.markNeedsLayout();
96101
break;
97102
}
103+
104+
this._resetHoverHandler();
98105
}
99106
}
100107

@@ -241,6 +248,16 @@ public bool hasFocus {
241248
}
242249
}
243250

251+
TextSpan _previousHoverSpan;
252+
bool _pointerHoverInside;
253+
bool _hasHoverRecognizer;
254+
255+
void _resetHoverHandler() {
256+
this._hasHoverRecognizer = this._textPainter.text.hasHoverRecognizer;
257+
this._previousHoverSpan = null;
258+
this._pointerHoverInside = false;
259+
}
260+
244261
void _handleKeyEvent(RawKeyEvent keyEvent) {
245262
//only allow KCommand.copy
246263
if (keyEvent is RawKeyUpEvent) {
@@ -316,17 +333,46 @@ void _handleSelectionChanged(TextSelection selection,
316333
this.onSelectionChanged?.Invoke();
317334
}
318335

336+
337+
void _handlePointerHover(PointerEvent evt) {
338+
if (!this._hasHoverRecognizer) {
339+
return;
340+
}
341+
342+
if (evt is PointerEnterEvent) {
343+
this._pointerHoverInside = true;
344+
}
345+
else if (evt is PointerLeaveEvent) {
346+
this._pointerHoverInside = false;
347+
this._previousHoverSpan?.hoverRecognizer?.OnPointerLeave?.Invoke();
348+
this._previousHoverSpan = null;
349+
}
350+
else if (evt is PointerHoverEvent && this._pointerHoverInside) {
351+
this._layoutTextWithConstraints(this.constraints);
352+
Offset offset = this.globalToLocal(evt.position);
353+
TextPosition position = this._textPainter.getPositionForOffset(offset);
354+
TextSpan span = this._textPainter.text.getSpanForPosition(position);
355+
356+
if (this._previousHoverSpan != span) {
357+
this._previousHoverSpan?.hoverRecognizer?.OnPointerLeave?.Invoke();
358+
span?.hoverRecognizer?.OnPointerEnter?.Invoke((PointerHoverEvent) evt);
359+
this._previousHoverSpan = span;
360+
}
361+
}
362+
}
363+
319364
public override void handleEvent(PointerEvent evt, HitTestEntry entry) {
320365
D.assert(this.debugHandleEvent(evt, entry));
321-
if (!(evt is PointerDownEvent)) {
366+
if (evt is PointerDownEvent) {
367+
this._layoutTextWithConstraints(this.constraints);
368+
Offset offset = ((BoxHitTestEntry) entry).localPosition;
369+
TextPosition position = this._textPainter.getPositionForOffset(offset);
370+
TextSpan span = this._textPainter.text.getSpanForPosition(position);
371+
span?.recognizer?.addPointer((PointerDownEvent) evt);
322372
return;
323373
}
324374

325-
this._layoutTextWithConstraints(this.constraints);
326-
Offset offset = ((BoxHitTestEntry) entry).localPosition;
327-
TextPosition position = this._textPainter.getPositionForOffset(offset);
328-
TextSpan span = this._textPainter.text.getSpanForPosition(position);
329-
span?.recognizer?.addPointer((PointerDownEvent) evt);
375+
this._handlePointerHover(evt);
330376
}
331377

332378
protected override void performLayout() {
@@ -375,6 +421,7 @@ void _paintSelection(Canvas canvas, Offset effectiveOffset) {
375421
foreach (var box in this._selectionRects) {
376422
barPath.addRect(box.toRect().shift(effectiveOffset));
377423
}
424+
378425
canvas.drawPath(barPath, paint);
379426
}
380427

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
using System.Collections.Generic;
2+
using Unity.UIWidgets.gestures;
3+
using Unity.UIWidgets.material;
4+
using Unity.UIWidgets.painting;
5+
using Unity.UIWidgets.rendering;
6+
using Unity.UIWidgets.ui;
7+
using Unity.UIWidgets.widgets;
8+
using UnityEngine;
9+
10+
namespace UIWidgetsSample {
11+
public class HoverRecognizerSample : UIWidgetsSamplePanel {
12+
protected override Widget createWidget() {
13+
return new MaterialApp(
14+
showPerformanceOverlay: false,
15+
home: new HoverMainPanel()
16+
);
17+
}
18+
19+
protected override void OnEnable() {
20+
FontManager.instance.addFont(Resources.Load<Font>(path: "MaterialIcons-Regular"), "Material Icons");
21+
base.OnEnable();
22+
}
23+
}
24+
25+
class HoverMainPanel : StatefulWidget {
26+
public override State createState() {
27+
return new HoverMainPanelState();
28+
}
29+
}
30+
31+
class HoverMainPanelState : State<HoverMainPanel> {
32+
bool hoverActivated = false;
33+
34+
public override Widget build(BuildContext context) {
35+
return new Scaffold(
36+
appBar: new AppBar(
37+
title: new Center(
38+
child: new Text("Test Hover Widget")
39+
)
40+
),
41+
body: new Card(
42+
color: Colors.white,
43+
child: new Center(
44+
child: new Column(
45+
mainAxisSize: MainAxisSize.min,
46+
crossAxisAlignment: CrossAxisAlignment.center,
47+
children: new List<Widget> {
48+
new Icon(this.hoverActivated ? Unity.UIWidgets.material.Icons.pool : Unity.UIWidgets.material.Icons.directions_walk, size: 128.0f),
49+
new RichText(
50+
text: new TextSpan(
51+
text: "Test <",
52+
style: new TextStyle(color: Colors.black),
53+
children: new List<TextSpan>() {
54+
new TextSpan(
55+
text: "Hover Me",
56+
style: new TextStyle(
57+
color: Colors.green,
58+
decoration: TextDecoration.underline
59+
),
60+
hoverRecognizer: new HoverRecognizer {
61+
OnPointerEnter = evt => {
62+
this.setState(() => { this.hoverActivated = true; });
63+
},
64+
OnPointerLeave = () => {
65+
this.setState(() => { this.hoverActivated = false;});
66+
}
67+
}
68+
),
69+
new TextSpan(
70+
text: ">"
71+
)
72+
}
73+
)
74+
)
75+
}
76+
)
77+
)
78+
)
79+
);
80+
}
81+
}
82+
}

Samples/UIWidgetSample/HoverRecognizerSample.cs.meta

Lines changed: 11 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Samples/UIWidgetSample/txt/TextSpanGesture.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public override Widget build(BuildContext context) {
5656
color: Colors.green,
5757
decoration: TextDecoration.underline
5858
)
59-
// recognizer: this._longPressRecognizer
59+
//recognizer: this._longPressRecognizer
6060
),
6161
new TextSpan(
6262
text: " secret?"

0 commit comments

Comments
 (0)