1 /* DefaultHSBChooserPanel.java --
2    Copyright (C) 2004, 2005 Free Software Foundation, Inc.
3 
4 This file is part of GNU Classpath.
5 
6 GNU Classpath is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2, or (at your option)
9 any later version.
10 
11 GNU Classpath is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with GNU Classpath; see the file COPYING.  If not, write to the
18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 02110-1301 USA.
20 
21 Linking this library statically or dynamically with other modules is
22 making a combined work based on this library.  Thus, the terms and
23 conditions of the GNU General Public License cover the whole
24 combination.
25 
26 As a special exception, the copyright holders of this library give you
27 permission to link this library with independent modules to produce an
28 executable, regardless of the license terms of these independent
29 modules, and to copy and distribute the resulting executable under
30 terms of your choice, provided that you also meet, for each linked
31 independent module, the terms and conditions of the license of that
32 module.  An independent module is a module which is not derived from
33 or based on this library.  If you modify this library, you may extend
34 this exception to your version of the library, but you are not
35 obligated to do so.  If you do not wish to do so, delete this
36 exception statement from your version. */
37 
38 
39 package javax.swing.colorchooser;
40 
41 import java.awt.BorderLayout;
42 import java.awt.Color;
43 import java.awt.Container;
44 import java.awt.Dimension;
45 import java.awt.Graphics;
46 import java.awt.GridLayout;
47 import java.awt.Image;
48 import java.awt.Point;
49 import java.awt.event.MouseAdapter;
50 import java.awt.event.MouseEvent;
51 import java.awt.event.MouseMotionListener;
52 import java.awt.image.MemoryImageSource;
53 
54 import javax.swing.AbstractButton;
55 import javax.swing.ButtonGroup;
56 import javax.swing.Icon;
57 import javax.swing.JColorChooser;
58 import javax.swing.JLabel;
59 import javax.swing.JPanel;
60 import javax.swing.JRadioButton;
61 import javax.swing.JSlider;
62 import javax.swing.JSpinner;
63 import javax.swing.SpinnerNumberModel;
64 import javax.swing.SwingConstants;
65 import javax.swing.event.ChangeEvent;
66 import javax.swing.event.ChangeListener;
67 
68 /**
69  * This is the Default HSB Panel displayed in the JColorChooser.
70  */
71 class DefaultHSBChooserPanel extends AbstractColorChooserPanel
72 {
73   /** The gradient image displayed.
74    * This is package-private to avoid an accessor method.  */
75   transient Image gradientImage;
76 
77   /** The Panel that holds the gradient image. */
78   private transient JPanel gradientPanel;
79 
80   /** The track gradient image.
81    * This is package-private to avoid an accessor method.  */
82   transient Image trackImage;
83 
84   /** The panel that holds the track. */
85   private transient JPanel trackPanel;
86 
87   /** The slider for the locked HSB value.
88    * This is package-private to avoid an accessor method.  */
89   transient JSlider slider;
90 
91   /** The RadioButton that controls the Hue.
92    * This is package-private to avoid an accessor method.  */
93   transient JRadioButton hRadio;
94 
95   /** The RadioButton that controls the Saturation.
96    * This is package-private to avoid an accessor method.  */
97   transient JRadioButton sRadio;
98 
99   /** The RadioButton that controls the Brightness.
100    * This is package-private to avoid an accessor method.  */
101   transient JRadioButton bRadio;
102 
103   /** The JSpinner that controls the Hue.
104    * This is package-private to avoid an accessor method.  */
105   transient JSpinner hSpinner;
106 
107   /** The JSpinner that controls the Saturation.
108    * This is package-private to avoid an accessor method.  */
109   transient JSpinner sSpinner;
110 
111   /** The JSpinner that controls the Brightness.
112    * This is package-private to avoid an accessor method.  */
113   transient JSpinner bSpinner;
114 
115   /** The default width of the gradient image. */
116   private static final int imgWidth = 200;
117 
118   /** The default height of the gradient image. */
119   private static final int imgHeight = 200;
120 
121   /** The default width of the track gradient. */
122   private static final int trackWidth = 30;
123 
124   /** The JLabel for Red. */
125   private static final JLabel R = new JLabel("R");
126 
127   /** The JLabel for Green. */
128   private static final JLabel G = new JLabel("G");
129 
130   /** The JLabel for Blue. */
131   private static final JLabel B = new JLabel("B");
132 
133   // FIXME: Should be textfields.
134 
135   /** The JLabel that displays the value of Red. */
136   private transient JLabel rFull;
137 
138   /** The JLabel that displays the value of Green. */
139   private transient JLabel gFull;
140 
141   /** The JLabel that displays the value of Blue. */
142   private transient JLabel bFull;
143 
144   /** The point that is displayed in the gradient image.
145    * Package-private to avoid an accessor method.
146    */
147   transient Point gradientPoint = new Point();
148 
149   /**
150    * This indicates that the change to the slider or point is triggered
151    * internally.
152    * This is package-private to avoid an accessor method.
153    */
154   transient boolean internalChange = false;
155 
156   /** This indicates that the change to the spinner is triggered
157    * internally.
158    * This is package-private to avoid an accessor method.  */
159   transient boolean spinnerTrigger = false;
160 
161   /** This int identifies which spinner is currently locked.
162    * This is package-private to avoid an accessor method.  */
163   transient int locked = -1;
164 
165   /** This value indicates that the Hue spinner is locked. */
166   static final int HLOCKED = 0;
167 
168   /** This value indicates that the Saturation spinner is locked. */
169   static final int SLOCKED = 1;
170 
171   /** This value indicates that the Brightness spinner is locked. */
172   static final int BLOCKED = 2;
173 
174   /**
175    * This method indicates that the mouse event is in the process of being
176    * handled.
177    * This is package-private to avoid an accessor method.
178    */
179   transient boolean handlingMouse;
180 
181   /**
182    * This helper class handles mouse events on the gradient image.
183    */
184   class MainGradientMouseListener extends MouseAdapter
185     implements MouseMotionListener
186   {
187     /**
188      * This method is called when the mouse is pressed over the gradient
189      * image. The JColorChooser is then updated with new HSB values.
190      *
191      * @param e The MouseEvent.
192      */
mousePressed(MouseEvent e)193     public void mousePressed(MouseEvent e)
194     {
195       gradientPoint = e.getPoint();
196       update(e.getPoint());
197     }
198 
199     /**
200      * This method is called when the mouse is dragged over the gradient
201      * image. The JColorChooser is then updated with the new HSB values.
202      *
203      * @param e The MouseEvent.
204      */
mouseDragged(MouseEvent e)205     public void mouseDragged(MouseEvent e)
206     {
207       Point p = e.getPoint();
208       if (p.x < 0 || p.y < 0 || p.y > imgHeight || p.x > imgWidth)
209         return;
210 
211       gradientPoint = p;
212       update(p);
213     }
214 
215     /**
216      * This method is called when the mouse is moved over the gradient image.
217      *
218      * @param e The MouseEvent.
219      */
mouseMoved(MouseEvent e)220     public void mouseMoved(MouseEvent e)
221     {
222       // Do nothing.
223     }
224 
225     /**
226      * This method updates the JColorChooser with the new values.
227      *
228      * @param p The Point where the MouseEvent occurred.
229      */
update(Point p)230     private void update(Point p)
231     {
232       handlingMouse = true;
233       if (hSpinner.isEnabled())
234         updateH(p);
235       else if (sSpinner.isEnabled())
236         updateS(p);
237       else
238         updateB(p);
239       handlingMouse = false;
240     }
241 
242     /**
243      * This method updates the SB values if Hue is locked.
244      *
245      * @param p The point where the MouseEvent occurred.
246      */
updateH(Point p)247     private void updateH(Point p)
248     {
249       float s = (imgWidth - p.x * 1f) / imgWidth;
250       float b = (imgHeight - p.y * 1f) / imgHeight;
251 
252       // Avoid two changes to the model by changing internalChange to true.
253       internalChange = true;
254       sSpinner.setValue(new Integer((int) (s * 100)));
255       internalChange = false;
256       bSpinner.setValue(new Integer((int) (b * 100)));
257 
258       revalidate();
259     }
260 
261     /**
262      * This method updates the HB values if Saturation is locked.
263      *
264      * @param p The point where the MouseEvent occurred.
265      */
updateS(Point p)266     private void updateS(Point p)
267     {
268       float h = p.x * 1f / imgWidth;
269       float b = (imgHeight - p.y * 1f) / imgHeight;
270 
271       internalChange = true;
272       hSpinner.setValue(new Integer((int) (h * 365)));
273       internalChange = false;
274       bSpinner.setValue(new Integer((int) (b * 100)));
275 
276       revalidate();
277     }
278 
279     /**
280      * This method updates the HS values if Brightness is locked.
281      *
282      * @param p The point where the MouseEvent occurred.
283      */
updateB(Point p)284     private void updateB(Point p)
285     {
286       float h = p.x * 1f / imgWidth;
287       float s = (imgHeight - p.y * 1f) / imgHeight;
288 
289       internalChange = true;
290       hSpinner.setValue(new Integer((int) (h * 365)));
291       internalChange = false;
292       sSpinner.setValue(new Integer((int) (s * 100)));
293 
294       revalidate();
295     }
296   }
297 
298   /**
299    * This method listens for slider value changes.
300    */
301   class SliderChangeListener implements ChangeListener
302   {
303     /**
304      * This method is called when the slider value changes. It should change
305      * the color of the JColorChooser.
306      *
307      * @param e The ChangeEvent.
308      */
stateChanged(ChangeEvent e)309     public void stateChanged(ChangeEvent e)
310     {
311       if (internalChange)
312         return;
313 
314       Integer value = new Integer(slider.getValue());
315 
316       switch (locked)
317         {
318         case HLOCKED:
319           hSpinner.setValue(value);
320           break;
321         case SLOCKED:
322           sSpinner.setValue(value);
323           break;
324         case BLOCKED:
325           bSpinner.setValue(value);
326           break;
327         }
328     }
329   }
330 
331   /**
332    * This helper class determines the active JSpinner.
333    */
334   class RadioStateListener implements ChangeListener
335   {
336     /**
337      * This method is called when there is a new JRadioButton that was
338      * selected. As a result, it should activate the associated JSpinner.
339      *
340      * @param e The ChangeEvent.
341      */
stateChanged(ChangeEvent e)342     public void stateChanged(ChangeEvent e)
343     {
344       JSpinner change;
345       if (e.getSource() == hRadio)
346         {
347           locked = HLOCKED;
348           change = hSpinner;
349         }
350       else if (e.getSource() == sRadio)
351         {
352           locked = SLOCKED;
353           change = sSpinner;
354         }
355       else
356         {
357           locked = BLOCKED;
358           change = bSpinner;
359         }
360 
361       change.setEnabled(((AbstractButton) e.getSource()).isSelected());
362       updateSlider();
363       updateTrack();
364       updateImage();
365       repaint();
366     }
367   }
368 
369   /**
370    * This class listens to the JSpinners for changes.
371    */
372   class ImageScrollListener implements ChangeListener
373   {
374     /**
375      * This method is called whenever one of the JSpinner values change. The
376      * JColorChooser should be updated with the new HSB values.
377      *
378      * @param e The ChangeEvent.
379      */
stateChanged(ChangeEvent e)380     public void stateChanged(ChangeEvent e)
381     {
382       if (internalChange)
383         return;
384 
385       float h = ((Number) hSpinner.getValue()).intValue() / 360f;
386       float s = ((Number) sSpinner.getValue()).intValue() / 100f;
387       float b = ((Number) bSpinner.getValue()).intValue() / 100f;
388 
389       spinnerTrigger = true;
390       getColorSelectionModel().setSelectedColor(new Color(Color.HSBtoRGB(h, s,
391                                                                          b)));
392       spinnerTrigger = false;
393 
394       if (! handlingMouse && slider != null && ! slider.getValueIsAdjusting())
395         {
396           updateImage();
397           updateTrack();
398         }
399       repaint();
400     }
401   }
402 
403   /**
404    * Creates a new DefaultHSBChooserPanel object.
405    */
DefaultHSBChooserPanel()406   DefaultHSBChooserPanel()
407   {
408     super();
409   }
410 
411   /**
412    * This method returns the name displayed by the JColorChooser tab that
413    * holds this panel.
414    *
415    * @return The name displayed in the JColorChooser tab.
416    */
getDisplayName()417   public String getDisplayName()
418   {
419     return "HSB";
420   }
421 
422   /**
423    * This method updates the various components inside the HSBPanel (the
424    * JSpinners, the JSlider, and the gradient image point) with updated
425    * values when the JColorChooser color value changes.
426    */
updateChooser()427   public void updateChooser()
428   {
429     Color c = getColorSelectionModel().getSelectedColor();
430 
431     float[] hsbVals = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(),
432                                      null);
433 
434     internalChange = true;
435 
436     if (! spinnerTrigger)
437       {
438         hSpinner.setValue(new Integer((int) (hsbVals[0] * 360)));
439         sSpinner.setValue(new Integer((int) (hsbVals[1] * 100)));
440         bSpinner.setValue(new Integer((int) (hsbVals[2] * 100)));
441       }
442 
443     switch (locked)
444       {
445       case HLOCKED:
446         if (slider != null)
447           slider.setValue(((Number) hSpinner.getValue()).intValue());
448         if (! handlingMouse)
449           {
450             gradientPoint.x = (int) ((1
451                               - ((Number) sSpinner.getValue()).intValue() / 100f) * imgWidth);
452             gradientPoint.y = (int) ((1
453                               - ((Number) bSpinner.getValue()).intValue() / 100f) * imgHeight);
454           }
455         break;
456       case SLOCKED:
457         if (slider != null)
458           slider.setValue(((Number) sSpinner.getValue()).intValue());
459         if (! handlingMouse)
460           {
461             gradientPoint.x = (int) (((Number) hSpinner.getValue()).intValue() / 360f * imgWidth);
462             gradientPoint.y = (int) ((1
463                               - ((Number) bSpinner.getValue()).intValue() / 100f) * imgHeight);
464           }
465         break;
466       case BLOCKED:
467         if (slider != null)
468           slider.setValue(((Number) bSpinner.getValue()).intValue());
469         if (! handlingMouse)
470           {
471             gradientPoint.x = (int) (((Number) hSpinner.getValue()).intValue() / 360f * imgWidth);
472             gradientPoint.y = (int) ((1
473                               - ((Number) sSpinner.getValue()).intValue() / 100f) * imgHeight);
474           }
475         break;
476       }
477     internalChange = false;
478 
479     if (! handlingMouse && slider != null && ! slider.getValueIsAdjusting())
480       updateImage();
481 
482     if (! handlingMouse || locked != HLOCKED)
483       updateTrack();
484     updateTextFields();
485   }
486 
487   /**
488    * This method builds the DefaultHSBChooserPanel.
489    */
buildChooser()490   protected void buildChooser()
491   {
492     setLayout(new BorderLayout());
493 
494     add(buildRightPanel(), BorderLayout.EAST);
495 
496     JPanel container = new JPanel();
497     container.setLayout(new BorderLayout());
498 
499     gradientPanel = new JPanel()
500         {
501           public Dimension getPreferredSize()
502           {
503             return new Dimension(imgWidth, imgHeight);
504           }
505 
506           public void paint(Graphics g)
507           {
508             if (gradientImage != null)
509               g.drawImage(gradientImage, 0, 0, this);
510 
511             Color saved = g.getColor();
512             g.setColor(Color.WHITE);
513             g.drawOval(gradientPoint.x - 3, gradientPoint.y - 3, 6, 6);
514             g.setColor(saved);
515           }
516         };
517 
518     MouseAdapter ml = new MainGradientMouseListener();
519     gradientPanel.addMouseListener(ml);
520     gradientPanel.addMouseMotionListener((MouseMotionListener) ml);
521 
522     trackPanel = new JPanel()
523         {
524           public Dimension getPreferredSize()
525           {
526             return new Dimension(trackWidth, imgHeight);
527           }
528 
529           public void paint(Graphics g)
530           {
531             if (trackImage != null)
532               g.drawImage(trackImage, 0, 0, this);
533           }
534         };
535 
536     slider = new JSlider();
537     slider.setPaintTrack(false);
538     slider.setPaintTicks(false);
539 
540     slider.setOrientation(SwingConstants.VERTICAL);
541 
542     updateSlider();
543 
544     container.add(gradientPanel, BorderLayout.WEST);
545     container.add(slider, BorderLayout.CENTER);
546     container.add(trackPanel, BorderLayout.EAST);
547 
548     add(container, BorderLayout.WEST);
549     slider.addChangeListener(new SliderChangeListener());
550     repaint();
551   }
552 
553   /**
554    * This method uninstalls the DefaultHSBPanel.
555    *
556    * @param chooser The JColorChooser to remove this panel from.
557    */
uninstallChooserPanel(JColorChooser chooser)558   public void uninstallChooserPanel(JColorChooser chooser)
559   {
560     trackImage = null;
561     gradientImage = null;
562     gradientPanel = null;
563     slider = null;
564 
565     hSpinner = null;
566     sSpinner = null;
567     bSpinner = null;
568 
569     hRadio = null;
570     sRadio = null;
571     bRadio = null;
572 
573     removeAll();
574     super.uninstallChooserPanel(chooser);
575   }
576 
577   /**
578    * This helper method creates the right side panel (the panel with the
579    * Spinners and TextFields).
580    *
581    * @return The right side panel.
582    */
buildRightPanel()583   private Container buildRightPanel()
584   {
585     JPanel container = new JPanel();
586     container.setLayout(new GridLayout(6, 2));
587 
588     hRadio = new JRadioButton("H");
589     sRadio = new JRadioButton("S");
590     bRadio = new JRadioButton("B");
591 
592     ButtonGroup group = new ButtonGroup();
593     group.add(hRadio);
594     group.add(sRadio);
595     group.add(bRadio);
596 
597     hSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 359, 1));
598     sSpinner = new JSpinner(new SpinnerNumberModel(0, 0, 100, 1));
599     bSpinner = new JSpinner(new SpinnerNumberModel(100, 0, 100, 1));
600 
601     hSpinner.setEnabled(false);
602     sSpinner.setEnabled(false);
603     bSpinner.setEnabled(false);
604 
605     ChangeListener cl = new RadioStateListener();
606     ChangeListener scroll = new ImageScrollListener();
607 
608     hRadio.addChangeListener(cl);
609     sRadio.addChangeListener(cl);
610     bRadio.addChangeListener(cl);
611 
612     hSpinner.addChangeListener(scroll);
613     sSpinner.addChangeListener(scroll);
614     bSpinner.addChangeListener(scroll);
615 
616     hRadio.setSelected(true);
617 
618     container.add(hRadio);
619     container.add(hSpinner);
620 
621     container.add(sRadio);
622     container.add(sSpinner);
623 
624     container.add(bRadio);
625     container.add(bSpinner);
626 
627     rFull = new JLabel("red full");
628     gFull = new JLabel("green full");
629     bFull = new JLabel("blue full");
630 
631     container.add(R);
632     container.add(rFull);
633 
634     container.add(G);
635     container.add(gFull);
636 
637     container.add(B);
638     container.add(bFull);
639 
640     return container;
641   }
642 
643   /**
644    * This method returns the small display icon.
645    *
646    * @return The small display icon.
647    */
getSmallDisplayIcon()648   public Icon getSmallDisplayIcon()
649   {
650     return null;
651   }
652 
653   /**
654    * This method returns the large display icon.
655    *
656    * @return The large display icon.
657    */
getLargeDisplayIcon()658   public Icon getLargeDisplayIcon()
659   {
660     return null;
661   }
662 
663   /**
664    * This method paints the chooser panel.
665    *
666    * @param g The graphics object to paint with.
667    */
paint(Graphics g)668   public void paint(Graphics g)
669   {
670     super.paint(g);
671   }
672 
673   /**
674    * This method updates the gradient image with a new one taking the Hue
675    * value as the constant.
676    */
updateHLockImage()677   private void updateHLockImage()
678   {
679     int index = 0;
680     int[] pix = new int[imgWidth * imgHeight];
681     float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
682 
683     for (int j = 0; j < imgHeight; j++)
684       for (int i = 0; i < imgWidth; i++)
685         pix[index++] = Color.HSBtoRGB(hValue, (imgWidth - i * 1f) / imgWidth,
686                                       (imgHeight - j * 1f) / imgHeight)
687                        | (255 << 24);
688 
689     gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
690                                                       pix, 0, imgWidth));
691   }
692 
693   /**
694    * This method updates the gradient image with a new one taking the
695    * Brightness value as the constant.
696    */
updateBLockImage()697   private void updateBLockImage()
698   {
699     int[] pix = new int[imgWidth * imgHeight];
700     float bValue = ((Number) bSpinner.getValue()).intValue() / 100f;
701 
702     int index = 0;
703     for (int j = 0; j < imgHeight; j++)
704       for (int i = 0; i < imgWidth; i++)
705         pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth,
706                                       (imgHeight - j * 1f) / imgHeight, bValue)
707                        | (255 << 24);
708 
709     gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
710                                                       pix, 0, imgWidth));
711   }
712 
713   /**
714    * This method updates the gradient image with a new one taking the
715    * Saturation value as the constant.
716    */
updateSLockImage()717   private void updateSLockImage()
718   {
719     int[] pix = new int[imgWidth * imgHeight];
720     float sValue = ((Number) sSpinner.getValue()).intValue() / 100f;
721 
722     int index = 0;
723     for (int j = 0; j < imgHeight; j++)
724       for (int i = 0; i < imgWidth; i++)
725         pix[index++] = Color.HSBtoRGB(i * 1f / imgWidth, sValue,
726                                       (imgHeight - j * 1f) / imgHeight)
727                        | (255 << 24);
728     gradientImage = createImage(new MemoryImageSource(imgWidth, imgHeight,
729                                                       pix, 0, imgWidth));
730   }
731 
732   /**
733    * This method calls the appropriate method to update the gradient image
734    * depending on which HSB value is constant.
735    * This is package-private to avoid an accessor method.
736    */
updateImage()737   void updateImage()
738   {
739     switch (locked)
740       {
741       case HLOCKED:
742         updateHLockImage();
743         break;
744       case SLOCKED:
745         updateSLockImage();
746         break;
747       case BLOCKED:
748         updateBLockImage();
749         break;
750       }
751   }
752 
753   /**
754    * This method updates the TextFields with the correct RGB values.
755    */
updateTextFields()756   private void updateTextFields()
757   {
758     int c = getColorSelectionModel().getSelectedColor().getRGB();
759 
760     rFull.setText("" + (c >> 16 & 0xff));
761     gFull.setText("" + (c >> 8 & 0xff));
762     bFull.setText("" + (c & 0xff));
763 
764     repaint();
765   }
766 
767   /**
768    * This method updates the slider in response to making a different HSB
769    * property the constant.
770    * This is package-private to avoid an accessor method.
771    */
updateSlider()772   void updateSlider()
773   {
774     if (slider == null)
775       return;
776 
777     slider.setMinimum(0);
778     if (locked == HLOCKED)
779       {
780         slider.setMaximum(359);
781         slider.setValue(((Number) hSpinner.getValue()).intValue());
782         slider.setInverted(true);
783       }
784     else
785       {
786         slider.setMaximum(100);
787         slider.setInverted(false);
788         if (sRadio.isSelected())
789           slider.setValue(((Number) sSpinner.getValue()).intValue());
790         else
791           slider.setValue(((Number) bSpinner.getValue()).intValue());
792       }
793     repaint();
794   }
795 
796   /**
797    * This method updates the track gradient image depending on which HSB
798    * property is constant.
799    * This is package-private to avoid an accessor method.
800    */
updateTrack()801   void updateTrack()
802   {
803     switch (locked)
804       {
805       case HLOCKED:
806         updateHTrack();
807         break;
808       case SLOCKED:
809         updateSTrack();
810         break;
811       case BLOCKED:
812         updateBTrack();
813         break;
814       }
815   }
816 
817   /**
818    * This method updates the track gradient image if the Hue value is allowed
819    * to change (according to the JRadioButtons).
820    */
updateHTrack()821   private void updateHTrack()
822   {
823     int trackIndex = 0;
824     int[] trackPix = new int[trackWidth * imgHeight];
825 
826     for (int j = 0; j < imgHeight; j++)
827       for (int i = 0; i < trackWidth; i++)
828         trackPix[trackIndex++] = Color.HSBtoRGB(j * 1f / imgHeight, 1f, 1f)
829                                  | (255 << 24);
830 
831     trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
832                                                    trackPix, 0, trackWidth));
833   }
834 
835   /**
836    * This method updates the track gradient image if the Saturation value is
837    * allowed to change (according to the JRadioButtons).
838    */
updateSTrack()839   private void updateSTrack()
840   {
841     int[] trackPix = new int[trackWidth * imgHeight];
842 
843     float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
844     float bValue = ((Number) bSpinner.getValue()).intValue() / 100f;
845 
846     int trackIndex = 0;
847     for (int j = 0; j < imgHeight; j++)
848       for (int i = 0; i < trackWidth; i++)
849         trackPix[trackIndex++] = Color.HSBtoRGB(hValue,
850                                                 (imgHeight - j * 1f) / imgHeight,
851                                                 bValue) | (255 << 24);
852 
853     trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
854                                                    trackPix, 0, trackWidth));
855   }
856 
857   /**
858    * This method updates the track gradient image if the Brightness value is
859    * allowed to change (according to the JRadioButtons).
860    */
updateBTrack()861   private void updateBTrack()
862   {
863     int[] trackPix = new int[trackWidth * imgHeight];
864 
865     float hValue = ((Number) hSpinner.getValue()).intValue() / 360f;
866     float sValue = ((Number) sSpinner.getValue()).intValue() / 100f;
867 
868     int trackIndex = 0;
869     for (int j = 0; j < imgHeight; j++)
870       for (int i = 0; i < trackWidth; i++)
871         trackPix[trackIndex++] = Color.HSBtoRGB(hValue, sValue,
872                                                 (imgHeight - j * 1f) / imgHeight)
873                                  | (255 << 24);
874 
875     trackImage = createImage(new MemoryImageSource(trackWidth, imgHeight,
876                                                    trackPix, 0, trackWidth));
877   }
878 
879   /**
880    * This method returns the HSB values for the currently selected color.
881    *
882    * @return The HSB values for the currently selected color.
883    */
getHSBValues()884   private float[] getHSBValues()
885   {
886     Color c = getColorFromModel();
887     float[] f = Color.RGBtoHSB(c.getRed(), c.getGreen(), c.getBlue(), null);
888     return f;
889   }
890 }
891