Java tutorial
/* * Copyright (c) 2012, 2017, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. Oracle designates this * particular file as subject to the "Classpath" exception as provided * by Oracle in the LICENSE file that accompanied this code. * * This code is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA * or visit www.oracle.com if you need additional information or have any * questions. */ package javafx.scene.layout; import java.util.ArrayList; import java.util.Collections; import java.util.List; import javafx.beans.NamedArg; import javafx.scene.shape.StrokeLineCap; import javafx.scene.shape.StrokeLineJoin; import javafx.scene.shape.StrokeType; /** * Defines the style of the stroke to use on one side of a BorderStroke. There are * several predefined styles, although the properties of these predefined styles may * not match the settings used to ultimately draw them. Or you may create a new * BorderStrokeStyle and define each of the stroke settings manually, similar * to any {@link javafx.scene.shape.Shape}. * @since JavaFX 8.0 */ public final class BorderStrokeStyle { private static final List<Double> DOTTED_LIST = Collections.unmodifiableList(asList(0, 2)); private static final List<Double> DASHED_LIST = Collections.unmodifiableList(asList(2, 1.4)); /** * Indicates that no stroke should be drawn. */ public static final BorderStrokeStyle NONE = new BorderStrokeStyle(StrokeType.INSIDE, StrokeLineJoin.MITER, StrokeLineCap.BUTT, 0, 0, null); /** * A predefined dotted pattern to be used for stroking */ public static final BorderStrokeStyle DOTTED = new BorderStrokeStyle(StrokeType.INSIDE, StrokeLineJoin.MITER, StrokeLineCap.ROUND, 10, 0, DOTTED_LIST); /** * A predefined dashed pattern to be used for stroking */ public static final BorderStrokeStyle DASHED = new BorderStrokeStyle(StrokeType.INSIDE, StrokeLineJoin.MITER, StrokeLineCap.BUTT, 10, 0, DASHED_LIST); /** * A predefined solid line to be used for stroking */ public static final BorderStrokeStyle SOLID = new BorderStrokeStyle(StrokeType.INSIDE, StrokeLineJoin.MITER, StrokeLineCap.BUTT, 10, 0, null); /** * Defines the direction (inside, outside, or both) that the strokeWidth * is applied to the boundary of the shape. * * @return the the direction that the strokeWidth is applied to the boundary * of the shape * @defaultValue CENTERED */ public final StrokeType getType() { return type; } private final StrokeType type; /** * Defines the decoration applied where path segments meet. * The value must have one of the following values: * {@code StrokeLineJoin.BEVEL}, {@code StrokeLineJoin.MITER}, * and {@code StrokeLineJoin.ROUND}. * * @return the decoration applied where path segments meet * @defaultValue MITER */ public final StrokeLineJoin getLineJoin() { return lineJoin; } private final StrokeLineJoin lineJoin; /** * The end cap style of this {@code Shape} as one of the following * values that define possible end cap styles: * {@code StrokeLineCap.BUTT}, {@code StrokeLineCap.ROUND}, * and {@code StrokeLineCap.SQUARE}. * * @return the end cap style * @defaultValue SQUARE */ public final StrokeLineCap getLineCap() { return lineCap; } private final StrokeLineCap lineCap; /** * Defines the limit for the {@code StrokeLineJoin.MITER} line join style. * * @return the limit for the StrokeLineJoin.MITER line join style * @defaultValue 10 */ public final double getMiterLimit() { return miterLimit; } private final double miterLimit; /** * Defines a distance specified in user coordinates that represents * an offset into the dashing pattern. In other words, the dash phase * defines the point in the dashing pattern that will correspond * to the beginning of the stroke. * * @return the offset into the dashing pattern * @defaultValue 0 */ public final double getDashOffset() { return dashOffset; } private final double dashOffset; /** * Defines the array representing the lengths of the dash segments. * Alternate entries in the array represent the user space lengths * of the opaque and transparent segments of the dashes. * As the pen moves along the outline of the {@code Shape} to be stroked, * the user space distance that the pen travels is accumulated. * The distance value is used to index into the dash array. * The pen is opaque when its current cumulative distance maps * to an even element of the dash array and transparent otherwise. * An empty dashArray indicates a solid line with no spaces. * @return the array representing the lengths of the dash segments * @defaultValue empty */ public final List<Double> getDashArray() { return dashArray; } private final List<Double> dashArray; /** * A cached hash code */ private final int hash; /** * Creates a new BorderStrokeStyle. * * @param type The type of stroke, whether rendered OUTSIDE, INSIDE, or CENTERED on the * border line. If null, defaults to CENTERED. * @param lineJoin The line join. If null, defaults to MITER * @param lineCap The line cap. If null, defaults to BUTT. * @param miterLimit The miter limit. 10 is a good default value. * @param dashOffset The dashOffset. 0 is a good default value. * @param dashArray The dash array. If null, defaults to an empty list. */ public BorderStrokeStyle(@NamedArg("type") StrokeType type, @NamedArg("lineJoin") StrokeLineJoin lineJoin, @NamedArg("lineCap") StrokeLineCap lineCap, @NamedArg("miterLimit") double miterLimit, @NamedArg("dashOffset") double dashOffset, @NamedArg("dashArray") List<Double> dashArray) { this.type = (type != null) ? type : StrokeType.CENTERED; this.lineJoin = (lineJoin != null) ? lineJoin : StrokeLineJoin.MITER; this.lineCap = (lineCap != null) ? lineCap : StrokeLineCap.BUTT; this.miterLimit = miterLimit; this.dashOffset = dashOffset; if (dashArray == null) { this.dashArray = Collections.emptyList(); } else { if (dashArray == DASHED_LIST || dashArray == DOTTED_LIST) { // We want to use the SAME EXACT LIST in the case of DASHED_LIST or DOTTED_LIST // so that code in NGRegion can execute specialized code paths for such cases. this.dashArray = dashArray; } else { // Must not allow the passed in array to inadvertently mutate the // state of this BorderStrokeStyle! List<Double> list = new ArrayList<Double>(dashArray); this.dashArray = Collections.unmodifiableList(list); } } // Pre-compute the hash code. NOTE: all variables are prefixed with "this" so that we // do not accidentally compute the hash based on the constructor arguments rather than // based on the fields themselves! int result; long temp; result = this.type.hashCode(); // result = 31 * result + (this == NONE ? 0 : 1); // TODO OH NO. NONE hasn't been assigned yet. result = 31 * result + this.lineJoin.hashCode(); result = 31 * result + this.lineCap.hashCode(); temp = this.miterLimit != +0.0d ? Double.doubleToLongBits(this.miterLimit) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); temp = this.dashOffset != +0.0d ? Double.doubleToLongBits(this.dashOffset) : 0L; result = 31 * result + (int) (temp ^ (temp >>> 32)); result = 31 * result + this.dashArray.hashCode(); hash = result; } /** * {@inheritDoc} */ @Override public String toString() { if (this == NONE) { return "BorderStyle.NONE"; } else if (this == DASHED) { return "BorderStyle.DASHED"; } else if (this == DOTTED) { return "BorderStyle.DOTTED"; } else if (this == SOLID) { return "BorderStyle.SOLID"; } else { StringBuilder buffer = new StringBuilder(); buffer.append("BorderStyle: "); buffer.append(type); buffer.append(", "); buffer.append(lineJoin); buffer.append(", "); buffer.append(lineCap); buffer.append(", "); buffer.append(miterLimit); buffer.append(", "); buffer.append(dashOffset); buffer.append(", ["); if (dashArray != null) { buffer.append(dashArray); } buffer.append("]"); return buffer.toString(); } } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) return true; if ((this == NONE && o != NONE) || (o == NONE && this != NONE)) return false; if (o == null || getClass() != o.getClass()) return false; BorderStrokeStyle that = (BorderStrokeStyle) o; if (this.hash != that.hash) return false; if (Double.compare(that.dashOffset, dashOffset) != 0) return false; if (Double.compare(that.miterLimit, miterLimit) != 0) return false; if (!dashArray.equals(that.dashArray)) return false; if (lineCap != that.lineCap) return false; if (lineJoin != that.lineJoin) return false; if (type != that.type) return false; return true; } /** * {@inheritDoc} */ @Override public int hashCode() { return hash; } private static List<Double> asList(double... items) { List<Double> list = new ArrayList<Double>(items.length); for (int i = 0; i < items.length; i++) { list.add(items[i]); } return list; } }