Tag Archives: flex

Raw text printing from Adobe AIR

Printing raw text in Adobe AIR is kinda pain, specially if the text is too large, or multipage!

After some research and gerring ideas, I derived my own version of Util class which manages basic functionality.

package
{
	import mx.utils.StringUtils;
	
	import flash.display.Sprite;
	import flash.geom.Rectangle;
	import flash.printing.PrintJob;
	import flash.printing.PrintUIOptions;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;

	public class PrintUtils
	{
		public function PrintUtils()
		{}
		
		public static function printText(textString:String, printPageCount:Boolean = false):Boolean
		{
			var marginX:Number = 10;
			var marginY:Number = 10;
			var printJob:PrintJob = new PrintJob();
			var uiOpt:PrintUIOptions = new PrintUIOptions();
			
			if (!PrintJob.supportsPageSetupDialog) 
				return false;
			
			printJob.showPageSetupDialog(); 
			if( !printJob.start2(uiOpt, true) )
			{
				printJob.terminate();
				return false;
			}
			
			try
			{
				var fontSize:int = 10;
				var fontColor:uint = 0x000000;
				var format:TextFormat = new TextFormat( null, fontSize , fontColor );
				var printableArea:Rectangle = new Rectangle(0, 0, printJob.printableArea.width, printJob.printableArea.height);
				var lastChar:Number = 1;
				var pageCounter:int = 1;
				var pageCounterLine:int = printPageCount ? 1 : 0;
				while(lastChar > 0)
				{
					var remainingTextField:TextField = new TextField();
					remainingTextField.width = printableArea.width - (marginX*2);
					remainingTextField.height = printableArea.height - (marginY*2);
					
					remainingTextField.autoSize = TextFieldAutoSize.LEFT;
					remainingTextField.defaultTextFormat = format;
					remainingTextField.multiline = true;
					remainingTextField.wordWrap = true;
					
					remainingTextField.text = textString;
					
					// text strip out logic
					var lastLineTextString:String = StringUtil.trim(remainingTextField.getLineText(remainingTextField.bottomScrollV-pageCounterLine));
					if(lastLineTextString=="")
					{
						// find next printable line
						for(var j:int=1 ; j<(remainingTextField.bottomScrollV-pageCounterLine) ; j++)
						{
							lastLineTextString = StringUtil.trim(remainingTextField.getLineText(remainingTextField.bottomScrollV - pageCounterLine - j));
							if(lastLineTextString!="")
								break;
						}
					}
					
					lastChar = textString.indexOf(lastLineTextString) + lastLineTextString.length;
					var pageString:String = StringUtil.trim(textString.substr(0, lastChar));
					textString = StringUtil.trim(textString.substr(lastChar+1));
					
					if( StringUtils.isBlankOrNull(textString) )
						lastChar = 0;
					
					// print grabbed text on one page----------------------------------------------
					var printableSprite:Sprite = new Sprite();
					printableSprite.graphics.clear();
					//printableSprite.graphics.beginFill(0x00FF00);
					//printableSprite.graphics.drawRect(marginX, marginY, printableArea.width, printableArea.height);
					//printableSprite.graphics.endFill();
					
					var textFieldPrint:TextField = new TextField();
					textFieldPrint.width = printableArea.width - (marginX*2);
					textFieldPrint.height = printableArea.height - (marginY*2);
					textFieldPrint.x = marginX;
					textFieldPrint.y = marginY;
					
					textFieldPrint.autoSize = TextFieldAutoSize.LEFT;
					textFieldPrint.defaultTextFormat = format;
					textFieldPrint.multiline = true;
					textFieldPrint.wordWrap = true;
					
					textFieldPrint.text = pageString;
					
					printableSprite.addChild(textFieldPrint);
					
					// add pageCount
					if(printPageCount)
					{
						var pgCountTextFieldPrint:TextField = new TextField();
						
						pgCountTextFieldPrint.autoSize = TextFieldAutoSize.LEFT;
						pgCountTextFieldPrint.defaultTextFormat = format;
						pgCountTextFieldPrint.multiline = false;
						pgCountTextFieldPrint.wordWrap = true;
						pgCountTextFieldPrint.text = "Page " + pageCounter;
						
						pgCountTextFieldPrint.width = printableArea.width - (marginX*2);
						pgCountTextFieldPrint.x = marginX;
						pgCountTextFieldPrint.y = printableArea.height - pgCountTextFieldPrint.height - (marginY*2);
						
						printableSprite.addChild(pgCountTextFieldPrint);
						
						pageCounter++;
					}
					printJob.addPage(printableSprite, printableArea); 
				}
			}
			catch(error:Error)
			{
				return false;
			}
			printJob.send();
			return true;
		}
	}
}

This handles multi page text based on selected page size and margin. Also has minor feature of adding page number and so. This isn’t certainly rich utility, but also is enough to get started to add more features.

Lazy Loading of Proxies

While working on a pureMVC project, I realised that there were N number of proxies registered with facade (yes, ApplicationFacade). The truth was, not all have been used during life cycle of a typical user functionality.

So what? It was merely difficult to categories the proxies for need of individual module/functionality.

The simple idea is to implement Lazy Loading / Lazy registration of proxy!

Instead of declaring statement at compile time like

facade.registerProxy(new MyProxy()); 

I overridden

retrieveProxy(...)

function in extended Facade class:

override public function retrieveProxy(proxyName:String):IProxy
{
 var proxyInstance:IProxy = super.retrieveProxy(proxyName);
 if(proxyInstance==null)
 {
 var myClass:Class = getDefinitionByName(proxyName) as Class;
 if(!myClass)
 return null;

 var proxyInstance:IProxy = new myClass();
 if(proxyInstance)
 registerProxy(proxyInstance);
 }
 return proxyInstance;
}

This also takes care of not registering duplicate proxy.
Uh oh! While doing this trick, I encountered on more problem.


ReferenceError: Error #1065: Variable myClass is not defined.

I banged my head and tried to figure out the reason. After digging for some time, I found that the (class) definition of proxy was somehow not been retrieved with

getDefinitionByName() 

.
It wasn’t possible to simply add import statements with those Proxy class names as Flex compiler ignores such unused (yes while compiling none of proxy was referenced) imports.

Simple trick worked:
in extended facade class constructer, I declared each proxy as variable, something like:

public class ApplicationFacade extends Facade
{
 public function ApplicationFacade(parameter:SingletonEnforcer)
 {
 super();

 var myProxy:MyProxy;
 }
}

and that’s all I wanted! The trick is this code doesn’t force an instance of proxy to be created, still at runtime when required, it finds definition of MyProxy class.

Adobe Flash Player & KeyboardEvent – FullScreenEvent relation explored

Since Adobe Flash player has allowed limited keyboard support for full screen mode (application), the feature also comes with a strange cost.

When KeyboardEvent.KEY_DOWN event listener is registered on stage, KeyboardEvent with keycode 32 (equivalent to Space key) is fired always when the application goes from normal state to full screen state!

To make sure, I made a sample test application as under:

package 
{
	import flash.display.*;
	import flash.events.*;
	import flash.text.TextField;
	import flash.net.URLRequest;
	import flash.ui.Keyboard;

	public class fullScreenTest extends Sprite
	{
		private var loader:Loader;
		private var player:Object;
		public function fullScreenTest()
		{
			super();
			if(stage)
				onAddedToStage();
			else
				addEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
		}
		
		private function onAddedToStage(event:Event = null):void
		{
			if(hasEventListener(Event.ADDED_TO_STAGE))
				removeEventListener(Event.ADDED_TO_STAGE, onAddedToStage);
			var changeScreenState:TextField = new TextField();
			changeScreenState.text = "Change Screen State";
			changeScreenState.selectable = false;
			changeScreenState.addEventListener(MouseEvent.CLICK, onChangeScreenState);
			addChild(changeScreenState);
			
			stage.scaleMode = StageScaleMode.NO_SCALE;
			stage.align = StageAlign.TOP_LEFT;
			
			stage.addEventListener(FullScreenEvent.FULL_SCREEN, onToggleFullScreen);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, onKeyDown);
		}
		
		private function onChangeScreenState(event:Event = null):void
		{
			if(stage.displayState == StageDisplayState.NORMAL)
				stage.displayState = StageDisplayState.FULL_SCREEN;
			else
				stage.displayState = StageDisplayState.NORMAL;
		}
		
		private function onToggleFullScreen(event:FullScreenEvent):void
		{
			trace("is app in full screen? "+event.fullScreen);
		}
		
		private function onKeyDown(event:KeyboardEvent):void
		{
			if(event.keyCode == Keyboard.SPACE)
			{
				trace("event target : " + event.target +
						"\n\tevent keycode : " + event.keyCode);
			}
		}
	}
}

Up to surprise, KeyboardEvent.KEY_UP listener does the same job, perfectly fine, without sending extra KeyboardEvent with SPACE keyCode! Of course, this doesn’t apply when application state changes to normal, from full.

So, in a way the solution to this is either only use KeyboardEvent.KEY_UP event listener(s) or, remove event listener registered with KeyboardEvent.KEY_DOWN while switching from normal screen state of application to full screen, after some dummy time, (re)register listener for KeyboardEvent.KEY_DOWN !

I am yet not sure why FullScreenEvent event comes with KeyboardEvent event instance propagating through!

alpha & rotation issue for textArea with htmlText

I had been playing with this for one of a project requirement.

Description of scenario:

  • Embedded fonts ‘Times New Roman’ both, using default font manager (Batik) as well as AFE
  • The application consists of two text area components
  • For 1st textarea, I am setting text using ‘text’ property and setting font family, size and color using setStyle().
  • For second, I am providing text related information via ‘htmlText’ property.
  • Using a slider I should be able to change alpha value of both textArea components.

Behavioral problems:

  • When I change value using slider, the alpha effect is applied and visible for 1st textarea, but in case of second, alpha value gets applied but text has no visible impact of alpha.
  • When I rotate both textArea components using, 1st gets rotated, but not second. In case of both textareas, I am referring and using embedded font only. (font family ‘TNR’ in example)

I expect both textAreas behave identical.

As far as I know and received primary feedback from a famous flexer guy, my code is right. If I consider this, there is definitely a limitation / bug in flex SDK. Hence I suggested a new task in SDK.

Here is a code I had written to simulate the SDK limitation / bug:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Style>
		@font-face
		{
			src: url('/assets/fonts/times-new-roman.ttf');
			fontFamily: "TNR";
			font-weight:normal;
			font-style:normal;

			advancedAntiAliasing: true;
		}
	</mx:Style>
	<mx:Script>
		<![CDATA[
			import mx.events.SliderEvent;

			private function init():void
			{
				basicTxt.text = "This is a sample text!";
			}

			private function onChange(event:SliderEvent):void
			{
				basicTxt.alpha = event.value;
				htmlTxt.alpha = event.value;
			}

			private function doRotate(event:MouseEvent):void
			{
				basicTxt.rotation = 20;
				htmlTxt.rotation = 20;
			}
		]]>
	</mx:Script>
	<mx:VBox width="100%" height="100%">
		<mx:HBox width="70%" height="50%">
			<mx:TextArea id="basicTxt" width="80%" backgroundColor="blue" fontSize="36" height="100%" fontFamily="TNR"/>
			<mx:TextArea id="htmlTxt" width="80%" backgroundColor="blue" height="100%">
			<mx:htmlText>
					<![CDATA[<TEXTFORMAT LEADING="2"><P ALIGN="LEFT"><FONT FACE="TNR" SIZE="36" COLOR="#000000" LETTERSPACING="0" KERNING="0">This is a sample text!</FONT></P></TEXTFORMAT>]]>
				</mx:htmlText>
			</mx:TextArea>
		</mx:HBox>
		<mx:HSlider minimum="0" maximum="1" value="1" change="onChange(event)" />
		<mx:Button label="Rotate" click="doRotate(event)" />
	</mx:VBox>
</mx:Application>

I will appreciate if anyone can give some ideas / pointers to work around.

Flex Formatter

Flex Builder 3, an eclipse~ IDE for flex and actionscript based project development lacks few primary code indentation and refactoring functionalities by itself.

Searching for some other technical requirement drove me to Flex Formatter, a third party project on source! Cheers, its BSD license! 🙂

This tool is really small but very essential and useful plugin

Flex Formatter tools

Flex Formatter tools

Many times it happens that code is written in hurry to achieve some short term goal. Either some efforts need to invest to refactor and indent the code, or else go for Flex Formatter.

Built in capability to generate ASDoc is also impressive! However, I suppose, all these features, of flex formatter have been covered with Flash Builder 4.

Flash Player and Text

It’s been very difficult to achieve WUSIWUG in Flex 3 (Flash Player 9) and InDesign Server, at least for Text viz, font family, font size etc. In other words, a character with Arial font and size 12 in flash player will look differently from other non flash applications like text editors, design tools etc, having the same character specification. Therefore it is difficult to achieve the same output what you see in flash player, with InDesign Server and so in output PDF! Albeit, both are Adobe products!!!

Speaking to Serge Jespers about this he accepted that Flash player is built differently. Also, Anand added that the new Text Layout Framework, available with Flex 4, runs with Flash Player 10 has addressed many such issues. It has many changes as compared to traditional TextArea component available with Flex 3.

However, Text Layout Framework is not 100% compatible with Flex 3.2. It is not possible to embed and use font in Flex 3.2 (or 3.3) with TLF. The release notes from adobe clearly mentions this, considering root level change in embedded font structure. My experiment also failed to show an embedded font with TLF under Flex 3.3.

However, a point communicated by Jespers, that the TLF is made with the help of InDesign team is a ray of hope to go forward WUSIWUG. But is long way to migrate from Flex 3 to Flex 4, waiting for Flex 4 to be mature from its beta release.

Flex application & new fonts

A typical requirement was to provide some means so that anyone can upload / add new font(s) and the same can be used by Flex application. The Flex project should not require recompilation process.

Font, as a TTF or FON file cannot be used unless embedded, but that requires recompilation.

Searching around net gave me a way to solve this gave me a reasonable good solution.

Instead of specifying external styles such as <mx:Style source=”assets/styles/fonts.css”/> I used StyleManager.

Any change in fonts.css requires project recompilation to get the change in effect.

So, I compiled fonts.css using mxmlc fonts.css . This compiled CSS to SWF.

Then I loaded fonts at runtime using StyleManager.loadStyleDeclarations(“fonts.swf”, true, true);

And that’s it….! The font(s) inside fonts.swf can be used and that gives the same effect as embedded.

RIA in a new avtar with Flash Builder 4

Adobe Flash Builder, formerly Flex Builder is already out with beta tag at present. Personally, I dislike the renamed brand as Flash Builder. Already, many have misconception that Flash and Flex are similar! The only common point is that both supports ActionScript (ECMA 335), but so what? Application of both suits are totally different. Of course, the SDK brand remains same, Flex SDK version 4, Gumbo.

It is near to Adobe’s Creative Suite family. In Flash Builder 4, you can work with Flash MovieClip, import designs from Catalyst. So is pointer in that direction.

Data centric features are really attractive, be it data binding or data object like Hibrnate in java, representing data as POJO. But, this is limited to CRUD only. Flex 4 has backward compatibility – with halo components!

Features with newer IDE is welcomed, especially network monitor. This eliminates need of httpfox and such third party browser plug-in!

Overall, Flex 4 seems to be reached to the community expectations! 🙂 Here is something more. Tim Buntel says this.

Adobe Flash Builder, formerly Flex Builder is already out with beta tag at present. Personally, I dislike the renamed brand as Flash Builder. Of course, the SDK brand remains same, Flex SDK version 4, Gumbo.

It is near to Adobe’s Creative Suite family. In Flash Builder 4, you can play with Flash MovieClip, import designs from Catalyst. So is that pointer.

Data centric features are really attractive, be it data binding or data object like in Hibrnate with java, representing data as POJO. But, this is limited to CRUD only. Flex 4 has backward compatibility – with halo components (I am yet not sure about the level)!

Features with newer IDE is welcomed, especially network monitor. This eliminates need of httpfox and such third party browser plug-in!

Overall, Flex 4 seems to be reached to the community expectations! 🙂

Flex (Flash Player) – DPI and input/output

DPI is often confused with screen resolution. Actually when screen resolution changes (in pixel height x width) the DPI rate is not necessarily changed.

In most cases DPI remains same, unless changed intentionally. In simple language, increasing screen resolution will allow more dots to be displayed on screen, by decreasing distance between each dot. Increasing DPI rate of screen but keeping resolution will increase number of dots per inch; by decreasing dot thickness, and that will eventually result into more dots in whole screen, with unchanged resolution.

When image resolution comes into picture, DPI plays role to consider depth of an Image. More the DPIs, better is the image – depth.
Two similar looking image (at its original size) may have different DPIs. The image with higher DPI rate, if zoomed in, will not get blurred or distorted very easily.

DPI is the somewhat similar concept of mega pixel – the camera term.

This term and its effect came into picture when I started input and output to real wprld from Flex application!
Flex application (or flash player) accepts width, height, x, y or such dimension properties in pixels only. The real world deals with inch, foot, centimeter or any such unit.

So where the game is?

Above simple question puzzles many.
widthInch = widthPixels/DPI is the key!

Say you have image with 500 pixels, width in inch will be 500/DPI. So if DPI is 96, then width is 500/96inches.

In case of flash player, DPI rate is 96.
So if I want to display an image in 2 inches width, I need to set image width to 2*96 pixels. This ignores Image (physical image file) and its DPI rate as I am going to display in flash player, not any image editor.

Also, this bug post is strange upto my knowledge. Flash Player’s DPI seems constant, ignoring screen DPI.

Simple solution to a complex problem – customized Rich Text Editor

Apparently, creating customized RichTextEditor component in flex was looking time consuming. The rich APIs that flex provides made this task easier.

I retrieved reference of different styling controls from a hidden richTextEditor object, arranged them as per my requirement, and its done!

I thought to make a custom editor with customized control positions is a big task, but is not what I thought! 🙂

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="absolute" creationComplete="init()">
	<mx:Script>
		<!&#91;CDATA&#91;
			import mx.controls.Button;
			import mx.controls.TextArea;
			import mx.controls.TextInput;
			import mx.controls.RichTextEditor;

			private function init():void
			{
				var textInput:TextInput = rte.linkTextInput;
				textInput.visible = false;

				var bulletsButton:Button = rte.bulletButton;
				bulletsButton.visible = false;

				var fontFamily:DisplayObject = rte.fontFamilyCombo;
				font.addChild(fontFamily);
				var fontSize:DisplayObject = rte.fontSizeCombo;
				font.addChild(fontSize);

				var alignBtns:DisplayObject = rte.alignButtons;
				effects.addChild(alignBtns);

				var boldBtn:DisplayObject = rte.boldButton;
				var italicBtn:DisplayObject = rte.italicButton;
				var underlineBtn:DisplayObject = rte.underlineButton;
				var colorPicker:DisplayObject = rte.colorPicker;
				var styles:HBox = new HBox();
				styles.addChild(boldBtn);
				styles.addChild(italicBtn);
				styles.addChild(underlineBtn);
				styles.addChild(colorPicker);
				effects.addChild(styles);

				var textArea:TextArea = rte.textArea;
				editor1.addChild(textArea);
			}
		&#93;&#93;>
	</mx:Script>
	<mx:VBox id="controls" width="250" height="100">
		<mx:HBox id="font" />
		<mx:HBox id="effects" />
	</mx:VBox>
	<mx:Panel id="editor1" x="300" width="300" height="300"/>
	<mx:RichTextEditor id="rte" visible="false" />
</mx:Application>
%d bloggers like this: