3030import java .lang .reflect .InvocationTargetException ;
3131import java .lang .reflect .Method ;
3232import java .util .ArrayList ;
33+ import java .util .IdentityHashMap ;
3334import java .util .List ;
3435import java .util .function .IntFunction ;
3536import javafx .collections .ObservableList ;
@@ -109,6 +110,9 @@ private class ParagraphGraphic
109110 {
110111 private final int paragraphIndex ;
111112 private final Node gutter ;
113+ private final IdentityHashMap <OverlayFactory , List <Node >> overlayNodesMap
114+ = new IdentityHashMap <>(overlayFactories .size ());
115+ private Node paragraphTextNode ;
112116
113117 ParagraphGraphic (int paragraphIndex ) {
114118 this .paragraphIndex = paragraphIndex ;
@@ -128,9 +132,17 @@ private class ParagraphGraphic
128132 } else
129133 gutter = null ;
130134
131- // make this node is the first child so that its nodes are rendered
132- // 'under' the paragraph text
133135 parentProperty ().addListener ((observable , oldParent , newParent ) -> {
136+ // this node also "need layout" if parent "needs layout"
137+ if (newParent != null ) {
138+ newParent .needsLayoutProperty ().addListener ((ob , o , n ) -> {
139+ if (n )
140+ setNeedsLayout (true );
141+ });
142+ }
143+
144+ // make this node is the first child so that its nodes are rendered
145+ // 'under' the paragraph text
134146 if (newParent != null && newParent .getChildrenUnmodifiable ().get (0 ) != this ) {
135147 @ SuppressWarnings ("unchecked" )
136148 ObservableList <Node > children = (ObservableList <Node >) invoke (mGetChildren , newParent );
@@ -152,44 +164,42 @@ protected double computePrefHeight(double width) {
152164
153165 @ Override
154166 protected void layoutChildren () {
155- update ();
156- }
157-
158- private void update () {
159- getChildren (). clear ();
167+ // layout gutter
168+ if ( gutter != null ) {
169+ double gutterWidth = gutter . prefWidth (- 1 );
170+ layoutInArea ( gutter , 0 , 0 , gutterWidth , getHeight (), - 1 , null , true , true , HPos . LEFT , VPos . TOP );
171+ }
160172
161- if (getParent () == null )
162- return ;
173+ // create overlay nodes
174+ if (overlayNodesMap .isEmpty () && !overlayFactories .isEmpty ())
175+ createOverlayNodes ();
163176
164- Node paragraphTextNode = getParent ().lookup (".paragraph-text" );
165- Insets insets = ((Region )paragraphTextNode ).getInsets ();
166- double leftInsets = insets .getLeft ();
167- double topInsets = insets .getTop ();
177+ // layout overlay nodes
178+ layoutOverlayNodes ();
179+ }
168180
169- if (gutter != null ) {
170- double prefGutterWidth = gutter .prefWidth (-1 );
171- layoutInArea (gutter , 0 , 0 , prefGutterWidth , getHeight (), -1 , null , true , true , HPos .LEFT , VPos .TOP );
172- getChildren ().add (gutter );
181+ private void createOverlayNodes () {
173182
174- leftInsets += prefGutterWidth ;
175- }
183+ paragraphTextNode = getParent ().lookup (".paragraph-text" );
176184
177185 for (OverlayFactory overlayFactory : overlayFactories ) {
178- overlayFactory .init (textArea , paragraphTextNode );
179- Node [] nodes = overlayFactory .createOverlayNodes (paragraphIndex );
180- if (nodes == null )
181- continue ;
186+ overlayFactory .init (textArea , paragraphTextNode , gutter );
187+ List <Node > nodes = overlayFactory .createOverlayNodes (paragraphIndex );
188+ overlayNodesMap .put (overlayFactory , nodes );
182189
183- for (Node node : nodes ) {
190+ for (Node node : nodes )
184191 node .setManaged (false );
185- if (leftInsets != 0 )
186- node .setLayoutX (node .getLayoutX () + leftInsets );
187- if (topInsets != 0 )
188- node .setLayoutY (node .getLayoutY () + topInsets );
189- }
192+
190193 getChildren ().addAll (nodes );
191194 }
192195 }
196+
197+ private void layoutOverlayNodes () {
198+ for (OverlayFactory overlayFactory : overlayFactories ) {
199+ overlayFactory .init (textArea , paragraphTextNode , gutter );
200+ overlayFactory .layoutOverlayNodes (paragraphIndex , overlayNodesMap .get (overlayFactory ));
201+ }
202+ }
193203 }
194204
195205 //---- class OverlayFactory -----------------------------------------------
@@ -198,13 +208,18 @@ static abstract class OverlayFactory
198208 {
199209 private StyleClassedTextArea textArea ;
200210 private Node paragraphTextNode ;
211+ private Node gutter ;
212+ private double gutterWidth ;
201213
202- private void init (StyleClassedTextArea textArea , Node paragraphTextNode ) {
214+ private void init (StyleClassedTextArea textArea , Node paragraphTextNode , Node gutter ) {
203215 this .textArea = textArea ;
204216 this .paragraphTextNode = paragraphTextNode ;
217+ this .gutter = gutter ;
218+ this .gutterWidth = -1 ;
205219 }
206220
207- abstract Node [] createOverlayNodes (int paragraphIndex );
221+ abstract List <Node > createOverlayNodes (int paragraphIndex );
222+ abstract void layoutOverlayNodes (int paragraphIndex , List <Node > nodes );
208223
209224 protected StyleClassedTextArea getTextArea () {
210225 return textArea ;
@@ -234,6 +249,16 @@ protected Rectangle2D getBounds(int start, int end) {
234249 }
235250 return new Rectangle2D (minX , minY , maxX - minX , maxY - minY );
236251 }
252+
253+ protected Insets getInsets () {
254+ Insets insets = ((Region )paragraphTextNode ).getInsets ();
255+ if (gutter != null ) {
256+ if (gutterWidth < 0 )
257+ gutterWidth = gutter .prefWidth (-1 );
258+ insets = new Insets (insets .getTop (), insets .getRight (), insets .getBottom (), gutterWidth + insets .getLeft ());
259+ }
260+ return insets ;
261+ }
237262 }
238263
239264 //---- reflection utilities -----------------------------------------------
0 commit comments