<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Saturnboy &#187; skinning</title>
	<atom:link href="http://saturnboy.com/tag/skinning/feed/" rel="self" type="application/rss+xml" />
	<link>http://saturnboy.com</link>
	<description>Code, Work, and Life</description>
	<lastBuildDate>Wed, 28 Jul 2010 13:20:37 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.0</generator>
		<item>
		<title>SuperTextInput &#8211; Building a Custom Component in Flex 4</title>
		<link>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/</link>
		<comments>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/#comments</comments>
		<pubDate>Thu, 22 Jul 2010 18:59:29 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1489</guid>
		<description><![CDATA[I&#8217;ve been building a lot of Flex 4 custom components lately, including a sliding drawer, a multiple content area container, and now SuperTextInput. Nor will this be that last, because I think I have a few more in me. I thought it would be useful to spend some time in the details, explaining The Flex [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;ve been building a lot of Flex 4 custom components lately, including a <a href="http://saturnboy.com/2010/06/drawer-component-flex-4/">sliding drawer</a>, a <a href="http://saturnboy.com/2010/07/multiple-content-area-containers/">multiple content area container</a>, and now SuperTextInput.  Nor will this be that last, because I think I have a few more in me.  I thought it would be useful to spend some time in the details, explaining <i>The Flex 4 Way</i> and how I try to walk the path.</p>
<p>SuperTextInput is a prompting, clearable <code>TextInput</code> extension in Flex 4.  It&#8217;s just an enhanced version of the default <code>TextInput</code> control, and as such, it follows a fairly standard pattern of custom component creation.</p>
<h3>Enhanced Component Pattern</h3>
<p>It&#8217;s almost too stupid to call this a pattern, but it&#8217;s <b>so</b> common in custom component creation that I&#8217;ll run with it.  Also, I&#8217;ve found it to be worthwhile to distinguish between adding new functionality to a component already present in the framework (aka an enhanced component) versus creating a truly custom component.</p>
<p class="bottom">The enhanced component pattern is just two simple steps:</p>
<ol>
<li><b>Extend</b> &ndash; extend some default component and add some new functionality</li>
<li><b>Skin</b> &ndash; make it look good</li>
</ol>
<p>In my version of reality, these steps carry equal weight, because almost all worthwhile functionality in Flex touches the UI in some fashion, so the design and UX (the look-and-feel, it&#8217;s usability, the integration into the rest of the app, etc.) are critical. Don&#8217;t forget or skimp on step #2 because it&#8217;s all the client, team, customer ever sees.</p>
<h3>A Prompting TextInput</h3>
<p>Since SuperTextInput has two new pieces of functionality (the prompt and the clear button), I&#8217;ll split them apart, and consider each part separately.  First, the prompt is merely the text you see when the <code>TextInput</code> is empty.  It often becomes a space saving label, because it can be used to tell the user what goes into the <code>TextInput</code> without costing the UI any screen real estate.</p>
<p>Thinking more about the prompt, we want the prompt text to be visible initially, but it should disappear when the user clicks (or tabs) to the control, and only returns when the control loses focus and is still empty.  So this tells us that we need to communicate both the prompt text and it&#8217;s visibility to our skin.  The prompt text can just be a simple <code>Label</code> <code>SkinPart</code>, but it&#8217;s visibility is complicated enough that it makes sense to add a new <code>prompting</code> <code>SkinState</code>.</p>
<p class="bottom">Here&#8217;s a functioning <code>PromptingTextInput</code> custom component (which is simply the prompting code lifted from <code>SuperTextInput.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package components <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">FocusEvent</span>;
    <span style="color: #0066CC;">import</span> mx.<span style="color: #006600;">events</span>.<span style="color: #006600;">FlexEvent</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Label</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">TextInput</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">events</span>.<span style="color: #006600;">TextOperationEvent</span>;
&nbsp;
    <span style="color: #66cc66;">&#91;</span>SkinState<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;prompting&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> PromptingTextInput <span style="color: #0066CC;">extends</span> TextInput <span style="color: #66cc66;">&#123;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> promptDisplay:Label;
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _prompt:<span style="color: #0066CC;">String</span> = <span style="color: #ff0000;">''</span>;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _focused:<span style="color: #0066CC;">Boolean</span> = <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> PromptingTextInput<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for programmatic changes to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>FlexEvent.<span style="color: #006600;">VALUE_COMMIT</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for user changes (aka typing) to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>TextOperationEvent.<span style="color: #006600;">CHANGE</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>Bindable<span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> prompt<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">return</span> _prompt;
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> prompt<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">String</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_prompt <span style="color: #66cc66;">!</span>= value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                _prompt = value;
                <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>promptDisplay <span style="color: #66cc66;">!</span>= <span style="color: #000000; font-weight: bold;">null</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                    promptDisplay.<span style="color: #0066CC;">text</span> = value;
                <span style="color: #66cc66;">&#125;</span>
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> textChangedHandler<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:Event<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> focusInHandler<span style="color: #66cc66;">&#40;</span>event:FocusEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">focusInHandler</span><span style="color: #66cc66;">&#40;</span>event<span style="color: #66cc66;">&#41;</span>;
            _focused = <span style="color: #000000; font-weight: bold;">true</span>;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
        override protected <span style="color: #000000; font-weight: bold;">function</span> focusOutHandler<span style="color: #66cc66;">&#40;</span>event:FocusEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">focusOutHandler</span><span style="color: #66cc66;">&#40;</span>event<span style="color: #66cc66;">&#41;</span>;
            _focused = <span style="color: #000000; font-weight: bold;">false</span>;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == promptDisplay<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                promptDisplay.<span style="color: #0066CC;">text</span> = prompt;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>prompt.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> == <span style="color: #cc66cc;">0</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #66cc66;">!</span>_focused<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                <span style="color: #b1b100;">return</span> <span style="color: #ff0000;">'prompting'</span>;
            <span style="color: #66cc66;">&#125;</span>
            <span style="color: #b1b100;">return</span> <span style="color: #0066CC;">super</span>.<span style="color: #006600;">getCurrentSkinState</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>In addition to the <code>promptDisplay</code> <code>SkinPart</code> and the new <code>prompting</code> <code>SkinState</code>, there is a lot of other stuff going on in the above code.  First, as is typical with data-driven <code>SkinPart</code>s, we back the <code>promptDisplay</code> with a good old <code>prompt</code> property.  The net is the fairly common pattern of: check if the <code>SkinPart</code> is not null, then do something to it.  So in the <code>prompt</code> setter, we assign the incoming value to the private <code>_prompt</code> variable, then check if <code>promptDisplay</code> is available and if yes, set it&#8217;s <code>text</code> property.  The setter does the job of updating the prompt, but only once everything is happily running.  In order to get the data to the skin initially, we must use the <code>partAdded()</code> override to pass the local prompt to the <code>promptDisplay</code>&#8216;s <code>text</code> property.  And that&#8217;s it for the prompt text.</p>
<p>The prompt visibility part requires lots of event watching, and also <code>SkinState</code> stuff because we made the choice to push visibility via the <code>prompting</code> <code>SkinState</code>.  First, we wire up both the programmatic text change events and the user text change events to a handler, <code>textChangedHandler()</code>, that does nothing more than invalidate the state.  <code>TextInput</code> change events are a <a href="http://stackoverflow.com/questions/283497/capturing-user-input-from-flex-textinput-control-which-event-to-use">little wacky</a>, but the code works fine.  Next, instead of wiring the focus events to another handler (as seen in this <a href="http://www.andymcintosh.com/?p=207">prompting <code>TextInput</code> component</a> by Andy McIntosh), we simply override the protected handlers in the parent and add our focus-tracking logic directly.  Finally, we override <code>getCurrentSkinState()</code> to do the work of figuring out whether or not the prompt should be displayed.</p>
<p class="bottom">A skin for <code>PromptingTextInput</code> is now trivial because our component does the work of pushing the important information to the skin.  If we ignore all the pretty stuff, the skin is very simple:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SparkSkin</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;prompting&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichEditableText</span> id=<span style="color: #ff0000;">&quot;textDisplay&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> id=<span style="color: #ff0000;">&quot;promptDisplay&quot;</span> includeIn=<span style="color: #ff0000;">&quot;prompting&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SparkSkin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We add the <code>prompting</code> <code>State</code> to the list of states and also add the <code>promptDisplay</code> <code>Label</code> component.  By using the standard inline state syntax, <code>includeIn=&quot;prompting&quot;</code> our <code>Label</code> is shown only in the <code>prompting</code> state.</p>
<h3>A Clearable TextInput</h3>
<p>The second piece of SuperTextInput functionality is the clear button.  The clear button appears when the <code>TextInput</code> has a value, and when clicked, it clears that value (which re-displays the prompt).  Again, there are two pieces of information the need to be communicated to the skin to create the clear button functionality: the button itself and it&#8217;s visibility.  In this case, since the visibility is so simple (on if <code>TextInput</code> has a value, otherwise off), we&#8217;ll just punt and manage it directly in the component.  Therefore, the only a <code>Button</code> <code>SkinPart</code> for the clear button will be pushed to the skin.</p>
<p class="bottom">Here&#8217;s a functioning <code>ClearableTextInput</code> custom component (which is simply the clear button code lifted from <code>SuperTextInput.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package components <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">Event</span>;
    <span style="color: #0066CC;">import</span> flash.<span style="color: #006600;">events</span>.<span style="color: #006600;">MouseEvent</span>;
    <span style="color: #0066CC;">import</span> mx.<span style="color: #006600;">events</span>.<span style="color: #006600;">FlexEvent</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #0066CC;">Button</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">TextInput</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">events</span>.<span style="color: #006600;">TextOperationEvent</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> ClearableTextInput <span style="color: #0066CC;">extends</span> TextInput <span style="color: #66cc66;">&#123;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> clearButton:<span style="color: #0066CC;">Button</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> ClearableTextInput<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for programmatic changes to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>FlexEvent.<span style="color: #006600;">VALUE_COMMIT</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #808080; font-style: italic;">//watch for user changes (aka typing) to text property</span>
            <span style="color: #0066CC;">this</span>.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>TextOperationEvent.<span style="color: #006600;">CHANGE</span>, textChangedHandler, <span style="color: #000000; font-weight: bold;">false</span>, <span style="color: #cc66cc;">0</span>, <span style="color: #000000; font-weight: bold;">true</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> textChangedHandler<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:Event<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #0066CC;">visible</span> = <span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> clearClick<span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">e</span>:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">text</span> = <span style="color: #ff0000;">''</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clearClick<span style="color: #66cc66;">&#41;</span>;
                clearButton.<span style="color: #0066CC;">visible</span> = <span style="color: #66cc66;">&#40;</span><span style="color: #0066CC;">text</span> <span style="color: #66cc66;">!</span>= <span style="color: #000000; font-weight: bold;">null</span> <span style="color: #66cc66;">&amp;&amp;</span> <span style="color: #0066CC;">text</span>.<span style="color: #0066CC;">length</span> <span style="color: #66cc66;">&gt;</span> <span style="color: #cc66cc;">0</span><span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == clearButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                clearButton.<span style="color: #006600;">removeEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clearClick<span style="color: #66cc66;">&#41;</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>After the <code>PromptingTextInput</code>, the <code>ClearableTextInput</code> is a little more straightforward.  First, we have the <code>clearButton</code> <code>SkinPart</code> and it&#8217;s <code>clearClick()</code> event handler.  Wiring the handler function to the button is done in the <code>partAdded()</code> override, and un-wiring in the <code>partRemoved()</code> override.  Next, button visibility is managed by watching for both programmatic text change events and user text change events.  The handler, <code>textChangedHandler()</code>, sets the button as visible when the control has text in it.</p>
<p>As I mentioned above, I decided against pushing the <code>clearButton</code>&#8216;s visibility down to the skin via a <code>SkinState</code>, and instead chose to manage it inside the component by setting <code>clearButton.visible</code> directly.  I tend to favor the <code>SkinState</code> method when more than one thing needs to change in the skin or if I need advanced visuals (like transitions).  If I need to do just one thing and I don&#8217;t care about visuals, I&#8217;ll do it inside the component.  The two examples here aren&#8217;t the best to illustrate the two options, but that&#8217;s my general thought process when building a custom component and custom skin.</p>
<p class="bottom">A skin for <code>ClearingTextInput</code> is super trivial.  Again, ignoring all the pretty stuff, the skin is:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SparkSkin</span> ...<span style="color: #7400FF;">&gt;</span></span>
    ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichEditableText</span> id=<span style="color: #ff0000;">&quot;textDisplay&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Button</span> id=<span style="color: #ff0000;">&quot;clearButton&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SparkSkin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Just add the <code>clearButton</code> <code>Button</code> and position it.</p>
<h3>Fusion, Glorious Fusion</h3>
<p>The fusion process of creating <code>SuperTextInput</code> from <code>PromptingTextInput</code> and <code>ClearableTextInput</code> is nothing more than copy and paste.  <code>SuperTextInput</code> has lots of uses, but my favorite is to use it to capture text input to filter a list.  It also works great as a search box, or in any smart form UI.  Enjoy.</p>
<p class="bottom">Here&#8217;s the finished product showing all three custom components skinned and ready for action (view source enabled):</p>
<div id="flashcontent-supertextinput">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/super_text_input/SuperTextInput.html">SuperTextInput</a> (<a href="http://saturnboy.com/proj/flex4/super_text_input/srcview/SuperTextInput.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/super_text_input/SuperTextInput.swf', 'flashcontent-supertextinput', '240', '94', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/07/supertextinput-building-a-custom-component/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Building Flex 4 Containers with Multiple Content Areas</title>
		<link>http://saturnboy.com/2010/07/multiple-content-area-containers/</link>
		<comments>http://saturnboy.com/2010/07/multiple-content-area-containers/#comments</comments>
		<pubDate>Thu, 15 Jul 2010 22:48:18 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1454</guid>
		<description><![CDATA[Back in the days of Flex 3, if you wanted multiple content areas in your main application, you&#8217;d need to arrange some set of containers (Canvas, HBox, VBox) in the app and fill them with content. It was just your basic Flex 3 development process. The danger, of course, is that you are mixing content [...]]]></description>
			<content:encoded><![CDATA[<p>Back in the days of Flex 3, if you wanted multiple content areas in your main application, you&#8217;d need to arrange some set of containers (<code>Canvas</code>, <code>HBox</code>, <code>VBox</code>) in the app and fill them with content.  It was just your basic Flex 3 development process.  The danger, of course, is that you are mixing content with presentation, aka bad separation of concerns.  Today, with the power of Flex 4 skins, we can avoid this issue by moving the presentation layer into a skin (or set of skins).  And thus, we can do a much better job achieving a happy level of separation of concerns.</p>
<h3>The Flex 3 Way</h3>
<p class="bottom">To give a concrete example, I&#8217;ll build a blog layout (yes, another blog layout) with a header, footer, sidebar, and main content areas.  But before we get started, let&#8217;s review the old Flex 3 way:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:HBox</span> id=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Image</span> source=<span style="color: #ff0000;">&quot;@Embed('assets/logo.png')&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:HBox</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> id=<span style="color: #ff0000;">&quot;body&quot;</span> width=<span style="color: #ff0000;">&quot;800&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;main content&quot;</span> width=<span style="color: #ff0000;">&quot;600&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VBox</span> id=<span style="color: #ff0000;">&quot;sidebar&quot;</span> x=<span style="color: #ff0000;">&quot;600&quot;</span> width=<span style="color: #ff0000;">&quot;200&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;Sidebar&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;sidebar content&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:VBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VBox</span> id=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Text</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:VBox</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The above code comes from a previous post, <a href="http://saturnboy.com/2009/02/designing-in-flex/">Designing in Flex 3</a>, but has been modified to make sense here.  You&#8217;ve got you basic blog design: a box for the header, footer, and body, where body is subsequently is divided into a main content area and a sidebar.</p>
<h3>The 3-in-4 Way, aka The Wrong Way</h3>
<p>The unfortunate next step in a Flex developer&#8217;s evolution is what I like to call the Flex 3-in-4 way.  This is a the way of neanderthals,  which is to say, it is an evolutionary dead end.  If you ever have the bad luck to see 3-in-4 code, you can be sure you are dealing with a novice Flex 4 developer.  In general, the 3-in-4 way consists of making the simple transcription: <code>Canvas</code> &rarr; <code>Group</code>, <code>HBox</code> &rarr; <code>HGroup</code>, <code>VBox</code> &rarr; <code>VGroup</code>.  But the most damning tipoff of a 3-in-4 developer is the assertion that one is now a Flex 4 developer and the learning curve wasn&#8217;t all that bad.  While I do think Flex 4 is more of an evolutionary release than a revolutionary release, it&#8217;s different enough.  And it is particularly different on the design side of the framework, how it handles skins, layout, etc.</p>
<p class="bottom">If we just transcribe the above example, we get some classic 3-in-4 code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:HGroup</span> id=<span style="color: #ff0000;">&quot;header&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Multi Content Area Example&quot;</span> styleName=<span style="color: #ff0000;">&quot;header&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:HGroup</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;body&quot;</span> width=<span style="color: #ff0000;">&quot;800&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;main content&quot;</span> width=<span style="color: #ff0000;">&quot;600&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> x=<span style="color: #ff0000;">&quot;600&quot;</span> width=<span style="color: #ff0000;">&quot;200&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebarBox&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Sidebar&quot;</span> styleName=<span style="color: #ff0000;">&quot;title&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;sidebar content&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebar&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Group</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> id=<span style="color: #ff0000;">&quot;footer&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>*Barf*, please <b>not</b> do this.  This code has all the same issues as the Flex 3 code in the first example, and moreover it is a slap in the face of <i>The Flex 4 Way</i> and all of its improvements.</p>
<h3>The Flex 4 Way</h3>
<p>Yes, there is a Flex 4 Way and it looks like this.</p>
<p class="bottom">First, we rewrite the main app using a custom container.  Ignoring the specifics of the custom container for a moment, here is the re-written main app (minus some clutter):</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:headerContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;Multi Content Area Example&quot;</span> styleName=<span style="color: #ff0000;">&quot;header&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:headerContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:sidebarContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichText</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span> styleName=<span style="color: #ff0000;">&quot;sidebar&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:content</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span> fontSize=<span style="color: #ff0000;">&quot;20&quot;</span><span style="color: #7400FF;">&gt;</span></span>Sidebar<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span><span style="color: #7400FF;">&gt;</span></span>sidebar content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:content</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:RichText</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:sidebarContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:footerContent</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Label</span> text=<span style="color: #ff0000;">&quot;2010 saturnboy&quot;</span> styleName=<span style="color: #ff0000;">&quot;footer&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:footerContent</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RichText</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:content</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span> fontSize=<span style="color: #ff0000;">&quot;30&quot;</span><span style="color: #7400FF;">&gt;</span></span>Content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:p</span><span style="color: #7400FF;">&gt;</span></span>main content<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:p</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:content</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:RichText</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>As you can see, the main app is now a nice set of semantic buckets, one for each of the content areas.  Header stuff goes in the <code>headerContent</code> bucket, footer stuff goes in the <code>footerContent</code> bucket, etc.</p>
<h3>Building a Multi Content Area Container</h3>
<p>Second, we need to create a custom container with the nice set of semantic buckets used in the above code.  This is achieved by following a straightforward formula:</p>
<ol>
<li><b>Extend SkinnableContainer</b> &ndash; Extend <code>SkinnableContainer</code> or some child class.  In our sample app, our custom container extends <code>Application</code> (which extends <code>SkinnableContainer</code>).</li>
<li><b>Add Buckets</b> &ndash; add some content buckets (in the form of <i>xxx</i><code>Content</code>) as <code>Array</code>s.  These become the MXML tags used to bucket components together.  Each content bucket has a public getter, but most importantly a public setter that accepts an incoming <code>Array</code> of <code>IVisualElement</code>s and uses the magical <code>mxmlContent</code> property to assign it to the associated <code>SkinPart</code>.</li>
<li><b>Add SkinParts</b> &ndash; add some matching SkinParts (in the form of <i>xxx</i><code>Group</code>) as spark <code>Group</code>s.  There are used in the custom skin to display the content.  Also, I usually set <code>required=&quot;false&quot;</code> to make everything optional.</li>
<li><b>Add partAdded() &amp; partRemoved()</b> &ndash; override the new Flex 4 skinning lifecycle methods to wire the incoming content to the outgoing <code>SkinPart</code>.</li>
</ol>
<p class="bottom">The custom component code is actually easier to follow then the description.  Here is a custom container with only one additional content bucket, <code>sidebarContent</code>, and its matching <code>SkinPart</code>, <code>sidebarGroup</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;">package containers <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Group</span>;
    <span style="color: #0066CC;">import</span> spark.<span style="color: #006600;">components</span>.<span style="color: #006600;">Application</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> MainApp <span style="color: #0066CC;">extends</span> Application <span style="color: #66cc66;">&#123;</span>
        <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> sidebarGroup:Group;
&nbsp;
        <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _sidebarContent:<span style="color: #0066CC;">Array</span> = <span style="color: #66cc66;">&#91;</span><span style="color: #66cc66;">&#93;</span>;
&nbsp;
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> MainApp<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        <span style="color: #66cc66;">&#91;</span>ArrayElementType<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;mx.core.IVisualElement&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> sidebarContent<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">Array</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #b1b100;">return</span> _sidebarContent;
        <span style="color: #66cc66;">&#125;</span>
        <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> sidebarContent<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">Array</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            _sidebarContent = value;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = value;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = _sidebarContent;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
&nbsp;
        override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
            <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
&nbsp;
            <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == sidebarGroup<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
                sidebarGroup.<span style="color: #006600;">mxmlContent</span> = <span style="color: #000000; font-weight: bold;">null</span>;
            <span style="color: #66cc66;">&#125;</span>
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>Following the four steps: we extend <code>Application</code>, have a <code>sidebarContent</code> bucket and its associated <code>sidebarGroup</code> <code>SkinPart</code>, and override <code>partAdded()</code> and <code>partRemoved()</code> to wire everything together.</p>
<h3>Skinning a Multi Content Area Container</h3>
<p>Skinning in Flex 4 is awesome, and like everyone says, it&#8217;s easily one of the best new features in the framework.  While I find the skinning process fairly straightforward, I would never call it trivial, mostly due to the depth and flexibility of the skinning system.</p>
<p>We need a custom skin for our custom multi content area component.  This is probably the 10% case for skinning, but it&#8217;s also the coolest.  In my experience, an average Flex 4 app has many <code>Button</code> skins (like 10 or even 20), a few default component skins (skins for <code>List</code>, <code>DropDownList</code>, <code>TextInput</code>, etc.), and maybe only two or three skins for custom components.</p>
<p>The skin itself is nothing special.  To display our custom component&#8217;s <code>SkinPart</code>s, we simply include a <code>Group</code> with the matching <code>id</code> attribute.  For example, our skin will include a <code>&lt;s:Group id="sidebarGroup" /&gt;</code> to display the <code>sidebarGroup</code> <code>SkinPart</code>.  Just rinse, wash, repeat, to add all of our custom content areas in the container to the skin.</p>
<p class="bottom">Here is a trivial skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ... <span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;containers.MainApp&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span> 
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:VGroup</span> left=<span style="color: #ff0000;">&quot;40&quot;</span> right=<span style="color: #ff0000;">&quot;40&quot;</span> top=<span style="color: #ff0000;">&quot;40&quot;</span> bottom=<span style="color: #ff0000;">&quot;40&quot;</span> gap=<span style="color: #ff0000;">&quot;20&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;headerGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;contentGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;sidebarGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;footerGroup&quot;</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:VGroup</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>In this trivial skin, we just shove all the content groups (including <code>SkinnableContainer</code>&#8216;s default <code>Group</code>, <code>contentGroup</code>) into a <code>VGroup</code>.  Also note, we correctly set <code>HostComponent</code> to our custom container.  If you are thinking, &quot;Hey, this skin looks similar to the Flex 3 and 3-in-4 example code, just minus the content&quot; that&#8217;s exactly the point.</p>
<p class="bottom">Lastly, we wire out skin to our custom component via CSS:</p>

<div class="wp_syntax"><div class="code"><pre class="css" style="font-family:monospace;">containers|MainApp <span style="color: #00AA00;">&#123;</span>
    skinClass<span style="color: #00AA00;">:</span>ClassReference<span style="color: #00AA00;">&#40;</span><span style="color: #ff0000;">'skins.TrivialAppSkin'</span><span style="color: #00AA00;">&#41;</span><span style="color: #00AA00;">;</span>
<span style="color: #00AA00;">&#125;</span></pre></div></div>

<p>Using <code>skinClass</code> to wire a skin to a component is <b>so</b> 2009.  The sample app has its CSS inline, but in any real app I&#8217;ll always put this in an external file.</p>
<h3>Conclusion</h3>
<p>After this, there&#8217;s really not much more to say.  You can certainly create a more complicated arrangement of the multiple content areas by making a more complicated skin.  I&#8217;ve done exactly this in the final sample, which includes three different skins and a skin switcher (click 1, 2, or 3 to switch skins).</p>
<p>&raquo; <a href="http://saturnboy.com/proj/flex4/multi_content_area/MultiContentArea.html">view MultiConentArea sample</a> (view source enabled)</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/multi_content_area/MultiContentArea.html">MultiContentArea</a> (<a href="http://saturnboy.com/proj/flex4/multi_content_area/srcview/MultiContentArea.zip">download</a>)</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/07/multiple-content-area-containers/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Drawer Component in Flex 4</title>
		<link>http://saturnboy.com/2010/06/drawer-component-flex-4/</link>
		<comments>http://saturnboy.com/2010/06/drawer-component-flex-4/#comments</comments>
		<pubDate>Wed, 02 Jun 2010 04:31:09 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[custom component]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[flexlib]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=1418</guid>
		<description><![CDATA[I needed a good way to have a large settings panel with a minimal visual impact. The obvious answer is to hide or minimize or collapse the settings panel when not in use. I thought about using Flexlib&#8216;s WindowShade component (which I&#8217;ve dicussed in detail in Styling Flexlib&#8217;s WindowShade), but why reuse something when you [...]]]></description>
			<content:encoded><![CDATA[<p>I needed a good way to have a large settings panel with a minimal visual impact.  The obvious answer is to hide or minimize or collapse the settings panel when not in use.  I thought about using <a href="http://code.google.com/p/flexlib/">Flexlib</a>&#8216;s WindowShade component (which I&#8217;ve dicussed in detail in <a href="http://saturnboy.com/2009/03/styling-flexlib-windowshade/">Styling Flexlib&#8217;s WindowShade</a>), but why reuse something when you can reinvent the wheel?  Plus, it always helps to hone my Flex 4 custom component kung-fu.  So, I chose to implement a simple sliding drawer component from scratch as a Flex 4 component.</p>
<p class="bottom">The Drawer component is a vanilla container (it actually extends <code>SkinnableContainer</code>), so it will happily take any spark component for its children.  Before I dive into my implementation, let&#8217;s check out the finished drawer component in action (view source enabled):</p>
<div id="flashcontent-drawer" style="background-color:#eee">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p> Just click on the handle to open and close the drawer.</p>
<h3>Extending <code>SkinnableContainer</code></h3>
<p>The Drawer component itself, is just pure AS3, but the demo above uses a few MXML skins to achieve the desired look-and-feel.  This is a pretty standard pattern that I see during Flex 4 development, so expect it when you write your own custom components.</p>
<p class="bottom">We&#8217;ll review the component implementation in two steps.  First, we focus on the skin state management aspect of the drawer.  Here&#8217;s the relevant code (taken from <code>Drawer.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #66cc66;">&#91;</span>SkinState<span style="color: #66cc66;">&#40;</span><span style="color: #ff0000;">&quot;opened&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
<span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Drawer <span style="color: #0066CC;">extends</span> SkinnableContainer <span style="color: #66cc66;">&#123;</span>
    <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">var</span> _opened:<span style="color: #0066CC;">Boolean</span> = <span style="color: #000000; font-weight: bold;">false</span>;
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">get</span> opened<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">Boolean</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">return</span> _opened;
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">function</span> <span style="color: #0066CC;">set</span> opened<span style="color: #66cc66;">&#40;</span>value:<span style="color: #0066CC;">Boolean</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>_opened <span style="color: #66cc66;">!</span>= value<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            _opened = value;
            invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">String</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #b1b100;">return</span> <span style="color: #66cc66;">&#40;</span>opened ? <span style="color: #ff0000;">'opened'</span> : <span style="color: #0066CC;">super</span>.<span style="color: #006600;">getCurrentSkinState</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span>
    ...
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The <code>Drawer</code> component can either be closed (the default) or opened.  To model theses states, we use the <code>normal</code> state from the superclass to represent the closed drawer, and add a new <code>opened</code> <code>SkinState</code> to represent the opened drawer.  We just expose a simple <code>opened</code> boolean property with a custom getter and setter, and then override the <code>getCurrentSkinState()</code> method.  It&#8217;s important to remember the states we are talking about are skin states, and not <i>component</i> states (see <a href="http://saturnboy.com/2009/09/flex4-component-states-skin-states/">Flex 4 Component States vs. Skin States</a> for the difference).</p>
<p class="bottom">Second, we focus on the action of opening and closing the drawer.  Here&#8217;s the relevant code (taken from <code>Drawer.as</code>):</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">class</span> Drawer <span style="color: #0066CC;">extends</span> SkinnableContainer <span style="color: #66cc66;">&#123;</span>
    ...
    <span style="color: #66cc66;">&#91;</span>SkinPart<span style="color: #66cc66;">&#40;</span>required=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #66cc66;">&#41;</span><span style="color: #66cc66;">&#93;</span>
    <span style="color: #0066CC;">public</span> <span style="color: #000000; font-weight: bold;">var</span> openButton:<span style="color: #0066CC;">Button</span>;
&nbsp;
    <span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> clickHandler<span style="color: #66cc66;">&#40;</span>event:MouseEvent<span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        opened = <span style="color: #66cc66;">!</span>opened;
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> partAdded<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partAdded</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == openButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            openButton.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clickHandler<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
&nbsp;
    override protected <span style="color: #000000; font-weight: bold;">function</span> partRemoved<span style="color: #66cc66;">&#40;</span>partName:<span style="color: #0066CC;">String</span>, instance:<span style="color: #0066CC;">Object</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
        <span style="color: #0066CC;">super</span>.<span style="color: #006600;">partRemoved</span><span style="color: #66cc66;">&#40;</span>partName, instance<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>instance == openButton<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
            openButton.<span style="color: #006600;">removeEventListener</span><span style="color: #66cc66;">&#40;</span>MouseEvent.<span style="color: #006600;">CLICK</span>, clickHandler<span style="color: #66cc66;">&#41;</span>;
        <span style="color: #66cc66;">&#125;</span>
    <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The <code>Drawer</code> component includes a simple spark button, as an optional <code>SkinPart</code>, that is used to initiate the state change.  The <code>partAdded()</code> and <code>partRemoved()</code> methods are overridden to manage and adding and removing of the button&#8217;s click event handler.  And lastly, the <code>clickHandler()</code> method flips between skin states by toggling the <code>opened</code> boolean property.</p>
<h3>Usage</h3>
<p class="bottom">Using the <code>Drawer</code> is the same as any container.  In MXML, just put any child components you want between the container&#8217;s open and close tags:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;containers:Drawer</span> ... skinClass=<span style="color: #ff0000;">&quot;skins.DrawerSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- components go here --&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/containers:Drawer</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Here we also apply the <code>DrawerSkin</code> to our container.</p>
<h3>Skins</h3>
<p class="bottom">The <code>DrawerSkin</code> is responsible for creating the desired look-and-feel and generally making the <code>Drawer</code> component look cool.  Here are the interesting parts of the skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;containers.Drawer&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;opened&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;disabled&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
   ...
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Button</span> id=<span style="color: #ff0000;">&quot;openButton&quot;</span> ...</span>
<span style="color: #000000;">            skinClass=<span style="color: #ff0000;">&quot;skins.DrawerOpenButtonSkin&quot;</span></span>
<span style="color: #000000;">            skinClass.opened=<span style="color: #ff0000;">&quot;skins.DrawerCloseButtonSkin&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Group</span> id=<span style="color: #ff0000;">&quot;contentGroup&quot;</span> ... includeIn=<span style="color: #ff0000;">&quot;opened&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The <code>DrawerSkin</code> has three skin states, <code>normal</code> and <code>disabled</code> are inherited from <code>SkinnableContainer</code>, but <code>opened</code> is our custom skin state.  The skin also includes the optional <code>openButton</code> <code>SkinPart</code>, which itself uses two custom buttons skins, one for the open drawer and one for the closed drawer.  Lastly, note that the container&#8217;s content is only displayed when the skin is in the <code>opened</code> state via the newfangled inline state syntax: <code>includeIn=&quot;opened&quot;</code>.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/drawer/Drawer.html">Drawer</a> (<a href="http://saturnboy.com/proj/flex4/drawer/srcview/Drawer.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/drawer/Drawer.swf', 'flashcontent-drawer', '520', '340', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#eeeeee', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2010/06/drawer-component-flex-4/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Flex 4 Component States vs. Skin States</title>
		<link>http://saturnboy.com/2009/09/flex4-component-states-skin-states/</link>
		<comments>http://saturnboy.com/2009/09/flex4-component-states-skin-states/#comments</comments>
		<pubDate>Sun, 20 Sep 2009 19:14:39 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[flex4]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=692</guid>
		<description><![CDATA[Flex 4 introduced an awesome new skinning architecture. Among other things, the new architecture provides significantly better separation between a component and its skin. Flex 4 also promotes the use of states to the point where they are virtually mandatory in any non-trivial app. And that brings us to the question of the day: How [...]]]></description>
			<content:encoded><![CDATA[<p>Flex 4 introduced an awesome new skinning architecture.  Among other things, the new architecture provides significantly better separation between a component and its skin. Flex 4 also promotes the use of states to the point where they are virtually mandatory in any non-trivial app. And that brings us to the question of the day:</p>
<blockquote><p><b>How do you communicate state information from the host component down to its skin?</b></p></blockquote>
<p class="bottom">As always, we&#8217;ll dive into some examples to explore how things work. In our first example, we just want our skin to <i>mirror</i> the states of its host component.  So, we begin with a simple component based on <code>SkinnableComponent</code>. And then we add three states: <code>base</code>, <code>happy</code>, <code>sad</code>. The code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SkinnableComponent</span></span>
<span style="color: #000000;">        xmlns:fx=<span style="color: #ff0000;">&quot;http://ns.adobe.com/mxml/2009&quot;</span></span>
<span style="color: #000000;">        xmlns:s=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/spark&quot;</span></span>
<span style="color: #000000;">        skinClass=<span style="color: #ff0000;">&quot;skins.SmileySkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;base&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;happy&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;sad&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SkinnableComponent</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Right now our component is just a bag of states.  But going forward, we know we want to skin it with skin that has same three states. So we force the skin state to mirror the host state with three simple steps:</p>
<ol>
<li><b>SkinState</b> &#8211; Add <code>SkinState</code> metadata to the host component.</li>
<li><b>getCurrentSkinState()</b> &#8211; Override the <code>getCurrentSkinState()</code> method to return the host&#8217;s <code>currentState</code>. (This is the <em>mirror</em>!)</li>
<li><b>invalidateSkinState()</b> &#8211; Force the skin state to update by calling <code>invalidateSkinState()</code> every time the host&#8217;s state changes.</li>
</ol>
<p class="bottom">Implementing these changes, we arrive at:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SkinnableComponent</span></span>
<span style="color: #000000;">        xmlns:fx=<span style="color: #ff0000;">&quot;http://ns.adobe.com/mxml/2009&quot;</span></span>
<span style="color: #000000;">        xmlns:s=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/spark&quot;</span></span>
<span style="color: #000000;">        skinClass=<span style="color: #ff0000;">&quot;skins.SmileySkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [SkinState(&quot;base&quot;)]
        [SkinState(&quot;happy&quot;)]
        [SkinState(&quot;sad&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;!<span style="color: #66cc66;">&#91;</span>CDATA<span style="color: #66cc66;">&#91;</span></span>
<span style="color: #000000;">            override protected function getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:String <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                return currentState;</span>
<span style="color: #000000;">            <span style="color: #66cc66;">&#125;</span></span>
<span style="color: #000000;">        <span style="color: #66cc66;">&#93;</span><span style="color: #66cc66;">&#93;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;base&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;happy&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;sad&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SkinnableComponent</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>Step 1 is straightforward.  In Step 2, we override and return <code>currentState</code>.  And Step 3 is achieved by calling <code>invalidateSkinState()</code> directly in each state&#8217;s <code>enterState</code> event handler.  So to answer our original question: skin state is literally communicated from the host component down to the skin via the <code>getCurrentSkinState()</code> method.  If we pass in <code>currentState</code> then we get a perfect state mirror (aka skin state = host component state).</p>
<p class="bottom">We finish off our example app by adding a silly yellow smiley face skin and a simple main app to hold our component.  Here it is (view source enabled):</p>
<div id="flashcontent-smiley-states">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>Use the <code>ButtonBar</code> to change the component&#8217;s state.  Check the source to see the trivial FXG used to draw the smiley face.</p>
<h5>ItemRenderer States</h5>
<p>All of this has been leading up to my typical case. I have a nice custom component with a nice skin (maybe I built my component and skin in <a href="http://labs.adobe.com/technologies/flashcatalyst/">Flash Catalyst</a> or maybe I built them by hand). Then I suddenly realize, <i>Damn!</i>, I need to use my component in an <code>ItemRenderer</code>. So how do I go about hooking up the standard <code>ItemRenderer</code> states (<code>normal</code>, <code>hovered</code>, <code>selected</code>) to my custom component?</p>
<p>Before I get to the answer, let&#8217;s rewind a little bit to set the scene.  Imagine I have a component that displays a grade, and I want to display a different graphical treatment depending on the grade.  The Flex implementation is the standard stateless custom component with a multi-state skin (<code>Button</code> is a good example).  A little different that our first example, but our component still need to communicate skin state information down to its skin.</p>
<p class="bottom">Our grade component:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SkinnableComponent</span></span>
<span style="color: #000000;">        xmlns:fx=<span style="color: #ff0000;">&quot;http://ns.adobe.com/mxml/2009&quot;</span></span>
<span style="color: #000000;">        xmlns:s=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/spark&quot;</span></span>
<span style="color: #000000;">        skinClass=<span style="color: #ff0000;">&quot;skins.GradeSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [SkinState(&quot;A&quot;)]
        [SkinState(&quot;B&quot;)]
        [SkinState(&quot;C&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;!<span style="color: #66cc66;">&#91;</span>CDATA<span style="color: #66cc66;">&#91;</span></span>
<span style="color: #000000;">            private var _grade:int = <span style="color: #cc66cc;">0</span>;</span>
&nbsp;
<span style="color: #000000;">            <span style="color: #66cc66;">&#91;</span>Bindable<span style="color: #66cc66;">&#93;</span></span>
<span style="color: #000000;">            public function get grade<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:int <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                return _grade;</span>
<span style="color: #000000;">            <span style="color: #66cc66;">&#125;</span></span>
<span style="color: #000000;">            public function set grade<span style="color: #66cc66;">&#40;</span>value:int<span style="color: #66cc66;">&#41;</span>:void <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                _grade = <span style="color: #66cc66;">&#40;</span>value <span style="color: #7400FF;">&gt;</span></span> 100 ? 100 : value <span style="color: #000000;">&lt; <span style="color: #cc66cc;">0</span> ? <span style="color: #cc66cc;">0</span> : value<span style="color: #66cc66;">&#41;</span>;</span>
<span style="color: #000000;">                invalidateSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;</span>
<span style="color: #000000;">            <span style="color: #66cc66;">&#125;</span></span>
&nbsp;
<span style="color: #000000;">            override protected function getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:String <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                return <span style="color: #66cc66;">&#40;</span>grade <span style="color: #7400FF;">&gt;</span></span>= 90 ? 'A' : grade &gt;= 80 ? 'B' : 'C');
            }
        ]]&gt;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SkinnableComponent</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We followed a similar set of three steps to create this component.  Step 1 is still &#8220;add <code>SkinState</code> metadata&#8221;.  Step 2 is still &#8220;override <code>getCurrentSkinState()</code>&#8221; but this time we return a state based on the value of grade.  Step 3 is still &#8220;force the skin state to change by calling <code>invalidateSkinState()</code>&#8221; but this time we call it in the setter method for grade.  These three steps give us exactly what we want: a host component without any states that changes its skin state depending on the value of grade.</p>
<p class="bottom">The code for our three state skin is here:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;components.Grade&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;A&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;B&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;C&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- gold star --&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Path</span> scaleX=<span style="color: #ff0000;">&quot;0.2655&quot;</span> scaleY=<span style="color: #ff0000;">&quot;0.2655&quot;</span> includeIn=<span style="color: #ff0000;">&quot;A&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Path</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- pink circle --&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Ellipse</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span> top=<span style="color: #ff0000;">&quot;0&quot;</span> bottom=<span style="color: #ff0000;">&quot;0&quot;</span> includeIn=<span style="color: #ff0000;">&quot;B&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Ellipse</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- blue square --&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Rect</span> left=<span style="color: #ff0000;">&quot;0&quot;</span> right=<span style="color: #ff0000;">&quot;0&quot;</span> top=<span style="color: #ff0000;">&quot;0&quot;</span> bottom=<span style="color: #ff0000;">&quot;0&quot;</span> includeIn=<span style="color: #ff0000;">&quot;C&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        ...
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Rect</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SimpleText</span> text=<span style="color: #ff0000;">&quot;{hostComponent.grade}&quot;</span> ... <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>We define our three states and then use a different FXG shape for each state.  A is a gold star, B is a pink circle, and C is a blue square.  We also display the number grade via simple binding to <code>hostComponent.grade</code>.  Alternately, we could have used a <code>SkinPart</code> to pass the grade information down to the skin (<a href="http://blog.digitalbackcountry.com/2009/07/building-custom-components-in-flex-4-skinparts/">here is a good example</a>), but it costs us complexity so I went with the simple binding instead.</p>
<h5>Where I Say, <i>Damn!</i>, ItemRenderer</h5>
<p class="bottom">So, I need to use my nice component in an <code>ItemRenderer</code>.  <i>Damn!</i>, I say.  As a first attempt, we just dump our custom component inside an inline <code>ItemRenderer</code>, like this:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Application</span> ... <span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:List</span> left=<span style="color: #ff0000;">&quot;10&quot;</span> top=<span style="color: #ff0000;">&quot;10&quot;</span> width=<span style="color: #ff0000;">&quot;400&quot;</span> height=<span style="color: #ff0000;">&quot;95&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:ArrayCollection</span> source=<span style="color: #ff0000;">&quot;[95,85,75,5,101,90,80,-1]&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:itemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Component</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;comps:Grade</span> grade=<span style="color: #ff0000;">&quot;{data}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Component</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:itemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:layout</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:HorizontalLayout</span> ... <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:layout</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:List</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">We get a nice app, but it obviously doesn&#8217;t respond to any of the <code>ItemRenderer</code>&#8216;s states.  Here is attempt #1 (view source enabled):</p>
<div id="flashcontent-grade-states-simple">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p class="bottom">For attempt #2, we can respond to the states directly by adding some code inside the inline <code>ItemRenderer</code>.  What code?  Well, filters are the prefect fit in this case.  They provide a nice visual effect (not easily mimicked by JavaScript), and they are very easy to wrap around a component in a non-invasive manner.  Here is the code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;comps:Grade</span> grade=<span style="color: #ff0000;">&quot;{data}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;comps:filters</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:GlowFilter</span> color=<span style="color: #ff0000;">&quot;#000000&quot;</span> includeIn=<span style="color: #ff0000;">&quot;hovered&quot;</span></span>
<span style="color: #000000;">                     alpha=<span style="color: #ff0000;">&quot;0.5&quot;</span> blurX=<span style="color: #ff0000;">&quot;8&quot;</span> blurY=<span style="color: #ff0000;">&quot;8&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:DropShadowFilter</span> includeIn=<span style="color: #ff0000;">&quot;selected&quot;</span></span>
<span style="color: #000000;">                     alpha=<span style="color: #ff0000;">&quot;0.5&quot;</span> blurX=<span style="color: #ff0000;">&quot;8&quot;</span> blurY=<span style="color: #ff0000;">&quot;8&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/comps:filters</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/comps:Grade</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>I love filters, and using them can often save the day and avoid some implementation pain.  But sometimes, it&#8217;s just not enough.  Sometimes, you absolutely must have your custom component (and it&#8217;s skin) respond to the <code>ItermRenderer</code>&#8216;s states.  In those cases, you just need get a little dirty&#8230;</p>
<p class="bottom">For attempt #3 (our final attempt), we need to communicate the <code>ItemRenderer</code>&#8216;s state down to our custom component.  The easiest thing to do is bind our custom component&#8217;s state to the <code>ItemRenderer</code>&#8216;s state.  A simple <code>currentState = "{this.currentState}"</code> does the trick.  Here is the refactored inline <code>ItemRenderer</code> code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;comps:Grade</span> grade=<span style="color: #ff0000;">&quot;{data}&quot;</span> currentState=<span style="color: #ff0000;">&quot;{this.currentState}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:ItemRenderer</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">Now we must add three new states to our custom component, and communicate those states down to our skin.  Again, we revisit our favorite three steps and refactor our custom component like this:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SkinnableComponent</span></span>
<span style="color: #000000;">        xmlns:fx=<span style="color: #ff0000;">&quot;http://ns.adobe.com/mxml/2009&quot;</span></span>
<span style="color: #000000;">        xmlns:s=<span style="color: #ff0000;">&quot;library://ns.adobe.com/flex/spark&quot;</span></span>
<span style="color: #000000;">        skinClass=<span style="color: #ff0000;">&quot;skins.GradeSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [SkinState(&quot;Anormal&quot;)]
        [SkinState(&quot;Ahovered&quot;)]
        [SkinState(&quot;Aselected&quot;)]
        [SkinState(&quot;Bnormal&quot;)]
        [SkinState(&quot;Bhovered&quot;)]
        [SkinState(&quot;Bselected&quot;)]
        [SkinState(&quot;Cnormal&quot;)]
        [SkinState(&quot;Chovered&quot;)]
        [SkinState(&quot;Cselected&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;!<span style="color: #66cc66;">&#91;</span>CDATA<span style="color: #66cc66;">&#91;</span></span>
<span style="color: #000000;">            ... getter and setter for grade, same as before ...</span>
&nbsp;
<span style="color: #000000;">            override protected function getCurrentSkinState<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:String <span style="color: #66cc66;">&#123;</span></span>
<span style="color: #000000;">                return <span style="color: #66cc66;">&#40;</span>grade <span style="color: #7400FF;">&gt;</span></span>= 90 ? 'A' : grade &gt;= 80 ? 'B' : 'C') + currentState;
            }
        ]]&gt;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Script</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;normal&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;hovered&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;selected&quot;</span> enterState=<span style="color: #ff0000;">&quot;invalidateSkinState()&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:SkinnableComponent</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>In Step 1, we added a bunch more <code>SkinState</code> metadata directives.  In Step 2, we simply appended <code>currentState</code> to the string returned by the overridden <code>getCurrentSkinState()</code> method.  The result is 3&#215;3 = 9 skin states (added in Step 1).  In Step 3, we added three new states (mirroring the <code>ItemRenderer</code>&#8216;s states) to our component. And in each <code>enterState</code> event handler, we call <code>invalidateSkinState()</code>.  There are, of course, other ways to do it.  But to me it makes the most conceptual sense to add the new states to our custom component, and then pass them down to the skin.</p>
<p class="bottom">Lastly, we refactor our skin to include all 9 states and respond to them graphically:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Skin</span> ...<span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
        [HostComponent(&quot;components.Grade&quot;)]
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/fx:Metadata</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:states</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Anormal&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;A, normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Ahovered&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;A, hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Aselected&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;A, selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Bnormal&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;B, normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Bhovered&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;B, hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Bselected&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;B, selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Cnormal&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;C, normal&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Chovered&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;C, hovered&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:State</span> name=<span style="color: #ff0000;">&quot;Cselected&quot;</span> stateGroups=<span style="color: #ff0000;">&quot;C, selected&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:states</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:Path</span> scaleX=<span style="color: #ff0000;">&quot;0.2655&quot;</span> scaleY=<span style="color: #ff0000;">&quot;0.2655&quot;</span> includeIn=<span style="color: #ff0000;">&quot;A&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:data</span><span style="color: #7400FF;">&gt;</span></span>...<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:data</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:stroke</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:SolidColorStroke</span> color=<span style="color: #ff0000;">&quot;#000000&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:stroke</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:RadialGradient</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:GradientEntry</span> color=<span style="color: #ff0000;">&quot;#FFCC00&quot;</span> ratio=<span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;s:GradientEntry</span> ratio=<span style="color: #ff0000;">&quot;1&quot;</span></span>
<span style="color: #000000;">                    color=<span style="color: #ff0000;">&quot;#FFCC00&quot;</span></span>
<span style="color: #000000;">                    color.Ahovered=<span style="color: #ff0000;">&quot;#CC0066&quot;</span></span>
<span style="color: #000000;">                    color.Aselected=<span style="color: #ff0000;">&quot;#660033&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:RadialGradient</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:fill</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Path</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    ...
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/s:Skin</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The first thing to note is the use of <code>stateGroups</code>.  And all this time you thought they were useless?  Here they enable us to split our combined states into their component parts, giving a simpler and more understandable set of states: <code>A</code>, <code>B</code>, <code>C</code>, <code>normal</code>, <code>hovered</code>, <code>selected</code>.  In the code, we preserve the original grade to shape mapping (A is still a gold star, etc.), but we&#8217;ve added code to respond to the <code>ItemRenderer</code> states via a color change.</p>
<p class="bottom">It is more interesting to see the result.  So, here is attempt #3 (view source enabled):</p>
<div id="flashcontent-grade-states-complex">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Conclusion</h5>
<p>Remember the three steps to achieve host component to skin state communication and you will live forever in skinning nirvana:</p>
<ol>
<li><b>SkinState</b></li>
<li><b>getCurrentSkinState()</b></li>
<li><b>invalidateSkinState()</b></li>
</ol>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/flex4/skin_states/SmileyStates/SmileyStates.html">SmileyStates</a> (<a href="http://saturnboy.com/proj/flex4/skin_states/SmileyStates/srcview/SmileyStates.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/flex4/skin_states/GradeStatesSimple/GradeStatesSimple.html">GradeStatesSimple</a> (<a href="http://saturnboy.com/proj/flex4/skin_states/GradeStatesSimple/srcview/GradeStatesSimple.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/flex4/skin_states/GradeStatesComplex/GradeStatesComplex.html">GradeStatesComplex</a> (<a href="http://saturnboy.com/proj/flex4/skin_states/GradeStatesComplex/srcview/GradeStatesComplex.zip">download</a>)</li>
</ul>
<blockquote><p><b>NOTE:</b> All code was built with Flash Builder 4 Beta 1.</p></blockquote>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/skin_states/SmileyStates/SmileyStates.swf', 'flashcontent-smiley-states', '180', '80', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script><br />
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/skin_states/GradeStatesSimple/GradeStatesSimple.swf', 'flashcontent-grade-states-simple', '420', '125', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script><br />
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/flex4/skin_states/GradeStatesComplex/GradeStatesComplex.swf', 'flashcontent-grade-states-complex', '420', '125', '10.0.0', 'playerProductInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/09/flex4-component-states-skin-states/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Degrafa Video Player, Part 2</title>
		<link>http://saturnboy.com/2009/06/degrafa-video-player-2/</link>
		<comments>http://saturnboy.com/2009/06/degrafa-video-player-2/#comments</comments>
		<pubDate>Mon, 01 Jun 2009 10:00:57 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[inkscape]]></category>
		<category><![CDATA[open video player]]></category>
		<category><![CDATA[skinning]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=503</guid>
		<description><![CDATA[The plan is simple, take the nice Degrafa-skinned components from Part 1 and assemble them into a video player powered by the OvpNetStream class from the Open Video Player project. Design I knew right away that the design was not going to have any right angles, but I also didn&#8217;t want to go with rounded [...]]]></description>
			<content:encoded><![CDATA[<p>The plan is simple, take the nice <a href="http://www.degrafa.org/">Degrafa</a>-skinned components from <a href="http://saturnboy.com/2009/05/degrafa-video-player-1/">Part 1</a> and assemble them into a video player powered by the <code>OvpNetStream</code> class from the <a href="http://www.openvideoplayer.com/">Open Video Player</a> project.</p>
<h5>Design</h5>
<p class="bottom">I knew right away that the design was not going to have any right angles, but I also didn&#8217;t want to go with rounded rectangles everywhere.  Modern TVs tend to have a lot of soft rounded edges, so I decided to go with a more vintage look.  So I fired up <a href="http://www.inkscape.org/">Inkscape</a> and got to work:</p>
<div class="span-14 top bottom" style="min-height:232px; text-align:center;">
<img src="http://saturnboy.com/wp-content/uploads/2009/06/tv.png" alt="tv" title="tv" width="176" height="222" />
</div>
<p class="bottom">Implementing the video player design above in Degrafa, the cabinet mapped to a <code>RoundedRectangle</code>, and the screen &#038; antenna became <code>Path</code>s.  You can read more about about translating SVG to Degrafa in my <a href="http://saturnboy.com/2009/06/inkscape-svg-degrafa-pathinkscape-svg-degrafa-path/">Inkscape SVG to Degrafa Path</a> article.  But for now, let&#8217;s focus on the resulting Degrafa code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        xmlns:Degrafa=<span style="color: #ff0000;">&quot;http://www.degrafa.com/2007&quot;</span></span>
<span style="color: #000000;">        layout=<span style="color: #ff0000;">&quot;absolute&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:GeometryComposition</span> graphicsTarget=<span style="color: #ff0000;">&quot;{[box]}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- Antenna --&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;...path data...&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:transform</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:TranslateTransform</span> x=<span style="color: #ff0000;">&quot;15&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:transform</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- TV cabinet --&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:RoundedRectangle</span> y=<span style="color: #ff0000;">&quot;144&quot;</span> width=<span style="color: #ff0000;">&quot;350&quot;</span> height=<span style="color: #ff0000;">&quot;300&quot;</span></span>
<span style="color: #000000;">                cornerRadius=<span style="color: #ff0000;">&quot;20&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#333333&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;4&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.4&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:GeometryComposition</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #808080; font-style: italic;">&lt;!-- TV Screen --&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:GeometryComposition</span> graphicsTarget=<span style="color: #ff0000;">&quot;{[tvscreen]}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:Path</span> data=<span style="color: #ff0000;">&quot;...path data...&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidFill</span> color=<span style="color: #ff0000;">&quot;#FF99FF&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:fill</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:SolidStroke</span> color=<span style="color: #ff0000;">&quot;#FF00FF&quot;</span> weight=<span style="color: #ff0000;">&quot;2&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.4&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:stroke</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;Degrafa:filters</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:GlowFilter</span> color=<span style="color: #ff0000;">&quot;#EEEEEE&quot;</span> alpha=<span style="color: #ff0000;">&quot;0.2&quot;</span> blurX=<span style="color: #ff0000;">&quot;16&quot;</span> blurY=<span style="color: #ff0000;">&quot;16&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:filters</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:Path</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/Degrafa:GeometryComposition</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;350&quot;</span> height=<span style="color: #ff0000;">&quot;444&quot;</span></span>
<span style="color: #000000;">            horizontalCenter=<span style="color: #ff0000;">&quot;0&quot;</span> verticalCenter=<span style="color: #ff0000;">&quot;0&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> id=<span style="color: #ff0000;">&quot;box&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> x=<span style="color: #ff0000;">&quot;50&quot;</span> y=<span style="color: #ff0000;">&quot;174&quot;</span> id=<span style="color: #ff0000;">&quot;tvscreen&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Canvas</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>I ended up using a pair of <code>GeometryComposition</code>s to wrap my three shapes to help keep my fills, strokes, and filters organized.  It made sense to do it this way, but I won&#8217;t claim it&#8217;s the best way.  Throw the control bar on below the TV screen, and the design is done.</p>
<h5>Backend</h5>
<p>The backend is build on the <code>OvpNetStream</code> class provided by the Open Video Player project.  <code>OvpNetStream</code> extends <code>NetStream</code> and smooths out some of the rough edges as I <a href="http://saturnboy.com/2009/04/open-video-player-air/">discussed</a> previously.  Basically, it provides a sane interface (no need to construct a dynamic object with function callbacks) and useful events (like metadata and progress events).</p>
<p class="bottom">For this demo, we simply instantiate <code>OvpNetStream</code> on <code>creationComplete</code> and wire up all the event handlers:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> complete<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    nc = <span style="color: #000000; font-weight: bold;">new</span> OvpConnection<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #0066CC;">ERROR</span>, errorHandler<span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>NetStatusEvent.<span style="color: #006600;">NET_STATUS</span>, connStatusHandler<span style="color: #66cc66;">&#41;</span>;
    nc.<span style="color: #0066CC;">connect</span><span style="color: #66cc66;">&#40;</span><span style="color: #000000; font-weight: bold;">null</span><span style="color: #66cc66;">&#41;</span>;
&nbsp;
    ns = <span style="color: #000000; font-weight: bold;">new</span> OvpNetStream<span style="color: #66cc66;">&#40;</span>nc<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #0066CC;">ERROR</span>, errorHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>NetStatusEvent.<span style="color: #006600;">NET_STATUS</span>, streamStatusHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">NETSTREAM_METADATA</span>, streamMetadataHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">PROGRESS</span>, streamProgressHandler<span style="color: #66cc66;">&#41;</span>;
    ns.<span style="color: #006600;">addEventListener</span><span style="color: #66cc66;">&#40;</span>OvpEvent.<span style="color: #006600;">COMPLETE</span>, streamCompleteHandler<span style="color: #66cc66;">&#41;</span>;
&nbsp;
    vid = <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #0066CC;">Video</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    vid.<span style="color: #006600;">attachNetStream</span><span style="color: #66cc66;">&#40;</span>ns<span style="color: #66cc66;">&#41;</span>;
    vidContainer.<span style="color: #006600;">addChild</span><span style="color: #66cc66;">&#40;</span>vid<span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>The most interesting events are the metadata and progress events.  The metadata event delivers the duration of the video and its size.  The progress event arrives periodically (theoretically every 100ms by default, but in reality I see them come in just a couple of times per second) and delivers the current video time.</p>
<h5>Control Bar</h5>
<p>The control bar consists of three components: a play-pause button, a scrubber, and a volume slider.  They were skinned using Degrafa in <a href="http://saturnboy.com/2009/05/degrafa-video-player-1/">Part 1</a>.  In order to control video playback, we need to wire the control bar components to the instance of <code>OvpNetStream</code> created above.</p>
<p class="bottom">Here are the event handlers for the three control bar components:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript" style="font-family:monospace;"><span style="color: #808080; font-style: italic;">// PlayPause event handler</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> playPauseClick<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    <span style="color: #b1b100;">if</span> <span style="color: #66cc66;">&#40;</span>first<span style="color: #66cc66;">&#41;</span> <span style="color: #66cc66;">&#123;</span>
        first = <span style="color: #000000; font-weight: bold;">false</span>;
        ns.<span style="color: #0066CC;">play</span><span style="color: #66cc66;">&#40;</span>filename<span style="color: #66cc66;">&#41;</span>;
    <span style="color: #66cc66;">&#125;</span> <span style="color: #b1b100;">else</span> <span style="color: #66cc66;">&#123;</span>
        ns.<span style="color: #006600;">togglePause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
     <span style="color: #66cc66;">&#125;</span>
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// Scrub event handlers</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubPress<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #0066CC;">pause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    playPause.<span style="color: #006600;">selected</span> = <span style="color: #000000; font-weight: bold;">false</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubDrag<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #0066CC;">seek</span><span style="color: #66cc66;">&#40;</span>scrub.<span style="color: #006600;">value</span><span style="color: #66cc66;">&#41;</span>;
<span style="color: #66cc66;">&#125;</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> scrubRelease<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #006600;">togglePause</span><span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>;
    playPause.<span style="color: #006600;">selected</span> = <span style="color: #000000; font-weight: bold;">true</span>;
<span style="color: #66cc66;">&#125;</span>
&nbsp;
<span style="color: #808080; font-style: italic;">// Volume event handler</span>
<span style="color: #0066CC;">private</span> <span style="color: #000000; font-weight: bold;">function</span> volumeChange<span style="color: #66cc66;">&#40;</span><span style="color: #66cc66;">&#41;</span>:<span style="color: #0066CC;">void</span> <span style="color: #66cc66;">&#123;</span>
    ns.<span style="color: #006600;">volume</span> = volume.<span style="color: #006600;">value</span>;
<span style="color: #66cc66;">&#125;</span></pre></div></div>

<p>In the <code>playPauseHandler()</code>, the initial click calls <code>play()</code> which actually <i>loads</i> the video (and then starts playback), all subsequent clicks just toggle between play or pause.  For the scrubber handlers, I chose to break them up into three separate steps: on mouse down pause the video, on mouse up restart playback, and on drag attempt to seek to the to the new time.</p>
<p class="bottom">That&#8217;s it.  Here is the resulting Degrafa-skinned video player (view source enabled):</a></p>
<div id="flashcontent-degrafa-videoplayer">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>Click <b>Play</b> to start playing <a href="http://www.elephantsdream.org/">Elephants Dream</a> (which is the &#8220;world&#8217;s first open movie,&#8221; and pretty cool too).  Right away you&#8217;ll notice some visual issues because the dimensions of the video are unknown until the metadata arrives.  Also, scrubbing has some problems which I believe are related to cue points in progressive downloads.  Lastly, I didn&#8217;t implement any indicators for buffering or download progress, so you&#8217;ll need to be patient.  Since this is just a demo, I&#8217;ll have to leave fixing those bugs as an exercise for the reader.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_videoplayer/degrafa_videoplayer.html">Video Player</a> (<a href="http://saturnboy.com/proj/degrafa_videoplayer/srcview/degrafa_videoplayer.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_videoplayer/degrafa_videoplayer.swf', 'flashcontent-degrafa-videoplayer', '500', '460', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/06/degrafa-video-player-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Degrafa Video Player, Part 1</title>
		<link>http://saturnboy.com/2009/05/degrafa-video-player-1/</link>
		<comments>http://saturnboy.com/2009/05/degrafa-video-player-1/#comments</comments>
		<pubDate>Wed, 27 May 2009 05:42:47 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[open video player]]></category>
		<category><![CDATA[skinning]]></category>
		<category><![CDATA[video]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=472</guid>
		<description><![CDATA[I&#8217;m going to combine my earlier Degrafa skinning efforts with my more recent video work to create a Degrafa-skinned video player. In this post, I&#8217;ll build out all the components required for a video player control bar. And in Part 2, I&#8217;ll weld the control bar to an Open Video Player OvpNetStream backend. Button To [...]]]></description>
			<content:encoded><![CDATA[<p>I&#8217;m going to combine my earlier <a href="http://www.degrafa.org/">Degrafa</a> <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">skinning</a> <a href="http://saturnboy.com/2009/04/more-degrafa-skins/">efforts</a> with my more recent <a href="http://saturnboy.com/2009/04/open-video-player-air/">video work</a> to create a Degrafa-skinned video player.  In this post, I&#8217;ll build out all the components required for a video player control bar.  And in <a href="http://saturnboy.com/2009/06/degrafa-video-player-2/">Part 2</a>, I&#8217;ll weld the control bar to an <a href="http://www.openvideoplayer.com/">Open Video Player</a> OvpNetStream backend.</p>
<h5>Button</h5>
<p class="bottom">To get started, I built out a simple button skin with a slight shine on the top half.  I also added rounded corners to give the classic web 2.0 look-and-feel.  There&#8217;s really not much to look at:</p>
<div id="flashcontent-degrafa-videoplayer-button">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Play-Pause Button</h5>
<p class="bottom">I&#8217;m using a toggleable Button component as the base of my Play-Pause button.  By leveraging Degrafa&#8217;s stateful skins, I simply change the visibility of the Play and Pause geometry depending on the skin&#8217;s state.  Here&#8217;s a snippet from the <code>states</code> block of the skin:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;states<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;upSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{upFill}&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{play}&quot;</span> name=<span style="color: #ff0000;">&quot;visible&quot;</span> value=<span style="color: #ff0000;">&quot;true&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;selectedUpSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{upFill}&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
        <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{play}&quot;</span> name=<span style="color: #ff0000;">&quot;visible&quot;</span> value=<span style="color: #ff0000;">&quot;false&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span>
    ...
<span style="color: #000000;">&lt;/states<span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p class="bottom">Additionally, the play arrow and pause bars are dynamically sized based on the button height, so they readily scale to any size.  The result:</p>
<div id="flashcontent-degrafa-videoplayer-playpause">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Scrubber</h5>
<p class="bottom">Getting total control over a Slider skin is not easy in Flex 3.  There are two issue that I find quite annoying: the thumb size is hard-coded into the class and the highlight skin is offset from the track.  Fortunately, the web is full of workarounds for the <a href="http://blog.flexexamples.com/2007/09/12/changing-a-slider-controls-thumb-skin/">thumb size issue</a>, but for this skin I only needed to hard-code an offset (+6,+6) to bring the thumb&#8217;s origin to (0,0) and make all my geometry line up correctly.  Similarly, I added a 1 pixel offset to the highlight skin to bring its origin to (0,0) to match the track.  The result:</p>
<div id="flashcontent-degrafa-videoplayer-scrub">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Volume Slider</h5>
<p class="bottom">For consistency, the Volume slider re-uses the Scrubber&#8217;s thumb skin, but the track and highlight are wedges (<code>Polygon</code>&#8216;s in Degrafa).  The only clever piece of code is the highlight skin&#8217;s overridden <code>updateDisplayList()</code> function:</p>

<div class="wp_syntax"><div class="code"><pre class="actionscript3" style="font-family:monospace;">override <span style="color: #0033ff; font-weight: bold;">protected</span> <span style="color: #339966; font-weight: bold;">function</span> updateDisplayList<span style="color: #000000;">&#40;</span>unscaledWidth<span style="color: #000000; font-weight: bold;">:</span><span style="color: #004993;">Number</span>, unscaledHeight<span style="color: #000000; font-weight: bold;">:</span><span style="color: #004993;">Number</span><span style="color: #000000;">&#41;</span><span style="color: #000000; font-weight: bold;">:</span><span style="color: #0033ff; font-weight: bold;">void</span> <span style="color: #000000;">&#123;</span>
    <span style="color: #0033ff; font-weight: bold;">super</span>.updateDisplayList<span style="color: #000000;">&#40;</span>unscaledWidth, unscaledHeight<span style="color: #000000;">&#41;</span>;
    awidth = unscaledWidth;
    aheight = unscaledHeight;
&nbsp;
    <span style="color: #0033ff; font-weight: bold;">if</span> <span style="color: #000000;">&#40;</span><span style="color: #0033ff; font-weight: bold;">this</span>.<span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'parent'</span><span style="color: #000000;">&#41;</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'parent'</span><span style="color: #000000;">&#41;</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">hasOwnProperty</span><span style="color: #000000;">&#40;</span><span style="color: #990000;">'width'</span><span style="color: #000000;">&#41;</span> <span style="color: #000000; font-weight: bold;">&amp;&amp;</span>
             <span style="color: #0033ff; font-weight: bold;">this</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">width</span> <span style="color: #000000; font-weight: bold;">&gt;</span> <span style="color: #000000; font-weight:bold;">0</span><span style="color: #000000;">&#41;</span> <span style="color: #000000;">&#123;</span>
        _ratio = awidth <span style="color: #000000; font-weight: bold;">/</span> <span style="color: #0033ff; font-weight: bold;">this</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">parent</span>.<span style="color: #004993;">width</span>;
    <span style="color: #000000;">&#125;</span> <span style="color: #0033ff; font-weight: bold;">else</span> <span style="color: #000000;">&#123;</span>
        _ratio = <span style="color: #000000; font-weight:bold;">0.00001</span>;
    <span style="color: #000000;">&#125;</span>
<span style="color: #000000;">&#125;</span></pre></div></div>

<p class="bottom">In order to correctly draw the highlight wedge, we first need to know the dimensions of the track.  For simplicity, the Volume track height is hard-coded in both the track skin and highlight skin, but the width of the track is variable.  In this case, the width of the track is the same as the width of the <code>HSlider</code> component itself.  So in the <code>updateDisplayList()</code> code above, the track width is found and used to compute the ratio of widths.  This ratio is later used to draw the highlight geometry.  The end result:</p>
<div id="flashcontent-degrafa-videoplayer-volume">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>The Full Control Bar</h5>
<p class="bottom">Just displaying all the components side-by-side gives us the beginnings of a video player control bar:</p>
<div id="flashcontent-degrafa-videoplayer-controlbar">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p>Not too shabby.  In <a href="http://saturnboy.com/2009/06/degrafa-video-player-2/">Part 2</a>, I&#8217;ll assemble the final video player frontend including the pretty control bar components above, and weld it to an OvpNetStream-powered backend.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/degrafa_videoplayer_button.html">Button</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/srcview/degrafa_videoplayer_button.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/degrafa_videoplayer_playpause.html">Play-Pause Button</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/srcview/degrafa_videoplayer_playpause.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/degrafa_videoplayer_scrub.html">Scrubber</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/srcview/degrafa_videoplayer_scrub.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/degrafa_videoplayer_volume.html">Volume Slider</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/srcview/degrafa_videoplayer_volume.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/degrafa_videoplayer_controlbar.html">The Full Control Bar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/srcview/degrafa_videoplayer_controlbar.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_button/degrafa_videoplayer_button.swf', 'flashcontent-degrafa-videoplayer-button', '500', '40', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_playpause/degrafa_videoplayer_playpause.swf', 'flashcontent-degrafa-videoplayer-playpause', '500', '120', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_scrub/degrafa_videoplayer_scrub.swf', 'flashcontent-degrafa-videoplayer-scrub', '500', '50', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_volume/degrafa_videoplayer_volume.swf', 'flashcontent-degrafa-videoplayer-volume', '500', '50', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_videoplayer_controlbar/degrafa_videoplayer_controlbar.swf', 'flashcontent-degrafa-videoplayer-controlbar', '500', '40', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/05/degrafa-video-player-1/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>More Degrafa skins</title>
		<link>http://saturnboy.com/2009/04/more-degrafa-skins/</link>
		<comments>http://saturnboy.com/2009/04/more-degrafa-skins/#comments</comments>
		<pubDate>Mon, 06 Apr 2009 22:43:46 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=371</guid>
		<description><![CDATA[Before I dig too deep trying to create a Degrafa Skin Explorer (the idea) as an evolution of the Degrafa Button Explorer, I thought it would be a good idea to spend some more time with some basic Degrafa skinning. I managed to create a few button skins previously, but this time around I wanted [...]]]></description>
			<content:encoded><![CDATA[<p>Before I dig too deep trying to create a Degrafa Skin Explorer (<a href="http://groups.google.com/group/degrafa/browse_thread/thread/3041beeb5c4a92ee">the idea</a>) as an evolution of the <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">Degrafa Button Explorer</a>, I thought it would be a good idea to spend some more time with some basic <a href="http://www.degrafa.org/">Degrafa</a> skinning.  I managed to create a few button skins <a href="http://saturnboy.com/2009/03/degrafa-button-explorer/">previously</a>, but this time around I wanted something more involved.</p>
<h5>ButtonBar</h5>
<p class="bottom">First, I built out a pair of ButtonBar skins (view source enabled):</p>
<div id="flashcontent-degrafa-buttonbars">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>ToggleButtonBar</h5>
<p class="bottom">Next, I augmented the my basic ButtonBar skins with the various required selected skins (<code>selectedUpSkin</code>, <code>selectedDownSkin</code>, etc.) to create a pair of ToggleButtonBar skins (view source enabled):</p>
<div id="flashcontent-degrafa-tabs">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>iPhone Theme</h5>
<p class="bottom">Lastly, I dissected the <a href="http://www.degrafa.org/source/iPhoneSkin/iPhoneSkin.html">iPhone-esque theme</a> sample from the <a href="http://www.degrafa.org/samples/">Degrafa Samples</a> page, and created my own bastardized iPhone theme.  I factored out a <i>theme color</i> from each component into a CSS style called <code>mainColor</code> to allow the skin to be tweaked.  Check it out (view source enabled):</p>
<div id="flashcontent-degrafa-iphone">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<h5>Conclusions</h5>
<p>I learned a couple of things during my skinning exercise, but probably the most important came to me in an amazing &#8220;A-Duh&#8221; moment: <a href="http://www.degrafa.org/">Degrafa</a> is <b>really</b> powerful.  This is probably the same as saying MXML is a high-level language with a lot of leverage, but the Degrafa team has done a great job bringing this leverage to bear on skinning and graphics in Flex.  At this point, I find it hard to imagine creating a style without it.</p>
<p class="bottom">Secondly, semantic naming is a must inside a stateful skin.  So, I replaced any names like <code>darkFill</code> or <code>lightStroke</code>, with nice semantic names like <code>overFill</code> and <code>selectedStroke</code>.  So if I look at a chunk of code like this:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;State name=<span style="color: #ff0000;">&quot;downSkin&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;">&lt;SetProperty target=<span style="color: #ff0000;">&quot;{rect}&quot;</span> name=<span style="color: #ff0000;">&quot;fill&quot;</span> value=<span style="color: #ff0000;">&quot;{overFill}&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;">&lt;/State<span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>I can immediately know that my <code>downSkin</code> state is using a fill from my <code>overSkin</code> state, and probably implies the states are the same.</p>
<p>Lastly, always resist the temptation to re-use/re-purpose the CSS style from the underlying component in a skin.  For example, the iPhone theme above uses a <i>theme color</i> which I intentionally named <code>mainColor</code>.  I could easily have used Button&#8217;s aptly-named <code>themeColor</code> style (inherited down from UIComponent).  But this would dangerously overload the meaning of <code>themeColor</code>, because while it normally controls the Button&#8217;s border color it would now control the body color in my iPhone button skin.</p>
<h5>Files</h5>
<ul>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/degrafa_buttonbars.html">ButtonBar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/srcview/degrafa_buttonbars.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/degrafa_tabs.html">ToggleButtonBar</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/srcview/degrafa_tabs.zip">download</a>)</li>
<li><a href="http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/degrafa_iphone.html">iPhone Theme</a> (<a href="http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/srcview/degrafa_iphone.zip">download</a>)</li>
</ul>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_buttonbars/degrafa_buttonbars.swf', 'flashcontent-degrafa-buttonbars', '400', '70', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_tabs/degrafa_tabs.swf', 'flashcontent-degrafa-tabs', '500', '320', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_iphone/degrafa_iphone.swf', 'flashcontent-degrafa-iphone', '420', '216', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script></div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/04/more-degrafa-skins/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Degrafa Button Explorer</title>
		<link>http://saturnboy.com/2009/03/degrafa-button-explorer/</link>
		<comments>http://saturnboy.com/2009/03/degrafa-button-explorer/#comments</comments>
		<pubDate>Fri, 27 Mar 2009 22:50:58 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[degrafa]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=332</guid>
		<description><![CDATA[Recently, I&#8217;ve been playing around with Degrafa in preparation for actually using it on an upcoming project at work. For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex. One of my favorite parts so far is the amazing leverage it brings to building custom-styled components. It&#8217;s terse and powerful, [...]]]></description>
			<content:encoded><![CDATA[<p>Recently, I&#8217;ve been playing around with <a href="http://www.degrafa.org/">Degrafa</a> in preparation for actually using it on an upcoming project at <a href="http://www.gorillalogic.com/">work</a>.  For those that aren&#8217;t in the know, Degrafa is a badass graphics framework for Flex.  One of my favorite parts so far is the amazing leverage it brings to building custom-styled components.  It&#8217;s terse and powerful, just the way I like it.</p>
<h5>Building Buttons</h5>
<p class="bottom">With a very minimal amount of effort, I was able to create a few &#8220;web 2.0&#8243; button skins.  I just followed one of the millions of glass button photoshop tutorials, but did the work in mxml code using Degrafa&#8217;s declarative syntax.  Here are my results (view source enabled):</p>
<div class="span-14 top bottom" style="text-align:center;">
<div id="flashcontent-degrafa-buttons">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
</div>
<h5>Button Explorer</h5>
<p>But then I decided to take it a step further and build out a Degrafa Button Explorer (with a small tip of the hat to the original <a href="http://examples.adobe.com/flex3/consulting/styleexplorer/Flex3StyleExplorer.html">Flex Style Explorer</a>).  The Degrafa Button Explorer allows you to adjust a bunch of properties and colors for all three buttons styles.  It goes a step further than the original and provides not only the CSS, but also the full code of the stateful Degrafa-powered button components.</p>
<p class="large">&nbsp;&raquo;&nbsp;&nbsp;<a href="http://saturnboy.com/proj/degrafa_button_explorer/" target="_blank">Degrafa Button Explorer</a></p>
<blockquote class="deeper"><p><b>Digging Deeper:</b> I&#8217;ve been following the skinning performance issues discovered by the <a href="http://behindtheui.blogspot.com/2009/03/flex-component-kit-cpu-black-hole.html">guys</a> at <a href="http://www.effectiveui.com/">EffectiveUI</a>.  <a href="http://patrickhansen.com/blog/index.php/2009/03/25/stateful-vs-stateless-now-vs-degrafa/">The most recent benchmarks</a> appear to show that stateful Degrafa skins (like those produced by the Degrafa Button Explorer) are safe to use.</p>
</blockquote>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/degrafa_skins/degrafa_buttons/degrafa_buttons.swf', 'flashcontent-degrafa-buttons', '300', '90', '9.0.28', 'expressInstall.swf', false, { 'bgColor':'#ffffff', 'base':'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/03/degrafa-button-explorer/feed/</wfw:commentRss>
		<slash:comments>13</slash:comments>
		</item>
		<item>
		<title>Styling Flexlib&#8217;s WindowShade</title>
		<link>http://saturnboy.com/2009/03/styling-flexlib-windowshade/</link>
		<comments>http://saturnboy.com/2009/03/styling-flexlib-windowshade/#comments</comments>
		<pubDate>Thu, 05 Mar 2009 05:45:03 +0000</pubDate>
		<dc:creator>justin</dc:creator>
				<category><![CDATA[Code]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[design]]></category>
		<category><![CDATA[flex]]></category>
		<category><![CDATA[flexlib]]></category>
		<category><![CDATA[skinning]]></category>

		<guid isPermaLink="false">http://saturnboy.com/?p=246</guid>
		<description><![CDATA[A while back I started digging into the WindowShade component in Flexlib. I really needed a set of cool collapsable buckets for a project at work, and WindowShade was perfect for the task. Alas, I couldn&#8217;t find too much info on styling a WindowShade other than Doug McCune&#8217;s awesome example of WindowShade and Degrafa. So, [...]]]></description>
			<content:encoded><![CDATA[<p>A while back I started digging into the <a href="http://flexlib.googlecode.com/svn/trunk/docs/flexlib/containers/WindowShade.html">WindowShade</a> component in <a href="http://code.google.com/p/flexlib/">Flexlib</a>. I really needed a set of cool collapsable buckets for a project at <a href="http://www.gorillalogic.com/">work</a>, and WindowShade was perfect for the task.  Alas, I couldn&#8217;t find too much info on styling a WindowShade other than Doug McCune&#8217;s <a href="http://dougmccune.com/blog/2008/02/26/examples-from-my-360flex-session-using-open-source-community-projects/">awesome example of WindowShade and Degrafa</a>.  So, here is how I went about achieving the look and feel I needed with WindowShade.</p>
<h5>Plain Vanilla</h5>
<p>I started with an unstyled, super vanilla WindowShade wrapping a List.  And of course, I get this super-vanilla output:</p>
<p><a href="http://saturnboy.com/proj/shade/shade1/shade1.html">shade 1</a> (view source enabled)</p>
<p>The only styling magic was to add <code>padding="0"</code> to the WindowShade to get the child List component to suck up to the bottom of the WindowShade button.</p>
<h5>My First Attempt</h5>
<p class="bottom">In the next pass, I ditched the lame WindowShade button, and went with Flexlib&#8217;s <a href="http://flexlib.googlecode.com/svn/trunk/docs/flexlib/controls/CanvasButton.html">CanvasButton</a>, which contains a simple Label plus a CheckBox skinned with a plus or minus graphic. The code:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;">&lt;?xml version=<span style="color: #ff0000;">&quot;1.0&quot;</span> encoding=<span style="color: #ff0000;">&quot;utf-8&quot;</span>?<span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Application</span></span>
<span style="color: #000000;">        xmlns:mx=<span style="color: #ff0000;">&quot;http://www.adobe.com/2006/mxml&quot;</span></span>
<span style="color: #000000;">        xmlns:flexlibContainer=<span style="color: #ff0000;">&quot;flexlib.containers.*&quot;</span></span>
<span style="color: #000000;">        xmlns:flexlibControl=<span style="color: #ff0000;">&quot;flexlib.controls.*&quot;</span></span>
<span style="color: #000000;">        viewSourceURL=<span style="color: #ff0000;">&quot;srcview/index.html&quot;</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">    &lt;![CDATA[</span>
<span style="color: #339933;">        [Bindable]</span>
<span style="color: #339933;">        private var goodies:Array = [</span>
<span style="color: #339933;">            { header:'Ice Cream', items:['Vanilla', 'Chocolate', 'Strawberry', 'Cookies &amp; Cream'] },</span>
<span style="color: #339933;">            { header:'Candy', items:['Twix', 'Snickers', 'Fire Balls', 'Hot Tamales', 'Mike &amp; Ikes', 'Pez'] },</span>
<span style="color: #339933;">            { header:'Cookies', items:['Chewy Chips Ahoy', 'Mint Milano', 'Oreo', 'Nutter Butter', 'Fig Newtons'] }];</span>
<span style="color: #339933;">    ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Style</span> source=<span style="color: #ff0000;">&quot;style.css&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:VBox</span> width=<span style="color: #ff0000;">&quot;140&quot;</span> styleName=<span style="color: #ff0000;">&quot;container&quot;</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Repeater</span> id=<span style="color: #ff0000;">&quot;r&quot;</span> dataProvider=<span style="color: #ff0000;">&quot;{goodies}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;flexlibContainer:WindowShade</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> styleName=<span style="color: #ff0000;">&quot;shade&quot;</span></span>
<span style="color: #000000;">                    data=<span style="color: #ff0000;">&quot;{r.currentItem.header}&quot;</span></span>
<span style="color: #000000;">                    opened=<span style="color: #ff0000;">&quot;{r.currentIndex == 0}&quot;</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;flexlibContainer:headerRenderer</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Component</span><span style="color: #7400FF;">&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;flexlibControl:CanvasButton</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;30&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeBtn&quot;</span><span style="color: #7400FF;">&gt;</span></span>
                            <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">                            &lt;![CDATA[</span>
<span style="color: #339933;">                                import flexlib.containers.WindowShade;</span>
<span style="color: #339933;">                            ]]&gt;</span>
<span style="color: #339933;">                            &lt;/mx:Script&gt;</span>
&nbsp;
                            <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;header&quot;</span> top=<span style="color: #ff0000;">&quot;3&quot;</span> left=<span style="color: #ff0000;">&quot;4&quot;</span> text=<span style="color: #ff0000;">&quot;{WindowShade(parent).data}&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeHead&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
                            <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:CheckBox</span> id=<span style="color: #ff0000;">&quot;chk&quot;</span> top=<span style="color: #ff0000;">&quot;9&quot;</span> right=<span style="color: #ff0000;">&quot;6&quot;</span> selected=<span style="color: #ff0000;">&quot;{WindowShade(parent).opened}&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeChk&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
                        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/flexlibControl:CanvasButton</span><span style="color: #7400FF;">&gt;</span></span>
                    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Component</span><span style="color: #7400FF;">&gt;</span></span>
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;/flexlibContainer:headerRenderer</span><span style="color: #7400FF;">&gt;</span></span>
&nbsp;
                <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:List</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> dataProvider=<span style="color: #ff0000;">&quot;{r.currentItem.items}&quot;</span> rowCount=<span style="color: #ff0000;">&quot;{r.currentItem.items.length}&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeList&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
            <span style="color: #000000;"><span style="color: #7400FF;">&lt;/flexlibContainer:WindowShade</span><span style="color: #7400FF;">&gt;</span></span>
        <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Repeater</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:VBox</span><span style="color: #7400FF;">&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/mx:Application</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>After throwing in some colors from a sweet <a href="http://kuler.adobe.com/#themeID/356863">Kuler theme</a> and embedding Helvetica, we get this:</p>
<p><a href="http://saturnboy.com/proj/shade/shade2/shade2.html">shade 2</a> (view source enabled)</p>
<p>At this point, I was really happy with look and feel, but there we still a few minor issues with the CanvasButton header that needed to be fixed before declaring victory.</p>
<h5>Fixups</h5>
<p>First, I needed the rollover event to flow down to the checkbox, so it would correctly show the overSkin on mouse over.  Second, I wanted a color change on the Label on rollover to provide better visual feedback to the user.  And lastly, I wanted the entire CanvasButton header to be clickable, not just the label text or the checkbox graphic.</p>
<p class="bottom">Focusing just on the modified CanvasButton code, used in the <code>headerRendered</code>:</p>

<div class="wp_syntax"><div class="code"><pre class="mxml" style="font-family:monospace;"><span style="color: #000000;"><span style="color: #7400FF;">&lt;flexlibControl:CanvasButton</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;30&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeBtn&quot;</span></span>
<span style="color: #000000;">        rollOver=<span style="color: #ff0000;">&quot;header.setStyle('color', 0xffffff); chk.dispatchEvent(event);&quot;</span></span>
<span style="color: #000000;">        rollOut=<span style="color: #ff0000;">&quot;header.setStyle('color', 0xcccccc); chk.dispatchEvent(event);&quot;</span><span style="color: #7400FF;">&gt;</span></span>
    <span style="color: #339933;">&lt;mx:Script&gt;</span>
<span style="color: #339933;">    &lt;![CDATA[</span>
<span style="color: #339933;">        import flexlib.containers.WindowShade;</span>
<span style="color: #339933;">    ]]&gt;</span>
<span style="color: #339933;">    &lt;/mx:Script&gt;</span>
&nbsp;
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Label</span> id=<span style="color: #ff0000;">&quot;header&quot;</span> top=<span style="color: #ff0000;">&quot;3&quot;</span> left=<span style="color: #ff0000;">&quot;4&quot;</span> text=<span style="color: #ff0000;">&quot;{WindowShade(parent).data}&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeHead&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:CheckBox</span> id=<span style="color: #ff0000;">&quot;chk&quot;</span> top=<span style="color: #ff0000;">&quot;9&quot;</span> right=<span style="color: #ff0000;">&quot;6&quot;</span> selected=<span style="color: #ff0000;">&quot;{WindowShade(parent).opened}&quot;</span> styleName=<span style="color: #ff0000;">&quot;shadeChk&quot;</span><span style="color: #7400FF;">/&gt;</span></span>
    <span style="color: #000000;"><span style="color: #7400FF;">&lt;mx:Canvas</span> width=<span style="color: #ff0000;">&quot;100%&quot;</span> height=<span style="color: #ff0000;">&quot;100%&quot;</span> backgroundColor=<span style="color: #ff0000;">&quot;#000000&quot;</span> backgroundAlpha=<span style="color: #ff0000;">&quot;0&quot;</span> <span style="color: #7400FF;">/&gt;</span></span>
<span style="color: #000000;"><span style="color: #7400FF;">&lt;/flexlibControl:CanvasButton</span><span style="color: #7400FF;">&gt;</span></span></pre></div></div>

<p>The final result, a nice styled WindowShade:</p>
<p><a href="http://saturnboy.com/proj/shade/shade3/shade3.html">shade 3</a> (view source enabled)</p>
<p>I used the parent CanvasButton&#8217;s rollover event to set the child Label color and forward the event to the child CheckBox.  To make the entire button clickable, I used one of my favorite Flex UI hacks: I added a space-filling transparent Canvas.</p>
<h5>Comparison Shopping</h5>
<p class="bottom">And finally, a side-by-side comparison of all three WindowShade skins:</p>
<div id="flashcontent-windowshade">
Flash is required.  <a href="http://www.adobe.com/go/getflashplayer">Get it here!</a>
</div>
<p><b>Update:</b> See my <a href="http://saturnboy.com/2010/06/drawer-component-flex-4/">Drawer Component in Flex 4</a> post for a custom collapsible drawer component written from scratch in Flex 4.</p>
<div>
<script type="text/javascript">
swfobject.embedSWF('http://saturnboy.com/proj/shade/shade/shade.swf', 'flashcontent-windowshade', '530', '400', '9.0.28', 'expressInstall.swf', false, { bgColor:'#ffffff', base:'.' });
</script>
</div>
]]></content:encoded>
			<wfw:commentRss>http://saturnboy.com/2009/03/styling-flexlib-windowshade/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
	</channel>
</rss>
