package photoSpreadUtilities;
import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Point;
import java.awt.image.BufferedImage;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JLabel;
/**
* @author paepcke
*
* This glass pane class provides the following services:
* - Any components added to this pane will float
* on top of the regular (contentPane's) UI components.
* NOTE: Currently only JLabel is supported. Not buttons,
* which would not be clickable anyway.
* - One component or image may be added to an instance
* of this class via setCursorTrailer(). This item
* will trail the cursor, offset by a value set
* through setCursorTrailOffset(). This trail will have
* transparency (alpha value) set via setAlpha().
* - As for the superclass, all events are passed through
* to the underlying contentPane. Active elements like
* buttons will therefore not work on this pane. They
* will only show.
*
* - Visibility control:
*
* The cursor trail's visibility can be controlled via
* setCursorTrailVisible(boolean). The other components'
* visibility is controlled via setComponentVisible(boolean).
*
* Both cursor trail and component visibility together
* are controlled by setVisible(boolean).
*
* An instance of this class must be set as the glass panel
* of a JPanel (setGlassPane()).
*
* NOTE: for the cursor trail image of a component to show up,
* you must ensure that the component has been laid out.
* A way to do this, for instance for a button:
*
* contentPane.add(cursorTrailButton);
* window.pack();
* contentPane.remove(cursorTrailButton);
*
* Where contentPane is a content pane that was obtained via
* getContentPane() on a JFrame, or that is a normal
* JPanel that is later given to a JFrame via
* setContentPane();
*/
public class OsmoticOverlayTracker extends OsmoticGlassPane {
private static final long serialVersionUID = 1L;
private JComponent _cursorTrailComponent = null;
private Image _cursorTrailImage = null;
private Dimension _cursorTrailOffset = new Dimension(0,0);
private float _alphaValue = 0.7f;
private boolean _componentsVisible = true;
private boolean _cursorTrailVisible = true;
public OsmoticOverlayTracker(JFrame frame) {
super(frame);
setLayout(new BorderLayout());
}
public void setCursorTrailer (Image cursorTrailImage) {
// Check for zero size:
if ((cursorTrailImage.getHeight(null) <= 0) ||
(cursorTrailImage.getWidth(null) <= 0))
throw new RuntimeException(
"Labels to use for cursor trail " +
"images must contain an ImageIcon. " +
"This label's ImageIcon has zero width and/or height.");
_cursorTrailImage = cursorTrailImage;
}
public void setCursorTrailer (JComponent cursorTrailComponent) {
// Ensure that the component that's to be used
// as a cursor trailer either contains a preferred
// size, or has non-zero dimensions:
if ((cursorTrailComponent.getPreferredSize() == null) &&
((cursorTrailComponent.getHeight() <= 0) ||
(cursorTrailComponent.getWidth() <= 0)))
throw new RuntimeException(
"Labels to use for cursor trail " +
"components must either have a specified " +
"preferred size, or non-zero with and height. " +
"This component does not satisfy either condition.");
_cursorTrailComponent = cursorTrailComponent;
// Make sure that an image is created of this
// component next time paintComponent() is called:
_cursorTrailImage = null;
}
/**
* @param _alphaValue the _alphaValue to set
*/
public void setAlphaValue(float _alphaValue) {
this._alphaValue = _alphaValue;
}
/**
* @return the _alphaValue
*/
public float getAlphaValue() {
return _alphaValue;
}
public void setCursorTrailOffset(Dimension cursorTrailOffset) {
this._cursorTrailOffset = cursorTrailOffset;
}
public Dimension getCursorTrailOffset() {
return _cursorTrailOffset;
}
/**
* @param _componentsVisible the _componentsVisible to set
*/
public void setComponentsVisible(boolean componentsVisible) {
this._componentsVisible = componentsVisible;
}
/**
* @return the _componentsVisible
*/
public boolean isComponentsVisible() {
return _componentsVisible;
}
/**
* @param _cursorTrailVisible the _cursorTrailVisible to set
*/
public void setCursorTrailVisible(boolean cursorTrailVisible) {
this._cursorTrailVisible = cursorTrailVisible;
}
/**
* @return the _cursorTrailVisible
*/
public boolean isCursorTrailVisible() {
return _cursorTrailVisible;
}
public boolean isCursorTrailSet () {
return ((_cursorTrailImage != null) ||
(_cursorTrailComponent != null));
}
/**
* Paint all the regular components, like buttons, that have
* been added to the glass pane, plus the special overlay component
* that follows the cursor.
*
* For an example of drawing a fixed-location rectangle on this
* glass pane, and a circle that follows the cursor: see
* the commented out body of the superclass' paintComponent().
*
* @see photoSpreadUtilities.OsmoticGlassPane#paintComponent(java.awt.Graphics)
*/
protected void paintComponent(Graphics g) {
// Have all the standard components
// on this glass pane be drawn. (Like
// buttons, etc.):
Graphics2D g2 = (Graphics2D) g;
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, _alphaValue));
if (_componentsVisible) {
// Draw all components:
// ******super.paintComponents(g2);
// Draw labels again:
Component compToShow;
JLabel labelComp = null;
Component[] comps = getComponents();
for (int i=0; i<getComponentCount(); i++) {
compToShow = comps[i];
try {
labelComp = (JLabel) compToShow;
} catch (ClassCastException e) {
// Component is not a JLabel
}
g2.drawImage(((ImageIcon) labelComp.getIcon()).getImage(), 0, 0, null);
}
}
if (!_cursorTrailVisible)
return;
// Does the image of the overlay component
// need to be created? Yes, if the
// user set an overlay component, but
// this is the first time that paintComponent()
// was called since then, and we therefore haven't
// created an image of the component yet:
if ((_cursorTrailImage == null) &&
(_cursorTrailComponent != null)) {
// Create a BufferedImage, get its graphics
// context, and have the cursor trail component
// paint itself onto it. So do this we want
// the component's preferred size, or if that's
// unavailable, its current size. We guaranteed in
// setTrailerComponent() that those are not both
// zero:
Dimension prefDim = _cursorTrailComponent.getPreferredSize();
_cursorTrailComponent.setSize(prefDim);
if (prefDim == null) {
prefDim = new Dimension (_cursorTrailComponent.getWidth(),
_cursorTrailComponent.getHeight());
}
int cursorTrailWidth = prefDim.width;
int cursorTrailHeight = prefDim.height;
_cursorTrailImage = new BufferedImage(
cursorTrailWidth,
cursorTrailHeight,
BufferedImage.TYPE_INT_ARGB);
Graphics2D gComponentImage = ((BufferedImage) _cursorTrailImage).createGraphics();
_cursorTrailComponent.paint(gComponentImage);
}
// If an cursor trail image exists, draw it at
// offset _overlayOffset from the cursor position:
Point cursorSnapshot = getCursorLoc();
if ((getCursorLoc() != null) &&
(_cursorTrailImage != null)) {
g2.drawImage(
_cursorTrailImage,
// null, // No transform operation
cursorSnapshot.x + _cursorTrailOffset.width,
cursorSnapshot.y + _cursorTrailOffset.height,
null); // no ImageObserver
}
g2.dispose();
}
/****************************************************
* Main and/or Testing Methods
* @return
*****************************************************/
/*
private static void createAndShowGUI () {
JFrame window = new JFrame();
Dimension emptySpaceDim = new Dimension(50, 50);
Box.Filler emptySpace1 = new Box.Filler(emptySpaceDim, emptySpaceDim, emptySpaceDim);
Box.Filler emptySpace2 = new Box.Filler(emptySpaceDim, emptySpaceDim, emptySpaceDim);
Box.Filler emptySpace3 = new Box.Filler(emptySpaceDim, emptySpaceDim, emptySpaceDim);
JButton testButtonNorth = new JButton("North");
JButton testButtonCenter= new JButton("Center");
JButton testButtonSouth = new JButton("South");
JButton buttonGlass = new JButton("Glass");
buttonGlass.setBackground(Color.BLUE);
OsmoticOverlayTracker glassPane = new OsmoticOverlayTracker(window);
glassPane.setLayout(new BorderLayout());
JPanel contentPane = (JPanel) window.getContentPane();
contentPane.setLayout(new BorderLayout());
contentPane.setBackground(Color.YELLOW);
contentPane.add(testButtonNorth, BorderLayout.NORTH);
// contentPane.add(emptySpace2, BorderLayout.CENTER);
contentPane.add(testButtonCenter, BorderLayout.CENTER);
contentPane.add(testButtonSouth, BorderLayout.SOUTH);
window.setGlassPane(glassPane);
glassPane.setOpaque(false);
glassPane.setVisible(true);
glassPane.add(emptySpace1, BorderLayout.NORTH);
glassPane.add(buttonGlass, BorderLayout.CENTER);
glassPane.add(emptySpace2, BorderLayout.SOUTH);
window.setContentPane(contentPane);
window.setBounds(1000, 1000, 300, 300);
window.pack();
window.setVisible(true);
// Make a component that will follow the
// cursor at partial transparency as an
// image on the glass pane:
JButton xButton = new JButton("XMen");
xButton.setPreferredSize(new Dimension(100,100));
// Must ensure that the component gets properly sized:
contentPane.add(xButton);
window.pack();
contentPane.remove(xButton);
// Tell glass pane to use this button
// as the cursor-following overlay:
glassPane.setCursorTrailer(xButton);
}
public static void main (String[] args) {
//Schedule a job for the event-dispatching thread:
//creating and showing this application's GUI.
javax.swing.SwingUtilities.invokeLater(new Runnable() {
public void run() {
createAndShowGUI();
}
});
System.out.println("Done");
}
*/
}