Skip to content

Commit

Permalink
Popup: on Windows 10, update drop shadow of heavy-weight popup if pop…
Browse files Browse the repository at this point in the history
…up moved/resized (issue #942)
  • Loading branch information
DevCharly committed Jan 25, 2025
1 parent f30dd87 commit 1cc0232
Show file tree
Hide file tree
Showing 5 changed files with 218 additions and 22 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ FlatLaf Change Log
- FileChooser: Improved performance when navigating to large directories with
thousands of files. (issue #953)
- PopupFactory: Fixed NPE on Windows 10 when `owner` is `null`. (issue #952)
- Popup: On Windows 10, drop shadow of heavy-weight popup was not updated if
popup moved/resized. (issue #942)
- FlatLaf window decorations: Minimize and maximize icons were not shown for
custom scale factors less than 100% (e.g. `-Dflatlaf.uiScale=75%`). (issue
#951)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ public FlatDropShadowBorder( Color shadowColor, Insets shadowInsets, float shado

this.shadowColor = shadowColor;
this.shadowInsets = shadowInsets;
this.shadowOpacity = shadowOpacity;
this.shadowOpacity = Math.min( Math.max( shadowOpacity, 0f ), 1f );

shadowSize = maxInset( shadowInsets );
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -709,6 +709,7 @@ void reset( Component contents, int ownerX, int ownerY ) {

private class DropShadowPopup
extends NonFlashingPopup
implements ComponentListener
{
// light weight
private JComponent lightComp;
Expand Down Expand Up @@ -768,7 +769,7 @@ private class DropShadowPopup
}

// Windows 11: reset corner preference on reused heavy weight popups
if( isWindows11BorderSupported() ) {
if( SystemInfo.isWindows_11_orLater && FlatNativeWindowsLibrary.isLoaded() ) {
resetWindows11Border( popupWindow );
if( dropShadowWindow != null )
resetWindows11Border( dropShadowWindow );
Expand Down Expand Up @@ -838,10 +839,18 @@ void showImpl() {
if( insets.left != 0 || insets.top != 0 )
lightComp.setLocation( lightComp.getX() - insets.left, lightComp.getY() - insets.top );
}

if( popupWindow != null ) {
removeAllPopupWindowComponentListeners();
popupWindow.addComponentListener( this );
}
}

@Override
void hideImpl() {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();

if( dropShadowDelegate != null ) {
dropShadowDelegate.hide();
dropShadowDelegate = null;
Expand Down Expand Up @@ -941,23 +950,55 @@ private void resizeMediumWeightDropShadow() {

@Override
void reset( Component contents, int ownerX, int ownerY ) {
if( popupWindow != null )
removeAllPopupWindowComponentListeners();

super.reset( contents, ownerX, ownerY );

if( dropShadowWindow != null ) {
// set preferred size of drop shadow panel
Dimension prefSize = popupWindow.getPreferredSize();
Insets insets = dropShadowPanel2.getInsets();
int w = prefSize.width + insets.left + insets.right;
int h = prefSize.height + insets.top + insets.bottom;
dropShadowPanel2.setPreferredSize( new Dimension( w, h ) );
dropShadowPanel2.invalidate();
dropShadowWindow.pack();
updateDropShadowWindowBounds();
}

// update drop shadow popup window location
int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top;
dropShadowWindow.setLocation( x, y );
private void updateDropShadowWindowBounds() {
if( dropShadowWindow == null )
return;

// calculate size of drop shadow window
Dimension size = popupWindow.getSize();
Insets insets = dropShadowPanel2.getInsets();
int w = size.width + insets.left + insets.right;
int h = size.height + insets.top + insets.bottom;

// update drop shadow popup window bounds
int x = popupWindow.getX() - insets.left;
int y = popupWindow.getY() - insets.top;
dropShadowWindow.setBounds( x, y, w, h );
dropShadowWindow.validate();
}

private void removeAllPopupWindowComponentListeners() {
// make sure that there is no old component listener
// necessary because this class is cloned if reusing popup windows
for( ComponentListener l : popupWindow.getComponentListeners() ) {
if( l instanceof DropShadowPopup )
popupWindow.removeComponentListener( l );
}
}

//---- interface ComponentListener ----

@Override
public void componentResized( ComponentEvent e ) {
if( e.getSource() == popupWindow )
updateDropShadowWindowBounds();
}

@Override
public void componentMoved( ComponentEvent e ) {
if( e.getSource() == popupWindow )
updateDropShadowWindowBounds();
}

@Override public void componentShown( ComponentEvent e ) {}
@Override public void componentHidden( ComponentEvent e ) {}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@
import java.util.Random;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.FlatSystemProperties;
import com.formdev.flatlaf.util.Animator;
import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*;
Expand All @@ -43,6 +47,8 @@ public static void main( String[] args ) {

FlatPopupTest() {
initComponents();
addPopupMenuListener( popupMenu1, "popupMenu1" );
addPopupMenuListener( popupMenu2, "popupMenu2" );
}

private void showPopupMenu() {
Expand Down Expand Up @@ -114,6 +120,46 @@ private void createPopupPanels() {
}
}

private void showDirectPopup() {
DirectPopupContent content = new DirectPopupContent();
content.putClientProperty( FlatClientProperties.POPUP_FORCE_HEAVY_WEIGHT, true );
Point pt = showDirectPopupButton.getLocationOnScreen();

System.setProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER, "false" );
UIManager.put( "Popup.dropShadowColor", Color.red );
UIManager.put( "Popup.dropShadowInsets", new Insets( 5, 5, 5, 5 ) );
UIManager.put( "Popup.dropShadowOpacity", 1f );

Popup popup = PopupFactory.getSharedInstance().getPopup( showDirectPopupButton,
content, pt.x, pt.y + showDirectPopupButton.getHeight() + 10 );
content.popup = popup;
popup.show();

System.clearProperty( FlatSystemProperties.USE_ROUNDED_POPUP_BORDER );
UIManager.put( "Popup.dropShadowColor", null );
UIManager.put( "Popup.dropShadowInsets", null );
UIManager.put( "Popup.dropShadowOpacity", null );
}

private void addPopupMenuListener( JPopupMenu popupMenu, String name ) {
popupMenu.addPopupMenuListener( new PopupMenuListener() {
@Override
public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeVisible " + name );
}

@Override
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
System.out.println( "popupMenuWillBecomeInvisible " + name );
}

@Override
public void popupMenuCanceled( PopupMenuEvent e ) {
System.out.println( "popupMenuCanceled " + name );
}
} );
}

@Override
public void updateUI() {
super.updateUI();
Expand All @@ -128,15 +174,12 @@ public void updateUI() {
}
}

private void countChanged() {
// TODO add your code here
}

private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents
label1 = new JLabel();
label2 = new JLabel();
showPopupMenuButton = new JButton();
showDirectPopupButton = new JButton();
showLargePopupMenuButton = new JButton();
showPopupButton = new JButton();
hidePopupButton = new JButton();
Expand Down Expand Up @@ -209,6 +252,11 @@ private void initComponents() {
showPopupMenuButton.addActionListener(e -> showPopupMenu());
add(showPopupMenuButton, "cell 0 2");

//---- showDirectPopupButton ----
showDirectPopupButton.setText("show direct move/resize popup");
showDirectPopupButton.addActionListener(e -> showDirectPopup());
add(showDirectPopupButton, "cell 2 2 2 1");

//---- showLargePopupMenuButton ----
showLargePopupMenuButton.setText("show heavy-weight JPopupMenu");
showLargePopupMenuButton.addActionListener(e -> showLargePopupMenu());
Expand Down Expand Up @@ -240,7 +288,6 @@ private void initComponents() {

//---- countField ----
countField.setModel(new SpinnerNumberModel(1, 1, null, 1));
countField.addChangeListener(e -> countChanged());
add(countField, "cell 5 4");

//---- label4 ----
Expand Down Expand Up @@ -366,6 +413,7 @@ private void initComponents() {
private JLabel label1;
private JLabel label2;
private JButton showPopupMenuButton;
private JButton showDirectPopupButton;
private JButton showLargePopupMenuButton;
private JButton showPopupButton;
private JButton hidePopupButton;
Expand Down Expand Up @@ -444,4 +492,69 @@ private void initComponents() {
private JLabel label6;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}

//---- class MyPopupContent -----------------------------------------------

private class DirectPopupContent
extends JPanel
{
Popup popup;

DirectPopupContent() {
initComponents();
}

private void resizePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setSize( popupWindow.getWidth() + 20, popupWindow.getHeight() + 50 );
}

private void movePopup() {
Window popupWindow = SwingUtilities.windowForComponent( this );
popupWindow.setLocation( popupWindow.getX() + 20, popupWindow.getY() + 50 );
}

private void hidePopup() {
popup.hide();
}

private void initComponents() {
// JFormDesigner - Component initialization - DO NOT MODIFY //GEN-BEGIN:initComponents @formatter:off
resizeButton = new JButton();
moveButton = new JButton();
hideButton = new JButton();

//======== this ========
setLayout(new MigLayout(
"hidemode 3",
// columns
"[fill]" +
"[fill]" +
"[fill]",
// rows
"[]"));

//---- resizeButton ----
resizeButton.setText("Resize");
resizeButton.addActionListener(e -> resizePopup());
add(resizeButton, "cell 0 0");

//---- moveButton ----
moveButton.setText("Move");
moveButton.addActionListener(e -> movePopup());
add(moveButton, "cell 1 0");

//---- hideButton ----
hideButton.setText("Hide");
hideButton.addActionListener(e -> hidePopup());
add(hideButton, "cell 2 0");
// JFormDesigner - End of component initialization //GEN-END:initComponents @formatter:on
}

// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables @formatter:off
private JButton resizeButton;
private JButton moveButton;
private JButton hideButton;
// JFormDesigner - End of variables declaration //GEN-END:variables @formatter:on
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
JFDML JFormDesigner: "8.2.3.0.386" Java: "21" encoding: "UTF-8"
JFDML JFormDesigner: "8.3" encoding: "UTF-8"

new FormModel {
contentType: "form/swing"
Expand Down Expand Up @@ -30,6 +30,13 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 2"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showDirectPopupButton"
"text": "show direct move/resize popup"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showDirectPopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 2 2 1"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "showLargePopupMenuButton"
"text": "show heavy-weight JPopupMenu"
Expand Down Expand Up @@ -77,7 +84,6 @@ new FormModel {
minimum: 1
value: 1
}
addEvent( new FormEvent( "javax.swing.event.ChangeListener", "stateChanged", "countChanged", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 5 4"
} )
Expand Down Expand Up @@ -215,5 +221,39 @@ new FormModel {
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 5, 505 )
} )
add( new FormContainer( "javax.swing.JPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "hidemode 3"
"$columnConstraints": "[fill][fill][fill]"
"$rowConstraints": "[]"
} ) {
name: "panel1"
auxiliary() {
"JavaCodeGenerator.className": "DirectPopupContent"
}
add( new FormComponent( "javax.swing.JButton" ) {
name: "resizeButton"
"text": "Resize"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "resizePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "moveButton"
"text": "Move"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "movePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 1 0"
} )
add( new FormComponent( "javax.swing.JButton" ) {
name: "hideButton"
"text": "Hide"
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "hidePopup", false ) )
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 2 0"
} )
}, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 180, 395 )
"size": new java.awt.Dimension( 270, 100 )
} )
}
}

0 comments on commit 1cc0232

Please sign in to comment.