Project: nodebox
package nodebox.client;
 
import nodebox.graphics.Color; 
 
import javax.swing.*; 
import javax.swing.event.ChangeEvent; 
import javax.swing.event.ChangeListener; 
import java.awt.*; 
import java.awt.event.MouseEvent; 
import java.awt.event.MouseListener; 
import java.awt.event.MouseMotionListener; 
import java.util.EventListener; 
 
public class ColorWell extends JComponent { 
 
    private Color color = new Color(); 
    private transient ClickHandler clickHandler = new ClickHandler(); 
    private transient ColorPicker colorPicker = new ColorPicker(); 
 
    /**
     * Only one <code>ChangeEvent</code> is needed per slider instance since the 
     * event's only (read-only) state is the source property.  The source 
     * of events generated here is always "this". The event is lazily 
     * created the first time that an event notification is fired. 
     * 
     * @see #fireStateChanged 
     */
 
    protected transient ChangeEvent changeEvent = null
 
    public ColorWell() { 
        setPreferredSize(new Dimension(4030)); 
        addMouseListener(clickHandler); 
        addMouseMotionListener(clickHandler); 
    } 
 
    @Override 
    public void paint(Graphics g) { 
        g.setColor(color.getAwtColor()); 
        Rectangle r = g.getClipBounds(); 
        g.fillRect(r.x, r.y, r.width, r.height); 
    } 
 
    public Color getColor() { 
        return color; 
    } 
 
    public void setColor(Color color) { 
        if (color.equals(this.color)) return
        this.color = color; 
        fireStateChanged(); 
        repaint(); 
    } 
 
    /**
     * Adds a ChangeListener to the slider. 
     * 
     * @param l the ChangeListener to add 
     * @see #fireStateChanged 
     * @see #removeChangeListener 
     */
 
    public void addChangeListener(ChangeListener l) { 
        listenerList.add(ChangeListener.class, l); 
    } 
 
 
    /**
     * Removes a ChangeListener from the slider. 
     * 
     * @param l the ChangeListener to remove 
     * @see #fireStateChanged 
     * @see #addChangeListener 
     */
 
    public void removeChangeListener(ChangeListener l) { 
        listenerList.remove(ChangeListener.class, l); 
    } 
 
 
    /**
     * Returns an array of all the <code>ChangeListener</code>s added 
     * to this JSlider with addChangeListener(). 
     * 
     * @return all of the <code>ChangeListener</code>s added or an empty 
     *         array if no listeners have been added 
     * @since 1.4 
     */
 
    public ChangeListener[] getChangeListeners() { 
        return (ChangeListener[]) listenerList.getListeners( 
                ChangeListener.class); 
    } 
 
    protected void fireStateChanged() { 
        if (changeEvent == null) { 
            changeEvent = new ChangeEvent(this); 
        } 
        for (EventListener l : listenerList.getListeners(ChangeListener.class)) { 
            ((ChangeListener) l).stateChanged(changeEvent); 
        } 
    } 
 
    private class ClickHandler implements MouseListener, MouseMotionListener { 
 
        private boolean isDragging; 
 
        public void mouseClicked(MouseEvent e) { 
        } 
 
        public void mouseReleased(MouseEvent e) { 
            if (isDragging) { 
                colorPicker.setVisible(false); 
            } 
            isDragging = false
        } 
 
        public void mouseEntered(MouseEvent e) { 
        } 
 
        public void mouseExited(MouseEvent e) { 
        } 
 
        public void mouseDragged(MouseEvent e) { 
            isDragging = true
            JComponent c = ColorWell.this
            Point pt = e.getPoint(); 
            JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(c); 
            pt = SwingUtilities.convertPoint(c, pt, frame.getContentPane()); 
            MouseEvent newEvent = new MouseEvent(colorPicker, e.getID(), e.getWhen(), e.getModifiers(), (int) pt.getX(), (int) pt.getY(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); 
            colorPicker.dispatchEvent(newEvent); 
        } 
 
        public void mouseMoved(MouseEvent e) { 
        } 
 
        public void mousePressed(MouseEvent e) { 
            isDragging = false
            JComponent c = ColorWell.this
            JFrame frame = (JFrame) SwingUtilities.getWindowAncestor(c); 
            if (frame == nullreturn
            Point pt = c.getLocation(); 
            pt = SwingUtilities.convertPoint(c, pt, frame.getContentPane()); 
            Rectangle r = c.getBounds(); 
            frame.setGlassPane(colorPicker); 
            colorPicker.setVisible(true); 
            colorPicker.setPoint(new Point(pt.x, pt.y + r.height)); 
            frame.validate(); 
        } 
    } 
 
    private java.awt.Color colorFromPoint(int x, int y) { 
        float h = x / 255.0F
        float s = 1.0F
        float b = 1.0F - (y / 100.0F); 
        return java.awt.Color.getHSBColor(h, s, b); 
    } 
 
    private class ColorPicker extends JComponent implements MouseListener, MouseMotionListener { 
 
        public Point point; 
        public Point dragPoint; 
        public Rectangle pickerRect; 
 
        private ColorPicker() { 
            addMouseListener(this); 
            addMouseMotionListener(this); 
        } 
 
        public void setPoint(Point point) { 
            this.point = point; 
            pickerRect = new Rectangle(point.x, point.y, 255100); 
        } 
 
        public void setDragPoint(Point dragPoint) { 
            this.dragPoint = dragPoint; 
            repaint(); 
            int x = dragPoint.x - point.x; 
            int y = dragPoint.y - point.y; 
            setColor(new Color(colorFromPoint(x, y))); 
        } 
 
        @Override 
        public void paint(Graphics g) { 
            if (point == nullreturn
            //Graphics2D g2 = (Graphics2D) g; 
            Rectangle r = g.getClipBounds(); 
            //g2.setColor(new java.awt.Color(30, 30, 30, 100)); 
            //g2.fillRect(r.x, r.y, r.width, r.height); 
            g.setColor(new java.awt.Color(200200200220)); 
            g.fillRect(pickerRect.x, pickerRect.y, pickerRect.width, pickerRect.height); 
 
            for (int y = 0; y < 100; y++) { 
                for (int x = 0; x < 255; x++) { 
                    g.setColor(colorFromPoint(x, y)); 
                    g.fillRect(pickerRect.x + x, pickerRect.y + y, 11); 
                } 
            } 
            if (dragPoint == nullreturn
            if (!pickerRect.contains(dragPoint)) return
        } 
 
 
        public void mouseClicked(MouseEvent e) { 
            if (pickerRect.contains(e.getPoint())) { 
                setDragPoint(e.getPoint()); 
            } 
            setVisible(false); 
        } 
 
        public void mouseDragged(MouseEvent e) { 
            setDragPoint(e.getPoint()); 
        } 
 
        public void mousePressed(MouseEvent e) { 
        } 
 
        public void mouseReleased(MouseEvent e) { 
            setVisible(false); 
        } 
 
        public void mouseEntered(MouseEvent e) { 
        } 
 
        public void mouseExited(MouseEvent e) { 
        } 
 
        public void mouseMoved(MouseEvent e) { 
        } 
 
    } 
}