MarchingAntsRect demo usage

a new class was added in Nabiro: MarchingAntsRect wich render a rectangle with dotted line, used to represent a selection area, here is a very simple demo:
<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
width="800" height="600"
layout="absolute">

<mx:Script>
<![CDATA[
import com.gnstudio.nabiro.ui.MarchingAntsRect;

override protected function childrenCreated():void{

super.childrenCreated();

var maRect1:MarchingAntsRect = new MarchingAntsRect();
var r1:Rectangle = new Rectangle(10, 30, 100, 30);
maRect1.draw(r1);

var maRect2:MarchingAntsRect = new MarchingAntsRect();
var r2:Rectangle = new Rectangle(130, 80, 200, 400);
maRect2.draw(r2);

var maRect3:MarchingAntsRect = new MarchingAntsRect();
var r3:Rectangle = new Rectangle(10, 170, 30, 160);
maRect1.draw(r3);

mainPanel.addChild(maRect1);
mainPanel.addChild(maRect2);
mainPanel.addChild(maRect3);
}

]]>
</mx:Script>

<mx:Panel id="mainPanel" width="100%" height="100%" />
</mx:Application>

stylable custom events in mxml

this isn't an unpublished info for sure, but can be useful as a little reminder.
The scenario:
You have some custom mxml event and need to add your custom event o simply dispatch an ordinary event not listed in your parent class. Usually extending mxml comp it's a matter to base on IEventDispatcher inherited class, so it's quite easy to invoke dispatchEvent BUT ...
You want to refer to you component in mxml code, f.i.: change="onCustomCompChange(event)"
the solution:
- add the event you need via Metadata tag
- of course, if it's a custom event, you must implement it :D
in this snippet we simple add Event.CHANGE to an HBox (that's current missing by default)
// your custom comp
<?xml version="1.0" encoding="UTF-8"?>
<mx:HBox xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Metadata>
[Event(name="change", type="flash.events.Event")]
</mx:Metadata>

<mx:Script>
<![CDATA[

import flash.events.Event;
import flash.events.MouseEvent;


/*... */


/**
* event that dispatch the event we added
*/
internal function onBtClickmeClick(evt:MouseEvent):void {

if(hasEventListener(Event.CHANGE)) dispatchEvent(new Event(Event.CHANGE, true));
}

]]>
</mx:Script>

<mx:Button label="clickme" click="onBtClickmeClick(event)" />

</mx:HBox>

// your app demo, fit the path to your CustomComp
<?xml version="1.0" encoding="UTF-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
ui="path.to.your.customcomp.*">

<mx:Script>
<![CDATA[

import flash.events.Event;
import flash.events.MouseEvent;

/*... */

/**
* change listener on customComp
*/
internal function onCustomCompChange(evt:Event):void { trace("something has changed!"); }

]]>
</mx:Script>



<ui:CustomComp change="onCustomCompChange(event)" />
</mx:Application>


/*
:)
Jaco
*/

HTTPService and basic authentication

suppose your HTTPService goes to a server that need basic authentication, you'll be prompted EACH time with a pop-up, fill with user and password. This can be very annoying specially in long dev/debug session.
setCredentials and setRemoteCredentials for different reasons, don't work with "simple" http auth.
Solution:
- add custom header and send it before any further request
how to implement:
- define your HTTPService as you desidred (mxml, as)
- add initialization code as shown below:
<?xml version="1.0"?>
<!--
/**
* @author jaco
*
* created on 17/10/2009 16.51.03
*/
-->
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
creationComplete="init_app()">

<mx:Script>
<![CDATA[

import mx.utils.Base64Encoder;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;


[Bindable]
private var SERVER_APP_URL:String = "http://your.auth_server.com/your_app"; // accommodate with your real url

/**
* application initialization
*/
internal function init_app():void {

var b64:Base64Encoder = new Base64Encoder();
b64.insertNewLines = false;
b64.encode("youruser:yourpwd"); // credentials must be base64 encoded, change to fit your needs

abService.headers = {Authorization:"Basic " +b64.toString()};
abService.send();

// ...
}

/**
* event triggered on service error
* @param error event
*/
internal function onServiceFault(evt:FaultEvent):void {
/* TODO */
trace(evt.type, evt.fault);
// your code here
}

/**
* event triggered on service result
* @param result event
*/
internal function onServiceResult(evt:ResultEvent):void {
/* TODO */
// your code here
}
]]>
</mx:Script>

<mx:HTTPService id="abService"
url="{SERVER_APP_URL}"
method="POST"
resultFormat="e4x"
fault="onServiceFault(event)"
result="onServiceResult(event)" />

<mx:Panel title="" height="100%" width="100%"
paddingTop="5" paddingLeft="5" paddingRight="5" paddingBottom="5">

</mx:Panel>
</mx:Application>

load binary data via xml message

say you are dealing with a backend via xml messages, for some instance you need to load binary data. Flash player can load images, sounds, videos and other movies, but these are operations that go separated from the data exchange context. You can join xml messages and binary content using base64 classes.
The advantages are:
- concurrent messages with content
- you can build up your own distributed objects
- more opportunities to hardening your movies, e.g content protection, cryptography, progressive and conditioned loading
and the cons:
- messages are greater, almost 20/30%
- if you plan to getting touch with real data, some ByteArray skills needed
- some people prefers amf, faster and data driven
// these two code files show how to load a sample image using xml message generated from php


// as3, TryB64php.as

/**
* @author jaco
*
* created on 16/10/2009 16.56.51
*/
package {

import flash.display.*;
import flash.events.*;
import flash.text.*;
import flash.net.*;
import flash.geom.*;
import flash.utils.*;

// as3, got from http://dynamicflash.com/goodies/base64/
// if you're in flex/air, there are mx.utils.Base64* classes
import com.dynamicflash.util.Base64;


/**
*
*/
public class TryB64php extends MovieClip {

private static const PHP_URL:String = "get_xml_b64response.php";

private var ul:URLLoader;
private var ld:Loader;

/**
* the constructor
*/
function TryB64php(){

var ur:URLRequest = new URLRequest(PHP_URL);
ld = new Loader();
ul = new URLLoader();

addChild(ld);

ul.addEventListener(Event.COMPLETE, onULComplete);
ul.load(ur);
}

private function onULComplete(evt:Event):void {

var xml:XML = XML(ul.data);

var ba:ByteArray = Base64.decodeToByteArray(xml);
ld.loadBytes(ba);
}
}
}


// php, get_xml_b64response.php

<?php
/*
* Created on 16/ott/2009
*
* jaco_at_pixeldump
*/

define("XML_HEADER", "<?xml version=\"1.0\"?>");
define("NL", "\r\n");

define("RESPONSE_INFO", "info");
define("RESPONSE_VALUE_BASE64", "base64");

/**
* read resource from path
* @param file name
* @param directory
*
* @return xml instance with base64 encoded data
*/
function get_resource($resFN, $resDir = "./") {

$filePath = $resDir .$resFN;
$fRes = file_get_contents($filePath, FILE_BINARY);

return create_simpleXmlMessage(base64_encode($fRes), RESPONSE_VALUE_BASE64);
}

/**
* create an xml message
* @param message string
* @param response type
*
* @return formatted xml instance with given data
*/
function create_simpleXmlMessage($str, $type = RESPONSE_INFO) {

$xmlStr = XML_HEADER .NL;
$xmlStr .= create_xmlNode("response", $str, array("type" => $type, "timeStamp" => mktime()));

return $xmlStr;
}

/**
* create a simple xml node with some data population
* @param node name
* @param node content
* @param attributes
* @param CDATA flag
*
* @return formatted xml node with given data
*/
function create_xmlNode($nodeName, $nodeContent = "", $attrs = array(), $cDataFlag = true){

$xmlStr = "<" .$nodeName ." ";
$sfx1 = $cDataFlag ? "<![CDATA[" : "";
$sfx2 = $cDataFlag ? "]]>" : "";

if(count($attrs))
foreach($attrs as $k => $v) $xmlStr .= $k ."=\"" .$v ."\" " ;

if(strlen($nodeContent)){
$xmlStr .= ">" .$sfx1 .$nodeContent .$sfx2;
$xmlStr .= "</" .$nodeName .">";
}
else $xmlStr .= "/>";

return $xmlStr;
}

// the app

header("Content-type: text/xml");
echo get_resource("sample_avatar.png"); // sample image
?>

DataGrid Custom Drag

it's simple to add drag/drop feature to DataGrid, just add dragEnabled="true", but in most cases the default drag behaviour is not what you expect 'cause it renders the whole row during dragging operation. There are different ways to change, the one i'm going to show is about extending DataGridDragProxy class, here is the summary of steps:
- create a custom component that extends DataGrid
- assign a default DataGridDragProxy via dragImage overriden method
- create a class that extends DataGridDragProxy
- override createChildren method and work within to implement your stuff
- use your custom comp and use the attribute dragProxy to point towards your DataGridDragProxy extended class
// custom component, say the name is: AssetDataGrid

<?xml version="1.0"?>
<mx:DataGrid xmlns:mx="http://www.adobe.com/2006/mxml">

<mx:Script>
<![CDATA[
import mx.controls.dataGridClasses.DataGridDragProxy;
import mx.core.IUIComponent;

import prj.ui.*;

/**
* @public
* class to use as DragProxy image
*/
[Bindable]
public var dragProxy:Class = DataGridDragProxy; //set the default value to the standard DataGridDragProxy class

override protected function get dragImage():IUIComponent {
var dgdp:IUIComponent = new dragProxy();
dgdp.owner = this;
return dgdp;
}
]]>
</mx:Script>
</mx:DataGrid>

// DataGridDragProxy extended class, AssetDragProxy

package prj.ui {

import flash.display.*;

import mx.core.*;
import mx.controls.*;
import mx.controls.dataGridClasses.DataGridDragProxy;
import mx.controls.listClasses.IListItemRenderer;

import prj.ui.*;

public class AssetDragProxy extends DataGridDragProxy {

[Embed(source="/../assets/stock/layout.png")]
[Bindable]
private var LayoutIcon:Class; // custom drag icon

/**
* the constructor
*/
public function AssetDragProxy():void {
super();
}

override protected function createChildren():void {

super.createChildren();

var do2dContent:* = getChildAt(0);

while (do2dContent.numChildren)
do2dContent.removeChildAt(0); // remove all unuseful children, be aware of the mask concerns if your are going to put cumbersome stuff

var items:Array = AssetDataGrid(owner).selectedIndices;
var dg:AssetDataGrid = AssetDataGrid(owner);

// your stuff here
var item:Object = dg.dataProvider[items[0]];
var label:UITextField = new UITextField();
label.text = item.name;
label.x = 16;

var bmp:Bitmap = new LayoutIcon() as Bitmap;
do2dContent.addChild(bmp);
do2dContent.addChild(label);

x = this.mouseX - 15;
}
}
}

// demo:
// files: src
// |_ DemoApp.mxml
// |_ prj
// |_ ui
// |_ AssetDataGrid.mxml
// |_ AssetDragProxy.as

<?xml version="1.0"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
xmlns:ui="prj.ui.*" width="100%" height="100%">

<mx:ArrayCollection id="stubDataset">
<mx:Object name="child_play.png" width="150" height="100" size="35616" />
<mx:Object name="toy.png" width="480" height="250" size="586566" />
<mx:Object name="playground.png" width="320" height="240" size="135648" />
<mx:Object name="teacher.jpg" width="600" height="350" size="385616" />
<mx:Object name="funny_dog.jpg" width="532" height="412" size="412616" />
</mx:ArrayCollection>

<mx:Panel width="100%" height="100%" label="custom datagrid drag image">
<ui:AssetDataGrid id="dgImages"
dataProvider="{stubDataset}"
width="100%" height="100%"
dragProxy="prj.ui.AssetDragProxy"
dragEnabled="true">
<ui:columns>
<mx:DataGridColumn dataField="name" headerText="file name"/>
<mx:DataGridColumn dataField="width" headerText="width" width="40" />
<mx:DataGridColumn dataField="height" headerText="height" width="40" />
<mx:DataGridColumn dataField="size" headerText="size" width="60"/>
</ui:columns>
</ui:AssetDataGrid>
</mx:Panel>
</mx:Application>

// please note that datagrid columns inherits from the custom component, don't use mx

* inspired by: http://www.dgrigg.com/post.cfm/11/03/2006/DataGrid-Drag-Image