|
1 | 1 | package org.fxmisc.richtext; |
2 | 2 |
|
3 | 3 | import java.util.ArrayList; |
| 4 | +import java.util.Arrays; |
4 | 5 | import java.util.List; |
5 | 6 | import java.util.Optional; |
6 | 7 | import java.util.function.BiConsumer; |
|
17 | 18 | import javafx.scene.paint.Paint; |
18 | 19 | import javafx.scene.shape.Path; |
19 | 20 | import javafx.scene.shape.PathElement; |
| 21 | +import javafx.scene.shape.StrokeLineCap; |
20 | 22 |
|
21 | 23 | import org.reactfx.value.Val; |
22 | 24 | import org.reactfx.value.Var; |
@@ -190,47 +192,101 @@ private void updateBackgroundShapes() { |
190 | 192 | FilteredList<Node> nodeList = getChildren().filtered(node -> node instanceof TextExt); |
191 | 193 | for (Node node : nodeList) { |
192 | 194 | TextExt text = (TextExt) node; |
193 | | - Path backgroundShape = backgroundShapes.get(index); |
194 | 195 | int end = start + text.getText().length(); |
195 | 196 |
|
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); |
200 | 199 |
|
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 | + } |
205 | 226 |
|
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 | | - } |
222 | 227 |
|
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(); |
227 | 259 | } |
| 260 | + } |
228 | 261 |
|
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); |
231 | 286 | } |
232 | 287 | } |
233 | 288 |
|
| 289 | + |
234 | 290 | @Override |
235 | 291 | protected void layoutChildren() { |
236 | 292 | super.layoutChildren(); |
|
0 commit comments