package se.cth.hedgehogphoto.view; import java.awt.AlphaComposite; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Composite; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.RenderingHints; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.beans.PropertyChangeEvent; import javax.swing.JComponent; import javax.swing.JLayer; import javax.swing.JPanel; import javax.swing.Timer; import javax.swing.plaf.LayerUI; /** * @modified Barnabas Sapan * * * * Copyright (c) 2011, Oracle and/or its affiliates. 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 Oracle or 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. */ @SuppressWarnings("serial") class LoadingLayer extends LayerUI<JPanel> implements ActionListener { private JLayer<JPanel> decoratedPanel; private boolean mIsRunning; private boolean mIsFadingOut; private Timer mTimer; private int mAngle; private int mFadeCount; private int mFadeLimit = 20; /** * @param panel the panel to decorate with a loading spinner. */ public LoadingLayer(JPanel panel){ this.decoratedPanel = new JLayer<JPanel>(panel, this); } /** * @return returns the decorated animated layer ready to be added to a container. */ public JLayer<JPanel> getDecoratedPanel(){ return this.decoratedPanel; } /** * Starts the animations, runs until stop is called. */ public void start() { if (this.mIsRunning) { return; } // Run a thread for animation. this.mIsRunning = true; this.mIsFadingOut = false; this.mFadeCount = 0; int fps = 30; int tick = 1000 / fps; this.mTimer = new Timer(tick, this); this.mTimer.start(); } /** * Stops the current animation while keeping the panel intact. */ public void stop() { this.mIsFadingOut = true; } /** * Stops the current animation and removes ourself. */ public void stopAndRemove(){ this.stop(); //Remove ourself this.decoratedPanel.removeAll(); } @Override public void paint (Graphics g, JComponent c) { int w = c.getWidth(); int h = c.getHeight(); // Paint the view. super.paint (g, c); if (!this.mIsRunning) { return; } Graphics2D g2 = (Graphics2D)g.create(); float fade = (float)this.mFadeCount / (float)this.mFadeLimit; // Gray it out. Composite urComposite = g2.getComposite(); g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .25f * fade)); g2.fillRect(0, 0, w, h); g2.setComposite(urComposite); // Paint the wait indicator. int s = Math.min(w, h) / 5; int cx = w / 2; int cy = h / 2; g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2.setStroke(new BasicStroke(s / 4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.WHITE); g2.rotate(Math.PI * this.mAngle / 180, cx, cy); for (int i = 0; i < 12; i++) { float scale = (12.0f - (float)i) / 12.0f; g2.drawLine(cx + s, cy, cx + s * 2, cy); g2.rotate(-Math.PI / 6, cx, cy); g2.setComposite(AlphaComposite.getInstance( AlphaComposite.SRC_OVER, scale * fade)); } g2.dispose(); } public void actionPerformed(ActionEvent e) { if (this.mIsRunning) { firePropertyChange("tick", 0, 1); this.mAngle += 3; if (this.mAngle >= 360) { this.mAngle = 0; } if (this.mIsFadingOut) { if (--this.mFadeCount == 0) { this.mIsRunning = false; this.mTimer.stop(); } } else if (this.mFadeCount < this.mFadeLimit) { this.mFadeCount++; } } } @SuppressWarnings("rawtypes") @Override public void applyPropertyChange(PropertyChangeEvent pce, JLayer l) { if ("tick".equals(pce.getPropertyName())) { l.repaint(); } } }