浏览代码

Merge pull request #76 from memspace/cursor-color

Allow customizing cursor color
Anatoly Pulyaevskiy 6 年前
父节点
当前提交
aa422567fa
没有帐户链接到提交者的电子邮件

+ 2
- 1
packages/zefyr/CHANGELOG.md 查看文件

@@ -1,6 +1,7 @@
1
-## Unreleased
1
+## 0.3.1
2 2
 
3 3
 - Fixed autofocus not being triggered when set to `true` for the first time.
4
+- Allow customizing cursor color via ZefyrTheme.
4 5
 
5 6
 ## 0.3.0
6 7
 

+ 1
- 0
packages/zefyr/example/lib/src/full_page.dart 查看文件

@@ -43,6 +43,7 @@ class _FullPageEditorScreenState extends State<FullPageEditorScreen> {
43 43
   @override
44 44
   Widget build(BuildContext context) {
45 45
     final theme = new ZefyrThemeData(
46
+      cursorColor: Colors.blue,
46 47
       toolbarTheme: ZefyrToolbarTheme.fallback(context).copyWith(
47 48
         color: Colors.grey.shade800,
48 49
         toggleColor: Colors.grey.shade900,

+ 14
- 2
packages/zefyr/lib/src/widgets/caret.dart 查看文件

@@ -5,7 +5,8 @@ import 'dart:ui';
5 5
 
6 6
 import 'package:flutter/material.dart';
7 7
 
8
-class CaretPainter {
8
+/// Helper class responsible for cursor layout and painting.
9
+class CursorPainter {
9 10
   static const double _kCaretHeightOffset = 2.0; // pixels
10 11
   static const double _kCaretWidth = 1.0; // pixels
11 12
 
@@ -14,16 +15,27 @@ class CaretPainter {
14 15
         0.0, 0.0, _kCaretWidth, lineHeight - _kCaretHeightOffset);
15 16
   }
16 17
 
18
+  CursorPainter(Color color)
19
+      : assert(color != null),
20
+        _color = color;
21
+
17 22
   Rect _prototype;
18 23
 
19 24
   Rect get prototype => _prototype;
20 25
 
26
+  Color _color;
27
+  Color get color => _color;
28
+  set color(Color value) {
29
+    assert(value != null);
30
+    _color = value;
31
+  }
32
+
21 33
   void layout(double lineHeight) {
22 34
     _prototype = buildPrototype(lineHeight);
23 35
   }
24 36
 
25 37
   void paint(Canvas canvas, Offset offset) {
26
-    final Paint paint = new Paint()..color = Colors.black;
38
+    final Paint paint = new Paint()..color = _color;
27 39
     final Rect caretRect = _prototype.shift(offset);
28 40
     canvas.drawRect(caretRect, paint);
29 41
   }

+ 3
- 0
packages/zefyr/lib/src/widgets/common.dart 查看文件

@@ -65,6 +65,7 @@ class _RawZefyrLineState extends State<RawZefyrLine> {
65 65
         showCursor: editable.showCursor,
66 66
         selection: editable.selection,
67 67
         selectionColor: theme.selectionColor,
68
+        cursorColor: theme.cursorColor,
68 69
       );
69 70
     }
70 71
 
@@ -153,6 +154,7 @@ class _RawZefyrLineState extends State<RawZefyrLine> {
153 154
         showCursor: editable.showCursor,
154 155
         selection: editable.selection,
155 156
         selectionColor: theme.selectionColor,
157
+        cursorColor: theme.cursorColor,
156 158
       );
157 159
     } else if (embed.type == EmbedType.image) {
158 160
       return new EditableBox(
@@ -163,6 +165,7 @@ class _RawZefyrLineState extends State<RawZefyrLine> {
163 165
         showCursor: editable.showCursor,
164 166
         selection: editable.selection,
165 167
         selectionColor: theme.selectionColor,
168
+        cursorColor: theme.cursorColor,
166 169
       );
167 170
     } else {
168 171
       throw new UnimplementedError('Unimplemented embed type ${embed.type}');

+ 21
- 8
packages/zefyr/lib/src/widgets/editable_box.dart 查看文件

@@ -20,6 +20,7 @@ class EditableBox extends SingleChildRenderObjectWidget {
20 20
     @required this.showCursor,
21 21
     @required this.selection,
22 22
     @required this.selectionColor,
23
+    @required this.cursorColor,
23 24
   }) : super(child: child);
24 25
 
25 26
   final ContainerNode node;
@@ -28,6 +29,7 @@ class EditableBox extends SingleChildRenderObjectWidget {
28 29
   final ValueNotifier<bool> showCursor;
29 30
   final TextSelection selection;
30 31
   final Color selectionColor;
32
+  final Color cursorColor;
31 33
 
32 34
   @override
33 35
   RenderEditableProxyBox createRenderObject(BuildContext context) {
@@ -38,6 +40,7 @@ class EditableBox extends SingleChildRenderObjectWidget {
38 40
       showCursor: showCursor,
39 41
       selection: selection,
40 42
       selectionColor: selectionColor,
43
+      cursorColor: cursorColor,
41 44
     );
42 45
   }
43 46
 
@@ -50,7 +53,8 @@ class EditableBox extends SingleChildRenderObjectWidget {
50 53
       ..renderContext = renderContext
51 54
       ..showCursor = showCursor
52 55
       ..selection = selection
53
-      ..selectionColor = selectionColor;
56
+      ..selectionColor = selectionColor
57
+      ..cursorColor = cursorColor;
54 58
   }
55 59
 }
56 60
 
@@ -67,6 +71,7 @@ class RenderEditableProxyBox extends RenderBox
67 71
     @required ValueNotifier<bool> showCursor,
68 72
     @required TextSelection selection,
69 73
     @required Color selectionColor,
74
+    @required Color cursorColor,
70 75
   })  : _node = node,
71 76
         _layerLink = layerLink,
72 77
         _renderContext = renderContext,
@@ -75,6 +80,16 @@ class RenderEditableProxyBox extends RenderBox
75 80
         _selectionColor = selectionColor,
76 81
         super() {
77 82
     this.child = child;
83
+    _cursorPainter = CursorPainter(cursorColor);
84
+  }
85
+
86
+  CursorPainter _cursorPainter;
87
+
88
+  set cursorColor(Color value) {
89
+    if (_cursorPainter.color != value) {
90
+      _cursorPainter.color = value;
91
+      markNeedsPaint();
92
+    }
78 93
   }
79 94
 
80 95
   bool _isDirty = true;
@@ -171,7 +186,7 @@ class RenderEditableProxyBox extends RenderBox
171 186
   @mustCallSuper
172 187
   void performLayout() {
173 188
     super.performLayout();
174
-    _caretPainter.layout(preferredLineHeight);
189
+    _cursorPainter.layout(preferredLineHeight);
175 190
     // Indicate to render context that this object can be used by other
176 191
     // layers (selection overlay, for instance).
177 192
     _isDirty = false;
@@ -196,16 +211,14 @@ class RenderEditableProxyBox extends RenderBox
196 211
       paintSelection(context, offset, selection, selectionColor);
197 212
     }
198 213
     if (isCaretVisible) {
199
-      _paintCaret(context, offset);
214
+      _paintCursor(context, offset);
200 215
     }
201 216
   }
202 217
 
203
-  final CaretPainter _caretPainter = new CaretPainter();
204
-
205
-  void _paintCaret(PaintingContext context, Offset offset) {
218
+  void _paintCursor(PaintingContext context, Offset offset) {
206 219
     Offset caretOffset =
207
-        getOffsetForCaret(_selection.extent, _caretPainter.prototype);
208
-    _caretPainter.paint(context.canvas, caretOffset + offset);
220
+        getOffsetForCaret(_selection.extent, _cursorPainter.prototype);
221
+    _cursorPainter.paint(context.canvas, caretOffset + offset);
209 222
   }
210 223
 
211 224
   @override

+ 1
- 1
packages/zefyr/lib/src/widgets/rich_text.dart 查看文件

@@ -127,7 +127,7 @@ class RenderEditableParagraph extends RenderParagraph
127 127
   List<ui.TextBox> getEndpointsForSelection(TextSelection selection) {
128 128
     TextSelection local = getLocalSelection(selection);
129 129
     if (local.isCollapsed) {
130
-      final caret = CaretPainter.buildPrototype(preferredLineHeight);
130
+      final caret = CursorPainter.buildPrototype(preferredLineHeight);
131 131
       final offset = getOffsetForCaret(local.extent, caret);
132 132
       return [
133 133
         new ui.TextBox.fromLTRBD(

+ 6
- 0
packages/zefyr/lib/src/widgets/theme.dart 查看文件

@@ -60,6 +60,7 @@ class ZefyrThemeData {
60 60
   final HeadingTheme headingTheme;
61 61
   final BlockTheme blockTheme;
62 62
   final Color selectionColor;
63
+  final Color cursorColor;
63 64
 
64 65
   /// Size of indentation for blocks.
65 66
   final double indentSize;
@@ -88,6 +89,7 @@ class ZefyrThemeData {
88 89
       headingTheme: new HeadingTheme.fallback(),
89 90
       blockTheme: new BlockTheme.fallback(),
90 91
       selectionColor: Colors.lightBlueAccent.shade100,
92
+      cursorColor: Colors.black,
91 93
       indentSize: 16.0,
92 94
       toolbarTheme: new ZefyrToolbarTheme.fallback(context),
93 95
     );
@@ -101,6 +103,7 @@ class ZefyrThemeData {
101 103
     this.headingTheme,
102 104
     this.blockTheme,
103 105
     this.selectionColor,
106
+    this.cursorColor,
104 107
     this.indentSize,
105 108
     this.toolbarTheme,
106 109
   });
@@ -114,6 +117,7 @@ class ZefyrThemeData {
114 117
     HeadingTheme headingTheme,
115 118
     BlockTheme blockTheme,
116 119
     Color selectionColor,
120
+    Color cursorColor,
117 121
     double indentSize,
118 122
     ZefyrToolbarTheme toolbarTheme,
119 123
   }) {
@@ -125,6 +129,7 @@ class ZefyrThemeData {
125 129
       headingTheme: headingTheme ?? this.headingTheme,
126 130
       blockTheme: blockTheme ?? this.blockTheme,
127 131
       selectionColor: selectionColor ?? this.selectionColor,
132
+      cursorColor: cursorColor ?? this.cursorColor,
128 133
       indentSize: indentSize ?? this.indentSize,
129 134
       toolbarTheme: toolbarTheme ?? this.toolbarTheme,
130 135
     );
@@ -139,6 +144,7 @@ class ZefyrThemeData {
139 144
       headingTheme: other.headingTheme,
140 145
       blockTheme: other.blockTheme,
141 146
       selectionColor: other.selectionColor,
147
+      cursorColor: other.cursorColor,
142 148
       indentSize: other.indentSize,
143 149
       toolbarTheme: other.toolbarTheme,
144 150
     );

+ 4
- 3
packages/zefyr/test/painting/caret_painter_test.dart 查看文件

@@ -3,18 +3,19 @@
3 3
 // BSD-style license that can be found in the LICENSE file.
4 4
 import 'dart:ui';
5 5
 
6
+import 'package:flutter/material.dart';
6 7
 import 'package:flutter_test/flutter_test.dart';
7 8
 import 'package:zefyr/src/widgets/caret.dart';
8 9
 
9 10
 void main() {
10
-  group('$CaretPainter', () {
11
+  group('$CursorPainter', () {
11 12
     test('prototype is null before layout', () {
12
-      var painter = new CaretPainter();
13
+      var painter = new CursorPainter(Colors.black);
13 14
       expect(painter.prototype, isNull);
14 15
     });
15 16
 
16 17
     test('prototype is set after layout', () {
17
-      var painter = new CaretPainter();
18
+      var painter = new CursorPainter(Colors.black);
18 19
       painter.layout(16.0);
19 20
       expect(painter.prototype, new Rect.fromLTWH(0.0, 0.0, 1.0, 14.0));
20 21
     });

+ 1
- 0
packages/zefyr/test/rendering/render_editable_proxy_box_test.dart 查看文件

@@ -36,6 +36,7 @@ void main() {
36 36
         showCursor: ValueNotifier<bool>(true),
37 37
         selection: TextSelection.collapsed(offset: 0),
38 38
         selectionColor: Color(0),
39
+        cursorColor: Color(0),
39 40
       );
40 41
     });
41 42
 

+ 1
- 0
packages/zefyr/test/widgets/editable_text_scope_test.dart 查看文件

@@ -103,5 +103,6 @@ RenderEditableProxyBox createParagraph(ZefyrRenderContext context) {
103 103
     showCursor: showCursor,
104 104
     selection: selection,
105 105
     selectionColor: selectionColor,
106
+    cursorColor: Color(0),
106 107
   );
107 108
 }

+ 1
- 0
packages/zefyr/test/widgets/render_context_test.dart 查看文件

@@ -85,5 +85,6 @@ RenderEditableProxyBox createParagraph(ZefyrRenderContext viewport) {
85 85
     showCursor: showCursor,
86 86
     selection: selection,
87 87
     selectionColor: selectionColor,
88
+    cursorColor: Color(0),
88 89
   );
89 90
 }