You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
242 lines
6.6 KiB
242 lines
6.6 KiB
package com.fine.component.popup; |
|
|
|
import com.fine.theme.utils.FineUIUtils; |
|
import com.formdev.flatlaf.ui.FlatUIUtils; |
|
import com.formdev.flatlaf.util.Animator; |
|
import com.formdev.flatlaf.util.CubicBezierEasing; |
|
import com.formdev.flatlaf.util.UIScale; |
|
import net.miginfocom.swing.MigLayout; |
|
|
|
import javax.swing.JPanel; |
|
import java.awt.AlphaComposite; |
|
import java.awt.Graphics; |
|
import java.awt.Graphics2D; |
|
import java.awt.Image; |
|
import java.awt.image.BufferedImage; |
|
import java.util.Stack; |
|
|
|
/** |
|
* 遮罩功能:渐显遮罩层 |
|
* |
|
* @author Levy.Xie |
|
* @since 12.0 |
|
* Created on 2024/12/12 |
|
*/ |
|
public class ComponentLayer extends JPanel { |
|
|
|
private GlassPaneChild component; |
|
private GlassPaneChild nextComponent; |
|
private Animator animator; |
|
private float animate; |
|
private boolean showSnapshot; |
|
private boolean simpleSnapshot; |
|
private Image image; |
|
|
|
private Image nextImage; |
|
private Stack<GlassPaneChild> componentStack; |
|
private boolean push; |
|
|
|
private void pushStack(GlassPaneChild component) { |
|
if (componentStack == null) { |
|
componentStack = new Stack<>(); |
|
} |
|
componentStack.push(component); |
|
} |
|
|
|
public ComponentLayer(GlassPaneChild component) { |
|
this.component = component; |
|
init(); |
|
} |
|
|
|
private void init() { |
|
MigLayout layout = new MigLayout("insets 0,fill", "fill", "fill"); |
|
setLayout(layout); |
|
if (component.getRoundBorder() > 0) { |
|
setOpaque(false); |
|
component.setOpaque(false); |
|
} |
|
add(component); |
|
component.setVisible(false); |
|
} |
|
|
|
private void initAnimator() { |
|
animator = new Animator(350, new Animator.TimingTarget() { |
|
|
|
@Override |
|
public void timingEvent(float v) { |
|
animate = v; |
|
repaint(); |
|
} |
|
|
|
@Override |
|
public void begin() { |
|
nextImage = FineUIUtils.createImage(nextComponent); |
|
} |
|
|
|
@Override |
|
public void end() { |
|
showSnapshot = false; |
|
component = nextComponent; |
|
component.popupShow(); |
|
nextComponent = null; |
|
animate = 0; |
|
component.setVisible(true); |
|
if (nextImage != null) { |
|
nextImage.flush(); |
|
} |
|
} |
|
}); |
|
animator.setInterpolator(CubicBezierEasing.EASE); |
|
} |
|
|
|
private void startAnimate() { |
|
if (animator == null) { |
|
initAnimator(); |
|
} |
|
if (animator.isRunning()) { |
|
animator.stop(); |
|
} |
|
animate = 0; |
|
animator.start(); |
|
} |
|
|
|
/** |
|
* 放入组件 |
|
* |
|
* @param component 组件 |
|
*/ |
|
public void pushComponent(GlassPaneChild component) { |
|
component.onPush(); |
|
pushStack(this.component); |
|
push = true; |
|
showComponent(component); |
|
} |
|
|
|
|
|
/** |
|
* 弹出组件 |
|
*/ |
|
public void popComponent() { |
|
if (!componentStack.isEmpty()) { |
|
GlassPaneChild component = componentStack.pop(); |
|
component.onPop(); |
|
push = false; |
|
showComponent(component); |
|
} |
|
} |
|
|
|
private void showComponent(GlassPaneChild component) { |
|
showSnapshot = true; |
|
this.nextComponent = component; |
|
if (!component.isTransparent()) { |
|
image = FineUIUtils.createImage(this.component); |
|
} |
|
if (component.getRoundBorder() > 0) { |
|
setOpaque(false); |
|
component.setOpaque(false); |
|
} |
|
component.setVisible(false); |
|
remove(this.component); |
|
add(component); |
|
revalidate(); |
|
startAnimate(); |
|
} |
|
|
|
/** |
|
* 显示遮罩 |
|
*/ |
|
public void showSnapshot() { |
|
if (animator != null && animator.isRunning()) { |
|
animator.stop(); |
|
} |
|
simpleSnapshot = true; |
|
doLayout(); |
|
if (!component.isTransparent()) { |
|
image = FineUIUtils.createImage(component, component.getRoundBorder()); |
|
} |
|
component.setVisible(false); |
|
} |
|
|
|
/** |
|
* 隐藏遮罩 |
|
*/ |
|
public void hideSnapshot() { |
|
showSnapshot = false; |
|
simpleSnapshot = false; |
|
component.setVisible(true); |
|
if (image != null) { |
|
image.flush(); |
|
} |
|
} |
|
|
|
@Override |
|
protected void paintComponent(Graphics g) { |
|
if (!component.isTransparent()) { |
|
if (!isOpaque() && component.getRoundBorder() > 0) { |
|
Graphics2D g2 = (Graphics2D) g.create(); |
|
FlatUIUtils.setRenderingHints(g2); |
|
g2.setColor(getBackground()); |
|
int arc = UIScale.scale(component.getRoundBorder()); |
|
FlatUIUtils.paintComponentBackground(g2, 0, 0, getWidth(), getHeight(), 0, arc); |
|
g2.dispose(); |
|
} |
|
} |
|
super.paintComponent(g); |
|
} |
|
|
|
@Override |
|
public void paint(Graphics g) { |
|
if (simpleSnapshot) { |
|
g.drawImage(image, 0, 0, null); |
|
} else if (showSnapshot) { |
|
int width = getWidth(); |
|
int height = getHeight(); |
|
if (width > 0 && height > 0) { |
|
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB); |
|
Graphics2D g2 = bufferedImage.createGraphics(); |
|
FlatUIUtils.setRenderingHints(g2); |
|
int arc = UIScale.scale(component.getRoundBorder()); |
|
g2.setColor(getBackground()); |
|
FlatUIUtils.paintComponentBackground(g2, 0, 0, width, height, 0, arc); |
|
if (image != null) { |
|
paintImage(g2); |
|
} |
|
if (nextImage != null) { |
|
paintNextImage(g2); |
|
} |
|
g2.dispose(); |
|
g.drawImage(bufferedImage, 0, 0, null); |
|
} |
|
} else { |
|
super.paint(g); |
|
} |
|
} |
|
|
|
private void paintNextImage(Graphics2D g2) { |
|
int w = nextImage.getWidth(null); |
|
double x; |
|
if (push) { |
|
x = getWidth() - (w * animate); |
|
} else { |
|
x = -getWidth() + (w * animate); |
|
} |
|
g2.setComposite(AlphaComposite.SrcAtop.derive(animate)); |
|
g2.drawImage(nextImage, (int) x, 0, null); |
|
} |
|
|
|
private void paintImage(Graphics2D g2) { |
|
int w = image.getWidth(null); |
|
double x; |
|
if (push) { |
|
x = -w * animate; |
|
} else { |
|
x = w * animate; |
|
} |
|
g2.setComposite(AlphaComposite.SrcAtop.derive(1f - animate)); |
|
g2.drawImage(image, (int) x, 0, null); |
|
} |
|
|
|
public GlassPaneChild getComponent() { |
|
return component; |
|
} |
|
}
|
|
|