Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Menus: rounded selection #536

Merged
merged 2 commits into from Oct 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -70,7 +70,12 @@ public class FlatMenuBarUI
/** @since 2 */ @Styleable protected Insets itemMargins;

// used in FlatMenuUI
/** @since 3 */ @Styleable protected Insets selectionInsets;
/** @since 3 */ @Styleable protected Insets selectionEmbeddedInsets;
/** @since 3 */ @Styleable protected int selectionArc = -1;
/** @since 2 */ @Styleable protected Color hoverBackground;
/** @since 3 */ @Styleable protected Color selectionBackground;
/** @since 3 */ @Styleable protected Color selectionForeground;
/** @since 2 */ @Styleable protected Color underlineSelectionBackground;
/** @since 2 */ @Styleable protected Color underlineSelectionColor;
/** @since 2 */ @Styleable protected int underlineSelectionHeight = -1;
Expand Down
Expand Up @@ -63,6 +63,8 @@
* @uiDefault MenuItem.acceleratorArrowGap int
* @uiDefault MenuItem.checkBackground Color
* @uiDefault MenuItem.checkMargins Insets
* @uiDefault MenuItem.selectionInsets Insets
* @uiDefault MenuItem.selectionArc int
* @uiDefault MenuItem.selectionType String null (default) or underline
* @uiDefault MenuItem.underlineSelectionBackground Color
* @uiDefault MenuItem.underlineSelectionCheckBackground Color
Expand Down Expand Up @@ -91,6 +93,9 @@ public class FlatMenuItemRenderer
@Styleable protected Color checkBackground = UIManager.getColor( "MenuItem.checkBackground" );
@Styleable protected Insets checkMargins = UIManager.getInsets( "MenuItem.checkMargins" );

/** @since 3 */ @Styleable protected Insets selectionInsets = UIManager.getInsets( "MenuItem.selectionInsets" );
/** @since 3 */ @Styleable protected int selectionArc = UIManager.getInt( "MenuItem.selectionArc" );

@Styleable protected Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" );
@Styleable protected Color underlineSelectionCheckBackground = UIManager.getColor( "MenuItem.underlineSelectionCheckBackground" );
@Styleable protected Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" );
Expand Down Expand Up @@ -321,32 +326,56 @@ protected void paintMenuItem( Graphics g, Color selectionBackground, Color selec
g.setColor( Color.orange ); g.drawRect( arrowRect.x, arrowRect.y, arrowRect.width - 1, arrowRect.height - 1 );
debug*/

boolean armedOrSelected = isArmedOrSelected( menuItem );
boolean underlineSelection = isUnderlineSelection();
paintBackground( g, underlineSelection ? underlineSelectionBackground : selectionBackground );
if( underlineSelection && isArmedOrSelected( menuItem ) )
paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );

paintBackground( g );
if( armedOrSelected ) {
if( underlineSelection )
paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
else
paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}
paintIcon( g, iconRect, getIconForPainting(), underlineSelection ? underlineSelectionCheckBackground : checkBackground, selectionBackground );
paintText( g, textRect, menuItem.getText(), selectionForeground, disabledForeground );
paintAccelerator( g, accelRect, getAcceleratorText(), acceleratorForeground, acceleratorSelectionForeground, disabledForeground );
if( !isTopLevelMenu( menuItem ) )
paintArrowIcon( g, arrowRect, arrowIcon );
}

protected void paintBackground( Graphics g, Color selectionBackground ) {
boolean armedOrSelected = isArmedOrSelected( menuItem );
if( menuItem.isOpaque() || armedOrSelected ) {
// paint background
g.setColor( armedOrSelected
? deriveBackground( selectionBackground )
: menuItem.getBackground() );
/** @since 3 */
protected void paintBackground( Graphics g ) {
if( menuItem.isOpaque() ) {
g.setColor( menuItem.getBackground() );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
}
}

protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
/** @since 3 */
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
Rectangle r = FlatUIUtils.subtractInsets( new Rectangle( menuItem.getSize() ), scale( selectionInsets ) );

g.setColor( deriveBackground( selectionBackground ) );
if( selectionArc > 0 ) {
Object[] oldRenderingHints = FlatUIUtils.setRenderingHints( g );
FlatUIUtils.paintComponentBackground( (Graphics2D) g, r.x, r.y, r.width, r.height, 0, scale( selectionArc ) );
FlatUIUtils.resetRenderingHints( g, oldRenderingHints );
} else
g.fillRect( r.x, r.y, r.width, r.height );
}

/** @since 3 */
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
Color underlineSelectionColor, int underlineSelectionHeight )
{
int width = menuItem.getWidth();
int height = menuItem.getHeight();

// paint background
g.setColor( deriveBackground( underlineSelectionBackground ) );
g.fillRect( 0, 0, width, height );

// paint underline
int underlineHeight = scale( underlineSelectionHeight );
g.setColor( underlineSelectionColor );
if( isTopLevelMenu( menuItem ) ) {
Expand Down
98 changes: 79 additions & 19 deletions flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuUI.java
Expand Up @@ -20,6 +20,9 @@
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Insets;
import java.awt.Rectangle;
import java.awt.Window;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;
Expand All @@ -30,7 +33,9 @@
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.LookAndFeel;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
Expand Down Expand Up @@ -71,7 +76,12 @@
*
* <!-- FlatMenuRenderer -->
*
* @uiDefault MenuBar.selectionInsets Insets
* @uiDefault MenuBar.selectionEmbeddedInsets Insets
* @uiDefault MenuBar.selectionArc int
* @uiDefault MenuBar.hoverBackground Color
* @uiDefault MenuBar.selectionBackground Color optional; defaults to Menu.selectionBackground
* @uiDefault MenuBar.selectionForeground Color optional; defaults to Menu.selectionForeground
* @uiDefault MenuBar.underlineSelectionBackground Color
* @uiDefault MenuBar.underlineSelectionColor Color
* @uiDefault MenuBar.underlineSelectionHeight int
Expand Down Expand Up @@ -215,43 +225,93 @@ public void paint( Graphics g, JComponent c ) {
protected class FlatMenuRenderer
extends FlatMenuItemRenderer
{
/** @since 3 */ protected Insets menuBarSelectionInsets = UIManager.getInsets( "MenuBar.selectionInsets" );
/** @since 3 */ protected Insets menuBarSelectionEmbeddedInsets = UIManager.getInsets( "MenuBar.selectionEmbeddedInsets" );
/** @since 3 */ protected int menuBarSelectionArc = UIManager.getInt( "MenuBar.selectionArc" );
protected Color hoverBackground = UIManager.getColor( "MenuBar.hoverBackground" );
protected Color menuBarUnderlineSelectionBackground = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionBackground", underlineSelectionBackground );
protected Color menuBarUnderlineSelectionColor = FlatUIUtils.getUIColor( "MenuBar.underlineSelectionColor", underlineSelectionColor );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", underlineSelectionHeight );
/** @since 3 */ protected Color menuBarSelectionBackground = UIManager.getColor( "MenuBar.selectionBackground" );
/** @since 3 */ protected Color menuBarSelectionForeground = UIManager.getColor( "MenuBar.selectionForeground" );
protected Color menuBarUnderlineSelectionBackground = UIManager.getColor( "MenuBar.underlineSelectionBackground" );
protected Color menuBarUnderlineSelectionColor = UIManager.getColor( "MenuBar.underlineSelectionColor" );
protected int menuBarUnderlineSelectionHeight = FlatUIUtils.getUIInt( "MenuBar.underlineSelectionHeight", -1 );

protected FlatMenuRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter )
{
super( menuItem, checkIcon, arrowIcon, acceleratorFont, acceleratorDelimiter );
}

/** @since 3 */
@Override
protected void paintBackground( Graphics g, Color selectionBackground ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( isUnderlineSelection() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground );

ButtonModel model = menuItem.getModel();
if( model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled() ) {
g.setColor( deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) ) );
protected void paintBackground( Graphics g ) {
if( ((JMenu)menuItem).isTopLevelMenu() && isHover() ) {
// paint hover background
Color color = deriveBackground( getStyleFromMenuBarUI( ui -> ui.hoverBackground, hoverBackground ) );
if( isUnderlineSelection() ) {
g.setColor( color );
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() );
return;
}
} else
paintSelection( g, color, selectionInsets, selectionArc );
return;
}

super.paintBackground( g );
}

/** @since 3 */
@Override
protected void paintSelection( Graphics g, Color selectionBackground, Insets selectionInsets, int selectionArc ) {
if( ((JMenu)menuItem).isTopLevelMenu() ) {
if( !isHover() )
selectionBackground = getStyleFromMenuBarUI( ui -> ui.selectionBackground, menuBarSelectionBackground, selectionBackground );

JMenuBar menuBar = (JMenuBar) menuItem.getParent();
JRootPane rootPane = SwingUtilities.getRootPane( menuBar );
if( rootPane != null && rootPane.getParent() instanceof Window &&
rootPane.getJMenuBar() == menuBar &&
FlatRootPaneUI.isMenuBarEmbedded( rootPane ) )
{
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionEmbeddedInsets, menuBarSelectionEmbeddedInsets );
} else
selectionInsets = getStyleFromMenuBarUI( ui -> ui.selectionInsets, menuBarSelectionInsets );

selectionArc = getStyleFromMenuBarUI( ui -> (ui.selectionArc != -1)
? ui.selectionArc : null, menuBarSelectionArc );
}

super.paintBackground( g, selectionBackground );
super.paintSelection( g, selectionBackground, selectionInsets, selectionArc );
}

/** @since 3 */
@Override
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionColor, int underlineSelectionHeight ) {
protected void paintUnderlineSelection( Graphics g, Color underlineSelectionBackground,
Color underlineSelectionColor, int underlineSelectionHeight )
{
if( ((JMenu)menuItem).isTopLevelMenu() ) {
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor );
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1)
? ui.underlineSelectionHeight : null, menuBarUnderlineSelectionHeight );
underlineSelectionBackground = getStyleFromMenuBarUI( ui -> ui.underlineSelectionBackground, menuBarUnderlineSelectionBackground, underlineSelectionBackground );
underlineSelectionColor = getStyleFromMenuBarUI( ui -> ui.underlineSelectionColor, menuBarUnderlineSelectionColor, underlineSelectionColor );
underlineSelectionHeight = getStyleFromMenuBarUI( ui -> (ui.underlineSelectionHeight != -1) ? ui.underlineSelectionHeight : null,
(menuBarUnderlineSelectionHeight != -1) ? menuBarUnderlineSelectionHeight : underlineSelectionHeight );
}

super.paintUnderlineSelection( g, underlineSelectionColor, underlineSelectionHeight );
super.paintUnderlineSelection( g, underlineSelectionBackground, underlineSelectionColor, underlineSelectionHeight );
}

@Override
protected void paintText( Graphics g, Rectangle textRect, String text, Color selectionForeground, Color disabledForeground ) {
if( ((JMenu)menuItem).isTopLevelMenu() )
selectionForeground = getStyleFromMenuBarUI( ui -> ui.selectionForeground, menuBarSelectionForeground, selectionForeground );

super.paintText( g, textRect, text, selectionForeground, disabledForeground );
}

private boolean isHover() {
ButtonModel model = menuItem.getModel();
return model.isRollover() && !model.isArmed() && !model.isSelected() && model.isEnabled();
}

private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue, T defaultValue2 ) {
return getStyleFromMenuBarUI( f, (defaultValue != null) ? defaultValue : defaultValue2 );
}

private <T> T getStyleFromMenuBarUI( Function<FlatMenuBarUI, T> f, T defaultValue ) {
Expand Down
Expand Up @@ -422,6 +422,9 @@ MenuBar.border = com.formdev.flatlaf.ui.FlatMenuBarBorder
MenuBar.background = @menuBackground
MenuBar.hoverBackground = @menuHoverBackground
MenuBar.itemMargins = 3,8,3,8
MenuBar.selectionInsets = $MenuItem.selectionInsets
MenuBar.selectionEmbeddedInsets = $MenuItem.selectionInsets
MenuBar.selectionArc = $MenuItem.selectionArc


#---- MenuItem ----
Expand All @@ -444,6 +447,8 @@ MenuItem.textNoAcceleratorGap = 6
MenuItem.acceleratorArrowGap = 2
MenuItem.acceleratorDelimiter = +
[mac]MenuItem.acceleratorDelimiter =
MenuItem.selectionInsets = 0,0,0,0
MenuItem.selectionArc = 0

# for MenuItem.selectionType = underline
MenuItem.underlineSelectionBackground = @menuHoverBackground
Expand Down
Expand Up @@ -271,7 +271,12 @@ void menuBar() {

Map<String, Class<?>> expected = expectedMap(
"itemMargins", Insets.class,
"selectionInsets", Insets.class,
"selectionEmbeddedInsets", Insets.class,
"selectionArc", int.class,
"hoverBackground", Color.class,
"selectionBackground", Color.class,
"selectionForeground", Color.class,
"underlineSelectionBackground", Color.class,
"underlineSelectionColor", Color.class,
"underlineSelectionHeight", int.class,
Expand Down Expand Up @@ -355,6 +360,9 @@ private void menuItemRenderer( Map<String, Class<?>> expected ) {
"checkBackground", Color.class,
"checkMargins", Insets.class,

"selectionInsets", Insets.class,
"selectionArc", int.class,

"underlineSelectionBackground", Color.class,
"underlineSelectionCheckBackground", Color.class,
"underlineSelectionColor", Color.class,
Expand Down
Expand Up @@ -423,7 +423,12 @@ void menuBar() {
FlatMenuBarUI ui = (FlatMenuBarUI) c.getUI();

ui.applyStyle( "itemMargins: 1,2,3,4" );
ui.applyStyle( "selectionInsets: 1,2,3,4" );
ui.applyStyle( "selectionEmbeddedInsets: 1,2,3,4" );
ui.applyStyle( "selectionArc: 8" );
ui.applyStyle( "hoverBackground: #fff" );
ui.applyStyle( "selectionBackground: #fff" );
ui.applyStyle( "selectionForeground: #fff" );
ui.applyStyle( "underlineSelectionBackground: #fff" );
ui.applyStyle( "underlineSelectionColor: #fff" );
ui.applyStyle( "underlineSelectionHeight: 3" );
Expand Down Expand Up @@ -509,6 +514,9 @@ private void menuItemRenderer( Consumer<String> applyStyle ) {
applyStyle.accept( "checkBackground: #fff" );
applyStyle.accept( "checkMargins: 1,2,3,4" );

applyStyle.accept( "selectionInsets: 1,2,3,4" );
applyStyle.accept( "selectionArc: 8" );

applyStyle.accept( "underlineSelectionBackground: #fff" );
applyStyle.accept( "underlineSelectionCheckBackground: #fff" );
applyStyle.accept( "underlineSelectionColor: #fff" );
Expand Down
5 changes: 5 additions & 0 deletions flatlaf-testing/dumps/uidefaults/FlatDarkLaf_1.8.0.txt
Expand Up @@ -593,6 +593,9 @@ MenuBar.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.Colo
MenuBar.highlight #232324 HSL 240 1 14 javax.swing.plaf.ColorUIResource [UI]
MenuBar.hoverBackground #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
MenuBar.itemMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionArc 0
MenuBar.selectionEmbeddedInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.shadow #616365 HSL 210 2 39 javax.swing.plaf.ColorUIResource [UI]
MenuBar.windowBindings length=2 [Ljava.lang.Object;
[0] F10
Expand Down Expand Up @@ -621,8 +624,10 @@ MenuItem.margin 3,6,3,6 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.minimumIconSize 16,16 javax.swing.plaf.DimensionUIResource [UI]
MenuItem.minimumWidth 72
MenuItem.opaque false
MenuItem.selectionArc 0
MenuItem.selectionBackground #4b6eaf HSL 219 40 49 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.textAcceleratorGap 24
MenuItem.textNoAcceleratorGap 6
MenuItem.underlineSelectionBackground #484c4f HSL 206 5 30 com.formdev.flatlaf.util.DerivedColor [UI] lighten(10% autoInverse)
Expand Down
5 changes: 5 additions & 0 deletions flatlaf-testing/dumps/uidefaults/FlatLightLaf_1.8.0.txt
Expand Up @@ -598,6 +598,9 @@ MenuBar.foreground #000000 HSL 0 0 0 javax.swing.plaf.Colo
MenuBar.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
MenuBar.hoverBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
MenuBar.itemMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionArc 0
MenuBar.selectionEmbeddedInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.shadow #c2c2c2 HSL 0 0 76 javax.swing.plaf.ColorUIResource [UI]
MenuBar.windowBindings length=2 [Ljava.lang.Object;
[0] F10
Expand Down Expand Up @@ -626,8 +629,10 @@ MenuItem.margin 3,6,3,6 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.minimumIconSize 16,16 javax.swing.plaf.DimensionUIResource [UI]
MenuItem.minimumWidth 72
MenuItem.opaque false
MenuItem.selectionArc 0
MenuItem.selectionBackground #2675bf HSL 209 67 45 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionInsets 0,0,0,0 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.textAcceleratorGap 24
MenuItem.textNoAcceleratorGap 6
MenuItem.underlineSelectionBackground #e6e6e6 HSL 0 0 90 com.formdev.flatlaf.util.DerivedColor [UI] darken(10% autoInverse)
Expand Down
7 changes: 7 additions & 0 deletions flatlaf-testing/dumps/uidefaults/FlatTestLaf_1.8.0.txt
Expand Up @@ -600,6 +600,11 @@ MenuBar.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.Colo
MenuBar.highlight #ffffff HSL 0 0 100 javax.swing.plaf.ColorUIResource [UI]
MenuBar.hoverBackground #ffdddd HSL 0 100 93 javax.swing.plaf.ColorUIResource [UI]
MenuBar.itemMargins 3,8,3,8 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionArc 8
MenuBar.selectionBackground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
MenuBar.selectionEmbeddedInsets 2,3,2,3 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.selectionForeground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
MenuBar.selectionInsets 1,3,1,3 javax.swing.plaf.InsetsUIResource [UI]
MenuBar.shadow #a0a0a0 HSL 0 0 63 javax.swing.plaf.ColorUIResource [UI]
MenuBar.underlineSelectionBackground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
MenuBar.underlineSelectionColor #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
Expand Down Expand Up @@ -631,8 +636,10 @@ MenuItem.margin 3,6,3,6 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.minimumIconSize 16,16 javax.swing.plaf.DimensionUIResource [UI]
MenuItem.minimumWidth 72
MenuItem.opaque false
MenuItem.selectionArc 8
MenuItem.selectionBackground #00aa00 HSL 120 100 33 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #ffff00 HSL 60 100 50 javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionInsets 0,3,0,3 javax.swing.plaf.InsetsUIResource [UI]
MenuItem.textAcceleratorGap 24
MenuItem.textNoAcceleratorGap 6
MenuItem.underlineSelectionBackground #e6e6e6 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
Expand Down