001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Dennis Ushakov
019: * @version $Revision$
020: */package javax.swing.colorchooser;
021:
022: import java.awt.Color;
023: import java.awt.Component;
024: import java.awt.Dimension;
025: import java.awt.Graphics;
026: import java.awt.GridBagConstraints;
027: import java.awt.GridBagLayout;
028: import java.awt.event.ActionEvent;
029: import java.awt.event.ActionListener;
030: import java.awt.event.MouseEvent;
031:
032: import javax.swing.ButtonGroup;
033: import javax.swing.Icon;
034: import javax.swing.JLabel;
035: import javax.swing.JPanel;
036: import javax.swing.JRadioButton;
037: import javax.swing.JSlider;
038: import javax.swing.JSpinner;
039: import javax.swing.JTextField;
040: import javax.swing.SpinnerNumberModel;
041: import javax.swing.SwingConstants;
042: import javax.swing.UIManager;
043: import javax.swing.event.ChangeEvent;
044: import javax.swing.event.ChangeListener;
045: import javax.swing.event.MouseInputAdapter;
046:
047: import org.apache.harmony.x.swing.Utilities;
048:
049: class HSBPanel extends AbstractColorChooserPanel {
050: private class SelectorIcon implements Icon {
051: private final Dimension size = new Dimension(SELECTOR_WIDTH,
052: COMPONENTS_HEIGHT);
053:
054: public void paintIcon(final Component c, final Graphics g,
055: final int x, final int y) {
056: Color color = getColorSelectionModel().getSelectedColor();
057: float[] hsb = Color.RGBtoHSB(color.getRed(), color
058: .getGreen(), color.getBlue(), null);
059: float fixed = hsb[selectionMode];
060:
061: for (int i = 0; i < SELECTOR_WIDTH; i++) {
062: for (int j = 0; j < COMPONENTS_HEIGHT; j++) {
063: switch (selectionMode) {
064: case HUE:
065: g.setColor(Color.getHSBColor(fixed,
066: (float) (SELECTOR_WIDTH - i)
067: / SELECTOR_WIDTH,
068: (float) (COMPONENTS_HEIGHT - j)
069: / COMPONENTS_HEIGHT));
070: break;
071: case SATURATION:
072: g.setColor(Color.getHSBColor(
073: (float) (SELECTOR_WIDTH - i)
074: / SELECTOR_WIDTH, fixed,
075: (float) (COMPONENTS_HEIGHT - j)
076: / COMPONENTS_HEIGHT));
077: break;
078: case BRIGHTNESS:
079: g.setColor(Color.getHSBColor(
080: (float) (SELECTOR_WIDTH - i)
081: / SELECTOR_WIDTH,
082: (float) (COMPONENTS_HEIGHT - j)
083: / COMPONENTS_HEIGHT, fixed));
084: break;
085: }
086: g.drawLine(i, j, i, j);
087: }
088: }
089: }
090:
091: public int getIconWidth() {
092: return size.width;
093: }
094:
095: public int getIconHeight() {
096: return size.height;
097: }
098: }
099:
100: private class Selector extends JLabel {
101:
102: private int selectionMode = -1;
103:
104: public Selector() {
105: setIcon(new SelectorIcon());
106: }
107:
108: public void setSelectionMode(final int selectionMode) {
109: if (this .selectionMode != selectionMode) {
110: this .selectionMode = selectionMode;
111: repaint();
112: }
113: }
114:
115: public void paint(final Graphics graphics) {
116: Color oldColor = graphics.getColor();
117: super .paint(graphics);
118: paintCircle(graphics);
119:
120: graphics.setColor(oldColor);
121: }
122:
123: private void paintCircle(final Graphics graphics) {
124: Color color = getColorSelectionModel().getSelectedColor();
125: float[] hsb = Color.RGBtoHSB(color.getRed(), color
126: .getGreen(), color.getBlue(), null);
127:
128: int x = 0;
129: int y = 0;
130: int r = 5;
131: switch (selectionMode) {
132: case HUE:
133: x = Math.round(SELECTOR_WIDTH * (1 - hsb[SATURATION]));
134: y = Math.round(COMPONENTS_HEIGHT
135: * (1 - hsb[BRIGHTNESS]));
136: break;
137: case SATURATION:
138: x = Math.round(SELECTOR_WIDTH * (1 - hsb[HUE]));
139: y = Math.round(COMPONENTS_HEIGHT
140: * (1 - hsb[BRIGHTNESS]));
141: break;
142: case BRIGHTNESS:
143: x = Math.round(SELECTOR_WIDTH * (1 - hsb[HUE]));
144: y = Math.round(COMPONENTS_HEIGHT
145: * (1 - hsb[SATURATION]));
146: break;
147: }
148:
149: graphics.setColor(Color.WHITE);
150: graphics.drawArc(x - r, y - r, 2 * r, 2 * r, 0, 360);
151: }
152: }
153:
154: private class SliderImage extends JLabel {
155: private final Dimension size = new Dimension(
156: SLIDER_IMAGE_WIDTH, COMPONENTS_HEIGHT);
157: private int selectionMode = -1;
158:
159: public Dimension getPreferredSize() {
160: return size;
161: }
162:
163: public void setSelectionMode(final int selectionMode) {
164: if (this .selectionMode != selectionMode) {
165: this .selectionMode = selectionMode;
166: repaint();
167: }
168: }
169:
170: public void paint(final Graphics graphics) {
171: Color color = getColorSelectionModel().getSelectedColor();
172: float[] hsb = Color.RGBtoHSB(color.getRed(), color
173: .getGreen(), color.getBlue(), null);
174:
175: for (int i = 0; i < COMPONENTS_HEIGHT; i++) {
176: float t = (float) i / COMPONENTS_HEIGHT;
177: switch (selectionMode) {
178: case HUE:
179: graphics.setColor(Color.getHSBColor(t, 1.f, 1.f));
180: break;
181: case SATURATION:
182: graphics.setColor(Color.getHSBColor(hsb[0],
183: 1.f - t, 1.f));
184: break;
185: case BRIGHTNESS:
186: graphics.setColor(Color.getHSBColor(hsb[0], 1.f,
187: 1.f - t));
188: break;
189: }
190: graphics.drawLine(0, i, SLIDER_IMAGE_WIDTH, i);
191: }
192:
193: }
194: }
195:
196: private static final int COMPONENTS_HEIGHT = 200;
197: private static final int SELECTOR_WIDTH = 200;
198: private static final int SLIDER_IMAGE_WIDTH = 16;
199:
200: private static final int HUE = 0;
201: private static final int SATURATION = 1;
202: private static final int BRIGHTNESS = 2;
203:
204: private static final int MAX_HUE = 359;
205: private static final int MAX_SATURATION = 100;
206: private static final int MAX_BRIGHTNESS = 100;
207: private static final int[] MAX = { MAX_HUE, MAX_SATURATION,
208: MAX_BRIGHTNESS };
209: private static final boolean[] SLIDER_INVERTED = { true, false,
210: false };
211:
212: private JSlider slider;
213: private SliderImage sliderImage;
214: private Selector selector;
215:
216: private JSpinner[] spinners;
217: private JRadioButton[] radioButtons;
218: private JTextField[] rgbText;
219:
220: private int selectionMode;
221: private boolean internalUpdateDisabled;
222:
223: public String getDisplayName() {
224: return UIManager.getString("ColorChooser.hsbNameText");
225: }
226:
227: public Icon getSmallDisplayIcon() {
228: return null;
229: }
230:
231: public Icon getLargeDisplayIcon() {
232: return null;
233: }
234:
235: public void updateChooser() {
236: Color color = getColorSelectionModel().getSelectedColor();
237: if (color == null) {
238: return;
239: }
240: internalUpdateDisabled = true;
241:
242: float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(),
243: color.getBlue(), null);
244: float[] rgb = color.getRGBComponents(null);
245:
246: for (int i = 0; i < 3; i++) {
247: spinners[i].setValue(new Integer(Math
248: .round(hsb[i] * MAX[i])));
249: rgbText[i].setText(Integer.toString(Math
250: .round(rgb[i] * 255)));
251: }
252:
253: updateSelector();
254: internalUpdateDisabled = false;
255: }
256:
257: protected void buildChooser() {
258: String[] namesHSB = {
259: UIManager.getString("ColorChooser.hsbHueText"),
260: UIManager.getString("ColorChooser.hsbSaturationText"),
261: UIManager.getString("ColorChooser.hsbBrightnessText") };
262:
263: String[] namesRGB = {
264: UIManager.getString("ColorChooser.hsbRedText"),
265: UIManager.getString("ColorChooser.hsbGreenText"),
266: UIManager.getString("ColorChooser.hsbBlueText") };
267:
268: mnemonic = UIManager.getInt("ColorChooser.hsbMnemonic");
269: displayedMnemonicIndex = Integer.parseInt(UIManager
270: .getString("ColorChooser.hsbDisplayedMnemonicIndex"));
271:
272: GridBagLayout layout = new GridBagLayout();
273: GridBagConstraints c = new GridBagConstraints();
274: c.anchor = GridBagConstraints.WEST;
275: c.weightx = 1;
276:
277: JPanel left = buildSelectorPanel();
278:
279: ButtonGroup group = new ButtonGroup();
280: radioButtons = new JRadioButton[3];
281: spinners = new JSpinner[3];
282: rgbText = new JTextField[3];
283:
284: JPanel right = new JPanel();
285: right.setLayout(layout);
286: int rgbInset = 2 * UIManager.getInt("RadioButton.textIconGap")
287: + UIManager.getIcon("RadioButton.icon").getIconWidth();
288:
289: for (int i = 0; i < 3; i++) {
290: JRadioButton button = new JRadioButton(namesHSB[i]);
291: installRadioButtonListener(button);
292: radioButtons[i] = button;
293: group.add(button);
294:
295: JSpinner spinner = buildHSBSpinner(i);
296: spinners[i] = spinner;
297:
298: JPanel spinnerLabelHolder = new JPanel();
299: spinnerLabelHolder.add(spinner);
300: c.gridx = 0;
301: c.gridy = i;
302: layout.setConstraints(button, c);
303: right.add(button);
304:
305: c.gridx = 1;
306: c.gridy = i;
307: layout.setConstraints(spinner, c);
308: right.add(spinner);
309:
310: JTextField text = buildRGBTextField();
311:
312: JLabel rgbLabel = new JLabel(namesRGB[i]);
313: rgbLabel.setLabelFor(text);
314: rgbText[i] = text;
315:
316: c.gridx = 0;
317: c.gridy = i + 4;
318: c.weightx = 0;
319: c.insets.left = rgbInset;
320: c.anchor = GridBagConstraints.WEST;
321: layout.setConstraints(rgbLabel, c);
322: right.add(rgbLabel);
323:
324: c.gridx = 1;
325: c.gridy = i + 4;
326: c.weightx = 1;
327: c.insets.left = 0;
328: c.anchor = GridBagConstraints.WEST;
329: layout.setConstraints(text, c);
330: right.add(text);
331: }
332: c.gridx = 0;
333: c.gridy = 3;
334: JPanel separator = new JPanel();
335: layout.setConstraints(separator, c);
336: right.add(separator);
337:
338: radioButtons[0].setSelected(true);
339:
340: JPanel fullPanel = new JPanel();
341: fullPanel.add(left);
342: fullPanel.add(right);
343: this .add(fullPanel);
344: }
345:
346: private void installRadioButtonListener(final JRadioButton button) {
347: button.addActionListener(new ActionListener() {
348: public void actionPerformed(ActionEvent e) {
349: for (int i = 0; i < 3; i++) {
350: if (radioButtons[i].isSelected()) {
351: selectionMode = i;
352: }
353: }
354: updateSelector();
355: }
356: });
357: }
358:
359: private void updateSelector() {
360: ChangeListener listener = slider.getChangeListeners()[0];
361: slider.removeChangeListener(listener);
362: slider.setMaximum(MAX[selectionMode]);
363: slider.setValue(((Number) spinners[selectionMode].getValue())
364: .intValue());
365: slider.setInverted(SLIDER_INVERTED[selectionMode]);
366: slider.addChangeListener(listener);
367:
368: sliderImage.setSelectionMode(selectionMode);
369: selector.setSelectionMode(selectionMode);
370: sliderImage.repaint();
371: selector.repaint();
372: }
373:
374: private void updateColor(final int x, final int y) {
375: Color color = getColorSelectionModel().getSelectedColor();
376: float[] hsb = Color.RGBtoHSB(color.getRed(), color.getGreen(),
377: color.getBlue(), null);
378:
379: float xColor = (float) (SELECTOR_WIDTH - x) / SELECTOR_WIDTH;
380: xColor = (xColor >= 1.f) ? 1.f : xColor;
381: xColor = (xColor <= 0.f) ? 0.f : xColor;
382: float yColor = (float) (COMPONENTS_HEIGHT - y)
383: / COMPONENTS_HEIGHT;
384: yColor = (yColor >= 1.f) ? 1.f : yColor;
385: yColor = (yColor <= 0.f) ? 0.f : yColor;
386:
387: switch (selectionMode) {
388: case HUE:
389: hsb[SATURATION] = xColor;
390: hsb[BRIGHTNESS] = yColor;
391: break;
392: case SATURATION:
393: hsb[HUE] = xColor;
394: hsb[BRIGHTNESS] = yColor;
395: break;
396: case BRIGHTNESS:
397: hsb[HUE] = xColor;
398: hsb[SATURATION] = yColor;
399: break;
400: }
401: getColorSelectionModel().setSelectedColor(
402: Color.getHSBColor(hsb[0], hsb[1], hsb[2]));
403: }
404:
405: private JPanel buildSelectorPanel() {
406: JPanel selectorPanel = new JPanel();
407: selector = new Selector();
408: MouseInputAdapter selectorMouseAdapter = new MouseInputAdapter() {
409: public void mousePressed(MouseEvent e) {
410: updateColor(e.getX(), e.getY());
411: }
412:
413: public void mouseDragged(MouseEvent e) {
414: updateColor(e.getX(), e.getY());
415: }
416: };
417: selector.addMouseListener(selectorMouseAdapter);
418: selector.addMouseMotionListener(selectorMouseAdapter);
419: selectorPanel.add(selector);
420:
421: selectionMode = HUE;
422: slider = new JSlider(JSlider.VERTICAL);
423: slider.setMinimum(0);
424: slider.setPaintTrack(false);
425: slider.setInverted(true);
426: slider
427: .setPreferredSize(new Dimension(slider
428: .getPreferredSize().width,
429: COMPONENTS_HEIGHT + 24));
430: slider.addChangeListener(new ChangeListener() {
431: public void stateChanged(ChangeEvent e) {
432: if (internalUpdateDisabled
433: || slider.getValueIsAdjusting()) {
434: return;
435: }
436: Color color = getColorSelectionModel()
437: .getSelectedColor();
438: float[] hsb = Color.RGBtoHSB(color.getRed(), color
439: .getGreen(), color.getBlue(), null);
440: hsb[selectionMode] = 1.f * slider.getValue()
441: / MAX[selectionMode];
442: getColorSelectionModel().setSelectedColor(
443: Color.getHSBColor(hsb[0], hsb[1], hsb[2]));
444: }
445: });
446: selectorPanel.add(slider);
447: sliderImage = new SliderImage();
448: selectorPanel.add(sliderImage);
449: return selectorPanel;
450: }
451:
452: private JSpinner buildHSBSpinner(int hsbComponent) {
453: JSpinner spinner = new JSpinner(new SpinnerNumberModel(0, 0,
454: MAX[hsbComponent], 1));
455: spinner.addChangeListener(new ChangeListener() {
456: public void stateChanged(ChangeEvent e) {
457: if (internalUpdateDisabled) {
458: return;
459: }
460:
461: Color color = getColorSelectionModel()
462: .getSelectedColor();
463: float[] hsb = Color.RGBtoHSB(color.getRed(), color
464: .getGreen(), color.getBlue(), null);
465:
466: for (int i = 0; i < 3; i++) {
467: if (e.getSource() == spinners[i]) {
468: hsb[i] = ((Number) spinners[i].getValue())
469: .floatValue()
470: / MAX[i];
471: }
472: }
473: getColorSelectionModel().setSelectedColor(
474: Color.getHSBColor(hsb[0], hsb[1], hsb[2]));
475: }
476: });
477: Dimension stringSize = Utilities.getStringSize("999", spinner
478: .getEditor().getFontMetrics(
479: spinner.getEditor().getFont()));
480: Utilities
481: .addInsets(stringSize, spinner.getEditor().getInsets());
482: spinner.getEditor().setPreferredSize(
483: new Dimension(stringSize.width, stringSize.height));
484:
485: return spinner;
486: }
487:
488: private static JTextField buildRGBTextField() {
489: JTextField text = new JTextField();
490: Dimension stringSize = Utilities.getStringSize("999", text
491: .getFontMetrics(text.getFont()));
492: Utilities.addInsets(stringSize, text.getInsets());
493: text.setPreferredSize(new Dimension(stringSize.width + 2,
494: stringSize.height));
495: text.setEditable(false);
496: text.setHorizontalAlignment(SwingConstants.RIGHT);
497: return text;
498: }
499: }
|