components/visual-panels/core/src/java/util/com/oracle/solaris/vp/util/swing/FadablePanel.java
author Dan Labrecque <dan.labrecque@oracle.com>
Thu, 24 May 2012 04:16:47 -0400
changeset 827 0944d8c0158b
permissions -rw-r--r--
7169052 Integrate Visual Panels into Userland

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */

/*
 * Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 */

package com.oracle.solaris.vp.util.swing;

import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import javax.swing.border.*;
import org.jdesktop.animation.timing.*;

@SuppressWarnings({"serial"})
public class FadablePanel extends JPanel implements TimingTarget {
    //
    // Instance data
    //

    private AlphaComposite composite;
    private BufferedImage image;
    private boolean useImageBuffer;

    private AnimatedBooleanProperty faded =
	new AnimatedBooleanProperty(500, this);

    private ShowingListener showListener =
	new ShowingListener() {
	    @Override
	    public void componentHidden() {
		setFaded(true, false);
	    }

	    public void componentShown() {
		setFaded(false);
	    }
	};

    //
    // Constructors
    //

    public FadablePanel(LayoutManager layout) {
	setLayout(layout == null ? new BorderLayout() : layout);
	setOpaque(false);
    }

    public FadablePanel() {
	this((LayoutManager)null);
    }

    public FadablePanel(JComponent c) {
	this();
	add(c, BorderLayout.CENTER);
    }

    //
    // TimingTarget methods
    //

    @Override
    public void begin() {
	// No implementation here -- setup should occur before the animator is
	// started since the clock is ticking at this point.  A design flaw in
	// the timing framework?  Perhaps.
    }

    @Override
    public void end() {
	image = null;
    }

    @Override
    public void repeat() {
    }

    @Override
    public void timingEvent(float alpha) {
	setAlpha(1f - alpha);
	repaint();
    }

    //
    // Component methods
    //

    @Override
    public void paint(Graphics g) {
	Composite composite = this.composite;
	if (composite == null) {
	    super.paint(g);
	    return;
	}

	Graphics2D g2 = (Graphics2D)g;
	Composite old = g2.getComposite();
	g2.setComposite(composite);

	if (useImageBuffer) {
	    if (image == null) {
		// We have just begun animating -- paint initially to an image
		image = new BufferedImage(getWidth(), getHeight(),
		    BufferedImage.TYPE_INT_ARGB);
		Graphics2D iG = image.createGraphics();
		super.paint(iG);
	    }

	    g2.drawImage(image, 0, 0, null);
	} else {
	    super.paint(g2);
	}

	g2.setComposite(old);
    }

    //
    // FadablePanel methods
    //

    public float getAlpha() {
	return composite == null ? 1f : composite.getAlpha();
    }

    public Animator getAnimator() {
	return faded.getAnimator();
    }

    public boolean getUseImageBuffer() {
	return useImageBuffer;
    }

    public boolean isFaded() {
	return faded.getValue();
    }

    public void setAlpha(float alpha) {
	this.composite = alpha == 1f ? null : AlphaComposite.getInstance(
	    AlphaComposite.SRC_OVER, alpha);
    }

    public void setFaded(boolean value) {
	setFaded(value, isShowing());
    }

    public void setFaded(boolean value, boolean animated) {
	faded.setValue(value, animated);
    }

    /**
     * Synchronizes the fade of this component with its visibility.  When this
     * {@code FadePanel} becomes both visible and displayable, it fades in.
     * When this {@code FadePanel} loses either visibility or displayability, it
     * fades out.
     * <p>
     * This synchronization may facilitate using a {@code FadePanel} as a glass
     * pane.
     *
     * @param	    synch
     *		    {@code true} to establish this link, {@code false} to remove
     *		    this link if set up previously
     */
    public void setSyncFadeWithVisibility(boolean synch) {
	if (synch) {
	    // Make sure listener is only added once
	    removeListener();

	    addHierarchyListener(showListener);
	    showListener.updateShowing(this);
	} else {
	    removeListener();
	}
    }

    public void setUseImageBuffer(boolean useImageBuffer) {
	this.useImageBuffer = useImageBuffer;
    }

    //
    // Private methods
    //

    private void removeListener() {
	removeHierarchyListener(showListener);
    }

    //
    // Static methods
    //

    // XXX Unit test - remove
    public static void main(String args[]) {
	JButton b1 = new JButton("Hello");
	JLabel b2 = new JLabel("There");

	Border border = new CompoundBorder(
	    new EmptyBorder(5, 5, 5, 5),
	    new LineBorder(ColorUtil.getRandomColor(), 5));

	JPanel p = new JPanel(new GridLayout());
	p.setBackground(ColorUtil.getRandomColor());
	p.setBorder(border);
	p.add(b1);
	p.add(b2);

	final FadablePanel fadePanel = new FadablePanel(p);
	fadePanel.setBorder(border);

	JButton fadeButton = new JButton("fade");
	fadeButton.addActionListener(
	    new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
		    boolean faded = fadePanel.isFaded();
		    fadePanel.setFaded(!faded);
		}
	    });

	JButton fadeNowButton = new JButton("fade immediately");
	fadeNowButton.addActionListener(
	    new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
		    boolean faded = fadePanel.isFaded();
		    fadePanel.setFaded(!faded, false);
		}
	    });

	JButton stopButton = new JButton("stop");
	stopButton.addActionListener(
	    new ActionListener() {
		@Override
		public void actionPerformed(ActionEvent e) {
		    fadePanel.getAnimator().stop();
		}
	    });

	JFrame frame = new JFrame();
	Container c = frame.getContentPane();
	c.setBackground(Color.red);
	c.setLayout(new GridLayout());
	c.add(fadePanel);
	c.add(fadeButton);
	c.add(fadeNowButton);
	c.add(stopButton);
	frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
	frame.pack();
	Dimension d = frame.getSize();
	frame.setSize(d.width * 2, d.height * 2);
	frame.setVisible(true);
    }
}