package net.homelinux.nikiroo.utils.gui;
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.Insets;
import java.awt.LayoutManager;
import java.awt.Paint;
import java.awt.Rectangle;
import javax.swing.ImageIcon;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JViewport;
/**
* Support custom painting on a panel in the form of
images - that can be
* scaled, tiled or painted at original size non solid painting - that
* can be done by using a Paint object Also, any component added directly
* to this panel will be made non-opaque so that the custom painting can show
* through.
*/
public class JBackgroundPanel extends JPanel {
private static final long serialVersionUID = 1L;
public static final int SCALED = 0;
public static final int TILED = 1;
public static final int ACTUAL = 2;
public static final int RATIO = 3;
private Paint painter;
private Image image;
private int style = SCALED;
private float alignmentX = 0.5f;
private float alignmentY = 0.5f;
private boolean isTransparentAdd = true;
/**
* Empty {@link JBackgroundPanel}.
*/
public JBackgroundPanel() {
}
/**
* Empty {@link JBackgroundPanel} with the given {@link LayoutManager}.
*/
public JBackgroundPanel(LayoutManager layout) {
super(layout);
}
/*
* Set image as the background with the SCALED style
*/
public JBackgroundPanel(ImageIcon image) {
this(image.getImage());
}
/*
* Set image as the background with the SCALED style
*/
public JBackgroundPanel(ImageIcon image, int style) {
this(image.getImage(), style);
}
/*
* Set image as the backround with the specified style and alignment
*/
public JBackgroundPanel(ImageIcon image, int style, float alignmentX, float alignmentY) {
this(image.getImage(), style, alignmentX, alignmentY);
}
/*
* Set image as the background with the SCALED style
*/
public JBackgroundPanel(Image image) {
this(image, SCALED);
}
/*
* Set image as the background with the specified style
*/
public JBackgroundPanel(Image image, int style) {
setImage(image);
setStyle(style);
setLayout(new BorderLayout());
}
/*
* Set image as the backround with the specified style and alignment
*/
public JBackgroundPanel(Image image, int style, float alignmentX, float alignmentY) {
setImage(image);
setStyle(style);
setImageAlignmentX(alignmentX);
setImageAlignmentY(alignmentY);
setLayout(new BorderLayout());
}
/*
* Use the Paint interface to paint a background
*/
public JBackgroundPanel(Paint painter) {
setPaint(painter);
setLayout(new BorderLayout());
}
/*
* Set the image used as the background
*/
public void setImage(Image image) {
this.image = image;
repaint();
}
/*
* Set the style used to paint the background image
*/
public void setStyle(int style) {
this.style = style;
repaint();
}
/*
* Set the Paint object used to paint the background
*/
public void setPaint(Paint painter) {
this.painter = painter;
repaint();
}
/*
* Specify the horizontal alignment of the image when using ACTUAL style
*/
public void setImageAlignmentX(float alignmentX) {
this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX;
repaint();
}
/*
* Specify the horizontal alignment of the image when using ACTUAL style
*/
public void setImageAlignmentY(float alignmentY) {
this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY;
repaint();
}
/*
* Override method so we can make the component transparent
*/
public void add(JComponent component) {
add(component, null);
}
/*
* Override to provide a preferred size equal to the image size
*/
@Override
public Dimension getPreferredSize() {
if (image == null)
return super.getPreferredSize();
else
return new Dimension(image.getWidth(null), image.getHeight(null));
}
/*
* Override method so we can make the component transparent
*/
public void add(JComponent component, Object constraints) {
if (isTransparentAdd) {
makeComponentTransparent(component);
}
super.add(component, constraints);
}
/*
* Controls whether components added to this panel should automatically be
* made transparent. That is, setOpaque(false) will be invoked. The default
* is set to true.
*/
public void setTransparentAdd(boolean isTransparentAdd) {
this.isTransparentAdd = isTransparentAdd;
}
/*
* Try to make the component transparent. For components that use renderers,
* like JTable, you will also need to change the renderer to be transparent.
* An easy way to do this it to set the background of the table to a Color
* using an alpha value of 0.
*/
private void makeComponentTransparent(JComponent component) {
component.setOpaque(false);
if (component instanceof JScrollPane) {
JScrollPane scrollPane = (JScrollPane) component;
JViewport viewport = scrollPane.getViewport();
viewport.setOpaque(false);
Component c = viewport.getView();
if (c instanceof JComponent) {
((JComponent) c).setOpaque(false);
}
}
}
/*
* Add custom painting
*/
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
// Invoke the painter for the background
if (painter != null) {
Dimension d = getSize();
Graphics2D g2 = (Graphics2D) g;
g2.setPaint(painter);
g2.fill(new Rectangle(0, 0, d.width, d.height));
}
// Draw the image
if (image == null)
return;
switch (style) {
case RATIO:
drawRatio(g);
break;
case SCALED:
drawScaled(g);
break;
case TILED:
drawTiled(g);
break;
case ACTUAL:
drawActual(g);
break;
default:
drawScaled(g);
}
}
/*
* Custom painting code for drawing a SCALED image as the background
*/
private void drawScaled(Graphics g) {
Dimension d = getSize();
g.drawImage(image, 0, 0, d.width, d.height, null);
}
/*
* Custom painting code for drawing TILED images as the background
*/
private void drawTiled(Graphics g) {
Dimension d = getSize();
int width = image.getWidth(null);
int height = image.getHeight(null);
for (int x = 0; x < d.width; x += width) {
for (int y = 0; y < d.height; y += height) {
g.drawImage(image, x, y, null, null);
}
}
}
/*
* Custom painting code for drawing the ACTUAL image as the background. The
* image is positioned in the panel based on the horizontal and vertical
* alignments specified.
*/
private void drawActual(Graphics g) {
Dimension d = getSize();
Insets insets = getInsets();
int width = d.width - insets.left - insets.right;
int height = d.height - insets.top - insets.left;
float x = (width - image.getWidth(null)) * alignmentX;
float y = (height - image.getHeight(null)) * alignmentY;
g.drawImage(image, (int) x + insets.left, (int) y + insets.top, this);
}
private void drawRatio(Graphics g) {
if (image != null && g != null) {
// si la dimension actuelle est > � la preferedSize (qui est
// elle-meme a la taille de l'avatar)
int h = (this.getHeight() - image.getHeight(null)) / 2;
int w = (this.getWidth() - image.getWidth(null)) / 2;
if (h < 0) {
h = 0;
}
if (w < 0) {
w = 0;
}
// TODO: alignment, solid paint
g.drawImage(image, w, h, null, null);
}
}
}