Spec-Zone .ru
спецификации, руководства, описания, API
|
001/* 002 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 003 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 004 * 005 * This code is free software; you can redistribute it and/or modify it 006 * under the terms of the GNU General Public License version 2 only, as 007 * published by the Free Software Foundation. Oracle designates this 008 * particular file as subject to the "Classpath" exception as provided 009 * by Oracle in the LICENSE file that accompanied this code. 010 * 011 * This code is distributed in the hope that it will be useful, but WITHOUT 012 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 013 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 014 * version 2 for more details (a copy is included in the LICENSE file that 015 * accompanied this code). 016 * 017 * You should have received a copy of the GNU General Public License version 018 * 2 along with this work; if not, write to the Free Software Foundation, 019 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 020 * 021 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 022 * or visit www.oracle.com if you need additional information or have any 023 * questions. 024 */ 025 026package javafx.scene.shape; 027 028import javafx.css.CssMetaData; 029import com.sun.javafx.css.converters.PaintConverter; 030import javafx.beans.property.DoubleProperty; 031import javafx.beans.property.DoublePropertyBase; 032import javafx.scene.paint.Color; 033 034import com.sun.javafx.geom.BaseBounds; 035import com.sun.javafx.geom.Line2D; 036import com.sun.javafx.geom.transform.BaseTransform; 037import com.sun.javafx.scene.DirtyBits; 038import com.sun.javafx.sg.PGLine; 039import com.sun.javafx.sg.PGNode; 040import com.sun.javafx.sg.PGShape.Mode; 041import com.sun.javafx.tk.Toolkit; 042import java.util.ArrayList; 043import java.util.Collections; 044import java.util.List; 045import javafx.beans.value.WritableValue; 046import javafx.css.StyleableProperty; 047import javafx.scene.paint.Paint; 048 049 050/** 051 * This Line represents a line segment in {@code (x,y)} 052 * coordinate space. Example: 053 * 054<PRE> 055import javafx.scene.shape.*; 056 057Line line = new Line(); 058line.setStartX(0.0f); 059line.setStartY(0.0f); 060line.setEndX(100.0f); 061line.setEndY(100.0f); 062} 063</PRE> 064 */ 065public class Line extends Shape { 066 067 private final Line2D shape = new Line2D(); 068 069 { 070 // overriding default values for fill and stroke 071 // Set through CSS property so that it appears to be a UA style rather 072 // that a USER style so that fill and stroke can still be set from CSS. 073 ((StyleableProperty)fillProperty()).applyStyle(null, null); 074 ((StyleableProperty)strokeProperty()).applyStyle(null, Color.BLACK); 075 } 076 077 /** 078 * Creates an empty instance of Line. 079 */ 080 public Line() { 081 } 082 083 /** 084 * Creates a new instance of Line. 085 * @param startX the horizontal coordinate of the start point of the line segment 086 * @param startY the vertical coordinate of the start point of the line segment 087 * @param endX the horizontal coordinate of the end point of the line segment 088 * @param endY the vertical coordinate of the end point of the line segment 089 */ 090 public Line(double startX, double startY, double endX, double endY) { 091 setStartX(startX); 092 setStartY(startY); 093 setEndX(endX); 094 setEndY(endY); 095 } 096 097 /** 098 * The X coordinate of the start point of the line segment. 099 * 100 * @defaultValue 0.0 101 */ 102 private DoubleProperty startX; 103 104 105 public final void setStartX(double value) { 106 if (startX != null || value != 0.0) { 107 startXProperty().set(value); 108 } 109 } 110 111 public final double getStartX() { 112 return startX == null ? 0.0 : startX.get(); 113 } 114 115 public final DoubleProperty startXProperty() { 116 if (startX == null) { 117 startX = new DoublePropertyBase() { 118 119 @Override 120 public void invalidated() { 121 impl_markDirty(DirtyBits.NODE_GEOMETRY); 122 impl_geomChanged(); 123 } 124 125 @Override 126 public Object getBean() { 127 return Line.this; 128 } 129 130 @Override 131 public String getName() { 132 return "startX"; 133 } 134 }; 135 } 136 return startX; 137 } 138 139 /** 140 * The Y coordinate of the start point of the line segment. 141 * 142 * @defaultValue 0.0 143 */ 144 private DoubleProperty startY; 145 146 147 148 public final void setStartY(double value) { 149 if (startY != null || value != 0.0) { 150 startYProperty().set(value); 151 } 152 } 153 154 public final double getStartY() { 155 return startY == null ? 0.0 : startY.get(); 156 } 157 158 public final DoubleProperty startYProperty() { 159 if (startY == null) { 160 startY = new DoublePropertyBase() { 161 162 @Override 163 public void invalidated() { 164 impl_markDirty(DirtyBits.NODE_GEOMETRY); 165 impl_geomChanged(); 166 } 167 168 @Override 169 public Object getBean() { 170 return Line.this; 171 } 172 173 @Override 174 public String getName() { 175 return "startY"; 176 } 177 }; 178 } 179 return startY; 180 } 181 182 /** 183 * The X coordinate of the end point of the line segment. 184 * 185 * @defaultValue 0.0 186 */ 187 private DoubleProperty endX; 188 189 190 191 public final void setEndX(double value) { 192 if (endX != null || value != 0.0) { 193 endXProperty().set(value); 194 } 195 } 196 197 public final double getEndX() { 198 return endX == null ? 0.0 : endX.get(); 199 } 200 201 public final DoubleProperty endXProperty() { 202 if (endX == null) { 203 endX = new DoublePropertyBase() { 204 205 @Override 206 public void invalidated() { 207 impl_markDirty(DirtyBits.NODE_GEOMETRY); 208 impl_geomChanged(); 209 } 210 211 @Override 212 public Object getBean() { 213 return Line.this; 214 } 215 216 @Override 217 public String getName() { 218 return "endX"; 219 } 220 }; 221 } 222 return endX; 223 } 224 225 /** 226 * The Y coordinate of the end point of the line segment. 227 * 228 * @defaultValue 0.0 229 */ 230 private DoubleProperty endY; 231 232 public final void setEndY(double value) { 233 if (endY != null || value != 0.0) { 234 endYProperty().set(value); 235 } 236 } 237 238 public final double getEndY() { 239 return endY == null ? 0.0 : endY.get(); 240 } 241 242 public final DoubleProperty endYProperty() { 243 if (endY == null) { 244 endY = new DoublePropertyBase() { 245 246 @Override 247 public void invalidated() { 248 impl_markDirty(DirtyBits.NODE_GEOMETRY); 249 impl_geomChanged(); 250 } 251 252 @Override 253 public Object getBean() { 254 return Line.this; 255 } 256 257 @Override 258 public String getName() { 259 return "endY"; 260 } 261 }; 262 } 263 return endY; 264 } 265 266 /** 267 * @treatAsPrivate implementation detail 268 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 269 */ 270 @Deprecated 271 @Override 272 protected PGNode impl_createPGNode() { 273 return Toolkit.getToolkit().createPGLine(); 274 } 275 276 PGLine getPGLine() { 277 return (PGLine)impl_getPGNode(); 278 } 279 280 /** 281 * @treatAsPrivate implementation detail 282 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 283 */ 284 @Deprecated 285 @Override 286 public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) { 287 288 // Since line's only draw with strokes, if the mode is FILL or EMPTY 289 // then we simply return empty bounds 290 if (impl_mode == Mode.FILL || impl_mode == Mode.EMPTY || 291 getStrokeType() == StrokeType.INSIDE) 292 { 293 return bounds.makeEmpty(); 294 } 295 296 double x1 = getStartX(); 297 double x2 = getEndX(); 298 double y1 = getStartY(); 299 double y2 = getEndY(); 300 // Get the draw stroke, and figure out the bounds based on the stroke. 301 double wpad = getStrokeWidth(); 302 if (getStrokeType() == StrokeType.CENTERED) { 303 wpad /= 2.0f; 304 } 305 // fast path the case of AffineTransform being TRANSLATE or identity 306 if (tx.isTranslateOrIdentity()) { 307 final double xpad; 308 final double ypad; 309 wpad = Math.max(wpad, 0.5f); 310 if (tx.getType() == BaseTransform.TYPE_TRANSLATION) { 311 final double ddx = tx.getMxt(); 312 final double ddy = tx.getMyt(); 313 x1 += ddx; 314 y1 += ddy; 315 x2 += ddx; 316 y2 += ddy; 317 } 318 if (y1 == y2 && x1 != x2) { 319 ypad = wpad; 320 xpad = (getStrokeLineCap() == StrokeLineCap.BUTT) ? 0.0f : wpad; 321 } else if (x1 == x2 && y1 != y2) { 322 xpad = wpad; 323 ypad = (getStrokeLineCap() == StrokeLineCap.BUTT) ? 0.0f : wpad; 324 } else { 325 if (getStrokeLineCap() == StrokeLineCap.SQUARE) { 326 wpad *= Math.sqrt(2); 327 } 328 xpad = ypad = wpad; 329 } 330 if (x1 > x2) { final double t = x1; x1 = x2; x2 = t; } 331 if (y1 > y2) { final double t = y1; y1 = y2; y2 = t; } 332 333 x1 -= xpad; 334 y1 -= ypad; 335 x2 += xpad; 336 y2 += ypad; 337 bounds = bounds.deriveWithNewBounds((float)x1, (float)y1, 0.0f, 338 (float)x2, (float)y2, 0.0f); 339 return bounds; 340 } 341 342 double dx = x2 - x1; 343 double dy = y2 - y1; 344 final double len = Math.sqrt(dx * dx + dy * dy); 345 if (len == 0.0f) { 346 dx = wpad; 347 dy = 0.0f; 348 } else { 349 dx = wpad * dx / len; 350 dy = wpad * dy / len; 351 } 352 final double ecx; 353 final double ecy; 354 if (getStrokeLineCap() != StrokeLineCap.BUTT) { 355 ecx = dx; 356 ecy = dy; 357 } else { 358 ecx = ecy = 0.0f; 359 } 360 final double corners[] = new double[] { 361 x1-dy-ecx, y1+dx-ecy, 362 x1+dy-ecx, y1-dx-ecy, 363 x2+dy+ecx, y2-dx+ecy, 364 x2-dy+ecx, y2+dx+ecy }; 365 tx.transform(corners, 0, corners, 0, 4); 366 x1 = Math.min(Math.min(corners[0], corners[2]), 367 Math.min(corners[4], corners[6])); 368 y1 = Math.min(Math.min(corners[1], corners[3]), 369 Math.min(corners[5], corners[7])); 370 x2 = Math.max(Math.max(corners[0], corners[2]), 371 Math.max(corners[4], corners[6])); 372 y2 = Math.max(Math.max(corners[1], corners[3]), 373 Math.max(corners[5], corners[7])); 374 x1 -= 0.5f; 375 y1 -= 0.5f; 376 x2 += 0.5f; 377 y2 += 0.5f; 378 bounds = bounds.deriveWithNewBounds((float)x1, (float)y1, 0.0f, 379 (float)x2, (float)y2, 0.0f); 380 return bounds; 381 } 382 383 /** 384 * @treatAsPrivate implementation detail 385 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 386 */ 387 @Deprecated 388 @Override 389 public Line2D impl_configShape() { 390 shape.setLine((float)getStartX(), (float)getStartY(), (float)getEndX(), (float)getEndY()); 391 return shape; 392 } 393 394 /** 395 * @treatAsPrivate implementation detail 396 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 397 */ 398 @Deprecated 399 @Override 400 public void impl_updatePG() { 401 super.impl_updatePG(); 402 403 if (impl_isDirty(DirtyBits.NODE_GEOMETRY)) { 404 PGLine peer = getPGLine(); 405 peer.updateLine((float)getStartX(), 406 (float)getStartY(), 407 (float)getEndX(), 408 (float)getEndY()); 409 } 410 } 411 412 /*************************************************************************** 413 * * 414 * Stylesheet Handling * 415 * * 416 **************************************************************************/ 417 418 /** 419 * Some sub-class of Shape, such as {@link Line}, override the 420 * default value for the {@link Shape#fill} property. This allows 421 * CSS to get the correct initial value. 422 * @treatAsPrivate Implementation detail 423 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 424 */ 425 @Deprecated 426 protected Paint impl_cssGetFillInitialValue() { 427 return null; 428 } 429 430 /** 431 * Some sub-class of Shape, such as {@link Line}, override the 432 * default value for the {@link Shape#stroke} property. This allows 433 * CSS to get the correct initial value. 434 * @treatAsPrivate Implementation detail 435 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 436 */ 437 @Deprecated 438 protected Paint impl_cssGetStrokeInitialValue() { 439 return Color.BLACK; 440 } 441 442 /** 443 * Returns a string representation of this {@code Line} object. 444 * @return a string representation of this {@code Line} object. 445 */ 446 @Override 447 public String toString() { 448 final StringBuilder sb = new StringBuilder("Line["); 449 450 String id = getId(); 451 if (id != null) { 452 sb.append("id=").append(id).append(", "); 453 } 454 455 sb.append("startX=").append(getStartX()); 456 sb.append(", startY=").append(getStartY()); 457 sb.append(", endX=").append(getEndX()); 458 sb.append(", endY=").append(getEndY()); 459 460 Paint stroke = getStroke(); 461 if (stroke != null) { 462 sb.append(", stroke=").append(stroke); 463 sb.append(", strokeWidth=").append(getStrokeWidth()); 464 } 465 466 return sb.append("]").toString(); 467 } 468} 469