/* Copyright (C) 2005-2011 Fabio Riccardi */
package com.lightcrafts.ui.operation.colorbalance;
import com.lightcrafts.ui.layout.Box;
import com.lightcrafts.ui.toolkit.DropperButton;
import com.lightcrafts.ui.swing.ColorSwatch;
import javax.swing.*;
import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
/**
* A JComponent that renders a circular color picker and provides a facility
* to convert Points (for instance, from MouseEvents) into Colors.
*/
class ColorWheel extends JComponent {
// The currently picked Color, or null if no Color has been picked.
private Color picked;
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
Color getPickedColor() {
return picked;
}
void pickColor(Color color) {
picked = color;
repaint();
}
// Determine the size of the wheel, in screen coordinates.
private int getWheelSize() {
Dimension size = getSize();
return Math.min(size.width, size.height);
}
// Determine the centerpoint of the wheel, in screen coordinates.
private Point2D getWheelCenter() {
Dimension size = getSize();
return new Point2D.Double(size.width / 2, size.height / 2);
}
// Compute distance from the wheel center, in internal coordinates.
private double getRadius(Point p) {
Point2D center = getWheelCenter();
int size = getWheelSize();
double x = 2 * (p.x + .5 - center.getX()) / (double) size;
double y = 2 * (p.y + .5 - center.getY()) / (double) size;
return Math.sqrt(x * x + y * y);
}
private double getAngle(Point p) {
Point2D center = getWheelCenter();
double x = p.x + .5 - center.getX();
double y = p.y + .5 - center.getY();
return Math.atan2(y, - x);
}
Color pointToColor(Point p) {
return pointToColor(p, true);
}
// Note: the 2.2 and 1.2 magic constants make sure that the picked point stays inside the color wheel
Color pointToColor(Point p, boolean linear) {
double r = getRadius(p);
double theta = getAngle(p);
r = Math.min(r, 1);
float hue = (1 + (float) (theta / Math.PI)) / 2f;
float saturation = linear ? (float) r : (float) Math.min(1.1 * (r * r), 1); // non linearity for reduced sensitivity
float brightness = 1;
Color color = new Color(Color.HSBtoRGB(hue, saturation, brightness));
if (r <= .97 || !linear)
return color;
// Some alpha blending at the edge, for antialiasing:
float alpha = (float) Math.max(0, 33.3 * (1d - r));
float[] comps = color.getRGBComponents(null);
return new Color(comps[0], comps[1], comps[2], alpha);
}
Point colorToPoint(Color c) {
return colorToPoint(c, true);
}
Point colorToPoint(Color c, boolean linear) {
float[] hsb = Color.RGBtoHSB(
c.getRed(), c.getGreen(), c.getBlue(), null
);
float hue = hsb[0];
float saturation = hsb[1];
double r = linear ? saturation : Math.sqrt(saturation); // non linearity for reduced sensitivity
double theta = Math.PI * (2 * hue - 1);
Point2D center = getWheelCenter();
double radius = getWheelSize() / (linear ? 2 : 2.1);
int x = (int) Math.round(center.getX() - radius * r * Math.cos(theta));
int y = (int) Math.round(center.getY() + radius * r * Math.sin(theta));
return new Point(x, y);
}
private BufferedImage wheelImage = null;
protected void paintComponent(Graphics graphics) {
Graphics2D g = (Graphics2D) graphics;
Point2D center = getWheelCenter();
double radius = getWheelSize() / 2;
int minX = (int) Math.round(center.getX() - radius);
int maxX = (int) Math.round(center.getX() + radius);
int minY = (int) Math.round(center.getY() - radius);
int maxY = (int) Math.round(center.getY() + radius);
if (wheelImage == null) {
wheelImage = new BufferedImage((int) (2*radius), (int) (2*radius), BufferedImage.TYPE_INT_ARGB);
Graphics2D gg = wheelImage.createGraphics();
/* Shape circle = new Ellipse2D.Double(minX, minY, 2 * radius, 2 * radius);
gg.setClip(circle); */
for (int x=minX; x<=maxX; x++) {
for (int y=minY; y<=maxY; y++) {
Point p = new Point(x, y);
Color color = pointToColor(p);
gg.setColor(color);
gg.fillRect((int) (x - center.getX() + radius), (int) (y - center.getY() + radius), 1, 1);
}
}
gg.dispose();
}
g.drawImage(wheelImage, null, (int) (center.getX() - radius), (int) (center.getY() - radius));
if (picked != null) {
Point p = colorToPoint(picked, false);
g.setColor(Color.black);
g.drawRect(p.x - 2, p.y - 2, 3, 3);
}
}
public static void main(String[] args) {
ColorWheel wheel = new ColorWheel();
ColorWheelMouseListener listener = new ColorWheelMouseListener(wheel) {
void colorPicked(Color color, boolean isChanging) {
System.out.println(color);
}
};
wheel.addMouseListener(listener);
wheel.addMouseMotionListener(listener);
Box colorContent = Box.createHorizontalBox();
colorContent.add(wheel);
colorContent.add(Box.createHorizontalStrut(8));
colorContent.add(new ColorSwatch(Color.gray));
colorContent.add(Box.createHorizontalStrut(8));
colorContent.add(new ColorText(Color.gray));
colorContent.add(Box.createHorizontalStrut(8));
colorContent.add(new DropperButton());
colorContent.setBorder(BorderFactory.createEmptyBorder(3, 3, 3, 3));
JFrame frame = new JFrame("Test");
frame.setContentPane(colorContent);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}