Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Styling individual components #341

Merged
merged 65 commits into from
Sep 15, 2021
Merged

Styling individual components #341

merged 65 commits into from
Sep 15, 2021

Conversation

DevCharly
Copy link
Collaborator

@DevCharly DevCharly commented Jun 15, 2021

Currently most FlatLaf styling capabilities are limited to change all components at once.
This PR is an attempt to better support styling individual components.

Some "styling" properties are available via Swing API (background, foreground, border, font, etc) for individual components,
but many FlatLaf UI defaults can be defined only for all components in FlatLaf properties files (https://www.formdev.com/flatlaf/properties-files/) or with UIManager.put(key, value).

The idea is to use a single client property to modify multiple style properties of a component.
This is similar to what can be done in JavaFX with Node.setStyle(String style).

CSS syntax

Therefore I've chosen CSS syntax: key1: value1; key2: value2; ...

mySlider.putClientProperty( "FlatLaf.style", "trackWidth: 2" );

The key is the same as used in UI defaults, but without component type prefix.
E.g. for UI default Slider.thumbSize use key thumbSize.
The syntax of the value is the same as used in FlatLaf properties files
(https://www.formdev.com/flatlaf/properties-files/),
but some features are not supported (e.g. variables).

Color functions and references are supported. E.g::

mySlider.putClientProperty( "FlatLaf.style", "thumbColor: lighten(#f00,20%)" );
mySlider.putClientProperty( "FlatLaf.style", "trackColor: lighten($TextField.foreground,20%)" );
mySlider.putClientProperty( "FlatLaf.style", "tickColor: $TextField.foreground" );

$TextField.foreground is replaced with the value returned by UIManager.get( "$TextField.foreground" ).

Map

Instead of the CSS string, it is also possible to assign a java.util.Map to the client property.
In this case the values are not parsed from a string. They must be binary:

Map<String, Object> map = new HashMap<>();
map.put( "trackWidth", 2 );
map.put( "thumbColor", new Color( 0xf0f0f0 ) );
mySlider.putClientProperty( "FlatLaf.style", map );

Supported components

  • JButton and JToggleButton
  • JCheckBox and JRadioButton (including icon)
  • JComboBox and JSpinner
  • JInternalFrame
  • JLabel
  • JList, JTable, JTableHeader and JTree
  • JMenuBar, JMenu, JMenuItem, JCheckBoxMenuItem, JRadioButtonMenuItem and JPopupMenu
  • JProgressBar
  • JSeparator and JPopupMenu.Separator
  • JScrollPane and JScrollBar
  • JSlider
  • JSplitPane
  • JTabbedPane
  • JTextField, JFormattedTextField and JPasswordField
  • JTextArea, JTextPane and JEditorPane
  • JToolBar and JToolBar.Separator

Possible "styles"

For possible "styles" take a look at: https://www.formdev.com/flatlaf/components/
(or https://github.com/JFormDesigner/FlatLaf/blob/main/flatlaf-core/src/test/java/com/formdev/flatlaf/ui/TestFlatStyling.java)

It is also possible to "style" any JavaBean property (that has public getter and setter methods).
For CSS strings this works only for property types that can be parsed from a string.

mySlider.putClientProperty( "FlatLaf.style", "maximum: 200; value: 100; majorTickSpacing: 50; paintLabels: true" );

Platform specific and light/dark theme specific styles

If a key is preceded by [win], [mac] or [linux], then its value is only used on the given platform.
If a key is preceded by [light] or [dark], then its value is only used if the current FlatLaf theme is light or dark.

mySlider.putClientProperty( "FlatLaf.style",
    "[mac]trackWidth: 4; [light]thumbColor: #000; [dark]thumbColor: #fff" );

This is also supported in FlatLaf properties files:
https://www.formdev.com/flatlaf/properties-files/#platform_specific

JSlider examples

Windows 10 style slider:

mySlider.putClientProperty( "FlatLaf.style", "thumbSize: 8,24" );

image

macOS style slider:

mySlider.putClientProperty( "FlatLaf.style", "thumbColor: #fff; thumbBorderColor: #c4c4c4" );

image

Thicker focus indicator (as in material design):

mySlider.putClientProperty( "FlatLaf.style", "focusWidth: 8" );

image

CC @Chrriis (issue #117); @orange451 (issue #340)

…y `JComponent.style` and CSS syntax

only for JSlider (at the moment)

e.g. `mySlider.putClientProperty( "JComponent.style", "trackValueColor: #00f; trackColor: #f00; thumbColor: #0f0; trackWidth: 6; thumbSize: 40,20; focusWidth: 20" );`

(issues #117 and #340)
e.g. `mySlider.putClientProperty( "JComponent.style", "thumbColor: $TextField.background; thumbBorderColor: $Component.borderColor" );`
e.g. `mySlider.putClientProperty( "JComponent.style", Collections.singletonMap( "thumbSize", new Dimension( 8, 24 ) ) );`
Copy link
Contributor

@Chrriis Chrriis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked at the code and this is good!
I would only suggest one change: I think all FlatLaf-specific client properties should indicate so: instead of "JComponent.style", I think it would be better to use "FlatLaf.style".

@Chrriis
Copy link
Contributor

Chrriis commented Jun 16, 2021

Something crossed my mind: how would you defined more complex objects, e.g. an icon?
One possibility would be to use indirections:

myTree.putClientProperty("FlatLaf.style", "expandedIcon: chrriis.expandedIcon; collapsedIcon: chrriis.collapsedIcon");
myTree.putClientProperty("chrriis.expandedIcon", myExpandedIcon);
myTree.putClientProperty("chrriis.collapsedIcon", myCollapsedIcon);

@DevCharly
Copy link
Collaborator Author

I think all FlatLaf-specific client properties should indicate so: instead of "JComponent.style", I think it would be better to use "FlatLaf.style".

Good idea. I'll change it.

"JComponent.style" is very FlatLaf specific and it is unlikely that other LaFs will (or can) implement it in a compatible way.

I will not change the other client properties for various reasons

  • compatibility with current and older FlatLaf versions
  • some client properties are compatible to other Lafs e.g. Aqua, Nimbus and IntelliJ LaFs (relevant for IDEA plugins)

@DevCharly
Copy link
Collaborator Author

Something crossed my mind: how would you defined more complex objects, e.g. an icon?

Good question.

In the meantime it is possible to pass a Map<String, Object> to the client property (instead of a CSS string).
Then following is possible:

Map<String, Object> map = new HashMap<>();
map.put( "expandedIcon", myExpandedIcon );
map.put( "collapsedIcon", myCollapsedIcon );
myTree.putClientProperty( "FlatLaf.style", map );

References to UI default values are already possible in CSS string syntax.
E.g. following invokes UIManager.get( "MySlider.someColor" ) to get the value for thumbColor.

mySlider.putClientProperty( "JComponent.style", "thumbColor: $MySlider.someColor" );

Maybe it makes sense to first look into client properties and then into UIManager...

@Chrriis
Copy link
Contributor

Chrriis commented Jun 19, 2021

In the meantime it is possible to pass a Map<String, Object> to the client property (instead of a CSS string).

I will definitely use a map instead of the CSS syntax for my use cases!

One thing I am not sure about is that I cannot simply copy/paste and tweak the definitions from UIManager default values to the client properties map because the keys are different: I have to remove all the prefixes. That being said, styling a specific component is for special cases, so having to remove the prefixes is not a big deal.

@DevCharly DevCharly linked an issue Aug 1, 2021 that may be closed by this pull request
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatButtonUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatInternalFrameUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTextFieldUI.java
# Conflicts:
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatListUI.java
#	flatlaf-core/src/main/java/com/formdev/flatlaf/ui/FlatTableUI.java
- support references in color functions
- added test for using color functions in styling
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Different theme same component
3 participants