FadingPopup
package com.gossamer.voyant.client.ui.dialog;
import com.gossamer.voyant.client.AppStyle;
import com.gossamer.voyant.client.Voyant;
import com.gossamer.voyant.client.swing.FormDesignerPanel;
import org.jdesktop.animation.timing.Animator;
import org.jdesktop.animation.timing.interpolation.PropertySetter;
import org.jdesktop.swinghelper.layer.JXLayer;
import org.jdesktop.swinghelper.layer.painter.AbstractPainter;
import javax.swing.*;
import javax.swing.text.BadLocationException;
import javax.swing.text.Style;
import javax.swing.text.StyleContext;
import javax.swing.text.StyledDocument;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/**
*
*
*/
public class FadingPopup extends JPanel {
private float alpha = 1.0f;
private BufferedImage img;
private Dimension dimension;
private JComponent content;
private Animator animator;
private int fadeTime;
private int fadeDelay = 1000;
private float acceleration = 0.2f;
private float deceleration = 0.4f;
private boolean fading; // Indicates that an animator is currently fading out this popup
/**
* Default fade time of 3000 milliseconds
* @param text text you want in the popup
*/
public static void popup(String text) {
popup(makeContent(text));
}
/**
* Default fade time of 3000 milliseconds
* @param content the JComponent you want displayed in the popup. Add a FadingPopupListener to any components to which you want click events passed.
*/
public static void popup(JComponent content) {
new FadingPopup(content).popup(3000);
}
public static void popup(int fadeTime, String text) {
popup(fadeTime, makeContent(text));
}
/**
* @param fadeTime
* @param content the JComponent you want displayed in the popup. Add a FadingPopupListener to any components to which you want click events passed.
*/
public static void popup(int fadeTime, JComponent content) {
new FadingPopup(content).popup(fadeTime);
}
/**
* @param fadeTime
* @param content the JComponent you want displayed in the popup. Add a FadingPopupListener to any components to which you want click events passed.
* @param x The x value will be the right-side coordinate of the popup
*/
public static void popupToTheLeftOf(int fadeTime, JComponent content, int x) {
new FadingPopup(content).popupToTheLeftOf(fadeTime, x);
}
private static JComponent makeContent(String text) {
if (text == null) {
return new JLabel();
}
FormDesignerPanel form = new FormDesignerPanel("com/gossamer/voyant/client/forms/dialogs/fadingPopup.jfd");
JTextPane textArea = form.getTextPane("textPane");
JPanel underIcon = form.getPanel("underIcon");
JLabel icon = form.getLabel("icon");
StyledDocument doc = textArea.getStyledDocument();
Style def = StyleContext.getDefaultStyleContext().getStyle(StyleContext.DEFAULT_STYLE);
try {
doc.remove(0, doc.getLength());
doc.insertString(doc.getLength(), text, def);
} catch (BadLocationException e) {
}
textArea.setFont(new Font("Arial", Font.PLAIN, 12));
return form;
}
public FadingPopup(String text) {
this(makeContent(text));
}
public FadingPopup(final JComponent content) {
setLayout(new GridBagLayout());
GridBagConstraints gc = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.BOTH, new Insets(7, 2, 1, 1), 0, 0);
this.content = content;
img = AppStyle.getInstance().popupBackground;
dimension = new Dimension(img.getWidth(), img.getHeight());
final JXLayer layer = new JXLayer(content);
layer.setPainter(new TransparentPainter<JComponent>());
add(layer, gc);
layer.getGlassPane().addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
cancelFade();
}
@Override
public void mouseExited(MouseEvent e) {
fadeQuick();
}
@Override
public void mouseClicked(MouseEvent e) {
// First, pass events down into any components that are listening - if they're listening with a FadingPopupListener
Component c = SwingUtilities.getDeepestComponentAt(layer.getView(), e.getX(), e.getY());
if (c instanceof AbstractButton) {
AbstractButton b = (AbstractButton) c;
for (ActionListener al : b.getActionListeners()) {
if (al instanceof FadingPopupListener) {
al.actionPerformed(new ActionEvent(c, 0, ""));
}
}
}
dismiss();
}
});
}
@Override
public Dimension getPreferredSize() {
return dimension;
}
public void popup(int fadeTime) {
popupToTheLeftOf(fadeTime, Voyant.getFrame().getSize().width);
}
public void popupToTheLeftOf(int fadeTime, int x) {
popup(fadeTime, x - img.getWidth() - 17);
}
private void popup(int fadeTime, int x) {
this.fadeTime = fadeTime;
Voyant.getFrame().showOnTopOnGlassPane(this, x, getPopupY(), false);
doLayout();
validate();
repaint();
fade();
}
public void setAlpha(float alpha) {
this.alpha = alpha;
if (alpha <= 0.01f) {
dismiss();
}
repaint();
}
public float getAlpha() {
return this.alpha;
}
@Override
public void paint(Graphics g) {
BufferedImage img2 = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.OPAQUE);
Graphics2D imgGraphics = img2.createGraphics();
Graphics2D panelGraphics = (Graphics2D) g.create();
imgGraphics.drawImage(img, 0, 0, null);
imgGraphics.setClip(new Rectangle2D.Double(0, 0, img.getWidth() - 2, img.getHeight() - 2));
imgGraphics.dispose();
panelGraphics.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, alpha));
panelGraphics.drawImage(img2, 0, 0, null);
setOpaque(false);
content.setOpaque(false);
super.paint(panelGraphics);
panelGraphics.dispose();
}
private int getPopupY() {
return Voyant.getFrame().getSize().height - img.getHeight() - 44;
}
private void fade() {
fade(fadeTime);
}
private void fadeQuick() {
setAlpha(0.8f);
fade(fadeTime);
}
private synchronized void fade(int fadeTime) {
if (fading) {
return;
}
animator = new Animator(fadeTime);
animator.addTarget(new PropertySetter(this, "alpha", 0.0f));
animator.setStartDelay(fadeDelay);
animator.setAcceleration(acceleration);
animator.setDeceleration(deceleration);
animator.start();
fading = true;
}
private synchronized void dismiss() {
setVisible(false);
Voyant.getFrame().removeFromGlassPane(this);
animator.cancel();
fading = false;
}
private synchronized void cancelFade() {
animator.cancel();
setAlpha(1.0f);
fading = false;
fadeDelay = 0; // Set to zero now that they've moused over it once. Don't make em wait in the future.
}
private static class TransparentPainter<V extends JComponent>
extends AbstractPainter<V> {
public void paint(Graphics2D g2, JXLayer<V> l) {
l.setOpaque(false);
l.paint(g2);
if (!l.isEnabled()) {
g2.setColor(new Color(0.0f, 0.0f, 0.0f, 0.0f));
g2.fillRect(0, 0, l.getWidth(), l.getHeight());
}
}
}
public static interface FadingPopupListener extends ActionListener {}
}