@@ -95,14 +95,18 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
95
95
Val <Double > leftInset = Val .map (insetsProperty (), Insets ::getLeft );
96
96
Val <Double > topInset = Val .map (insetsProperty (), Insets ::getTop );
97
97
98
- ChangeListener <IndexRange > selectionRangeListener = (obs , ov , nv ) -> requestLayout ();
98
+ ChangeListener <IndexRange > selectionRangeListener = (obs , prevRange , nv ) -> {
99
+ resetTextSelection (prevRange );
100
+ requestLayout ();
101
+ };
99
102
selectionPathListener = change -> {
100
103
if (change .wasRemoved ()) {
101
104
SelectionPath p = change .getValueRemoved ();
102
105
p .rangeProperty ().removeListener (selectionRangeListener );
103
106
p .layoutXProperty ().unbind ();
104
107
p .layoutYProperty ().unbind ();
105
108
109
+ resetTextSelection (p .rangeProperty ().getValue ());
106
110
getChildren ().remove (p );
107
111
}
108
112
if (change .wasAdded ()) {
@@ -139,22 +143,15 @@ public ObjectProperty<Paint> highlightTextFillProperty() {
139
143
};
140
144
carets .addListener ( caretNodeListener );
141
145
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
- // });
146
+ highlightTextFill .addListener ((ob ,oldFill ,newFill ) -> getChildren ().stream ()
147
+ .filter ( n -> n instanceof TextExt ).map ( n -> (TextExt ) n )
148
+ .forEach ( t -> t .selectionFillProperty ().set (newFill ) )
149
+ );
151
150
152
151
// populate with text nodes
153
152
par .getStyledSegments ().stream ().map (nodeFactory ).forEach (n -> {
154
153
if (n instanceof TextExt ) {
155
154
TextExt t = (TextExt ) n ;
156
- // XXX: binding selectionFill to textFill,
157
- // see the note at highlightTextFill
158
155
t .selectionFillProperty ().bind (highlightTextFill );
159
156
}
160
157
getChildren ().add (n );
@@ -231,7 +228,7 @@ void dispose() {
231
228
carets .removeListener ( caretNodeListener );
232
229
233
230
getChildren ().stream ().filter ( n -> n instanceof TextExt ).map ( n -> (TextExt ) n )
234
- .forEach ( t -> t .selectionFillProperty ().unbind () );
231
+ .forEach ( t -> t .selectionFillProperty ().unbind () );
235
232
236
233
try { getChildren ().clear (); }
237
234
catch ( Exception EX ) {}
@@ -336,6 +333,7 @@ private void updateAllSelectionShapes() {
336
333
337
334
private void updateSingleSelection (SelectionPath path ) {
338
335
path .getElements ().setAll (getRangeShapeSafely (path .rangeProperty ().getValue ()));
336
+ updateTextSelection (path );
339
337
}
340
338
341
339
private PathElement [] getRangeShapeSafely (IndexRange range ) {
@@ -435,32 +433,75 @@ private PathElement[] createRectangle(double topLeftX, double topLeftY, double b
435
433
};
436
434
}
437
435
436
+
438
437
// XXX: Because of JDK bug https://bugs.openjdk.java.net/browse/JDK-8149134
439
438
// this does not work correctly if a paragraph contains more than one segment
440
439
// and the selection is (also) in the second or later segments.
441
440
// 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 ();
441
+ private void updateTextSelection (SelectionPath selection )
442
+ {
443
+ IndexRange range = selection .rangeProperty ().getValue ();
444
+ if (range .getLength () == 0 ) return ;
445
+
446
+ final int selStart = range .getStart ();
447
+ final int selEnd = range .getEnd ();
448
+ int charSoFar = 0 ;
449
+
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());
445
461
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 ();
462
+ if (selStart <= charSoFar ) text .setSelectionStart (0 );
463
+ else text .setSelectionStart (selStart -charSoFar );
451
464
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 ;
465
+ if (selEnd > end ) text .setSelectionEnd (len );
466
+ else
467
+ {
468
+ text .setSelectionEnd (selEnd -charSoFar );
469
+ break ;
470
+ }
471
+ }
472
+ charSoFar = end ;
459
473
}
460
- text .setImpl_selectionStart (textSelStart );
461
- text .setImpl_selectionEnd (textSelEnd );
474
+ else if (node .isManaged ()) // custom user nodes
475
+ {
476
+ charSoFar ++;
477
+ }
478
+ }
479
+ }
462
480
463
- start = end ;
481
+ private void resetTextSelection (IndexRange range )
482
+ {
483
+ final int selStart = range .getStart ();
484
+ final int selEnd = range .getEnd ();
485
+ int charSoFar = 0 ;
486
+
487
+ for (Node node : getChildren ())
488
+ {
489
+ if (node instanceof TextExt )
490
+ {
491
+ TextExt text = (TextExt ) node ;
492
+ charSoFar += text .getText ().length ();
493
+
494
+ if (charSoFar >= selStart )
495
+ {
496
+ text .setSelectionStart (-1 );
497
+ text .setSelectionEnd (-1 );
498
+ if (charSoFar >= selEnd ) break ;
499
+ }
500
+ }
501
+ else if (node .isManaged ()) // custom user nodes
502
+ {
503
+ charSoFar ++;
504
+ }
464
505
}
465
506
}
466
507
@@ -511,9 +552,8 @@ public String toString() {
511
552
@ Override
512
553
protected void layoutChildren () {
513
554
super .layoutChildren ();
514
- updateCaretShape ();
515
- updateSelectionShape ();
516
- updateTextSelection ();
555
+ updateAllCaretShapes ();
556
+ updateAllSelectionShapes ();
517
557
updateBackgroundShapes ();
518
558
}
519
559
@@ -543,7 +583,7 @@ private void updateSharedShapeRange(T value, int start, int end, BiFunction<T, T
543
583
Runnable addNewValueRange = () -> ranges .add (Tuples .t (value , new IndexRange (start , end )));
544
584
545
585
if (ranges .isEmpty ()) {
546
- addNewValueRange .run ();;
586
+ addNewValueRange .run ();
547
587
} else {
548
588
int lastIndex = ranges .size () - 1 ;
549
589
Tuple2 <T , IndexRange > lastShapeValueRange = ranges .get (lastIndex );
0 commit comments