So I’ve been reading the gumbo framework code and there is a lot I learnt from the code. I’ll share some of the things I leanred while browsing the code.
First, the base class of all components in Gumbo is the “FXComponent” Since FXComponent is a subclass of Halo’s UIComponent, it retains backward compatibility with flex 2&3 components but introduces some of its own goodies.
I’ll do an analysis of the code in this component for this post.
public function FxComponent()
{
// Initially state is dirty
skinStateIsDirty = true;
}
As we see gumbo still use the same convention of invalidation -> validation cycle and this variable is used to signal the fact that skin needs validation.
private function setSkin(value:Skin):void
{
if (value === _skin)
return;
_skin = value;
dispatchEvent(new Event(“skinChanged”));
}
setter for skin is private means that this function will be called by some other part of the code. Notice that “skinChanged=true” is not called here which seems a little strange but we will see later why.
override protected function commitProperties():void
{
super.commitProperties();
if (skinChanged)
{
skinChanged = false;
if (skin)
unloadSkin();
loadSkin();
}
if (skinStateIsDirty)
{
skin.currentState = getCurrentSkinState();
skinStateIsDirty = false;
}
}
Here we see the invalidation -> validation in action. Basically this takes place for 2 things, skinChanged and SkinStateDirty and the corresponding function to validate them are unloadSkin()-> loadSkin(); and getCurrentSkinState();
override protected function measure():void
{
if (skin)
{
measuredWidth = skin.getExplicitOrMeasuredWidth();
measuredHeight = skin.getExplicitOrMeasuredHeight();
measuredMinWidth = isNaN( skin.explicitWidth ) ? skin.minWidth : skin.explicitWidth;
measuredMinHeight = isNaN( skin.explicitHeight ) ? skin.minHeight : skin.explicitHeight;
}
}
As we see in the measure function, all the layouts in gumbo are going to be done by skin objects, which are just light weight wrappers for group objects and group objects delegate all their positioning and layout to special layout classes. But more on that perhaps in another post
override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void
{
if (skin)
skin.setActualSize(unscaledWidth, unscaledHeight);
if (focusObj && focusObj is IInvalidating)
IInvalidating(focusObj).invalidateDisplayList();
}
we see here that skin are treated like childrens of the FXComponent and the component is responsible for telling the skin its size.
protected function loadSkin():void
{
// Factory
var skinClassFactory:IFactory = getStyle(“skinFactory”) as IFactory;
if (skinClassFactory)
setSkin( skinClassFactory.newInstance() as Skin );
This function “loads” a skin, as we see skins are set as factories or classes and now its apparant why the setSkin function doesn’t mark skinChanged = true since this is the only place were its called and its during the validation cycle.
if (skin)
{
skin.owner = this;
skin.fxComponent = this;
// As a convenience if someone has declared hostComponent
// we assign a reference to ourselves. If the hostComponent
// property exists as a direct result of utilizing [HostComponent]
// metadata it will be strongly typed. We need to do more work
// here and only assign if the type exactly matches our component
// type.
if (“hostComponent” in skin)
{
try
{
Object(skin).hostComponent = this;
}
catch (err:Error) {}
}
addChild(skin);
skin.addEventListener(PropertyChangeEvent.PROPERTY_CHANGE, skin_propertyChangeHandler);
}
else
{
throw(new Error(“Skin for ” + this + ” cannot be found.”));
}
Some interesting code here:
the hostComponent propert set in skin allow the skin to resize itself to fit certain parameters of the host component, as described here (http://www.philterdesign.com/blog/2008/09/10_reasons_to_dig_skinning_in_1.html)
the skin is indead treated as a Child of the hostComponent, and such, its a UIComponent too =)
Immediately after the skin gets loaded, this gets called:
protected function findSkinParts():void
the skin parts are found by this function:
var skinParts:Array = getSkinPartMetadata(className);
who’s details are something that is beyond my understanding at this point, but in the findSkinParts function we can see that information about the skin parts are tacked unto the object itself
this[part.id] = skin[part.id]; and we also see that each one of these objects should be an IFactory
if (this[part.id] != null && !(this[part.id] is IFactory))
partAdded(part.id, this[part.id]);
which brings us to the next function : partAdded(partName:String, instance:Object):void
which is….. empty…. but its used in child classes since the base class FXComponent itself has no subparts to speak of, it only has itself and its own skin to take care of.
There are also other functions such as createDynamicPartInstance and removeDynamicPartInstance, but they don’t get called anywhere in the base FXComponent class, so I will probably stumble upon them later in my later exploration of the framework.
As you can see, the new gumbo framework:
- keeps the old component lifecycle
- adds the support for skin
- the code is surprisingly readable and consistent.