001/* 002 * $Id: JXColorSelectionButton.java 4082 2011-11-15 18:39:43Z kschaefe $ 003 * 004 * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle, 005 * Santa Clara, California 95054, U.S.A. All rights reserved. 006 * 007 * This library is free software; you can redistribute it and/or 008 * modify it under the terms of the GNU Lesser General Public 009 * License as published by the Free Software Foundation; either 010 * version 2.1 of the License, or (at your option) any later version. 011 * 012 * This library is distributed in the hope that it will be useful, 013 * but WITHOUT ANY WARRANTY; without even the implied warranty of 014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 015 * Lesser General Public License for more details. 016 * 017 * You should have received a copy of the GNU Lesser General Public 018 * License along with this library; if not, write to the Free Software 019 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 020 */ 021 022package org.jdesktop.swingx; 023 024import static java.awt.RenderingHints.KEY_ANTIALIASING; 025import static java.awt.RenderingHints.VALUE_ANTIALIAS_ON; 026 027import java.awt.Color; 028import java.awt.Dimension; 029import java.awt.Graphics; 030import java.awt.Graphics2D; 031import java.awt.Insets; 032import java.awt.event.ActionEvent; 033import java.awt.event.ActionListener; 034import java.awt.geom.Ellipse2D; 035import java.awt.image.BufferedImage; 036import java.beans.PropertyChangeEvent; 037import java.beans.PropertyChangeListener; 038 039import javax.imageio.ImageIO; 040import javax.swing.JButton; 041import javax.swing.JColorChooser; 042import javax.swing.JDialog; 043import javax.swing.event.ChangeEvent; 044import javax.swing.event.ChangeListener; 045 046import org.jdesktop.swingx.color.EyeDropperColorChooserPanel; 047import org.jdesktop.swingx.plaf.UIManagerExt; 048import org.jdesktop.swingx.util.GraphicsUtilities; 049import org.jdesktop.swingx.util.OS; 050import org.jdesktop.swingx.util.PaintUtils; 051 052/** 053 * A button which allows the user to select a single color. The button has a platform 054 * specific look. Ex: on Mac OS X it will mimic an NSColorWell. When the user 055 * clicks the button it will open a color chooser set to the current background 056 * color of the button. The new selected color will be stored in the background 057 * property and can be retrieved using the getBackground() method. As the user is 058 * choosing colors within the color chooser the background property will be updated. 059 * By listening to this property developers can make other parts of their programs 060 * update. 061 * 062 * @author joshua@marinacci.org 063 */ 064public class JXColorSelectionButton extends JButton { 065 private BufferedImage colorwell; 066 private JDialog dialog = null; 067 private JColorChooser chooser = null; 068 private Color initialColor = null; 069 070 /** 071 * Creates a new instance of JXColorSelectionButton 072 */ 073 public JXColorSelectionButton() { 074 this(Color.red); 075 } 076 077 /** 078 * Creates a new instance of JXColorSelectionButton set to the specified color. 079 * @param col The default color 080 */ 081 public JXColorSelectionButton(Color col) { 082 setBackground(col); 083 this.addActionListener(new ActionHandler()); 084 this.setContentAreaFilled(false); 085 this.setOpaque(false); 086 087 try { 088 colorwell = ImageIO.read(JXColorSelectionButton.class.getResourceAsStream("color/colorwell.png")); 089 } catch (Exception ex) { 090 ex.printStackTrace(); 091 } 092 093 this.addPropertyChangeListener("background",new PropertyChangeListener() { 094 public void propertyChange(PropertyChangeEvent propertyChangeEvent) { 095 getChooser().setColor(getBackground()); 096 } 097 }); 098 } 099 100 101 /** 102 * A listener class to update the button's background when the selected 103 * color changes. 104 */ 105 private class ColorChangeListener implements ChangeListener { 106 public JXColorSelectionButton button; 107 public ColorChangeListener(JXColorSelectionButton button) { 108 this.button = button; 109 } 110 public void stateChanged(ChangeEvent changeEvent) { 111 button.setBackground(button.getChooser().getColor()); 112 } 113 } 114 115 /** 116 * {@inheritDoc} 117 */ 118 @Override 119 protected void paintComponent(Graphics g) { 120 // want disabledForeground when disabled, current colour otherwise 121 final Color FILL_COLOR = isEnabled() ? PaintUtils.removeAlpha(getBackground()) 122 : UIManagerExt.getSafeColor("Button.disabledForeground", Color.LIGHT_GRAY); 123 124 // draw the colorwell image (should only be on OSX) 125 if(OS.isMacOSX() && colorwell != null) { 126 Insets ins = new Insets(5,5,5,5); 127 GraphicsUtilities.tileStretchPaint(g, this, colorwell, ins); 128 129 // fill in the color area 130 g.setColor(FILL_COLOR); 131 g.fillRect(ins.left, ins.top, 132 getWidth() - ins.left - ins.right, 133 getHeight() - ins.top - ins.bottom); 134 // draw the borders 135 g.setColor(PaintUtils.setBrightness(FILL_COLOR,0.85f)); 136 g.drawRect(ins.left, ins.top, 137 getWidth() - ins.left - ins.right - 1, 138 getHeight() - ins.top - ins.bottom - 1); 139 g.drawRect(ins.left + 1, ins.top + 1, 140 getWidth() - ins.left - ins.right - 3, 141 getHeight() - ins.top - ins.bottom - 3); 142 }else{ 143 Graphics2D g2 = (Graphics2D) g.create(); 144 145 try { 146 g2.setRenderingHint(KEY_ANTIALIASING, VALUE_ANTIALIAS_ON); 147 g2.setColor(Color.LIGHT_GRAY); 148 final int DIAM = Math.min(getWidth(), getHeight()); 149 final int inset = 3; 150 g2.fill(new Ellipse2D.Float(inset, inset, DIAM-2*inset, DIAM-2*inset)); 151 g2.setColor(FILL_COLOR); 152 final int border = 1; 153 g2.fill(new Ellipse2D.Float(inset+border, inset+border, DIAM-2*inset-2*border, DIAM-2*inset-2*border)); 154 } finally { 155 g2.dispose(); 156 } 157 158 } 159 } 160 161// /** 162// * Sample usage of JXColorSelectionButton 163// * @param args not used 164// */ 165// public static void main(String[] args) { 166// javax.swing.JFrame frame = new javax.swing.JFrame("Color Button Test"); 167// frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE); 168// javax.swing.JPanel panel = new javax.swing.JPanel(); 169// javax.swing.JComponent btn = new JXColorSelectionButton(); 170// btn.setEnabled(true); 171// panel.add(btn); 172// panel.add(new javax.swing.JLabel("ColorSelectionButton test")); 173// 174// frame.add(panel); 175// frame.pack(); 176// frame.setVisible(true); 177// } 178 179 /** 180 * Conditionally create and show the color chooser dialog. 181 */ 182 private void showDialog() { 183 if (dialog == null) { 184 dialog = JColorChooser.createDialog(JXColorSelectionButton.this, 185 "Choose a color", true, getChooser(), 186 new ActionListener() { 187 public void actionPerformed(ActionEvent actionEvent) { 188 Color color = getChooser().getColor(); 189 if (color != null) { 190 setBackground(color); 191 } 192 } 193 }, 194 new ActionListener() { 195 public void actionPerformed(ActionEvent actionEvent) { 196 setBackground(initialColor); 197 } 198 }); 199 dialog.getContentPane().add(getChooser()); 200 getChooser().getSelectionModel().addChangeListener( 201 new ColorChangeListener(JXColorSelectionButton.this)); 202 } 203 204 initialColor = getBackground(); 205 dialog.setVisible(true); 206 207 } 208 209 /** 210 * Get the JColorChooser that is used by this JXColorSelectionButton. This 211 * chooser instance is shared between all invocations of the chooser, but is unique to 212 * this instance of JXColorSelectionButton. 213 * @return the JColorChooser used by this JXColorSelectionButton 214 */ 215 public JColorChooser getChooser() { 216 if(chooser == null) { 217 chooser = new JColorChooser(); 218 // add the eyedropper color chooser panel 219 chooser.addChooserPanel(new EyeDropperColorChooserPanel()); 220 } 221 return chooser; 222 } 223 224 /** 225 * Set the JColorChooser that is used by this JXColorSelectionButton. 226 * chooser instance is shared between all invocations of the chooser, 227 * but is unique to 228 * this instance of JXColorSelectionButton. 229 * @param chooser The new JColorChooser to use. 230 */ 231 public void setChooser(JColorChooser chooser) { 232 JColorChooser oldChooser = getChooser(); 233 this.chooser = chooser; 234 firePropertyChange("chooser",oldChooser,chooser); 235 } 236 237 /** 238 * {@inheritDoc} 239 */ 240 @Override 241 public Dimension getPreferredSize() { 242 if (isPreferredSizeSet() || colorwell == null) { 243 return super.getPreferredSize(); 244 } 245 246 return new Dimension(colorwell.getWidth(), colorwell.getHeight()); 247 } 248 249 /** 250 * A private class to conditionally create and show the color chooser 251 * dialog. 252 */ 253 private class ActionHandler implements ActionListener { 254 255 public void actionPerformed(ActionEvent actionEvent) { 256 showDialog(); 257 } 258 } 259}