This email is a bit long but I think it represents a good way to move the
styling discussion forward. Please read it if you are interested in this
discussion.
I have been thinking about a way that we could support CSS either in addition
to or instead of JSON for styling. My original proposal for adding named style
support was something along these lines:
<Window styleClasses="@my_styles.json"
xmlns:bxml="http://pivot.apache.org/bxml"
xmlns="org.apache.pivot.wtk">
<BoxPane>
<Label styleClassNames="a, b, c" styles="{color:green;
font:Arial-BOLD-24}"/>
</BoxPane>
</Window>
The "my_styles.json" file defines the (untyped) style classes "a", "b", and
"c". These would be applied when the "styleClassNames" attribute is processed.
The values in the "styles" attribute would then override any of the styles
defined by the style classes.
However, this approach didn't work for two reasons:
1) Attributes aren't processed until the closing tag. This is by design -
consider a CardPane with a "selectedIndex" attribute. This value can't be set
until the card pane's children have been added. The implication here is that
the named styles specified by Window's "styleClasses" attribute won't be loaded
by the time the Label is created, so the named style classes won't be found.
2) Child elements aren't added to the parent until the closing tag. So, even if
#1 is solved, Label won't be able to walk up the tree to find the named styles
because BoxPane wouldn't have been added to the Window yet.
However, I believe I have a solution to both of these issues. I have already
modified BXMLSerializer to add child elements in the start tag, which resolves
#2. The resolution to #1 could be an annotation that specifies when an
attribute should be processed (e.g. @PostApply). If this attribute is not
specified, the attribute would be pre-applied (i.e. processed in the start tag).
Unfortunately, as we have discussed, another issue with this approach is that
JSON doesn't support namespaces. So it would be cumbersome to try to support
typed selectors in JSON. Typed selectors could be specified in WTKX, though:
<Window
xmlns:bxml="http://pivot.apache.org/bxml"
xmlns="org.apache.pivot.wtk">
<styleClasses>
<StyleClass type="org.apache.pivot.wtk.Label" name="a"
styles="{foo:'bar'}"/>
</styleClasses>
<BoxPane>
<Label styleClassNames="a, b, c" styles="{color:green;
font:Arial-BOLD-24}"/>
</BoxPane>
</Window>
Additionally, given CSS 3's proposed support for namespaces, it would become
possible to declare both typed and untyped selectors in an external CSS file.
WTK could also be updated to use inline CSS for local style specifications vs.
JSON, which would be slightly less verbose (no opening and closing curly
braces).
<Window styleClasses="@my_styles.css"
xmlns:bxml="http://pivot.apache.org/bxml"
xmlns="org.apache.pivot.wtk">
<BoxPane>
<Label styleClassNames="a, b, c" styles="color:green;
font:Arial-BOLD-24"/>
</BoxPane>
</Window>
I think this approach would be much more intuitive than the current one. It
would also be more consistent, since all styling would be specified via CSS,
rather than by a combination of classpath, attribute, and page-level variables.
The changes required to support this feature include:
1) BXMLSerializer modifications discussed above (trivial, and nearly complete)
2) Addition of a StyleClassSequence to Container (easy, but slightly
time-consuming)
3) Addition of serialization support for loading stylesheets and processing
inline CSS
#3 is obviously the most challenging. It will require implementing a new
serializer capable of processing CSS stylesheets:
StylesheetSerializer : Serializer<StyleClass>
An instance of this class would be used to process the "styleClasses"
attribute. It would probably also be used to process inline style declarations,
perhaps via a readStyleDeclaration(InputStream):Map<String, ?> method.
I don't think that implementing such a class will be very difficult. However,
as I mentioned earlier, I don't want to introduce a dependency on a 3rd party
library to support it. I'm not opposed to porting an existing implementation
that has a compatible license and including it in the platform, though. No need
to build it from scratch if there is already a good one we can use.
One downside to moving to CSS for styling is the potential loss of support for
font encodings such as this:
font: {bold:true}
I don't think we'd want to mix this kind of JSON-oriented styling with CSS.
Instead, we'd want to support the CSS syntax:
font-weight: bold
This is doable - it just means that any skin that supports a "font" style
should also define setFontFamily(), setFontSize(), and setFontWeight() methods.
So, here is what I propose: I will make the necessary changes to BXMLSerializer
and Container that are required to support this. I will leave the existing
JSON-based style support in place for now (though I will probably yank the
classpath-based type selectors, since they will no longer be necessary). CSS
won't be supported, but developers will be able to define and apply style
classes in BXML as shown above.
I would very much like to see support for CSS added, though. If anyone is
interested in working on the StylesheetSerializer class, please let me know. I
think it would make a great addition to the platform, and I would be highly
inclined to drop support for JSON styling in favor of CSS if this functionality
becomes available.
Please let me know what you think.
Thanks,
Greg