IMO the current CSS priorities are wrong. A value set from code should be 
adjacent to an in-line style in terms of precedence.  They are both ways of 
saying saying “this particular instance should have this value”

Scott

> On Jan 30, 2024, at 8:31 AM, John Hendrikx <john.hendr...@gmail.com> wrote:
> 
> Hi Michael,
> 
> I think we first need to decide what the correct behavior is for CSS 
> properties, as the "bind" solution IMHO is a bug.
> 
> The StyleOrigin enum encodes the relative priorities of styles and user set 
> values, but it is incomplete and not fully enforced.  There is (currently) 
> actually a 5th level (next to USER_AGENT, USER, AUTHOR and INLINE) where it 
> checks the binding state (it has no choice, as it will get an exception 
> otherwise, or has to call `unbind` first).  Whether that's a bug or should 
> more formally be accepted as the correct behavior remains to be seen.  Also 
> the AUTHOR and INLINE levels are only best effort, as setting a value in code 
> (USER level) will override AUTHOR and INLINE values **temporarily** until the 
> next CSS pass...
> 
> So first questions to answer IMHO are:
> 
> 1) Does it make sense to treat values set in code (which IMHO should always 
> be the last word on anything) as less important than values from AUTHOR and 
> INLINE styles?  This is specified in the CSS document, but not fully enforced.
> 
> 2) Should bound values (which IMHO fall under "values set from code") be able 
> to override AUTHOR and INLINE styles?  Why are they being treated differently 
> at all?  Which StyleOrigin level do they fall under?  "USER"?  A 5th level 
> with higher priority than "INLINE"?
> 
> 3) Should properties which hold an AUTHOR or INLINE value reject calls to 
> `setValue` (to make it clear they are temporary and that your code is 
> probably wrong)?  This currently is not in line with the CSS document.  Note 
> that this will be slightly annoying for the CSS engine as it may not be able 
> to "reset" such values as easily as before (which is probably the reason it 
> currently works the way it does, but that's no excuse IMHO).
> 
> As for your potential solution, if you introduce a constant binding system 
> (to solve a CSS problem), does that make sense for properties as a whole?  
> What can be achieved with `bindConstant` that can't be done with `setValue`?  
> `bindConstant` will become the "setter" that always works (never throws an 
> exception...), but probably at a higher cost than using `setValue`.  Would it 
> not make more sense to only have such methods on the Styleable properties 
> (which can then also signal this by using an even higher precedence 
> StyleOrigin instead of relying on bound/unbound) once there is agreement on 
> the above questions?
> 
> In other words, I'd look more in the direction of providing users with a 
> better "setter" only for CSS properties, that also uses a different 
> StyleOrigin, and to bring both binding and setting in line with the CSS 
> document's specification (or alternatively, to change that specification).  
> This means that the normal setter provided next to the property method (ie. 
> setXXX) would have to default to some standard behavior, while a more 
> specific setter provided on the property itself can have an overriding 
> behavior, something like:
> 
>     setX() -> calls cssProperty.setValue()
>     cssProperty.setValue() -> sets values if not originated from an AUTHOR or 
> INLINE stylesheet, otherwise throws exception (as if bound)
>     cssProperty.forceValue() -> sets value unconditionally, setting 
> StyleOrigin to some new to introduce 5th level 
> (StyleOrigin.FORCED/DEVELOPER/DEBUG/CONSTANT/FINAL)
> 
> Binding can then either be categorized as the StyleOrigin.FORCED or if it is 
> StyleOrigin.USER, the CSS engine is free to **unbind** if the need arises.
> 
> --John
> 
> 
>> On 30/01/2024 09:25, Michael Strauß wrote:
>> Hi everyone,
>> 
>> I'm interested in hearing your thoughts on the following proposal,
>> which could increase the expressiveness of the JavaFX Property API:
>> 
>> Problem
>> -------
>> The JavaFX CSS system applies the following order of precedence to
>> determine the value of a styleable property (in ascending
>> specificity):
>> 1. user-agent stylesheets
>> 2. values set from code
>> 3. Scene stylesheets
>> 4. Parent stylesheets
>> 5. inline styles
>> 
>> While this system works quite well in general, applications sometimes
>> need to override individual property values from code. However, this
>> doesn't work reliably in the presence of Scene or Parent stylesheets.
>> There are two usual workarounds to solve this problem:
>> 
>> A) Use an inline style instead of setting the property value directly.
>> 
>> This is obviously not a good solution, as you'll lose the strong
>> typing afforded by the Java language. Additionally, the value must be
>> a true constant, it can't be an expression or the result of a
>> computation.
>> 
>> B) Create an `ObservableValue` instance that holds the desired value,
>> and bind the property to it.
>> 
>> This is a much better solution. However, what we really want is just
>> the binding semantics: the bound property becomes unmodifiable and has
>> the highest precedence in the CSS cascade. But the API only gives us
>> binding semantics if we give it an `ObservableValue`.
>> 
>> 
>> Solution
>> --------
>> I'm proposing to separate the toggles "binding semantics" and
>> "observability". While observability requires you to provide an
>> `ObservableValue`, binding semantics should work with both observable
>> and regular values.
>> 
>> This is a powerful addition to the Property API, since it increases
>> the expressiveness of the API in a natural way:
>> 
>>     // instead of:
>>     rect.setStyle("-fx-fill: red; -fx-width: 200");
>> 
>>     // you can use strongly-typed Java code:
>>     rect.fillProperty().bindConstant(Color.RED);
>>     rect.widthProperty().bindConstant(200);
>> 
>> Since the `bindConstant` method accepts a value of the property type,
>> all features of the Java language can be used to fill in the value.
>> 
>> 
>> Implementation
>> --------------
>> The following method will be added to the `Property` interface:
>> 
>>     default void bindConstant(T value) {
>>         bind(ObjectConstant.valueOf(value));
>>     }
>> 
>> Specialized methods will be added to `BooleanProperty`,
>> `DoubleProperty`, `FloatProperty`, `IntegerProperty`, and
>> `LongProperty`, each with one of the preexisting constant wrappers
>> that are already in the framework.
>> Some wrappers can be deduplicated (we only ever need two wrapper
>> instances for boolean values).

Reply via email to