217 * Returns shape for the range of the text in local coordinates.
218 *
219 * @param start the beginning character index for the range
220 * @param start the end character index (non-inclusive) for the range
221 * @return an array of {@code PathElement} which can be used to create a {@code Shape}
222 * @since 9
223 */
224 public final PathElement[] rangeShape(int start, int end) {
225 return getRange(start, end, TextLayout.TYPE_TEXT);
226 }
227
228 @Override
229 public boolean usesMirroring() {
230 return false;
231 }
232
233 @Override protected void setWidth(double value) {
234 if (value != getWidth()) {
235 TextLayout layout = getTextLayout();
236 Insets insets = getInsets();
237 double left = snapSpace(insets.getLeft());
238 double right = snapSpace(insets.getRight());
239 double width = Math.max(1, value - left - right);
240 layout.setWrapWidth((float)width);
241 super.setWidth(value);
242 }
243 }
244
245 @Override protected double computePrefWidth(double height) {
246 TextLayout layout = getTextLayout();
247 layout.setWrapWidth(0);
248 double width = layout.getBounds().getWidth();
249 Insets insets = getInsets();
250 double left = snapSpace(insets.getLeft());
251 double right = snapSpace(insets.getRight());
252 double wrappingWidth = Math.max(1, getWidth() - left - right);
253 layout.setWrapWidth((float)wrappingWidth);
254 return left + width + right;
255 }
256
257 @Override protected double computePrefHeight(double width) {
258 TextLayout layout = getTextLayout();
259 Insets insets = getInsets();
260 double left = snapSpace(insets.getLeft());
261 double right = snapSpace(insets.getRight());
262 if (width == USE_COMPUTED_SIZE) {
263 layout.setWrapWidth(0);
264 } else {
265 double wrappingWidth = Math.max(1, width - left - right);
266 layout.setWrapWidth((float)wrappingWidth);
267 }
268 double height = layout.getBounds().getHeight();
269 double wrappingWidth = Math.max(1, getWidth() - left - right);
270 layout.setWrapWidth((float)wrappingWidth);
271 double top = snapSpace(insets.getTop());
272 double bottom = snapSpace(insets.getBottom());
273 return top + height + bottom;
274 }
275
276 @Override protected double computeMinHeight(double width) {
277 return computePrefHeight(width);
278 }
279
280 @Override public void requestLayout() {
281 /* The geometry of text nodes can be changed during layout children.
282 * For that reason it has to call impl_geomChanged() causing
283 * requestLayout() to happen during layoutChildren().
284 * The inLayout flag prevents this call to cause any extra work.
285 */
286 if (inLayout) return;
287
288 /*
289 * There is no need to reset the text layout's content every time
290 * requestLayout() is called. For example, the content needs
291 * to be set when:
292 * children add or removed
296 * The content does not need to set when:
297 * the width/height changes in the region
298 * the insets changes in the region
299 *
300 * Unfortunately, it is not possible to know what change invoked request
301 * layout. The solution is to always reset the content in the text
302 * layout and rely on it to preserve itself if the new content equals to
303 * the old one. The cost to generate the new content is not avoid.
304 */
305 needsContent = true;
306 super.requestLayout();
307 }
308
309 @Override public Orientation getContentBias() {
310 return Orientation.HORIZONTAL;
311 }
312
313 @Override protected void layoutChildren() {
314 inLayout = true;
315 Insets insets = getInsets();
316 double top = snapSpace(insets.getTop());
317 double left = snapSpace(insets.getLeft());
318
319 GlyphList[] runs = getTextLayout().getRuns();
320 for (int j = 0; j < runs.length; j++) {
321 GlyphList run = runs[j];
322 TextSpan span = run.getTextSpan();
323 if (span instanceof EmbeddedSpan) {
324 Node child = ((EmbeddedSpan)span).getNode();
325 Point2D location = run.getLocation();
326 double baselineOffset = -run.getLineBounds().getMinY();
327
328 layoutInArea(child, left + location.x, top + location.y,
329 run.getWidth(), run.getHeight(),
330 baselineOffset, null, true, true,
331 HPos.CENTER, VPos.BASELINE);
332 }
333 }
334
335 List<Node> managed = getManagedChildren();
336 for (Node node: managed) {
337 if (node instanceof Text) {
466 lineSpacing =
467 new StyleableDoubleProperty(0) {
468 @Override public Object getBean() { return TextFlow.this; }
469 @Override public String getName() { return "lineSpacing"; }
470 @Override public CssMetaData<TextFlow, Number> getCssMetaData() {
471 return StyleableProperties.LINE_SPACING;
472 }
473 @Override public void invalidated() {
474 TextLayout layout = getTextLayout();
475 if (layout.setLineSpacing((float)get())) {
476 requestLayout();
477 }
478 }
479 };
480 }
481 return lineSpacing;
482 }
483
484 @Override public final double getBaselineOffset() {
485 Insets insets = getInsets();
486 double top = snapSpace(insets.getTop());
487 return top - getTextLayout().getBounds().getMinY();
488 }
489
490 /***************************************************************************
491 * *
492 * Stylesheet Handling *
493 * *
494 **************************************************************************/
495
496 /**
497 * Super-lazy instantiation pattern from Bill Pugh.
498 * @treatAsPrivate implementation detail
499 */
500 private static class StyleableProperties {
501
502 private static final
503 CssMetaData<TextFlow, TextAlignment> TEXT_ALIGNMENT =
504 new CssMetaData<TextFlow,TextAlignment>("-fx-text-alignment",
505 new EnumConverter<TextAlignment>(TextAlignment.class),
506 TextAlignment.LEFT) {
557 }
558
559 static double boundedSize(double min, double pref, double max) {
560 double a = pref >= min ? pref : min;
561 double b = min >= max ? min : max;
562 return a <= b ? a : b;
563 }
564
565 double computeChildPrefAreaWidth(Node child, Insets margin) {
566 return computeChildPrefAreaWidth(child, margin, -1);
567 }
568
569 double computeChildPrefAreaWidth(Node child, Insets margin, double height) {
570 final boolean snap = isSnapToPixel();
571 double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
572 double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
573 double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
574 double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
575 double alt = -1;
576 if (child.getContentBias() == Orientation.VERTICAL) { // width depends on height
577 alt = snapSize(boundedSize(
578 child.minHeight(-1), height != -1? height - top - bottom :
579 child.prefHeight(-1), child.maxHeight(-1)));
580 }
581 return left + snapSize(boundedSize(child.minWidth(alt), child.prefWidth(alt), child.maxWidth(alt))) + right;
582 }
583
584 double computeChildPrefAreaHeight(Node child, Insets margin) {
585 return computeChildPrefAreaHeight(child, margin, -1);
586 }
587
588 double computeChildPrefAreaHeight(Node child, Insets margin, double width) {
589 final boolean snap = isSnapToPixel();
590 double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
591 double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
592 double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
593 double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
594 double alt = -1;
595 if (child.getContentBias() == Orientation.HORIZONTAL) { // height depends on width
596 alt = snapSize(boundedSize(
597 child.minWidth(-1), width != -1? width - left - right :
598 child.prefWidth(-1), child.maxWidth(-1)));
599 }
600 return top + snapSize(boundedSize(child.minHeight(alt), child.prefHeight(alt), child.maxHeight(alt))) + bottom;
601 }
602 /* end of copied code */
603
604 @Override
605 public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
606 switch (attribute) {
607 case TEXT: {
608 String accText = getAccessibleText();
609 if (accText != null && !accText.isEmpty()) return accText;
610
611 StringBuilder title = new StringBuilder();
612 for (Node node: getChildren()) {
613 Object text = node.queryAccessibleAttribute(AccessibleAttribute.TEXT, parameters);
614 if (text != null) {
615 title.append(text.toString());
616 }
617 }
618 return title.toString();
619 }
620 default: return super.queryAccessibleAttribute(attribute, parameters);
|
217 * Returns shape for the range of the text in local coordinates.
218 *
219 * @param start the beginning character index for the range
220 * @param start the end character index (non-inclusive) for the range
221 * @return an array of {@code PathElement} which can be used to create a {@code Shape}
222 * @since 9
223 */
224 public final PathElement[] rangeShape(int start, int end) {
225 return getRange(start, end, TextLayout.TYPE_TEXT);
226 }
227
228 @Override
229 public boolean usesMirroring() {
230 return false;
231 }
232
233 @Override protected void setWidth(double value) {
234 if (value != getWidth()) {
235 TextLayout layout = getTextLayout();
236 Insets insets = getInsets();
237 double left = snapSpaceX(insets.getLeft());
238 double right = snapSpaceX(insets.getRight());
239 double width = Math.max(1, value - left - right);
240 layout.setWrapWidth((float)width);
241 super.setWidth(value);
242 }
243 }
244
245 @Override protected double computePrefWidth(double height) {
246 TextLayout layout = getTextLayout();
247 layout.setWrapWidth(0);
248 double width = layout.getBounds().getWidth();
249 Insets insets = getInsets();
250 double left = snapSpaceX(insets.getLeft());
251 double right = snapSpaceX(insets.getRight());
252 double wrappingWidth = Math.max(1, getWidth() - left - right);
253 layout.setWrapWidth((float)wrappingWidth);
254 return left + width + right;
255 }
256
257 @Override protected double computePrefHeight(double width) {
258 TextLayout layout = getTextLayout();
259 Insets insets = getInsets();
260 double left = snapSpaceX(insets.getLeft());
261 double right = snapSpaceX(insets.getRight());
262 if (width == USE_COMPUTED_SIZE) {
263 layout.setWrapWidth(0);
264 } else {
265 double wrappingWidth = Math.max(1, width - left - right);
266 layout.setWrapWidth((float)wrappingWidth);
267 }
268 double height = layout.getBounds().getHeight();
269 double wrappingWidth = Math.max(1, getWidth() - left - right);
270 layout.setWrapWidth((float)wrappingWidth);
271 double top = snapSpaceY(insets.getTop());
272 double bottom = snapSpaceY(insets.getBottom());
273 return top + height + bottom;
274 }
275
276 @Override protected double computeMinHeight(double width) {
277 return computePrefHeight(width);
278 }
279
280 @Override public void requestLayout() {
281 /* The geometry of text nodes can be changed during layout children.
282 * For that reason it has to call impl_geomChanged() causing
283 * requestLayout() to happen during layoutChildren().
284 * The inLayout flag prevents this call to cause any extra work.
285 */
286 if (inLayout) return;
287
288 /*
289 * There is no need to reset the text layout's content every time
290 * requestLayout() is called. For example, the content needs
291 * to be set when:
292 * children add or removed
296 * The content does not need to set when:
297 * the width/height changes in the region
298 * the insets changes in the region
299 *
300 * Unfortunately, it is not possible to know what change invoked request
301 * layout. The solution is to always reset the content in the text
302 * layout and rely on it to preserve itself if the new content equals to
303 * the old one. The cost to generate the new content is not avoid.
304 */
305 needsContent = true;
306 super.requestLayout();
307 }
308
309 @Override public Orientation getContentBias() {
310 return Orientation.HORIZONTAL;
311 }
312
313 @Override protected void layoutChildren() {
314 inLayout = true;
315 Insets insets = getInsets();
316 double top = snapSpaceY(insets.getTop());
317 double left = snapSpaceX(insets.getLeft());
318
319 GlyphList[] runs = getTextLayout().getRuns();
320 for (int j = 0; j < runs.length; j++) {
321 GlyphList run = runs[j];
322 TextSpan span = run.getTextSpan();
323 if (span instanceof EmbeddedSpan) {
324 Node child = ((EmbeddedSpan)span).getNode();
325 Point2D location = run.getLocation();
326 double baselineOffset = -run.getLineBounds().getMinY();
327
328 layoutInArea(child, left + location.x, top + location.y,
329 run.getWidth(), run.getHeight(),
330 baselineOffset, null, true, true,
331 HPos.CENTER, VPos.BASELINE);
332 }
333 }
334
335 List<Node> managed = getManagedChildren();
336 for (Node node: managed) {
337 if (node instanceof Text) {
466 lineSpacing =
467 new StyleableDoubleProperty(0) {
468 @Override public Object getBean() { return TextFlow.this; }
469 @Override public String getName() { return "lineSpacing"; }
470 @Override public CssMetaData<TextFlow, Number> getCssMetaData() {
471 return StyleableProperties.LINE_SPACING;
472 }
473 @Override public void invalidated() {
474 TextLayout layout = getTextLayout();
475 if (layout.setLineSpacing((float)get())) {
476 requestLayout();
477 }
478 }
479 };
480 }
481 return lineSpacing;
482 }
483
484 @Override public final double getBaselineOffset() {
485 Insets insets = getInsets();
486 double top = snapSpaceY(insets.getTop());
487 return top - getTextLayout().getBounds().getMinY();
488 }
489
490 /***************************************************************************
491 * *
492 * Stylesheet Handling *
493 * *
494 **************************************************************************/
495
496 /**
497 * Super-lazy instantiation pattern from Bill Pugh.
498 * @treatAsPrivate implementation detail
499 */
500 private static class StyleableProperties {
501
502 private static final
503 CssMetaData<TextFlow, TextAlignment> TEXT_ALIGNMENT =
504 new CssMetaData<TextFlow,TextAlignment>("-fx-text-alignment",
505 new EnumConverter<TextAlignment>(TextAlignment.class),
506 TextAlignment.LEFT) {
557 }
558
559 static double boundedSize(double min, double pref, double max) {
560 double a = pref >= min ? pref : min;
561 double b = min >= max ? min : max;
562 return a <= b ? a : b;
563 }
564
565 double computeChildPrefAreaWidth(Node child, Insets margin) {
566 return computeChildPrefAreaWidth(child, margin, -1);
567 }
568
569 double computeChildPrefAreaWidth(Node child, Insets margin, double height) {
570 final boolean snap = isSnapToPixel();
571 double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
572 double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
573 double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
574 double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
575 double alt = -1;
576 if (child.getContentBias() == Orientation.VERTICAL) { // width depends on height
577 alt = snapSizeY(boundedSize(
578 child.minHeight(-1), height != -1? height - top - bottom :
579 child.prefHeight(-1), child.maxHeight(-1)));
580 }
581 return left + snapSizeX(boundedSize(child.minWidth(alt), child.prefWidth(alt), child.maxWidth(alt))) + right;
582 }
583
584 double computeChildPrefAreaHeight(Node child, Insets margin) {
585 return computeChildPrefAreaHeight(child, margin, -1);
586 }
587
588 double computeChildPrefAreaHeight(Node child, Insets margin, double width) {
589 final boolean snap = isSnapToPixel();
590 double top = margin != null? snapSpace(margin.getTop(), snap) : 0;
591 double bottom = margin != null? snapSpace(margin.getBottom(), snap) : 0;
592 double left = margin != null? snapSpace(margin.getLeft(), snap) : 0;
593 double right = margin != null? snapSpace(margin.getRight(), snap) : 0;
594 double alt = -1;
595 if (child.getContentBias() == Orientation.HORIZONTAL) { // height depends on width
596 alt = snapSizeX(boundedSize(
597 child.minWidth(-1), width != -1? width - left - right :
598 child.prefWidth(-1), child.maxWidth(-1)));
599 }
600 return top + snapSizeY(boundedSize(child.minHeight(alt), child.prefHeight(alt), child.maxHeight(alt))) + bottom;
601 }
602 /* end of copied code */
603
604 @Override
605 public Object queryAccessibleAttribute(AccessibleAttribute attribute, Object... parameters) {
606 switch (attribute) {
607 case TEXT: {
608 String accText = getAccessibleText();
609 if (accText != null && !accText.isEmpty()) return accText;
610
611 StringBuilder title = new StringBuilder();
612 for (Node node: getChildren()) {
613 Object text = node.queryAccessibleAttribute(AccessibleAttribute.TEXT, parameters);
614 if (text != null) {
615 title.append(text.toString());
616 }
617 }
618 return title.toString();
619 }
620 default: return super.queryAccessibleAttribute(attribute, parameters);
|