mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2025-12-07 14:30:56 +03:00
Menus: scroll large menus using mouse wheel or up/down arrows (issue #225)
This commit is contained in:
@@ -6,6 +6,7 @@ FlatLaf Change Log
|
|||||||
#### New features and improvements
|
#### New features and improvements
|
||||||
|
|
||||||
- Menus: Improved usability of submenus. (PR #490; issue #247)
|
- Menus: Improved usability of submenus. (PR #490; issue #247)
|
||||||
|
- Menus: Scroll large menus using mouse wheel or up/down arrows. (issue #225)
|
||||||
- Linux: Support using custom window decorations. Enable with
|
- Linux: Support using custom window decorations. Enable with
|
||||||
`JFrame.setDefaultLookAndFeelDecorated(true)` and
|
`JFrame.setDefaultLookAndFeelDecorated(true)` and
|
||||||
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
|
`JDialog.setDefaultLookAndFeelDecorated(true)` before creating a window.
|
||||||
|
|||||||
@@ -16,18 +16,58 @@
|
|||||||
|
|
||||||
package com.formdev.flatlaf.ui;
|
package com.formdev.flatlaf.ui;
|
||||||
|
|
||||||
|
import java.awt.BorderLayout;
|
||||||
|
import java.awt.Color;
|
||||||
|
import java.awt.Component;
|
||||||
import java.awt.Container;
|
import java.awt.Container;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
|
import java.awt.EventQueue;
|
||||||
|
import java.awt.Graphics;
|
||||||
|
import java.awt.GraphicsConfiguration;
|
||||||
|
import java.awt.GraphicsDevice;
|
||||||
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.Insets;
|
||||||
import java.awt.LayoutManager;
|
import java.awt.LayoutManager;
|
||||||
|
import java.awt.Point;
|
||||||
|
import java.awt.Rectangle;
|
||||||
|
import java.awt.Toolkit;
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.awt.event.ActionListener;
|
||||||
|
import java.awt.event.MouseEvent;
|
||||||
|
import java.awt.event.MouseListener;
|
||||||
|
import java.awt.event.MouseWheelEvent;
|
||||||
|
import java.awt.event.MouseWheelListener;
|
||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicBoolean;
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
import javax.swing.BoxLayout;
|
import javax.swing.BoxLayout;
|
||||||
|
import javax.swing.JButton;
|
||||||
import javax.swing.JComponent;
|
import javax.swing.JComponent;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.JPanel;
|
||||||
|
import javax.swing.JPopupMenu;
|
||||||
|
import javax.swing.JScrollPane;
|
||||||
|
import javax.swing.JViewport;
|
||||||
|
import javax.swing.MenuElement;
|
||||||
|
import javax.swing.MenuSelectionManager;
|
||||||
|
import javax.swing.Popup;
|
||||||
|
import javax.swing.PopupFactory;
|
||||||
|
import javax.swing.SwingConstants;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.Timer;
|
||||||
|
import javax.swing.UIManager;
|
||||||
|
import javax.swing.event.MenuKeyEvent;
|
||||||
|
import javax.swing.event.MenuKeyListener;
|
||||||
|
import javax.swing.event.PopupMenuEvent;
|
||||||
|
import javax.swing.event.PopupMenuListener;
|
||||||
|
import javax.swing.plaf.ButtonUI;
|
||||||
import javax.swing.plaf.ComponentUI;
|
import javax.swing.plaf.ComponentUI;
|
||||||
import javax.swing.plaf.UIResource;
|
import javax.swing.plaf.UIResource;
|
||||||
|
import javax.swing.plaf.basic.BasicComboPopup;
|
||||||
|
import javax.swing.plaf.basic.BasicMenuItemUI;
|
||||||
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
import javax.swing.plaf.basic.BasicPopupMenuUI;
|
||||||
import javax.swing.plaf.basic.DefaultMenuLayout;
|
import javax.swing.plaf.basic.DefaultMenuLayout;
|
||||||
|
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
|
||||||
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
|
||||||
import com.formdev.flatlaf.util.LoggingFacade;
|
import com.formdev.flatlaf.util.LoggingFacade;
|
||||||
|
|
||||||
@@ -41,12 +81,22 @@ import com.formdev.flatlaf.util.LoggingFacade;
|
|||||||
* @uiDefault PopupMenu.foreground Color
|
* @uiDefault PopupMenu.foreground Color
|
||||||
* @uiDefault PopupMenu.border Border
|
* @uiDefault PopupMenu.border Border
|
||||||
*
|
*
|
||||||
|
* <!-- FlatPopupMenuUI -->
|
||||||
|
*
|
||||||
|
* @uiDefault Component.arrowType String chevron (default) or triangle
|
||||||
|
* @uiDefault PopupMenu.scrollArrowColor Color
|
||||||
|
* @uiDefault PopupMenu.hoverScrollArrowBackground Color optional
|
||||||
|
*
|
||||||
* @author Karl Tauber
|
* @author Karl Tauber
|
||||||
*/
|
*/
|
||||||
public class FlatPopupMenuUI
|
public class FlatPopupMenuUI
|
||||||
extends BasicPopupMenuUI
|
extends BasicPopupMenuUI
|
||||||
implements StyleableUI
|
implements StyleableUI
|
||||||
{
|
{
|
||||||
|
/** @since 2.1 */ @Styleable protected String arrowType;
|
||||||
|
/** @since 2.1 */ @Styleable protected Color scrollArrowColor;
|
||||||
|
/** @since 2.1 */ @Styleable protected Color hoverScrollArrowBackground;
|
||||||
|
|
||||||
private PropertyChangeListener propertyChangeListener;
|
private PropertyChangeListener propertyChangeListener;
|
||||||
private Map<String, Object> oldStyleValues;
|
private Map<String, Object> oldStyleValues;
|
||||||
private AtomicBoolean borderShared;
|
private AtomicBoolean borderShared;
|
||||||
@@ -74,11 +124,23 @@ public class FlatPopupMenuUI
|
|||||||
public void installDefaults() {
|
public void installDefaults() {
|
||||||
super.installDefaults();
|
super.installDefaults();
|
||||||
|
|
||||||
|
arrowType = UIManager.getString( "Component.arrowType" );
|
||||||
|
scrollArrowColor = UIManager.getColor( "PopupMenu.scrollArrowColor" );
|
||||||
|
hoverScrollArrowBackground = UIManager.getColor( "PopupMenu.hoverScrollArrowBackground" );
|
||||||
|
|
||||||
LayoutManager layout = popupMenu.getLayout();
|
LayoutManager layout = popupMenu.getLayout();
|
||||||
if( layout == null || layout instanceof UIResource )
|
if( layout == null || layout instanceof UIResource )
|
||||||
popupMenu.setLayout( new FlatMenuLayout( popupMenu, BoxLayout.Y_AXIS ) );
|
popupMenu.setLayout( new FlatMenuLayout( popupMenu, BoxLayout.Y_AXIS ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void uninstallDefaults() {
|
||||||
|
super.uninstallDefaults();
|
||||||
|
|
||||||
|
scrollArrowColor = null;
|
||||||
|
hoverScrollArrowBackground = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void installListeners() {
|
protected void installListeners() {
|
||||||
super.installListeners();
|
super.installListeners();
|
||||||
@@ -122,6 +184,52 @@ public class FlatPopupMenuUI
|
|||||||
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
|
return FlatStylingSupport.getAnnotatedStyleableInfos( this, popupMenu.getBorder() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Popup getPopup( JPopupMenu popup, int x, int y ) {
|
||||||
|
// do not add scroller to combobox popups or to popups that already have a scroll pane
|
||||||
|
if( popup instanceof BasicComboPopup ||
|
||||||
|
(popup.getComponentCount() > 0 && popup.getComponent( 0 ) instanceof JScrollPane) )
|
||||||
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
|
// do not add scroller if popup fits into screen
|
||||||
|
Dimension prefSize = popup.getPreferredSize();
|
||||||
|
int screenHeight = getScreenHeightAt( x, y );
|
||||||
|
if( prefSize.height <= screenHeight )
|
||||||
|
return super.getPopup( popup, x, y );
|
||||||
|
|
||||||
|
// create scroller
|
||||||
|
FlatPopupScroller scroller = new FlatPopupScroller( popup );
|
||||||
|
scroller.setPreferredSize( new Dimension( prefSize.width, screenHeight ) );
|
||||||
|
|
||||||
|
// create popup
|
||||||
|
PopupFactory popupFactory = PopupFactory.getSharedInstance();
|
||||||
|
return popupFactory.getPopup( popup.getInvoker(), scroller, x, y );
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getScreenHeightAt( int x, int y ) {
|
||||||
|
// find GraphicsConfiguration at popup location (similar to JPopupMenu.getCurrentGraphicsConfiguration())
|
||||||
|
GraphicsConfiguration gc = null;
|
||||||
|
for( GraphicsDevice device : GraphicsEnvironment.getLocalGraphicsEnvironment().getScreenDevices() ) {
|
||||||
|
if( device.getType() == GraphicsDevice.TYPE_RASTER_SCREEN ) {
|
||||||
|
GraphicsConfiguration dgc = device.getDefaultConfiguration();
|
||||||
|
if( dgc.getBounds().contains( x, y ) ) {
|
||||||
|
gc = dgc;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if( gc == null && popupMenu.getInvoker() != null )
|
||||||
|
gc = popupMenu.getInvoker().getGraphicsConfiguration();
|
||||||
|
|
||||||
|
// compute screen height
|
||||||
|
// (always subtract screen insets because there is no API to detect whether
|
||||||
|
// the popup can overlap the taskbar; see JPopupMenu.canPopupOverlapTaskBar())
|
||||||
|
Toolkit toolkit = Toolkit.getDefaultToolkit();
|
||||||
|
Rectangle screenBounds = (gc != null) ? gc.getBounds() : new Rectangle( toolkit.getScreenSize() );
|
||||||
|
Insets screenInsets = Toolkit.getDefaultToolkit().getScreenInsets( gc );
|
||||||
|
return screenBounds.height - screenInsets.top - screenInsets.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
//---- class FlatMenuLayout -----------------------------------------------
|
//---- class FlatMenuLayout -----------------------------------------------
|
||||||
|
|
||||||
protected static class FlatMenuLayout
|
protected static class FlatMenuLayout
|
||||||
@@ -138,4 +246,206 @@ public class FlatPopupMenuUI
|
|||||||
return super.preferredLayoutSize( target );
|
return super.preferredLayoutSize( target );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//---- class FlatPopupScroller --------------------------------------------
|
||||||
|
|
||||||
|
private class FlatPopupScroller
|
||||||
|
extends JPanel
|
||||||
|
implements MouseWheelListener, PopupMenuListener, MenuKeyListener
|
||||||
|
{
|
||||||
|
private final JPopupMenu popup;
|
||||||
|
|
||||||
|
private final JScrollPane scrollPane;
|
||||||
|
private final JButton scrollUpButton;
|
||||||
|
private final JButton scrollDownButton;
|
||||||
|
private int unitIncrement;
|
||||||
|
|
||||||
|
FlatPopupScroller( JPopupMenu popup ) {
|
||||||
|
super( new BorderLayout() );
|
||||||
|
this.popup = popup;
|
||||||
|
|
||||||
|
// this panel is required to avoid that JPopupMenu.setLocation() will be invoked
|
||||||
|
// while scrolling, because this would call JPopupMenu.showPopup()
|
||||||
|
JPanel view = new JPanel( new BorderLayout() );
|
||||||
|
view.add( popup, BorderLayout.CENTER );
|
||||||
|
|
||||||
|
scrollPane = new JScrollPane( view, JScrollPane.VERTICAL_SCROLLBAR_NEVER, JScrollPane.HORIZONTAL_SCROLLBAR_NEVER );
|
||||||
|
scrollPane.setBorder( null );
|
||||||
|
|
||||||
|
scrollUpButton = new ArrowButton( SwingConstants.NORTH );
|
||||||
|
scrollDownButton = new ArrowButton( SwingConstants.SOUTH );
|
||||||
|
|
||||||
|
add( scrollPane, BorderLayout.CENTER );
|
||||||
|
add( scrollUpButton, BorderLayout.NORTH );
|
||||||
|
add( scrollDownButton, BorderLayout.SOUTH );
|
||||||
|
|
||||||
|
setBackground( popup.getBackground() );
|
||||||
|
setBorder( popup.getBorder() );
|
||||||
|
popup.setBorder( null );
|
||||||
|
|
||||||
|
popup.addPopupMenuListener( this );
|
||||||
|
popup.addMouseWheelListener( this );
|
||||||
|
popup.addMenuKeyListener( this );
|
||||||
|
|
||||||
|
updateArrowButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void scroll( int unitsToScroll ) {
|
||||||
|
if( unitIncrement == 0 )
|
||||||
|
unitIncrement = new JMenuItem( "X" ).getPreferredSize().height;
|
||||||
|
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
Point viewPosition = viewport.getViewPosition();
|
||||||
|
int newY = viewPosition.y + (unitIncrement * unitsToScroll);
|
||||||
|
if( newY < 0 )
|
||||||
|
newY = 0;
|
||||||
|
else
|
||||||
|
newY = Math.min( newY, viewport.getViewSize().height - viewport.getExtentSize().height );
|
||||||
|
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
|
||||||
|
|
||||||
|
updateArrowButtons();
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateArrowButtons() {
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
Point viewPosition = viewport.getViewPosition();
|
||||||
|
|
||||||
|
scrollUpButton.setVisible( viewPosition.y > 0 );
|
||||||
|
scrollDownButton.setVisible( viewPosition.y < viewport.getViewSize().height - viewport.getExtentSize().height );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface PopupMenuListener ----
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void popupMenuWillBecomeInvisible( PopupMenuEvent e ) {
|
||||||
|
// restore popup border
|
||||||
|
popup.setBorder( getBorder() );
|
||||||
|
|
||||||
|
popup.removePopupMenuListener( this );
|
||||||
|
popup.removeMouseWheelListener( this );
|
||||||
|
popup.removeMenuKeyListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void popupMenuWillBecomeVisible( PopupMenuEvent e ) {}
|
||||||
|
@Override public void popupMenuCanceled( PopupMenuEvent e ) {}
|
||||||
|
|
||||||
|
//---- interface MouseWheelListener ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll when user rotates mouse wheel.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void mouseWheelMoved( MouseWheelEvent e ) {
|
||||||
|
// convert mouse location before scrolling
|
||||||
|
Point mouseLocation = SwingUtilities.convertPoint( (Component) e.getSource(), e.getPoint(), this );
|
||||||
|
|
||||||
|
// scroll
|
||||||
|
scroll( e.getUnitsToScroll() );
|
||||||
|
|
||||||
|
// select menu item at mouse location
|
||||||
|
Component c = SwingUtilities.getDeepestComponentAt( this, mouseLocation.x, mouseLocation.y );
|
||||||
|
if( c instanceof JMenuItem ) {
|
||||||
|
ButtonUI ui = ((JMenuItem)c).getUI();
|
||||||
|
if( ui instanceof BasicMenuItemUI )
|
||||||
|
MenuSelectionManager.defaultManager().setSelectedPath( ((BasicMenuItemUI)ui).getPath() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// this avoids that the popup is closed when running on Java 8
|
||||||
|
// https://bugs.openjdk.java.net/browse/JDK-8075063
|
||||||
|
e.consume();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface MenuKeyListener ----
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scroll when user presses Up or Down keys.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void menuKeyPressed( MenuKeyEvent e ) {
|
||||||
|
// use invokeLater() because menu selection is not yet updated because
|
||||||
|
// this listener is invoked before another listener that updates the menu selection
|
||||||
|
EventQueue.invokeLater( () -> {
|
||||||
|
if( !isDisplayable() )
|
||||||
|
return;
|
||||||
|
|
||||||
|
MenuElement[] path = MenuSelectionManager.defaultManager().getSelectedPath();
|
||||||
|
if( path.length == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
// scroll selected menu item to visible area
|
||||||
|
Component c = path[path.length - 1].getComponent();
|
||||||
|
JViewport viewport = scrollPane.getViewport();
|
||||||
|
Point pt = SwingUtilities.convertPoint( c, 0, 0, viewport );
|
||||||
|
viewport.scrollRectToVisible( new Rectangle( pt, c.getSize() ) );
|
||||||
|
|
||||||
|
// update arrow buttons
|
||||||
|
boolean upVisible = scrollUpButton.isVisible();
|
||||||
|
updateArrowButtons();
|
||||||
|
if( !upVisible && scrollUpButton.isVisible() ) {
|
||||||
|
// if "up" button becomes visible, make sure that bottom menu item stays visible
|
||||||
|
Point viewPosition = viewport.getViewPosition();
|
||||||
|
int newY = viewPosition.y + scrollUpButton.getPreferredSize().height;
|
||||||
|
viewport.setViewPosition( new Point( viewPosition.x, newY ) );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override public void menuKeyTyped( MenuKeyEvent e ) {}
|
||||||
|
@Override public void menuKeyReleased( MenuKeyEvent e ) {}
|
||||||
|
|
||||||
|
//---- class ArrowButton ----------------------------------------------
|
||||||
|
|
||||||
|
private class ArrowButton
|
||||||
|
extends FlatArrowButton
|
||||||
|
implements MouseListener, ActionListener
|
||||||
|
{
|
||||||
|
private Timer timer;
|
||||||
|
|
||||||
|
ArrowButton( int direction ) {
|
||||||
|
super( direction, arrowType, scrollArrowColor, null, null, hoverScrollArrowBackground, null, null );
|
||||||
|
|
||||||
|
addMouseListener( this );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void paint( Graphics g ) {
|
||||||
|
// always fill background to paint over border on HiDPI screens
|
||||||
|
g.setColor( popup.getBackground() );
|
||||||
|
g.fillRect( 0, 0, getWidth(), getHeight() );
|
||||||
|
|
||||||
|
super.paint( g );
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface MouseListener ----
|
||||||
|
|
||||||
|
@Override public void mouseClicked( MouseEvent e ) {}
|
||||||
|
@Override public void mousePressed( MouseEvent e ) {}
|
||||||
|
@Override public void mouseReleased( MouseEvent e ) {}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseEntered( MouseEvent e ) {
|
||||||
|
if( timer == null )
|
||||||
|
timer = new Timer( 50, this );
|
||||||
|
timer.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void mouseExited( MouseEvent e ) {
|
||||||
|
if( timer != null )
|
||||||
|
timer.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//---- interface ActionListener ----
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed( ActionEvent e ) {
|
||||||
|
if( timer != null && !isDisplayable() ) {
|
||||||
|
timer.stop();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
scroll( direction == SwingConstants.NORTH ? -1 : 1 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -252,6 +252,7 @@ Popup.dropShadowOpacity = 0.25
|
|||||||
#---- PopupMenu ----
|
#---- PopupMenu ----
|
||||||
|
|
||||||
PopupMenu.borderColor = tint(@background,17%)
|
PopupMenu.borderColor = tint(@background,17%)
|
||||||
|
PopupMenu.hoverScrollArrowBackground = lighten(@background,5%)
|
||||||
|
|
||||||
|
|
||||||
#---- ProgressBar ----
|
#---- ProgressBar ----
|
||||||
|
|||||||
@@ -500,6 +500,7 @@ Popup.dropShadowInsets = -4,-4,4,4
|
|||||||
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
PopupMenu.border = com.formdev.flatlaf.ui.FlatPopupMenuBorder
|
||||||
PopupMenu.borderInsets = 4,1,4,1
|
PopupMenu.borderInsets = 4,1,4,1
|
||||||
PopupMenu.background = @menuBackground
|
PopupMenu.background = @menuBackground
|
||||||
|
PopupMenu.scrollArrowColor = @buttonArrowColor
|
||||||
|
|
||||||
|
|
||||||
#---- PopupMenuSeparator ----
|
#---- PopupMenuSeparator ----
|
||||||
|
|||||||
@@ -259,6 +259,7 @@ Popup.dropShadowOpacity = 0.15
|
|||||||
#---- PopupMenu ----
|
#---- PopupMenu ----
|
||||||
|
|
||||||
PopupMenu.borderColor = shade(@background,28%)
|
PopupMenu.borderColor = shade(@background,28%)
|
||||||
|
PopupMenu.hoverScrollArrowBackground = darken(@background,5%)
|
||||||
|
|
||||||
|
|
||||||
#---- ProgressBar ----
|
#---- ProgressBar ----
|
||||||
|
|||||||
@@ -422,6 +422,10 @@ public class TestFlatStyleableInfo
|
|||||||
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
||||||
|
|
||||||
Map<String, Class<?>> expected = expectedMap(
|
Map<String, Class<?>> expected = expectedMap(
|
||||||
|
"arrowType", String.class,
|
||||||
|
"scrollArrowColor", Color.class,
|
||||||
|
"hoverScrollArrowBackground", Color.class,
|
||||||
|
|
||||||
"borderInsets", Insets.class,
|
"borderInsets", Insets.class,
|
||||||
"borderColor", Color.class
|
"borderColor", Color.class
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -565,6 +565,10 @@ public class TestFlatStyling
|
|||||||
JPopupMenu c = new JPopupMenu();
|
JPopupMenu c = new JPopupMenu();
|
||||||
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
FlatPopupMenuUI ui = (FlatPopupMenuUI) c.getUI();
|
||||||
|
|
||||||
|
ui.applyStyle( "arrowType: chevron" );
|
||||||
|
ui.applyStyle( "scrollArrowColor: #fff" );
|
||||||
|
ui.applyStyle( "hoverScrollArrowBackground: #fff" );
|
||||||
|
|
||||||
ui.applyStyle( "borderInsets: 1,2,3,4" );
|
ui.applyStyle( "borderInsets: 1,2,3,4" );
|
||||||
ui.applyStyle( "borderColor: #fff" );
|
ui.applyStyle( "borderColor: #fff" );
|
||||||
|
|
||||||
|
|||||||
@@ -464,6 +464,7 @@ class DemoFrame
|
|||||||
JMenuItem projectViewMenuItem = new JMenuItem();
|
JMenuItem projectViewMenuItem = new JMenuItem();
|
||||||
JMenuItem structureViewMenuItem = new JMenuItem();
|
JMenuItem structureViewMenuItem = new JMenuItem();
|
||||||
JMenuItem propertiesViewMenuItem = new JMenuItem();
|
JMenuItem propertiesViewMenuItem = new JMenuItem();
|
||||||
|
scrollingPopupMenu = new JMenu();
|
||||||
JMenuItem menuItem2 = new JMenuItem();
|
JMenuItem menuItem2 = new JMenuItem();
|
||||||
htmlMenuItem = new JMenuItem();
|
htmlMenuItem = new JMenuItem();
|
||||||
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
|
JRadioButtonMenuItem radioButtonMenuItem1 = new JRadioButtonMenuItem();
|
||||||
@@ -668,6 +669,12 @@ class DemoFrame
|
|||||||
}
|
}
|
||||||
viewMenu.add(menu1);
|
viewMenu.add(menu1);
|
||||||
|
|
||||||
|
//======== scrollingPopupMenu ========
|
||||||
|
{
|
||||||
|
scrollingPopupMenu.setText("Scrolling Popup Menu");
|
||||||
|
}
|
||||||
|
viewMenu.add(scrollingPopupMenu);
|
||||||
|
|
||||||
//---- menuItem2 ----
|
//---- menuItem2 ----
|
||||||
menuItem2.setText("Disabled Item");
|
menuItem2.setText("Disabled Item");
|
||||||
menuItem2.setEnabled(false);
|
menuItem2.setEnabled(false);
|
||||||
@@ -889,6 +896,12 @@ class DemoFrame
|
|||||||
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
|
copyMenuItem.addActionListener( new DefaultEditorKit.CopyAction() );
|
||||||
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
|
pasteMenuItem.addActionListener( new DefaultEditorKit.PasteAction() );
|
||||||
|
|
||||||
|
scrollingPopupMenu.add( "Large menus are scrollable" );
|
||||||
|
scrollingPopupMenu.add( "Use mouse wheel to scroll" );
|
||||||
|
scrollingPopupMenu.add( "Or use up/down arrows at top/bottom" );
|
||||||
|
for( int i = 1; i <= 100; i++ )
|
||||||
|
scrollingPopupMenu.add( "Item " + i );
|
||||||
|
|
||||||
if( FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated()) ) {
|
if( FlatLaf.supportsNativeWindowDecorations() || (SystemInfo.isLinux && JFrame.isDefaultLookAndFeelDecorated()) ) {
|
||||||
if( SystemInfo.isLinux )
|
if( SystemInfo.isLinux )
|
||||||
unsupported( windowDecorationsCheckBoxMenuItem );
|
unsupported( windowDecorationsCheckBoxMenuItem );
|
||||||
@@ -934,6 +947,7 @@ class DemoFrame
|
|||||||
|
|
||||||
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
// JFormDesigner - Variables declaration - DO NOT MODIFY //GEN-BEGIN:variables
|
||||||
private JMenuItem exitMenuItem;
|
private JMenuItem exitMenuItem;
|
||||||
|
private JMenu scrollingPopupMenu;
|
||||||
private JMenuItem htmlMenuItem;
|
private JMenuItem htmlMenuItem;
|
||||||
private JMenu fontMenu;
|
private JMenu fontMenu;
|
||||||
private JMenu optionsMenu;
|
private JMenu optionsMenu;
|
||||||
|
|||||||
@@ -282,6 +282,13 @@ new FormModel {
|
|||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "menuItemActionPerformed", true ) )
|
||||||
} )
|
} )
|
||||||
} )
|
} )
|
||||||
|
add( new FormContainer( "javax.swing.JMenu", new FormLayoutManager( class javax.swing.JMenu ) ) {
|
||||||
|
name: "scrollingPopupMenu"
|
||||||
|
"text": "Scrolling Popup Menu"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
add( new FormComponent( "javax.swing.JMenuItem" ) {
|
||||||
name: "menuItem2"
|
name: "menuItem2"
|
||||||
"text": "Disabled Item"
|
"text": "Disabled Item"
|
||||||
|
|||||||
@@ -737,6 +737,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
|
|||||||
PopupMenu.consumeEventOnClose false
|
PopupMenu.consumeEventOnClose false
|
||||||
PopupMenu.font [active] $defaultFont [UI]
|
PopupMenu.font [active] $defaultFont [UI]
|
||||||
PopupMenu.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
PopupMenu.foreground #bbbbbb HSL 0 0 73 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.hoverScrollArrowBackground #484c4e HSL 200 4 29 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.scrollArrowColor #9b9b9b HSL 0 0 61 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
|
||||||
|
|
||||||
#---- PopupMenuSeparator ----
|
#---- PopupMenuSeparator ----
|
||||||
|
|||||||
@@ -742,6 +742,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
|
|||||||
PopupMenu.consumeEventOnClose false
|
PopupMenu.consumeEventOnClose false
|
||||||
PopupMenu.font [active] $defaultFont [UI]
|
PopupMenu.font [active] $defaultFont [UI]
|
||||||
PopupMenu.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
PopupMenu.foreground #000000 HSL 0 0 0 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.hoverScrollArrowBackground #e5e5e5 HSL 0 0 90 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.scrollArrowColor #666666 HSL 0 0 40 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
|
||||||
|
|
||||||
#---- PopupMenuSeparator ----
|
#---- PopupMenuSeparator ----
|
||||||
|
|||||||
@@ -752,6 +752,8 @@ PopupMenu.borderInsets 4,1,4,1 javax.swing.plaf.InsetsUIResource [UI]
|
|||||||
PopupMenu.consumeEventOnClose false
|
PopupMenu.consumeEventOnClose false
|
||||||
PopupMenu.font [active] $defaultFont [UI]
|
PopupMenu.font [active] $defaultFont [UI]
|
||||||
PopupMenu.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
PopupMenu.foreground #ff0000 HSL 0 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.hoverScrollArrowBackground #00ff00 HSL 120 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
PopupMenu.scrollArrowColor #0000ff HSL 240 100 50 javax.swing.plaf.ColorUIResource [UI]
|
||||||
|
|
||||||
|
|
||||||
#---- PopupMenuSeparator ----
|
#---- PopupMenuSeparator ----
|
||||||
|
|||||||
@@ -80,13 +80,24 @@ public class FlatMenusTest
|
|||||||
FlatLaf.updateUI();
|
FlatLaf.updateUI();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showPopupMenuButtonActionPerformed(ActionEvent e) {
|
private void showPopupMenuButton(ActionEvent e) {
|
||||||
Component invoker = (Component) e.getSource();
|
Component invoker = (Component) e.getSource();
|
||||||
PopupMenu popupMenu = new PopupMenu();
|
PopupMenu popupMenu = new PopupMenu();
|
||||||
popupMenu.applyComponentOrientation( getComponentOrientation() );
|
popupMenu.applyComponentOrientation( getComponentOrientation() );
|
||||||
popupMenu.show( invoker, 0, invoker.getHeight() );
|
popupMenu.show( invoker, 0, invoker.getHeight() );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void showScrollingPopupMenu(ActionEvent e) {
|
||||||
|
Component invoker = (Component) e.getSource();
|
||||||
|
JPopupMenu popupMenu = new JPopupMenu();
|
||||||
|
for( int i = 1; i <= 100; i++ ) {
|
||||||
|
popupMenu.add( "menu item " + i + (i % 5 == 0 ? " test" : "") )
|
||||||
|
.addActionListener( e2 -> System.out.println( ((JMenuItem)e2.getSource()).getText() ) );
|
||||||
|
}
|
||||||
|
popupMenu.applyComponentOrientation( getComponentOrientation() );
|
||||||
|
popupMenu.show( invoker, 0, invoker.getHeight() );
|
||||||
|
}
|
||||||
|
|
||||||
private void largerChanged() {
|
private void largerChanged() {
|
||||||
LargerMenuItem.useLargerSize = largerCheckBox.isSelected();
|
LargerMenuItem.useLargerSize = largerCheckBox.isSelected();
|
||||||
menuBar2.revalidate();
|
menuBar2.revalidate();
|
||||||
@@ -230,6 +241,7 @@ public class FlatMenusTest
|
|||||||
JRadioButtonMenuItem radioButtonMenuItem11 = new JRadioButtonMenuItem();
|
JRadioButtonMenuItem radioButtonMenuItem11 = new JRadioButtonMenuItem();
|
||||||
JLabel popupMenuLabel = new JLabel();
|
JLabel popupMenuLabel = new JLabel();
|
||||||
JButton showPopupMenuButton = new JButton();
|
JButton showPopupMenuButton = new JButton();
|
||||||
|
showScrollingPopupMenuButton = new JButton();
|
||||||
armedCheckBox = new JCheckBox();
|
armedCheckBox = new JCheckBox();
|
||||||
underlineCheckBox = new JCheckBox();
|
underlineCheckBox = new JCheckBox();
|
||||||
popupMenubackgroundCheckBox = new JCheckBox();
|
popupMenubackgroundCheckBox = new JCheckBox();
|
||||||
@@ -839,9 +851,14 @@ public class FlatMenusTest
|
|||||||
|
|
||||||
//---- showPopupMenuButton ----
|
//---- showPopupMenuButton ----
|
||||||
showPopupMenuButton.setText("show JPopupMenu");
|
showPopupMenuButton.setText("show JPopupMenu");
|
||||||
showPopupMenuButton.addActionListener(e -> showPopupMenuButtonActionPerformed(e));
|
showPopupMenuButton.addActionListener(e -> showPopupMenuButton(e));
|
||||||
add(showPopupMenuButton, "cell 1 2");
|
add(showPopupMenuButton, "cell 1 2");
|
||||||
|
|
||||||
|
//---- showScrollingPopupMenuButton ----
|
||||||
|
showScrollingPopupMenuButton.setText("show scrolling JPopupMenu");
|
||||||
|
showScrollingPopupMenuButton.addActionListener(e -> showScrollingPopupMenu(e));
|
||||||
|
add(showScrollingPopupMenuButton, "cell 2 2");
|
||||||
|
|
||||||
//---- armedCheckBox ----
|
//---- armedCheckBox ----
|
||||||
armedCheckBox.setText("armed");
|
armedCheckBox.setText("armed");
|
||||||
armedCheckBox.setMnemonic('A');
|
armedCheckBox.setMnemonic('A');
|
||||||
@@ -884,6 +901,7 @@ public class FlatMenusTest
|
|||||||
private JMenuBar menuBar2;
|
private JMenuBar menuBar2;
|
||||||
private JCheckBox largerCheckBox;
|
private JCheckBox largerCheckBox;
|
||||||
private JCheckBox accelCheckBox;
|
private JCheckBox accelCheckBox;
|
||||||
|
private JButton showScrollingPopupMenuButton;
|
||||||
private JCheckBox armedCheckBox;
|
private JCheckBox armedCheckBox;
|
||||||
private JCheckBox underlineCheckBox;
|
private JCheckBox underlineCheckBox;
|
||||||
private JCheckBox popupMenubackgroundCheckBox;
|
private JCheckBox popupMenubackgroundCheckBox;
|
||||||
|
|||||||
@@ -629,10 +629,20 @@ new FormModel {
|
|||||||
add( new FormComponent( "javax.swing.JButton" ) {
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
name: "showPopupMenuButton"
|
name: "showPopupMenuButton"
|
||||||
"text": "show JPopupMenu"
|
"text": "show JPopupMenu"
|
||||||
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButtonActionPerformed", true ) )
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showPopupMenuButton", true ) )
|
||||||
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
"value": "cell 1 2"
|
"value": "cell 1 2"
|
||||||
} )
|
} )
|
||||||
|
add( new FormComponent( "javax.swing.JButton" ) {
|
||||||
|
name: "showScrollingPopupMenuButton"
|
||||||
|
"text": "show scrolling JPopupMenu"
|
||||||
|
auxiliary() {
|
||||||
|
"JavaCodeGenerator.variableLocal": false
|
||||||
|
}
|
||||||
|
addEvent( new FormEvent( "java.awt.event.ActionListener", "actionPerformed", "showScrollingPopupMenu", true ) )
|
||||||
|
}, new FormLayoutConstraints( class net.miginfocom.layout.CC ) {
|
||||||
|
"value": "cell 2 2"
|
||||||
|
} )
|
||||||
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
add( new FormComponent( "javax.swing.JCheckBox" ) {
|
||||||
name: "armedCheckBox"
|
name: "armedCheckBox"
|
||||||
"text": "armed"
|
"text": "armed"
|
||||||
|
|||||||
@@ -276,6 +276,8 @@ Popup.dropShadowInsets = -6,6,6,6
|
|||||||
#---- PopupMenu ----
|
#---- PopupMenu ----
|
||||||
|
|
||||||
PopupMenu.borderColor = #00f
|
PopupMenu.borderColor = #00f
|
||||||
|
PopupMenu.scrollArrowColor = #00f
|
||||||
|
PopupMenu.hoverScrollArrowBackground = #0f0
|
||||||
|
|
||||||
|
|
||||||
#---- PopupMenuSeparator ----
|
#---- PopupMenuSeparator ----
|
||||||
|
|||||||
@@ -575,6 +575,8 @@ PopupMenu.borderInsets
|
|||||||
PopupMenu.consumeEventOnClose
|
PopupMenu.consumeEventOnClose
|
||||||
PopupMenu.font
|
PopupMenu.font
|
||||||
PopupMenu.foreground
|
PopupMenu.foreground
|
||||||
|
PopupMenu.hoverScrollArrowBackground
|
||||||
|
PopupMenu.scrollArrowColor
|
||||||
PopupMenu.selectedWindowInputMapBindings
|
PopupMenu.selectedWindowInputMapBindings
|
||||||
PopupMenu.selectedWindowInputMapBindings.RightToLeft
|
PopupMenu.selectedWindowInputMapBindings.RightToLeft
|
||||||
PopupMenuSeparator.height
|
PopupMenuSeparator.height
|
||||||
|
|||||||
Reference in New Issue
Block a user