001:package org.zilonis.tool.ui;
002:
003:import java.awt.AlphaComposite;
004:import java.awt.Color;
005:import java.awt.Composite;
006:import java.awt.Dimension;
007:import java.awt.Font;
008:import java.awt.FontMetrics;
009:import java.awt.Graphics;
010:import java.awt.Graphics2D;
011:import java.awt.Image;
012:import java.awt.Insets;
013:import java.awt.RenderingHints;
014:import java.awt.event.MouseAdapter;
015:import java.awt.event.MouseEvent;
016:import java.awt.font.TextLayout;
017:import java.awt.geom.Rectangle2D;
018:import java.awt.image.BufferedImage;
019:
020:import javax.swing.Action;
021:import javax.swing.BorderFactory;
022:import javax.swing.ButtonModel;
023:import javax.swing.JButton;
024:import javax.swing.JComponent;
025:import javax.swing.plaf.basic.BasicButtonUI;
026:
027:import org.jdesktop.animation.timing.Animator;
028:import org.jdesktop.animation.timing.TimingTarget;
029:import org.jdesktop.fuse.InjectedResource;
030:import org.jdesktop.fuse.ResourceInjector;
031:import org.zilonis.tool.ext.aerith.g2d.GraphicsUtil;
032:
033:/**
034: *
035: * @author rbair
036: */
037:public class ActionButton extends JButton {
038:
039: private float shadowOffsetX;
040: private float shadowOffsetY;
041:
042: @InjectedResource(key="Common.shadowColor")
043: private Color shadowColor;
044: @InjectedResource(key="Common.shadowDirection")
045: private int shadowDirection;
046:
047: @InjectedResource()
048: private Image mainButton, mainButtonPressed,
049: normalButton, normalButtonPressed, buttonHighlight;
050: @InjectedResource
051: private int shadowDistance;
052: @InjectedResource
053: private Insets sourceInsets;
054: @InjectedResource
055: private Dimension buttonDimension;
056: @InjectedResource
057: private Color buttonForeground;
058: @InjectedResource
059: private Font buttonFont;
060:
061: private float ghostValue;
062:
063: private boolean main = false;
064:
065: public ActionButton(String text) {
066: this ();
067: setText(text);
068: }
069:
070: public ActionButton(Action a) {
071: this ();
072: setAction(a);
073: }
074:
075: public ActionButton() {
076:
077: ResourceInjector.get().inject(this );
078:
079: computeShadow();
080:
081: addMouseListener(new HiglightHandler());
082:
083: setBorder(BorderFactory.createEmptyBorder(0, 0, 0, 0));
084: setForeground(buttonForeground);
085: setFont(buttonFont);
086: setContentAreaFilled(false);
087: setBorderPainted(false);
088: setFocusable(false);
089:
090: // Hacky? Hacky!
091: setUI(new BasicButtonUI() {
092: @Override
093: public Dimension getMinimumSize(JComponent c) {
094: return getPreferredSize(c);
095: }
096:
097: @Override
098: public Dimension getMaximumSize(JComponent c) {
099: return getPreferredSize(c);
100: }
101:
102: @Override
103: public Dimension getPreferredSize(JComponent c) {
104: Insets insets = c.getInsets();
105: Dimension d = new Dimension(buttonDimension);
106: d.width += insets.left + insets.right;
107: d.height += insets.top + insets.bottom;
108: return d;
109: }
110: });
111: }
112:
113: public void setMain(boolean main) {
114: boolean old = isMain();
115: this .main = main;
116: firePropertyChange("main", old, isMain());
117: }
118:
119: public boolean isMain() {
120: return main;
121: }
122:
123: private void computeShadow() {
124: double rads = Math.toRadians(shadowDirection);
125: shadowOffsetX = (float) Math.cos(rads) * shadowDistance;
126: shadowOffsetY = (float) Math.sin(rads) * shadowDistance;
127: }
128:
129: private Image getImage(boolean armed) {
130: if (isMain()) {
131: return armed ? mainButtonPressed : mainButton;
132: } else {
133: return armed ? normalButtonPressed : normalButton;
134: }
135: }
136:
137: @Override
138: protected void paintComponent(Graphics g) {
139: Graphics2D g2 = (Graphics2D) g;
140: g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
141: RenderingHints.VALUE_ANTIALIAS_ON);
142:
143: ButtonModel m = getModel();
144: Insets insets = getInsets();
145:
146: int width = getWidth() - insets.left - insets.right;
147: int height = getHeight() - insets.top - insets.bottom;
148:
149: GraphicsUtil.tileStretchPaint(g2,this ,(BufferedImage) getImage(m.isArmed()), sourceInsets);
150:
151: if (ghostValue > 0.0f) {
152: g2.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
153: RenderingHints.VALUE_INTERPOLATION_BILINEAR);
154:
155: float alphaValue = ghostValue;
156: Composite composite = g2.getComposite();
157: if (composite instanceof AlphaComposite) {
158: alphaValue *= ((AlphaComposite) composite).getAlpha();
159: }
160:
161: g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,
162: alphaValue));
163:
164: g2.drawImage(buttonHighlight,
165: insets.left + 2, insets.top + 2,
166: width - 4, height - 4, null);
167: g2.setComposite(composite);
168: }
169:
170: FontMetrics fm = getFontMetrics(getFont());
171: TextLayout layout = new TextLayout(getText(),
172: getFont(),
173: g2.getFontRenderContext());
174: Rectangle2D bounds = layout.getBounds();
175:
176: int x = (int) (getWidth() - insets.left - insets.right -
177: bounds.getWidth()) / 2;
178: //x -= 2;
179: int y = (getHeight() - insets.top - insets.bottom -
180: fm.getMaxAscent() - fm.getMaxDescent()) / 2;
181: y += fm.getAscent() - 1;
182:
183: if (m.isArmed()) {
184: x += 1;
185: y += 1;
186: }
187:
188: g2.setColor(shadowColor);
189: layout.draw(g2,
190: x + (int) Math.ceil(shadowOffsetX),
191: y + (int) Math.ceil(shadowOffsetY));
192: g2.setColor(getForeground());
193: layout.draw(g2, x, y);
194: }
195:
196: private final class HiglightHandler extends MouseAdapter {
197: private Animator timer;
198:
199: @Override
200: public void mouseEntered(MouseEvent e) {
201: if (timer != null && timer.isRunning()) {
202: timer.stop();
203: }
204: timer = new Animator(300, new AnimateGhost(true));
205: timer.start();
206: }
207:
208: @Override
209: public void mouseExited(MouseEvent e) {
210: if (timer != null && timer.isRunning()) {
211: timer.stop();
212: }
213: timer = new Animator(300, new AnimateGhost(false));
214: timer.start();
215: }
216: }
217:
218: private final class AnimateGhost implements TimingTarget {
219: private boolean forward;
220: private float oldValue;
221:
222: AnimateGhost(boolean forward) {
223: this .forward = forward;
224: oldValue = ghostValue;
225: }
226:
227: public void timingEvent(float fraction) {
228: ghostValue = oldValue + fraction * (forward ? 1.0f : -1.0f);
229:
230: if (ghostValue > 1.0f) {
231: ghostValue = 1.0f;
232: } else if (ghostValue < 0.0f) {
233: ghostValue = 0.0f;
234: }
235:
236: repaint();
237: }
238: public void repeat() {
239:
240: }
241: public void begin() {
242: }
243:
244: public void end() {
245: }
246: }
247:}
|