Ghosh blog

Wednesday, January 6, 2010

Icons in Flex MenuBar

I came across this strange behavior (I'm not sure if it qualifies to be called a bug, but it definitely is not a feature) in Flex while trying to add icons to the MenuBar control.

The icons are displayed properly if both the MenuBar and the icon-embed variables are declared in the main application class. But if they are nested inside another component, only the top level menu-items' icons are displayed - child menu items' icons are not displayed.

After some debugging I realized that only the top-level menu items are displayed using the itemToIcon method of the MenuBar class; child menu-items are displayed using the itemToIcon method of the Menu class. The problem here is that even though both of these methods use document[data[iconField]] to grab the icon-embed class, the document properties of these two objects point to different items. The document property of the MenuBar points correctly to the enclosing component (MyPanel). Whereas, for some reason that I don't understand, the document property for nested Menu points to the MainApplication class.

In short, while rendering icons of a MenuBar within a component, flex searches the component class for icons of top-level menu items, and the main-application class for icons of its nested menu items. The obvious workaround is to embed all icons to public static const in some class and to keep appropriate references to them in both application and component classes. But that doesn't sound so pretty to me (even though that's what I am doing now). Does anyone know better?

Here is example code and screenshots to demonstrate the issue:

<!--The main Application class-->
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical"
   creationComplete="create()" xmlns:local="*">
   <mx:Label text="MenuBar in the Application works fine"/>
   <mx:MenuBar id="menuBar" top="10" left="10"
       dataProvider="{menuBarCollection}" labelField="@label"
       iconField="@icon" />

   <local:MyPanel/>

   <mx:Script>
       <![CDATA[
           import mx.collections.XMLListCollection;

           [Bindable]
           protected var menuBarCollection:XMLListCollection;

           [Embed(source="assets/icon_one.png")]
           public var iconOne_App:Class;

           [Embed(source="assets/icon_two.png")]
           public var iconTwo_App:Class;

           private function create():void
           {
               menuBarCollection = new XMLListCollection(XMLList(
                   '<menuitem label="One" icon="iconOne_App">' +
                       '<menuitem label="Two" icon="iconTwo_App"/>' +
                       '<menuitem label="Three" icon="iconTwo_App"/>' +
                   '</menuitem>'
               ));
           }
       ]]>
   </mx:Script>
</mx:Application>

MenuBar in the Application

<!--MyPanel.mxml-->
<mx:Panel xmlns:mx="http://www.adobe.com/2006/mxml" height="144"
   creationComplete="create();" horizontalAlign="center" verticalAlign="middle">
   <mx:Text text="MenuBar inside a component doesn't display icons properly"/>
   <mx:MenuBar id="menuBar" top="10" left="10"
       dataProvider="{menuBarCollection}" labelField="@label"
       iconField="@icon" />
   <mx:Script>
       <![CDATA[
           import mx.collections.XMLListCollection;

           [Bindable]
           protected var menuBarCollection:XMLListCollection;

           [Embed(source="assets/icon_one.png")]
           public var iconOne_Panel:Class;

           [Embed(source="assets/icon_two.png")]
           public var iconTwo_Panel:Class;

           private function create():void
           {
               menuBarCollection = new XMLListCollection(XMLList(
                   //top level item referring to component
                   //this icon is displayed
                   '<menuitem label="ParentIcon_panel" icon="iconOne_Panel">' +

                       //nested item referring to component
                       //this icon is not displayed
                       '<menuitem label="ChildIcon_panel" icon="iconTwo_Panel"/>' +

                       //nested item referring to application
                       //this icon is displayed
                       '<menuitem label="ChildIcon-app" icon="iconTwo_App"/>' +
                   '</menuitem>' +

                   //top level item referring to Application
                   //this icon is not displayed
                   '<menuitem label="ParentIcon_app" icon="iconOne_App"/>'
               ));
           }
       ]]>
   </mx:Script>
</mx:Panel>

MenuBar inside a Component

Wednesday, November 18, 2009

Generating getters and setters in Flex Builder

Fine print: This post discusses not so thoroughly tested regexes that the author used to edit his source code (and to fulfill his newly found affection for exploring regular expressions). Author cannot be held responsible or abused for the damages that these regexes might incur to your code and/or job. Eclipse has this cool feature that lets you generate getters and setters for the variables in your source code. Flex Builder 3, though based on Eclipse platform, doesn't have such an option. For those interested, here is a way to generate get and set methods for your ActionScript private/protected variables using the inbuilt Find/Replace and regular expressions. Though it assumes that you're using tabs for indenting the code (which is the default in FB), you can modify it for spaces easily. Open the Find/Replace window (Ctrl-F) and add the following regular expression to the Find field.

^((\t)+)(?:private|protected)\s+var\s+_(\w+):(\w+)\s*;\s*(\n)

Now add the following pattern to the Replace field.

$0$5$1public function set $3(value:$4):void$5$1{$5$1$2_$3 = value;$5$1}$5$5$1public function get $3():$4$5$1{$5$1$2return _$3;$5$1}$5$5

Don't forget to select the Regular expressions check box in the options box. The replace pattern doesn't accept any meta characters other than $, and hence we need to capture a tab and a new-line using the regex itself. Now use the Find, (Alt-N), Replace (Alt-R) and Replace/Find (Alt-D) to generate get and set methods for the required properties. If you want to generate get/set methods for all the private/protected variables in your class - and you're really courageous, use Replace All (Alt-A).

Tuesday, October 27, 2009

StackOverflow Reputation Tracker

Did I say that I've gotten addicted to StackOverflow? Here is a snippet of shell script to check your StackOverflow reputation from the comfort of your Linux console. Replace the highlighted part with your user ID. #!/bin/sh json=$(curl -s http://stackoverflow.com/users/flair/{165297}.json) echo $json | sed 's/.*"reputation":"\([0-9,]\{1,\}\)".*/\1/' | sed s/,// Haven't tested this for other sites in the trilogy, but I believe this would work for all the three sites and also the meta. Now onto writing an AIR app that would track reps and alert about new questions with your favorite tags... :)