/* * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. * * * * * * * * * * * * * * * * * * * * */ package javafx.scene.paint; import java.util.List; import com.sun.javafx.collections.annotations.ReturnsUnmodifiableCollection; import com.sun.javafx.scene.paint.GradientUtils; import com.sun.javafx.tk.Toolkit; import javafx.beans.NamedArg; /** * The {@code RadialGradient} class provides a way to fill a shape * with a circular radial color gradient pattern. * The user may specify 2 or more gradient colors, * and this paint will provide an interpolation between each color. *
* The user must specify the circle controlling the gradient pattern, * which is defined by a center point and a radius. * The user can also specify a separate focus point within that circle, * which controls the location of the first color of the gradient. * By default the focus is set to be the center of the circle. * * The center and radius are specified * relative to a unit square, unless theproportional
* variable is false. By default proportional is true, and the
* gradient will be scaled to fill whatever shape it is applied to.
* The focus point is always specified relative to the center point
* by an angle and a distance relative to the radius.
*
* This paint will map the first color of the gradient to the focus point,
* and the last color to the perimeter of the circle,
* interpolating smoothly for any in-between colors specified by the user.
* Any line drawn from the focus point to the circumference will
* thus span all of the gradient colors.
*
* The focus distance will be clamped to the range {@code (-1, 1)}
* so that the focus point is always strictly inside the circle.
*
* The application provides an array of {@code Stop}s specifying how to distribute
* the colors along the gradient. The {@code Stop#offset} variable must be
* the range 0.0 to 1.0 and act like keyframes along the gradient.
* They mark where the gradient should be exactly a particular color.
* @since JavaFX 2.0
*/
public final class RadialGradient extends Paint {
private double focusAngle;
/**
* Defines the angle in degrees from the center of the gradient
* to the focus point to which the first color is mapped.
*/
public final double getFocusAngle() {
return focusAngle;
}
private double focusDistance;
/**
* Defines the distance from the center of the gradient to the
* focus point to which the first color is mapped.
* A distance of 0.0 will be at the center of the gradient circle.
* A distance of 1.0 will be on the circumference of the gradient circle.
*/
public final double getFocusDistance() {
return focusDistance;
}
private double centerX;
/**
* Defines the X coordinate of the center point of the circle defining the gradient.
* If proportional is true (the default), this value specifies a
* point on a unit square that will be scaled to match the size of the
* the shape that the gradient fills.
* The last color of the gradient is mapped to the perimeter of this circle.
*
* @defaultValue 0.0
*/
public final double getCenterX() {
return centerX;
}
private double centerY;
/**
* Defines the X coordinate of the center point of the circle defining the gradient.
* If proportional is true (the default), this value specifies a
* point on a unit square that will be scaled to match the size of the
* the shape that the gradient fills.
* The last color of the gradient is mapped to the perimeter of this circle.
*
* @defaultValue 0.0
*/
public final double getCenterY() {
return centerY;
}
private double radius;
/**
* Specifies the radius of the circle defining the extents of the color gradient.
* If proportional is true (the default), this value specifies a
* size relative to unit square that will be scaled to match the size of the
* the shape that the gradient fills.
*
* @defaultValue 1.0
*/
public final double getRadius() {
return radius;
}
private boolean proportional;
/**
* Indicates whether the center and radius values are proportional or
* absolute.
* If this flag is true, the center point and radius are defined
* in a coordinate space where coordinates in the range {@code [0..1]}
* are scaled to map onto the bounds of the shape that the gradient fills.
* If this flag is false, then the center coordinates and the radius are
* specified in the local coordinate system of the node.
*
* @defaultValue true
*/
public final boolean isProportional() {
return proportional;
}
private CycleMethod cycleMethod;
/**
* Defines which of the follwing cycle method is applied
* to the {@code LinearGradient}: {@code CycleMethod.NO_CYCLE},
* {@code CycleMethod.REFLECT}, or {@code CycleMethod.REPEAT}.
*
* @defaultValue NO_CYCLE
*/
public final CycleMethod getCycleMethod() {
return cycleMethod;
}
private ListEach stop in the sequence must have an offset that is greater than the previous * stop in the sequence.
* *The list is unmodifiable and will throw * {@code UnsupportedOperationException} on each modification attempt.
* * @defaultValue empty */ @ReturnsUnmodifiableCollection public final ListThe format of the string representation is based on * JavaFX CSS specification for radial gradient which is *
* radial-gradient([focus-angle <angle>, ]? * [focus-distance <percentage>, ]? * [center <point>, ]? * radius [<length> | <percentage>], * [[repeat | reflect],]? * <color-stop>[, <color-stop>]+) ** where *
* <point> = [ [ <length> <length> ] | [ <percentage> | <percentage> ] ] * <color-stop> = [ <color> [ <percentage> | <length>]? ] ** *
Currently length can be only specified in px, the specification of unit can be omited. * Format of color representation is the one used in {@link Color#web(String color)}. * The radial-gradient keyword can be omited. * For additional information about the format of string representation, see the * CSS Reference Guide. *
* * Examples: *
* RadialGradient g
* = RadialGradient.valueOf("radial-gradient(center 100px 100px, radius 200px, red 0%, blue 30%, black 100%)");
* RadialGradient g
* = RadialGradient.valueOf("center 100px 100px, radius 200px, red 0%, blue 30%, black 100%");
* RadialGradient g
* = RadialGradient.valueOf("radial-gradient(center 50% 50%, radius 50%, cyan, violet 75%, magenta)");
* RadialGradient g
* = RadialGradient.valueOf("center 50% 50%, radius 50%, cyan, violet 75%, magenta");
*
*
* @param value the string to convert
* @throws NullPointerException if the {@code value} is {@code null}
* @throws IllegalArgumentException if the {@code value} cannot be parsed
* @return a {@code RadialGradient} object holding the value represented
* by the string argument.
* @since JavaFX 2.1
*/
public static RadialGradient valueOf(String value) {
if (value == null) {
throw new NullPointerException("gradient must be specified");
}
String start = "radial-gradient(";
String end = ")";
if (value.startsWith(start)) {
if (!value.endsWith(end)) {
throw new IllegalArgumentException("Invalid gradient specification,"
+ " must end with \"" + end + '"');
}
value = value.substring(start.length(), value.length() - end.length());
}
GradientUtils.Parser parser = new GradientUtils.Parser(value);
if (parser.getSize() < 2) {
throw new IllegalArgumentException("Invalid gradient specification");
}
double angle = 0, distance = 0;
GradientUtils.Point centerX, centerY, radius;
String[] tokens = parser.splitCurrentToken();
if ("focus-angle".equals(tokens[0])) {
GradientUtils.Parser.checkNumberOfArguments(tokens, 1);
angle = GradientUtils.Parser.parseAngle(tokens[1]);
parser.shift();
}
tokens = parser.splitCurrentToken();
if ("focus-distance".equals(tokens[0])) {
GradientUtils.Parser.checkNumberOfArguments(tokens, 1);
distance = GradientUtils.Parser.parsePercentage(tokens[1]);
parser.shift();
}
tokens = parser.splitCurrentToken();
if ("center".equals(tokens[0])) {
GradientUtils.Parser.checkNumberOfArguments(tokens, 2);
centerX = parser.parsePoint(tokens[1]);
centerY = parser.parsePoint(tokens[2]);
parser.shift();
} else {
centerX = GradientUtils.Point.MIN;
centerY = GradientUtils.Point.MIN;
}
tokens = parser.splitCurrentToken();
if ("radius".equals(tokens[0])) {
GradientUtils.Parser.checkNumberOfArguments(tokens, 1);
radius = parser.parsePoint(tokens[1]);
parser.shift();
} else {
throw new IllegalArgumentException("Invalid gradient specification: "
+ "radius must be specified");
}
CycleMethod method = CycleMethod.NO_CYCLE;
String currentToken = parser.getCurrentToken();
if ("repeat".equals(currentToken)) {
method = CycleMethod.REPEAT;
parser.shift();
} else if ("reflect".equals(currentToken)) {
method = CycleMethod.REFLECT;
parser.shift();
}
Stop[] stops = parser.parseStops(radius.proportional, radius.value);
return new RadialGradient(angle, distance, centerX.value, centerY.value,
radius.value, radius.proportional, method, stops);
}
}