FTE cannot display Thai characters under Windows XP English using default set of device fonts

May 5th, 2010

   Are you unlucky user of Windows XP English with clean install?

   If yes, then probably you cannot see Thai characters in Spark text components (e.g Spark Label) in the following demo:

Get Adobe Flash player

Code listing: http://gist.github.com/390993

    New Flex Spark Label to display text uses the new Flash Text Engine (FTE) introduced in Flash Player 10. And that’s true, FTE brought many very useful new features (text subscript, bidirectional text to name a few) that were previously impossible to achieve with older flash.text.TextField object, but I’ve learned recently that FTE can fail to display Thai characters under Windows XP clean install.

   Eric Y Muller explains the technical details at Adobe forums:, why FTE cannot use neither Tahoma nor Microsoft Sans Serif standard Windows XP fonts as device fallback to display Thai characters.

   The only workaround for this issue for the frustrated user would be to insert original CD with Windows XP install and install Thai language support using “Regional and Language Options” control panel. But this would impossible to achieve for the anonymous employee that works for trans-global corporation without admin access account %-)

   As for the developer of the Flash application we can always embed font into Flash app that contains Thai characters, but this will impact the overall bytesize of the resulting SWF file.

ps
   In 2010, Windows XP remains highly relevant OS. Various stat counters show that 52% 64% computer users use Windows XP. Thus it is very important for any Flash application to play nice under this OS without an hassle.

Flex 4 AutoComplete component with text highlighting

March 8th, 2010

   Updated: More recent version of this component was announced at September.

   Disclaimer: My implementation of AutoComplete component is based on the revised codebase of AutoComplete 4 component originally created by Tenger Ivan from FlashCommander.org

   Two different search modes are supported : PREFIX and INFIX, to see the difference please play with the interactive sample file below.

Get Adobe Flash player

   The auto-completion operation can be achieved in two ways:

  • via keyboard
    First, select the list item by moving selected index via UP and DOWN keys and confirm the choice by hitting ENTER key

  • via mouse
    Just mouse click upon the currently selected list item.

       Disclaimer: the source code of this component is of beta quality and can be obtained for free here: ZIP file, 23 kb. If any bug is found, please let me know.

       UPD: Updated sample file with a real world list of 978 US universities.
       Also a few bugs were fixed related to case insensitive search and not working text highlight of the last string character.

  • Applying selection dynamically to Spark RichText component

    February 4th, 2010

    Flex 4 documentation article named “Selecting and modifying text” lists an finite final list of components that supports the selection:

    • RichEditableText
    • Label (Spark only)
    • TextInput (both MX and Spark)
    • TextArea (both MX and Spark)
    • RichTextEditor and all controls that have a TextArea as a subcomponent

       This list does not include RichText component, but luckily with a new Text Layout Framework (TLF) available starting from Flash player 10, it is quite easy to “simulate” dynamic selection of the text with some ActionScript 3 code.

       In the following example, try to drag the slider to the left and to the right to control the dynamic selection of the text of RichText component:

    Get Adobe Flash player

    Code listing:

    <?xml version="1.0" encoding="utf-8"?>
    <s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
                   xmlns:s="library://ns.adobe.com/flex/spark" 
                   xmlns:mx="library://ns.adobe.com/flex/halo"
                   width="200"
                   height="75">
        <s:layout>
            <s:HorizontalLayout paddingLeft="25"
                                paddingTop="25"
                                paddingRight="25"/>
        </s:layout>
        <fx:Script>
            <![CDATA[            
                import flashx.textLayout.edit.EditManager;
                import flashx.textLayout.edit.SelectionState;
                import flashx.textLayout.formats.TextLayoutFormat;            
     
                protected function highlightItem(endSelectionCharIndex : int):void
                {
                    var containerFormat:TextLayoutFormat = new TextLayoutFormat();                
                    var paragraphFormat:TextLayoutFormat = new TextLayoutFormat();                
                    var characterFormat:TextLayoutFormat = new TextLayoutFormat();
     
                    characterFormat = _selectedTextFormat;
     
                    var selectionState : SelectionState = new SelectionState(rt.textFlow, 0, endSelectionCharIndex, _selectedTextFormat);                
     
                    // apply format to the selection
                    _textEditManager.applyFormat(
                        characterFormat, 
                        paragraphFormat, 
                        containerFormat, 
                        selectionState);                                
     
                    characterFormat = _notSelectedTextFormat;                
     
                    // apply format to the rest of the text
                    var notSelectionState : SelectionState = new SelectionState(rt.textFlow, endSelectionCharIndex, rt.text.length, _notSelectedTextFormat);                
                    _textEditManager.applyFormat(
                        characterFormat, paragraphFormat, containerFormat, notSelectionState);
                }
     
     
                protected function onRichTextCreationComplete():void
                {
                    _textEditManager = new EditManager();
                    rt.textFlow.interactionManager = _textEditManager;
     
                    _selectedTextFormat = new TextLayoutFormat();
                    _selectedTextFormat.backgroundColor = 0xFF99CC;
                    _selectedTextFormat.color = 0x000000;
     
                    _notSelectedTextFormat = new TextLayoutFormat();
                    _notSelectedTextFormat.backgroundColor = 0xFFFFFF;
                    _notSelectedTextFormat.color = 0x000000;
                }
     
                private var _textEditManager : EditManager;
     
                private var _selectedTextFormat : TextLayoutFormat;
     
                private var _notSelectedTextFormat : TextLayoutFormat;            
     
            ]]>
        </fx:Script>                   
        <s:RichText id="rt" text="Sample text" 
                    creationComplete="onRichTextCreationComplete()"/>
        <s:HSlider id="slider" 
                  minimum="0" 
                  maximum="10" 
                  change="highlightItem(slider.value)">        
        </s:HSlider>        
    </s:Application>

    When overriding “commitProperties” put “super.commitProperties” call to the end of the method

    February 3rd, 2010

    My use-case
       Recently I’ve tried to introduce skin states to the pretty complex UI component in Adobe Flex 4. I have got puzzled by the behaviour that my invalidateSkinState() calls never had triggered execution of getCurrentSkinState method that controlls the current UI component skin state value as expected.

    [pullquote]Invalidation of the same phase while processing that phase is ignored – by Alex Harui[/pullquote]

       Under closer examination I found out that I fall into the same invalidation trap that James Polanco did in November 2010.

       I must stress out that it was easy to fall into this trap in my case because inside “commitProperties” call I was doing pretty complex calculations that involved, for example, the creation of display object sub-children, listening for “preinitialize” events from those sub-children, reacting to it, etc.

        To cut the talk short, to prevent this property invalidation trap from happening I suggest to always follow the simple rule of the thumb:

    When overriding “commitProperties” put “super.commitProperties” call to the end of the method

    override protected function commitProperties():void
    {
        if (myPropertyChanged)
        {        
            disableMyUIComponent = true;
            invalidateSkinState();
            myPropertyChanged = false;
        }
        super.commitProperties();
    }
     
    override protected function getCurrentSkinState():String { 
        var returnState:String = "normal"; 
     
        // Use information in the class to determine the new view state of the skin class. 
        if (disableMyUIComponent)     { 
            returnState = "disabled"; 
        } 
        return returnState; 
    }

    Futher reading:
    Discussion at 2008 at Flexcoders mailing list (yeah, at that time, this mailing list was more interesting to read) “Must call super.commitProperties at END of overrided commitProperties when extending XXXX?”

    When it is time to reset dirty flag “invalidatePropertiesFlag” in Flex invalidation framework?

    December 24th, 2009

       Invalidation in Flex is a mechanism by which changes made to a component’s property values are queued and postponed for the final procession till the end of the current Flash movie frame play. This property value invalidation mechanism in Flex is controlled by setting and resetting boolean variables called dirty flags.

       One of such a dirty flags used internally in Flex invalidation mechanism is invalidatePropertiesFlag flag.

       This particular flag is reset in validateProperties() method from mx.core.UIComponent class from Flex 3 SDK:

    public function validateProperties():void
    {
        if (invalidatePropertiesFlag)
        {
            commitProperties();
            invalidatePropertiesFlag = false;
        }
    }

       Inside commitProperties() function the actual change occur to the invalidated property’s value, for example, it can be “width” property.

       The question is – why dirty flag invalidatePropertiesFlag is reset after call to commitProperties() method, but not before this call?

        My far-fetched speculation is that this had happened because:

    • It is just a matter of life == code convention to put the dirty flag at the end of IF block;
    • If code within commitProperties() raises RTE, we will still have a chance to execute the code in commitProperties() during playing next frame in Flash Player and this time maybe the code will not throw RTE.

       At this point, you may start to wonder why the exact location (at the very beginning or at the very end of IF sequence) of the dirty flag can be important?

       The reason is:

       If the code within commitProperties() implementation will try to invalidate some other component’s property (e.g “height” property) that tries to invoke another invalidation routine by using dirty flag, then this invalidation call will not be added to mx.managers.LayoutManager.invalidatePropertiesQueue, because dirty flag invalidatePropertiesFlag is still equal to true, see the listing of invalidateProperties method from UIComponent for the method logic:

    public function invalidateProperties():void
        {
            if (!invalidatePropertiesFlag)
            {
                invalidatePropertiesFlag = true;
     
                if (parent && UIComponentGlobals.layoutManager)
                    UIComponentGlobals.layoutManager.invalidateProperties(this);
            }
        }

    NEVER use selectable=false for editable List or DataGrid Flex components

    June 15th, 2009

    It is very likely that the authors of Adobe Flex SDK have never devised the following simple use-case for both List and DataGrid components from Flex SDK:

  • “selectable” property is set to false
  • “editable” property is set to true

    To prove this fact, try to play with the following samples:

    mx:List

    Get Adobe Flash player

    Click the first row, in a List, then the itemEditor appears on the first row.
    Click the second row in a List , but the itemEditor doesn’t appear on the second row

    That’s bug SDK-15309, documented over year ago.

    mx:DataGrid

    Get Adobe Flash player

    Code listing:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml"
                    creationComplete="initApp();"
                    width="400"
                    height="300"
                    styleName="plain"
                    paddingLeft="0"
                    paddingRight="0"
                    paddingTop="0"
                    paddingBottom="0">
     
        <mx:Script>
            <![CDATA[
                import mx.events.DataGridEvent;
     
                private function initApp():void {
                    dg.dataProvider =                     [
                        {Artist:'Carole King', Album:'Tapestry', Price:11.99},
                        {Artist:'Paul Simon', Album:'Graceland', Price:10.99},
                        {Artist:'Original Cast', Album:'Camelot', Price:12.99},
                        {Artist:'The Beatles', Album:'The White Album', Price:11.99}
                        ];
                }
     
                private function onItemEditBegin(event : DataGridEvent) : void
                {
                    trace ("DG onItemEditBegin");
                }
     
            ]]>
        </mx:Script>
        <mx:DataGrid id="dg"
                     rowHeight="20"
                     editable="true"
                     selectable="false"
                     width="100%"
                     height="100%"
                     itemEditBegin="onItemEditBegin(event)">
            <mx:columns>
                <mx:DataGridColumn
                                   dataField="Artist"
                                   width="100">
                </mx:DataGridColumn>
                <mx:DataGridColumn
                                   dataField="Album"/>
                <mx:DataGridColumn
                                   dataField="Price"/>
            </mx:columns>
        </mx:DataGrid>
    </mx:Application>

    Now, try to click on the DataGrid header, oops, you’ve just hit SDK-19436 bug (itemEditor instance is created unwillingly at first column, first row of DataGrid).

    Then try to scroll the DataGrid with scroller buttons, and again you’ve hit another, albeit similar, SDK-21726 bug (itemEditor instance is created unwillingly at first column, first row of DataGrid).

    Now scroll the contents of Datagrid a little bit down with a scroller thumb and start to edit cell in the first topmost visible row, first column, now move the current focus by pressing keyboard combination Shift+Tab, and once again, you’ve hit a SDK-16262 bug.

    To conclude this post: do not set selectable on mx:List or mx:DataGrid components to false if you are going to edit their values using itemEditors, until all above mentioned bugs will be fixed.

  • Always keep an eye on most recent stable release of Adobe Flex SDK

    November 4th, 2008

       I was going to enter a new issue into Adobe JIRA Flex SDK bugbase that I could confirm to be present in the most recent milestone Adobe Flex SDK release 3.1.0.2710, shipped together with an August 2008 Flex Builder 3.0.1 update.

       Just before submitting the bug issue, I’ve tested the functionality under the question under the latest Adobe Flex SDK stable build (3.2.0.3794 at the time of writing) – and I was surprised to find out that the bug is already fixed. Joy! Joy!

        I rushed to find the reasoning for this change for UITextFormat class by reading change notes at Flex SDK download section at Adobe open source web-site, but could not find any remarks regarding this change – would be handy to have a better insight behind this change for the community.

       ps If you wonder, the issue was incorrect implementation of an internal function copyFrom from UITextFormat class. UITextField’s public getUITextFormat() method relies on this copyFrom function to return UITextFormat object for the UITextField class instance. In a nutshell UITextFormat object is just a wrapper around textFormat class that should contain all the properties from wrapped textFormat class instance + add some additional functionality.

       As it turned out, In Adobe Flex SDK 3.1 and below, 7(!) different properties were not copied into UITextFormat object from existing textFormat format object because of wrong implementation of UITextFormat.copyFrom function.

       Now, we are safe, this particular issue is fixed!

    Hint: Always better to use ‘itemUpdated’ method instead of ‘setItemAt’ when updating existing items in ArrayCollection

    April 20th, 2008

       When you want to update already existing data item in your ArrayCollection in ActionScript 3 with a new values for object’s properties you have 2 options to select from:

    1. use itemUpdated(obj) ArrayCollection’s method.
    2. use setItemAt(obj, index) ArrayCollection’s method.

       ActionScript code sample:

        //Update an existing person in the ArrayCollection via setItemAt
     
        public function updatePersonViaSetItemAt():void {
            var currentlySelectedItem : Object = dg.selectedItem;
            currentlySelectedItem.first = firstInput.text;
            currentlySelectedItem.last = lastInput.text;
            ac.setItemAt(currentlySelectedItem, dg.selectedIndex);
        }
     
        // Update an existing person in the ArrayCollection via itemUpdated
     
        public function updatePersonViaItemUpdated():void {
            var currentlySelectedItem : Object = dg.selectedItem;
            currentlySelectedItem.first =  firstInput.text;
            currentlySelectedItem.last =  lastInput.text;
            ac.itemUpdated(currentlySelectedItem);
     
        }

       Which one to choose?

       I would strongly advice to always use ‘itemUpdated’ because of the following reasons:

    • Calling setItemAt(x) on your existing data item in ArrayCollection is an equivalent to calling the removeItemAt(x) method and then calling the addItemAt(…, x) method on your data item.
         Thus after making the call to setItemAt(x, index) you will loose the current selection in your ArrayCollection dependant UI component (mx:DataGrid, mx:Tree, mx:Combobox.. etc..)

    • If the Sort rule is already applied to your ArrayCollection then you can receive some funky results like unwanted inserting of a new row when partly changing several properties of the existing data item in ArrayCollection.

       Interactive sample with “View source” option enabled to watch the difference:
    http://jabbypanda.com/labs/updateArrayCollectionItem/updateArrayCollectionItem.html

    You can try the following:

    1. First apply sorting to any of the DataGrid’s column
    2. Select the first row in the Datagrid
    3. Rename the surname of the person to something completely new starting with a new letter
    4. Press “Update via setItemAt()” button control

    Voilà, new unwanted row becomes visible in the Datagrid.

    The first meeting of Ukrainian Adobe Flash platform user group (UAFPUG) went well!

    March 16th, 2008

    Kharkiv, Ukraine is quickly becoming a popular place for Ukrainian Flash and Flex developers to meet.

    After intoductory meeting of Ukrainian Adobe Flash platform user group(UAFPUG) at February 2008 codenamed UAFPUG-0, the first real seminar UAFPUG-1 had quickly followed at 15th of March, 2008 at Global Logic office premises at Kharkiv, Ukraine.

    Speakers list had included 3 (THREE!) talented local Flash profesionals who had presented to the audience of 45 attendees mostly from all major cities in Eastern Ukraine and Kyiv included + 1 international visitor from Russia.

    The speech topics were as follows:

  • Event flow model in ActionScript 3.0 (presented by Pirrest)
  • Introducing Flash media server 3.0 feature (presented by Dinosaur)
  • Applying PureMVC framework to the creation of vector map of Moscow city (like Mos2.ru does) (presented by _rost)
  • .
    UAFPUG-1 meeting
    Rostyslav Syrik _rost discusses the ins and outs of PureMVC framework.

    UAFPUG-1 meeting audience
    The UAFPUG-1 meeting audience was very into the subject of the seminars :).

    Thank you to all of you, who had helped to make this meeting to become a reality, especially _rost, Reijji, __i, Pirrest and Global Logic team crew.

    How to hide the unwanted content visible outside of mx:SWFLoader boundaries

    February 13th, 2008

    The issue:

    I was stumbled upon once ago when I loaded my external SWF file authored by the Flash IDE by the help of component and suddenly (?) every content object that was originally placed outside of the Stage inside the Flash IDE became visible in my Flex 2 based web application outside of the boundaries after loading sequence for my external SWF file was over (the file is Flash8 based, AVM1 if this matters).

    The corresponding task in Adobe JIRA bug-database:
    http://bugs.adobe.com/jira/browse/SDK-14590

    I currently fight this issue by applying the mask over the content that is loaded by the component, see the code below, may be you can find it helpful too:

    [sourcecode language=”xml”]
    <?xml version="1.0" encoding="utf-8"?>
    <mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml"
    resize="applyMask()" >

    <mx:Script>
    <![CDATA[
    private function applyMask() : void {
    if (swf != null &&
    swf.content != null &&
    swf.content.loaderInfo.width > 0 &&
    swf.content.loaderInfo.height > 0) {
    var scaleRatioX : Number = swf.content.loaderInfo.width /
    this.width;
    var scaleRatioY : Number = swf.content.loaderInfo.height /
    (this.height – this.controlBar.height);
    var scaleRatio : Number = Math.max(scaleRatioX, scaleRatioY);

    swf.width = swf.content.loaderInfo.width > 0 ?
    Math.round(swf.content.loaderInfo.width / scaleRatio) : 100;
    swf.height = swf.content.loaderInfo.height > 0 ?
    Math.round(swf.content.loaderInfo.height / scaleRatio) : 100;

    var s : Shape = new Shape();
    s.graphics.beginFill(0xFFFFFF);
    s.graphics.drawRect(0, 0, swf.width, swf.height);
    s.graphics.endFill();
    swf.addChild(s);
    s.visible = false;
    swf.mask = s;
    }
    }
    ]]>
    </mx:Script>
    <mx:SWFLoader id="swf"
    complete="applyMask()"
    source="navigation.swf"/>
    </mx:VBox>
    [/sourcecode]