Menus: support "underline" menu selection type (suggested in issue #49)

This commit is contained in:
Karl Tauber
2020-04-29 00:26:25 +02:00
parent bd2f5dd6fe
commit e8c8bece3f
14 changed files with 129 additions and 11 deletions

View File

@@ -30,7 +30,8 @@ import javax.swing.UIManager;
* *
* @uiDefault MenuItemCheckBox.icon.checkmarkColor Color * @uiDefault MenuItemCheckBox.icon.checkmarkColor Color
* @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color * @uiDefault MenuItemCheckBox.icon.disabledCheckmarkColor Color
* @uiDefault Menu.selectionForeground Color * @uiDefault MenuItem.selectionForeground Color
* @uiDefault MenuItem.selectionType String
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -39,7 +40,7 @@ public class FlatCheckBoxMenuItemIcon
{ {
protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" ); protected final Color checkmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.checkmarkColor" );
protected final Color disabledCheckmarkColor = UIManager.getColor( "MenuItemCheckBox.icon.disabledCheckmarkColor" ); 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() { public FlatCheckBoxMenuItemIcon() {
super( 15, 15, null ); super( 15, 15, null );
@@ -67,9 +68,14 @@ public class FlatCheckBoxMenuItemIcon
} }
private Color getCheckmarkColor( Component c ) { private Color getCheckmarkColor( Component c ) {
if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() ) if( c instanceof JMenuItem && ((JMenuItem)c).isArmed() && !isUnderlineSelection() )
return selectionForeground; return selectionForeground;
return c.isEnabled() ? checkmarkColor : disabledCheckmarkColor; 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" ) );
}
} }

View File

@@ -32,6 +32,7 @@ import com.formdev.flatlaf.ui.FlatUIUtils;
* @uiDefault Menu.icon.arrowColor Color * @uiDefault Menu.icon.arrowColor Color
* @uiDefault Menu.icon.disabledArrowColor Color * @uiDefault Menu.icon.disabledArrowColor Color
* @uiDefault Menu.selectionForeground Color * @uiDefault Menu.selectionForeground Color
* @uiDefault MenuItem.selectionType String
* *
* @author Karl Tauber * @author Karl Tauber
*/ */
@@ -65,9 +66,14 @@ public class FlatMenuArrowIcon
} }
private Color getArrowColor( Component c ) { private Color getArrowColor( Component c ) {
if( c instanceof JMenu && ((JMenu)c).isSelected() ) if( c instanceof JMenu && ((JMenu)c).isSelected() && !isUnderlineSelection() )
return selectionForeground; return selectionForeground;
return c.isEnabled() ? arrowColor : disabledArrowColor; 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" ) );
}
} }

View File

@@ -55,6 +55,11 @@ public class FlatMenuItemRenderer
protected final int textAcceleratorGap; protected final int textAcceleratorGap;
protected final int textArrowGap; 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, protected FlatMenuItemRenderer( JMenuItem menuItem, Icon checkIcon, Icon arrowIcon,
Font acceleratorFont, String acceleratorDelimiter ) Font acceleratorFont, String acceleratorDelimiter )
{ {
@@ -226,8 +231,30 @@ debug*/
protected void paintBackground( Graphics g, Color selectionBackground ) { protected void paintBackground( Graphics g, Color selectionBackground ) {
boolean armedOrSelected = isArmedOrSelected( menuItem ); boolean armedOrSelected = isArmedOrSelected( menuItem );
if( menuItem.isOpaque() || armedOrSelected ) { if( menuItem.isOpaque() || armedOrSelected ) {
g.setColor( armedOrSelected ? selectionBackground : menuItem.getBackground() ); int width = menuItem.getWidth();
g.fillRect( 0, 0, menuItem.getWidth(), menuItem.getHeight() ); 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; int mnemonicIndex = FlatLaf.isShowMnemonics() ? menuItem.getDisplayedMnemonicIndex() : -1;
Color foreground = menuItem.getForeground();
paintText( g, menuItem, textRect, text, mnemonicIndex, menuItem.getFont(), 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, protected void paintAccelerator( Graphics g, Rectangle accelRect, String accelText,
Color foreground, Color selectionForeground, Color disabledForeground ) Color foreground, Color selectionForeground, Color disabledForeground )
{ {
paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont, paintText( g, menuItem, accelRect, accelText, -1, acceleratorFont,
foreground, selectionForeground, disabledForeground ); foreground, isUnderlineSelection() ? foreground : selectionForeground, disabledForeground );
} }
protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) { protected void paintArrowIcon( Graphics g, Rectangle arrowRect, Icon arrowIcon ) {
@@ -311,6 +339,10 @@ debug*/
return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu(); return menuItem instanceof JMenu && ((JMenu)menuItem).isTopLevelMenu();
} }
private boolean isUnderlineSelection() {
return "underline".equals( selectionType );
}
private Icon getIconForPainting() { private Icon getIconForPainting() {
Icon icon = menuItem.getIcon(); Icon icon = menuItem.getIcon();

View File

@@ -29,6 +29,7 @@
@disabledText=#777777 @disabledText=#777777
@textComponentBackground=#45494A @textComponentBackground=#45494A
@menuBackground=darken(@background,5%) @menuBackground=darken(@background,5%)
@menuHoverBackground=lighten(@menuBackground,10%)
@menuCheckBackground=lighten(@menuBackground,15%) @menuCheckBackground=lighten(@menuBackground,15%)
@cellFocusColor=#000000 @cellFocusColor=#000000
@icon=#adadad @icon=#adadad
@@ -171,7 +172,7 @@ Menu.icon.disabledArrowColor=#606060
#---- MenuBar ---- #---- MenuBar ----
MenuBar.borderColor=#515151 MenuBar.borderColor=#515151
MenuBar.hoverBackground=lighten($MenuBar.background,10%) MenuBar.hoverBackground=@menuHoverBackground
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----

View File

@@ -319,6 +319,11 @@ MenuItem.textArrowGap=8
MenuItem.acceleratorDelimiter=- MenuItem.acceleratorDelimiter=-
[mac]MenuItem.acceleratorDelimiter= [mac]MenuItem.acceleratorDelimiter=
# for MenuItem.selectionType=underline
MenuItem.underlineSelectionBackground=@menuHoverBackground
MenuItem.underlineSelectionColor=$TabbedPane.underlineColor
MenuItem.underlineSelectionHeight=3
#---- OptionPane ---- #---- OptionPane ----

View File

@@ -29,6 +29,7 @@
@disabledText=#8C8C8C @disabledText=#8C8C8C
@textComponentBackground=#ffffff @textComponentBackground=#ffffff
@menuBackground=#fff @menuBackground=#fff
@menuHoverBackground=darken(@menuBackground,10%)
@menuCheckBackground=darken(@menuBackground,15%) @menuCheckBackground=darken(@menuBackground,15%)
@cellFocusColor=#000000 @cellFocusColor=#000000
@icon=#afafaf @icon=#afafaf
@@ -178,7 +179,7 @@ Menu.icon.disabledArrowColor=#ABABAB
#---- MenuBar ---- #---- MenuBar ----
MenuBar.borderColor=#cdcdcd MenuBar.borderColor=#cdcdcd
MenuBar.hoverBackground=darken($MenuBar.background,10%) MenuBar.hoverBackground=@menuHoverBackground
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----

View File

@@ -59,6 +59,11 @@ class DemoFrame
} ); } );
} }
private void underlineMenuSelection() {
UIManager.put( "MenuItem.selectionType", underlineMenuSelectionMenuItem.isSelected() ? "underline" : null );
FlatLaf.updateUI();
}
private void fontFamilyChanged( ActionEvent e ) { private void fontFamilyChanged( ActionEvent e ) {
String fontFamily = e.getActionCommand(); String fontFamily = e.getActionCommand();
@@ -132,6 +137,8 @@ class DemoFrame
JMenuItem restoreFontMenuItem = new JMenuItem(); JMenuItem restoreFontMenuItem = new JMenuItem();
JMenuItem incrFontMenuItem = new JMenuItem(); JMenuItem incrFontMenuItem = new JMenuItem();
JMenuItem decrFontMenuItem = new JMenuItem(); JMenuItem decrFontMenuItem = new JMenuItem();
JMenu optionsMenu = new JMenu();
underlineMenuSelectionMenuItem = new JCheckBoxMenuItem();
JMenu helpMenu = new JMenu(); JMenu helpMenu = new JMenu();
JMenuItem aboutMenuItem = new JMenuItem(); JMenuItem aboutMenuItem = new JMenuItem();
JToolBar toolBar1 = new JToolBar(); JToolBar toolBar1 = new JToolBar();
@@ -355,6 +362,17 @@ class DemoFrame
} }
menuBar1.add(fontMenu); 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 ========
{ {
helpMenu.setText("Help"); helpMenu.setText("Help");
@@ -481,6 +499,7 @@ class DemoFrame
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables // JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
private JMenu fontMenu; private JMenu fontMenu;
private JCheckBoxMenuItem underlineMenuSelectionMenuItem;
private JTabbedPane tabbedPane; private JTabbedPane tabbedPane;
private ControlBar controlBar; private ControlBar controlBar;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables

View File

@@ -310,6 +310,18 @@ new FormModel {
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "decrFont", false ) ) 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 ) ) { add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
name: "helpMenu" name: "helpMenu"
"text": "Help" "text": "Help"

View File

@@ -23,6 +23,7 @@ import java.awt.Graphics;
import java.awt.event.*; import java.awt.event.*;
import java.util.function.Supplier; import java.util.function.Supplier;
import javax.swing.*; import javax.swing.*;
import com.formdev.flatlaf.FlatLaf;
import com.formdev.flatlaf.util.UIScale; import com.formdev.flatlaf.util.UIScale;
import net.miginfocom.swing.*; 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) { private void showPopupMenuButtonActionPerformed(ActionEvent e) {
Component invoker = (Component) e.getSource(); Component invoker = (Component) e.getSource();
PopupMenu popupMenu = new PopupMenu(); PopupMenu popupMenu = new PopupMenu();
@@ -193,6 +199,7 @@ public class FlatMenusTest
JLabel popupMenuLabel = new JLabel(); JLabel popupMenuLabel = new JLabel();
JButton showPopupMenuButton = new JButton(); JButton showPopupMenuButton = new JButton();
armedCheckBox = new JCheckBox(); armedCheckBox = new JCheckBox();
underlineCheckBox = new JCheckBox();
//======== this ======== //======== this ========
setLayout(new MigLayout( setLayout(new MigLayout(
@@ -207,6 +214,7 @@ public class FlatMenusTest
"[]" + "[]" +
"[top]" + "[top]" +
"[]" + "[]" +
"[]" +
"[]")); "[]"));
//---- menuBarLabel ---- //---- menuBarLabel ----
@@ -691,6 +699,11 @@ public class FlatMenusTest
armedCheckBox.addActionListener(e -> armedChanged()); armedCheckBox.addActionListener(e -> armedChanged());
add(armedCheckBox, "cell 0 3"); add(armedCheckBox, "cell 0 3");
//---- underlineCheckBox ----
underlineCheckBox.setText("underline menu selection");
underlineCheckBox.addActionListener(e -> underlineChanged());
add(underlineCheckBox, "cell 0 4 2 1");
//---- buttonGroup1 ---- //---- buttonGroup1 ----
ButtonGroup buttonGroup1 = new ButtonGroup(); ButtonGroup buttonGroup1 = new ButtonGroup();
buttonGroup1.add(radioButtonMenuItem5); buttonGroup1.add(radioButtonMenuItem5);
@@ -708,6 +721,7 @@ public class FlatMenusTest
private JCheckBox largerCheckBox; private JCheckBox largerCheckBox;
private JCheckBox accelCheckBox; private JCheckBox accelCheckBox;
private JCheckBox armedCheckBox; private JCheckBox armedCheckBox;
private JCheckBox underlineCheckBox;
// JFormDesigner - End of variables declaration //GEN-END:variables // JFormDesigner - End of variables declaration //GEN-END:variables
//---- class PopupMenu ---------------------------------------------------- //---- class PopupMenu ----------------------------------------------------

View File

@@ -9,7 +9,7 @@ new FormModel {
add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) { add( new FormContainer( "com.formdev.flatlaf.testing.FlatTestPanel", new FormLayoutManager( class net.miginfocom.swing.MigLayout ) {
"$layoutConstraints": "ltr,insets dialog,hidemode 3" "$layoutConstraints": "ltr,insets dialog,hidemode 3"
"$columnConstraints": "[125][][][][]" "$columnConstraints": "[125][][][][]"
"$rowConstraints": "[][top][][]" "$rowConstraints": "[][top][][][]"
} ) { } ) {
name: "this" name: "this"
add( new FormComponent( "javax.swing.JLabel" ) { add( new FormComponent( "javax.swing.JLabel" ) {
@@ -528,6 +528,16 @@ new FormModel {
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) { }, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
"value": "cell 0 3" "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 ) { }, new FormLayoutConstraints( null ) {
"location": new java.awt.Point( 0, 0 ) "location": new java.awt.Point( 0, 0 )
"size": new java.awt.Dimension( 790, 380 ) "size": new java.awt.Dimension( 790, 380 )

View File

@@ -527,6 +527,9 @@ MenuItem.selectionBackground #4b6eaf javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI]
MenuItem.textAcceleratorGap 24 MenuItem.textAcceleratorGap 24
MenuItem.textArrowGap 8 MenuItem.textArrowGap 8
MenuItem.underlineSelectionBackground #484c4f javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionColor #4a88c7 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionHeight 3
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----

View File

@@ -526,6 +526,9 @@ MenuItem.selectionBackground #4b6eaf javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #bbbbbb javax.swing.plaf.ColorUIResource [UI]
MenuItem.textAcceleratorGap 24 MenuItem.textAcceleratorGap 24
MenuItem.textArrowGap 8 MenuItem.textArrowGap 8
MenuItem.underlineSelectionBackground #484c4f javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionColor #4a88c7 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionHeight 3
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----

View File

@@ -529,6 +529,9 @@ MenuItem.selectionBackground #2675bf javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI]
MenuItem.textAcceleratorGap 24 MenuItem.textAcceleratorGap 24
MenuItem.textArrowGap 8 MenuItem.textArrowGap 8
MenuItem.underlineSelectionBackground #e6e6e6 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionColor #4083c9 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionHeight 3
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----

View File

@@ -528,6 +528,9 @@ MenuItem.selectionBackground #2675bf javax.swing.plaf.ColorUIResource [UI]
MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI] MenuItem.selectionForeground #ffffff javax.swing.plaf.ColorUIResource [UI]
MenuItem.textAcceleratorGap 24 MenuItem.textAcceleratorGap 24
MenuItem.textArrowGap 8 MenuItem.textArrowGap 8
MenuItem.underlineSelectionBackground #e6e6e6 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionColor #4083c9 javax.swing.plaf.ColorUIResource [UI]
MenuItem.underlineSelectionHeight 3
#---- MenuItemCheckBox ---- #---- MenuItemCheckBox ----