88 path.getElements().add(lineTo); 89 path.getElements().add(arcTo); 90 91 </PRE> 92 * @since JavaFX 2.0 93 */ 94 public class Path extends Shape { 95 static { 96 PathHelper.setPathAccessor(new PathHelper.PathAccessor() { 97 @Override 98 public NGNode doCreatePeer(Node node) { 99 return ((Path) node).doCreatePeer(); 100 } 101 102 @Override 103 public void doUpdatePeer(Node node) { 104 ((Path) node).doUpdatePeer(); 105 } 106 107 @Override 108 public Paint doCssGetFillInitialValue(Shape shape) { 109 return ((Path) shape).doCssGetFillInitialValue(); 110 } 111 112 @Override 113 public Paint doCssGetStrokeInitialValue(Shape shape) { 114 return ((Path) shape).doCssGetStrokeInitialValue(); 115 } 116 117 @Override 118 public com.sun.javafx.geom.Shape doConfigShape(Shape shape) { 119 return ((Path) shape).doConfigShape(); 120 } 121 122 }); 123 } 124 125 private Path2D path2d = null; 126 127 { 149 public Path(PathElement... elements) { 150 if (elements != null) { 151 this.elements.addAll(elements); 152 } 153 } 154 155 /** 156 * Creates new instance of Path 157 * @param elements The collection of the elements of the Path 158 * @since JavaFX 2.2 159 */ 160 public Path(Collection<? extends PathElement> elements) { 161 if (elements != null) { 162 this.elements.addAll(elements); 163 } 164 } 165 166 void markPathDirty() { 167 path2d = null; 168 NodeHelper.markDirty(this, DirtyBits.NODE_CONTENTS); 169 impl_geomChanged(); 170 } 171 172 /** 173 * Defines the filling rule constant for determining the interior of the path. 174 * The value must be one of the following constants: 175 * {@code FillRile.EVEN_ODD} or {@code FillRule.NON_ZERO}. 176 * The default value is {@code FillRule.NON_ZERO}. 177 * 178 * @defaultValue FillRule.NON_ZERO 179 */ 180 private ObjectProperty<FillRule> fillRule; 181 182 public final void setFillRule(FillRule value) { 183 if (fillRule != null || value != FillRule.NON_ZERO) { 184 fillRuleProperty().set(value); 185 } 186 } 187 188 public final FillRule getFillRule() { 189 return fillRule == null ? FillRule.NON_ZERO : fillRule.get(); 190 } 191 192 public final ObjectProperty<FillRule> fillRuleProperty() { 193 if (fillRule == null) { 194 fillRule = new ObjectPropertyBase<FillRule>(FillRule.NON_ZERO) { 195 196 @Override 197 public void invalidated() { 198 NodeHelper.markDirty(Path.this, DirtyBits.NODE_CONTENTS); 199 impl_geomChanged(); 200 } 201 202 @Override 203 public Object getBean() { 204 return Path.this; 205 } 206 207 @Override 208 public String getName() { 209 return "fillRule"; 210 } 211 }; 212 } 213 return fillRule; 214 } 215 216 private boolean isPathValid; 217 /** 218 * Defines the array of path elements of this path. 219 * 239 // we cannot count the number of PathElements removed (fast enough). 240 // Thus we can optimize only if some elements were added to the end 241 if (path2d != null) { 242 c.reset(); 243 c.next(); 244 // we just have to check the first change, as more changes cannot come after such change 245 if (c.getFrom() == c.getList().size() && !c.wasRemoved() && c.wasAdded()) { 246 // some elements added 247 for (int i = c.getFrom(); i < c.getTo(); ++i) { 248 PathElementHelper.addTo(list.get(i), path2d); 249 } 250 } else { 251 path2d = null; 252 } 253 } 254 if (firstElementChanged) { 255 isPathValid = isFirstPathElementValid(); 256 } 257 258 NodeHelper.markDirty(Path.this, DirtyBits.NODE_CONTENTS); 259 impl_geomChanged(); 260 } 261 }; 262 263 /** 264 * Gets observable list of path elements of this path. 265 * @return Elements of this path 266 */ 267 public final ObservableList<PathElement> getElements() { return elements; } 268 269 /* 270 * Note: This method MUST only be called via its accessor method. 271 */ 272 private NGNode doCreatePeer() { 273 return new NGPath(); 274 } 275 276 /* 277 * Note: This method MUST only be called via its accessor method. 278 */ 279 private Path2D doConfigShape() { 280 if (isPathValid) { 281 if (path2d == null) { 282 path2d = PathUtils.configShape(getElements(), getFillRule() == FillRule.EVEN_ODD); 283 } else { 284 path2d.setWindingRule(getFillRule() == FillRule.NON_ZERO ? 285 Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD); 286 } 287 return path2d; 288 } else { 289 return new Path2D(); 290 } 291 } 292 293 /** 294 * @treatAsPrivate implementation detail 295 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 296 */ 297 @Deprecated 298 @Override 299 protected Bounds impl_computeLayoutBounds() { 300 if (isPathValid) { 301 return super.impl_computeLayoutBounds(); 302 } 303 return new BoundingBox(0, 0, -1, -1); //create empty bounds 304 } 305 306 private boolean isFirstPathElementValid() { 307 ObservableList<PathElement> _elements = getElements(); 308 if (_elements != null && _elements.size() > 0) { 309 PathElement firstElement = _elements.get(0); 310 if (!firstElement.isAbsolute()) { 311 System.err.printf("First element of the path can not be relative. Path: %s\n", this); 312 return false; 313 } else if (firstElement instanceof MoveTo) { 314 return true; 315 } else { 316 System.err.printf("Missing initial moveto in path definition. Path: %s\n", this); 317 return false; 318 } 319 } 320 return true; 321 } | 88 path.getElements().add(lineTo); 89 path.getElements().add(arcTo); 90 91 </PRE> 92 * @since JavaFX 2.0 93 */ 94 public class Path extends Shape { 95 static { 96 PathHelper.setPathAccessor(new PathHelper.PathAccessor() { 97 @Override 98 public NGNode doCreatePeer(Node node) { 99 return ((Path) node).doCreatePeer(); 100 } 101 102 @Override 103 public void doUpdatePeer(Node node) { 104 ((Path) node).doUpdatePeer(); 105 } 106 107 @Override 108 public Bounds doComputeLayoutBounds(Node node) { 109 return ((Path) node).doComputeLayoutBounds(); 110 } 111 112 @Override 113 public Paint doCssGetFillInitialValue(Shape shape) { 114 return ((Path) shape).doCssGetFillInitialValue(); 115 } 116 117 @Override 118 public Paint doCssGetStrokeInitialValue(Shape shape) { 119 return ((Path) shape).doCssGetStrokeInitialValue(); 120 } 121 122 @Override 123 public com.sun.javafx.geom.Shape doConfigShape(Shape shape) { 124 return ((Path) shape).doConfigShape(); 125 } 126 127 }); 128 } 129 130 private Path2D path2d = null; 131 132 { 154 public Path(PathElement... elements) { 155 if (elements != null) { 156 this.elements.addAll(elements); 157 } 158 } 159 160 /** 161 * Creates new instance of Path 162 * @param elements The collection of the elements of the Path 163 * @since JavaFX 2.2 164 */ 165 public Path(Collection<? extends PathElement> elements) { 166 if (elements != null) { 167 this.elements.addAll(elements); 168 } 169 } 170 171 void markPathDirty() { 172 path2d = null; 173 NodeHelper.markDirty(this, DirtyBits.NODE_CONTENTS); 174 NodeHelper.geomChanged(this); 175 } 176 177 /** 178 * Defines the filling rule constant for determining the interior of the path. 179 * The value must be one of the following constants: 180 * {@code FillRile.EVEN_ODD} or {@code FillRule.NON_ZERO}. 181 * The default value is {@code FillRule.NON_ZERO}. 182 * 183 * @defaultValue FillRule.NON_ZERO 184 */ 185 private ObjectProperty<FillRule> fillRule; 186 187 public final void setFillRule(FillRule value) { 188 if (fillRule != null || value != FillRule.NON_ZERO) { 189 fillRuleProperty().set(value); 190 } 191 } 192 193 public final FillRule getFillRule() { 194 return fillRule == null ? FillRule.NON_ZERO : fillRule.get(); 195 } 196 197 public final ObjectProperty<FillRule> fillRuleProperty() { 198 if (fillRule == null) { 199 fillRule = new ObjectPropertyBase<FillRule>(FillRule.NON_ZERO) { 200 201 @Override 202 public void invalidated() { 203 NodeHelper.markDirty(Path.this, DirtyBits.NODE_CONTENTS); 204 NodeHelper.geomChanged(Path.this); 205 } 206 207 @Override 208 public Object getBean() { 209 return Path.this; 210 } 211 212 @Override 213 public String getName() { 214 return "fillRule"; 215 } 216 }; 217 } 218 return fillRule; 219 } 220 221 private boolean isPathValid; 222 /** 223 * Defines the array of path elements of this path. 224 * 244 // we cannot count the number of PathElements removed (fast enough). 245 // Thus we can optimize only if some elements were added to the end 246 if (path2d != null) { 247 c.reset(); 248 c.next(); 249 // we just have to check the first change, as more changes cannot come after such change 250 if (c.getFrom() == c.getList().size() && !c.wasRemoved() && c.wasAdded()) { 251 // some elements added 252 for (int i = c.getFrom(); i < c.getTo(); ++i) { 253 PathElementHelper.addTo(list.get(i), path2d); 254 } 255 } else { 256 path2d = null; 257 } 258 } 259 if (firstElementChanged) { 260 isPathValid = isFirstPathElementValid(); 261 } 262 263 NodeHelper.markDirty(Path.this, DirtyBits.NODE_CONTENTS); 264 NodeHelper.geomChanged(Path.this); 265 } 266 }; 267 268 /** 269 * Gets observable list of path elements of this path. 270 * @return Elements of this path 271 */ 272 public final ObservableList<PathElement> getElements() { return elements; } 273 274 /* 275 * Note: This method MUST only be called via its accessor method. 276 */ 277 private NGNode doCreatePeer() { 278 return new NGPath(); 279 } 280 281 /* 282 * Note: This method MUST only be called via its accessor method. 283 */ 284 private Path2D doConfigShape() { 285 if (isPathValid) { 286 if (path2d == null) { 287 path2d = PathUtils.configShape(getElements(), getFillRule() == FillRule.EVEN_ODD); 288 } else { 289 path2d.setWindingRule(getFillRule() == FillRule.NON_ZERO ? 290 Path2D.WIND_NON_ZERO : Path2D.WIND_EVEN_ODD); 291 } 292 return path2d; 293 } else { 294 return new Path2D(); 295 } 296 } 297 298 private Bounds doComputeLayoutBounds() { 299 if (isPathValid) { 300 return null; // Helper will need to call its super's compute layout bounds 301 } 302 return new BoundingBox(0, 0, -1, -1); //create empty bounds 303 } 304 305 private boolean isFirstPathElementValid() { 306 ObservableList<PathElement> _elements = getElements(); 307 if (_elements != null && _elements.size() > 0) { 308 PathElement firstElement = _elements.get(0); 309 if (!firstElement.isAbsolute()) { 310 System.err.printf("First element of the path can not be relative. Path: %s\n", this); 311 return false; 312 } else if (firstElement instanceof MoveTo) { 313 return true; 314 } else { 315 System.err.printf("Missing initial moveto in path definition. Path: %s\n", this); 316 return false; 317 } 318 } 319 return true; 320 } |