/*
* @(#)PaletteSwatchesChooser.java
*
* Copyright (c) 2010 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.gui.plaf.palette.colorchooser;
import edu.umd.cs.findbugs.annotations.Nullable;
import java.awt.Color;
import java.util.Collections;
import java.util.LinkedList;
import javax.swing.Icon;
import javax.swing.ListModel;
import javax.swing.colorchooser.AbstractColorChooserPanel;
import javax.swing.event.ListSelectionEvent;
import javax.swing.event.ListSelectionListener;
import javax.swing.plaf.ListUI;
import org.jhotdraw.color.HSBColorSpace;
import org.jhotdraw.gui.plaf.palette.PaletteListUI;
import org.jhotdraw.gui.plaf.palette.PaletteLookAndFeel;
import org.jhotdraw.gui.plaf.palette.PalettePanelUI;
import org.jhotdraw.util.ResourceBundleUtil;
/**
* PaletteSwatchesChooser.
*
* @author Werner Randelshofer
* @version $Id$
*/
public class PaletteSwatchesChooser extends AbstractColorChooserPanel {
private static final long serialVersionUID = 1L;
private int updateRecursion = 0;
/**
* HSB color palette with a set of colors chosen based on a physical criteria.
* <p>
* This is a 'human friendly' color palette which arranges the color in a
* way that makes it easy for humans to select the desired
* color. The colors are ordered in a way which minimizes the color contrast
* effect in the human visual system.
* <p>
* This palette has 12 columns and 10 rows.
* <p>
* The topmost row contains a null-color and a gray scale from white to
* black in 10 percent steps.
* <p>
* The remaining rows contain colors taken from the outer hull of the HSB
* color model:
* <p>
* The columns are ordered by hue starting with red - the lowest wavelength -
* and ending with purple - the highest wavelength. There are 12 different
* hues, so that all primary colors with their additive complements can be
* selected.
* <p>
* The rows are orderd by brightness with the brightest color at the top (sky)
* and the darkest color at the bottom (earth).
* The first 5 rows contain colors with maximal brightness and a saturation
* ranging form 20% up to 100%. The remaining 4 rows contain colors with
* maximal saturation and a brightness ranging from 90% to 20% (this also
* makes for a range from 100% to 20% if the 5th row is taken into account).
*/
private static final java.util.List<ColorIcon> HSB_COLORS;
private static final int HSB_COLORS_COLUMN_COUNT = 12;
/**
* This is the same palette as HSB_COLORS, but all color values are
* specified in the sRGB color space.
*/
private static final java.util.List<ColorIcon> HSB_COLORS_AS_RGB;
private static final int HSB_COLORS_AS_RGB_COLUMN_COUNT = 12;
static {
// FIXME - Move this into a lazy initializer
HSBColorSpace hsbCS = HSBColorSpace.getInstance();
LinkedList<ColorIcon> m = new LinkedList<ColorIcon>();
ResourceBundleUtil labels = ResourceBundleUtil.getBundle("org.jhotdraw.gui.Labels");
for (int s = 2; s <= 8; s += 2) {
for (int h = 0; h < 12; h++) {
Color c = new Color(hsbCS, new float[]{(h) / 12f, s * 0.1f, 1f}, 1f);
m.add(new ColorIcon(c,//
labels.getFormatted("ColorChooser.colorSwatch.hsbComponents.toolTipText", h * 360 / 12, s * 10, 100)));
}
}
for (int b = 10; b >= 2; b -= 2) {
for (int h = 0; h < 12; h++) {
Color c = new Color(hsbCS, new float[]{(h) / 12f, 1f, b * 0.1f}, 1f);
m.add(new ColorIcon(new Color(hsbCS, new float[]{(h) / 12f, 1f, b * 0.1f}, 1f),//
labels.getFormatted("ColorChooser.colorSwatch.hsbComponents.toolTipText", h * 360 / 12, 100, b * 10)));
}
}
m.add(new ColorIcon(new Color(0, true), labels.getToolTipTextProperty("ColorChooser.colorSwatch.noColor")));
HSB_COLORS = Collections.unmodifiableList(m);
m = new LinkedList<ColorIcon>();
for (ColorIcon ci : HSB_COLORS) {
if (ci.getColor() == null) {
m.add(new ColorIcon(new Color(0, true), labels.getToolTipTextProperty("ColorChooser.colorSwatch.noColor")));
} else {
Color c = ci.getColor();
m.add(new ColorIcon(c,//
labels.getFormatted("ColorChooser.colorSwatch.rgbComponents.toolTipText", c.getRed(), c.getGreen(), c.getBlue())));
}
}
HSB_COLORS_AS_RGB = Collections.unmodifiableList(m);
}
/** Creates new form PaletteSwatchesChooser */
public PaletteSwatchesChooser() {
}
/** 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.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
private void initComponents() {
jList = new javax.swing.JList();
setBorder(javax.swing.BorderFactory.createEmptyBorder(4, 6, 6, 6));
setLayout(new java.awt.GridBagLayout());
jList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
jList.setLayoutOrientation(javax.swing.JList.VERTICAL_WRAP);
add(jList, new java.awt.GridBagConstraints());
}// </editor-fold>//GEN-END:initComponents
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JList jList;
// End of variables declaration//GEN-END:variables
@Override
public void updateChooser() {
if (updateRecursion++ == 0) {
ListModel m = jList.getModel();
Color mc = getColorFromModel();
if (mc != null) {
int ma = mc.getAlpha();
int mr = mc.getRed();
int mg = mc.getGreen();
int mb = mc.getBlue();
int closestSquaredDistance = Integer.MAX_VALUE;
int closestIndex = -1;
for (int i = 0, n = m.getSize(); i < n; i++) {
ColorIcon item = (ColorIcon) m.getElementAt(i);
Color ic = item==null?null:item.getColor();
int squaredDistance;
if (ic == null||ic.getAlpha()!=ma) {
squaredDistance = Integer.MAX_VALUE;
} else {
squaredDistance = (mr - ic.getRed()) * (mr - ic.getRed())
+ (mg - ic.getGreen()) * (mg - ic.getGreen())
+ (mb - ic.getBlue()) * (mb - ic.getBlue());
}
if (squaredDistance <= closestSquaredDistance) {
closestSquaredDistance = squaredDistance;
closestIndex = i;
if (squaredDistance == 0) {
break;
}
}
}
if (closestIndex == -1) {
jList.clearSelection();
} else {
jList.setSelectedIndex(closestIndex);
}
}
}
updateRecursion--;
}
@Override
public String getDisplayName() {
return PaletteLookAndFeel.getInstance().getString("ColorChooser.colorSwatches");
}
@Override
public Icon getSmallDisplayIcon() {
return PaletteLookAndFeel.getInstance().getIcon("ColorChooser.colorSwatchesIcon");
}
@Override
public Icon getLargeDisplayIcon() {
return getSmallDisplayIcon();
}
@Override
protected void buildChooser() {
initComponents();
setUI(PalettePanelUI.createUI(this));
jList.setUI((ListUI) PaletteListUI.createUI(jList));
Object[] byRows=HSB_COLORS_AS_RGB.toArray();
Object[] byColumns=new Object[byRows.length];
for (int y=0,my=byRows.length/HSB_COLORS_AS_RGB_COLUMN_COUNT;y<my;y++) {
for (int x=0;x< HSB_COLORS_AS_RGB_COLUMN_COUNT;x++) {
if (x*my+y<byColumns.length)
byColumns[x*my+y]=byRows[y*HSB_COLORS_AS_RGB_COLUMN_COUNT+x];
}
}
byColumns[byColumns.length-1]=byRows[byRows.length-1];
jList.setListData(byColumns);
jList.setVisibleRowCount(HSB_COLORS_AS_RGB.size() / HSB_COLORS_AS_RGB_COLUMN_COUNT);
jList.addListSelectionListener(new ListSelectionListener() {
@Override
public void valueChanged(ListSelectionEvent e) {
if (updateRecursion++ == 0) {
ColorIcon item = (ColorIcon) jList.getSelectedValue();
setColorToModel(item == null ? null : item.getColor());
}
updateRecursion--;
}
});
}
public void setColorToModel(@Nullable Color color) {
getColorSelectionModel().setSelectedColor(color);
}
}