Styling: added styling properties that are likewise to client properties

(e.g. `buttonType: help` on `JButton` does the same as setting client property `JButton.buttonType` to `help`)
This commit is contained in:
Karl Tauber
2021-10-07 14:22:47 +02:00
parent 9636809b4d
commit 5ecf19ef4f
13 changed files with 169 additions and 28 deletions

View File

@@ -80,6 +80,11 @@ public class FlatBorder
@Styleable(dot=true) protected Color warningFocusedBorderColor = UIManager.getColor( "Component.warning.focusedBorderColor" );
@Styleable(dot=true) protected Color customBorderColor = UIManager.getColor( "Component.custom.borderColor" );
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected String outline;
/** @since 2 */ @Styleable protected Color outlineColor;
/** @since 2 */ @Styleable protected Color outlineFocusedColor;
/** @since 2 */
@Override
public Object applyStyleProperty( String key, Object value ) {
@@ -136,6 +141,17 @@ public class FlatBorder
return null;
Object outline = ((JComponent)c).getClientProperty( FlatClientProperties.OUTLINE );
if( outline == null )
outline = this.outline;
if( outline == null ) {
if( outlineColor != null && outlineFocusedColor != null )
outline = new Color[] { outlineFocusedColor, outlineColor };
else if( outlineColor != null )
outline = outlineColor;
else if( outlineFocusedColor != null )
outline = outlineFocusedColor;
}
if( outline instanceof String ) {
switch( (String) outline ) {
case FlatClientProperties.OUTLINE_ERROR:

View File

@@ -42,6 +42,7 @@ import javax.swing.JToggleButton;
import javax.swing.JToolBar;
import javax.swing.LookAndFeel;
import javax.swing.UIManager;
import javax.swing.plaf.ButtonUI;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.UIResource;
import javax.swing.plaf.basic.BasicButtonListener;
@@ -137,6 +138,11 @@ public class FlatButtonUI
@Styleable(dot=true) protected Color toolbarPressedBackground;
@Styleable(dot=true) protected Color toolbarSelectedBackground;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected String buttonType;
/** @since 2 */ @Styleable protected boolean squareSize;
/** @since 2 */ @Styleable protected int minimumHeight;
private Icon helpButtonIcon;
private Insets defaultMargin;
@@ -353,11 +359,11 @@ public class FlatButtonUI
if( !(c instanceof AbstractButton) )
return TYPE_OTHER;
Object value = ((AbstractButton)c).getClientProperty( BUTTON_TYPE );
if( !(value instanceof String) )
String value = getButtonTypeStr( (AbstractButton) c );
if( value == null )
return TYPE_OTHER;
switch( (String) value ) {
switch( value ) {
case BUTTON_TYPE_SQUARE: return TYPE_SQUARE;
case BUTTON_TYPE_ROUND_RECT: return TYPE_ROUND_RECT;
default: return TYPE_OTHER;
@@ -365,16 +371,27 @@ public class FlatButtonUI
}
static boolean isHelpButton( Component c ) {
return c instanceof JButton && clientPropertyEquals( (JButton) c, BUTTON_TYPE, BUTTON_TYPE_HELP );
return c instanceof JButton && BUTTON_TYPE_HELP.equals( getButtonTypeStr( (JButton) c ) );
}
static boolean isToolBarButton( Component c ) {
return c.getParent() instanceof JToolBar ||
(c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_TOOLBAR_BUTTON ));
(c instanceof AbstractButton && BUTTON_TYPE_TOOLBAR_BUTTON.equals( getButtonTypeStr( (AbstractButton) c ) ));
}
static boolean isBorderlessButton( Component c ) {
return c instanceof AbstractButton && clientPropertyEquals( (AbstractButton) c, BUTTON_TYPE, BUTTON_TYPE_BORDERLESS );
return c instanceof AbstractButton && BUTTON_TYPE_BORDERLESS.equals( getButtonTypeStr( (AbstractButton) c ) );
}
static String getButtonTypeStr( AbstractButton c ) {
// get from client property
Object value = c.getClientProperty( BUTTON_TYPE );
if( value instanceof String )
return (String) value;
// get from styling property
ButtonUI ui = c.getUI();
return (ui instanceof FlatButtonUI) ? ((FlatButtonUI)ui).buttonType : null;
}
@Override
@@ -582,7 +599,7 @@ public class FlatButtonUI
// make square or apply minimum width/height
boolean isIconOnlyOrSingleCharacter = isIconOnlyOrSingleCharacterButton( c );
if( clientPropertyBoolean( c, SQUARE_SIZE, false ) ) {
if( clientPropertyBoolean( c, SQUARE_SIZE, squareSize ) ) {
// make button square (increase width or height so that they are equal)
prefSize.width = prefSize.height = Math.max( prefSize.width, prefSize.height );
} else if( isIconOnlyOrSingleCharacter && ((AbstractButton)c).getIcon() == null ) {
@@ -594,7 +611,7 @@ public class FlatButtonUI
// apply minimum width/height
int fw = Math.round( FlatUIUtils.getBorderFocusWidth( c ) * 2 );
prefSize.width = Math.max( prefSize.width, scale( FlatUIUtils.minimumWidth( c, minimumWidth ) ) + fw );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, 0 ) ) + fw );
prefSize.height = Math.max( prefSize.height, scale( FlatUIUtils.minimumHeight( c, minimumHeight ) ) + fw );
}
return prefSize;

View File

@@ -68,6 +68,10 @@ public class FlatProgressBarUI
@Styleable protected Dimension horizontalSize;
@Styleable protected Dimension verticalSize;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected boolean largeHeight;
/** @since 2 */ @Styleable protected boolean square;
private PropertyChangeListener propertyChangeListener;
private Map<String, Object> oldStyleValues;
@@ -160,7 +164,7 @@ public class FlatProgressBarUI
public Dimension getPreferredSize( JComponent c ) {
Dimension size = super.getPreferredSize( c );
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, false ) ) {
if( progressBar.isStringPainted() || clientPropertyBoolean( c, PROGRESS_BAR_LARGE_HEIGHT, largeHeight ) ) {
// recalculate progress height/width to make it smaller
Insets insets = progressBar.getInsets();
FontMetrics fm = progressBar.getFontMetrics( progressBar.getFont() );
@@ -203,7 +207,7 @@ public class FlatProgressBarUI
return;
boolean horizontal = (progressBar.getOrientation() == JProgressBar.HORIZONTAL);
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, false )
int arc = clientPropertyBoolean( c, PROGRESS_BAR_SQUARE, square )
? 0
: Math.min( UIScale.scale( this.arc ), horizontal ? height : width );

View File

@@ -32,12 +32,17 @@ public class FlatRoundBorder
{
@Styleable protected int arc = UIManager.getInt( "Component.arc" );
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected Boolean roundRect;
@Override
protected int getArc( Component c ) {
if( isCellEditor( c ) )
return 0;
Boolean roundRect = FlatUIUtils.isRoundRect( c );
if( roundRect == null )
roundRect = this.roundRect;
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
}
}

View File

@@ -284,9 +284,17 @@ public class FlatScrollBarUI
}
protected boolean isShowButtons() {
// check client property on scroll bar
Object showButtons = scrollbar.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane )
showButtons = ((JScrollPane)scrollbar.getParent()).getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
if( showButtons == null && scrollbar.getParent() instanceof JScrollPane ) {
JScrollPane scrollPane = (JScrollPane) scrollbar.getParent();
// check client property on scroll pane
showButtons = scrollPane.getClientProperty( FlatClientProperties.SCROLL_BAR_SHOW_BUTTONS );
if( showButtons == null && scrollPane.getUI() instanceof FlatScrollPaneUI ) {
// check styling property on scroll pane
showButtons = ((FlatScrollPaneUI)scrollPane.getUI()).showButtons;
}
}
return (showButtons != null) ? Objects.equals( showButtons, true ) : this.showButtons;
}

View File

@@ -48,6 +48,7 @@ import javax.swing.UIManager;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicScrollPaneUI;
import com.formdev.flatlaf.FlatClientProperties;
import com.formdev.flatlaf.ui.FlatStylingSupport.Styleable;
import com.formdev.flatlaf.ui.FlatStylingSupport.StyleableUI;
import com.formdev.flatlaf.util.LoggingFacade;
@@ -72,6 +73,9 @@ public class FlatScrollPaneUI
extends BasicScrollPaneUI
implements StyleableUI
{
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected Boolean showButtons;
private Handler handler;
private Map<String, Object> oldStyleValues;

View File

@@ -157,6 +157,7 @@ import com.formdev.flatlaf.util.UIScale;
* @uiDefault TabbedPane.buttonPressedBackground Color
*
* @uiDefault TabbedPane.moreTabsButtonToolTipText String
* @uiDefault TabbedPane.tabCloseToolTipText String
*
* @author Karl Tauber
*/
@@ -221,6 +222,13 @@ public class FlatTabbedPaneUI
@Styleable protected Color buttonPressedBackground;
@Styleable protected String moreTabsButtonToolTipText;
/** @since 2 */ @Styleable protected String tabCloseToolTipText;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected boolean showContentSeparator = true;
/** @since 2 */ @Styleable protected boolean hideTabAreaWithOneTab;
/** @since 2 */ @Styleable protected boolean tabClosable;
/** @since 2 */ @Styleable protected int tabIconPlacement = LEADING;
protected JViewport tabViewport;
protected FlatWheelTabScroller wheelTabScroller;
@@ -331,6 +339,7 @@ public class FlatTabbedPaneUI
Locale l = tabPane.getLocale();
moreTabsButtonToolTipText = UIManager.getString( "TabbedPane.moreTabsButtonToolTipText", l );
tabCloseToolTipText = UIManager.getString( "TabbedPane.tabCloseToolTipText", l );
// scale
textIconGap = scale( textIconGapUnscaled );
@@ -616,6 +625,8 @@ public class FlatTabbedPaneUI
case "tabAreaAlignment": value = parseAlignment( (String) value, LEADING ); break;
case "tabAlignment": value = parseAlignment( (String) value, CENTER ); break;
case "tabWidthMode": value = parseTabWidthMode( (String) value ); break;
case "tabIconPlacement": value = parseTabIconPlacement( (String) value ); break;
}
} else {
Object oldValue = null;
@@ -728,7 +739,7 @@ public class FlatTabbedPaneUI
Insets tabInsets = getTabInsets( tabPlacement, tabIndex );
tabWidth = icon.getIconWidth() + tabInsets.left + tabInsets.right;
} else {
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING );
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement );
if( (iconPlacement == TOP || iconPlacement == BOTTOM) &&
tabPane.getTabComponentAt( tabIndex ) == null &&
(icon = getIconForTab( tabIndex )) != null )
@@ -771,7 +782,7 @@ public class FlatTabbedPaneUI
int tabHeight;
Icon icon;
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING );
int iconPlacement = clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement );
if( (iconPlacement == TOP || iconPlacement == BOTTOM) &&
tabPane.getTabComponentAt( tabIndex ) == null &&
(icon = getIconForTab( tabIndex )) != null )
@@ -879,7 +890,7 @@ public class FlatTabbedPaneUI
*/
@Override
protected Insets getContentBorderInsets( int tabPlacement ) {
if( hideTabArea() || contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
if( hideTabArea() || contentSeparatorHeight == 0 || !clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, showContentSeparator ) )
return new Insets( 0, 0, 0, 0 );
boolean hasFullBorder = clientPropertyBoolean( tabPane, TABBED_PANE_HAS_FULL_BORDER, this.hasFullBorder );
@@ -1135,7 +1146,7 @@ public class FlatTabbedPaneUI
protected void paintContentBorder( Graphics g, int tabPlacement, int selectedIndex ) {
if( tabPane.getTabCount() <= 0 ||
contentSeparatorHeight == 0 ||
!clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, true ) )
!clientPropertyBoolean( tabPane, TABBED_PANE_SHOW_CONTENT_SEPARATOR, showContentSeparator ) )
return;
Insets insets = tabPane.getInsets();
@@ -1226,7 +1237,7 @@ public class FlatTabbedPaneUI
// icon placement
int verticalTextPosition;
int horizontalTextPosition;
switch( clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, LEADING ) ) {
switch( clientPropertyInt( tabPane, TABBED_PANE_TAB_ICON_PLACEMENT, tabIconPlacement ) ) {
default:
case LEADING: verticalTextPosition = CENTER; horizontalTextPosition = TRAILING; break;
case TRAILING: verticalTextPosition = CENTER; horizontalTextPosition = LEADING; break;
@@ -1307,8 +1318,11 @@ public class FlatTabbedPaneUI
}
protected boolean isTabClosable( int tabIndex ) {
if( tabIndex < 0 )
return false;
Object value = getTabClientProperty( tabIndex, TABBED_PANE_TAB_CLOSABLE );
return (value instanceof Boolean) ? (boolean) value : false;
return (value instanceof Boolean) ? (boolean) value : tabClosable;
}
@SuppressWarnings( { "unchecked" } )
@@ -1382,7 +1396,7 @@ public class FlatTabbedPaneUI
return tabPane.getTabCount() == 1 &&
leadingComponent == null &&
trailingComponent == null &&
clientPropertyBoolean( tabPane, TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, false );
clientPropertyBoolean( tabPane, TABBED_PANE_HIDE_TAB_AREA_WITH_ONE_TAB, hideTabAreaWithOneTab );
}
protected int getTabsPopupPolicy() {
@@ -1496,6 +1510,19 @@ public class FlatTabbedPaneUI
}
}
protected static int parseTabIconPlacement( String str ) {
if( str == null )
return LEADING;
switch( str ) {
default:
case "leading": return LEADING;
case "trailing": return TRAILING;
case "top": return TOP;
case "bottom": return BOTTOM;
}
}
private void runWithOriginalLayoutManager( Runnable runnable ) {
LayoutManager layout = tabPane.getLayout();
if( layout instanceof FlatTabbedPaneScrollLayout ) {
@@ -2347,6 +2374,8 @@ public class FlatTabbedPaneUI
// update tooltip
if( tabIndex >= 0 && hitClose ) {
Object closeTip = getTabClientProperty( tabIndex, TABBED_PANE_TAB_CLOSE_TOOLTIPTEXT );
if( closeTip == null )
closeTip = tabCloseToolTipText;
if( closeTip instanceof String )
setCloseToolTip( tabIndex, (String) closeTip );
else

View File

@@ -32,12 +32,17 @@ public class FlatTextBorder
{
@Styleable protected int arc = UIManager.getInt( "TextComponent.arc" );
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected Boolean roundRect;
@Override
protected int getArc( Component c ) {
if( isCellEditor( c ) )
return 0;
Boolean roundRect = FlatUIUtils.isRoundRect( c );
if( roundRect == null )
roundRect = this.roundRect;
return roundRect != null ? (roundRect ? Short.MAX_VALUE : 0) : arc;
}
}

View File

@@ -173,7 +173,7 @@ public class FlatToggleButtonUI
}
static boolean isTabButton( Component c ) {
return c instanceof JToggleButton && clientPropertyEquals( (JToggleButton) c, BUTTON_TYPE, BUTTON_TYPE_TAB );
return c instanceof JToggleButton && BUTTON_TYPE_TAB.equals( getButtonTypeStr( (JToggleButton) c ) );
}
@Override

View File

@@ -143,6 +143,9 @@ public class FlatTreeUI
@Styleable(dot=true) public Color iconClosedColor;
@Styleable(dot=true) public Color iconOpenColor;
// only used via styling (not in UI defaults, but has likewise client properties)
/** @since 2 */ @Styleable protected boolean paintSelection = true;
private Color defaultCellNonSelectionBackground;
private Color defaultSelectionBackground;
private Color defaultSelectionForeground;
@@ -535,6 +538,6 @@ public class FlatTreeUI
}
protected boolean isPaintSelection() {
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, true );
return clientPropertyBoolean( tree, TREE_PAINT_SELECTION, paintSelection );
}
}

View File

@@ -118,7 +118,11 @@ public class TestFlatStyleableInfo
"toolbar.spacingInsets", Insets.class,
"toolbar.hoverBackground", Color.class,
"toolbar.pressedBackground", Color.class,
"toolbar.selectedBackground", Color.class
"toolbar.selectedBackground", Color.class,
"buttonType", String.class,
"squareSize", boolean.class,
"minimumHeight", int.class
);
// border
@@ -432,7 +436,10 @@ public class TestFlatStyleableInfo
Map<String, Class<?>> expected = expectedMap(
"arc", int.class,
"horizontalSize", Dimension.class,
"verticalSize", Dimension.class
"verticalSize", Dimension.class,
"largeHeight", boolean.class,
"square", boolean.class
);
assertMapEquals( expected, ui.getStyleableInfos( c ) );
@@ -535,7 +542,9 @@ public class TestFlatStyleableInfo
JScrollPane c = new JScrollPane();
FlatScrollPaneUI ui = (FlatScrollPaneUI) c.getUI();
Map<String, Class<?>> expected = new LinkedHashMap<>();
Map<String, Class<?>> expected = expectedMap(
"showButtons", Boolean.class
);
// border
flatBorder( expected );
@@ -684,6 +693,12 @@ public class TestFlatStyleableInfo
"buttonPressedBackground", Color.class,
"moreTabsButtonToolTipText", String.class,
"tabCloseToolTipText", String.class,
"showContentSeparator", boolean.class,
"hideTabAreaWithOneTab", boolean.class,
"tabClosable", boolean.class,
"tabIconPlacement", int.class,
// FlatTabbedPaneCloseIcon
"closeSize", Dimension.class,
@@ -866,6 +881,8 @@ public class TestFlatStyleableInfo
"wideSelection", boolean.class,
"showCellFocusIndicator", boolean.class,
"paintSelection", boolean.class,
// icons
"icon.arrowType", String.class,
"icon.expandedColor", Color.class,
@@ -908,7 +925,9 @@ public class TestFlatStyleableInfo
flatBorder( expected );
expectedMap( expected,
"arc", int.class
"arc", int.class,
"roundRect", Boolean.class
);
}
@@ -916,7 +935,9 @@ public class TestFlatStyleableInfo
flatBorder( expected );
expectedMap( expected,
"arc", int.class
"arc", int.class,
"roundRect", Boolean.class
);
}
@@ -934,7 +955,11 @@ public class TestFlatStyleableInfo
"error.focusedBorderColor", Color.class,
"warning.borderColor", Color.class,
"warning.focusedBorderColor", Color.class,
"custom.borderColor", Color.class
"custom.borderColor", Color.class,
"outline", String.class,
"outlineColor", Color.class,
"outlineFocusedColor", Color.class
);
}

View File

@@ -232,6 +232,10 @@ public class TestFlatStyling
ui.applyStyle( b, "toolbar.pressedBackground: #fff" );
ui.applyStyle( b, "toolbar.selectedBackground: #fff" );
ui.applyStyle( b, "buttonType: help" );
ui.applyStyle( b, "squareSize: true" );
ui.applyStyle( b, "minimumHeight: 100" );
// border
flatButtonBorder( style -> ui.applyStyle( b, style ) );
@@ -546,6 +550,9 @@ public class TestFlatStyling
ui.applyStyle( "horizontalSize: 100,12" );
ui.applyStyle( "verticalSize: 12,100" );
ui.applyStyle( "largeHeight: true" );
ui.applyStyle( "square: true" );
// JComponent properties
ui.applyStyle( "background: #fff" );
ui.applyStyle( "foreground: #fff" );
@@ -654,6 +661,8 @@ public class TestFlatStyling
// border
flatBorder( style -> ui.applyStyle( style ) );
ui.applyStyle( "showButtons: true" );
// JComponent properties
ui.applyStyle( "background: #fff" );
ui.applyStyle( "foreground: #fff" );
@@ -823,6 +832,12 @@ public class TestFlatStyling
ui.applyStyle( "buttonPressedBackground: #fff" );
ui.applyStyle( "moreTabsButtonToolTipText: Gimme more" );
ui.applyStyle( "tabCloseToolTipText: Close me" );
ui.applyStyle( "showContentSeparator: true" );
ui.applyStyle( "hideTabAreaWithOneTab: true" );
ui.applyStyle( "tabClosable: true" );
ui.applyStyle( "tabIconPlacement: top" );
// FlatTabbedPaneCloseIcon
ui.applyStyle( "closeSize: 16,16" );
@@ -1034,6 +1049,8 @@ public class TestFlatStyling
ui.applyStyle( "wideSelection: true" );
ui.applyStyle( "showCellFocusIndicator: true" );
ui.applyStyle( "paintSelection: false" );
// icons
ui.applyStyle( "icon.arrowType: chevron" );
ui.applyStyle( "icon.expandedColor: #fff" );
@@ -1083,12 +1100,16 @@ public class TestFlatStyling
flatBorder( applyStyle );
applyStyle.accept( "arc: 6" );
applyStyle.accept( "roundRect: true" );
}
private void flatTextBorder( Consumer<String> applyStyle ) {
flatBorder( applyStyle );
applyStyle.accept( "arc: 6" );
applyStyle.accept( "roundRect: true" );
}
private void flatBorder( Consumer<String> applyStyle ) {
@@ -1105,6 +1126,10 @@ public class TestFlatStyling
applyStyle.accept( "warning.borderColor: #fff" );
applyStyle.accept( "warning.focusedBorderColor: #fff" );
applyStyle.accept( "custom.borderColor: desaturate(#f00,50%,relative derived noAutoInverse)" );
applyStyle.accept( "outline: error" );
applyStyle.accept( "outlineColor: #fff" );
applyStyle.accept( "outlineFocusedColor: #fff" );
}
//---- borders ------------------------------------------------------------

View File

@@ -82,7 +82,7 @@ class FlatThemePreviewButtons
continue;
AbstractButton b = (AbstractButton) c;
if( !Objects.equals( b.getClientProperty( BUTTON_TYPE ), BUTTON_TYPE_HELP ) )
if( !BUTTON_TYPE_HELP.equals( b.getClientProperty( BUTTON_TYPE ) ) )
b.putClientProperty( BUTTON_TYPE, buttonType );
}