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 028 029 030import java.util.ArrayList; 031import java.util.Collections; 032import java.util.List; 033 034import javafx.beans.property.DoubleProperty; 035import javafx.beans.property.DoublePropertyBase; 036import javafx.scene.paint.Paint; 037 038import javafx.css.StyleableDoubleProperty; 039import javafx.css.CssMetaData; 040import com.sun.javafx.css.converters.SizeConverter; 041import com.sun.javafx.geom.BaseBounds; 042import com.sun.javafx.geom.RoundRectangle2D; 043import com.sun.javafx.geom.transform.BaseTransform; 044import com.sun.javafx.scene.DirtyBits; 045import com.sun.javafx.sg.PGNode; 046import com.sun.javafx.sg.PGRectangle; 047import com.sun.javafx.sg.PGShape.Mode; 048import com.sun.javafx.tk.Toolkit; 049import javafx.css.Styleable; 050import javafx.css.StyleableProperty; 051 052 053/** 054 * The {@code Rectangle} class defines a rectangle 055 * with the specified size and location. By default the rectangle 056 * has sharp corners. Rounded corners can be specified using 057 * the arcWidth and arcHeight variables. 058 059 * <p>Example code: the following code creates a rectangle with 20 pixel 060 * rounded corners.</p> 061 * 062<PRE> 063import javafx.scene.shape.*; 064 065Rectangle r = new Rectangle(); 066r.setX(50); 067r.setY(50); 068r.setWidth(200); 069r.setHeight(100); 070r.setArcWidth(20); 071r.setArcHeight(20); 072</PRE> 073 */ 074public class Rectangle extends Shape { 075 076 private final RoundRectangle2D shape = new RoundRectangle2D(); 077 078 private static final int NON_RECTILINEAR_TYPE_MASK = ~( 079 BaseTransform.TYPE_TRANSLATION | 080 BaseTransform.TYPE_MASK_SCALE | 081 BaseTransform.TYPE_QUADRANT_ROTATION | 082 BaseTransform.TYPE_FLIP); 083 084 /** 085 * Creates an empty instance of Rectangle. 086 */ 087 public Rectangle() { 088 } 089 090 /** 091 * Creates a new instance of Rectangle with the given size. 092 * @param width width of the rectangle 093 * @param height height of the rectangle 094 */ 095 public Rectangle(double width, double height) { 096 setWidth(width); 097 setHeight(height); 098 } 099 100 /** 101 * Creates a new instance of Rectangle with the given size and fill. 102 * @param width width of the rectangle 103 * @param height height of the rectangle 104 * @param fill determines how to fill the interior of the rectangle 105 */ 106 public Rectangle(double width, double height, Paint fill) { 107 setWidth(width); 108 setHeight(height); 109 setFill(fill); 110 } 111 112 /** 113 * Creates a new instance of Rectangle with the given position and size. 114 * @param x horizontal position of the rectangle 115 * @param y vertical position of the rectangle 116 * @param width width of the rectangle 117 * @param height height of the rectangle 118 */ 119 public Rectangle(double x, double y, double width, double height) { 120 this(width, height); 121 setX(x); 122 setY(y); 123 } 124 125 /** 126 * Defines the X coordinate of the upper-left corner of the rectangle. 127 * 128 * @defaultValue 0.0 129 */ 130 private DoubleProperty x; 131 132 133 public final void setX(double value) { 134 if (x != null || value != 0.0) { 135 xProperty().set(value); 136 } 137 } 138 139 public final double getX() { 140 return x == null ? 0.0 : x.get(); 141 } 142 143 public final DoubleProperty xProperty() { 144 if (x == null) { 145 x = new DoublePropertyBase() { 146 147 @Override 148 public void invalidated() { 149 impl_markDirty(DirtyBits.NODE_GEOMETRY); 150 impl_geomChanged(); 151 } 152 153 @Override 154 public Object getBean() { 155 return Rectangle.this; 156 } 157 158 @Override 159 public String getName() { 160 return "x"; 161 } 162 }; 163 } 164 return x; 165 } 166 167 /** 168 * Defines the Y coordinate of the upper-left corner of the rectangle. 169 * 170 * @defaultValue 0.0 171 */ 172 private DoubleProperty y; 173 174 public final void setY(double value) { 175 if (y != null || value != 0.0) { 176 yProperty().set(value); 177 } 178 } 179 180 public final double getY() { 181 return y == null ? 0.0 : y.get(); 182 } 183 184 public final DoubleProperty yProperty() { 185 if (y == null) { 186 y = new DoublePropertyBase() { 187 188 @Override 189 public void invalidated() { 190 impl_markDirty(DirtyBits.NODE_GEOMETRY); 191 impl_geomChanged(); 192 } 193 194 @Override 195 public Object getBean() { 196 return Rectangle.this; 197 } 198 199 @Override 200 public String getName() { 201 return "y"; 202 } 203 }; 204 } 205 return y; 206 } 207 208 /** 209 * Defines the width of the rectangle. 210 * 211 * @defaultValue 0.0 212 */ 213 private DoubleProperty width = new DoublePropertyBase() { 214 215 @Override 216 public void invalidated() { 217 impl_markDirty(DirtyBits.NODE_GEOMETRY); 218 impl_geomChanged(); 219 } 220 221 @Override 222 public Object getBean() { 223 return Rectangle.this; 224 } 225 226 @Override 227 public String getName() { 228 return "width"; 229 } 230 }; 231 232 public final void setWidth(double value) { 233 width.set(value); 234 } 235 236 public final double getWidth() { 237 return width.get(); 238 } 239 240 public final DoubleProperty widthProperty() { 241 return width; 242 } 243 244 /** 245 * Defines the height of the rectangle. 246 * 247 * @defaultValue 0.0 248 */ 249 private DoubleProperty height = new DoublePropertyBase() { 250 251 @Override 252 public void invalidated() { 253 impl_markDirty(DirtyBits.NODE_GEOMETRY); 254 impl_geomChanged(); 255 } 256 257 @Override 258 public Object getBean() { 259 return Rectangle.this; 260 } 261 262 @Override 263 public String getName() { 264 return "height"; 265 } 266 }; 267 268 269 public final void setHeight(double value) { 270 height.set(value); 271 } 272 273 public final double getHeight() { 274 return height.get(); 275 } 276 277 public final DoubleProperty heightProperty() { 278 return height; 279 } 280 281 /** 282 * Defines the horizontal diameter of the arc 283 * at the four corners of the rectangle. 284 * 285 * @defaultValue 0.0 286 */ 287 private DoubleProperty arcWidth; 288 289 290 public final void setArcWidth(double value) { 291 if (arcWidth != null || value != 0.0) { 292 arcWidthProperty().set(value); 293 } 294 } 295 296 public final double getArcWidth() { 297 return arcWidth == null ? 0.0 : arcWidth.get(); 298 } 299 300 public final DoubleProperty arcWidthProperty() { 301 if (arcWidth == null) { 302 arcWidth = new StyleableDoubleProperty() { 303 304 @Override 305 public void invalidated() { 306 impl_markDirty(DirtyBits.NODE_GEOMETRY); 307 } 308 309 @Override 310 public CssMetaData<Rectangle, Number> getCssMetaData() { 311 return StyleableProperties.ARC_WIDTH; 312 } 313 314 @Override 315 public Object getBean() { 316 return Rectangle.this; 317 } 318 319 @Override 320 public String getName() { 321 return "arcWidth"; 322 } 323 }; 324 } 325 return arcWidth; 326 } 327 328 /** 329 * Defines the vertical diameter of the arc 330 * at the four corners of the rectangle. 331 * 332 * @defaultValue 0.0 333 */ 334 private DoubleProperty arcHeight; 335 336 337 public final void setArcHeight(double value) { 338 if (arcHeight != null || value != 0.0) { 339 arcHeightProperty().set(value); 340 } 341 } 342 343 public final double getArcHeight() { 344 return arcHeight == null ? 0.0 : arcHeight.get(); 345 } 346 347 public final DoubleProperty arcHeightProperty() { 348 if (arcHeight == null) { 349 arcHeight = new StyleableDoubleProperty() { 350 351 @Override 352 public void invalidated() { 353 impl_markDirty(DirtyBits.NODE_GEOMETRY); 354 } 355 356 @Override 357 public CssMetaData<Rectangle, Number> getCssMetaData() { 358 return StyleableProperties.ARC_HEIGHT; 359 } 360 361 @Override 362 public Object getBean() { 363 return Rectangle.this; 364 } 365 366 @Override 367 public String getName() { 368 return "arcHeight"; 369 } 370 }; 371 } 372 return arcHeight; 373 } 374 375 /** 376 * @treatAsPrivate implementation detail 377 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 378 */ 379 @Deprecated 380 @Override 381 protected PGNode impl_createPGNode() { 382 return Toolkit.getToolkit().createPGRectangle(); 383 } 384 385 PGRectangle getPGRect() { 386 return (PGRectangle) impl_getPGNode(); 387 } 388 389 /*************************************************************************** 390 * * 391 * Stylesheet Handling * 392 * * 393 **************************************************************************/ 394 395 /** 396 * Super-lazy instantiation pattern from Bill Pugh. 397 * @treatAsPrivate implementation detail 398 */ 399 private static class StyleableProperties { 400 private static final CssMetaData<Rectangle,Number> ARC_HEIGHT = 401 new CssMetaData<Rectangle,Number>("-fx-arc-height", 402 SizeConverter.getInstance(), 0.0) { 403 404 @Override 405 public boolean isSettable(Rectangle node) { 406 return node.arcHeight == null || !node.arcHeight.isBound(); 407 } 408 409 @Override 410 public StyleableProperty<Number> getStyleableProperty(Rectangle node) { 411 return (StyleableProperty<Number>)node.arcHeightProperty(); 412 } 413 414 }; 415 private static final CssMetaData<Rectangle,Number> ARC_WIDTH = 416 new CssMetaData<Rectangle,Number>("-fx-arc-width", 417 SizeConverter.getInstance(), 0.0) { 418 419 @Override 420 public boolean isSettable(Rectangle node) { 421 return node.arcWidth == null || !node.arcWidth.isBound(); 422 } 423 424 @Override 425 public StyleableProperty<Number> getStyleableProperty(Rectangle node) { 426 return (StyleableProperty<Number>)node.arcWidthProperty(); 427 } 428 429 }; 430 431 private static final List<CssMetaData<? extends Styleable, ?>> STYLEABLES; 432 static { 433 final List<CssMetaData<? extends Styleable, ?>> styleables = 434 new ArrayList<CssMetaData<? extends Styleable, ?>>(Shape.getClassCssMetaData()); 435 styleables.add(ARC_HEIGHT); 436 styleables.add(ARC_WIDTH); 437 STYLEABLES = Collections.unmodifiableList(styleables); 438 439 } 440 } 441 442 /** 443 * @return The CssMetaData associated with this class, which may include the 444 * CssMetaData of its super classes. 445 */ 446 public static List<CssMetaData<? extends Styleable, ?>> getClassCssMetaData() { 447 return StyleableProperties.STYLEABLES; 448 } 449 450 /** 451 * {@inheritDoc} 452 * 453 */ 454 455 456 @Override 457 public List<CssMetaData<? extends Styleable, ?>> getCssMetaData() { 458 return getClassCssMetaData(); 459 } 460 461 /** 462 * @treatAsPrivate implementation detail 463 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 464 */ 465 @Deprecated 466 @Override 467 protected com.sun.javafx.sg.PGShape.StrokeLineJoin toPGLineJoin(StrokeLineJoin t) { 468 // If we are a round rectangle then MITER can produce anomalous 469 // results for very thin or very wide corner arcs when the bezier 470 // curves that approximate the arcs become so distorted that they 471 // shoot out MITER-like extensions. This effect complicates matters 472 // because it makes such "round" rectangles non-round, and also 473 // because it means we might have to pad the bounds to account 474 // for this rare and unpredictable circumstance. 475 // To avoid the problem, we set the Join style to BEVEL for any 476 // rounded rect. The BEVEL join style is more predictable for 477 // anomalous angles and is the simplest join style to compute in 478 // the stroking code. 479 // For non-rounded rectangles, the angles are all 90 degrees and so 480 // the computations are both simple and non-problematic so we pass on 481 // the join style unmodified to the PG layer. 482 if ((getArcWidth() > 0) && (getArcHeight() > 0)) { 483 return com.sun.javafx.sg.PGShape.StrokeLineJoin.BEVEL; 484 } 485 return super.toPGLineJoin(t); 486 } 487 488 /** 489 * @treatAsPrivate implementation detail 490 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 491 */ 492 @Deprecated 493 @Override 494 public BaseBounds impl_computeGeomBounds(BaseBounds bounds, BaseTransform tx) { 495 // if there is no fill or stroke, then there are no bounds. The bounds 496 // must be marked empty in this case to distinguish it from 0,0,0,0 497 // which would actually contribute to the bounds of a group. 498 if (impl_mode == Mode.EMPTY) { 499 return bounds.makeEmpty(); 500 } 501 if ((getArcWidth() > 0) && (getArcHeight() > 0) 502 && ((tx.getType() & NON_RECTILINEAR_TYPE_MASK) != 0)) { 503 return computeShapeBounds(bounds, tx, impl_configShape()); 504 } 505 double upad; 506 double dpad; 507 if ((impl_mode == Mode.FILL) || (getStrokeType() == StrokeType.INSIDE)) { 508 upad = dpad = 0; 509 } else { 510 upad = getStrokeWidth(); 511 if (getStrokeType() == StrokeType.CENTERED) { 512 upad /= 2.0; 513 } 514 dpad = 0.0f; 515 } 516 return computeBounds(bounds, tx, upad, dpad, getX(), getY(), getWidth(), getHeight()); 517 } 518 519 /** 520 * @treatAsPrivate implementation detail 521 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 522 */ 523 @Deprecated 524 @Override 525 public RoundRectangle2D impl_configShape() { 526 if ((getArcWidth() > 0) && (getArcHeight() > 0)) { 527 shape.setRoundRect((float)getX(), (float)getY(), 528 (float)getWidth(), (float)getHeight(), 529 (float)getArcWidth(), (float)getArcHeight()); 530 } else { 531 shape.setRoundRect( 532 (float)getX(), (float)getY(), 533 (float)getWidth(), (float)getHeight(), 0, 0); 534 } 535 return shape; 536 } 537 538 /** 539 * @treatAsPrivate implementation detail 540 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 541 */ 542 @Deprecated 543 @Override 544 public void impl_updatePG() { 545 super.impl_updatePG(); 546 if (impl_isDirty(DirtyBits.NODE_GEOMETRY)) { 547 PGRectangle peer = getPGRect(); 548 peer.updateRectangle((float)getX(), 549 (float)getY(), 550 (float)getWidth(), 551 (float)getHeight(), 552 (float)getArcWidth(), 553 (float)getArcHeight()); 554 } 555 } 556 557 /** 558 * Returns a string representation of this {@code Rectangle} object. 559 * @return a string representation of this {@code Rectangle} object. 560 */ 561 @Override 562 public String toString() { 563 final StringBuilder sb = new StringBuilder("Rectangle["); 564 565 String id = getId(); 566 if (id != null) { 567 sb.append("id=").append(id).append(", "); 568 } 569 570 sb.append("x=").append(getX()); 571 sb.append(", y=").append(getY()); 572 sb.append(", width=").append(getWidth()); 573 sb.append(", height=").append(getHeight()); 574 575 sb.append(", fill=").append(getFill()); 576 577 Paint stroke = getStroke(); 578 if (stroke != null) { 579 sb.append(", stroke=").append(stroke); 580 sb.append(", strokeWidth=").append(getStrokeWidth()); 581 } 582 583 return sb.append("]").toString(); 584 } 585}