/** * @(#)JHarmonicColorWheel.java * * Copyright (c) 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 java.awt.*; import java.awt.color.ColorSpace; import java.awt.event.*; import java.awt.geom.*; import java.beans.*; import javax.swing.event.*; /** * JHarmonicColorWheel. * * FIXME - This is an experimental class. Do not use it. * * @author Werner Randelshofer * @version $Id$ */ public class JHarmonicColorWheel extends JColorWheel { private static final long serialVersionUID = 1L; public static final String SELECTED_INDEX_PROPERTY = "selectedIndex"; private HarmonicColorModel harmonicModel; private int selectedIndex = -1; private float handleRadius = 4f; private float baseRadius = 7f; private class MouseHandler implements MouseListener, MouseMotionListener { @Override public void mouseClicked(MouseEvent e) { } @Override public void mouseDragged(MouseEvent e) { update(e); } @Override public void mouseEntered(MouseEvent e) { } @Override public void mouseExited(MouseEvent e) { } @Override public void mouseMoved(MouseEvent e) { } @Override public void mousePressed(MouseEvent e) { int x = e.getX(); int y = e.getY(); int closestIndex = -1; if (harmonicModel != null && harmonicModel.size() > 0) { int closestError = Integer.MAX_VALUE; for (int i = 0, n = harmonicModel.size(); i < n; i++) { Color c = harmonicModel.get(i); if (c != null) { Point p = getColorLocation(harmonicModel.get(i)); int error = (p.x - x) * (p.x - x) + (p.y - y) * (p.y - y); if (error < closestError) { closestIndex = i; closestError = error; } } } if (closestIndex != -1) { if (closestError > 20) { closestIndex = -1; } } } setSelectedIndex(closestIndex); } @Override public void mouseReleased(MouseEvent e) { //update(e); } private void update(MouseEvent e) { if (selectedIndex != -1) { float[] hsb = getColorAt(e.getX(), e.getY()); hsb[1] = harmonicModel.get(selectedIndex).getColorComponents(null)[1]; //if (hsb != null) { harmonicModel.set(selectedIndex, new Color(harmonicModel.getColorSpace(), hsb, 1f)); //} repaint(); } } } private MouseHandler mouseHandler; private class ModelHandler implements PropertyChangeListener, ListDataListener { @Override public void propertyChange(PropertyChangeEvent evt) { String name = evt.getPropertyName(); if (name == HarmonicColorModel.COLOR_SPACE_PROPERTY) { model.setColorSpace(harmonicModel.getColorSpace()); model.setComponent(1, 1f); colorWheelProducer = createWheelProducer(getWidth(), getHeight()); colorWheelImage = null; } repaint(); } @Override public void intervalAdded(ListDataEvent e) { repaint(); } @Override public void intervalRemoved(ListDataEvent e) { repaint(); } @Override public void contentsChanged(ListDataEvent e) { repaint(); } } private ModelHandler modelHandler; /** Creates new form. */ public JHarmonicColorWheel() { super(HSLPhysiologicColorSpace.getInstance()); initComponents(); setRadialComponentIndex(2); setVerticalComponentIndex(1); getModel().setComponent(1, 1f); setWheelInsets(new Insets(5, 5, 5, 5)); modelHandler = new ModelHandler(); DefaultHarmonicColorModel p = new DefaultHarmonicColorModel(); setHarmonicColorModel(p); setToolTipText(""); } public void setColorSpace(ColorSpace newValue) { harmonicModel.setColorSpace(newValue); getModel().setColorSpace(newValue); getModel().setComponent(1, 1f); } public HarmonicColorModel getHarmonicColorModel() { return harmonicModel; } @Override public String getToolTipText(MouseEvent evt) { float[] hsb = getColorAt(evt.getX(), evt.getY()); if (hsb == null) { return null; } StringBuilder buf = new StringBuilder(); buf.append(Math.round(hsb[0] * 360)); buf.append(","); buf.append(Math.round(hsb[1] * 100f)); buf.append(","); buf.append(Math.round(hsb[2] * 100f)); if (buf.length() > 0) { buf.insert(0, "<html>"); return buf.toString(); } else { return null; } } @Override protected void installMouseListeners() { mouseHandler = new MouseHandler(); addMouseListener(mouseHandler); addMouseMotionListener(mouseHandler); } public void setHarmonicColorModel(HarmonicColorModel newValue) { HarmonicColorModel oldValue = harmonicModel; if (oldValue != null) { oldValue.removePropertyChangeListener(modelHandler); oldValue.removeListDataListener(modelHandler); } harmonicModel = newValue; if (newValue != null) { newValue.addPropertyChangeListener(modelHandler); newValue.addListDataListener(modelHandler); colorWheelProducer = createWheelProducer(getWidth(), getHeight()); } } @Override public void paintComponent(Graphics gr) { Graphics2D g = (Graphics2D) gr; g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); super.paintComponent(g); } @Override protected void paintThumb(Graphics2D g) { paintTicks(g); if (harmonicModel != null) { Point center = getCenter(); Ellipse2D.Float oval = new Ellipse2D.Float(0, 0, 0, 0); float[] comp = null; for (int i = harmonicModel.size() - 1; i >= 0; i--) { if (harmonicModel.get(i) != null) { Point p = getColorLocation(harmonicModel.get(i)); g.setColor(Color.black); g.drawLine(center.x, center.y, p.x, p.y); } } for (int i = harmonicModel.size() - 1; i >= 0; i--) { if (harmonicModel.get(i) != null) { Point p = getColorLocation(harmonicModel.get(i)); Color mixerColor = harmonicModel.get(i); comp = ColorUtil.fromColor(harmonicModel.getColorSpace(),mixerColor); if (i == selectedIndex) { g.setColor(Color.white); oval.x = p.x - baseRadius; oval.y = p.y - baseRadius; oval.width = baseRadius * 2f; oval.height = baseRadius * 2f; g.fill(oval); } g.setColor(mixerColor); oval.x = p.x - handleRadius; oval.y = p.y - handleRadius; oval.width = handleRadius * 2f; oval.height = handleRadius * 2f; g.fill(oval); g.setColor(Color.black); g.draw(oval); if (i == harmonicModel.getBase()) { oval.x = p.x - baseRadius; oval.y = p.y - baseRadius; oval.width = baseRadius * 2f; oval.height = baseRadius * 2f; g.draw(oval); } // g.drawString(i+"", p.x, p.y); } } } } protected void paintTicks(Graphics2D g) { if (true) return; if (harmonicModel != null) { Point center = getCenter(); float radius = getRadius(); Ellipse2D.Float oval = new Ellipse2D.Float(0, 0, 0, 0); int baseIndex = harmonicModel.getBase(); Color bc = harmonicModel.get(baseIndex); g.setColor(Color.DARK_GRAY); for (int i = 0; i < 12; i++) { float angle = bc.getColorComponents(null)[0] + i / 12f; float radial1 = radius; /*g.draw(new Line2D.Double( center.x + radius * Math.cos(angle * Math.PI * 2d), center.y - radius * Math.sin(angle * Math.PI * 2d), center.x + (radius + 2) * Math.cos(angle * Math.PI * 2d), center.y - (radius + 2) * Math.sin(angle * Math.PI * 2d))); */ g.fill(new Ellipse2D.Double( center.x + (radius+2) * Math.cos(angle * Math.PI * 2d)-2, center.y - (radius+2) * Math.sin(angle * Math.PI * 2d)-2, 4, 4)); } for (int i = 0, n = harmonicModel.size(); i < n; i++) { if (i != baseIndex) { Color dc = harmonicModel.get(i); if (dc != null) { float angle = dc.getColorComponents(null)[0]; float diff = Math.abs(angle - bc.getColorComponents(null)[0]) * 12; if (Math.abs(diff - Math.round(diff)) < 0.02f) { g.draw(new Line2D.Double( center.x + (radius + 6) * Math.cos(angle * Math.PI * 2d), center.y - (radius + 6) * Math.sin(angle * Math.PI * 2d), center.x + (radius - 2) * Math.cos(angle * Math.PI * 2d), center.y - (radius - 2) * Math.sin(angle * Math.PI * 2d))); } else { g.draw(new Line2D.Double( center.x + (radius) * Math.cos(angle * Math.PI * 2d), center.y - (radius) * Math.sin(angle * Math.PI * 2d), center.x + (radius - 1) * Math.cos(angle * Math.PI * 2d), center.y - (radius - 1) * Math.sin(angle * Math.PI * 2d))); } } } } } } public void setSelectedIndex(int newValue) { int oldValue = selectedIndex; selectedIndex = newValue; firePropertyChange(SELECTED_INDEX_PROPERTY, oldValue, newValue); repaint(); } public int getSelectedIndex() { return selectedIndex; } @Override protected Point getColorLocation(Color c) { Point p = colorWheelProducer.getColorLocation(c); p.x += wheelInsets.left; p.y += wheelInsets.top; return p; } /** 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.FlowLayout()); }// </editor-fold>//GEN-END:initComponents // Variables declaration - do not modify//GEN-BEGIN:variables // End of variables declaration//GEN-END:variables }