Adobe opens up RTMP protocol

Adobe will open the Real-Time Message Protocol (RTMP). RTMP is the protocol used in LiveCycle Data Services or Flash Media Server for streaming data or audio/video. Why is this important for you? Because, from now on other companies or developers can build products using this protocol (and they don’t have to reverse-engineer it :D), and as a result Flex developers will have more options to choose from – a healthy competition. For example, after the AMF protocol was opened last year, ZendAMF (the Remoting solution for PHP from Zend) appeared.

You can read the announcement here, and Ryan Stewart will have a post with more details on the same topic has a post on this topic.

How to use Text Layout Framework in Flex 3.2 or AIR 1.5

The goal of this article is to explain what the Text Layout Framework is and how you can use it to display rich text inside of Flash Player 10. While I will not cover all the possibilities of this framework, I hope I will give you enough of a push to get up to cruising speed.

As usual, you can find a demo and the source code for the examples in this article packaged as a Flex 3.2 project ZIP file. So if you prefer to see the code before reading the theory, then see the section “Code time: An example using the Text Layout Framweork in Flex 3.2″.

Note: For a Bulgarian translation you can check this website.

What is the Text Layout Framework

The Flash Text Engine (FTE) available in Flash Player 10 and Adobe AIR 1.5 brings support for many new text capabilities. There is an API that provides low-level access to this engine, but if you want to use the API you have to write a lot of code. Thus, the FTE is intended to provide the foundation for libraries that leverage these capabilities and make life easier for the developer.

And this is exactly what the Text Layout Framework is. It is a library written in pure ActionScript, and thus can be used in Flash CS4, Flex 3.2 or Gumbo, or AIR 1.5.

The Text Layout Framework provides support for:

Below are some screen shots from the samples you can find on http://labs.adobe.com/technologies/textlayout/:

Japanese text, left to right, vertical, you can see the text selection Text flowing in linked containers

Text formatting:  orientation, alignment, rotation, spacesSetting the number of columns

Inline imagesText blends and effects

Understanding Text Layout Framework components

The Text Layout Framework (TLF) comprises three components and ten packages. All the packages are subpackages of the flashx.textlayout package. As I said this framework is implemented using pure ActionScript 3, and thus can be used in Flash CS4, Flex 3.2, Gumbo (the Text Layout Framework is part of Gumbo), or AIR 1.5. And of course you have to target Flash Player 10. Here is a short description of the three components in TLF:

  1. textLayout_core.swc is the main component and handles data storage, flowing text into containers, and rendering the containers
  2. textLayout_conversion.swc is used to import text into the framework, and to export it
  3. textLayout_edit.swc facilitates text selection and text editing

One way to look at the TLF, is by comparing it with the MVC pattern. If you apply this pattern, then you will have:

  1. The model is defined mainly by the flashx.textlayout.elements package, which includes classes/interfaces that define the data structure that holds the text. Another package, flashx.textlayout.formats, is used for storing the format information. The package flashx.textlayout.conversion can be considered part of the model as it embodies the rules for importing/exporting the data
  2. The view includes three packages that handle the rendering of text for display. You can choose to display the text using one of the two different methods: using  flashx.textlayout.factory package you can display static text, and using flashx.textlayout.container you can display containers for dynamic text. The flashx.textlayout.compose package defines the methods for positioning and displaying dynamic text in containers
  3. The controller is represented by two packages that define how the user can interact with the text (selecting, editing, copy/paste, undo, and so on): flashx.textlayout.edit and flashx.textlayout.operations

The Model and Text Flow hierarchy

The model uses a hierarchical tree to represent text. Each element of the tree is a class from the package flashx.textlayout.elements. The root element is always an instance of the TextFlow class, and conceptually represents an entire story of text (the term story comes from DTP, and means a collection of text that should be treated as one unit). For example, the article you are reading now could be a story.

The rest of the elements are:

The TextFlow can have only these two elements as children: div and p. Here is how the model can look for a story:

TLF hierarchy

This Text Flow hierarchy translates to an XML document, using TLF Markup. Basically the nodes can be: TextFlow, div, p, a, img, span, tcy, br, and tab. At the same time, each node has an ActionScript class implementation: TextFlow, DivElement, ParagraphElement, LinkElement, TCYElement, SpanElement, InlineGraphicElement, TabElement, and BreakElement. All these classes inherit directly or indirectly from the class FlowElement.

Now, let’s see how you can create a TextFlow element. Basically, there are two ways you can create a TextFlow element: by using an XML object, or by creating the nodes and assembling them together in a tree (similar to creating an XML using DOM).

Creating a TextFlow element using an XML:

   1: private static const textInput:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008">
   2: <div>
   3:     <p>
   4:         <img source="air.png"/>
   5:         <span>Flex is a highly productive, free open source framework for building and maintaining expressive web applications...</span>
   6:         <br/>
   7:     </p>
      </div>
   8: </TextFlow>;
   9:
  10: private var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);

As you can see TextFilter class is used for importing the XML and creates an instance of TextFlow. The second parameter of the import method tells what format the XML is written in. In this case I am using TLF Markup.

Creating a TextFlow using the FlowElement classes:

   1: var textFlow:TextFlow = new TextFlow();
   2: var p:ParagraphElement = new ParagraphElement();
   3: var span:SpanElement = new SpanElement();
   4: span.text = "Hello, World!";
   5: p.addChild(span);
   6: textFlow.addChild(p);

The Model and formatting information

As noted earlier, the model stores the formatting information too. If you choose to create the TextFlow element using XML, then you can add the properties like attributes on the node you want:

   1: var text:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008" fontSize="14" textIndent="15" marginBottom="15" paddingTop="4" paddingLeft="4">"
   2:        <p>
   3:         <span>There are many </span>
   4:         <span fontStyle="italic">such</span>
   5:     </p>
   6: </TextFlow>;

Or, if you create it out of FlowElement classes, you can do it like this:

   1: var cf:CharacterFormat = new CharacterFormat();
   2: cf.fontSize = 14;
   3: textFlow.characterFormat = cf;

All the properties that can be set for all the nodes are grouped into three types: container, paragraph, and character properties. You can see the API for the flashx.textlayout.formats package here.

Container formats apply on the entire container of text, for example column properties and padding values. Container formats can be applied only on a TextFlow, DivElement, or other class that implements IContainerController. You can apply these properties using an instance of the ContainerFormat class.

Paragraph formats apply to an entire paragraph of text: justification, margins, tab stops. They can be applied on TextFlow, DivElement, and ParagraphElement. You apply these formats using an instance of ParagraphFormat class.

Character formats apply only to a single character or run of characters: font size, color, tracking, kerning, superscript. You can assign them to any FlowElement, thus you can set the font size for an entire story by setting the property on the TextFlow, or the SpanElement. You use a CharacterFormat class to apply the properties.

When you apply a format on a FlowElement, you have two options: to overwrite the existing formats, or to keep the existing ones, and add the new format. Below is code illustrating both options. To keep the existing format, when you create the new format you pass an instance of that format to the constructor.

   1: //overwrite the characterFormat for the TextFlow
   2: var cf:CharacterFormat = new CharacterFormat();
   3: cf.fontSize = 14;
   4: textFlow.characterFormat = cf;
   5:
   6: //keeps the existent characterFormat, and change only the font size
   7: var cf:CharacterFormat = new CharacterFormat(textFlow.characterFormat);
   8: cf.fontSize = 14;
   9: textFlow.characterFormat = cf;

Finally, if you apply a font-size change to the TextFlow element, then this change will be applied to all its children that don’t have a font-size explicitly set on them.

Important: every time you apply changes to a TextFlow object that has been displayed, you have to call the method updateAllContainers() on the flowComposer property of the TextFlow object to trigger the update of the display:

   1: textFlow.flowComposer.updateAllContainers();

The View: displaying the text

You’ve learned how to create the model for storing the text using the TextFlow class. Now it is time to see how you can display this text. Basically, you have two options depending on what level of control you need to have on the text. Both methods convert the TextFlow into TextLine instances, which are part of the new Flash Text Engine. In order to display the TextLine you have to add it to a control that is a subclass of DisplayObjectContainer, such as Sprite.

TextLineFactory

If you just want to display the text and you don’t want to interact with it (for example, by selecting parts of it), then you can use TextLineFactory. This class has two static methods, createTextLineFromTextFlow and createTextLinesFromString, which create TextLine objects out of a TextFlow or a string. Here is an example of how to use it:

   1: var sprite:Sprite = new Sprite();
   2: //this serves as the bound for the text
   3: var bounds:Rectangle = new Rectangle(0,0,300,100);
   4: var txtStr:String = "This is sample text showing lines created by TextLineFactory.";
   5: var characterFormat:CharacterFormat = new CharacterFormat();
   6: characterFormat.fontSize = 48;
   7:
   8: TextLineFactory.createTextLinesFromString(callback, txtStr, bounds, characterFormat);
   9:
  10: //this is the callback function that will be called by createTextLinesFromString() 
  11: //method for each TextLine
  12: function callback(tl:TextLine):void{
  13:     sprite.addChild(tl);
  14: }

Flow Composer

If you want to be able to select or edit, then you have to use the Flow Composer. Every TextFlow instance has an object that implements the IFlowComposer interface. You can use the property flowComposer of the TextFlow to access this object. This object has the methods to associate the text with one or more containers and prepare the text for display.

For the container you can use any instance of a DisplayObjectContainer, such as Sprite for example. In order to link a container to another one (when you do this, if the text overflows the first container, then it will flow into the second container) to support scrolling or container formatting, the DisplayObjectContainer is wrapped inside an instance of DisplayObjectContainerController.

This is how you can add the container to a TextFlow object, and then trigger the formatting and displaying of the text:

   1: var sprite:Sprite = new Sprite();
   2: canvas.rawChildren.addChild(sprite);
   3: var controller:IContainerController = new DisplayObjectContainerController(sprite, 600, 400);
   4: textFlow.flowComposer.addController(controller);
   5: textFlow.flowComposer.updateAllContainers();

Adding interaction capabilities to the TextFlow

If you want to make the text selectable, you have to use a manager, SelectionManager and associate it with the interactionManager property of the TextFlow. You setup the manager like this:

   1: textFlow.interactionManager = new SelectionManager();

After the manager is assigned to the TextFlow’s interactionManager, the TextFlow has access to the event handlers of the manager. For example, it knows when a key is pressed, when the container loses or gains focus, and when text is selected.

If you want to enable editing features on top of selecting features, then you would use EditManager instead of SelectionManager:

   1: textFlow.interactionManager = new EditManager();

And finally, if you want to enable Undo/Redo commands, you use UndoManager, like this:

   1: textFlow.interactionManager = new EditManager(new UndoManager());

Import and Export text

For import/export you use the TextFilter object from the flashx.textlayout.conversion package. You’ve already seen one way to import XML to the TextFlow. What you have to do is this:

   1: var textInput:XML = <TextFlow><div><span>Some text here.</span></div></TextFlow>;
   2: var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);

You can also import plain text (you set the convertor to parse string, by setting the second argument to TextFilter.PLAIN_TEXT_FORMAT):

   1: var textInput:String = "Hello World, this is plain text";
   2: var textFlow:TextFlow = TextFilter.importToFlow(textInput, TextFilter.PLAIN_TEXT_FORMAT);

Text Layout Framework can export text in any one of three formats: plain text, FXG, or Text Layout Format. For example this is how you export XML text from an existing TextFlow instance using Text Layout Format:

   1: var out:XML = TextFilter.export(textFlow, TextFilter.TEXT_LAYOUT_FORMAT, ConversionType.XML_TYPE );

Code time: an example of using the Text Layout Framework in Flex 3.2

If you want to run the example, click here; you can download the project from here. This example uses flowComposer. I use a single container, and the textFlow is created using an XML file. In this XML I have four paragraphs in four languages, two of them are rleft-to-right, and two are right-to-left.

Also I add some controls to change the font size, to change the number of columns, and to change the direction of text for the first two paragraphs.

Screen shot of the app

You can click on the text, scroll, edit, delete, insert, undo, copy/paste and so on.

Without further delay, here is the source code (don’t forget that you need the Flex SDK 3.2, and the three SWC libraries of the Framework; if you choose to download the project, then you’ll have these libraries):

   1: <?xml version="1.0" encoding="utf-8"?>
   2: <mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="*" layout="absolute" creationComplete="init()" horizontalScrollPolicy="off" viewSourceURL="srcview/index.html">
   3: <mx:Script>
   4:     <![CDATA[
   5:         import mx.controls.CheckBox;
   6:         import mx.collections.ArrayCollection;
   7:         import flashx.textLayout.formats.Direction;
   8:         import flashx.textLayout.elements.InlineGraphicElement;
   9:         import flashx.textLayout.events.StatusChangeEvent;
  10:         import flashx.textLayout.formats.ContainerFormat;
  11:         import flashx.textLayout.formats.ICharacterFormat;
  12:         import flashx.textLayout.formats.CharacterFormat;
  13:         import mx.events.SliderEvent;
  14:         import flashx.textLayout.edit.UndoManager;
  15:         import flashx.textLayout.edit.EditManager;
  16:         import flashx.textLayout.container.DisplayObjectContainerController;
  17:         import flashx.textLayout.conversion.TextFilter;
  18:         import flashx.textLayout.elements.TextFlow;
  19:
  20:
  21:         public var directions:ArrayCollection = new ArrayCollection(
  22:                             [
  23:                                 {label:"Left-to-Right", data:Direction.LTR},
  24:                                 {label:"Right-to-Left", data:Direction.RTL}
  25:                             ]
  26:                         );
  27:
  28:         [Embed(source="air.png")]
  29:         [Bindable]
  30:         static public var imgClass:Class;
  31:
  32:         private var _textContainer:Sprite = null;
  33:
  34:         private static const textInput:XML = <TextFlow xmlns="http://ns.adobe.com/textLayout/2008">
  35: <div>
  36:  <span>And the text come here...</span>
  37: </div>
  38: </TextFlow>;
  39:
  40:         private var _textFlow:TextFlow;
  41:
  42:         private function init():void {
  43:             _textContainer = new Sprite();
  44:             canvas.rawChildren.addChild(_textContainer);
  45:
  46:             _textFlow = TextFilter.importToFlow(textInput, TextFilter.TEXT_LAYOUT_FORMAT);
  47:             _textFlow.flowComposer.addController(new DisplayObjectContainerController(_textContainer, canvas.width-40, canvas.height));
  48:             _textFlow.addEventListener(StatusChangeEvent.INLINE_GRAPHIC_STATUS_CHANGED, picLoaded);
  49:             //adding Select/Edit/Copy/Paste/Undo features
  50:             _textFlow.interactionManager = new EditManager(new UndoManager());
  51:             // initialize with a selection before the first character
  52:             _textFlow.interactionManager.setSelection(0,0);
  53:
  54:             _textFlow.flowComposer.updateAllContainers();
  55:         }
  56:
  57:         private function picLoaded(event:StatusChangeEvent):void {
  58:             var image:InlineGraphicElement = event.element as InlineGraphicElement;
  59:             _textFlow.flowComposer.updateAllContainers();
  60:         }
  61:
  62:         private function changeFontSize(event:SliderEvent):void {
  63:             var cf:CharacterFormat = new CharacterFormat(_textFlow.characterFormat);
  64:             cf.fontSize = event.value;
  65:             _textFlow.characterFormat = cf;
  66:             _textFlow.flowComposer.updateAllContainers();
  67:         }
  68:
  69:         private function changeNoColumns(event:SliderEvent):void {
  70:             var cf:ContainerFormat = new ContainerFormat(_textFlow.containerFormat);
  71:             cf.columnCount = event.value;
  72:             cf.columnGap = 15;
  73:             _textFlow.containerFormat = cf;
  74:             _textFlow.flowComposer.updateAllContainers();
  75:         }
  76:
  77:         private function changeTextDirection(event:Event):void {
  78:             _textFlow.direction = (event.target as ComboBox).selectedItem.data;
  79:             _textFlow.flowComposer.updateAllContainers();
  80:         }
  81:
  82:     ]]>
  83: </mx:Script>
  84:     <mx:VBox x="20" y="20">
  85:         <mx:Canvas id="canvas" width="600" height="400"  backgroundColor="#ffffff" verticalScrollPolicy="auto"/>
  86:         <mx:HBox width="100%">
  87:             <mx:HSlider labels="Font size:" minimum="10" maximum="22" snapInterval="1" change="changeFontSize(event)" enabled="true" />
  88:             <mx:HSlider labels="No of Columns:" minimum="1" maximum="2" snapInterval="1" change="changeNoColumns(event)" enabled="true" />
  89:             <mx:Label text="Text Direction:"/>
  90:             <mx:ComboBox change="changeTextDirection(event)" dataProvider="{directions}"/>
  91:         </mx:HBox>
  92:     </mx:VBox>
  93:
  94: </mx:Application>

Conclusion

So, that was my introduction to the Text Layout Framework. If you want to learn more, the first step is to go to the labs page, where you can take a look at the demo application (the one from which I took the screen shots at the beginning of this article). If you click on the small arrow at the top right of this app, you can download the source code for the current panel and see for yourself how it was done. You can also check out this demo, which lets you explore many of the typographic and text layout capabilities of TLF.

You can find the APIs here, and you can download samples for Flash CS4, Flex 3.2, and Gumbo from the labs page.

LATER UPDATE: if you wonder how to add a scrollbar to control the text, read this post.

Flash Media Server 3.5 is out

On January 12th, the latest version of Flash Media Server for video and audio streaming was released. Flash Media Server 3.5 builds on the state of the art features of the previous version (such as H.264/AAC video and audio streaming and content protection) with new features including: HD quality with dynamic streaming and DVR capabilities (you can skip, and go back in a stream as it was a locally recorded video). A HTTP server was added, so you can deploy a complete media delivery solution from a single server.

You can find more by going to Flash Media Server Developer Center. There you can read about the new features of FMS 3.5, best practices for dynamic streaming, how to make the transition from Microsoft Media Server to the Adobe Flash Platform, and much more.

When should you stick with an AIR application?

Andrew Shorten has an interesting post called “Determining when you should (and shouldn’t) use AIR“. From time to time we get this question, and Andrew’s post manages to offer an excellent set of rules to make the right choice.

My own answer to the same question is this rule of thumb: if your AIR application doesn’t offer anything on top of what a web application can offer, than AIR is not the way to go.

If you applied this rule, and you ended up with a web app, then you have to apply this second rule of thumb: if the browser chrome can literally kill your application, then go for AIR.

Let me explain the last sentence: try to imagine an instant messenger client implemented as a web application, and the same application implemented as a desktop application. Although both versions could offer the same features (ie. sending and receiving messages) only the one implemented as a desktop application is user friendly and usable. And when you talk about RIA applications, you’re talking about improved usability, and richness.

And I have another belief that I want to share with you, and maybe to validate. This belief comes partly from my previous experience as a developer working in an IT department for a financial company, and partly from my first experience with building an AIR application for our local office, back in 2007.

I think that if you are in this position: already know Flex or Flash, your work in the IT department supporting the company business, and you have to create an Enterprise RIA application, then you should always choose AIR.

Bear with me, and listen my arguments. In this environment it is my experience that they always expect you to finish the application in the next couple of days. Thus, it is quite possible for the first version that you will not have the time to implement anything using AIR APIs (such as offline/online workflow, integration with OS using drag and drop, and so on). But – and it is big “but” – almost all these types of applications deal with a lot of data. And it’s possible for the next version of the application to have the time to implement online/offline workflow, and the users will love you. If you worry about strict policies regarding installing the software on the boxes, then keep in mind that for example you can always pack the AIR app as an executable together with the runtime. You can read more on how to distribute AIR apps in the enterprise here.

By choosing AIR from the beginning, you are planning for the future. As you probably might know, one of the priorities Adobe has is bringing Flash Player 10 and AIR to mobiles and other devices.

What do you think?

MAX 2008 Keynotes available on Adobe TV

You can watch the keynotes from MAX 2008 on Adobe TV:

  1. Day one keynote: Vectors of Innovation
  2. Day two keynote: The Agency

Personally, I enjoyed the second day keynote a lot. Ben and Tim were super cool!

LiveCycle Developer Express via Amazon Web Services

Adobe LiveCycle ES Developer Express software is available starting today as hosted software in the Amazon cloud, through Amazon EC2 (Amazon Elastic Cloud Computing) and Amazon S3 (Amazon Simple Storage Service).

“With Adobe LiveCycle ES Developer Express, Adobe LiveCycle ES applications are pre-configured as ready to run server instances on the Amazon EC2 server. This can help reduce the time required to boot new server instances to minutes, allowing enterprise developers to quickly begin testing and modifying applications. Developers can effectively bullet-proof their applications without having to invest in a development environment or test lab. Old projects may be deleted or saved for future access and new projects can begin without any cleanup required from the last install.”

More here.

Adobe TV segment: Flex and AMFPHP

Another segment was release on Adobe TV, this time on Flex and AMFPHP (at the time when I shoot the video the ZendAMF wasn’t launched yet). Enjoy.

Cool Flex application on top of Google App Engine

Anirudh created a Flex application (Question and Answers on Flex/AIR) on top of the Google App Engine. The app looks very neat, and has some interesting features: uses OpenID for login, syntax highlighting as you type, and voting.

sandboxViolation

 

You can see the application here, and you can read about the making here.

PHP for Enterprise/Business WhitePaper

An interesting document put together by Irish PHP UG,  PHP Group, and some J2EE and .NET experts. You can download the PDF from here: http://short.ie/php-whitepaper.

Free ColdFusion workshops across Europe

If you have interest in ColdFusion and live near one of the following cities, you can register for a free ColdFusion workshop.

  1. Cologne, January 20th – register
  2. Amsterdam, January 22nd – register
  3. Brussels (NL), January 27th – register
  4. Brussels (FR), January 28th – register
  5. Paris, February 3rd – register
  6. London, February 5th – register

You can find out what’s new in the latest version of ColdFusion, learn how to build RIA applications with ColdFusion and Flex, AJAX sites, and more. It is quite possible at these events to meet some of the Adobe Platform Evangelists :)

It is possible more workshops will be scheduled in Barcelona, Zurich, Milan, and Stockholm.

← Previous PageNext Page →

Switch to our mobile site