wtorek, 18 sierpnia 2009

Adobe AIR and Flex SDK dirty secrets part 1

Well there was a while since Adobe put their AIR(Adobe Integrated Runtime) to the public. The newest one is AIR 1.5.2 so there was 1.5.1, 1.5, 1.1 and 1.0 version. Adobe AIR 1.0 was released something like year ago and there are already 5 versions of this runtime each got some bug fixed.
All you should see here in release notes:
http://www.adobe.com/support/documentation/en/air/releasenotes.html
I unfortunately can't. This is only blank page for me for each version but not the last one.

So shortly, we get installer languages support in AIR, it supports 3 platforms Windows, Mac OS X and Linux.

The installer looks different and there are some more, less important enhancements like ex. check disk space available, or check transparency support.

Well when AIR was released the special flex sdk components get released too for programmers to make their life easier.

O RLY ?

I don't want to blame anybody and talk that air is bad , or the flex sdk code is sloppy. I'm also not the best programmer in the world. But since I use adobe technology I want to share what is bad and what is good for me and what you are dealing with while working with that technology.

Well Adobe want to release Flex SDK 4 but I got one fresh on my drive directly form svn and as far as I know nothing has changed what I'm writing about. That's public beta so don't wait for that changes I will make here for you.

The posts will be specially for You, that want to make glamurous applications and don't want to tear one's hair out.

Something easy for the start then:
mx.core.WindowedApplication have got showFlexChrome parameter that can be true or false. It's important for not with system chrome fancy applications.

Flexbuilder shows that this param it's style property so you can set it in style sheet. Well not exactly since it's not obvious how to use that style and since it's buggy one.

The positive part of the story is that Flex SDK is some kind of open source now so you can view the WindowedApplication component source, Thank You Adobe we need fix some stuff ;)

Let's back to the code.

Well we need to find showFlexChrome param. The first one is at 1768 line (WTF?) in createChildren() method. We are some kind of experienced Flex SDK users so we know what the method do cause we can do AS3 custom component's. It's obvious one that's creating all children of the component based on parameters you pass. so there is code:

/**
* @private
*/
override protected function createChildren():void
{
super.createChildren();

if (getStyle("showFlexChrome") == false ||
getStyle("showFlexChrome") == "false")
{
setStyle("borderStyle", "none");
setStyle("backgroundAlpha", 0);
return;
}

if (!_statusBar)
{
_statusBar = statusBarFactory.newInstance();
_statusBar.styleName = new StyleProxy(this, statusBarStyleFilters);
rawChildren.addChild(DisplayObject(_statusBar));
showStatusBarChanged = true;
}

if (systemManager.stage.nativeWindow.systemChrome != "none")
{
setStyle("borderStyle", "none");
return;
}

if (!_titleBar)
{
_titleBar = titleBarFactory.newInstance();
_titleBar.styleName = new StyleProxy(this, titleBarStyleFilters);
rawChildren.addChild(DisplayObject(titleBar));
showTitleBarChanged = true;
titleBarFactoryChanged = false;
}

if (!gripper)
{
gripper = new Button();
var gripSkin:String = getStyle("gripperStyleName");
if (gripSkin)
{
var tmp:CSSStyleDeclaration =
StyleManager.getStyleDeclaration("." + gripSkin);
gripper.styleName = gripSkin;
}
rawChildren.addChild(gripper);

gripperHit = new Sprite();
gripperHit.addEventListener(MouseEvent.MOUSE_DOWN, mouseDownHandler);
rawChildren.addChild(gripperHit);
}
}

Let's save the whole class in our project first to make sure the changes will take part.

Well just make structure mx.core, make class WindowedApplication.as, copy all source to it and also copy Version.as source to our mx/core structure and that's it we now got custom WindowedApplication but get back to main part for a second and we got 3 options how to set our style:
1. in component tag - it's working





2. in component in style tag - it's working again




WindowedApplication {
showFlexChrome: false;
}



3. in external style main.css - it's working again wow







/* CSS file */
WindowedApplication {
showFlexChrome: false;
}



So what's about ? Well let's do something like set showFlexChrome=false and then by calling setStyle() set it true. Also set our background color to red.


applicationComplete="appCompleteHandler()">

WindowedApplication {
showFlexChrome: false;
background-color: #ff0000;
}


private function appCompleteHandler():void {
setStyle('showFlexChrome', 'true');
}
]]>



It's not working now, the background is not red, why ?
That's why http://bugs.adobe.com/jira/browse/SDK-11107
Cause of the createChildren() method. There is a condition:

if (getStyle("showFlexChrome") == false ||
getStyle("showFlexChrome") == "false")
{
setStyle("borderStyle", "none");
setStyle("backgroundAlpha", 0);
return;
}

and that sets our backgroundAlpha to 0. If we set our showFlexChrome to false the background will not be showed cause alpha is 0. Wtf and why somebody is deciding for us? Also somebody decided that the borders style now will be none.
Well... the best part is third line return;
The children won't be created so the flex chrome will never be showed.


I don't really know why the showFlexChrome style is existing and why it's not a simple method cause we can loose the chrome just by doing this:


applicationComplete="appCompleteHandler()">

WindowedApplication {
background-color: #ff0000;
}


private function appCompleteHandler():void {
showGripper = showStatusBar = showTitleBar = false;
}
]]>



So it could be simple a getter / setter in WindowedApplication and it will be much simple for us.

//----------------------------------
// showFlexChrome
//----------------------------------

public function set showFlexChrome(value:Boolean):void {
showGripper = showStatusBar = showTitleBar = value;
}

public function get showFlexChrome():Boolean {
return _showGripper && _showStatusBar && _showTitleBar;
}

Let's make it in WindowedApplication.as - remove all showFlexChrome style, make some modifications to keep the code clear and what ? It's working as expected and now you can make some demo like this:


applicationComplete="appCompleteHandler()">

WindowedApplication {
background-color: #ff0000;
}


import flash.utils.setInterval;

private function appCompleteHandler():void {
setInterval(changeChrome, 2000);
}

private function changeChrome():void {
showFlexChrome = !showFlexChrome;
}
]]>



or more practical like this:


applicationComplete="appCompleteHandler()"
showFlexChrome="false">

WindowedApplication {
background-color: #ff0000;
}


import flash.utils.setTimeout;
import flash.utils.setInterval;

private var _mouseIsOver:Boolean;

private function appCompleteHandler():void {
addEventListener(MouseEvent.MOUSE_OVER, mouseRollOverHandler);
addEventListener(MouseEvent.MOUSE_OUT, mouseRollOutHandler);
}

private function mouseRollOverHandler(event:Event):void {
_mouseIsOver = showFlexChrome = true;
}

private function mouseRollOutHandler(event:Event):void {
setTimeout(hideFlexChrome, 1000);
_mouseIsOver = false;
}

private function hideFlexChrome():void {
showFlexChrome = _mouseIsOver;
}
]]>




happy codding

download sample with mx.core.WindowedApplication modifications

środa, 5 sierpnia 2009

namespace stuff for flex and as3

Well namespace here namespace there. Let me see what is that namespace in as3 ?

If you were ever programming flex framework you already have used it!

I'll try to show you the whole magic:


xmlns:mx="http://www.adobe.com/2006/mxml"

That's it.

layout="absolute"
minWidth="1024"
minHeight="768">



The namespace is "http://www.adobe.com/2006/mxml" and the namespace accessor is simply "mx". You can change it as you wish so typing



layout="absolute"
minWidth="1024" minHeight="768">



will be ok, but... Follow the white rabbit(The Rules) !

If you change to super and accessor will be mx



layout="absolute"
minWidth="1024"
minHeight="768">



"The prefix "super" for element "super:Application" is not bound."

If you change the namespace to super and live the "mx"



layout="absolute"
minWidth="1024"
minHeight="768">



it will throw you error again "The prefix "mx" for element "mx:Application" is not bound."

Cause it couldn't find the namespace for your prefix in the component definition.

So what when you want expose some of your components. You can add the same namespace but with different prefix ex.



xmlns:super="http://www.adobe.com/2006/mxml"
layout="absolute"
minWidth="1024"
minHeight="768">



remember

you cannot duplicate the namespaces with same accessor

xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
minWidth="1024"
minHeight="768">



is wrong cause there cannot be two "mx" accessors


If you ever created custom flex component and you placed it for ex. in my.beutiful.components.*
your namespace will be the path to them and you can name your accessor as you wish - ex. you can type:



xmlns:super="my.beautiful.components.*"
layout="absolute"
minWidth="1024"
minHeight="768">





If you have only one component from my.beautiful.components.* it will be correct to also type:



layout="absolute"
minWidth="1024"
minHeight="768">



So you can refactor your application without remember to clean out your main container namespace.


Well you if you don't follow the rules you can now type:




xmlns:display="flash.display.*"
width="100%" height="100%">



But please don't do this :D


Well what's with as3 ? Why we need namespaces ? Let's see flex again and will create some more magic canvas



package my.beautiful.components
{
import mx.containers.Canvas;

public class SuperCanvas extends Canvas
{
public function SuperCanvas()
{
super();
}
}
}

Simply add some default flex namespace to it called mx_internal



package my.beautiful.components
{
import mx.containers.Canvas;
import mx.core.mx_internal;

use namespace mx_internal

public class SuperCanvas extends Canvas
{
public function SuperCanvas()
{
super();
}
}
}

Now we can access all the mx_internal functions and properties and change them - sometimes it is very handy. Especially when creating custom components.

To check what functions are mx_internal by Ctrl+Space eclipse shortcut you need some Flash Builder beta. Just grab one from adobe labs site
You simply type there override mx_internal function and the shortcut (Ctrl+Space) and here we go - all the mx_internal functions pop up in the window.

We will use some mx_internal stuff now to change something simple:



package my.beautiful.components
{
import mx.containers.Canvas;
import mx.core.ScrollPolicy;
import mx.core.mx_internal;

use namespace mx_internal

public class SuperCanvas extends Canvas
{
public function SuperCanvas()
{
super();
_horizontalScrollPolicy = ScrollPolicy.ON;
_verticalScrollPolicy = ScrollPolicy.OFF;
}
}
}

We set the scroll policy in the canvas directly not trough reference. So to be clear - you use your namespace to cover some of your code, that you don't want the not experienced user to use directly.
Some user with your code can do something like that:



package my.beautiful.components
{
import mx.containers.Canvas;
import mx.controls.Button;
import mx.core.ScrollPolicy;
import mx.core.mx_internal;

use namespace mx_internal

public class SuperCanvas extends Canvas
{
public function SuperCanvas()
{
super();
_horizontalScrollPolicy = ScrollPolicy.ON;
_verticalScrollPolicy = ScrollPolicy.OFF;
}

override public function set horizontalScrollPolicy(value:String) : void {
//
}

override public function get horizontalScrollPolicy() : String {
return ScrollPolicy.AUTO
}
}
}

If you need to use some of the method in other class not by inheritance and don't want to expose it to the world use namespace

keep looking at the Fex SDK source code and learning, I hope that I helped you