001    /*
002     * GradientPicker.java
003     *
004     * Created on January 13, 2006, 3:17 PM
005     */
006    
007    package org.jdesktop.swingx;
008    
009    import java.awt.BorderLayout;
010    import java.awt.Color;
011    import java.awt.Component;
012    import java.awt.Dimension;
013    import java.awt.GridBagConstraints;
014    import java.awt.GridBagLayout;
015    import java.awt.GridLayout;
016    import java.awt.Insets;
017    import java.awt.Paint;
018    import java.awt.Toolkit;
019    import java.awt.event.ActionEvent;
020    import java.awt.event.ActionListener;
021    import java.awt.event.ItemEvent;
022    import java.awt.event.ItemListener;
023    import java.awt.event.MouseEvent;
024    import java.awt.geom.Point2D;
025    import java.beans.PropertyChangeEvent;
026    import java.beans.PropertyChangeListener;
027    import java.util.List;
028    import javax.swing.ActionMap;
029    import javax.swing.BorderFactory;
030    import javax.swing.BoxLayout;
031    import javax.swing.ButtonGroup;
032    import javax.swing.DefaultComboBoxModel;
033    import javax.swing.JButton;
034    import javax.swing.JCheckBox;
035    import javax.swing.JColorChooser;
036    import javax.swing.JComboBox;
037    import javax.swing.JDialog;
038    import javax.swing.JFrame;
039    import javax.swing.JLabel;
040    import javax.swing.JPanel;
041    import javax.swing.JRadioButton;
042    import javax.swing.JSlider;
043    import javax.swing.JSpinner;
044    import javax.swing.JTextField;
045    import javax.swing.SpinnerNumberModel;
046    import javax.swing.SwingConstants;
047    import javax.swing.SwingUtilities;
048    import javax.swing.UIManager;
049    import javax.swing.event.ChangeEvent;
050    import javax.swing.event.ChangeListener;
051    import org.apache.batik.ext.awt.LinearGradientPaint;
052    import org.apache.batik.ext.awt.MultipleGradientPaint;
053    import org.jdesktop.swingx.action.AbstractActionExt;
054    import org.jdesktop.swingx.color.*;
055    import org.jdesktop.swingx.multislider.Thumb;
056    import org.jdesktop.swingx.multislider.ThumbListener;
057    
058    /**
059     * A specialized JXPanel that allows the user to construct and choose a Gradient.
060     * The returned values will be one of: GradientPaint, LinearGradientPaint, RadialGradientPaint.
061     *
062     * @author  jm158417
063     */
064    public class JXGradientChooser extends JXPanel {
065        public enum GradientStyle { Linear, Radial };
066    
067        /**
068         * The multi-thumb slider to use for the gradient stops
069         */
070        private JXMultiThumbSlider<Color> slider;
071        public JButton deleteThumbButton;
072        public JButton addThumbButton;
073    
074        public JTextField colorField;
075        public JXColorSelectionButton changeColorButton;
076        public JSpinner colorLocationSpinner;
077        public JSpinner alphaSpinner;
078        public JSlider alphaSlider;
079        
080        public JComboBox styleCombo;
081        public GradientPreviewPanel gradientPreview;
082        
083        public JRadioButton noCycleRadio;
084        public JRadioButton reflectedRadio;
085        public JRadioButton repeatedRadio;
086        public JCheckBox reversedCheck;
087        
088        Paint checker_texture = null;
089        
090        /** Creates new form GradientPicker */
091        public JXGradientChooser() {
092        initComponents2();
093        }
094        
095        
096        public MultipleGradientPaint getGradient() {
097        // get the list of colors
098        List<Thumb<Color>> stops = slider.getModel().getSortedThumbs();
099        int len = stops.size();
100        
101        // set up the data for the gradient
102        float[] fractions = new float[len];
103        Color[] colors = new Color[len];
104        int i = 0;
105        for(Thumb<Color> thumb : stops) {
106            colors[i] = (Color)thumb.getObject();
107            fractions[i] = thumb.getPosition();
108            i++;
109        }
110        // fill in the gradient
111        Point2D start = new Point2D.Float(0,0);
112        Point2D end = new Point2D.Float(getWidth(),0);
113        MultipleGradientPaint paint = new org.apache.batik.ext.awt.LinearGradientPaint(
114            (float)start.getX(),
115            (float)start.getY(),
116            (float)end.getX(),
117            (float)end.getY(),
118            fractions,colors);
119        return paint;
120        }
121        
122        public void setGradient(MultipleGradientPaint mgrad) {
123        while(slider.getModel().getThumbCount() > 0) {
124            slider.getModel().removeThumb(0);
125        }
126        float[] fracts = mgrad.getFractions();
127        Color[] colors = mgrad.getColors();
128        for(int i=0; i<fracts.length; i++) {
129            slider.getModel().addThumb(fracts[i],colors[i]);
130        }
131        repaint();
132        }
133        
134        private void updateFromStop(Thumb<Color> thumb) {
135        if(thumb == null) {
136            updateFromStop(-1,-1,Color.black);
137        } else {
138            updateFromStop(1,thumb.getPosition(),thumb.getObject());
139        }
140        }
141        
142        private void updateFromStop(int thumb, float position, Color color) {
143        if(thumb == -1) {
144            colorLocationSpinner.setEnabled(false);
145            alphaSpinner.setEnabled(false);
146            alphaSlider.setEnabled(false);
147            colorField.setEnabled(false);
148            changeColorButton.setEnabled(false);
149            changeColorButton.setBackground(Color.black);
150            deleteThumbButton.setEnabled(false);
151        } else {
152            colorLocationSpinner.setEnabled(true);
153            alphaSpinner.setEnabled(true);
154            alphaSlider.setEnabled(true);
155            colorField.setEnabled(true);
156            changeColorButton.setEnabled(true);
157            colorLocationSpinner.setValue((int)(100*position));
158            colorField.setText(Integer.toHexString(color.getRGB()).substring(2));
159            alphaSpinner.setValue((int)(color.getAlpha()*100/255));
160            alphaSlider.setValue(color.getAlpha()*100/255);
161            changeColorButton.setBackground(color);
162            deleteThumbButton.setEnabled(true);
163        }
164            updateDeleteButtons();
165        ((GradientPreviewPanel)gradientPreview).repaint();
166        }
167        private void updateDeleteButtons() {
168        if(slider.getModel().getThumbCount() <= 2) {
169            deleteThumbButton.setEnabled(false);
170        }
171        }
172        
173        public JXMultiThumbSlider<Color> getSlider() {
174            return slider;
175        }
176        
177        
178        /** This method is called from within the constructor to
179         * initialize the form.
180         */
181    
182        private JPanel topPanel, previewPanel;
183        private void initComponents() {
184            // declarations for anonymous components
185            JPanel jPanel1, jPanel2, jPanel3, jPanel4;
186            JLabel jLabel1, jLabel5, jLabel2, jLabel6, jLabel4, jLabel7, jLabel8, jLabel9;
187            ButtonGroup typeGroup;
188            // pre-init stuff
189            slider = new JXMultiThumbSlider<Color>();
190            gradientPreview = new GradientPreviewPanel();
191            
192            java.awt.GridBagConstraints gridBagConstraints;
193    
194            typeGroup = new javax.swing.ButtonGroup();
195            jPanel1 = new javax.swing.JPanel();
196            topPanel = new javax.swing.JPanel();
197            jPanel2 = new javax.swing.JPanel();
198            jLabel1 = new javax.swing.JLabel();
199            jLabel5 = new javax.swing.JLabel();
200            colorField = new javax.swing.JTextField();
201            jLabel2 = new javax.swing.JLabel();
202            jLabel6 = new javax.swing.JLabel();
203            colorLocationSpinner = new javax.swing.JSpinner();
204            jLabel4 = new javax.swing.JLabel();
205            jLabel7 = new javax.swing.JLabel();
206            alphaSpinner = new javax.swing.JSpinner();
207            changeColorButton = new JXColorSelectionButton();
208            alphaSlider = new javax.swing.JSlider();
209            //slider = new javax.swing.JSlider();
210            jPanel4 = new javax.swing.JPanel();
211            addThumbButton = new javax.swing.JButton();
212            deleteThumbButton = new javax.swing.JButton();
213            previewPanel = new javax.swing.JPanel();
214            jPanel3 = new javax.swing.JPanel();
215            jLabel8 = new javax.swing.JLabel();
216            styleCombo = new javax.swing.JComboBox();
217            jLabel9 = new javax.swing.JLabel();
218            noCycleRadio = new javax.swing.JRadioButton();
219            reflectedRadio = new javax.swing.JRadioButton();
220            repeatedRadio = new javax.swing.JRadioButton();
221            reversedCheck = new javax.swing.JCheckBox();
222            //gradientPreview = new javax.swing.JPanel();
223    
224            //setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
225            jPanel1.setLayout(new java.awt.GridBagLayout());
226    
227            topPanel.setLayout(new java.awt.GridBagLayout());
228    
229            topPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Gradient"));
230            jPanel2.setLayout(new java.awt.GridBagLayout());
231    
232            jLabel1.setText("Color:");
233            gridBagConstraints = new java.awt.GridBagConstraints();
234            gridBagConstraints.gridx = 0;
235            gridBagConstraints.gridy = 0;
236            gridBagConstraints.ipadx = 2;
237            gridBagConstraints.ipady = 2;
238            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
239            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
240            jPanel2.add(jLabel1, gridBagConstraints);
241    
242            jLabel5.setText("#");
243            gridBagConstraints = new java.awt.GridBagConstraints();
244            gridBagConstraints.gridx = 1;
245            gridBagConstraints.gridy = 0;
246            gridBagConstraints.insets = new java.awt.Insets(4, 0, 4, 4);
247            jPanel2.add(jLabel5, gridBagConstraints);
248    
249            colorField.setColumns(6);
250            colorField.setEnabled(false);
251            colorField.setPreferredSize(null);
252            gridBagConstraints = new java.awt.GridBagConstraints();
253            gridBagConstraints.gridy = 0;
254            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
255            jPanel2.add(colorField, gridBagConstraints);
256    
257            jLabel2.setText("Location:");
258            gridBagConstraints = new java.awt.GridBagConstraints();
259            gridBagConstraints.gridy = 1;
260            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
261            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
262            jPanel2.add(jLabel2, gridBagConstraints);
263    
264            jLabel6.setText("%");
265            gridBagConstraints = new java.awt.GridBagConstraints();
266            gridBagConstraints.gridy = 1;
267            jPanel2.add(jLabel6, gridBagConstraints);
268    
269            colorLocationSpinner.setEnabled(false);
270            colorLocationSpinner.setPreferredSize(null);
271            gridBagConstraints = new java.awt.GridBagConstraints();
272            gridBagConstraints.gridy = 1;
273            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
274            jPanel2.add(colorLocationSpinner, gridBagConstraints);
275    
276            jLabel4.setText("Opacity:");
277            gridBagConstraints = new java.awt.GridBagConstraints();
278            gridBagConstraints.gridy = 2;
279            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
280            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
281            jPanel2.add(jLabel4, gridBagConstraints);
282    
283            jLabel7.setText("%");
284            gridBagConstraints = new java.awt.GridBagConstraints();
285            gridBagConstraints.gridy = 2;
286            jPanel2.add(jLabel7, gridBagConstraints);
287    
288            alphaSpinner.setEnabled(false);
289            alphaSpinner.setPreferredSize(null);
290            gridBagConstraints = new java.awt.GridBagConstraints();
291            gridBagConstraints.gridy = 2;
292            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
293            jPanel2.add(alphaSpinner, gridBagConstraints);
294    
295            changeColorButton.setText("00");
296            changeColorButton.setEnabled(false);
297            gridBagConstraints = new java.awt.GridBagConstraints();
298            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
299            gridBagConstraints.weightx = 1.0;
300            gridBagConstraints.insets = new java.awt.Insets(0, 4, 0, 0);
301            jPanel2.add(changeColorButton, gridBagConstraints);
302    
303            alphaSlider.setEnabled(false);
304            alphaSlider.setPreferredSize(new java.awt.Dimension(20, 25));
305            gridBagConstraints = new java.awt.GridBagConstraints();
306            gridBagConstraints.gridy = 2;
307            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
308            gridBagConstraints.weightx = 1.0;
309            jPanel2.add(alphaSlider, gridBagConstraints);
310    
311            gridBagConstraints = new java.awt.GridBagConstraints();
312            gridBagConstraints.gridx = 0;
313            gridBagConstraints.gridy = 2;
314            gridBagConstraints.gridwidth = 2;
315            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
316            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
317            gridBagConstraints.weightx = 1.0;
318            gridBagConstraints.weighty = 1.0;
319            gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
320            topPanel.add(jPanel2, gridBagConstraints);
321    
322            gridBagConstraints = new java.awt.GridBagConstraints();
323            gridBagConstraints.gridy = 0;
324            gridBagConstraints.gridwidth = 2;
325            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
326            topPanel.add(slider, gridBagConstraints);
327    
328            jPanel4.setLayout(new java.awt.GridLayout(1, 0, 2, 0));
329    
330            addThumbButton.setText("Add");
331            jPanel4.add(addThumbButton);
332    
333            deleteThumbButton.setText("Delete");
334            jPanel4.add(deleteThumbButton);
335    
336            gridBagConstraints = new java.awt.GridBagConstraints();
337            gridBagConstraints.gridy = 1;
338            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
339            gridBagConstraints.weightx = 1.0;
340            gridBagConstraints.insets = new java.awt.Insets(5, 5, 5, 5);
341            topPanel.add(jPanel4, gridBagConstraints);
342    
343            gridBagConstraints = new java.awt.GridBagConstraints();
344            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
345            gridBagConstraints.weightx = 1.0;
346            jPanel1.add(topPanel, gridBagConstraints);
347    
348            previewPanel.setLayout(new java.awt.GridBagLayout());
349    
350            previewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder("Preview"));
351            jPanel3.setLayout(new java.awt.GridBagLayout());
352    
353            jLabel8.setText("Style:");
354            gridBagConstraints = new java.awt.GridBagConstraints();
355            gridBagConstraints.gridy = 0;
356            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
357            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
358            jPanel3.add(jLabel8, gridBagConstraints);
359    
360            styleCombo.setModel(new javax.swing.DefaultComboBoxModel(new String[] { "Linear", "Radial" }));
361            gridBagConstraints = new java.awt.GridBagConstraints();
362            gridBagConstraints.gridy = 0;
363            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
364            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
365            jPanel3.add(styleCombo, gridBagConstraints);
366    
367            jLabel9.setText("Type:");
368            gridBagConstraints = new java.awt.GridBagConstraints();
369            gridBagConstraints.gridy = 1;
370            gridBagConstraints.anchor = java.awt.GridBagConstraints.EAST;
371            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
372            jPanel3.add(jLabel9, gridBagConstraints);
373    
374            typeGroup.add(noCycleRadio);
375            noCycleRadio.setSelected(true);
376            noCycleRadio.setText("None");
377            noCycleRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
378            noCycleRadio.setMargin(new java.awt.Insets(0, 0, 0, 0));
379            gridBagConstraints = new java.awt.GridBagConstraints();
380            gridBagConstraints.gridy = 1;
381            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
382            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
383            jPanel3.add(noCycleRadio, gridBagConstraints);
384    
385            typeGroup.add(reflectedRadio);
386            reflectedRadio.setText("Reflect");
387            reflectedRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
388            reflectedRadio.setMargin(new java.awt.Insets(0, 0, 0, 0));
389            gridBagConstraints = new java.awt.GridBagConstraints();
390            gridBagConstraints.gridx = 1;
391            gridBagConstraints.gridy = 2;
392            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
393            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
394            jPanel3.add(reflectedRadio, gridBagConstraints);
395    
396            typeGroup.add(repeatedRadio);
397            repeatedRadio.setText("Repeat");
398            repeatedRadio.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
399            repeatedRadio.setMargin(new java.awt.Insets(0, 0, 0, 0));
400            gridBagConstraints = new java.awt.GridBagConstraints();
401            gridBagConstraints.gridx = 1;
402            gridBagConstraints.gridy = 3;
403            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
404            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
405            jPanel3.add(repeatedRadio, gridBagConstraints);
406    
407            reversedCheck.setText("Reverse");
408            reversedCheck.setBorder(javax.swing.BorderFactory.createEmptyBorder(0, 0, 0, 0));
409            reversedCheck.setMargin(new java.awt.Insets(0, 0, 0, 0));
410            gridBagConstraints = new java.awt.GridBagConstraints();
411            gridBagConstraints.gridx = 1;
412            gridBagConstraints.gridy = 4;
413            gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST;
414            gridBagConstraints.insets = new java.awt.Insets(4, 4, 4, 4);
415            jPanel3.add(reversedCheck, gridBagConstraints);
416    
417            gridBagConstraints = new java.awt.GridBagConstraints();
418            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHWEST;
419            previewPanel.add(jPanel3, gridBagConstraints);
420    
421            gradientPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder());
422            gradientPreview.setPreferredSize(new java.awt.Dimension(130, 130));
423            /*
424            org.jdesktop.layout.GroupLayout gradientPreviewLayout = new org.jdesktop.layout.GroupLayout(gradientPreview);
425            gradientPreview.setLayout(gradientPreviewLayout);
426            gradientPreviewLayout.setHorizontalGroup(
427                gradientPreviewLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
428                .add(0, 132, Short.MAX_VALUE)
429            );
430            gradientPreviewLayout.setVerticalGroup(
431                gradientPreviewLayout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
432                .add(0, 118, Short.MAX_VALUE)
433            );
434             */
435            gridBagConstraints = new java.awt.GridBagConstraints();
436            gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
437            gridBagConstraints.weightx = 10.0;
438            gridBagConstraints.weighty = 10.0;
439            previewPanel.add(gradientPreview, gridBagConstraints);
440    
441            gridBagConstraints = new java.awt.GridBagConstraints();
442            gridBagConstraints.gridy = 1;
443            gridBagConstraints.fill = java.awt.GridBagConstraints.BOTH;
444            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTH;
445            gridBagConstraints.weightx = 1.0;
446            gridBagConstraints.weighty = 1.0;
447            jPanel1.add(previewPanel, gridBagConstraints);
448    
449            /*
450            org.jdesktop.layout.GroupLayout layout = new org.jdesktop.layout.GroupLayout(getContentPane());
451            getContentPane().setLayout(layout);
452            layout.setHorizontalGroup(
453                layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
454                .add(layout.createSequentialGroup()
455                    .addContainerGap()
456                    .add(jPanel1, org.jdesktop.layout.GroupLayout.PREFERRED_SIZE, 253, Short.MAX_VALUE)
457                    .addContainerGap())
458            );
459            layout.setVerticalGroup(
460                layout.createParallelGroup(org.jdesktop.layout.GroupLayout.LEADING)
461                .add(layout.createSequentialGroup()
462                    .addContainerGap()
463                    .add(jPanel1, org.jdesktop.layout.GroupLayout.DEFAULT_SIZE, 321, Short.MAX_VALUE)
464                    .addContainerGap())
465            );
466            pack();
467             */
468        }// </editor-fold>    
469        private void initComponents2() {
470            this.initComponents();
471            setLayout(new BorderLayout());
472            add(topPanel, BorderLayout.NORTH);
473            add(previewPanel, BorderLayout.CENTER);
474            
475            
476            // do event handling stuff
477            //create the actions and load them in the action map
478            AddThumbAction addThumbAction = new AddThumbAction();
479            DeleteThumbAction deleteThumbAction = new DeleteThumbAction();
480            deleteThumbAction.setEnabled(false); //disabled to begin with
481            //TODO Add to the action map with proper keys, etc
482            ActionMap actions = getActionMap();
483            actions.put("add-thumb", addThumbAction);
484            actions.put("delete-thumb", deleteThumbAction);
485            //actions.put("change-color", changeColorAction);
486            addThumbButton.setAction(addThumbAction);
487            deleteThumbButton.setAction(deleteThumbAction);
488            changeColorButton.addPropertyChangeListener("background", new PropertyChangeListener() {
489                public void propertyChange(PropertyChangeEvent evt) {
490                    System.out.println("color bg changed");
491                    selectColorForThumb();
492                }
493            });
494            colorLocationSpinner.addChangeListener(new ChangeLocationListener());
495            ChangeAlphaListener changeAlphaListener = new ChangeAlphaListener();
496            alphaSpinner.addChangeListener(changeAlphaListener);
497            alphaSlider.addChangeListener(changeAlphaListener);
498            RepaintOnEventListener repaintListener = new RepaintOnEventListener();
499        styleCombo.addItemListener(repaintListener);
500        styleCombo.setModel(new DefaultComboBoxModel(GradientStyle.values()));
501            noCycleRadio.addActionListener(repaintListener);
502            reflectedRadio.addActionListener(repaintListener);
503            repeatedRadio.addActionListener(repaintListener);
504            reversedCheck.addActionListener(repaintListener);
505            gradientPreview.picker = this; //wow, nasty
506    
507            /*
508            //configure the panel
509            JXPanel topPanel = new JXPanel(new GridBagLayout());
510            topPanel.setBorder(BorderFactory.createTitledBorder("Gradient"));
511    
512            ///////////////// Build and Configure the slider panel/////////////////
513            JXPanel sliderPanel = new JXPanel(new GridBagLayout());
514            slider = new JXMultiThumbSlider<Color>();
515            addThumbButton = new JButton(addThumbAction);
516            deleteThumbButton = new JButton(deleteThumbAction);
517            
518            Insets stdInsets = new Insets(3,3,3,3);
519            sliderPanel.add(slider, new GridBagConstraints(0, 0, 2, 1, 1.0, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 5, 0), 0, 0));
520            sliderPanel.add(addThumbButton, new GridBagConstraints(0, 1, 1, 1, .5, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(0, 0, 0, 3), 0, 0));
521            sliderPanel.add(deleteThumbButton, new GridBagConstraints(1, 1, 1, 1, .5, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 3, 0, 0), 0, 0));
522            
523            topPanel.add(sliderPanel, new GridBagConstraints(0, 0, 3, 1, 1.0, 1.0, GridBagConstraints.PAGE_START, GridBagConstraints.HORIZONTAL, new Insets(7, 7, 12, 7), 0, 0));
524            ///////////////////////////////////////////////////////////////////////
525            
526            //////////////// Build and Configure the top panel ////////////////////
527            JLabel label = new JLabel("Color: #");
528            label.setHorizontalAlignment(SwingConstants.TRAILING);
529            colorField = new JTextField();
530            colorField.setText("000");
531            colorField.setEnabled(false);
532            label.setLabelFor(colorField);
533            changeColorButton = new JXColorSelectionButton();
534            changeColorButton.setText("");
535            changeColorButton.addPropertyChangeListener("background", new PropertyChangeListener() {
536                public void propertyChange(PropertyChangeEvent evt) {
537                    System.out.println("color bg changed");
538                    selectColorForThumb();
539                }
540            });
541            topPanel.add(label, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(2, 2, 2, 2), 0, 0));
542            topPanel.add(colorField, new GridBagConstraints(1, 1, 1, 1, .5, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
543            topPanel.add(changeColorButton, new GridBagConstraints(2, 1, 1, 1, .5, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
544            
545            label = new JLabel("Location: %");
546            label.setHorizontalAlignment(SwingConstants.TRAILING);
547            colorLocationSpinner = new JSpinner();
548            colorLocationSpinner.setEnabled(false);
549            colorLocationSpinner.addChangeListener(new ChangeLocationListener());
550            label.setLabelFor(colorLocationSpinner);
551            topPanel.add(label, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
552            topPanel.add(colorLocationSpinner, new GridBagConstraints(1, 2, 1, 1, 1.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
553            
554            ChangeAlphaListener changeAlphaListener = new ChangeAlphaListener();
555            label = new JLabel("Opacity: %");
556            label.setHorizontalAlignment(SwingConstants.TRAILING);
557            alphaSpinner = new JSpinner();
558            alphaSpinner.setEnabled(false);
559            ChangeAlphaListener changeAlphaListener = new ChangeAlphaListener();
560            alphaSpinner.addChangeListener(changeAlphaListener);
561            label.setLabelFor(alphaSpinner);
562            alphaSlider = new JSlider();
563            alphaSlider.setEnabled(false);
564            alphaSlider.addChangeListener(changeAlphaListener);
565            topPanel.add(label, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
566            topPanel.add(alphaSpinner, new GridBagConstraints(1, 3, 1, 1, .5, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
567            topPanel.add(alphaSlider, new GridBagConstraints(2, 3, 1, 1, .5, 0.0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, new Insets(0, 0, 0, 0), 0, 0));
568            
569            add(topPanel, BorderLayout.NORTH);
570            /////////////////////////////////////////////////////////////////////
571            
572    
573            JXPanel previewPanel = new JXPanel(new GridBagLayout());
574            previewPanel.setBorder(BorderFactory.createTitledBorder("Preview"));
575            
576            label = new JLabel("Style:");
577            styleCombo = new JComboBox();
578            RepaintOnEventListener repaintListener = new RepaintOnEventListener();
579        styleCombo.addItemListener(repaintListener);
580        styleCombo.setModel(new DefaultComboBoxModel(GradientStyle.values()));
581            label.setLabelFor(styleCombo);
582            previewPanel.add(label, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
583            previewPanel.add(styleCombo, new GridBagConstraints(1, 0, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
584    
585            label = new JLabel("Type");
586            previewPanel.add(label, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_END, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
587            
588            ButtonGroup typeGroup = new ButtonGroup();
589            noCycleRadio = new JRadioButton("None");
590            noCycleRadio.setSelected(true);
591            noCycleRadio.addActionListener(repaintListener);
592            typeGroup.add(noCycleRadio);
593            previewPanel.add(noCycleRadio, new GridBagConstraints(1, 1, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
594    
595            reflectedRadio = new JRadioButton("Reflect");
596            reflectedRadio.addActionListener(repaintListener);
597            typeGroup.add(reflectedRadio);
598            previewPanel.add(reflectedRadio, new GridBagConstraints(1, 2, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
599    
600            repeatedRadio = new JRadioButton("Repeat");
601            repeatedRadio.addActionListener(repaintListener);
602            typeGroup.add(repeatedRadio);
603            previewPanel.add(repeatedRadio, new GridBagConstraints(1, 3, 1, 1, 0.0, 0.0, GridBagConstraints.LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
604    
605            reversedCheck = new JCheckBox("Reverse");
606            reversedCheck.addActionListener(repaintListener);
607            previewPanel.add(reversedCheck, new GridBagConstraints(1, 4, 1, 1, 0.0, 0.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0));
608            
609            gradientPreview = new GradientPreviewPanel();
610            gradientPreview.picker = this; //wow, nasty
611            previewPanel.add(gradientPreview, new GridBagConstraints(2, 0, 1, 5, 1.0, 1.0, GridBagConstraints.FIRST_LINE_START, GridBagConstraints.BOTH, new Insets(0, 0, 0, 0), 0, 0));
612    
613            add(previewPanel);
614            */
615            
616            ///To still refactor below::
617        SpinnerNumberModel alpha_model = new SpinnerNumberModel(100,0,100,1);
618        alphaSpinner.setModel(alpha_model);
619        SpinnerNumberModel location_model = new SpinnerNumberModel(100,0,100,1);
620        colorLocationSpinner.setModel(location_model);
621        
622        checker_texture = ColorUtil.getCheckerPaint();
623        
624        slider.setOpaque(false);
625        slider.setPreferredSize(new Dimension(100,35));
626        slider.getModel().setMinimumValue(0f);
627        slider.getModel().setMaximumValue(1.0f);
628        
629        slider.getModel().addThumb(0,Color.black);
630        slider.getModel().addThumb(0.5f,Color.red);
631        slider.getModel().addThumb(1.0f,Color.white);
632        
633        slider.setThumbRenderer(new GradientThumbRenderer(this, slider));
634        slider.setTrackRenderer(new GradientTrackRenderer(this));
635        slider.addMultiThumbListener(new StopListener(slider));
636    //  
637    ////    gradient_selector.add(slider, "Center");
638        }
639    
640        private final class ChangeLocationListener implements ChangeListener {
641            public void stateChanged(ChangeEvent evt) {
642                if(slider.getSelectedIndex() >= 0) {
643                    Thumb thumb = slider.getModel().getThumbAt(slider.getSelectedIndex());
644                    thumb.setPosition((float)((Integer)colorLocationSpinner.getValue())/100);
645                    //slider.recalc();
646                    slider.repaint();
647                    updateFromStop(thumb);
648                }
649            }
650        }
651        
652        private final class ChangeAlphaListener implements ChangeListener {
653        public void stateChanged(ChangeEvent changeEvent) {
654                if(slider.getSelectedIndex() >= 0) {
655                    Thumb<Color> thumb = slider.getModel().getThumbAt(slider.getSelectedIndex());
656                    int alpha = changeEvent.getSource() == alphaSpinner ?
657                        (Integer)alphaSpinner.getValue()
658                        : alphaSlider.getValue();
659                    
660            Color col = (Color)thumb.getObject();
661                    col = ColorUtil.setAlpha(col, alpha*255/100);
662                    thumb.setObject(col);
663    
664                    if (changeEvent.getSource() == alphaSpinner) {
665                        alphaSlider.setValue(alpha);
666                    } else {
667                        alphaSpinner.setValue(alpha);
668                    }
669            slider.repaint();
670            gradientPreview.repaint();
671            }
672        }
673        }
674        private final class AddThumbAction extends AbstractActionExt {
675        public AddThumbAction() {
676            super("Add");
677        }
678        
679        public void actionPerformed(ActionEvent actionEvent) {
680            float pos = 0.2f;
681            Color color = Color.black;
682            for (int i = 0; i < slider.getModel().getThumbCount(); i++) {
683            float pos2 = slider.getModel().getThumbAt(i).getPosition();
684            if (pos2 < pos) {
685                continue;
686            }
687            slider.getModel().insertThumb(pos, color, i);
688            updateFromStop(i,pos,color);
689            break;
690            }
691            
692        }
693        }
694        private final class DeleteThumbAction extends AbstractActionExt {
695        public DeleteThumbAction() {
696            super("Delete");
697        }
698        
699        public void actionPerformed(ActionEvent actionEvent) {
700            int index = slider.getSelectedIndex();
701            if (index >= 0) {
702            slider.getModel().removeThumb(index);
703            updateFromStop(-1,-1,null);
704            }
705        }
706        }
707        
708        private class StopListener implements ThumbListener {
709        
710        private JXMultiThumbSlider slider;
711        
712        public StopListener(JXMultiThumbSlider slider) {
713            super();
714            this.slider = slider;
715        }
716        
717        public void thumbMoved(int thumb, float pos) {
718            Color color = (Color)slider.getModel().getThumbAt(thumb).getObject();
719            updateFromStop(thumb,pos,color);
720            updateDeleteButtons();
721        }
722        
723        public void thumbSelected(int thumb) {
724            if(thumb == -1) {
725            updateFromStop(-1,-1,Color.black);
726            return;
727            }
728            float pos = slider.getModel().getThumbAt(thumb).getPosition();
729            Color color = (Color)slider.getModel().getThumbAt(thumb).getObject();
730            updateFromStop(thumb,pos,color);
731            updateDeleteButtons();
732        }
733        public void mousePressed(MouseEvent e) {
734            if(e.getClickCount() > 1) {
735                selectColorForThumb();
736            }
737        }
738        }
739        
740        private final class RepaintOnEventListener implements ActionListener, ItemListener {
741            public void actionPerformed(ActionEvent e) {
742                gradientPreview.repaint();
743            }
744    
745            public void itemStateChanged(ItemEvent e) {
746                gradientPreview.repaint();
747            }
748        }
749        
750        private void selectColorForThumb() {
751        int index = slider.getSelectedIndex();
752        if (index >= 0) {
753            Color color = (Color)slider.getModel().getThumbAt(index).getObject();
754                color = changeColorButton.getBackground();
755                slider.getModel().getThumbAt(index).setObject(color);
756                updateFromStop(index, slider.getModel().getThumbAt(index).getPosition(), color);
757                slider.repaint();
758                ((GradientPreviewPanel)gradientPreview).repaint();
759        }
760        }
761        
762        /**
763         * This static utility method <b>cannot</b> be called from the
764         * ETD, or your application will lock up. Call it from a separate
765         * thread or create a new Thread with a Runnable.
766         */
767        public static MultipleGradientPaint showDialog(Component comp, String title, MultipleGradientPaint mgrad) {
768        Component root = SwingUtilities.getRoot(comp);
769        final JDialog dialog = new JDialog((JFrame)root,title,true);
770        final JXGradientChooser picker = new JXGradientChooser();
771        if(mgrad != null) {
772            picker.setGradient(mgrad);
773        }
774        dialog.add(picker);
775        
776        
777        JPanel panel = new JPanel();
778        JButton cancel = new JButton("Cancel");
779        cancel.addActionListener(new ActionListener() {
780            public void actionPerformed(ActionEvent actionEvent) {
781            dialog.setVisible(false);
782            }
783        });
784        JButton okay = new JButton("Ok");
785        okay.addActionListener(new ActionListener() {
786            public void actionPerformed(ActionEvent actionEvent) {
787            dialog.setVisible(false);
788            }
789        });
790            okay.setDefaultCapable(true);
791        
792        
793            GridLayout gl = new GridLayout();
794            gl.setHgap(2);
795            panel.setLayout(gl);
796        panel.add(cancel);
797        panel.add(okay);
798            
799            JPanel p2 = new JPanel();
800            p2.setLayout(new GridBagLayout());
801            GridBagConstraints gbc = new GridBagConstraints();
802            gbc.anchor = gbc.EAST;
803            gbc.weightx = 1.0;
804            p2.add(panel,gbc);
805        dialog.add(p2,"South");
806        
807            dialog.getRootPane().setDefaultButton(okay);
808        dialog.pack();
809            dialog.setResizable(false);
810        dialog.setVisible(true);
811        
812        return picker.getGradient();
813        }
814        
815        public static void main(String[] args) throws Exception {
816            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
817            Toolkit.getDefaultToolkit().setDynamicLayout(true);
818            final JFrame frame = new JFrame("Gradient Picker");
819            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
820            frame.getContentPane().setLayout(new BoxLayout(frame.getContentPane(),BoxLayout.Y_AXIS));
821            
822            JButton button = new JButton("Select Gradient");
823            button.addActionListener(new ActionListener() {
824                public void actionPerformed(ActionEvent e) {
825                    Color[] colors = { Color.blue, Color.black};
826                    float[] vals = {0.0f,1.0f};
827                    LinearGradientPaint paint = new LinearGradientPaint(0f,0f,10f,0f,vals,colors);
828                    MultipleGradientPaint grad = JXGradientChooser.showDialog(frame,"Pick a Gradient",paint);
829                    System.out.println("got: " + JXGradientChooser.toString(grad));
830                }
831            });
832            frame.add(button);    
833            frame.pack();
834            frame.setVisible(true);
835        }
836        
837        public static String toString(MultipleGradientPaint paint) {
838        StringBuffer buffer = new StringBuffer();
839        buffer.append(paint.getClass().getName());
840        Color[] colors = paint.getColors();
841        float[] values = paint.getFractions();
842        buffer.append("[");
843        for(int i=0; i<colors.length; i++) {
844            buffer.append("#"+Integer.toHexString(colors[i].getRGB()));
845            buffer.append(":");
846            buffer.append(values[i]);
847            buffer.append(", ");
848        }
849        buffer.append("]");
850        return buffer.toString();
851        }
852        
853    }
854    
855