/*
* Copyright 2000-2015 JetBrains s.r.o.
*
* 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 com.intellij.util.ui;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
/**
* The {@code RegionPainter} interface defines exactly one method, {@code paint}.
* It is used in situations where the developer can change the painting routine
* of a component without having to resort to subclassing the component.
* It is also generically useful when doing any form of painting delegation.
* <p>
* Painters are simply encapsulations of Java2D code and make it fairly trivial
* to reuse existing painters or to combine them together.
* Implementations of this interface are also trivial to write,
* such that if you can't find a painter that does what you need,
* you can write one with minimal effort.
*
* @author Sergey.Malenkov
* @see com.sun.java.swing.Painter
*/
public interface RegionPainter<T> {
/**
* Renders to the given {@link Graphics2D} object.
*
* @param g the {@code Graphics2D} object to render to
* @param x X position of the area to paint
* @param y Y position of the area to paint
* @param width width of the area to paint
* @param height height of the area to paint
* @param object an optional configuration parameter
*/
void paint(Graphics2D g, int x, int y, int width, int height, T object);
/**
* This class provides a base functionality to paint a region with the specified alpha.
*/
abstract class Alpha implements RegionPainter<Float> {
@Override
public final void paint(Graphics2D g, int x, int y, int width, int height, Float value) {
float alpha = getAlpha(value);
if (alpha > 0) {
Composite composite = g.getComposite();
g.setComposite(getComposite(alpha));
paint(g, x, y, width, height);
g.setComposite(composite);
}
}
/**
* Calculates alpha from the specified value.
*
* @param value a configuration parameter used to calculate alpha
* @return an alpha calculated from the specified value
*/
protected float getAlpha(Float value) {
return value != null ? value : 0;
}
/**
* Returns new composite with the specified alpha.
*
* @param alpha the constant alpha to be multiplied with the alpha of the source
* @return new composite with the specified alpha
*/
protected Composite getComposite(float alpha) {
return alpha < 1
? AlphaComposite.SrcOver.derive(alpha)
: AlphaComposite.SrcOver;
}
/**
* Renders to the given {@link Graphics2D} object.
*
* @param g the {@code Graphics2D} object to render to
* @param x X position of the area to paint
* @param y Y position of the area to paint
* @param width width of the area to paint
* @param height height of the area to paint
*/
protected abstract void paint(Graphics2D g, int x, int y, int width, int height);
}
/**
* This class provides a caching functionality for a region painter.
*/
class Image implements RegionPainter<Object> {
private BufferedImage myImage;
/**
* This method is called for the cached image before {@code drawImage}.
* It should be overridden if the image must be updated without creating a new image.
*
* @param image the cached image to update
*/
protected void updateImage(BufferedImage image) {
}
/**
* This method is called if the cached image is invalidated or it's size is changed.
* It must be overridden to paint on newly created image.
*
* @param width width of the new image
* @param height height of the new image
* @return new {@link BufferedImage} object
*/
protected BufferedImage createImage(int width, int height) {
return UIUtil.createImage(width, height, BufferedImage.TYPE_INT_ARGB);
}
/**
* This method is called to invalidate the cached image.
*/
protected void invalidate() {
myImage = null;
}
@Override
public void paint(Graphics2D g, int x, int y, int width, int height, Object object) {
if (width > 0 && height > 0) {
if (myImage == null || width != myImage.getWidth() || height != myImage.getHeight()) {
myImage = createImage(width, height);
}
else if (myImage != null) {
updateImage(myImage);
}
if (myImage != null) {
UIUtil.drawImage(g, myImage, null, x, y);
}
}
}
}
}