On Fri, 21 May 2021 04:30:28 GMT, Michael Strauß <mstra...@openjdk.org> wrote:

> This PR adds style themes as a first-class concept to OpenJFX. A style theme 
> is a collection of stylesheets and the logic that governs them. Style themes 
> can respond to OS notifications and update their stylesheets dynamically. 
> This PR also re-implements Caspian and Modena as style themes.
> 
> ### New APIs in `javafx.graphics`
> The new theming-related APIs in `javafx.graphics` provide a basic framework 
> to support application-wide style themes. Higher-level theming concepts (for 
> example, "dark mode" detection or accent coloring) are not a part of this 
> basic framework, because any API invented here might soon be out of date. 
> Implementations can build on top of this framework to add useful higher-level 
> features.
> #### 1. StyleTheme
> A style theme is an implementation of the `javafx.css.StyleTheme` interface:
> 
> /**
>  * {@code StyleTheme} is a collection of stylesheets that specify the 
> appearance of UI controls and other
>  * nodes in the application. Like a user-agent stylesheet, a {@code 
> StyleTheme} is implicitly used by all
>  * JavaFX nodes in the scene graph.
>  * <p>
>  * The list of stylesheets that comprise a {@code StyleTheme} can be modified 
> while the application is running,
>  * enabling applications to create dynamic themes that respond to changing 
> user preferences.
>  * <p>
>  * In the CSS subsystem, stylesheets that comprise a {@code StyleTheme} are 
> classified as
>  * {@link StyleOrigin#USER_AGENT} stylesheets, but have a higher precedence 
> in the CSS cascade
>  * than a stylesheet referenced by {@link 
> Application#userAgentStylesheetProperty()}.
>  */
> public interface StyleTheme {
>     /**
>      * Gets the list of stylesheet URLs that comprise this {@code StyleTheme}.
>      * <p>
>      * If the list of stylesheets that comprise this {@code StyleTheme} is 
> changed at runtime, this
>      * method must return an {@link ObservableList} to allow the CSS 
> subsystem to subscribe to list
>      * change notifications.
>      *
>      * @implNote Implementations of this method that return an {@link 
> ObservableList} are encouraged
>      *           to minimize the number of subsequent list change 
> notifications that are fired by the
>      *           list, as each change notification causes the CSS subsystem 
> to re-apply the referenced
>      *           stylesheets.
>      */
>     List<String> getStylesheets();
> }
> 
> 
> A new `styleTheme` property is added to `javafx.application.Application`, and 
> `userAgentStylesheet` is promoted to a JavaFX property (currently, this is 
> just a getter/setter pair):
> 
> public class Application {
>     ...
>     /**
>      * Specifies the user-agent stylesheet of the application.
>      * <p>
>      * A user-agent stylesheet is a global stylesheet that can be specified 
> in addition to a
>      * {@link StyleTheme} and that is implicitly used by all JavaFX nodes in 
> the scene graph.
>      * It can be used to provide default styling for UI controls and other 
> nodes.
>      * A user-agent stylesheets has the lowest precedence in the CSS cascade.
>      * <p>
>      * Before JavaFX 20, built-in themes were selectable using the special 
> user-agent stylesheet constants
>      * {@link #STYLESHEET_CASPIAN} and {@link #STYLESHEET_MODENA}. For 
> backwards compatibility, the meaning
>      * of these special constants is retained: setting the user-agent 
> stylesheet to either {@code STYLESHEET_CASPIAN}
>      * or {@code STYLESHEET_MODENA} will also set the value of the {@link 
> #styleThemeProperty() styleTheme}
>      * property to a new instance of the corresponding theme class.
>      * <p>
>      * Note: this property must only be modified on the JavaFX application 
> thread.
>      */
>     public static StringProperty userAgentStylesheetProperty();
>     public static String getUserAgentStylesheet();
>     public static void setUserAgentStylesheet(String url);
> 
>     /**
>      * Specifies the {@link StyleTheme} of the application.
>      * <p>
>      * {@code StyleTheme} is a collection of stylesheets that define the 
> appearance of the application.
>      * Like a user-agent stylesheet, a {@code StyleTheme} is implicitly used 
> by all JavaFX nodes in the
>      * scene graph.
>      * <p>
>      * Stylesheets that comprise a {@code StyleTheme} have a higher 
> precedence in the CSS cascade than a
>      * stylesheet referenced by the {@link #userAgentStylesheetProperty() 
> userAgentStylesheet} property.
>      * <p>
>      * Note: this property must only be modified on the JavaFX application 
> thread.
>      */
>     public static ObjectProperty<StyleTheme> styleThemeProperty();
>     public static StyleTheme getStyleTheme();
>     public static void setStyleTheme(StyleTheme theme);
>     ...
> }
> 
> 
> `styleTheme` and `userAgentStylesheet` are correlated to preserve backwards 
> compatibility: setting `userAgentStylesheet` to the magic values "CASPIAN" or 
> "MODENA" will implicitly set `styleTheme` to a new instance of the 
> `CaspianTheme` or `ModenaTheme` class. Aside from these magic values, 
> `userAgentStylesheet` can be set independently from `styleTheme`. In the CSS 
> cascade, `userAgentStylesheet` has a lower precedence than `styleTheme`.
> 
> #### 2. PlatformPreferences
> `javafx.application.PlatformPreferences` can be used to query UI-related 
> information about the current platform to allow theme implementations to 
> adapt to the operating system. The interface extends `Map` and adds several 
> useful methods, as well as the option to register a listener for change 
> notifications:
> 
> /**
>  * Contains UI preferences of the current platform.
>  * <p>
>  * {@code PlatformPreferences} implements {@link Map} to expose platform 
> preferences as key-value pairs.
>  * For convenience, {@link #getString}, {@link #getBoolean} and {@link 
> #getColor} are provided as typed
>  * alternatives to the untyped {@link #get} method.
>  * <p>
>  * The preferences that are reported by the platform may be dependent on the 
> operating system version.
>  * Applications should always test whether a preference is available, or use 
> the {@link #getString(String, String)},
>  * {@link #getBoolean(String, boolean)} or {@link #getColor(String, Color)} 
> overloads that accept a fallback
>  * value if the preference is not available.
>  */
> public interface PlatformPreferences extends Map<String, Object> {
>     String getString(String key);
>     String getString(String key, String fallbackValue);
> 
>     Boolean getBoolean(String key);
>     boolean getBoolean(String key, boolean fallbackValue);
> 
>     Color getColor(String key);
>     Color getColor(String key, Color fallbackValue);
> 
>     void addListener(PlatformPreferencesListener listener);
>     void removeListener(PlatformPreferencesListener listener);
> }
> 
> An instance of `PlatformPreferences` can be retrieved via 
> `Platform.getPreferences()`.
> 
> ### Usage
> In its simplest form, a style theme is just a static collection of 
> stylesheets:
> 
> Application.setStyleTheme(() -> List.of("stylesheet1.css", "stylesheet2.css");
> 
> A dynamic theme can be created by returning an instance of `ObservableList`:
> 
> public class MyCustomTheme implements StyleTheme {
>     private final ObservableList<String> stylesheets =
>         FXCollections.observableArrayList("colors-light.css", "controls.css");
> 
>     @Override
>     public List<String> getStylesheets() {
>         return stylesheets;
>     }
> 
>     public void setDarkMode(boolean enabled) {
>         stylesheets.set(0, enabled ? "colors-dark.css" : "colors-light.css");
>     }
> }
> 
> `CaspianTheme` and `ModenaTheme` can be extended by prepending or appending 
> additional stylesheets:
> 
> Application.setStyleTheme(new ModenaTheme() {
>     {
>         addFirst("stylesheet1.css");
>         addLast("stylesheet2.css");
>     }
> });

Are there any plans for this to be merged or is there any work remaining for 
this? I'd love to use this instead of what I'm currently doing which is 
accessing private API in JavaFX with `--add-exports`.

-------------

PR: https://git.openjdk.org/jfx/pull/511

Reply via email to