mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-08 15:00:54 +03:00
fixed AWT components on macOS (issue #583)
- fixed missing focus indicator - fixed round corners - fixed java.awt.Button background - fixed java.awt.Choice background - fixed java.awt.Checkbox hover
This commit is contained in:
@@ -18,6 +18,8 @@ FlatLaf Change Log
|
||||
- Fixed missing UI value `MenuItem.acceleratorDelimiter` on macOS. (was `null`,
|
||||
is now an empty string)
|
||||
- Fixed possible exception in `FlatUIUtils.resetRenderingHints()`. (issue #575)
|
||||
- Fixed AWT components on macOS, which use Swing components internally. (issue
|
||||
#583)
|
||||
|
||||
|
||||
## 2.4
|
||||
|
||||
@@ -629,6 +629,9 @@ public class FlatButtonUI
|
||||
}
|
||||
|
||||
protected Color getBackgroundBase( JComponent c, boolean def ) {
|
||||
if( FlatUIUtils.isAWTPeer( c ) )
|
||||
return background;
|
||||
|
||||
// use component background if explicitly set
|
||||
Color bg = c.getBackground();
|
||||
if( isCustomBackground( bg ) )
|
||||
|
||||
@@ -631,6 +631,9 @@ public class FlatComboBoxUI
|
||||
|
||||
protected Color getBackground( boolean enabled ) {
|
||||
if( enabled ) {
|
||||
if( FlatUIUtils.isAWTPeer( comboBox ) )
|
||||
return UIManager.getColor( "ComboBox.background" );
|
||||
|
||||
Color background = comboBox.getBackground();
|
||||
|
||||
// always use explicitly set color
|
||||
|
||||
@@ -18,12 +18,16 @@ package com.formdev.flatlaf.ui;
|
||||
|
||||
import static com.formdev.flatlaf.util.UIScale.scale;
|
||||
import java.awt.Color;
|
||||
import java.awt.Component;
|
||||
import java.awt.Container;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Graphics;
|
||||
import java.awt.Insets;
|
||||
import java.awt.Rectangle;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import javax.swing.AbstractButton;
|
||||
@@ -31,6 +35,7 @@ import javax.swing.CellRendererPane;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.LookAndFeel;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicButtonListener;
|
||||
@@ -92,9 +97,20 @@ public class FlatRadioButtonUI
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
if( FlatUIUtils.isAWTPeer( c ) )
|
||||
AWTPeerMouseExitedFix.install( c );
|
||||
|
||||
installStyle( (AbstractButton) c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void uninstallUI( JComponent c ) {
|
||||
super.uninstallUI( c );
|
||||
|
||||
if( FlatUIUtils.isAWTPeer( c ) )
|
||||
AWTPeerMouseExitedFix.uninstall( c );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installDefaults( AbstractButton b ) {
|
||||
super.installDefaults( b );
|
||||
@@ -321,4 +337,69 @@ public class FlatRadioButtonUI
|
||||
FlatRadioButtonUI.this.propertyChange( b, e );
|
||||
}
|
||||
}
|
||||
|
||||
//---- class AWTPeerMouseExitedFix ----------------------------------------
|
||||
|
||||
/**
|
||||
* Hack for missing mouse-exited event for java.awt.Checkbox on macOS (to fix hover effect).
|
||||
*
|
||||
* On macOS, AWT components internally use Swing components.
|
||||
* This is implemented in class sun.lwawt.LWCheckboxPeer, which uses
|
||||
* a container component CheckboxDelegate that has a JCheckBox and a JRadioButton
|
||||
* as children. Only one of them is visible.
|
||||
*
|
||||
* The reason that mouse-exited event is not sent to the JCheckBox or JRadioButton
|
||||
* is that sun.lwawt.LWComponentPeer.createDelegateEvent() uses
|
||||
* SwingUtilities.getDeepestComponentAt() to find the event target,
|
||||
* which finds the container component CheckboxDelegate,
|
||||
* which receives the mouse-exited event.
|
||||
*
|
||||
* This class adds listeners and forwards the mouse-exited event
|
||||
* from CheckboxDelegate to JCheckBox or JRadioButton.
|
||||
*/
|
||||
private static class AWTPeerMouseExitedFix
|
||||
extends MouseAdapter
|
||||
implements PropertyChangeListener
|
||||
{
|
||||
private final JComponent button;
|
||||
|
||||
static void install( JComponent button ) {
|
||||
AWTPeerMouseExitedFix l = new AWTPeerMouseExitedFix( button );
|
||||
button.addPropertyChangeListener( "ancestor", l );
|
||||
Container parent = button.getParent();
|
||||
if( parent != null )
|
||||
parent.addMouseListener( l );
|
||||
}
|
||||
|
||||
static void uninstall( JComponent button ) {
|
||||
for( PropertyChangeListener l : button.getPropertyChangeListeners( "ancestor" ) ) {
|
||||
if( l instanceof AWTPeerMouseExitedFix ) {
|
||||
button.removePropertyChangeListener( "ancestor", l );
|
||||
Container parent = button.getParent();
|
||||
if( parent != null )
|
||||
parent.removeMouseListener( (AWTPeerMouseExitedFix) l );
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
AWTPeerMouseExitedFix( JComponent button ) {
|
||||
this.button = button;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void propertyChange( PropertyChangeEvent e ) {
|
||||
if( e.getOldValue() instanceof Component )
|
||||
((Component)e.getOldValue()).removeMouseListener( this );
|
||||
if( e.getNewValue() instanceof Component ) {
|
||||
((Component)e.getNewValue()).removeMouseListener( this ); // avoid duplicate listeners
|
||||
((Component)e.getNewValue()).addMouseListener( this );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited( MouseEvent e ) {
|
||||
button.dispatchEvent( SwingUtilities.convertMouseEvent( e.getComponent(), e, button ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,6 +59,7 @@ import com.formdev.flatlaf.FlatSystemProperties;
|
||||
import com.formdev.flatlaf.util.DerivedColor;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.HiDPIUtils;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -241,6 +242,11 @@ public class FlatUIUtils
|
||||
}
|
||||
}
|
||||
|
||||
// invoke hasFocus() here because components may have overridden this method
|
||||
// (e.g. Swing delegate components used for AWT components on macOS)
|
||||
if( c.hasFocus() )
|
||||
return true;
|
||||
|
||||
return keyboardFocusManager.getPermanentFocusOwner() == c &&
|
||||
isInActiveWindow( c, keyboardFocusManager.getActiveWindow() );
|
||||
}
|
||||
@@ -251,6 +257,13 @@ public class FlatUIUtils
|
||||
(window != null && window.getType() == Window.Type.POPUP && window.getOwner() == activeWindow);
|
||||
}
|
||||
|
||||
static boolean isAWTPeer( JComponent c ) {
|
||||
// on macOS, Swing components are used for AWT components
|
||||
if( SystemInfo.isMacOS )
|
||||
return c.getClass().getName().startsWith( "sun.lwawt.LW" );
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given component is in a window that is in full-screen mode.
|
||||
*/
|
||||
@@ -335,7 +348,7 @@ public class FlatUIUtils
|
||||
*/
|
||||
public static Object[] setRenderingHints( Graphics g ) {
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Object[] oldRenderingHints = new Object[] {
|
||||
Object[] oldRenderingHints = {
|
||||
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
|
||||
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
|
||||
};
|
||||
@@ -378,7 +391,7 @@ public class FlatUIUtils
|
||||
}
|
||||
|
||||
Graphics2D g2 = (Graphics2D) g;
|
||||
Object[] oldRenderingHints2 = new Object[] {
|
||||
Object[] oldRenderingHints2 = {
|
||||
g2.getRenderingHint( RenderingHints.KEY_ANTIALIASING ),
|
||||
g2.getRenderingHint( RenderingHints.KEY_STROKE_CONTROL ),
|
||||
};
|
||||
@@ -666,9 +679,9 @@ public class FlatUIUtils
|
||||
* is smaller than its bounds (for the focus decoration).
|
||||
*/
|
||||
public static void paintParentBackground( Graphics g, JComponent c ) {
|
||||
Container parent = findOpaqueParent( c );
|
||||
if( parent != null ) {
|
||||
g.setColor( parent.getBackground() );
|
||||
Color background = getParentBackground( c );
|
||||
if( background != null ) {
|
||||
g.setColor( background );
|
||||
g.fillRect( 0, 0, c.getWidth(), c.getHeight() );
|
||||
}
|
||||
}
|
||||
@@ -678,9 +691,10 @@ public class FlatUIUtils
|
||||
*/
|
||||
public static Color getParentBackground( JComponent c ) {
|
||||
Container parent = findOpaqueParent( c );
|
||||
return (parent != null)
|
||||
? parent.getBackground()
|
||||
: UIManager.getColor( "Panel.background" ); // fallback, probably never used
|
||||
// parent.getBackground() may return null
|
||||
// (e.g. for Swing delegate components used for AWT components on macOS)
|
||||
Color background = (parent != null) ? parent.getBackground() : null;
|
||||
return (background != null) ? background : UIManager.getColor( "Panel.background" );
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
package com.formdev.flatlaf.testing;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.MouseAdapter;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.WindowAdapter;
|
||||
import java.awt.event.WindowEvent;
|
||||
import javax.swing.SwingUtilities;
|
||||
import com.formdev.flatlaf.FlatLightLaf;
|
||||
|
||||
/**
|
||||
@@ -69,6 +72,52 @@ public class FlatAWTTest
|
||||
frame.add( new Panel() );
|
||||
frame.add( new Canvas() );
|
||||
|
||||
Panel controlPanel = new Panel();
|
||||
frame.add( controlPanel );
|
||||
|
||||
Checkbox enabledCheckBox = new Checkbox( "enabled", true );
|
||||
enabledCheckBox.addItemListener( e -> {
|
||||
boolean enabled = enabledCheckBox.getState();
|
||||
for( Component c : frame.getComponents() ) {
|
||||
if( c != controlPanel )
|
||||
c.setEnabled( enabled );
|
||||
}
|
||||
} );
|
||||
controlPanel.add( enabledCheckBox );
|
||||
|
||||
Checkbox explicitColorsCheckBox = new Checkbox( "explicit colors" );
|
||||
explicitColorsCheckBox.addItemListener( e -> {
|
||||
boolean explicit = explicitColorsCheckBox.getState();
|
||||
for( Component c : frame.getComponents() ) {
|
||||
if( c != controlPanel )
|
||||
c.setBackground( explicit ? Color.green : null );
|
||||
}
|
||||
} );
|
||||
controlPanel.add( explicitColorsCheckBox );
|
||||
|
||||
Menu menu = new Menu( "File" );
|
||||
menu.add( new MenuItem( "New" ) );
|
||||
menu.add( new MenuItem( "Open" ) );
|
||||
menu.add( new MenuItem( "Save" ) );
|
||||
|
||||
MenuBar menuBar = new MenuBar();
|
||||
menuBar.add( menu );
|
||||
frame.setMenuBar( menuBar );
|
||||
|
||||
PopupMenu popupMenu = new PopupMenu();
|
||||
popupMenu.add( new MenuItem( "item 1" ) );
|
||||
popupMenu.add( new MenuItem( "item 2" ) );
|
||||
popupMenu.add( new MenuItem( "item 3" ) );
|
||||
list.add( popupMenu );
|
||||
list.addMouseListener( new MouseAdapter() {
|
||||
@Override
|
||||
public
|
||||
void mousePressed( MouseEvent e ) {
|
||||
if( SwingUtilities.isRightMouseButton( e ) )
|
||||
popupMenu.show( list, 0, 0 );
|
||||
}
|
||||
} );
|
||||
|
||||
frame.setSize( 800, 600 );
|
||||
frame.setVisible( true );
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user