Skip to content

Commit 45b1241

Browse files
committed
Added support for -fx-underline-dash-array and -fx-underline-cap
1 parent f3a54a1 commit 45b1241

3 files changed

Lines changed: 175 additions & 110 deletions

File tree

Lines changed: 0 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,43 +1,6 @@
1-
.keyword {
2-
-fx-fill: purple;
3-
-fx-font-weight: bold;
4-
}
5-
61
.underlined {
72
-fx-underline-color: red;
83
-fx-underline-dash-array: 2 2;
94
-fx-underline-width: 1;
105
-fx-underline-cap: butt;
116
}
12-
13-
.url {
14-
-fx-underline-color: blue;
15-
-fx-underline-width: 0.5;
16-
}
17-
18-
.semicolon {
19-
-fx-font-weight: bold;
20-
}
21-
.paren {
22-
-fx-fill: firebrick;
23-
-fx-font-weight: bold;
24-
}
25-
.bracket {
26-
-fx-fill: darkgreen;
27-
-fx-font-weight: bold;
28-
}
29-
.brace {
30-
-fx-fill: teal;
31-
-fx-font-weight: bold;
32-
}
33-
.string {
34-
-fx-fill: blue;
35-
}
36-
37-
.comment {
38-
-fx-fill: cadetblue;
39-
}
40-
41-
.paragraph-box:has-caret {
42-
-fx-background-color: #f2f9fc;
43-
}

richtextfx/src/main/java/org/fxmisc/richtext/ParagraphText.java

Lines changed: 87 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.fxmisc.richtext;
22

33
import java.util.ArrayList;
4+
import java.util.Arrays;
45
import java.util.List;
56
import java.util.Optional;
67
import java.util.function.BiConsumer;
@@ -17,6 +18,7 @@
1718
import javafx.scene.paint.Paint;
1819
import javafx.scene.shape.Path;
1920
import javafx.scene.shape.PathElement;
21+
import javafx.scene.shape.StrokeLineCap;
2022

2123
import org.reactfx.value.Val;
2224
import org.reactfx.value.Var;
@@ -190,47 +192,101 @@ private void updateBackgroundShapes() {
190192
FilteredList<Node> nodeList = getChildren().filtered(node -> node instanceof TextExt);
191193
for (Node node : nodeList) {
192194
TextExt text = (TextExt) node;
193-
Path backgroundShape = backgroundShapes.get(index);
194195
int end = start + text.getText().length();
195196

196-
// Set fill
197-
Paint paint = text.backgroundFillProperty().get();
198-
if (paint != null) {
199-
backgroundShape.setFill(paint);
197+
updateBackground(text, start, end, index);
198+
updateUnderline(text, start, end, index);
200199

201-
// Set path elements
202-
PathElement[] shape = getRangeShape(start, end);
203-
backgroundShape.getElements().setAll(shape);
204-
}
200+
start = end;
201+
index++;
202+
}
203+
}
204+
205+
206+
/**
207+
* Updates the background shape for a text segment.
208+
*
209+
* @param text The text node which specified the style attributes
210+
* @param start The index of the first character
211+
* @param end The index of the last character
212+
* @param index The index of the background shape
213+
*/
214+
private void updateBackground(TextExt text, int start, int end, int index) {
215+
// Set fill
216+
Paint paint = text.backgroundFillProperty().get();
217+
if (paint != null) {
218+
Path backgroundShape = backgroundShapes.get(index);
219+
backgroundShape.setFill(paint);
220+
221+
// Set path elements
222+
PathElement[] shape = getRangeShape(start, end);
223+
backgroundShape.getElements().setAll(shape);
224+
}
225+
}
205226

206-
// set underline
207-
Path underlineShape = underlineShapes.get(index);
208-
Paint underlineStroke = text.underlineStrokeProperty().get();
209-
Number underlineStrokeWidth = text.underlineStrokeWidthProperty().get();
210-
Number underlineStrokeDashSize = text.underlineStrokeDashSizeProperty().get();
211-
if (underlineStroke != null) {
212-
underlineShape.setStroke(underlineStroke);
213-
}
214-
if (underlineStrokeWidth != null) {
215-
underlineShape.setStrokeWidth(underlineStrokeWidth.doubleValue());
216-
}
217-
if (underlineStrokeDashSize != null) {
218-
double dashSize = underlineStrokeDashSize.doubleValue();
219-
Double[] dashArray = {dashSize, dashSize};
220-
underlineShape.getStrokeDashArray().addAll(dashArray);
221-
}
222227

223-
if (underlineStroke != null || underlineStrokeWidth != null) {
224-
// Set path elements
225-
PathElement[] shape = getUnderlineShape(start, end);
226-
underlineShape.getElements().setAll(shape);
228+
/**
229+
* Updates the shape which renders the text underline.
230+
*
231+
* @param text The text node which specified the style attributes
232+
* @param start The index of the first character
233+
* @param end The index of the last character
234+
* @param index The index of the background shape
235+
*/
236+
private void updateUnderline(TextExt text, int start, int end, int index) {
237+
238+
// get all CSS properties for the underline
239+
240+
Paint underlineColor = text.underlineColorProperty().get();
241+
Number underlineWidth = text.underlineWidthProperty().get();
242+
243+
// get the dash array - JavaFX CSS parser seems to return either a Number[] array
244+
// or a single value, depending on whether only one or more than one value has been
245+
// specified in the CSS
246+
Double[] underlineDashArray = null;
247+
Object underlineDashArrayProp = text.underlineDashArrayProperty().get();
248+
if (underlineDashArrayProp != null) {
249+
if (underlineDashArrayProp.getClass().isArray()) {
250+
Number[] numberArray = (Number[]) underlineDashArrayProp;
251+
underlineDashArray = new Double[numberArray.length];
252+
int idx = 0;
253+
for (Number d : numberArray) {
254+
underlineDashArray[idx++] = (Double) d;
255+
}
256+
} else {
257+
underlineDashArray = new Double[1];
258+
underlineDashArray[0] = ((Double) underlineDashArrayProp).doubleValue();
227259
}
260+
}
228261

229-
start = end;
230-
index++;
262+
StrokeLineCap underlineCap = text.underlineCapProperty().get();
263+
264+
// apply style and render the underline
265+
266+
Path underlineShape = underlineShapes.get(index);
267+
if (underlineColor != null) {
268+
underlineShape.setStroke(underlineColor);
269+
}
270+
if (underlineWidth != null) {
271+
underlineShape.setStrokeWidth(underlineWidth.doubleValue());
272+
}
273+
if (underlineDashArray != null) {
274+
underlineShape.getStrokeDashArray().addAll(underlineDashArray);
275+
underlineShape.setStrokeLineCap(StrokeLineCap.BUTT);
276+
}
277+
if (underlineCap != null) {
278+
underlineShape.setStrokeLineCap(underlineCap);
279+
}
280+
281+
if (underlineColor != null || underlineWidth != null) {
282+
283+
// Set path elements
284+
PathElement[] shape = getUnderlineShape(start, end);
285+
underlineShape.getElements().setAll(shape);
231286
}
232287
}
233288

289+
234290
@Override
235291
protected void layoutChildren() {
236292
super.layoutChildren();

0 commit comments

Comments
 (0)