View Javadoc

1   /*
2    *  File: SmileyWidget.java 
3    *  Copyright (c) 2004-2007  Peter Kliem (Peter.Kliem@jaret.de)
4    *  A commercial license is available, see http://www.jaret.de.
5    *
6    * All rights reserved. This program and the accompanying materials
7    * are made available under the terms of the Common Public License v1.0
8    * which accompanies this distribution, and is available at
9    * http://www.eclipse.org/legal/cpl-v10.html
10   */
11  package de.jaret.util.ui;
12  
13  import javax.swing.BoundedRangeModel;
14  import javax.swing.DefaultBoundedRangeModel;
15  import javax.swing.event.ChangeEvent;
16  import javax.swing.event.ChangeListener;
17  
18  import org.eclipse.swt.SWT;
19  import org.eclipse.swt.events.PaintEvent;
20  import org.eclipse.swt.events.PaintListener;
21  import org.eclipse.swt.graphics.Color;
22  import org.eclipse.swt.graphics.GC;
23  import org.eclipse.swt.graphics.Path;
24  import org.eclipse.swt.widgets.Canvas;
25  import org.eclipse.swt.widgets.Composite;
26  import org.eclipse.swt.widgets.Display;
27  
28  /**
29   * Custom (fun) widget visualizing an integer as a smiley.
30   * 
31   * @author Peter Kliem
32   * @version $Id: SmileyWidget.java 242 2007-02-11 21:05:07Z olk $
33   */
34  public class SmileyWidget extends Canvas implements ChangeListener {
35      private double _currentValue = 0;
36      private BoundedRangeModel _brModel = new DefaultBoundedRangeModel(50, 0, 0, 100);
37      private boolean _eyeBrows = true;
38      private boolean _colorChange = true;
39  
40      private Color _neutral = Display.getCurrent().getSystemColor(SWT.COLOR_YELLOW);
41      private Color _positive = Display.getCurrent().getSystemColor(SWT.COLOR_GREEN);
42      private Color _negative = Display.getCurrent().getSystemColor(SWT.COLOR_RED);
43      private Color _currentColor;
44  
45      public SmileyWidget(Composite parent, int style) {
46          super(parent, style);
47          addPaintListener(new PaintListener() {
48              public void paintControl(PaintEvent event) {
49                  onPaint(event);
50              }
51          });
52          calcSmileFactor();
53          _brModel.addChangeListener(this);
54      }
55  
56      private void onPaint(PaintEvent event) {
57          GC gc = event.gc;
58          int width = getClientArea().width;
59          int height = getClientArea().height;
60  
61          int lineWidth = height / 40;
62          if (!_colorChange) {
63              gc.setBackground(_neutral);
64          } else {
65              if (_currentValue >= 0) { // positive
66                  gc.setBackground(calcColor(_positive));
67              } else { // negative
68                  gc.setBackground(calcColor(_negative));
69              }
70          }
71  
72          Path p = new Path(Display.getCurrent());
73          p.addArc(0 + lineWidth / 2, 0 + lineWidth / 2, width - 1 - lineWidth, height - 1 - lineWidth, 0, 360);
74          gc.fillPath(p);
75          gc.setForeground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
76          gc.setLineWidth(lineWidth);
77          gc.drawPath(p);
78          p.dispose();
79          // eyes
80          int y = height / 3;
81          int x1 = width / 3;
82          int x2 = width - width / 3;
83          int r = width / 30;
84          // eyes have a minimal size
85          if (r == 0) {
86              r = 1;
87          }
88          gc.setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_BLACK));
89          gc.fillOval(x1 - r, y - r, 2 * r, 2 * r);
90          gc.fillOval(x2 - r, y - r, 2 * r, 2 * r);
91          // eye brows
92          if (_eyeBrows) {
93              gc.setLineWidth(lineWidth / 2);
94              int ebWidth = width / 10;
95              int yDist = height / 13;
96              int yOff = (int) (_currentValue * (double) height / 30);
97              int xShift = (int) (_currentValue * (double) width / 90);
98              p = new Path(Display.getCurrent());
99              p.moveTo(x1 - ebWidth / 2 + xShift, y - yDist + yOff);
100             p.lineTo(x1 + ebWidth / 2 - xShift, y - yDist - yOff);
101             gc.drawPath(p);
102             p.dispose();
103 
104             p = new Path(Display.getCurrent());
105             p.moveTo(x2 - ebWidth / 2 + xShift, y - yDist - yOff);
106             p.lineTo(x2 + ebWidth / 2 - xShift, y - yDist + yOff);
107             gc.drawPath(p);
108             p.dispose();
109         }
110         // mouth
111         gc.setLineWidth(lineWidth);
112         x1 = (int) (width / 4.5);
113         x2 = width - x1;
114         y = height - height / 3;
115         int midX = width / 2;
116         int offset = (int) (_currentValue * (double) height / 3);
117         p = new Path(Display.getCurrent());
118         p.moveTo(x1, y);
119         p.quadTo(midX, y + offset, x2, y);
120         gc.drawPath(p);
121         p.dispose();
122     }
123 
124     /**
125      * Scales the BoundedRangeModel to [-1, 1]
126      */
127     private void calcSmileFactor() {
128         int range = _brModel.getMaximum() - _brModel.getMinimum();
129         int mid = _brModel.getMinimum() + range / 2;
130         int value = _brModel.getValue();
131         _currentValue = (double) (value - mid) / (double) (range / 2);
132         // due to rounding errors the smileFactor may be over 1
133         if (_currentValue > 1) {
134             _currentValue = 1;
135         } else if (_currentValue < -1) {
136             _currentValue = -1;
137         }
138     }
139 
140     public BoundedRangeModel getModel() {
141         return _brModel;
142     }
143 
144     public void setModel(BoundedRangeModel model) {
145         _brModel.removeChangeListener(this);
146         _brModel = model;
147         _brModel.addChangeListener(this);
148         calcSmileFactor();
149         redraw();
150     }
151 
152     /**
153      * Calculates the color beetween _neutral and the specified color
154      * 
155      * @param destColor
156      * @return the mixed color
157      */
158     private Color calcColor(Color destColor) {
159         int rDiff = destColor.getRed() - _neutral.getRed();
160         int gDiff = destColor.getGreen() - _neutral.getGreen();
161         int bDiff = destColor.getBlue() - _neutral.getBlue();
162         double factor = Math.abs(_currentValue);
163         int r = (int) ((double) rDiff * factor);
164         int g = (int) ((double) gDiff * factor);
165         int b = (int) ((double) bDiff * factor);
166 
167         if (_currentColor != null) {
168             _currentColor.dispose();
169         }
170         _currentColor = new Color(Display.getCurrent(), _neutral.getRed() + r, _neutral.getGreen() + g, _neutral
171                 .getBlue()
172                 - b);
173         return _currentColor;
174     }
175 
176     @Override
177     public void dispose() {
178         super.dispose();
179         if (_currentColor != null) {
180             _currentColor.dispose();
181         }
182     }
183 
184     /*
185      * (non-Javadoc)
186      * 
187      * @see javax.swing.event.ChangeListener#stateChanged(javax.swing.event.ChangeEvent)
188      */
189     public void stateChanged(ChangeEvent e) {
190         calcSmileFactor();
191         redraw();
192     }
193 
194     /**
195      * @return Returns the colorChange.
196      */
197     public boolean getColorChange() {
198         return _colorChange;
199     }
200 
201     /**
202      * @param colorChange The colorChange to set.
203      */
204     public void setColorChange(boolean colorChange) {
205         _colorChange = colorChange;
206         redraw();
207     }
208 
209     /**
210      * @return Returns the eyeBrows.
211      */
212     public boolean getEyeBrows() {
213         return _eyeBrows;
214     }
215 
216     /**
217      * @param eyeBrows The eyeBrows to set.
218      */
219     public void setEyeBrows(boolean eyeBrows) {
220         _eyeBrows = eyeBrows;
221         redraw();
222     }
223 
224     /**
225      * shortcut for getModel().setValue()
226      * 
227      * @see javax.swing.BoundedRangeModel
228      * @param value
229      */
230     public void setValue(int value) {
231         _brModel.setValue(value);
232     }
233 
234     /**
235      * @return Returns the negative.
236      */
237     public Color getNegative() {
238         return _negative;
239     }
240 
241     /**
242      * @param negative The negative to set.
243      */
244     public void setNegative(Color negative) {
245         _negative = negative;
246         redraw();
247     }
248 
249     /**
250      * @return Returns the neutral.
251      */
252     public Color getNeutral() {
253         return _neutral;
254     }
255 
256     /**
257      * Set the neutral color. If color change is not actiovated zhis color will be used to paint the smiley. default is
258      * classic YELLOW
259      * 
260      * @param neutral The neutral to set.
261      */
262     public void setNeutral(Color neutral) {
263         _neutral = neutral;
264         redraw();
265     }
266 
267     /**
268      * @return Returns the positive.
269      */
270     public Color getPositive() {
271         return _positive;
272     }
273 
274     /**
275      * @param positive The positive to set.
276      */
277     public void setPositive(Color positive) {
278         _positive = positive;
279         redraw();
280     }
281 
282 }