blob: 1ff57edd7e622ace212b3973308cb8315d60d103 [file] [log] [blame]
/*
* Copyright 2000-2012 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.application.options.codeStyle.arrangement.animation;
import com.intellij.application.options.codeStyle.arrangement.ArrangementConstants;
import com.intellij.ide.ui.UISettings;
import com.intellij.util.ui.GridBag;
import com.intellij.util.ui.UIUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.awt.*;
import java.awt.image.BufferedImage;
/**
* @author Denis Zhdanov
* @since 11/2/12 8:50 PM
*/
public class ArrangementAnimationPanel extends JPanel {
@NotNull private final JComponent myContent;
@Nullable private BufferedImage myImage;
@Nullable private BufferedImage myCurrentImage;
@Nullable private Listener myListener;
private final boolean myExpand;
private final boolean myHorizontal;
private boolean myDelayedAnimation;
private boolean myAnimated;
public ArrangementAnimationPanel(@NotNull JComponent content, boolean expand, boolean horizontal) {
super(new GridBagLayout());
myContent = content;
myExpand = expand;
myHorizontal = horizontal;
add(content, new GridBag().fillCell().weightx(1).weighty(1));
setOpaque(false);
setBackground(UIUtil.getListBackground());
doLayout();
}
public void startAnimation() {
myDelayedAnimation = true;
}
private void prepareForAnimation() {
Dimension size = myContent.getPreferredSize();
Rectangle bounds = myContent.getBounds();
applyDoubledBuffered(myContent, false);
//myContent.setDoubleBuffered(false);
myContent.setBounds(0, 0, size.width, size.height);
myContent.validate();
myImage = UIUtil.createImage(size.width, size.height, BufferedImage.TYPE_INT_RGB);
assert myImage != null;
final Graphics2D graphics = myImage.createGraphics();
UISettings.setupAntialiasing(graphics);
graphics.setClip(0, 0, size.width, size.height);
graphics.setColor(UIUtil.getListBackground());
graphics.fillRect(0, 0, size.width, size.height);
myContent.paint(graphics);
graphics.dispose();
myContent.setBounds(bounds);
applyDoubledBuffered(myContent, true);
if (myExpand) {
if (myHorizontal) {
myCurrentImage = myImage.getSubimage(0, 0, ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP, myImage.getHeight());
}
else {
myCurrentImage = myImage.getSubimage(0, 0, myImage.getWidth(), ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP);
}
}
else {
if (myHorizontal) {
myCurrentImage = myImage.getSubimage(
0, 0, myImage.getWidth() - ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP, myImage.getHeight()
);
}
else {
myCurrentImage = myImage.getSubimage(
0, 0, myImage.getWidth(), myImage.getHeight() - ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP
);
}
}
invalidate();
}
private static void applyDoubledBuffered(JComponent component, boolean doubleBuffered) {
component.setDoubleBuffered(doubleBuffered);
for (int i = 0; i < component.getComponentCount(); i++) {
applyDoubledBuffered((JComponent)component.getComponent(i), doubleBuffered);
}
}
/**
* Asks current panel to switch to the next drawing iteration
*
* @return <code>true</code> if there are more iterations
*/
public boolean nextIteration() {
int widthToUse = getImageWidthToUse();
int heightToUse = getImageHeightToUse();
if (widthToUse <= 0 || heightToUse <= 0) {
myImage = null;
myCurrentImage = null;
myAnimated = true;
return false;
}
myCurrentImage = myImage.getSubimage(0, 0, widthToUse, heightToUse);
invalidate();
return true;
}
@Override
public void paint(Graphics g) {
if (myDelayedAnimation) {
prepareForAnimation();
myDelayedAnimation = false;
}
if (myCurrentImage == null) {
super.paint(g);
return;
}
g.drawImage(myCurrentImage, 0, 0, myCurrentImage.getWidth(), myCurrentImage.getHeight(), null);
if (myListener != null) {
myListener.onPaint();
}
}
@Override
public Dimension getMinimumSize() {
return getPreferredSize();
}
@Override
public Dimension getMaximumSize() {
return getPreferredSize();
}
@Override
public Dimension getPreferredSize() {
if (myAnimated) {
return myContent.getPreferredSize();
}
if (myCurrentImage == null) {
Dimension size = myContent.getPreferredSize();
int width = (myHorizontal && myExpand) ? ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP : size.width;
int height = (!myHorizontal && myExpand) ? ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP : size.height;
return new Dimension(width, height);
}
return new Dimension(myCurrentImage.getWidth(), myCurrentImage.getHeight());
}
private int getImageWidthToUse() {
assert myCurrentImage != null;
if (!myHorizontal) {
return myCurrentImage.getWidth();
}
int sign = myExpand ? 1 : -1;
int result = myCurrentImage.getWidth() + sign * ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP;
if (result <= 0 || result > myImage.getWidth()) {
return -1;
}
return result;
}
private int getImageHeightToUse() {
assert myCurrentImage != null;
if (myHorizontal) {
return myCurrentImage.getHeight();
}
int sign = myExpand ? 1 : -1;
int result = myCurrentImage.getHeight() + sign * ArrangementConstants.ANIMATION_ITERATION_PIXEL_STEP;
if (result <= 0 || result > myImage.getHeight()) {
return -1;
}
return result;
}
public void setListener(@Nullable Listener listener) {
myListener = listener;
}
@Override
public String toString() {
return "animation panel for " + myContent.toString();
}
public interface Listener {
void onPaint();
}
}