diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatCheckBoxMenuItemIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatCheckBoxMenuItemIcon.java index f49ac08e..c70be48b 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatCheckBoxMenuItemIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatCheckBoxMenuItemIcon.java @@ -30,7 +30,8 @@ import javax.swing.UIManager; * * @uiDefault MenuItemCheckBox.icon.checkmarkColor Color * @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color - * @uiDefault Menu.selectionForeground Color + * @uiDefault MenuItem.selectionForeground Color + * @uiDefault MenuItem.selectionType String * * @author Karl Tauber */ @@ -39,7 +40,7 @@ public class FlatCheckBoxMenuItemIcon { protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" ); protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" ); - protected final Color selectionForeground = UIManager.getColor( "Menu.selectionForeground" ); + protected final Color selectionForeground = UIManager.getColor( "MenuItem.selectionForeground" ); public FlatCheckBoxMenuItemIcon() { super( 15, 15, null ); @@ -67,9 +68,14 @@ public class FlatCheckBoxMenuItemIcon } private Color getCheckmarkColor( Component c ) { - if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() ) + if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() ) return selectionForeground; return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor; } + + private boolean isUnderlineSelection() { + // not storing value of "MenuItem.selectionType" in class to allow changing at runtime + return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatMenuArrowIcon.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatMenuArrowIcon.java index 0e6b41f8..2f4af4de 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatMenuArrowIcon.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/icons/FlatMenuArrowIcon.java @@ -32,6 +32,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils; * @uiDefault Menu.icon.arrowColor Color * @uiDefault Menu.icon.disabledArrowColor Color * @uiDefault Menu.selectionForeground Color + * @uiDefault MenuItem.selectionType String * * @author Karl Tauber */ @@ -65,9 +66,14 @@ public class FlatMenuArrowIcon } private Color getArrowColor( Component c ) { - if( c instanceof JMenu && ((JMenu)c).isSelected() ) + if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() ) return selectionForeground; return c.isEnabled() ? arrowColor : disabledArrowColor; } + + private boolean isUnderlineSelection() { + // not storing value of "MenuItem.selectionType" in class to allow changing at runtime + return "underline".equals( UIManager.getString( "MenuItem.selectionType" ) ); + } } diff --git a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java index 4bc2f8f3..325547da 100644 --- a/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java +++ b/flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatMenuItemRenderer.java @@ -55,6 +55,11 @@ public class FlatMenuItemRenderer protected final int textAcceleratorGap; protected final int textArrowGap; + protected final String selectionType = UIManager.getString( "MenuItem.selectionType" ); + protected final Color underlineSelectionBackground = UIManager.getColor( "MenuItem.underlineSelectionBackground" ); + protected final Color underlineSelectionColor = UIManager.getColor( "MenuItem.underlineSelectionColor" ); + protected final int underlineSelectionHeight = UIManager.getInt( "MenuItem.underlineSelectionHeight" ); + protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon, Font acceleratorFont, String acceleratorDelimiter ) { @@ -226,8 +231,30 @@ debug*/ protected void paintBackground( Graphics g, Color selectionBackground ) { boolean armedOrSelected = isArmedOrSelected( menuItem ); if( menuItem.isOpaque() || armedOrSelected ) { - g.setColor( armedOrSelected ? selectionBackground : menuItem.getBackground() ); - g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() ); + int width = menuItem.getWidth(); + int height = menuItem.getHeight(); + + // paint background + g.setColor( armedOrSelected + ? (isUnderlineSelection() ? underlineSelectionBackground : selectionBackground) + : menuItem.getBackground() ); + g.fillRect( 0, 0, width, height ); + + // paint underline + if( armedOrSelected && isUnderlineSelection() ) { + int underlineHeight = scale( underlineSelectionHeight ); + g.setColor( underlineSelectionColor ); + if( isTopLevelMenu( menuItem ) ) { + // paint underline at bottom + g.fillRect( 0, height - underlineHeight, width, underlineHeight ); + } else if( menuItem.getComponentOrientation().isLeftToRight() ) { + // paint underline at left side + g.fillRect( 0, 0, underlineHeight, height ); + } else { + // paint underline at right side + g.fillRect( width - underlineHeight, 0, underlineHeight, height ); + } + } } } @@ -252,16 +279,17 @@ debug*/ } int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1; + Color foreground = menuItem.getForeground(); paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(), - menuItem.getForeground(), selectionForeground, disabledForeground ); + foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground ); } protected void paintAccelerator( Graphics g, Rectangle accelRect, String accelText, Color foreground, Color selectionForeground, Color disabledForeground ) { paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont, - foreground, selectionForeground, disabledForeground ); + foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground ); } protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) { @@ -311,6 +339,10 @@ debug*/ return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu(); } + private boolean isUnderlineSelection() { + return "underline".equals( selectionType ); + } + private Icon getIconForPainting() { Icon icon = menuItem.getIcon(); diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties index 753fa689..6cc37334 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatDarkLaf.properties @@ -29,6 +29,7 @@ @disabledText=#777777 @textComponentBackground=#45494A @menuBackground=darken(@background,5%) +@menuHoverBackground=lighten(@menuBackground,10%) @menuCheckBackground=lighten(@menuBackground,15%) @cellFocusColor=#000000 @icon=#adadad @@ -171,7 +172,7 @@ Menu.icon.disabledArrowColor=#606060 #---- MenuBar ---- MenuBar.borderColor=#515151 -MenuBar.hoverBackground=lighten($MenuBar.background,10%) +MenuBar.hoverBackground=@menuHoverBackground #---- MenuItemCheckBox ---- diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties index 71ae358f..af705b1f 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLaf.properties @@ -319,6 +319,11 @@ MenuItem.textArrowGap=8 MenuItem.acceleratorDelimiter=- [mac]MenuItem.acceleratorDelimiter= +# for MenuItem.selectionType=underline +MenuItem.underlineSelectionBackground=@menuHoverBackground +MenuItem.underlineSelectionColor=$TabbedPane.underlineColor +MenuItem.underlineSelectionHeight=3 + #---- OptionPane ---- diff --git a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties index 8da1583d..12e9bc61 100644 --- a/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties +++ b/flatlaf-core/src/main/resources/com/formdev/flatlaf/FlatLightLaf.properties @@ -29,6 +29,7 @@ @disabledText=#8C8C8C @textComponentBackground=#ffffff @menuBackground=#fff +@menuHoverBackground=darken(@menuBackground,10%) @menuCheckBackground=darken(@menuBackground,15%) @cellFocusColor=#000000 @icon=#afafaf @@ -178,7 +179,7 @@ Menu.icon.disabledArrowColor=#ABABAB #---- MenuBar ---- MenuBar.borderColor=#cdcdcd -MenuBar.hoverBackground=darken($MenuBar.background,10%) +MenuBar.hoverBackground=@menuHoverBackground #---- MenuItemCheckBox ---- diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java index e204a15f..92ec5ead 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.java @@ -59,6 +59,11 @@ class DemoFrame } ); } + private void underlineMenuSelection() { + UIManager.put( "MenuItem.selectionType", underlineMenuSelectionMenuItem.isSelected() ? "underline" : null ); + FlatLaf.updateUI(); + } + private void fontFamilyChanged( ActionEvent e ) { String fontFamily = e.getActionCommand(); @@ -132,6 +137,8 @@ class DemoFrame JMenuItem restoreFontMenuItem = new JMenuItem(); JMenuItem incrFontMenuItem = new JMenuItem(); JMenuItem decrFontMenuItem = new JMenuItem(); + JMenu optionsMenu = new JMenu(); + underlineMenuSelectionMenuItem = new JCheckBoxMenuItem(); JMenu helpMenu = new JMenu(); JMenuItem aboutMenuItem = new JMenuItem(); JToolBar toolBar1 = new JToolBar(); @@ -355,6 +362,17 @@ class DemoFrame } menuBar1.add(fontMenu); + //======== optionsMenu ======== + { + optionsMenu.setText("Options"); + + //---- underlineMenuSelectionMenuItem ---- + underlineMenuSelectionMenuItem.setText("Use underline menu selection"); + underlineMenuSelectionMenuItem.addActionListener(e -> underlineMenuSelection()); + optionsMenu.add(underlineMenuSelectionMenuItem); + } + menuBar1.add(optionsMenu); + //======== helpMenu ======== { helpMenu.setText("Help"); @@ -481,6 +499,7 @@ class DemoFrame // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables private JMenu fontMenu; + private JCheckBoxMenuItem underlineMenuSelectionMenuItem; private JTabbedPane tabbedPane; private ControlBar controlBar; // JFormDesigner - End of variables declaration //GEN-END:variables diff --git a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd index 12717383..c3df8d44 100644 --- a/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd +++ b/flatlaf-demo/src/main/java/com/formdev/flatlaf/demo/DemoFrame.jfd @@ -310,6 +310,18 @@ new FormModel { addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "decrFont", false ) ) } ) } ) + add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { + name: "optionsMenu" + "text": "Options" + add( new FormComponent( "javax.swing.JCheckBoxMenuItem" ) { + name: "underlineMenuSelectionMenuItem" + "text": "Use underline menu selection" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "underlineMenuSelection", false ) ) + } ) + } ) add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) { name: "helpMenu" "text": "Help" diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.java b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.java index 22c440f7..deeff5d4 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.java +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.java @@ -23,6 +23,7 @@ import java.awt.Graphics; import java.awt.event.*; import java.util.function.Supplier; import javax.swing.*; +import com.formdev.flatlaf.FlatLaf; import com.formdev.flatlaf.util.UIScale; import net.miginfocom.swing.*; @@ -61,6 +62,11 @@ public class FlatMenusTest } } + private void underlineChanged() { + UIManager.put( "MenuItem.selectionType", underlineCheckBox.isSelected() ? "underline" : null ); + FlatLaf.updateUI(); + } + private void showPopupMenuButtonActionPerformed(ActionEvent e) { Component invoker = (Component) e.getSource(); PopupMenu popupMenu = new PopupMenu(); @@ -193,6 +199,7 @@ public class FlatMenusTest JLabel popupMenuLabel = new JLabel(); JButton showPopupMenuButton = new JButton(); armedCheckBox = new JCheckBox(); + underlineCheckBox = new JCheckBox(); //======== this ======== setLayout(new MigLayout( @@ -207,6 +214,7 @@ public class FlatMenusTest "[]" + "[top]" + "[]" + + "[]" + "[]")); //---- menuBarLabel ---- @@ -691,6 +699,11 @@ public class FlatMenusTest armedCheckBox.addActionListener(e -> armedChanged()); add(armedCheckBox, "cell 0 3"); + //---- underlineCheckBox ---- + underlineCheckBox.setText("underline menu selection"); + underlineCheckBox.addActionListener(e -> underlineChanged()); + add(underlineCheckBox, "cell 0 4 2 1"); + //---- buttonGroup1 ---- ButtonGroup buttonGroup1 = new ButtonGroup(); buttonGroup1.add(radioButtonMenuItem5); @@ -708,6 +721,7 @@ public class FlatMenusTest private JCheckBox largerCheckBox; private JCheckBox accelCheckBox; private JCheckBox armedCheckBox; + private JCheckBox underlineCheckBox; // JFormDesigner - End of variables declaration //GEN-END:variables //---- class PopupMenu ---------------------------------------------------- diff --git a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.jfd b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.jfd index 7108a2e8..5e30b3da 100644 --- a/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.jfd +++ b/flatlaf-testing/src/main/java/com/formdev/flatlaf/testing/FlatMenusTest.jfd @@ -9,7 +9,7 @@ new FormModel { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { "$layoutConstraints": "ltr,insets dialog,hidemode 3" "$columnConstraints": "[125][][][][]" - "$rowConstraints": "[][top][][]" + "$rowConstraints": "[][top][][][]" } ) { name: "this" add( new FormComponent( "javax.swing.JLabel" ) { @@ -528,6 +528,16 @@ new FormModel { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { "value": "cell 0 3" } ) + add( new FormComponent( "javax.swing.JCheckBox" ) { + name: "underlineCheckBox" + "text": "underline menu selection" + auxiliary() { + "JavaCodeGenerator.variableLocal": false + } + addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "underlineChanged", false ) ) + }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { + "value": "cell 0 4 2 1" + } ) }, new FormLayoutConstraints( null ) { "location": new java.awt.Point( 0, 0 ) "size": new java.awt.Dimension( 790, 380 ) diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt index eae2bfce..5ff98c35 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202-mac.txt @@ -527,6 +527,9 @@ MenuItem.selectionBackground #4b6eaf javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] MenuItem.textAcceleratorGap 24 MenuItem.textArrowGap 8 +MenuItem.underlineSelectionBackground #484c4f javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionColor #4a88c7 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionHeight 3 #---- MenuItemCheckBox ---- diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt index 0a6c23a9..fc85fc5e 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatDarkLaf_1.8.0_202.txt @@ -526,6 +526,9 @@ MenuItem.selectionBackground #4b6eaf javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] MenuItem.textAcceleratorGap 24 MenuItem.textArrowGap 8 +MenuItem.underlineSelectionBackground #484c4f javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionColor #4a88c7 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionHeight 3 #---- MenuItemCheckBox ---- diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202-mac.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202-mac.txt index f87f19f5..02a2427a 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202-mac.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202-mac.txt @@ -529,6 +529,9 @@ MenuItem.selectionBackground #2675bf javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI] MenuItem.textAcceleratorGap 24 MenuItem.textArrowGap 8 +MenuItem.underlineSelectionBackground #e6e6e6 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionColor #4083c9 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionHeight 3 #---- MenuItemCheckBox ---- diff --git a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt index 391a9071..119b4e7d 100644 --- a/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt +++ b/flatlaf-testing/src/main/resources/com/formdev/flatlaf/testing/uidefaults/FlatLightLaf_1.8.0_202.txt @@ -528,6 +528,9 @@ MenuItem.selectionBackground #2675bf javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI] MenuItem.textAcceleratorGap 24 MenuItem.textArrowGap 8 +MenuItem.underlineSelectionBackground #e6e6e6 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionColor #4083c9 javax.swing.plaf.ColorUIResource [UI] +MenuItem.underlineSelectionHeight 3 #---- MenuItemCheckBox ----