Hi all, Earlier today I committed a change that adds named and typed style support to WTK. Callers can either associate a set of styles with a "name" (a string) or a "type" (a class that extends Component). This is consistent with the styling support provided by Flex, which supports CSS type selectors and class selectors but not a combination of the two (e.g. "Button" and ".foo" but not "Button.foo").
Named and typed styles are specified via the static "namedStyles" and "typedStyles" collections of Component. When a component is instantiated, setSkin() walks the component's class hierarchy and applies any matching classes. When the "styleName" or "styleNames" property of a component is set, any matching named style(s) are applied. This is also consistent with Flex, which uses a static StyleManager singleton to manage named styles. Note that Pivot supports a list of style names, whereas Flex only supports a single style name. An application can populate the named and typed style maps manually, or it can be done automatically at application startup via the "stylesheet" startup property. This property contains the path to the stylesheet that will be used to style the application. This is slightly different from how it is done in Flex, where a caller can specify a stylesheet in MXML. This is not possible in Pivot because Pivot applications are not defined in markup; they are classes that implement the Application interface. However, separating the stylesheet from the application may actually be a better approach, since it allows the application to be instantiated with an arbitrary stylesheet, rather than creating a hard association with a single stylesheet. Another problem with the Flex approach is that defining a stylesheet anywhere other than in the <mx:Application> tag can have unexpected side effects; see note: http://livedocs.adobe.com/flex/3/html/help.html?content=styles_05.html#165272 I'm guessing this is because applying the <mx:Style> tag modifies the state of the StyleManager singleton. As a result, even though it looks like the styles would only apply to the current document, they would actually affect all documents in the application. Allowing stylesheets to be applied only at the application level eliminates this ambiguity. You can see an example of the new styling support here: http://svn.apache.org/repos/asf/pivot/trunk/demos/src/org/apache/pivot/demos/styles/ I haven't posted a live demo, but it should be pretty obvious from the code what is going on: styles.json defines a number of typed and named styles that are referred to by name and type in stylesheet_demo.bxml. Note that none of these changes preclude the use of CSS to define styles. However, I'm now leaning away from advocating a wholesale migration to CSS in Pivot. While thinking through this solution, I remembered that, even though styles are defined in CSS in HTML and in Flex, anytime you want to modify them programmatically, you need to use the JSON version of the style names. Given this, it is arguably better to use JSON throughout the framework for style specification, so the developer does not need to switch between two different syntaxes for managing styles. I'm happy with how this turned out, and I think it represents a considerable improvement over the previous two approaches I have prototyped (applying stylesheets via BXML includes and applying typed styles via JSON-based style classes). This change replaces the latter, but it actually does not replace the former. In fact, there are still occasions when you may want to use an include to specify styles. For example, the include approach supports dynamic binding to style values, while the named style approach does not. This was intentional - the primary purpose of named styles is to allow the details of an application's appearance to be abstracted from the structure of the UI itself. Most of the time, named styles are applied only once, when a component is initially created. Dynamic re-styling is almost a completely separate use case. Fortunately, the current implementation provides an easy way for developers to do both. Thanks to all involved for your input. Please let me know if you have any questions. Greg On Jul 17, 2010, at 9:53 AM, Greg Brown wrote: > If you haven't read through this thoroughly yet, please hold off. I have been > working through the design and have discovered a number of issues. I am > currently revising the approach and will send an updated email. > > On Jul 16, 2010, at 11:35 AM, Greg Brown wrote: > >> 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 >> >