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

Reply via email to