mirror of
https://github.com/JFormDesigner/FlatLaf.git
synced 2026-02-11 06:27:13 -06:00
Styling: support List, Table and Tree
This commit is contained in:
@@ -20,10 +20,13 @@ import java.awt.Color;
|
||||
import java.awt.EventQueue;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicListUI;
|
||||
import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable;
|
||||
|
||||
/**
|
||||
* Provides the Flat LaF UI delegate for {@link javax.swing.JList}.
|
||||
@@ -64,15 +67,24 @@ import javax.swing.plaf.basic.BasicListUI;
|
||||
public class FlatListUI
|
||||
extends BasicListUI
|
||||
{
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatListUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
applyStyle( FlatStyleSupport.getStyle( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -93,6 +105,8 @@ public class FlatListUI
|
||||
selectionForeground = null;
|
||||
selectionInactiveBackground = null;
|
||||
selectionInactiveForeground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -116,6 +130,49 @@ public class FlatListUI
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PropertyChangeListener createPropertyChangeListener() {
|
||||
return FlatStyleSupport.createPropertyChangeListener( list, this::applyStyle,
|
||||
super.createPropertyChangeListener() );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected void applyStyle( Object style ) {
|
||||
Color oldSelectionBackground = selectionBackground;
|
||||
Color oldSelectionForeground = selectionForeground;
|
||||
Color oldSelectionInactiveBackground = selectionInactiveBackground;
|
||||
Color oldSelectionInactiveForeground = selectionInactiveForeground;
|
||||
|
||||
oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
// update selection background
|
||||
if( selectionBackground != oldSelectionBackground ) {
|
||||
Color selBg = list.getSelectionBackground();
|
||||
if( selBg == oldSelectionBackground )
|
||||
list.setSelectionBackground( selectionBackground );
|
||||
else if( selBg == oldSelectionInactiveBackground )
|
||||
list.setSelectionBackground( selectionInactiveBackground );
|
||||
}
|
||||
|
||||
// update selection foreground
|
||||
if( selectionForeground != oldSelectionForeground ) {
|
||||
Color selFg = list.getSelectionForeground();
|
||||
if( selFg == oldSelectionForeground )
|
||||
list.setSelectionForeground( selectionForeground );
|
||||
else if( selFg == oldSelectionInactiveForeground )
|
||||
list.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStyleSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
|
||||
@@ -25,6 +25,8 @@ import java.awt.Graphics2D;
|
||||
import java.awt.event.FocusEvent;
|
||||
import java.awt.event.FocusListener;
|
||||
import java.awt.geom.Rectangle2D;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JScrollPane;
|
||||
import javax.swing.JViewport;
|
||||
@@ -34,6 +36,8 @@ import javax.swing.UIManager;
|
||||
import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTableUI;
|
||||
import javax.swing.table.JTableHeader;
|
||||
import com.formdev.flatlaf.FlatClientProperties;
|
||||
import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable;
|
||||
import com.formdev.flatlaf.util.Graphics2DProxy;
|
||||
import com.formdev.flatlaf.util.SystemInfo;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
@@ -92,19 +96,29 @@ public class FlatTableUI
|
||||
protected boolean showVerticalLines;
|
||||
protected Dimension intercellSpacing;
|
||||
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
|
||||
private boolean oldShowHorizontalLines;
|
||||
private boolean oldShowVerticalLines;
|
||||
private Dimension oldIntercellSpacing;
|
||||
|
||||
private PropertyChangeListener propertyChangeListener;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTableUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
applyStyle( FlatStyleSupport.getStyle( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -148,6 +162,8 @@ public class FlatTableUI
|
||||
selectionInactiveBackground = null;
|
||||
selectionInactiveForeground = null;
|
||||
|
||||
oldStyleValues = null;
|
||||
|
||||
// restore old show horizontal/vertical lines (if not modified)
|
||||
if( !showHorizontalLines && oldShowHorizontalLines && !table.getShowHorizontalLines() )
|
||||
table.setShowHorizontalLines( true );
|
||||
@@ -159,6 +175,22 @@ public class FlatTableUI
|
||||
table.setIntercellSpacing( oldIntercellSpacing );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installListeners() {
|
||||
super.installListeners();
|
||||
|
||||
propertyChangeListener = FlatStyleSupport.createPropertyChangeListener( table, this::applyStyle, null );
|
||||
table.addPropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void uninstallListeners() {
|
||||
super.uninstallListeners();
|
||||
|
||||
table.removePropertyChangeListener( FlatClientProperties.STYLE, propertyChangeListener );
|
||||
propertyChangeListener = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FocusListener createFocusListener() {
|
||||
return new BasicTableUI.FocusHandler() {
|
||||
@@ -180,6 +212,43 @@ public class FlatTableUI
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected void applyStyle( Object style ) {
|
||||
Color oldSelectionBackground = selectionBackground;
|
||||
Color oldSelectionForeground = selectionForeground;
|
||||
Color oldSelectionInactiveBackground = selectionInactiveBackground;
|
||||
Color oldSelectionInactiveForeground = selectionInactiveForeground;
|
||||
|
||||
oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
|
||||
// update selection background
|
||||
if( selectionBackground != oldSelectionBackground ) {
|
||||
Color selBg = table.getSelectionBackground();
|
||||
if( selBg == oldSelectionBackground )
|
||||
table.setSelectionBackground( selectionBackground );
|
||||
else if( selBg == oldSelectionInactiveBackground )
|
||||
table.setSelectionBackground( selectionInactiveBackground );
|
||||
}
|
||||
|
||||
// update selection foreground
|
||||
if( selectionForeground != oldSelectionForeground ) {
|
||||
Color selFg = table.getSelectionForeground();
|
||||
if( selFg == oldSelectionForeground )
|
||||
table.setSelectionForeground( selectionForeground );
|
||||
else if( selFg == oldSelectionInactiveForeground )
|
||||
table.setSelectionForeground( selectionInactiveForeground );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStyleSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle selection colors from focused to inactive and vice versa.
|
||||
*
|
||||
|
||||
@@ -26,6 +26,7 @@ import java.awt.Rectangle;
|
||||
import java.awt.event.MouseEvent;
|
||||
import java.awt.event.MouseListener;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.util.Map;
|
||||
import javax.swing.CellRendererPane;
|
||||
import javax.swing.Icon;
|
||||
import javax.swing.JComponent;
|
||||
@@ -39,6 +40,7 @@ import javax.swing.plaf.ComponentUI;
|
||||
import javax.swing.plaf.basic.BasicTreeUI;
|
||||
import javax.swing.tree.DefaultTreeCellRenderer;
|
||||
import javax.swing.tree.TreePath;
|
||||
import com.formdev.flatlaf.ui.FlatStyleSupport.Styleable;
|
||||
import com.formdev.flatlaf.util.UIScale;
|
||||
|
||||
/**
|
||||
@@ -99,20 +101,31 @@ import com.formdev.flatlaf.util.UIScale;
|
||||
public class FlatTreeUI
|
||||
extends BasicTreeUI
|
||||
{
|
||||
protected Color selectionBackground;
|
||||
protected Color selectionForeground;
|
||||
protected Color selectionInactiveBackground;
|
||||
protected Color selectionInactiveForeground;
|
||||
protected Color selectionBorderColor;
|
||||
protected boolean wideSelection;
|
||||
protected boolean showCellFocusIndicator;
|
||||
@Styleable protected Color selectionBackground;
|
||||
@Styleable protected Color selectionForeground;
|
||||
@Styleable protected Color selectionInactiveBackground;
|
||||
@Styleable protected Color selectionInactiveForeground;
|
||||
@Styleable protected Color selectionBorderColor;
|
||||
@Styleable protected boolean wideSelection;
|
||||
@Styleable protected boolean showCellFocusIndicator;
|
||||
|
||||
private Color defaultCellNonSelectionBackground;
|
||||
private Color defaultSelectionBackground;
|
||||
private Color defaultSelectionForeground;
|
||||
private Color defaultSelectionBorderColor;
|
||||
private Map<String, Object> oldStyleValues;
|
||||
|
||||
public static ComponentUI createUI( JComponent c ) {
|
||||
return new FlatTreeUI();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void installUI( JComponent c ) {
|
||||
super.installUI( c );
|
||||
|
||||
applyStyle( FlatStyleSupport.getStyle( c ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void installDefaults() {
|
||||
super.installDefaults();
|
||||
@@ -128,6 +141,9 @@ public class FlatTreeUI
|
||||
showCellFocusIndicator = UIManager.getBoolean( "Tree.showCellFocusIndicator" );
|
||||
|
||||
defaultCellNonSelectionBackground = UIManager.getColor( "Tree.textBackground" );
|
||||
defaultSelectionBackground = selectionBackground;
|
||||
defaultSelectionForeground = selectionForeground;
|
||||
defaultSelectionBorderColor = selectionBorderColor;
|
||||
|
||||
// scale
|
||||
int rowHeight = FlatUIUtils.getUIInt( "Tree.rowHeight", 16 );
|
||||
@@ -150,6 +166,10 @@ public class FlatTreeUI
|
||||
selectionBorderColor = null;
|
||||
|
||||
defaultCellNonSelectionBackground = null;
|
||||
defaultSelectionBackground = null;
|
||||
defaultSelectionForeground = null;
|
||||
defaultSelectionBorderColor = null;
|
||||
oldStyleValues = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -216,6 +236,12 @@ public class FlatTreeUI
|
||||
repaintWideDropLocation( tree.getDropLocation() );
|
||||
}
|
||||
break;
|
||||
|
||||
case STYLE:
|
||||
applyStyle( e.getNewValue() );
|
||||
tree.revalidate();
|
||||
tree.repaint();
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -230,6 +256,20 @@ public class FlatTreeUI
|
||||
tree.repaint( 0, r.y, tree.getWidth(), r.height );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected void applyStyle( Object style ) {
|
||||
oldStyleValues = FlatStyleSupport.parseAndApply( oldStyleValues, style, this::applyStyleProperty );
|
||||
}
|
||||
|
||||
/**
|
||||
* @since TODO
|
||||
*/
|
||||
protected Object applyStyleProperty( String key, Object value ) {
|
||||
return FlatStyleSupport.applyToAnnotatedObject( this, key, value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as super.paintRow(), but supports wide selection and uses
|
||||
* inactive selection background/foreground if tree is not focused.
|
||||
@@ -259,35 +299,32 @@ public class FlatTreeUI
|
||||
Component rendererComponent = currentCellRenderer.getTreeCellRendererComponent( tree,
|
||||
path.getLastPathComponent(), isSelected, isExpanded, isLeaf, row, cellHasFocus );
|
||||
|
||||
// apply inactive selection background/foreground if tree is not focused
|
||||
// renderer background/foreground
|
||||
Color oldBackgroundSelectionColor = null;
|
||||
if( isSelected && !hasFocus && !isDropRow ) {
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBackgroundSelectionColor() == selectionBackground ) {
|
||||
oldBackgroundSelectionColor = renderer.getBackgroundSelectionColor();
|
||||
renderer.setBackgroundSelectionColor( selectionInactiveBackground );
|
||||
}
|
||||
} else {
|
||||
if( rendererComponent.getBackground() == selectionBackground )
|
||||
rendererComponent.setBackground( selectionInactiveBackground );
|
||||
}
|
||||
// apply inactive selection background/foreground if tree is not focused
|
||||
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionInactiveBackground );
|
||||
setRendererForeground( rendererComponent, selectionInactiveForeground );
|
||||
|
||||
if( rendererComponent.getForeground() == selectionForeground )
|
||||
rendererComponent.setForeground( selectionInactiveForeground );
|
||||
} else if( isSelected ) {
|
||||
// update background/foreground if set via style
|
||||
if( selectionBackground != defaultSelectionBackground )
|
||||
oldBackgroundSelectionColor = setRendererBackgroundSelectionColor( rendererComponent, selectionBackground );
|
||||
if( selectionForeground != defaultSelectionForeground )
|
||||
setRendererForeground( rendererComponent, selectionForeground );
|
||||
}
|
||||
|
||||
// remove focus selection border if exactly one item is selected
|
||||
// update focus selection border
|
||||
Color oldBorderSelectionColor = null;
|
||||
if( isSelected && hasFocus &&
|
||||
(!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) &&
|
||||
rendererComponent instanceof DefaultTreeCellRenderer )
|
||||
(!showCellFocusIndicator || tree.getMinSelectionRow() == tree.getMaxSelectionRow()) )
|
||||
{
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBorderSelectionColor() == selectionBorderColor ) {
|
||||
oldBorderSelectionColor = renderer.getBorderSelectionColor();
|
||||
renderer.setBorderSelectionColor( null );
|
||||
}
|
||||
// remove focus selection border if exactly one item is selected or if showCellFocusIndicator is false
|
||||
oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, null );
|
||||
|
||||
} else if( hasFocus && selectionBorderColor != defaultSelectionBorderColor ) {
|
||||
// update focus selection border if set via style
|
||||
oldBorderSelectionColor = setRendererBorderSelectionColor( rendererComponent, selectionBorderColor );
|
||||
}
|
||||
|
||||
// paint selection background
|
||||
@@ -343,6 +380,42 @@ public class FlatTreeUI
|
||||
((DefaultTreeCellRenderer)rendererComponent).setBorderSelectionColor( oldBorderSelectionColor );
|
||||
}
|
||||
|
||||
private Color setRendererBackgroundSelectionColor( Component rendererComponent, Color color ) {
|
||||
Color oldColor = null;
|
||||
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBackgroundSelectionColor() == defaultSelectionBackground ) {
|
||||
oldColor = renderer.getBackgroundSelectionColor();
|
||||
renderer.setBackgroundSelectionColor( color );
|
||||
}
|
||||
} else {
|
||||
if( rendererComponent.getBackground() == defaultSelectionBackground )
|
||||
rendererComponent.setBackground( color );
|
||||
}
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
private void setRendererForeground( Component rendererComponent, Color color ) {
|
||||
if( rendererComponent.getForeground() == defaultSelectionForeground )
|
||||
rendererComponent.setForeground( color );
|
||||
}
|
||||
|
||||
private Color setRendererBorderSelectionColor( Component rendererComponent, Color color ) {
|
||||
Color oldColor = null;
|
||||
|
||||
if( rendererComponent instanceof DefaultTreeCellRenderer ) {
|
||||
DefaultTreeCellRenderer renderer = (DefaultTreeCellRenderer) rendererComponent;
|
||||
if( renderer.getBorderSelectionColor() == defaultSelectionBorderColor ) {
|
||||
oldColor = renderer.getBorderSelectionColor();
|
||||
renderer.setBorderSelectionColor( color );
|
||||
}
|
||||
}
|
||||
|
||||
return oldColor;
|
||||
}
|
||||
|
||||
private void paintCellBackground( Graphics g, Component rendererComponent, Rectangle bounds ) {
|
||||
int xOffset = 0;
|
||||
int imageOffset = 0;
|
||||
|
||||
@@ -173,6 +173,17 @@ public class FlatStylingTests
|
||||
textField( ui );
|
||||
}
|
||||
|
||||
@Test
|
||||
void list() {
|
||||
FlatListUI ui = new FlatListUI();
|
||||
ui.installUI( new JList<>() );
|
||||
|
||||
ui.applyStyle( "selectionBackground: #fff" );
|
||||
ui.applyStyle( "selectionForeground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveBackground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveForeground: #fff" );
|
||||
}
|
||||
|
||||
@Test
|
||||
void menu() {
|
||||
UIManager.put( "Menu.arrowIcon", new FlatMenuArrowIcon() );
|
||||
@@ -461,6 +472,17 @@ public class FlatStylingTests
|
||||
ui.applyStyle( "gripGap: 2" );
|
||||
}
|
||||
|
||||
@Test
|
||||
void table() {
|
||||
FlatTableUI ui = new FlatTableUI();
|
||||
ui.installUI( new JTable() );
|
||||
|
||||
ui.applyStyle( "selectionBackground: #fff" );
|
||||
ui.applyStyle( "selectionForeground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveBackground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveForeground: #fff" );
|
||||
}
|
||||
|
||||
@Test
|
||||
void textArea() {
|
||||
FlatTextAreaUI ui = new FlatTextAreaUI();
|
||||
@@ -529,6 +551,20 @@ public class FlatStylingTests
|
||||
ui.applyStyle( b, "tab.focusBackground: #fff" );
|
||||
}
|
||||
|
||||
@Test
|
||||
void tree() {
|
||||
FlatTreeUI ui = new FlatTreeUI();
|
||||
ui.installUI( new JTree() );
|
||||
|
||||
ui.applyStyle( "selectionBackground: #fff" );
|
||||
ui.applyStyle( "selectionForeground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveBackground: #fff" );
|
||||
ui.applyStyle( "selectionInactiveForeground: #fff" );
|
||||
ui.applyStyle( "selectionBorderColor: #fff" );
|
||||
ui.applyStyle( "wideSelection: true" );
|
||||
ui.applyStyle( "showCellFocusIndicator: true" );
|
||||
}
|
||||
|
||||
//---- component borders --------------------------------------------------
|
||||
|
||||
private void flatButtonBorder( Consumer<String> applyStyle ) {
|
||||
|
||||
Reference in New Issue
Block a user