On Wed, 14 Jul 2010, Greg Brown wrote:
Michael,
I have been giving the styling discussion some thought. It seems like
your primary objective is to provide support for CSS-like type
selectors. In other words, you would like to ensure that a consistent
set of styles is applied to all instances of a particular component type
- is that correct?
That's one but not all of them. I also like CSS class selectors. Maybe
attribute selectors, too. Maybe descendent and child selectors. I don't
know. I haven't used it with Pivot enough to say. I do have a lot of
experience using Adobe's implementation of CSS for Flex. It supports
type, class, and id selectors. I frequently used the former but rarely
used the latter. So my affinity for CSS comes in large part from that
experience.
If so, I have a solution that I think will fit in well with the existing
architecture but will still meet your needs. I am thinking that
Component#setSkin() can be updated to apply a predefined set of styles
to each component instance as it is created. For example, I could say
that all PushButtons should have the "{font:'Arial-BOLD-24'}" style
applied at creation time.
I thought about various means for how those styles should be specified.
I first considered supporting a global stylesheet defined in CSS.
However, the problem with this approach is that CSS doesn't know
anything about Java packages. So you'd end up repeating quite a bit in
your style declarations:
org.apache.pivot.wtk.PushButton: {
font: "Arial-BOLD-24";
}
With Flex, if I had a lot of type selectors, I would put them in a global
CSS file. However, one of the most useful features of Flex's CSS support
is writing CSS style declarations in-line in your MXML file. They go
inside a <Style> tag. You can import them from a file using <Style
src="blah.css"/> but in most cases it's just more useful to write the
styling in-line. In either case, these style declarations only applied to
components within the containing MXML file.
Anyway, as for types for the time being I'm just comparing Java simple
names. It's sloppy, but it did work for Flex. They don't have namespaces
in their CSS files. Anyway, I still don't like it.
If you look at the CSS 3 draft, you'll see the editors have included
support for namespaces. And they're pretty simple. Basically it goes
like
@namespace blah "ms.allman.blah"
blah|MyBlahComponent {
name: value
}
You can also define a default namespace like this:
@namespace "org.apache.pivot.wtk"
Personally, I don't have a problem with just using this convention, even
if it's still in draft. There are no Java CSS parsers I'm aware of that
support this syntax, but the SAC does and I think I could submit a patch
to CSSParser that would implement it.
It would also necessitate writing or porting a CSS parser, which I would
like to avoid. More importantly, it would introduce a dependency on CSS
that we currently don't have.
Not sure why we couldn't just add a dep for a binary jar like CSSParser.
It could even be optional. "If you want's CSS support, you need to
include the CSSParser jar file on the classpath."
Unfortunately, the same problem would apply to a JSON-based global
stylesheet, since JSON doesn't have a concept of namespaces either:
{ org.apache.pivot.wtk.PushButton: {
font: "Arial-BOLD-24";
}
}
Yeah, this is one reason I think JSON sucketh in general. But that's
neither here nor there.
I also thought about an XML approach, since XML does support namespaces:
<styles xmlns="org.apache.pivot.wtk">
<PushButton font="Arial-BOLD-24"/>
</styles>
However, this seems pretty clumsy, and it is a bit confusing, since it
looks a bit like BXML but is not.
In all of these cases, there is also the issue of how the location of
the stylesheet will be provided to the platform. It could be specified
via a custom system property, but those are only available to trusted
code. That's too limiting.
Well, Flex makes no assumption about where the stylesheets live. You tell
it with a <Style src="asasd.css"/> tag in your mxml file. I'm not sure
having such a tight relationship between the location of the BXML and CSS
or whatever for the purposes of autodiscovery is worth the restriction
this imposes.
So here is what I have come up with. To review, one current way to apply
styles to any instance of a type is as follows:
<PushButton styles="@my_button_styles.json"/>
The button styles are encapsulated in an external JSON file named
"my_button_styles.json" that looks like this:
{ font: "Arial-BOLD-24"
}
However, since we want all PushButton instances to have the same styles
applied, we want to put them somewhere that the platform knows about, so
they can be applied when the component is created. I think we can do it
like this: create a directory structure that parallels the package
structure of the component you want to style, and create a JSON file
that represents the styles you want applied to that particular type:
Personally, I don't care if Pivot can automagically find my style sheets
or not. If it can be done really well, then by all means. But otherwise,
I don't mind typing something like <Styles src="asd.css"/>
/org
/apache
/pivot
/wtk
PushButton.json
When the component is created, Component#setSkin() will look for a file
with the same name as the component class, but with a .json extension.
If it finds one, it will apply the styles contained in the file to the
new instance.
I like this approach because it is consistent with the existing
infrastructure, but also because it applies the CSS notion of a "class"
in a Java-centric manner: the actual Java class lives in
/org/apache/pivot/wtk/PushButton.class, and the style "class" for that
class lives in /org/apache/pivot/wtk/PushButton.json.
Please let me know what you think.
Greg