@@ -104,6 +104,7 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
104
104
p .layoutYProperty ().unbind ();
105
105
106
106
getChildren ().remove (p );
107
+ resetTextSelection (p );
107
108
}
108
109
if (change .wasAdded ()) {
109
110
SelectionPath p = change .getValueAdded ();
@@ -139,22 +140,15 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
139
140
};
140
141
carets .addListener ( caretNodeListener );
141
142
142
- // XXX: see the note at highlightTextFill
143
- // highlightTextFill.addListener(new ChangeListener<Paint>() {
144
- // @Override
145
- // public void changed(ObservableValue<? extends Paint> observable,
146
- // Paint oldFill, Paint newFill) {
147
- // for(PumpedUpText text: textNodes())
148
- // text.selectionFillProperty().set(newFill);
149
- // }
150
- // });
143
+ highlightTextFill .addListener ((ob ,oldFill ,newFill ) -> getChildren ().stream ()
144
+ .filter ( n -> n instanceof TextExt ).map ( n -> (TextExt ) n )
145
+ .forEach ( t -> t .selectionFillProperty ().set (newFill ) )
146
+ );
151
147
152
148
// populate with text nodes
153
149
par .getStyledSegments ().stream ().map (nodeFactory ).forEach (n -> {
154
150
if (n instanceof TextExt ) {
155
151
TextExt t = (TextExt ) n ;
156
- // XXX: binding selectionFill to textFill,
157
- // see the note at highlightTextFill
158
152
t .selectionFillProperty ().bind (highlightTextFill );
159
153
}
160
154
getChildren ().add (n );
@@ -231,7 +225,7 @@ void dispose() {
231
225
carets .removeListener ( caretNodeListener );
232
226
233
227
getChildren ().stream ().filter ( n -> n instanceof TextExt ).map ( n -> (TextExt ) n )
234
- .forEach ( t -> t .selectionFillProperty ().unbind () );
228
+ .forEach ( t -> t .selectionFillProperty ().unbind () );
235
229
236
230
try { getChildren ().clear (); }
237
231
catch ( Exception EX ) {}
@@ -336,6 +330,7 @@ private void updateAllSelectionShapes() {
336
330
337
331
private void updateSingleSelection (SelectionPath path ) {
338
332
path .getElements ().setAll (getRangeShapeSafely (path .rangeProperty ().getValue ()));
333
+ updateTextSelection (path );
339
334
}
340
335
341
336
private PathElement [] getRangeShapeSafely (IndexRange range ) {
@@ -435,32 +430,79 @@ private PathElement[] createRectangle(double topLeftX, double topLeftY, double b
435
430
};
436
431
}
437
432
433
+
438
434
// XXX: Because of JDK bug https://bugs.openjdk.java.net/browse/JDK-8149134
439
435
// this does not work correctly if a paragraph contains more than one segment
440
436
// and the selection is (also) in the second or later segments.
441
437
// Visually the text color of the selection may be mix black & white.
442
- private void updateTextSelection () {
443
- int selStart = selection .get ().getStart ();
444
- int selEnd = selection .get ().getEnd ();
438
+ private void updateTextSelection (SelectionPath selection )
439
+ {
440
+ IndexRange range = selection .rangeProperty ().getValue ();
441
+ if (range .getLength () == 0 ) {
442
+ resetTextSelection (selection );
443
+ return ;
444
+ }
445
445
446
- int start = 0 ;
447
- FilteredList <Node > nodeList = getChildren ().filtered (node -> node instanceof TextExt );
448
- for (Node node : nodeList ) {
449
- TextExt text = (TextExt ) node ;
450
- int end = start + text .getText ().length ();
446
+ int selStart = range .getStart ();
447
+ int selEnd = range .getEnd ();
448
+ int charSoFar = 0 ;
451
449
452
- int textSelStart = Math .max (start , selStart );
453
- int textSelEnd = Math .min (end , selEnd );
454
- if (textSelEnd > textSelStart ) {
455
- textSelStart -= start ;
456
- textSelEnd -= start ;
457
- } else {
458
- textSelStart = textSelEnd = -1 ;
450
+ for (Node node : getChildren ())
451
+ {
452
+ if (node instanceof TextExt )
453
+ {
454
+ TextExt text = (TextExt ) node ;
455
+ int len = text .getText ().length ();
456
+ int end = charSoFar + len ;
457
+
458
+ if (end > selStart )
459
+ {
460
+ // TODO text.setSelectionFill(selection.getTextFill());
461
+
462
+ if (selStart <= charSoFar ) text .setSelectionStart (0 );
463
+ else text .setSelectionStart (selStart -charSoFar );
464
+
465
+ if (selEnd > end ) text .setSelectionEnd (len );
466
+ else
467
+ {
468
+ text .setSelectionEnd (selEnd -charSoFar );
469
+ break ;
470
+ }
471
+ }
472
+ charSoFar = end ;
473
+ }
474
+ else if (node .isManaged ()) // custom user nodes
475
+ {
476
+ charSoFar ++;
459
477
}
460
- text . setImpl_selectionStart ( textSelStart );
461
- text . setImpl_selectionEnd ( textSelEnd );
478
+ }
479
+ }
462
480
463
- start = end ;
481
+ private void resetTextSelection (SelectionPath selection )
482
+ {
483
+ IndexRange range = selection .rangeProperty ().getValue ();
484
+ int selStart = range .getStart ();
485
+ int selEnd = range .getEnd ();
486
+ int charSoFar = 0 ;
487
+
488
+ for (Node node : getChildren ())
489
+ {
490
+ if (node instanceof TextExt )
491
+ {
492
+ TextExt text = (TextExt ) node ;
493
+ charSoFar += text .getText ().length ();
494
+
495
+ if (charSoFar >= selStart )
496
+ {
497
+ text .setSelectionStart (-1 );
498
+ text .setSelectionEnd (-1 );
499
+ if (charSoFar >= selEnd ) break ;
500
+ }
501
+ }
502
+ else if (node .isManaged ()) // custom user nodes
503
+ {
504
+ charSoFar ++;
505
+ }
464
506
}
465
507
}
466
508
@@ -511,9 +553,8 @@ public String toString() {
511
553
@ Override
512
554
protected void layoutChildren () {
513
555
super .layoutChildren ();
514
- updateCaretShape ();
515
- updateSelectionShape ();
516
- updateTextSelection ();
556
+ updateAllCaretShapes ();
557
+ updateAllSelectionShapes ();
517
558
updateBackgroundShapes ();
518
559
}
519
560
@@ -543,7 +584,7 @@ private void updateSharedShapeRange(T value, int start, int end, BiFunction<T, T
543
584
Runnable addNewValueRange = () -> ranges .add (Tuples .t (value , new IndexRange (start , end )));
544
585
545
586
if (ranges .isEmpty ()) {
546
- addNewValueRange .run ();;
587
+ addNewValueRange .run ();
547
588
} else {
548
589
int lastIndex = ranges .size () - 1 ;
549
590
Tuple2 <T , IndexRange > lastShapeValueRange = ranges .get (lastIndex );
0 commit comments