1   package org.wcb.gui.component;
2   
3   import java.awt.Color;
4   import java.awt.Component;
5   import java.awt.Dimension;
6   import java.awt.GradientPaint;
7   import java.awt.Graphics;
8   import java.awt.Graphics2D;
9   import java.awt.Insets;
10  import java.awt.Paint;
11  import java.awt.Rectangle;
12  import java.awt.RenderingHints;
13  import java.awt.geom.Area;
14  import java.awt.geom.CubicCurve2D;
15  import java.awt.geom.GeneralPath;
16  import java.awt.geom.Rectangle2D;
17  
18  import javax.swing.AbstractButton;
19  import javax.swing.ButtonModel;
20  import javax.swing.JButton;
21  import javax.swing.JComponent;
22  import javax.swing.border.AbstractBorder;
23  import javax.swing.border.CompoundBorder;
24  import javax.swing.plaf.basic.BasicBorders;
25  import javax.swing.plaf.ComponentUI;
26  import javax.swing.plaf.UIResource;
27  import javax.swing.plaf.metal.MetalButtonUI;
28  import javax.swing.plaf.metal.MetalLookAndFeel;
29  
30  /**
31   * <small>
32   * <p/>
33   * Copyright (c)  2006  wbogaardt.
34   * This library is free software; you can redistribute it and/or
35   * modify it under the terms of the GNU Lesser General Public
36   * License as published by the Free Software Foundation; either
37   * version 2.1 of the License, or (at your option) any later version.
38   *
39   * This library is distributed in the hope that it will be useful,
40   * but WITHOUT ANY WARRANTY; without even the implied warranty of
41   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
42   * Lesser General Public License for more details.
43   *
44   * You should have received a copy of the GNU Lesser General Public
45   * License along with this library; if not, write to the Free Software
46   * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
47   * <p/>
48   * $File:  $ <br>
49   * $Change:  $ submitted by $Author: wbogaardt $ at $DateTime: Sep 12, 2006 10:29:51 AM $ <br>
50   * </small>
51   *
52   * @author wbogaardt
53   *         Wavey button look.
54   */
55  
56  public class WaveButtonUI extends MetalButtonUI {
57  
58      private static final WaveButtonUI INSTANCE = new WaveButtonUI();
59  
60      public static ComponentUI createUI(JComponent b) {
61          return INSTANCE;
62      }
63  
64      public void installUI(JComponent c) {
65          super.installUI(c);
66          c.setBorder(new CompoundBorder(new WaveButtonBorder(), new BasicBorders.MarginBorder()));
67      }
68  
69      protected Color getSelectColor() {
70          return new Color(0x005092);
71          //return new Color(183, 234, 98);
72      }
73  
74      protected void paintButtonPressed(Graphics g, AbstractButton b) {
75          if (b.isContentAreaFilled()) {
76              Graphics2D g2 = (Graphics2D) g;
77              g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
78              g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
79              g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
80  
81              Dimension size = b.getSize();
82              g2.setColor(getSelectColor());
83              g2.fillRect(0, 0, size.width, size.height);
84          }
85      }
86  
87      public void update(Graphics g, JComponent c) {
88          AbstractButton b = (AbstractButton) c;
89          if (c.isOpaque() && b.isContentAreaFilled()) {
90              int width = b.getWidth();
91              int height = b.getHeight();
92  
93              g.setColor(b.getBackground());
94              g.fillRect(0, 0, width, height);
95  
96              if (!b.getModel().isArmed() && !b.getModel().isPressed()) {
97                  Graphics2D g2 = (Graphics2D) g;
98                  g2.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
99                  g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
100                 g2.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
101 
102                 CubicCurve2D curve = new CubicCurve2D.Double(0, height, 4, -2, width - 4, height + 2, width, 0);
103                 GeneralPath path = new GeneralPath(curve);
104                 path.lineTo(width, height);
105                 path.lineTo(0, height);
106 
107                 Rectangle2D fillArea = new Rectangle2D.Double(0, 0, width, height);
108                 Area area = new Area(fillArea);
109                 area.subtract(new Area(path));
110 
111                 Paint oldPaint = g2.getPaint();
112 
113                 Paint p;
114 
115                 if (b.getModel().isEnabled()) {
116                     //p = new GradientPaint(0, 0, new Color(162, 234, 41), 0, height, new Color(220, 255, 124));
117                     p = new GradientPaint(0, 0, new Color(150, 183, 210), 0, height, new Color(124, 165, 199));
118                     g2.setPaint(p);
119                 }
120                 else {
121                     g2.setColor(new Color(245, 245, 245));
122                 }
123                 g2.fill(area);
124 
125                 if (b.getModel().isEnabled()) {
126                     //p = new GradientPaint(0, 0, new Color(165, 207, 118), 0, height, new Color(193, 232, 145));
127                     p = new GradientPaint(0, 0, new Color(92, 143, 185), 0, height, new Color(51, 115, 168));
128                     g2.setPaint(p);
129                 }
130                 else {
131                     g2.setColor(new Color(227, 227, 227));
132                 }
133                 g2.fill(path);
134 
135                 g2.setPaint(oldPaint);
136             }
137         }
138         paint(g, c);
139     }
140 
141     protected void paintFocus(Graphics g, AbstractButton b, Rectangle viewRect, Rectangle textRect, Rectangle iconRect) {
142     }
143 
144     // The WaveButtonBorder code comes from Karsten Lentzsch's Plastic LnF source code
145     // refer to Plastic's license (looks.dev.java.net)
146 
147     private static class WaveButtonBorder extends AbstractBorder implements UIResource {
148         protected static final Insets INSETS = new Insets(2, 2, 2, 2);
149 
150         public void paintBorder(Component c, Graphics g, int x, int y, int w, int h) {
151             AbstractButton button = (AbstractButton) c;
152             ButtonModel    model  = button.getModel();
153 
154             if (!model.isEnabled()) {
155                 drawDisabledButtonBorder(g, x, y, w, h);
156                 return;
157             }
158 
159             boolean isPressed = model.isPressed() && model.isArmed();
160             boolean isDefault = button instanceof JButton
161                     && ((JButton) button).isDefaultButton();
162             boolean isFocused = button.isFocusPainted() && button.hasFocus();
163 
164             if (isPressed) {
165                 drawPressedButtonBorder(g, x, y, w, h);
166             }
167             else if (isFocused) {
168                 drawFocusedButtonBorder(g, x, y, w, h);
169             }
170             else if (isDefault) {
171                 drawDefaultButtonBorder(g, x, y, w, h);
172             }
173             else {
174                 drawPlainButtonBorder(g, x, y, w, h);
175             }
176         }
177 
178         private void drawPlainButtonBorder(Graphics g, int x, int y, int w, int h) {
179             drawButtonBorder(g, x, y, w, h,
180                     MetalLookAndFeel.getControl(),
181                     MetalLookAndFeel.getControlDarkShadow(),
182                     getSlightlyBrighter(
183                             MetalLookAndFeel.getControlDarkShadow(),
184                             1.25f)
185             );
186         }
187 
188         private void drawPressedButtonBorder(Graphics g, int x, int y, int w, int h) {
189             drawPlainButtonBorder(g, x, y, w, h);
190             Color darkColor =
191                     translucentColor(MetalLookAndFeel.getControlDarkShadow(),
192                             128);
193             Color lightColor =
194                     translucentColor(MetalLookAndFeel.getControlHighlight(),
195                             80);
196             g.translate(x, y);
197             g.setColor(darkColor);
198             g.fillRect(2, 1,  w - 4, 1);
199 
200             g.setColor(lightColor);
201             g.fillRect(2, h - 2,  w - 4, 1);
202             g.translate(-x, -y);
203         }
204 
205         private void drawDefaultButtonBorder(Graphics g, int x, int y, int w, int h) {
206             drawPlainButtonBorder(g, x, y, w, h);
207             drawInnerButtonDecoration(g, x, y, w, h,
208                     new Color(215, 215, 215));
209         }
210 
211         private void drawFocusedButtonBorder(Graphics g, int x, int y, int w, int h) {
212             drawPlainButtonBorder(g, x, y, w, h);
213             //drawInnerButtonDecoration(g, x, y, w, h,      new Color(102, 153, 51));
214             drawInnerButtonDecoration(g, x, y, w, h,
215                     new Color(187, 200, 211));
216         }
217 
218         private void drawRect(Graphics g, int x, int y, int w, int h) {
219             g.fillRect(x,   y,   w + 1, 1);
220             g.fillRect(x,   y + 1, 1,   h);
221             g.fillRect(x + 1, y + h, w,   1);
222             g.fillRect(x + w, y + 1, 1,   h);
223         }
224 
225         private void drawDisabledButtonBorder(Graphics g, int x, int y, int w, int h) {
226             drawButtonBorder(g, x, y, w, h,
227                     MetalLookAndFeel.getControl(),
228                     new Color(215, 215, 215),
229                     getSlightlyBrighter(new Color(215, 215, 215)));
230         }
231 
232         private Color getSlightlyBrighter(Color color) {
233             return getSlightlyBrighter(color, 1.1f);
234         }
235 
236         private Color getSlightlyBrighter(Color color, float factor) {
237             float[] hsbValues = new float[3];
238             Color.RGBtoHSB(
239                     color.getRed(),
240                     color.getGreen(),
241                     color.getBlue(),
242                     hsbValues);
243             float hue = hsbValues[0];
244             float saturation = hsbValues[1];
245             float brightness = hsbValues[2];
246             float newBrightness = Math.min(brightness * factor, 1.0f);
247             return Color.getHSBColor(hue, saturation, newBrightness);
248         }
249 
250         private void drawButtonBorder(
251                 Graphics g,
252                 int x, int y, int w, int h,
253                 Color backgroundColor,
254                 Color edgeColor,
255                 Color cornerColor) {
256             g.translate(x, y);
257             // Edges
258             g.setColor(edgeColor);
259             drawRect(g, 0, 0,  w - 1, h - 1);
260 
261             // Near corners
262             g.setColor(cornerColor);
263             g.fillRect(0,   0,   2, 2);
264             g.fillRect(0,   h - 2, 2, 2);
265             g.fillRect(w - 2, 0,   2, 2);
266             g.fillRect(w - 2, h - 2, 2, 2);
267 
268             // Corners
269             g.setColor(backgroundColor);
270             g.fillRect(0,   0,   1, 1);
271             g.fillRect(0,   h - 1, 1, 1);
272             g.fillRect(w - 1, 0,   1, 1);
273             g.fillRect(w - 1, h - 1, 1, 1);
274 
275             g.translate(-x, -y);
276         }
277 
278         private void drawInnerButtonDecoration(
279                 Graphics g,
280                 int x, int y, int w, int h,
281                 Color baseColor) {
282 
283             Color lightColor  = translucentColor(baseColor,  90);
284             Color mediumColor = translucentColor(baseColor, 120);
285             Color darkColor   = translucentColor(baseColor, 200);
286 
287             g.translate(x, y);
288             g.setColor(lightColor);
289             g.fillRect(2, 1,  w - 4, 1);
290 
291             g.setColor(mediumColor);
292             g.fillRect(1,   2,  1,   h - 4);
293             g.fillRect(w - 2, 2,  1,   h - 4);
294             drawRect(g, 2,   2,  w - 5, h - 5);
295 
296             g.setColor(darkColor);
297             g.fillRect(2,   h - 2,  w - 4, 1);
298             g.translate(-x, -y);
299         }
300 
301         private static Color translucentColor(Color baseColor, int alpha) {
302             return new Color(baseColor.getRed(),
303                     baseColor.getGreen(),
304                     baseColor.getBlue(),
305                     alpha);
306         }
307 
308         public Insets getBorderInsets(Component c) { return INSETS; }
309 
310         public Insets getBorderInsets(Component c, Insets newInsets) {
311             newInsets.top = INSETS.top;
312             newInsets.left = INSETS.left;
313             newInsets.bottom = INSETS.bottom;
314             newInsets.right = INSETS.right;
315             return newInsets;
316         }
317     }
318 }