001/*
002 * $Id: GradientPreviewPanel.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.color;
023
024import java.awt.Color;
025import java.awt.Graphics;
026import java.awt.Graphics2D;
027import java.awt.LinearGradientPaint;
028import java.awt.MultipleGradientPaint;
029import java.awt.Paint;
030import java.awt.RadialGradientPaint;
031import java.awt.RenderingHints;
032import java.awt.event.MouseEvent;
033import java.awt.geom.Point2D;
034import java.util.List;
035import java.util.logging.Logger;
036
037import javax.swing.event.MouseInputAdapter;
038
039import org.jdesktop.swingx.JXGradientChooser;
040import org.jdesktop.swingx.JXPanel;
041import org.jdesktop.swingx.multislider.MultiThumbModel;
042import org.jdesktop.swingx.multislider.Thumb;
043import org.jdesktop.swingx.util.PaintUtils;
044
045/**
046 * <p><b>Dependency</b>: Because this class relies on LinearGradientPaint and
047 * RadialGradientPaint, it requires the optional MultipleGradientPaint.jar</p>
048 *  
049 * @author joshy
050 */
051public class GradientPreviewPanel extends JXPanel {
052    private Paint checker_texture = null;
053    private Point2D start, end;
054    public JXGradientChooser picker;
055    boolean moving_start = false;
056    boolean moving_end = false;
057    private boolean radial = false;
058    private boolean reversed = false;
059    private boolean reflected = false;
060    private boolean repeated = false;
061    private MultipleGradientPaint gradient;
062    
063    public GradientPreviewPanel() {
064        start = new Point2D.Float(10,10);
065        end = new Point2D.Float(80,10);
066        checker_texture = PaintUtils.getCheckerPaint();
067        MouseInputAdapter ma = new GradientMouseHandler();
068        this.addMouseListener(ma);
069        this.addMouseMotionListener(ma);
070    }
071    
072    public void setGradient() {
073        repaint();
074    }
075    
076    public void setGradient(MultipleGradientPaint grad) {
077        MultipleGradientPaint old = getGradient();
078        if(grad instanceof LinearGradientPaint) {
079            LinearGradientPaint paint = (LinearGradientPaint)grad;
080            this.start = paint.getStartPoint();
081            this.end = paint.getEndPoint();
082        } else {
083            RadialGradientPaint paint = (RadialGradientPaint)grad;
084            this.start = paint.getCenterPoint();
085            this.end = new Point2D.Double(start.getX(),start.getY()+paint.getRadius());
086        }
087        this.gradient = grad;
088        firePropertyChange("gradient", old, getGradient());
089        repaint();
090    }
091    
092    public MultipleGradientPaint getGradient() {
093        return this.gradient;
094    }
095
096    public MultipleGradientPaint calculateGradient() {
097        List<Thumb<Color>> stops = getStops();
098        int len = stops.size();
099        
100        // set up the data for the gradient
101        float[] fractions = new float[len];
102        Color[] colors = new Color[len];
103        int i = 0;
104        for (Thumb<Color> thumb : stops) {
105            colors[i] = (Color)thumb.getObject();
106            fractions[i] = thumb.getPosition();
107            i++;
108        }
109        
110        // get the final gradient
111        this.setGradient(calculateGradient(fractions, colors));
112        return getGradient();
113    }
114
115    private MultiThumbModel model;
116    private Logger log = Logger.getLogger(GradientPreviewPanel.class.getName());
117    
118    private List<Thumb<Color>> getStops() {
119        // calculate the color stops
120        return model == null ? null : model.getSortedThumbs();
121    }
122    
123    public void setMultiThumbModel(MultiThumbModel model) {
124        MultiThumbModel old = getMultiThumbModel();
125        this.model = model;
126        firePropertyChange("multiThumbModel", old, getMultiThumbModel());
127    }
128    
129    public MultiThumbModel getMultiThumbModel() {
130        return this.model;
131    }
132
133    @Override
134    protected void paintComponent(Graphics g) {
135        try {
136            Graphics2D g2 = (Graphics2D)g;
137            
138            // fill the background with checker first
139            g2.setPaint(checker_texture);
140            g.fillRect(0,0,getWidth(),getHeight());
141
142        
143            Paint paint = getGradient();
144            // fill the area
145            if(paint != null) {
146                g2.setPaint(paint);
147            } else {
148                g2.setPaint(Color.black);
149            }
150
151            g.fillRect(0,0,getWidth(),getHeight());
152
153            drawHandles(g2);
154        } catch (Exception ex) {
155            log .severe("ex: " + ex);
156        }
157    }
158    
159    private MultipleGradientPaint calculateGradient(final float[] fractions, final Color[] colors) {
160        // set up the end points
161        Point2D start = this.start;
162        Point2D end = this.end;
163        if(isReversed()) {
164        //if(picker.reversedCheck.isSelected()) {
165            start = this.end;
166            end = this.start;
167        }
168
169        // set up the cycle type
170        MultipleGradientPaint.CycleMethod cycle = MultipleGradientPaint.CycleMethod.NO_CYCLE;
171        if(isRepeated()) {
172        //if(picker.repeatedRadio.isSelected()) {
173            cycle = MultipleGradientPaint.CycleMethod.REPEAT;
174        }
175        if(isReflected()) {
176        //if(picker.reflectedRadio.isSelected()) {
177            cycle = MultipleGradientPaint.CycleMethod.REFLECT;
178        }
179        
180        // create the underlying gradient paint
181        MultipleGradientPaint paint = null;
182        if(isRadial()) { //picker.styleCombo.getSelectedItem().toString().equals("Radial")) {
183            paint = new RadialGradientPaint(
184            start, (float)start.distance(end),start,
185            fractions, colors, cycle, MultipleGradientPaint.ColorSpaceType.SRGB, null
186            );
187        } else {
188            paint = new LinearGradientPaint(
189            (float)start.getX(),
190            (float)start.getY(),
191            (float)end.getX(),
192            (float)end.getY(),
193            fractions,colors,cycle);            
194        }
195        return paint;
196    }
197    
198    private void drawHandles(final Graphics2D g2) {
199        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
200                RenderingHints.VALUE_ANTIALIAS_ON);
201        // draw the points and gradient line
202        g2.setColor(Color.black);
203        g2.drawOval((int)start.getX()-5,(int)start.getY()-5,10,10);
204        g2.setColor(Color.white);
205        g2.drawOval((int)start.getX()-4,(int)start.getY()-4,8,8);
206        
207        g2.setColor(Color.black);
208        g2.drawOval((int)end.getX()-5,(int)end.getY()-5,10,10);
209        g2.setColor(Color.white);
210        g2.drawOval((int)end.getX()-4,(int)end.getY()-4,8,8);
211        
212        g2.setColor(Color.darkGray);
213        g2.drawLine((int)start.getX(),(int)start.getY(),
214                (int)end.getX(),(int)end.getY());
215        g2.setColor(Color.gray);
216        g2.drawLine((int)start.getX()-1,(int)start.getY()-1,
217                (int)end.getX()-1,(int)end.getY()-1);
218    }
219    
220    private class GradientMouseHandler extends MouseInputAdapter {
221
222        @Override
223        public void mousePressed(MouseEvent evt) {
224            moving_start = false;
225            moving_end = false;
226            if (evt.getPoint().distance(start) < 5) {
227                moving_start = true;
228                start = evt.getPoint();
229                return;
230            }
231            
232            if (evt.getPoint().distance(end) < 5) {
233                moving_end = true;
234                end = evt.getPoint();
235                return;
236            }
237
238            start = evt.getPoint();
239        }
240
241        @Override
242        public void mouseDragged(MouseEvent evt) {
243            if (moving_start) {
244                start = evt.getPoint();
245            } else {
246                end = evt.getPoint();
247            }
248            calculateGradient();
249            repaint();
250        }
251    }
252
253    public boolean isRadial() {
254        return radial;
255    }
256
257    public void setRadial(boolean radial) {
258        boolean old = isRadial();
259        this.radial = radial;
260        firePropertyChange("radial", old, isRadial());
261    }
262
263    public boolean isReversed() {
264        return reversed;
265    }
266
267    public void setReversed(boolean reversed) {
268        boolean old = isReversed(); 
269        this.reversed = reversed;
270        firePropertyChange("reversed", old, isReversed());
271    }
272
273    public boolean isReflected() {
274        return reflected;
275    }
276
277    public void setReflected(boolean reflected) {
278        boolean old = isReflected();
279        this.reflected = reflected;
280        firePropertyChange("reflected", old, isReflected());
281    }
282
283    public boolean isRepeated() {
284        return repeated;
285    }
286
287    public void setRepeated(boolean repeated) {
288        boolean old = isRepeated();
289        this.repeated = repeated;
290        firePropertyChange("repeated", old, isRepeated());
291    }
292}
293