Michael:

Thank you for clarifications.

Let me backtrack a bit and ask a very specific question: what is the problem 
(or problems) you are trying to solve?

I would like to understand if the problem exists (more on that below), does a 
workaround exists or it is currently impossible to solve the problem using the 
existing APIs, and relative importance of the problem.

For example, when speaking about themes and missing APIs, I would say that

1. Large scale stylesheet change at run time (i.e. going from Modena to 
Caspian), or listing available stylesheets is probably not high on the list of 
desired features.

2. What is high on the list of desired features is ability to select color 
theme (light/dark/hiContrast) at run time, possibly automatically by picking up 
the OS preference is it exists.  Ideally, the color scheme would also pick up 
other, user-defined colors from the OS and integrate this into the current 
stylesheet (Modena).  Right now there is no public API to support that, as far 
as I know, and no support in Modena.css

3. Another feature high on my wish list is ability to generate and apply CSS 
changes at run time.  For example, reacting to the user selecting larger or 
smaller font, more spacious or compact style, and so on.  Theoretically, this 
is possible by generating a new stylesheet (it has to be a heavily modified 
standard stylesheet) and feeding that to the Application using data: URL 
protocol.

4. Since you do mention javafx.application.Platform.Preferences in your PR, I 
fully agree that it is a good idea to expose platform and preferences, 
especially since there are no public APIs for that.  This probably deserves its 
own PR instead of being a part of #2.  But the main value, as I see it (and I 
could be wrong) is that the platform preferences are incorporated into the main 
stylesheet.

Perhaps I totally misunderstand the goal of your PR #511, so could you please 
describe the problem this PR is trying to solve?

Thank you
-andy


From: Michael Strauß <michaelstr...@gmail.com>
Date: Friday, 2023/01/13 at 16:14
To: Andy Goryachev <andy.goryac...@oracle.com>
Cc: openjfx-dev <openjfx-dev@openjdk.org>
Subject: [External] : Re: Style themes API
Hi Andy!

please see my comments below:


On Fri, Jan 13, 2023 at 6:31 PM Andy Goryachev
<andy.goryac...@oracle.com> wrote:
>
> #1 Theme
> I wonder if we need to clarify what we mean by the word "theme" in the 
> context of a javaFX application.  Are we talking about colors, fonts, 
> spacing, graphics, or all of the above?  Would a completely different 
> stylesheet like Caspian or Modena be considered a separate theme, or would we 
> rather have a way to modify the standard stylesheet by adding ability to 
> redefine the different aspects such as colors and spacing without making 
> structural changes to the stylesheet itself?


The proposed documentation defines it as: "StyleTheme is a collection
of stylesheets that specify the appearance of UI controls and other
nodes in the application."
So we're talking about everything that can be set via CSS. Caspian and
Modena are two separate themes, but they can be extended by prepending
or appending custom stylesheets.
One way to achieve this is by subclassing the
`javafx.scene.control.theme.CaspianTheme` or
`javafx.scene.control.theme.ModenaTheme` class and using the
`addFirst` and `addLast` methods to add custom stylesheets:

    public class MyTheme extends ModenaTheme {
        public MyTheme() {
            addLast("myColors.css");
        }
    }

Note that `addFirst` and `addLast` are two methods that are specific
to the implementation of Caspian and Modena, these are not
general-purpose methods available for all `StyleTheme`
implementations.
Since both themes are implemented using a single CSS file, there is no
way to fundamentally change the structure of the theme.

However, other theme implementations may offer a different API that
may allow changing the stylesheets that comprise the theme in a
structural way.
For example, a theme implementation might use one stylesheet per
control instead of a single stylesheet for the entire theme, and offer
a way to override or modify individual control stylesheets.



> #2 Colors
> When talking about colors specifically, the main requirements might be:
> change the base colors used by the standard stylesheets, or just Modena
> derived colors might use different logic for light and dark themes
> have ability to select a group of colors, or "color themes" - such as Light, 
> Dark, Solarized, High Contrast, etc.
> pick up the user-defined color preferences from the platform
> track the user-defined color preferences at run time
>
> I think most of these (except for platform colors) can be implemented 
> currently at the application level (that is, without introducing new APIs) 
> simply by loading a stylesheet that redefines base colors (e.g. -fx-base), 
> however, it gets complicated when we start deriving colors.  For example, the 
> use of derive() will need to change in order to obtain an esthetically 
> pleasing colors in the dark theme.


All of these things (except as you say, querying and tracking changes
of platform colors) can be currently implemented by programmatically
composing a monolithic user-agent stylesheet. The advantage of this
approach is that you can use any kind of logic, not just what's
supported by JavaFX CSS functions like derive().



> #3 Platform Colors
> Thank you for researching the preferences provided by the three different 
> platforms.  I wonder if it would make sense to extract that into a separate 
> PR, perhaps as an implementation detail, to be further refined as a part of 
> Desktop replacement for JavaFX?  And, if we are talking about exposing 
> platform colors via APIs, do we want to make it as a part of one giant 
> facility like java.swt.Desktop equivalent, or via individual methods in 
> Platform, or perhaps some other lookup scheme that allows for future 
> extension?
> Do you think it could be possible to describe the individual platform 
> properties (what is Windows.UIColor.AccentDark3?), and possibly attempt to 
> map platform-specific properties to a platform-independent set of properties 
> which represent a union of the three major platforms?
> There is one more complication - constant changes in the platform design 
> language.  Ideally, any new APIs would support gradual evolution of the 
> platform by, for example, providing methods to query whether particular item 
> is available or not.


The platform preferences API is an integral part of the value
proposition of style themes. JavaFX has long included a very limited
form of this (not as public API), built specifically to support
Windows high contrast themes.
I don't think that it makes sense to separate the platform preferences
API from style themes, because
a) the existing support for Windows high contrast themes must continue
to work with the new first-class theme implementations, which requires
new code that will instantly be rendered irrelevant when the platform
preferences API arrives. Not a good investment of our time.
b) leveraging the platform preferences API to support platform
dark/light modes will probably be the first thing that theme
implementers will want to do anyway.

Note that the proposed platform preferences API exposes all kinds of
properties as mappings of key-value pairs. The API reports properties
that are available on the current platform, which might depend on any
number of factors, including the operating system version.
For example, all of the Windows.UIColor properties are not available
on Windows systems running earlier versions than Windows 10 Build
10240. Similarly, properties might be deprecated or removed in future
OS versions.
That's why the documentation of `Platform.Preferences` explains:

    * 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.

Another approach to expose platform preferences would be to have Java
classes that mirror platform APIs (for example, something like a
javafx.application.windows.UIColor class).
But I don't see any clear advantage of that, and it's probably not a
good idea to promote platform implementation details to
front-and-center APIs.

One might ask why we should expose platform preferences in JavaFX at
all. Applications could just query the relevant properties themselves.
But that's easier said than done: many platform preferences can only
be queried from native code, and tracking changes of these properties
often requires a level of integration into windowing toolkits (for
example, event loops) that is hard or impossible to achieve in
application code.

Regarding documentation: "Windows.UIColor.AccentDark3" is whatever
Microsoft says it is. I don't think we should interpret what this
means, but we could point users to a relevant Microsoft documentation.
What is the policy of linking to external resources in Javadoc
comments?

Regarding platform-independent properties: Yes, that would be very
useful, but I don't think it should be a core part of JavaFX. As you
already noted, platforms constantly evolve and design trends come and
go. We shouldn't aim for this moving target. Third-party libraries can
build on top of the platform preferences API to provide developers
with platform-independent APIs for common OS features. The question
"what is a meaningful set of common properties" might also have
different answers depending on what theme implementers want to
achieve.



> #4 Spacing and Font Size
> A lot of modern UIs introduced the concept of density (for example, in MS 
> Outlook, Preferences -> General -> Density preference), by making spacing 
> between UI elements larger or smaller (at run time).  Similarly, the font 
> size can be made larger or smaller (Ctrl-+ / Ctrl-- in Firefox).  The font 
> size change affects "em" units, perhaps we need a parallel construct like 
> "space-em" units that is applied to spacing?  Even then, we might need 
> special logic to switch from pixels to fractions of "space-em" for large 
> scales.
>
> How can we enable this functionality, ideally without making drastic changes 
> to the base stylesheet?  Is it even possible?


Some platforms have a text scale preference that can be different from
general UI scale. For example, in Windows this is the
UISettings.TextScaleFactor preference, which is currently not reported
in the style themes PR. I think this should be added to the list of
reported preferences.
That being said, I don't plan on making any changes at all to the
existing themes (Caspian and Modena). These themes are implemented as
monoliths, and it would be a lot of work to refactor them into
reusable, composable parts.

Of course, new theme implementations might support multiple densities,
for example by programmatically composing the stylesheets.



> #5 Programmatic Stylesheet Generation
> Somewhere in this discussion we might also consider adding a possibility of 
> generating a stylesheet programmatically, ideally in a type-safe manner, 
> compatible with auto-completion.  jfx17 (I think) added a way to load a 
> stylesheet data url, so it is much easier now, but I think a better way would 
> be to skip the encoding/decoding step and just generate the stylesheet object 
> directly.
> Perhaps the ideal scenario, one that makes it possible to adjust every aspect 
> of the application styling, is to generate the complete stylesheet at run 
> time, and possibly passing it to JavaFx in a binary form that does not 
> require parsing.
> I understand this is totally separate issue which will no doubt require its 
> own discussion.


That's an interesting option, but it's not a good fit with the
existing stylesheet API, which generally expects a String with either
an inline data-URI or a link to a CSS file.
There's a bit of design space with the new StyleTheme interface, which
is currently defined as:

    interface StyleTheme {
        List<String> getStylesheets();
    }

If the getStylesheets() method returned a List<Object>, we could also
accept user-provided Stylesheet objects (in addition to Strings). What
do you think?

Reply via email to