RFR: 8263095: Provide a way for a custom control to indicate that its userAgentStyleSheet has changed
Kevin Rushforth
kevin.rushforth at oracle.com
Fri Jul 16 22:36:39 UTC 2021
OK, I think you've answered my first and third questions. The broader
question then is whether this fills a general need, and if so, is
allowing for a dynamic user agent style on a Control the best way to
provide this feature? I'd like to hear from some of the other developers
on this list.
As for the second question, I don't think the API you propose for
dynamic user agent style-sheets is feasible in a way that maintains
compatibility. The current API model is that the control itself provides
its userAgentStylesheet by overriding the get method, returning a String
specific to that control (or possibly a specific instance of that
control, if the designer of that control wants to add such logic for
some reason). You can't compatibly turn this API into a standard
property. Our properties have final set/get/property methods for a
reason. Namely, to satisfy the invariant that calling the set or get
method is identical to calling the property method (this is key to
allowing bindings and listeners to work in a consistent and predictable
manner). Also, since existing controls that override the getter, they
will know nothing about the setter. Applications may wonder why
setUserAgentStylesheet(sheet) does not imply
sheet.equals(getUserAgentStyleSheet()).
Off the top of my head I can think of three ways to resolve this
depending on what app developers and custom controls developers would
prefer to see:
A. Provide a property with some other name (i.e., not
userAgentStylesheet). If the value of this new property is non-null it
takes precedence over the userAgentStylesheet. When it changes, it
causes the necessary reevaluation to happen. This is the closest to what
you propose, but preserves backward compatibility. This add some
additional complexity, which may or may not be justified.
B. Provide an "updateUserAgentStylesheet(String)" method that acts
"like" a setter, but a control would be free to ignore (and a control
that overrides the "getter" today would certainly ignore). This seems
messy and has its own consistency issues. And it still doesn't solve the
question of how the control indicates that it has change its user agent
stylesheet.
C. Leave it up to the control to decide when and how to change the value
of its userAgentStylesheet. Provide a boolean
"dynamicUserAgentStylesheet" property indicating whether the
userAgentStylesheet is dynamic (most likely likely the control would set
it for itself). There might also need to be a way for a control to
indicate that its value has changed. Given your use cases, this seems
like a good fit.
There may be more options - e.g., a hybrid of B and C if setting this
under app control is a thing many apps want to do (although in that
case, why not just go with option A)? Maybe there something else I'm not
thinking of right now that would work.
A follow-up question is whether and how this would interact with the
proposed theming API that is also under discussion (maybe that
discussion could be revived)?
Before we spend too much more time on the API discussion, I want to hear
from other developers on the list as to the value proposition of doing
this and how they would like to see it done.
-- Kevin
On 7/16/2021 4:15 AM, Alessandro Parisi wrote:
>> The next steps would be to send an email (you can reply to this thread),
>> with a clear description of your proposal.
>>
>> The focus should be on what problem you are solving and on the proposed
>> public API and behavioral changes. I suggest not (yet) referring to code
>> changes in your PR except for illustrative purposes. Start with what the
>> current behavior is, what problem that is causing, and what your
>> proposed solution is. By way of a counter-example, the "computeIfAbsent"
>> code fragment you included in your email and PR description is an
>> implementation detail; the concept that should be discussed is the
>> presumed stability of a Region's userAgentStyleSheet. This presumed
>> stability is documented in the spec, so start there, not with the code.
>>
>> If there is general agreement that this feature is a good thing to add
>> to JavaFX as public API, meaning it is something that would benefit
>> multiple app developers, the next step would be to review the proposed
>> API and behavioral changes. This can be done in the context of reviewing
>> the PR. The focus during this phase of review would be mainly on the
>> specification changes that would need to go into the API docs and be
>> included in the CSR.
>>
>> The above is good general guidance for getting any new non-trivial
>> feature added to the JavaFX API.
>>
>> As for the specifics of what you are proposing, the main things I would
>> like to see addressed during the initial discussion are:
>>
>> * When and why do custom controls typically want to provide a dynamic
>> userAgentStylesheet?
>> * How should a control indicate that its userAgentStyleSheet is dynamic?
>> By a separate property (read-only?) that it provides as an override?
>> Should it be dynamic by default (I am skeptical, myself)?
>> * Does an application that uses a custom control need to know whether or
>> not that control uses a dynamic userAgentStylesheet? Can it affect the
>> answer (e.g., you mentioned theming, can you be more specific)?
>>
>> -- Kevin
>>
> So, without talking about code, I'm going to explain what I want to achieve
> with this change.
>
> As of now, custom controls can specify their userAgentStylesheet by
> overriding the getter inherited from Region. The documentation says:
>
>> An implementation may specify its own user-agent styles for this Region,
>> and its children, by overriding this method. Subclasses overriding this
>> method should not assume any particular implementation approach as to the
>> number and frequency with which it is called. For this reason, attempting
>> any kind of dynamic implementation (i.e. returning different user agent
>> stylesheet values) based on some state change is highly discouraged, as
>> there is no guarantee when, or even if, this method will be called.
>>
> The issue there is that the current implementation is not dynamic.
> To answer your first question:
>
>> When and why do custom controls typically want to provide a dynamic
>> userAgentStylesheet?
>>
> In my library, I currently have two custom controls. For each of them I
> have three stylesheets and I want the user to choose the style they
> prefer. So, the control is one, but the styles are three, and I can only
> provide one userAgentStylesheet because it is not dynamic. The solution
> would be to create three different controls and each of them uses one of
> the three stylesheets. However, this would lead to code duplication for
> just a stylesheet change.
>
> To answer the third question:
>
>> Does an application that uses a custom control need to know whether or
>> not that control uses a dynamic userAgentStylesheet? Can it affect the
>> answer (e.g., you mentioned theming, can you be more specific)?
>>
> Keeping in mind what I said above, let's suppose the user is developing an
> app with dark theme as default. With a dynamic implementation of the
> userAgentStylesheet I could specify two or more stylesheets for my custom
> controls, one or more for light and dark styles, the user would just need
> to change the style. That's what I mean by theming. In my custom controls
> then I could specify a way to change the style (an enumerator for example).
> It's up to the user then to decide which style to use.
> So the control needs to specify a way to change the style and that's up to
> the library developer to decide how (like I said an enumerator would be a
> way to do it), and JavaFX must allow the control to change the userAgent
> dynamically and update the control on change.
>
> To answer your second question:
>
>> How should a control indicate that its userAgentStyleSheet is dynamic?
>>
> Using a property. Rather than just having a getter, we could introduce a
> property to store the userAgent.
> When the user changes the style, the property changes too. On change, the
> StyleManager should also be notified about the change so that the CSS can
> be recomputed
More information about the openjfx-dev
mailing list