/* Copyright (c) 2006-2007 Timothy Wall, All Rights Reserved * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * <p/> * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package furbelow; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.RenderingHints; import java.awt.Transparency; import java.awt.image.BufferedImage; import javax.swing.Icon; import javax.swing.ImageIcon; /** Provides a spinning disk of hash marks. */ public class SpinningDial extends AbstractAnimatedIcon { private static final int MIN_ALPHA = 32; private static final int DEFAULT_SIZE = 32; private static final int SPOKES = 16; /** This is a good delay between increasing the phase. */ public static final int SPIN_INTERVAL = 1000/SPOKES; private int w; private int h; private Image[] frames; public SpinningDial() { this(DEFAULT_SIZE, DEFAULT_SIZE); } /** Not recommended to go below 16x16. */ public SpinningDial(int w, int h) { this(w, h, SPOKES); } public SpinningDial(int w, int h, int spokes) { super(spokes, SPIN_INTERVAL); this.w = w; this.h = h; frames = new Image[getFrameCount()]; } public int getIconHeight() { return h; } public int getIconWidth() { return w; } /** Set the stroke width according to the size. */ protected float getStrokeWidth(int size) { return size/16f; } // TODO: move image snapshot up to abstract class protected void paintFrame(Component c, Graphics graphics, int x, int y) { int idx = getFrame(); if (frames[idx] == null) { int w = getIconWidth(); int h = getIconHeight(); int size = Math.min(w, h); Image image = c != null ? c.getGraphicsConfiguration().createCompatibleImage(w, h, Transparency.TRANSLUCENT) : new BufferedImage(w, h, BufferedImage.TYPE_INT_ARGB); Graphics2D g = (Graphics2D)image.getGraphics(); g.setComposite(AlphaComposite.Clear); g.fillRect(0, 0, w, h); g.setComposite(AlphaComposite.Src); g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); final int FULL_SIZE = 256; float strokeWidth = getStrokeWidth(FULL_SIZE); float fraction = .6f; g.setStroke(new BasicStroke(strokeWidth, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g.translate((float)w/2, (float)h/2); float scale = (float)size/FULL_SIZE; g.scale(scale, scale); int alpha = 255; int x1, y1, x2, y2; int radius = FULL_SIZE/2-1-(int)(strokeWidth/2); int frameCount = getFrameCount(); for (int i=0;i < frameCount;i++) { double cos = Math.cos(Math.PI*2-Math.PI*2*(i-idx)/frameCount); double sin = Math.sin(Math.PI*2-Math.PI*2*(i-idx)/frameCount); x1 = (int)(radius*fraction * cos); x2 = (int)(radius* cos); y1 = (int)(radius*fraction * sin); y2 = (int)(radius* sin); g.setColor(new Color(0,0,0,Math.min(255, alpha))); g.drawLine(x1, y1, x2, y2); alpha = Math.max(MIN_ALPHA, alpha*3/4); } g.dispose(); frames[idx] = image; } graphics.drawImage(frames[idx], x, y, null); } public String toString() { return "SpinningDial(" + getIconWidth() + "x" + getIconHeight() + ")"; } }