/*
* @(#)JColorWheel.java
*
* Copyright (c) 2007-2008 The authors and contributors of JHotDraw.
* You may not use, copy or modify this file, except in compliance with the
* accompanying license terms.
*/
package org.jhotdraw.color;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
/**
* The {@code JColorWheel} displays a wheel made of two components of a
* {@code ColorSpace}.
* <p>
* The user can click at the wheel to pick a color.
* <p>
* The {@code JColorWheel} should be used together with a color slider for the
* remaining color component(s) of the color system.
*
* @author Werner Randelshofer
* @version $Id$
*/
public class JColorWheel extends JPanel {
private static final long serialVersionUID = 1L;
private boolean isFlipX, isFlipY;
public enum Type {
POLAR,
SQUARE,
DISK,
COMPLEX;
}
private Type type = Type.POLAR;
private ColorSpace sys;
protected Insets wheelInsets;
@Nullable protected Image colorWheelImage;
protected AbstractColorWheelImageProducer colorWheelProducer;
protected ColorSliderModel model;
/** Radial color component index. */
protected int radialIndex = 1;
/** Angular color component index. */
protected int angularIndex = 0;
/** Vertical color component index. */
protected int verticalIndex = 2;
private class MouseHandler extends MouseAdapter implements MouseMotionListener {
@Override
public void mouseDragged(MouseEvent e) {
update(e);
}
@Override
public void mousePressed(MouseEvent e) {
update(e);
}
@Override
public void mouseReleased(MouseEvent e) {
update(e);
}
private void update(MouseEvent e) {
float[] hsb = getColorAt(e.getX(), e.getY());
model.setComponent(angularIndex, hsb[angularIndex]);
model.setComponent(radialIndex, hsb[radialIndex]);
// FIXME - We should only repaint the damaged area
repaint();
}
}
private MouseHandler mouseHandler;
private class ModelHandler implements ChangeListener {
@Override
public void stateChanged(ChangeEvent e) {
repaint();
}
}
private ModelHandler modelHandler;
/**
* Creates a new instance.
*/
public JColorWheel() {
this(HSBColorSpace.getInstance());
}
public JColorWheel(ColorSpace sys) {
this.sys = sys;
wheelInsets = new Insets(0, 0, 0, 0);
model = new DefaultColorSliderModel(sys);
initComponents();
colorWheelProducer = createWheelProducer(0, 0);
modelHandler = new ModelHandler();
model.addChangeListener(modelHandler);
installMouseListeners();
setOpaque(false);
}
public void setType(Type type) {
this.type = type;
colorWheelProducer = createWheelProducer(0, 0);
}
protected void installMouseListeners() {
mouseHandler = new MouseHandler();
addMouseListener(mouseHandler);
addMouseMotionListener(mouseHandler);
}
public void setModel(ColorSliderModel m) {
if (model != null) {
model.removeChangeListener(modelHandler);
}
model = m;
if (model != null) {
model.addChangeListener(modelHandler);
colorWheelProducer = createWheelProducer(getWidth(), getHeight());
repaint();
}
}
public void setRadialComponentIndex(int newValue) {
radialIndex = newValue;
colorWheelImage = null;
repaint();
}
public void setAngularComponentIndex(int newValue) {
angularIndex = newValue;
colorWheelImage = null;
repaint();
}
public void setVerticalComponentIndex(int newValue) {
verticalIndex = newValue;
colorWheelImage = null;
repaint();
}
public void setWheelInsets(Insets newValue) {
wheelInsets = newValue;
repaint();
}
public Insets getWheelInsets() {
return wheelInsets;
}
@Override
public Dimension getPreferredSize() {
return new Dimension(100, 100);
}
public ColorSliderModel getModel() {
return model;
}
@Override
public void paintComponent(Graphics gr) {
Graphics2D g = (Graphics2D) gr;
paintWheel(g);
paintThumb(g);
}
public void setFlipX(boolean newValue) {
isFlipX=newValue;
colorWheelProducer = createWheelProducer(0, 0);
}
public void setFlipY(boolean newValue) {
isFlipY=newValue;
colorWheelProducer = createWheelProducer(0, 0);
}
public boolean isFlipX() {
return isFlipX;
}
public boolean isFlipY() {
return isFlipY;
}
protected AbstractColorWheelImageProducer createWheelProducer(int w, int h) {
AbstractColorWheelImageProducer p;
switch (type) {
case POLAR:
default:
p = new PolarColorWheelImageProducer(model.getColorSpace(), w, h);
break;
case SQUARE:
p = new ColorSquareImageProducer(model.getColorSpace(), w, h, isFlipX, isFlipY);
break;
case DISK:
p = new DiskColorWheelImageProducer(model.getColorSpace(), w, h, isFlipX, isFlipY);
break;
case COMPLEX:
p = new ComplexColorWheelImageProducer(model.getColorSpace(), w, h, isFlipX, isFlipY);
break;
}
p.setAngularComponentIndex(angularIndex);
p.setRadialComponentIndex(radialIndex);
p.setVerticalComponentIndex(verticalIndex);
return p;
}
protected void paintWheel(Graphics2D g) {
int w = getWidth() - wheelInsets.left - wheelInsets.right;
int h = getHeight() - wheelInsets.top - wheelInsets.bottom;
if (colorWheelImage == null || colorWheelImage.getWidth(this) != w || colorWheelImage.getHeight(this) != h) {
if (colorWheelImage != null) {
colorWheelImage.flush();
}
colorWheelProducer = createWheelProducer(w, h);
colorWheelImage = createImage(colorWheelProducer);
}
colorWheelProducer.setVerticalValue(model.getComponent(verticalIndex));
if (colorWheelProducer.needsGeneration()) {
// To keep the UI responsive, we only perform the time consuming
// regeneration of the color track if we don't already have
// a latency of more than a 10th of a second on the most recent event.
long latency = System.currentTimeMillis() - EventQueue.getMostRecentEventTime();
if (latency > 100) {
repaint();
} else {
colorWheelProducer.regenerateColorWheel();
}
}
g.drawImage(colorWheelImage, wheelInsets.left, wheelInsets.top, this);
}
protected void paintThumb(Graphics2D g) {
Point p = getThumbLocation();
g.setColor(Color.white);
g.fillRect(p.x - 1, p.y - 1, 2, 2);
g.setColor(Color.black);
g.drawRect(p.x - 2, p.y - 2, 3, 3);
}
protected Point getCenter() {
int w = getWidth() - wheelInsets.left - wheelInsets.right;
int h = getHeight() - wheelInsets.top - wheelInsets.bottom;
return new Point(
wheelInsets.left + w / 2,
wheelInsets.top + h / 2);
}
protected float getRadius() {
return colorWheelProducer.getRadius();
}
protected Point getThumbLocation() {
return getColorLocation(model.getComponents());
}
protected Point getColorLocation(Color c) {
Point p = colorWheelProducer.getColorLocation(c);
p.x += wheelInsets.left;
p.y += wheelInsets.top;
return p;
}
protected Point getColorLocation(float[] components) {
Point p = colorWheelProducer.getColorLocation(components);
p.x += wheelInsets.left;
p.y += wheelInsets.top;
return p;
}
protected float[] getColorAt(int x, int y) {
float[] cc = colorWheelProducer.getColorAt(x - wheelInsets.left, y - wheelInsets.top);
return cc;
}
/** This method is called from within the constructor to
* initialize the form.
* WARNING: Do NOT modify this code. The content of this method is
* always regenerated by the Form Editor.
*/
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
setLayout(new java.awt.BorderLayout());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
// End of variables declaration//GEN-END:variables
}