/*
* Copyright (c) 2005-2016 Substance Kirill Grouchnikov. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* o Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* o Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* o Neither the name of Substance Kirill Grouchnikov nor the names of
* its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.pushingpixels.substance.internal.utils;
import java.awt.Component;
import java.awt.geom.Arc2D;
import java.awt.geom.GeneralPath;
import java.util.Set;
import org.pushingpixels.substance.api.SubstanceConstants.Side;
/**
* Provides common functionality that can be used by button shapers. This class
* is <b>for internal use only</b>.
*
* @author Kirill Grouchnikov
*/
public class SubstanceOutlineUtilities {
/**
* Returns basic outline for the specified component. The basic outline is a
* rectangle with rounded corners. Some corners may not be rounded based on
* the contents of <code>straightSide</code> parameter.
*
* @param comp
* Component.
* @param radius
* Corner radius.
* @param straightSides
* Contains all sides which are straight.
* @return The basic outline for the specified parameters.
*/
public static GeneralPath getBaseOutline(Component comp, float radius,
Set<Side> straightSides) {
int width = comp.getWidth();
int height = comp.getHeight();
return getBaseOutline(width, height, radius, straightSides);
}
/**
* Returns basic outline for the specified parameters. The basic outline is
* a rectangle with rounded corners. Some corners may not be rounded based
* on the contents of <code>straightSide</code> parameter.
*
* @param width
* Width of some UI component.
* @param height
* Height of some UI component.
* @param radius
* Corner radius.
* @param straightSides
* Contains all sides which are straight.
* @return The basic outline for the specified parameters.
*/
public static GeneralPath getBaseOutline(float width, float height,
float radius, Set<Side> straightSides) {
return getBaseOutline(width, height, radius, straightSides, 0.0f);
}
/**
* Returns basic outline for the specified parameters. The basic outline is
* a rectangle with rounded corners. Some corners may not be rounded based
* on the contents of <code>straightSides</code> parameter.
*
* @param width
* Width of some UI component.
* @param height
* Height of some UI component.
* @param radius
* Corner radius.
* @param straightSides
* Contains all sides which are straight.
* @param insets
* Shape insets.
* @return The basic outline for the specified parameters.
*/
public static GeneralPath getBaseOutline(float width, float height,
float radius, Set<Side> straightSides, float insets) {
boolean isTopLeftCorner = (straightSides != null)
&& (straightSides.contains(Side.LEFT) || straightSides
.contains(Side.TOP));
boolean isTopRightCorner = (straightSides != null)
&& (straightSides.contains(Side.RIGHT) || straightSides
.contains(Side.TOP));
boolean isBottomRightCorner = (straightSides != null)
&& (straightSides.contains(Side.RIGHT) || straightSides
.contains(Side.BOTTOM));
boolean isBottomLeftCorner = (straightSides != null)
&& (straightSides.contains(Side.LEFT) || straightSides
.contains(Side.BOTTOM));
float xs = insets;
float ys = insets;
width -= 2 * insets;
height -= 2 * insets;
GeneralPath result = new GeneralPath();
if (isTopLeftCorner || (radius <= 0.0f)) {
result.moveTo(xs, ys);
} else {
result.moveTo(xs + radius, ys);
}
if (isTopRightCorner || (radius <= 0.0f)) {
result.lineTo(xs + width, ys);
} else {
if (isTopLeftCorner || ((xs + width - radius) >= radius)) {
result.lineTo(xs + width - radius, ys);
}
result.append(new Arc2D.Double(xs + width - 2 * radius, ys,
2 * radius, 2 * radius, 90, -90, Arc2D.OPEN), true);
}
if (isBottomRightCorner || (radius <= 0.0f)) {
result.lineTo(xs + width, ys + height);
} else {
if (isTopRightCorner || ((ys + height - radius) >= radius)) {
result.lineTo(xs + width, ys + height - radius);
}
result.append(new Arc2D.Double(xs + width - 2 * radius,
ys + height - 2 * radius, 2 * radius, 2 * radius, 0, -90,
Arc2D.OPEN), true);
}
if (isBottomLeftCorner || (radius <= 0.0f)) {
result.lineTo(xs, ys + height);
} else {
if (isBottomRightCorner || ((xs + width - radius) >= radius)) {
result.lineTo(xs + radius, ys + height);
}
result.append(new Arc2D.Double(xs, ys + height - 2 * radius,
2 * radius, 2 * radius, 270, -90, Arc2D.OPEN), true);
}
if (isTopLeftCorner || (radius == 0.0f)) {
result.lineTo(xs, ys);
} else {
if (isBottomLeftCorner || ((ys + height - radius) >= radius)) {
result.lineTo(xs, ys + radius);
}
result.append(new Arc2D.Double(xs, ys, 2 * radius, 2 * radius, 180,
-90, Arc2D.OPEN), true);
}
return result;
}
/**
* Returns outline that has a triangle pointing downwards. The top two
* corners in the outline are rounded. This function can be used to draw
* slider thumbs.
*
* @param width
* Width of some UI component.
* @param height
* Height of some UI component.
* @param radius
* Corner radius for the top two corners.
* @param insets
* Insets to compute the outline.
* @return Outline that has a triangle poiting downwards.
*/
public static GeneralPath getTriangleButtonOutline(float width, float height,
float radius, float insets) {
float xs = insets;
float ys = insets + 1;
float xe = width - insets;
float ye = height - insets;
width -= 2 * insets;
height -= 2 * insets;
GeneralPath result = new GeneralPath();
float radius3 = (float) (radius / (1.5 * Math.pow(height, 0.5)));
if (Math.max(width, height) < 15)
radius3 /= 2;
result.moveTo(radius + xs, ys);
if ((xe - radius) >= radius) {
result.lineTo(xe - radius, ys);
}
result.quadTo(xe - radius3, ys + radius3, xe, ys + radius);
float h2 = (ye - 1.0f) / 2.0f;
if (h2 >= radius) {
result.lineTo(xe, h2);
}
result.lineTo((xs + xe) / 2.0f, ye - 1);
result.lineTo(xs, h2);
if (h2 >= radius) {
result.lineTo(xs, h2);
}
if ((height - radius - 1) >= radius) {
result.lineTo(xs, radius + ys);
}
result.quadTo(xs + radius3, ys + radius3, xs + radius, ys);
return result;
}
}