116 * the shape.
117 * @since JavaFX 2.0
118 */
119 public abstract class Shape extends Node {
120
121 static {
122 // This is used by classes in different packages to get access to
123 // private and package private methods.
124 ShapeHelper.setShapeAccessor(new ShapeHelper.ShapeAccessor() {
125 @Override
126 public void doUpdatePeer(Node node) {
127 ((Shape) node).doUpdatePeer();
128 }
129
130 @Override
131 public void doMarkDirty(Node node, DirtyBits dirtyBit) {
132 ((Shape) node).doMarkDirty(dirtyBit);
133 }
134
135 @Override
136 public Paint doCssGetFillInitialValue(Shape shape) {
137 return shape.doCssGetFillInitialValue();
138 }
139
140 @Override
141 public Paint doCssGetStrokeInitialValue(Shape shape) {
142 return shape.doCssGetStrokeInitialValue();
143 }
144
145 @Override
146 public NGShape.Mode getMode(Shape shape) {
147 return shape.getMode();
148 }
149
150 @Override
151 public void setMode(Shape shape, NGShape.Mode mode) {
152 shape.setMode(mode);
153 }
154
155 @Override
374 return NGShape.Mode.EMPTY;
375 }
376 }
377
378 NGShape.Mode getMode() {
379 return mode;
380 }
381
382 void setMode(NGShape.Mode mode) {
383 mode = mode;
384 }
385
386 private NGShape.Mode mode = NGShape.Mode.FILL;
387
388 private void checkModeChanged() {
389 NGShape.Mode newMode = computeMode();
390 if (mode != newMode) {
391 mode = newMode;
392
393 NodeHelper.markDirty(this, DirtyBits.SHAPE_MODE);
394 impl_geomChanged();
395 }
396 }
397
398 /**
399 * Defines parameters to fill the interior of an {@code Shape}
400 * using the settings of the {@code Paint} context.
401 * The default value is {@code Color.BLACK} for all shapes except
402 * Line, Polyline, and Path. The default value is {@code null} for
403 * those shapes.
404 */
405 private ObjectProperty<Paint> fill;
406
407
408 public final void setFill(Paint value) {
409 fillProperty().set(value);
410 }
411
412 public final Paint getFill() {
413 return fill == null ? Color.BLACK : fill.get();
414 }
463 /**
464 * Defines parameters of a stroke that is drawn around the outline of
465 * a {@code Shape} using the settings of the specified {@code Paint}.
466 * The default value is {@code null} for all shapes except
467 * Line, Polyline, and Path. The default value is {@code Color.BLACK} for
468 * those shapes.
469 */
470 private ObjectProperty<Paint> stroke;
471
472
473 public final void setStroke(Paint value) {
474 strokeProperty().set(value);
475 }
476
477 private final AbstractNotifyListener platformImageChangeListener =
478 new AbstractNotifyListener() {
479 @Override
480 public void invalidated(Observable valueModel) {
481 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_FILL);
482 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_STROKE);
483 impl_geomChanged();
484 checkModeChanged();
485 }
486 };
487
488 public final Paint getStroke() {
489 return stroke == null ? null : stroke.get();
490 }
491
492 Paint old_stroke;
493 public final ObjectProperty<Paint> strokeProperty() {
494 if (stroke == null) {
495 stroke = new StyleableObjectProperty<Paint>() {
496
497 boolean needsListener = false;
498
499 @Override public void invalidated() {
500
501 Paint _stroke = get();
502
503 if (needsListener) {
873 * @return The CssMetaData associated with this class, which may include the
874 * CssMetaData of its super classes.
875 * @since JavaFX 8.0
876 */
877 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
878 return StyleableProperties.STYLEABLES;
879 }
880
881 /**
882 * {@inheritDoc}
883 *
884 * @since JavaFX 8.0
885 */
886
887
888 @Override
889 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
890 return getClassCssMetaData();
891 }
892
893 /**
894 * @treatAsPrivate implementation detail
895 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
896 */
897 @Deprecated
898 @Override
899 public BaseBounds impl_computeGeomBounds(BaseBounds bounds,
900 BaseTransform tx) {
901 return computeShapeBounds(bounds, tx, ShapeHelper.configShape(this));
902 }
903
904 /**
905 * @treatAsPrivate implementation detail
906 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
907 */
908 @Deprecated
909 @Override
910 protected boolean impl_computeContains(double localX, double localY) {
911 return computeShapeContains(localX, localY, ShapeHelper.configShape(this));
912 }
913
914 private static final double MIN_STROKE_WIDTH = 0.0f;
915 private static final double MIN_STROKE_MITER_LIMIT = 1.0f;
916
917 private void updatePGShape() {
918 final NGShape peer = NodeHelper.getPeer(this);
919 if (strokeAttributesDirty && (getStroke() != null)) {
920 // set attributes of stroke only when stroke paint is not null
921 final float[] pgDashArray =
922 (hasStrokeDashArray())
923 ? toPGDashArray(getStrokeDashArray())
924 : DEFAULT_PG_STROKE_DASH_ARRAY;
925
926 peer.setDrawStroke(
927 (float)Utils.clampMin(getStrokeWidth(),
928 MIN_STROKE_WIDTH),
929 getStrokeType(),
930 getStrokeLineCap(),
1498 }
1499
1500 public boolean canSetMiterLimit() {
1501 return (miterLimit == null) || !miterLimit.isBound();
1502 }
1503
1504 public boolean canSetDashOffset() {
1505 return (dashOffset == null) || !dashOffset.isBound();
1506 }
1507
1508 public boolean hasDashArray() {
1509 return (dashArray != null);
1510 }
1511
1512 private void invalidated(final CssMetaData<Shape, ?> propertyCssKey) {
1513 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_STROKEATTRS);
1514 strokeAttributesDirty = true;
1515 if (propertyCssKey != StyleableProperties.STROKE_DASH_OFFSET) {
1516 // all stroke attributes change geometry except for the
1517 // stroke dash offset
1518 impl_geomChanged();
1519 }
1520 }
1521 }
1522
1523 /**
1524 * @treatAsPrivate implementation detail
1525 * @deprecated This is an internal API that is not intended for use and will be removed in the next version
1526 */
1527 @Deprecated
1528 @Override
1529 public Object impl_processMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
1530 return alg.processLeafNode(this, ctx);
1531 }
1532
1533 // PENDING_DOC_REVIEW
1534 /**
1535 * Returns a new {@code Shape} which is created as a union of the specified
1536 * input shapes.
1537 * <p>
1538 * The operation works with geometric areas occupied by the input shapes.
1539 * For a single {@code Shape} such area includes the area occupied by the
1540 * fill if the shape has a non-null fill and the area occupied by the stroke
1541 * if the shape has a non-null stroke. So the area is empty for a shape
1542 * with {@code null} stroke and {@code null} fill. The area of an input
1543 * shape considered by the operation is independent on the type and
1544 * configuration of the paint used for fill or stroke. Before the final
1545 * operation the areas of the input shapes are transformed to the parent
1546 * coordinate space of their respective topmost parent nodes.
1547 * <p>
1548 * The resulting shape will include areas that were contained in any of the
1549 * input shapes.
1699 fillShape, strokeType, strokeWidth, strokeLineCap,
1700 strokeLineJoin, strokeMiterLimit,
1701 dashArray, (float) getStrokeDashOffset());
1702
1703 if (mode == NGShape.Mode.STROKE) {
1704 return createTransformedArea(strokeShape, transform);
1705 }
1706
1707 // fill and stroke
1708 final Area combinedArea = new Area(fillShape);
1709 combinedArea.add(new Area(strokeShape));
1710
1711 return createTransformedArea(combinedArea, transform);
1712 }
1713
1714 private static BaseTransform calculateNodeToSceneTransform(Node node) {
1715 final Affine3D cumulativeTransformation = new Affine3D();
1716
1717 do {
1718 cumulativeTransformation.preConcatenate(
1719 node.impl_getLeafTransform());
1720 node = node.getParent();
1721 } while (node != null);
1722
1723 return cumulativeTransformation;
1724 }
1725
1726 private static Area createTransformedArea(
1727 final com.sun.javafx.geom.Shape geomShape,
1728 final BaseTransform transform) {
1729 return transform.isIdentity()
1730 ? new Area(geomShape)
1731 : new Area(geomShape.getPathIterator(transform));
1732 }
1733
1734 private static Path createFromGeomShape(
1735 final com.sun.javafx.geom.Shape geomShape) {
1736 final Path path = new Path();
1737 final ObservableList<PathElement> elements = path.getElements();
1738
1739 final PathIterator iterator = geomShape.getPathIterator(null);
|
116 * the shape.
117 * @since JavaFX 2.0
118 */
119 public abstract class Shape extends Node {
120
121 static {
122 // This is used by classes in different packages to get access to
123 // private and package private methods.
124 ShapeHelper.setShapeAccessor(new ShapeHelper.ShapeAccessor() {
125 @Override
126 public void doUpdatePeer(Node node) {
127 ((Shape) node).doUpdatePeer();
128 }
129
130 @Override
131 public void doMarkDirty(Node node, DirtyBits dirtyBit) {
132 ((Shape) node).doMarkDirty(dirtyBit);
133 }
134
135 @Override
136 public BaseBounds doComputeGeomBounds(Node node,
137 BaseBounds bounds, BaseTransform tx) {
138 return ((Shape) node).doComputeGeomBounds(bounds, tx);
139 }
140
141 @Override
142 public boolean doComputeContains(Node node, double localX, double localY) {
143 return ((Shape) node).doComputeContains(localX, localY);
144 }
145
146 @Override
147 public Object doProcessMXNode(Node node, MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
148 return ((Shape) node).doProcessMXNode(alg, ctx);
149 }
150
151 @Override
152 public Paint doCssGetFillInitialValue(Shape shape) {
153 return shape.doCssGetFillInitialValue();
154 }
155
156 @Override
157 public Paint doCssGetStrokeInitialValue(Shape shape) {
158 return shape.doCssGetStrokeInitialValue();
159 }
160
161 @Override
162 public NGShape.Mode getMode(Shape shape) {
163 return shape.getMode();
164 }
165
166 @Override
167 public void setMode(Shape shape, NGShape.Mode mode) {
168 shape.setMode(mode);
169 }
170
171 @Override
390 return NGShape.Mode.EMPTY;
391 }
392 }
393
394 NGShape.Mode getMode() {
395 return mode;
396 }
397
398 void setMode(NGShape.Mode mode) {
399 mode = mode;
400 }
401
402 private NGShape.Mode mode = NGShape.Mode.FILL;
403
404 private void checkModeChanged() {
405 NGShape.Mode newMode = computeMode();
406 if (mode != newMode) {
407 mode = newMode;
408
409 NodeHelper.markDirty(this, DirtyBits.SHAPE_MODE);
410 NodeHelper.geomChanged(this);
411 }
412 }
413
414 /**
415 * Defines parameters to fill the interior of an {@code Shape}
416 * using the settings of the {@code Paint} context.
417 * The default value is {@code Color.BLACK} for all shapes except
418 * Line, Polyline, and Path. The default value is {@code null} for
419 * those shapes.
420 */
421 private ObjectProperty<Paint> fill;
422
423
424 public final void setFill(Paint value) {
425 fillProperty().set(value);
426 }
427
428 public final Paint getFill() {
429 return fill == null ? Color.BLACK : fill.get();
430 }
479 /**
480 * Defines parameters of a stroke that is drawn around the outline of
481 * a {@code Shape} using the settings of the specified {@code Paint}.
482 * The default value is {@code null} for all shapes except
483 * Line, Polyline, and Path. The default value is {@code Color.BLACK} for
484 * those shapes.
485 */
486 private ObjectProperty<Paint> stroke;
487
488
489 public final void setStroke(Paint value) {
490 strokeProperty().set(value);
491 }
492
493 private final AbstractNotifyListener platformImageChangeListener =
494 new AbstractNotifyListener() {
495 @Override
496 public void invalidated(Observable valueModel) {
497 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_FILL);
498 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_STROKE);
499 NodeHelper.geomChanged(Shape.this);
500 checkModeChanged();
501 }
502 };
503
504 public final Paint getStroke() {
505 return stroke == null ? null : stroke.get();
506 }
507
508 Paint old_stroke;
509 public final ObjectProperty<Paint> strokeProperty() {
510 if (stroke == null) {
511 stroke = new StyleableObjectProperty<Paint>() {
512
513 boolean needsListener = false;
514
515 @Override public void invalidated() {
516
517 Paint _stroke = get();
518
519 if (needsListener) {
889 * @return The CssMetaData associated with this class, which may include the
890 * CssMetaData of its super classes.
891 * @since JavaFX 8.0
892 */
893 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() {
894 return StyleableProperties.STYLEABLES;
895 }
896
897 /**
898 * {@inheritDoc}
899 *
900 * @since JavaFX 8.0
901 */
902
903
904 @Override
905 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() {
906 return getClassCssMetaData();
907 }
908
909 /*
910 * Note: This method MUST only be called via its accessor method.
911 */
912 private BaseBounds doComputeGeomBounds(BaseBounds bounds,
913 BaseTransform tx) {
914 return computeShapeBounds(bounds, tx, ShapeHelper.configShape(this));
915 }
916
917 /*
918 * Note: This method MUST only be called via its accessor method.
919 */
920 private boolean doComputeContains(double localX, double localY) {
921 return computeShapeContains(localX, localY, ShapeHelper.configShape(this));
922 }
923
924 private static final double MIN_STROKE_WIDTH = 0.0f;
925 private static final double MIN_STROKE_MITER_LIMIT = 1.0f;
926
927 private void updatePGShape() {
928 final NGShape peer = NodeHelper.getPeer(this);
929 if (strokeAttributesDirty && (getStroke() != null)) {
930 // set attributes of stroke only when stroke paint is not null
931 final float[] pgDashArray =
932 (hasStrokeDashArray())
933 ? toPGDashArray(getStrokeDashArray())
934 : DEFAULT_PG_STROKE_DASH_ARRAY;
935
936 peer.setDrawStroke(
937 (float)Utils.clampMin(getStrokeWidth(),
938 MIN_STROKE_WIDTH),
939 getStrokeType(),
940 getStrokeLineCap(),
1508 }
1509
1510 public boolean canSetMiterLimit() {
1511 return (miterLimit == null) || !miterLimit.isBound();
1512 }
1513
1514 public boolean canSetDashOffset() {
1515 return (dashOffset == null) || !dashOffset.isBound();
1516 }
1517
1518 public boolean hasDashArray() {
1519 return (dashArray != null);
1520 }
1521
1522 private void invalidated(final CssMetaData<Shape, ?> propertyCssKey) {
1523 NodeHelper.markDirty(Shape.this, DirtyBits.SHAPE_STROKEATTRS);
1524 strokeAttributesDirty = true;
1525 if (propertyCssKey != StyleableProperties.STROKE_DASH_OFFSET) {
1526 // all stroke attributes change geometry except for the
1527 // stroke dash offset
1528 NodeHelper.geomChanged(Shape.this);
1529 }
1530 }
1531 }
1532
1533 /*
1534 * Note: This method MUST only be called via its accessor method.
1535 */
1536 private Object doProcessMXNode(MXNodeAlgorithm alg, MXNodeAlgorithmContext ctx) {
1537 return alg.processLeafNode(this, ctx);
1538 }
1539
1540 // PENDING_DOC_REVIEW
1541 /**
1542 * Returns a new {@code Shape} which is created as a union of the specified
1543 * input shapes.
1544 * <p>
1545 * The operation works with geometric areas occupied by the input shapes.
1546 * For a single {@code Shape} such area includes the area occupied by the
1547 * fill if the shape has a non-null fill and the area occupied by the stroke
1548 * if the shape has a non-null stroke. So the area is empty for a shape
1549 * with {@code null} stroke and {@code null} fill. The area of an input
1550 * shape considered by the operation is independent on the type and
1551 * configuration of the paint used for fill or stroke. Before the final
1552 * operation the areas of the input shapes are transformed to the parent
1553 * coordinate space of their respective topmost parent nodes.
1554 * <p>
1555 * The resulting shape will include areas that were contained in any of the
1556 * input shapes.
1706 fillShape, strokeType, strokeWidth, strokeLineCap,
1707 strokeLineJoin, strokeMiterLimit,
1708 dashArray, (float) getStrokeDashOffset());
1709
1710 if (mode == NGShape.Mode.STROKE) {
1711 return createTransformedArea(strokeShape, transform);
1712 }
1713
1714 // fill and stroke
1715 final Area combinedArea = new Area(fillShape);
1716 combinedArea.add(new Area(strokeShape));
1717
1718 return createTransformedArea(combinedArea, transform);
1719 }
1720
1721 private static BaseTransform calculateNodeToSceneTransform(Node node) {
1722 final Affine3D cumulativeTransformation = new Affine3D();
1723
1724 do {
1725 cumulativeTransformation.preConcatenate(
1726 NodeHelper.getLeafTransform(node));
1727 node = node.getParent();
1728 } while (node != null);
1729
1730 return cumulativeTransformation;
1731 }
1732
1733 private static Area createTransformedArea(
1734 final com.sun.javafx.geom.Shape geomShape,
1735 final BaseTransform transform) {
1736 return transform.isIdentity()
1737 ? new Area(geomShape)
1738 : new Area(geomShape.getPathIterator(transform));
1739 }
1740
1741 private static Path createFromGeomShape(
1742 final com.sun.javafx.geom.Shape geomShape) {
1743 final Path path = new Path();
1744 final ObservableList<PathElement> elements = path.getElements();
1745
1746 final PathIterator iterator = geomShape.getPathIterator(null);
|