The changes at this stage are reflected in the MXML file (to see the complete file, select View Source from the app's context menu):
<components:ScrawlGrid id="dg" width="100%" height="50%" dataProvider="{employees.employee}">[Note the use of <components:columns> instead of <mx:columns>.] We are now using the subclasses of ComboBox and DataGrid: components.ScrawlComboBox and components.ScrawlGrid.
<components:columns>
<mx:DataGridColumn dataField="name" headerText="Name"/>
...
<components:ScrawlComboBox width="50%" dataProvider="[Lorem, Ipsum, Dolor, Amet]"/>
ScrawlComboBox differs from ComboBox only in specifying a different dropdownFactory:
private var _ddFactory:IFactory = new ClassFactory(ScrawlComboBoxDropdown);Subclassing ComboBox allows us to do two things: (1) specify a post-it skin for the dropdown list (in scrawl4.css):
ScrawlComboBoxDropdown { background-image: Embed('assets/postit.jpg'); }and (2) specify a cross-hatch pattern for rollover and selection in the dropdown list (in ScrawlComboBoxDropdown.as):
override protected function drawSelectionIndicator(Regarding (1): Since the background-image style is inherited, we could have simply created the style for List, which would have the same effect for this app, without subclassing ComboBox (since the default dropdown for a ComboBox is a List), but that would have meant that all Lists in the UI would have had a post-it background, which is not what we want here.
indicator:Sprite, xx:Number, yy:Number,
ignoredWidth:Number, h:Number, color:uint,
ignoredRenderer:IListItemRenderer):void
{
var w:int = unscaledWidth - viewMetrics.left - viewMetrics.right;
ScrawlUtil.drawCrossHatch(Sprite(indicator).graphics, w, h, color, 1.0);
indicator.x = xx;
indicator.y = yy;
}
Regarding (2): Note that ScrollComboBoxDropdown subclasses List and overrides drawHighlightIndicator() and drawSelectionIndicator(). Flex makes it easy to skin rollover and selection in a List or DataGrid if all you want to do is change the color:
roll-over-color: #E4E444;However, if you want to draw any patterns in there, you currently have to subclass.
selection-color: #C0C022;
Looking at the code for ScrawlGrid, we see that, in addition to the cross-hatch pattern for rollover and selection, there are other things that require overriding DataGrid:
(1) Drawing the column separator: ScrawlGrid overrides drawVerticalLine() to add some randomness so that the lines are not exactly vertical. To get the full effect, we also need to add the following graphical skin as a DataGrid style:
header-separator-skin: Embed('assets/header_separator.gif'); /* transparent */Strange but true: the header separator is skinnable, but the column separator as a whole is not.
(2) Drawing a diagonal line fill in the header: ScrawlGrid overrides drawHeaderBackground() -- once again, flex makes it easy to specify a solid background color for the header, but you have to subclass in order to draw any patterns.
We now get to the most difficult part of creating this theme: drawing rollover and selection indicators in the DataGrid headers. In DataGrid, the drawing code for rollover and selection for headers (but not for the DataGrid's contents) is hidden inside mouseOverHandler() and mouseDownHandler(). So we need the hack of overriding mouse handlers in order to change a purely visual part of the app:
override protected function mouseDownHandler(event:MouseEvent):voidNote the call to super.mouseDownHandler() -- we can't just ignore the superclass' mouse handling code the way we did with the draw***() methods. headerRendererHack() draws the cross-hatch pattern in the renderer for the correct header -- but there's a twist to finding that renderer. It turns out that mouseEventToItemRenderer() will return the correct header renderer except for the case where the mouse is over the sort arrow's hit area. What we want in that case is the renderer for the header of the column being sorted. getColumnHeaderRenderer() finds that renderer for us.
{
super.mouseDownHandler(event);
headerRendererHack(event, getStyle("selectionColor"));
}
That's it! (whew!) We now have reached the final version of the styled, skinned and tweaked Napkin app. Hopefully the tweaking needed at this stage will decrease over time as it is replaced with a more versatile use of programmatic and even graphical skins.