/* * * Copyright 2014 http://Bither.net * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * / */ package net.bither.viewsystem.panels; import com.google.common.base.Optional; import com.google.common.base.Preconditions; import net.bither.viewsystem.components.ImageDecorator; import javax.swing.*; import java.awt.*; public class BackgroundPanel extends JPanel { /** * Image will be scaled to fill the panel */ public static final int SCALED = 0; /** * Image will be tiled to fill the background */ public static final int TILED = 1; /** * Image will be rendered as is (see alignment for positioning) */ public static final int ACTUAL = 2; private Optional<Paint> painter = Optional.absent(); private Optional<Image> image = Optional.absent(); private int style = ACTUAL; private float alignmentX = 0.5f; private float alignmentY = 0.55f; private float alpha = 1.0f; private Composite originalComposite; /** * <p>Set image as the background with the SCALED style</p> * * @param image The image */ public BackgroundPanel(Image image) { this(image, SCALED); } /** * <p>Set image as the background with the specified style</p> * * @param image The image * @param style The style to use */ public BackgroundPanel(Image image, int style) { this(image, style, 0.5f, 0.5f); } /** * <p>Set image as the background with the specified style and alignment</p> * <p>By default the image will be centered in the panel</p> * * @param image The image * @param style The style to use * @param alignmentX The horizontal alignment (0.0 to 1.0 representing left to right) * @param alignmentY The vertical alignment (0.0 to 1.0 representing top to bottom) */ public BackgroundPanel(Image image, int style, float alignmentX, float alignmentY) { setImage(image); setStyle(style); setImageAlignmentX(alignmentX); setImageAlignmentY(alignmentY); setLayout(new BorderLayout()); this.applyComponentOrientation(this.getComponentOrientation()); } /** * <p>Use the Paint API to paint a solid background with no image</p> * * @param painter The painter */ public BackgroundPanel(Paint painter) { setPaint(painter); setLayout(new BorderLayout()); } @Override public Dimension getPreferredSize() { if (image.isPresent()) { return new Dimension(image.get().getWidth(null), image.get().getHeight(null)); } else { return super.getPreferredSize(); } } /** * <p>Custom painting code for drawing a SCALED image as the background</p> */ private void drawScaled(Graphics g) { Preconditions.checkState(image.isPresent(), "'image' must be present"); Graphics2D g2 = (Graphics2D) g; Dimension d = getSize(); applyAlphaComposite(g2); g2.drawImage(image.get(), 0, 0, d.width, d.height, null); removeAlphaComposite(g2); } /** * <p>Custom painting code for drawing TILED images as the background</p> */ private void drawTiled(Graphics g) { Preconditions.checkState(image.isPresent(), "'image' must be present"); Graphics2D g2 = (Graphics2D) g; Dimension d = getSize(); int width = image.get().getWidth(null); int height = image.get().getHeight(null); for (int x = 0; x < d.width; x += width) { for (int y = 0; y < d.height; y += height) { applyAlphaComposite(g2); g2.drawImage(image.get(), x, y, null, null); removeAlphaComposite(g2); } } } /** * <p>Custom painting code for drawing the ACTUAL image as the background.</p> * <p>The image is positioned in the panel based on the horizontal and * vertical alignments specified.</p> */ private void drawActual(Graphics g) { Preconditions.checkState(image.isPresent(), "'image' must be present"); Graphics2D g2 = (Graphics2D) g; Dimension d = getSize(); Insets insets = getInsets(); int width = d.width - insets.left - insets.right; int height = d.height - insets.top - insets.left; // Handle left to right orientation float x; if (this.getComponentOrientation().isLeftToRight()) { x = (width - image.get().getWidth(null)) * alignmentX; } else { //x = (width - image.get().getWidth(null)) * alignmentX; x = (width - image.get().getWidth(null)) * (1 - alignmentX); } float y = (height - image.get().getHeight(null)) * alignmentY; applyAlphaComposite(g2); g2.drawImage(image.get(), (int) x + insets.left, (int) y + insets.top, this); removeAlphaComposite(g2); } /** * <p>Apply the alpha composite to the given graphics context</p> * * @param g2 The graphics context */ private void applyAlphaComposite(Graphics2D g2) { originalComposite = g2.getComposite(); int rule = AlphaComposite.SRC_OVER; Composite alphaComposite = AlphaComposite.getInstance(rule, alpha); g2.setComposite(alphaComposite); } /** * <p>Remove the alpha composite from the given graphics context</p> * * @param g2 The graphics context */ private void removeAlphaComposite(Graphics2D g2) { g2.setComposite(originalComposite); } @Override protected void paintComponent(Graphics g) { super.paintComponent(g); // Use the painter for the background if (painter.isPresent()) { Dimension d = getSize(); Graphics2D g2 = (Graphics2D) g; g2.setRenderingHints(ImageDecorator.smoothRenderingHints()); g2.setPaint(painter.get()); g2.fill(new Rectangle(0, 0, d.width, d.height)); } // Draw the image if (image == null) return; switch (style) { case SCALED: drawScaled(g); break; case TILED: drawTiled(g); break; case ACTUAL: drawActual(g); break; default: drawActual(g); } } /** * <p>Set the image used as the background</p> */ public void setImage(Image image) { this.image = Optional.of(image); repaint(); } /** * <p>Set the style used to paint the background image</p> */ public void setStyle(int style) { this.style = style; repaint(); } /** * <p>Set the Paint object used to paint the background</p> */ public void setPaint(Paint painter) { this.painter = Optional.of(painter); repaint(); } /** * @param alignmentX The horizontal alignment (0.0 to 1.0 representing left to right) in ACTUAL style */ public void setImageAlignmentX(float alignmentX) { this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX; repaint(); } /** * @param alignmentY The vertical alignment (0.0 to 1.0 representing top to bottom) in ACTUAL style */ public void setImageAlignmentY(float alignmentY) { this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY; repaint(); } /** * @param alpha The transparency 0.0 (transparent) to 1.0 (opaque) */ public void setAlpha(float alpha) { this.alpha = alpha > 1.0f ? 1.0f : alpha < 0.0f ? 0.0f : alpha; repaint(); } }