Drop shadows on Windows: support medium-weight popups (issue #94)

This commit is contained in:
Karl Tauber
2020-05-18 13:13:57 +02:00
parent dc098025b6
commit 8c0ccdd227

View File

@@ -21,13 +21,20 @@ import java.awt.Component;
import java.awt.Container; import java.awt.Container;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Insets; import java.awt.Insets;
import java.awt.Panel;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ComponentEvent;
import java.awt.event.ComponentListener;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JLayeredPane;
import javax.swing.JPanel; import javax.swing.JPanel;
import javax.swing.Popup; import javax.swing.Popup;
import javax.swing.PopupFactory; import javax.swing.PopupFactory;
import javax.swing.RootPaneContainer;
import javax.swing.SwingUtilities; import javax.swing.SwingUtilities;
import javax.swing.UIManager; import javax.swing.UIManager;
import javax.swing.border.Border; import javax.swing.border.Border;
@@ -170,11 +177,18 @@ public class FlatPopupFactory
private class DropShadowPopup private class DropShadowPopup
extends NonFlashingPopup extends NonFlashingPopup
{ {
private final Component owner;
// light weight // light weight
private JComponent lightComp; private JComponent lightComp;
private Border oldBorder; private Border oldBorder;
private boolean oldOpaque; private boolean oldOpaque;
// medium weight
private Panel mediumWeightPanel;
private JPanel dropShadowPanel;
private ComponentListener mediumPanelListener;
// heavy weight // heavy weight
private Popup dropShadowDelegate; private Popup dropShadowDelegate;
private Window dropShadowWindow; private Window dropShadowWindow;
@@ -182,10 +196,7 @@ public class FlatPopupFactory
DropShadowPopup( Popup delegate, Component owner, Component contents ) { DropShadowPopup( Popup delegate, Component owner, Component contents ) {
super( delegate, contents ); super( delegate, contents );
this.owner = owner;
// drop shadows on medium weight popups are not supported
if( delegate.getClass().getName().endsWith( "MediumWeightPopup" ) )
return;
Dimension size = contents.getPreferredSize(); Dimension size = contents.getPreferredSize();
if( size.width <= 0 || size.height <= 0 ) if( size.width <= 0 || size.height <= 0 )
@@ -224,17 +235,26 @@ public class FlatPopupFactory
dropShadowWindow.setBackground( new Color( 0, true ) ); dropShadowWindow.setBackground( new Color( 0, true ) );
} }
} else { } else {
// light weight popup mediumWeightPanel = (Panel) SwingUtilities.getAncestorOfClass( Panel.class, contents );
Container p = contents.getParent(); if( mediumWeightPanel != null ) {
if( !(p instanceof JComponent) ) // medium weight popup
return; dropShadowPanel = new JPanel();
dropShadowPanel.setBorder( createDropShadowBorder() );
dropShadowPanel.setOpaque( false );
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
} else {
// light weight popup
Container p = contents.getParent();
if( !(p instanceof JComponent) )
return;
lightComp = (JComponent) p; lightComp = (JComponent) p;
oldBorder = lightComp.getBorder(); oldBorder = lightComp.getBorder();
oldOpaque = lightComp.isOpaque(); oldOpaque = lightComp.isOpaque();
lightComp.setBorder( createDropShadowBorder() ); lightComp.setBorder( createDropShadowBorder() );
lightComp.setOpaque( false ); lightComp.setOpaque( false );
lightComp.setSize( lightComp.getPreferredSize() ); lightComp.setSize( lightComp.getPreferredSize() );
}
} }
} }
@@ -250,6 +270,9 @@ public class FlatPopupFactory
if( dropShadowDelegate != null ) if( dropShadowDelegate != null )
dropShadowDelegate.show(); dropShadowDelegate.show();
if( mediumWeightPanel != null )
showMediumWeightDropShadow();
super.show(); super.show();
// fix location of light weight popup in case it has left or top drop shadow // fix location of light weight popup in case it has left or top drop shadow
@@ -267,6 +290,12 @@ public class FlatPopupFactory
dropShadowDelegate = null; dropShadowDelegate = null;
} }
if( mediumWeightPanel != null ) {
hideMediumWeightDropShadow();
dropShadowPanel = null;
mediumWeightPanel = null;
}
super.hide(); super.hide();
if( dropShadowWindow != null ) { if( dropShadowWindow != null ) {
@@ -280,5 +309,55 @@ public class FlatPopupFactory
lightComp = null; lightComp = null;
} }
} }
private void showMediumWeightDropShadow() {
Window window = SwingUtilities.windowForComponent( owner );
if( window == null )
return;
if( !(window instanceof RootPaneContainer) )
return;
dropShadowPanel.setVisible( false );
JLayeredPane layeredPane = ((RootPaneContainer)window).getLayeredPane();
layeredPane.add( dropShadowPanel, JLayeredPane.POPUP_LAYER, 0 );
mediumPanelListener = new ComponentListener() {
@Override
public void componentShown( ComponentEvent e ) {
dropShadowPanel.setVisible( true );
}
@Override
public void componentHidden( ComponentEvent e ) {
dropShadowPanel.setVisible( false );
}
@Override
public void componentMoved( ComponentEvent e ) {
Point location = mediumWeightPanel.getLocation();
Insets insets = dropShadowPanel.getInsets();
dropShadowPanel.setLocation( location.x - insets.left, location.y - insets.top );
}
@Override
public void componentResized( ComponentEvent e ) {
dropShadowPanel.setSize( FlatUIUtils.addInsets( mediumWeightPanel.getSize(), dropShadowPanel.getInsets() ) );
}
};
mediumWeightPanel.addComponentListener( mediumPanelListener );
}
private void hideMediumWeightDropShadow() {
mediumWeightPanel.removeComponentListener( mediumPanelListener );
Container parent = dropShadowPanel.getParent();
if( parent != null ) {
Rectangle bounds = dropShadowPanel.getBounds();
parent.remove( dropShadowPanel );
parent.repaint( bounds.x, bounds.y, bounds.width, bounds.height );
}
}
} }
} }