/* * Copyright (c) 2005, romain guy (romain.guy@jext.org) and craig wickesser (craig@codecraig.com) and henry story * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * * * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * * Neither the name of the <ORGANIZATION> nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package com.jidesoft.swing; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Area; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; public class InfiniteProgressPanel extends JComponent implements ActionListener { private static final int DEFAULT_NUMBER_OF_BARS = 12; private int numBars; private double dScale = 1.2d; private Area[] bars; private Rectangle barsBounds = null; private Rectangle barsScreenBounds = null; private AffineTransform centerAndScaleTransform = null; private Timer timer = new Timer(1000 / 16, this); private Color[] colors = null; private int colorOffset = 0; private boolean tempHide = false; public InfiniteProgressPanel() { this(1); } public InfiniteProgressPanel(double ratio) { this.numBars = DEFAULT_NUMBER_OF_BARS; colors = new Color[numBars * 2]; // build bars bars = buildTicker(numBars, ratio); // calculate bars bounding rectangle barsBounds = new Rectangle(); for (Area bar : bars) { barsBounds = barsBounds.union(bar.getBounds()); } // create colors for (int i = 0; i < bars.length; i++) { int channel = 224 - 128 / (i + 1); colors[i] = new Color(channel, channel, channel); colors[numBars + i] = colors[i]; } // set cursor //setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); // set opaque setOpaque(true); } /** * Called to animate the rotation of the bar's colors */ public void actionPerformed(ActionEvent e) { // rotate colors if (colorOffset == (numBars - 1)) { colorOffset = 0; } else { colorOffset++; } // repaint if (barsScreenBounds != null) { repaint(barsScreenBounds); } else { repaint(); } } /** * Show/Hide the pane, starting and stopping the animation as you go */ @Override public void setVisible(boolean i_bIsVisible) { setOpaque(false); // capture if (i_bIsVisible) { // start anim timer.start(); } else { // stop anim timer.stop(); } super.setVisible(i_bIsVisible); } /** * Recalc bars based on changes in size */ @Override public void setBounds(int x, int y, int width, int height) { super.setBounds(x, y, width, height); // update centering transform centerAndScaleTransform = new AffineTransform(); centerAndScaleTransform.translate((double) getWidth() / 2d, (double) getHeight() / 2d); centerAndScaleTransform.scale(dScale, dScale); // calc new bars bounds if (barsBounds != null) { Area oBounds = new Area(barsBounds); oBounds.transform(centerAndScaleTransform); barsScreenBounds = oBounds.getBounds(); } } /** * paint background dimmed and bars over top */ @Override protected void paintComponent(Graphics g) { if (!tempHide) { Rectangle oClip = g.getClipBounds(); if (isOpaque()) { g.setColor(getBackground()); g.fillRect(oClip.x, oClip.y, oClip.width, oClip.height); } // move to center Graphics2D g2 = (Graphics2D) g.create(); g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.transform(centerAndScaleTransform); // draw ticker for (int i = 0; i < bars.length; i++) { g2.setColor(colors[i + colorOffset]); g2.fill(bars[i]); } } } /* * Builds the circular shape and returns the result as an array of <code>Area</code>. Each <code>Area</code> is one of the bars composing the shape. */ private static Area[] buildTicker(int i_iBarCount, double ratio) { Area[] ticker = new Area[i_iBarCount]; Point2D.Double center = new Point2D.Double(0, 0); double fixedAngle = 2.0 * Math.PI / ((double) i_iBarCount); for (double i = 0.0; i < (double) i_iBarCount; i++) { Area primitive = buildPrimitive(ratio); AffineTransform toCenter = AffineTransform.getTranslateInstance(center.getX(), center.getY()); AffineTransform toBorder = AffineTransform.getTranslateInstance(2.0, -0.4); AffineTransform toCircle = AffineTransform.getRotateInstance(-i * fixedAngle, center.getX(), center.getY()); AffineTransform toWheel = new AffineTransform(); toWheel.concatenate(toCenter); toWheel.concatenate(toBorder); primitive.transform(toWheel); primitive.transform(toCircle); ticker[(int) i] = primitive; } return ticker; } /* * Builds a bar. */ private static Area buildPrimitive(double ratio) { // Rectangle2D.Double body = new Rectangle2D.Double(6, 0, 30, 12); // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 12, 12); // Ellipse2D.Double tail = new Ellipse2D.Double(30, 0, 12, 12); // Rectangle2D.Double body = new Rectangle2D.Double(3, 0, 15, 6); // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 6, 6); // Ellipse2D.Double tail = new Ellipse2D.Double(15, 0, 6, 6); // Rectangle2D.Double body = new Rectangle2D.Double(2, 0, 10, 4); // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 4, 4); // Ellipse2D.Double tail = new Ellipse2D.Double(10, 0, 4, 4); Rectangle2D.Double body = new Rectangle2D.Double(2 * ratio, 0, 4 * ratio, ratio); // Ellipse2D.Double head = new Ellipse2D.Double(0, 0, 2, 2); // Ellipse2D.Double tail = new Ellipse2D.Double(5, 0, 2, 2); // tick.add(new Area(head)); // tick.add(new Area(tail)); // return new Area(body); } public void start() { setVisible(true); } public void stop() { setVisible(false); } }