[prev in list] [next in list] [prev in thread] [next in thread] 

List:       openjdk-openjfx-dev
Subject:    Re: Binding properties to constant values
From:       Nir Lisker <nlisker () gmail ! com>
Date:       2024-01-31 21:36:45
Message-ID: CA+0ynh8JFmq47+nWjUmJMVQB37R1HDYHES96HWx6ytGdJ4dA2w () mail ! gmail ! com
[Download RAW message or body]

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


You mean the ones in com.sun.javafx.binding [1]?

I use both constant bindings and inline css to override stylesheets and I
like neither, but I'm not sure that exposing constant binding is the
solution. Like John said, it's specific for css and doesn't make much sense
semantically.

About the order of css origins, there was a relevant discussion on JBS [2].

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.


I think that the specifications chose the wrong order. They say "The
implementation allows designers to style an application by using style
sheets to override property values set from code." and I think this was a
poor and mostly surprising choice. I see that John and Scott agree with
that too. I've seen many StackOverflow questions about this confusion, many
can be found by searching "javafx override css from code". I don't know if
it can be changed, as it's a breaking change. I wonder what the original
writer's thoughts were, and what use case they had in mind. Perhaps they
thought that setting values from the java side is akin to specifying a user
stylesheet to the browser, which takes precedence over the browser's style
sheet, but not over the author's stylesheet.

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"?
> 

I don't see how anything should override bound values since they update on
every change and throw an exception if something tries to set the value of
a bound value.

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


I would wait with the ramifications of setting competing values from
different origins until the question of precedence is answered. Perhaps
emitting warnings is better, though I can see some scenarios in which they
will be annoying.

The way I see the order:
1. Setting from code should always take precedence (including the current
bindings over setter order of course).
2. INLINE origin (via setStyle).
3. Stylesheets according to their StyleOrigin as specified by the
non-javafx css specifications [3]: AUTHOR > USER > USER_AGENT (see below
for INLINE).

2 and 3 are already (more or less) specified in JavaFX's css as far as I
can see. However, 1 is not css, hence I don't think StyleOrigin should be
applicable here even. Even more, 2 isn't really css either, it mimics html
tags and shouldn't count as a css StyleOrigin in my opinion.
Note also that a Stylesheet can set its origin [4], even to INLINE, so it
takes precedence over java property setters and conflicts with 'setStyle'
"real" INLINE. I'm not sure if this is a bug because the javafx css specs
say that "Inline styles are specified via the Node setStyle AP".

So, if I were to able to do anything I wanted, I would have restricted
Stylesheets to the options in 3, remove INLINE from a public perspective
and apply it only behind the scenes to 'setStyle' calls, and stop treating
java settings in the css hierarchy (which means removing the USER
StyleOrigin from them). Obviously that breaks a lot of code, but this
behavior would be my general goal. As for how to represent it, maybe a
constant can be added to StyleOrigin to represent java code settings, but
that's not a real css origin. I guess we could call INLINE and the
hypothetical JAVA constants "pseudo-origins", because they don't apply to
stylesheets, and are only used internally. Or just don't check StyleOrigin
when the value is set from java. There are probably more ways.

I also wonder if StyleOrigin should implement Comparable for the precedence
calculations of stylesheets.

However, it seems like an arbitrary fact that attributes in an FXML
> document are equivalent to calling setters from code. Attributes in
> FXML documents could just as well be their own thing, couldn't they?
> 

Another good point. I don't really use FXML, so I can't say what I would
expect. There are several options for this.

[1]
https://github.com/openjdk/jfx/tree/master/modules/javafx.base/src/main/java/com/sun/javafx/binding
 [2] https://bugs.openjdk.org/browse/JDK-8317434
[3] https://drafts.csswg.org/css-cascade-4/#cascade
[4]
https://openjfx.io/javadoc/21/javafx.graphics/javafx/css/Stylesheet.html#setOrigin(javafx.css.StyleOrigin)


On Tue, Jan 30, 2024 at 9:24 PM Michael Strauß <michaelstrau2@gmail.com>
wrote:

> Hi John,
> 
> the rule that values set from code are less specific than values set
> in author and inline styles is probably lifted from the CSS
> specification, which says [0]:
> 
> "The UA may choose to honor presentational attributes in an HTML
> source document. If so, these attributes are translated to the
> corresponding CSS rules with specificity equal to 0, and are treated
> as if they were inserted at the start of the author style sheet."
> 
> However, it seems like an arbitrary fact that attributes in an FXML
> document are equivalent to calling setters from code. Attributes in
> FXML documents could just as well be their own thing, couldn't they?
> 
> Let's assume for a moment that we could change that (which is a
> breaking change), and make a distinction between values that come from
> FXML attributes and values that come from code. This would introduce a
> new StyleOrigin.ATTRIBUTE, which would be the origin for all attribute
> values set by FXMLLoader (or by anyone, this is a public API in
> StyleableProperty after all). However, bindings in FXML documents
> would probably continue to use the USER origin. The CSS system would
> then never change values with USER origin, since they definitely don't
> come from attribute values.
> 
> With regards to your idea of only allowing cssProperty.setValue() if
> the current value doesn't come from an AUTHOR or INLINE style: it
> seems like this *will* work some of the time, namely before CSS is
> applied for the first time.
> 
> 
> [0] https://www.w3.org/TR/CSS22/cascade.html#preshint
> 
> 
> On Tue, Jan 30, 2024 at 3:22 PM John Hendrikx <john.hendrikx@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
> 


[Attachment #3 (text/html)]

<div dir="ltr"><div><blockquote class="gmail_quote" style="border-left:1px solid \
rgb(204,204,204);margin:0px 0px 0px 0.8ex;padding-left:1ex">Specialized methods will \
be added to `BooleanProperty`,<br>`DoubleProperty`, `FloatProperty`, \
`IntegerProperty`, and<br>`LongProperty`, each with one of the preexisting constant \
wrappers<br>that are already in the framework.<br>Some wrappers can be deduplicated \
(we only ever need two wrapper<br>instances for boolean \
values).</blockquote><div><br></div><div>You mean the ones in com.sun.javafx.binding \
[1]?</div></div><div><br></div><div>I use both constant bindings and inline css to \
override stylesheets and I like neither, but I&#39;m not sure that exposing constant \
binding is the solution. Like John said, it&#39;s specific for css and doesn&#39;t \
make much sense semantically.</div><div><br></div>About the order of css origins, \
there was a relevant discussion on JBS [2].<div><br></div><div><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex">1) Does it make sense to treat values set in code \
(which IMHO should<br>always be the last word on anything) as less important than \
values from<br>AUTHOR and INLINE styles?   This is specified in the CSS document, \
but<br>not fully enforced.</blockquote><div><div><br></div><div>I think that the \
specifications chose the wrong order. They say &quot;The implementation allows \
designers to style an application by using style sheets to override property values \
set from code.&quot; and I think this was a poor and mostly surprising choice. I see \
that John and Scott agree with that too. I&#39;ve seen many StackOverflow  questions \
about this confusion, many can be found by searching &quot;javafx override css from \
code&quot;. I don&#39;t know if it can be changed, as it&#39;s a breaking change. I \
wonder what the original writer&#39;s thoughts were,  and what use case they  had in \
mind. Perhaps they thought that setting values from the java side is akin to \
specifying a user stylesheet to the browser, which takes precedence over the \
browser&#39;s style sheet, but not over the author&#39;s \
stylesheet.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px \
0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">2) Should bound \
values (which IMHO fall under &quot;values set from code&quot;) be<br>able to \
override AUTHOR and INLINE styles?   Why are they being treated<br>differently at \
all?   Which StyleOrigin level do they fall under?  <br>&quot;USER&quot;?   A 5th \
level with higher priority than \
&quot;INLINE&quot;?<br></blockquote><div><br></div><div>I don&#39;t see how anything \
should override bound values since they update on every change and throw an exception \
if something tries to set the value of a bound value.</div><div><br></div><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex">3) Should properties which hold an AUTHOR or \
INLINE value reject calls<br>to `setValue` (to make it clear they are temporary and \
that your code is<br>probably wrong)?   This currently is not in line with the CSS \
document.  <br>Note that this will be slightly annoying for the CSS engine as it \
may<br>not be able to &quot;reset&quot; such values as easily as before (which \
is<br>probably the reason it currently works the way it does, but that&#39;s \
no<br>excuse IMHO).</blockquote><div><br></div><div>I would wait with the \
ramifications of setting competing values from different origins until the question \
of precedence is answered. Perhaps emitting warnings is better, though I can see some \
scenarios in which they will be annoying.</div><div><br></div><div>The way I see the \
order:</div><div>1. Setting from code should always take precedence (including the \
current bindings over setter order of course).</div><div>2. INLINE origin (via \
setStyle).</div><div>3. Stylesheets according to their StyleOrigin as specified by \
the non-javafx css specifications [3]: AUTHOR &gt; USER &gt; USER_AGENT (see below \
for INLINE).</div><div><br></div><div>2 and 3 are already (more or less) specified in \
JavaFX&#39;s  css as far as I can see. However, 1 is not css, hence I don&#39;t think \
StyleOrigin should be applicable here even. Even more, 2 isn&#39;t really css either, \
it mimics html tags and shouldn&#39;t count as a css StyleOrigin in my \
opinion.</div><div>Note also that a Stylesheet can set its origin [4], even to \
INLINE, so it takes precedence over java property setters and conflicts with \
&#39;setStyle&#39; &quot;real&quot; INLINE. I&#39;m not sure if this is a bug because \
the javafx css specs say that &quot;Inline styles are specified via the Node setStyle \
AP&quot;.</div><div><br></div><div>So, if I were to able to do anything I wanted, I \
would have restricted Stylesheets to the options in 3, remove INLINE from a public \
perspective and apply it only behind the scenes to &#39;setStyle&#39; calls, and stop \
treating java settings in the css hierarchy (which means removing the USER \
StyleOrigin from them). Obviously that breaks a lot of code, but this behavior would \
be my general goal. As for how to represent it, maybe a constant can be added to \
StyleOrigin to represent java code settings, but that&#39;s not a real css origin. I \
guess we could call INLINE and the hypothetical JAVA constants \
&quot;pseudo-origins&quot;, because they don&#39;t apply to stylesheets, and are only \
used internally. Or just don&#39;t check StyleOrigin when the value is set from java. \
There are probably more ways.</div><div><br></div><div>I also wonder if StyleOrigin \
should implement Comparable for the  precedence calculations of \
stylesheets.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px \
0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">However, it \
seems like an arbitrary fact that attributes in an FXML<br>document are equivalent to \
calling setters from code. Attributes in<br>FXML documents could just as well be \
their own thing, couldn&#39;t they?<br></blockquote><div><br></div><div>Another good \
point. I don&#39;t really use FXML, so I can&#39;t say what I would expect. There are \
several options for this.</div><div><br></div><div>[1]  <a \
href="https://github.com/openjdk/jfx/tree/master/modules/javafx.base/src/main/java/com/sun/javafx/binding" \
target="_blank">https://github.com/openjdk/jfx/tree/master/modules/javafx.base/src/main/java/com/sun/javafx/binding</a><br></div><div><div>[2] \
<a href="https://bugs.openjdk.org/browse/JDK-8317434" \
target="_blank">https://bugs.openjdk.org/browse/JDK-8317434</a></div><div>[3]  <a \
href="https://drafts.csswg.org/css-cascade-4/#cascade" \
target="_blank">https://drafts.csswg.org/css-cascade-4/#cascade</a></div><div>[4]  <a \
href="https://openjfx.io/javadoc/21/javafx.graphics/javafx/css/Stylesheet.html#setOrigin(javafx.css.StyleOrigin)" \
target="_blank">https://openjfx.io/javadoc/21/javafx.graphics/javafx/css/Stylesheet.html#setOrigin(javafx.css.StyleOrigin)</a></div></div></div></div></div><br><div \
class="gmail_quote"><div dir="ltr" class="gmail_attr">On Tue, Jan 30, 2024 at \
9:24 PM Michael Strauß &lt;<a href="mailto:michaelstrau2@gmail.com" \
target="_blank">michaelstrau2@gmail.com</a>&gt; wrote:<br></div><blockquote \
class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid \
rgb(204,204,204);padding-left:1ex">Hi John,<br> <br>
the rule that values set from code are less specific than values set<br>
in author and inline styles is probably lifted from the CSS<br>
specification, which says [0]:<br>
<br>
&quot;The UA may choose to honor presentational attributes in an HTML<br>
source document. If so, these attributes are translated to the<br>
corresponding CSS rules with specificity equal to 0, and are treated<br>
as if they were inserted at the start of the author style sheet.&quot;<br>
<br>
However, it seems like an arbitrary fact that attributes in an FXML<br>
document are equivalent to calling setters from code. Attributes in<br>
FXML documents could just as well be their own thing, couldn&#39;t they?<br>
<br>
Let&#39;s assume for a moment that we could change that (which is a<br>
breaking change), and make a distinction between values that come from<br>
FXML attributes and values that come from code. This would introduce a<br>
new StyleOrigin.ATTRIBUTE, which would be the origin for all attribute<br>
values set by FXMLLoader (or by anyone, this is a public API in<br>
StyleableProperty after all). However, bindings in FXML documents<br>
would probably continue to use the USER origin. The CSS system would<br>
then never change values with USER origin, since they definitely don&#39;t<br>
come from attribute values.<br>
<br>
With regards to your idea of only allowing cssProperty.setValue() if<br>
the current value doesn&#39;t come from an AUTHOR or INLINE style: it<br>
seems like this *will* work some of the time, namely before CSS is<br>
applied for the first time.<br>
<br>
<br>
[0] <a href="https://www.w3.org/TR/CSS22/cascade.html#preshint" rel="noreferrer" \
target="_blank">https://www.w3.org/TR/CSS22/cascade.html#preshint</a><br> <br>
<br>
On Tue, Jan 30, 2024 at 3:22 PM John Hendrikx &lt;<a \
href="mailto:john.hendrikx@gmail.com" target="_blank">john.hendrikx@gmail.com</a>&gt; \
wrote:<br> &gt;<br>
&gt; Hi Michael,<br>
&gt;<br>
&gt; I think we first need to decide what the correct behavior is for CSS<br>
&gt; properties, as the &quot;bind&quot; solution IMHO is a bug.<br>
&gt;<br>
&gt; The StyleOrigin enum encodes the relative priorities of styles and user<br>
&gt; set values, but it is incomplete and not fully enforced.   There is<br>
&gt; (currently) actually a 5th level (next to USER_AGENT, USER, AUTHOR and<br>
&gt; INLINE) where it checks the binding state (it has no choice, as it will<br>
&gt; get an exception otherwise, or has to call `unbind` first).   Whether<br>
&gt; that&#39;s a bug or should more formally be accepted as the correct behavior<br>
&gt; remains to be seen.   Also the AUTHOR and INLINE levels are only best<br>
&gt; effort, as setting a value in code (USER level) will override AUTHOR and<br>
&gt; INLINE values **temporarily** until the next CSS pass...<br>
&gt;<br>
&gt; So first questions to answer IMHO are:<br>
&gt;<br>
&gt; 1) Does it make sense to treat values set in code (which IMHO should<br>
&gt; always be the last word on anything) as less important than values from<br>
&gt; AUTHOR and INLINE styles?   This is specified in the CSS document, but<br>
&gt; not fully enforced.<br>
&gt;<br>
&gt; 2) Should bound values (which IMHO fall under &quot;values set from code&quot;) \
be<br> &gt; able to override AUTHOR and INLINE styles?   Why are they being \
treated<br> &gt; differently at all?   Which StyleOrigin level do they fall \
under?<br> &gt; &quot;USER&quot;?   A 5th level with higher priority than \
&quot;INLINE&quot;?<br> &gt;<br>
&gt; 3) Should properties which hold an AUTHOR or INLINE value reject calls<br>
&gt; to `setValue` (to make it clear they are temporary and that your code is<br>
&gt; probably wrong)?   This currently is not in line with the CSS document.<br>
&gt; Note that this will be slightly annoying for the CSS engine as it may<br>
&gt; not be able to &quot;reset&quot; such values as easily as before (which is<br>
&gt; probably the reason it currently works the way it does, but that&#39;s no<br>
&gt; excuse IMHO).<br>
&gt;<br>
&gt; As for your potential solution, if you introduce a constant binding<br>
&gt; system (to solve a CSS problem), does that make sense for properties as<br>
&gt; a whole?   What can be achieved with `bindConstant` that can&#39;t be done<br>
&gt; with `setValue`?   `bindConstant` will become the &quot;setter&quot; that \
always<br> &gt; works (never throws an exception...), but probably at a higher cost \
than<br> &gt; using `setValue`.   Would it not make more sense to only have such<br>
&gt; methods on the Styleable properties (which can then also signal this by<br>
&gt; using an even higher precedence StyleOrigin instead of relying on<br>
&gt; bound/unbound) once there is agreement on the above questions?<br>
&gt;<br>
&gt; In other words, I&#39;d look more in the direction of providing users with a<br>
&gt; better &quot;setter&quot; only for CSS properties, that also uses a \
different<br> &gt; StyleOrigin, and to bring both binding and setting in line with \
the CSS<br> &gt; document&#39;s specification (or alternatively, to change that<br>
&gt; specification).   This means that the normal setter provided next to the<br>
&gt; property method (ie. setXXX) would have to default to some standard<br>
&gt; behavior, while a more specific setter provided on the property itself<br>
&gt; can have an overriding behavior, something like:<br>
&gt;<br>
&gt;         setX() -&gt; calls cssProperty.setValue()<br>
&gt;         cssProperty.setValue() -&gt; sets values if not originated from an<br>
&gt; AUTHOR or INLINE stylesheet, otherwise throws exception (as if bound)<br>
&gt;         cssProperty.forceValue() -&gt; sets value unconditionally, setting<br>
&gt; StyleOrigin to some new to introduce 5th level<br>
&gt; (StyleOrigin.FORCED/DEVELOPER/DEBUG/CONSTANT/FINAL)<br>
&gt;<br>
&gt; Binding can then either be categorized as the StyleOrigin.FORCED or if<br>
&gt; it is StyleOrigin.USER, the CSS engine is free to **unbind** if the need<br>
&gt; arises.<br>
&gt;<br>
&gt; --John<br>
</blockquote></div>



[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic