components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/ColorUtil.java
changeset 827 0944d8c0158b
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/ColorUtil.java	Thu May 24 04:16:47 2012 -0400
@@ -0,0 +1,200 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+
+/*
+ * Copyright (c) 2009, 2012, Oracle and/or its affiliates. All rights reserved.
+ */
+
+package com.oracle.solaris.vp.util.swing;
+
+import java.awt.*;
+import javax.swing.*;
+
+public class ColorUtil {
+    //
+    // Static data
+    //
+
+    /**
+     * According to the java.awt.Component API, {@code null} should cause the
+     * background of a {@code Component} to be transparent.  But buttons and
+     * other components of some L∓Fs (<cough> metal <cough>)
+     * paint their own background in that case.  So a completely transparent
+     * color is provided here instead.
+     */
+    public static Color TRANSPARENT = new Color(0, 0, 0, 0);
+
+    //
+    // Static methods
+    //
+
+    /**
+     * Returns a color identicial to the given color but with a new alpha.
+     *
+     * @param	    c
+     *		    the subject color
+     *
+     * @param	    alpha
+     *		    the alpha setting
+     */
+    public static Color alpha(Color c, float alpha) {
+	float[] rgb = c.getRGBColorComponents(null);
+	return new Color(rgb[0], rgb[1], rgb[2], alpha);
+    }
+
+    /**
+     * Returns a darker version of the given color by the given factor.
+     * <p>
+     * Compared with {@code Color.darker()}, this method provides finer
+     * control over how much to darken the given color.
+     *
+     * @param	    c
+     *		    the subject color
+     *
+     * @param	    factor
+     *		    a number between 0 (no change) and 1 (resulting color will
+     *		    be black) inclusive
+     *
+     * @return	    a darker (closer to black) version of the given color
+     *
+     * @exception   IllegalArgumentException
+     *		    if factor is not betwee 0 and 1 inclusive
+     */
+    public static Color darker(Color c, float factor) {
+	return blend(c, Color.BLACK, factor);
+    }
+
+    public static double distance(Color c1, Color c2) {
+	float[] rgb1 = c1.getRGBColorComponents(null);
+	float[] rgb2 = c2.getRGBColorComponents(null);
+
+	double x = rgb2[0] - rgb1[0];
+	double y = rgb2[1] - rgb1[1];
+	double z = rgb2[2] - rgb1[2];
+
+	return Math.sqrt(x * x + y * y + z * z);
+    }
+
+    /**
+     * Blends the given colors by the given factor.
+     *
+     * @param	    cFrom
+     *		    the color to blend with cTo
+     *
+     * @param	    cTo
+     *		    the color to blend with cFrom
+     *
+     * @param	    factor
+     *		    a number between 0 (resulting color will be {@code cFrom})
+     *		    and 1 (resulting color will be {@code cTo}) inclusive, with
+     *		    .5 indicating an even blend between the two
+     *
+     * @return	    a blend of the given colors
+     *
+     * @exception   IllegalArgumentException
+     *		    if factor is not betwee 0 and 1 inclusive
+     */
+    public static Color blend(Color cFrom, Color cTo, float factor) {
+	if (factor < 0f || factor > 1f) {
+	    throw new IllegalArgumentException(
+		"factor not between 0 and 1: " + factor);
+	}
+
+	float[] rgbaFrom = cFrom.getRGBComponents(null);
+	float[] rgbaTo = cTo.getRGBComponents(null);
+
+	rgbaFrom[0] += (rgbaTo[0] - rgbaFrom[0]) * factor;
+	rgbaFrom[1] += (rgbaTo[1] - rgbaFrom[1]) * factor;
+	rgbaFrom[2] += (rgbaTo[2] - rgbaFrom[2]) * factor;
+
+	return new Color(rgbaFrom[0], rgbaFrom[1], rgbaFrom[2], rgbaFrom[3]);
+    }
+
+    public static Color getRandomColor() {
+	return new Color(
+	    (int)(Math.random() * 256),
+	    (int)(Math.random() * 256),
+	    (int)(Math.random() * 256));
+    }
+
+    /**
+     * Determines whether the given {@code Color} is more dark than light.
+     */
+    public static boolean isDark(Color c) {
+	double whiteDist = distance(c, Color.WHITE);
+	double blackDist = distance(c, Color.BLACK);
+
+	return whiteDist > blackDist;
+    }
+
+    /**
+     * Returns a lighter version of the given color by the given
+     * factor.
+     * <p>
+     * Compared with {@code Color.brighter()}, this method provides finer
+     * control over how much to lighten the given color.
+     * <p>
+     * Note: When {@code factor &gt; 0}, this method differs functionally from
+     * {@code Color.brighter()} - repeated invocations of the former for any
+     * color will eventually yield white, whereas the latter will just create a
+     * brighter version of the same color.  For "pure" colors (zero r, g, or b),
+     * repeated invocations of {@code Color.brighter()} will never yield white.
+     *
+     * @param	    c
+     *		    the subject color
+     *
+     * @param	    factor
+     *		    a number between 0 (no change) and 1 (resulting color will
+     *		    be white) inclusive
+     *
+     * @return	    a lighter (closer to white) version of the given color
+     *
+     * @exception   IllegalArgumentException
+     *		    if factor is not betwee 0 and 1 inclusive
+     */
+    public static Color lighter(Color c, float factor) {
+	return blend(c, Color.WHITE, factor);
+    }
+
+    public static void main(String args[]) {
+	Color color = Color.RED;
+	JPanel panel = new JPanel();
+	panel.setLayout(new GridLayout(0, 1, 5, 5));
+	for (int i = -10; i <= 10; i++) {
+	    float factor = (float)i / (float)10;
+	    Color lighter = i < 0 ?
+		darker(color, -factor) : lighter(color, factor);
+	    JLabel l = new JLabel(factor + ": " + lighter.toString());
+	    l.setBackground(lighter);
+	    l.setForeground(isDark(lighter) ? Color.WHITE : Color.BLACK);
+	    l.setOpaque(true);
+	    panel.add(l);
+	}
+
+	JFrame frame = new JFrame();
+	Container c = frame.getContentPane();
+	c.setLayout(new BorderLayout());
+	c.add(new JScrollPane(panel), BorderLayout.CENTER);
+	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
+	frame.pack();
+	frame.setVisible(true);
+    }
+}