Flex Tyro

Tuesday, July 21, 2009

Drag and Drop: double binding?

We had a minor fracas at work this morning. The burning issue: does Flex 3, in fact, have double binding?

The official answer is no, Flex 3 does not have double binding. But... it seems that in certain cases, doubly-bound behavior is nevertheless present.

For example:

* create a tree, and enable drag and drop behavior
* set your tree's data provider as an ArrayCollection with nested Arrays; in other words, a treelike structure.
* grab a handy data serialization package, such as as3yaml (http://code.google.com/p/as3yaml/), to display the data structure, then run in debug mode.

Then start dragging elements around, and you'll see something natural: as elements change position, the underlying data structure changes. In other words, the data provider is the model, and the Tree is the view... but also the controller. Change the tree, change the underlying data provider.

Acts like double binding. In reality, it's boilerplate code underwiring the drag and drop attributes on things like Tree and DataGrid. Remember: [Bindable] is boilerplate code forcing the view to change when the model changes. And this one sort of seems like the reverse... hence it is very like double binding.


My sample code:

<?xml version="1.0" encoding="utf-8"?>
<mx:Application
xmlns:mx="http://www.adobe.com/2006/mxml"
layout="absolute"
creationComplete="handleCreationComplete()">

<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
import org.as3yaml.*;

private var node1:Object =
{
label: 'parent 1',
index: 0,
children:
[
{ label: 'A' }, // , index: 0 },
{ label: 'B' }, // index: 1 },
{ label: 'C' }, // index: 2 }
]
};

private var node2:Object =
{
label: 'parent 2',
index: 1,
children:
[
{ label: 'D' }, //index: 0 },
{ label: 'E' }, //index: 1 },
{ label: 'F' }, //index: 2 }
]
};

private var node3:Object =
{
label: 'parent 3',
index: 1,
children:
[
{ label: 'G' }, //index: 0 },
{ label: 'H' }, //index: 1 },
{ label: 'I' }, //index: 2 }
]
};


[Bindable]
private var mydata:ArrayCollection = new ArrayCollection([node1, node2, node3]);

private function handleCreationComplete():void
{
dump();
}

private function dump():void
{
var s:String = YAML.encode( mydata.source );
trace( s );
}
]]>
</mx:Script>
<mx:Tree id="mytree"
dataProvider="{mydata}"
dragEnabled="true"
dropEnabled="true"
dragComplete="dump()"
editable="true"
x="40" y="40" width="300" height="300"
/>
</mx:Application>

Monday, July 20, 2009

Refresh that ArrayCollection

So I have this ArrayCollection, which looks basically like this:

[Bindable]
public var d1:ArrayCollection = new ArrayCollection(
[
{ label: 'first', code: 'A', num: 4 },
{ label: 'sec', code: 'B', num: 7 },
{ label: 'tria', code: 'C', num: 9 }
]
);

It's the dataProvider for a DataGrid, like this:

<mx:DataGrid id="dg1"
dataProvider="{d1}"
dragEnabled="true"
dragDrop="handleDragDrop(event)"
dropEnabled="true"
x="320" y="126">
<mx:columns>
<mx:DataGridColumn headerText="Column 1" dataField="label"/>
<mx:DataGridColumn headerText="Column 2" dataField="code"/>
<mx:DataGridColumn headerText="Column 3" dataField="num"/>
</mx:columns>
</mx:DataGrid>

And then, I've got a horizontal slider that sets a value in the ArrayCollection, like this:

<mx:HSlider id="hslider" x="10" y="320" width="302"
minimum="1" maximum="10" snapInterval="1"
change="d1.getItemAt(0).num = this.hslider.value"
labels="{[1,2,3,4,5,6,7,8,9,10]}" />

So I can slide the slider, and the "num" attribute of the first element in d1 changes, but the display list in the datagrid doesn't change. And so I learned (or perhaps re-learned) a lesson today:

Whenever you change data in a data provider, also call refresh() on it.

Not only does this re-run filters and sorts, it also refreshes the display. So when a single value changes, calling refresh() will update display lists that are bound to the array.

So, the slider's change property should look like this:

change="d1.getItemAt(0).num = this.hslider.value; d1.refresh()"

I'm actually using these widgets in a web application I'm slowly working on, which has a web of components that interact with each other. It's wargame rules for starship combat for a pencil-and-paper game called Traveller:

http://eaglestone.pocketempires.com/rules/t5/starships/Shipyard.html

Monday, July 6, 2009

Data Binding is Beautiful

One of THE best things about Flex is its data binding. Back in Java days, you had to write synchronization code for every GUI component backed by a data model. Thanks to Flex, all that boilerplate boredom is GONE. As a result, I can populate data grids with ease. For example, check out this Flex app I built in a few hours yesterday:

http://eaglestone.pocketempires.com/rules/t5/starships/TechChooser.html

Monday, May 11, 2009

Comprehensive Flex Archive Network

We need a repository where individuals can share ActionScript and Flex modules. Basically, a large collection of Flex software and documentation.

Or do we?

Take Perl. Do you want to turn your Perl script into a CGI system? Go to CPAN -- the Comprehensive Perl Archive Network -- and grab the CGI module (okay, bad example, it's included in the standard distribution, but you get the idea). CPAN has bazillions of modules, and is an invaluable resource for handling whatever you need to handle. Proofs of concepts get hammered out, new ideas get born, and thoughtful robust code is freely available. All in one practical place.

But, perhaps Flex has a higher level of focus. I've noticed that most of the modules we create require just a bit too much cohesion to be generally useful. Instead of plug-in modules that you can use to add functionality to an application, Flex tends to focus on the applications (or projects) themselves. So it's a higher-level view.

Thursday, May 7, 2009

Password Strength Meter

http://eaglestone.pocketempires.com/flex/passwordMeter/PasswordMeter.html

I found a good starting example of a password strength meter at http://subeesh.wordpress.com/2008/02/19/flex-password-strength-meter/#comment-69

It's got a nice graphical component, and great regular expression checkers, but the algorithms used to evaluate password strength are unknown to me. I imported his gradient bar into my component, which is simply a VBox which contains the graphics context for the gradient and algorithm. The component also requires a "dataProvider", which is just the TextInput component you wish to evaluate.

The source is here:

http://eaglestone.pocketempires.com/flex/passwordMeter/Password.mxml

Monday, May 4, 2009

ComboBox Mediator

Friday I applied the Mediator pattern to a pair of ComboBoxes.

The Mediator, in short, is an interaction between two objects that's been encapsulated into a third object. A go-between. It's almost like a Decorator that works on two objects instead of one.

We have Combo Boxes to choose your country and state. So when a user picks a country, then the list of states has to be filtered for valid selections. We do this all throughout our code for various custom forms (the forms themselves all vary in significant ways, otherwise we could simply re-use one form).

Instead of cloning our code over into yet another class, I wrote a ComboBoxMediator, which wires two ComboBoxes together in a source-sink relationship. The MXML looks like this:


<bgs:ComboBoxMediator
sourceBox="{countryCodeComboBox}"
sourceSelectedValue="{address.countryCode}"
targetBox="{provinceCodeComboBox}"
targetSelectedValue="{address.provinceCode}"
/>


The class itself is short. It sets up filtering in the province ComboBox and adds a change event listener on the country ComboBox.

One important step that I originally didn't anticipate is when the province box is being refreshed: I have to check to see if the filtered data results in no data at all (in other words, in cases where a chosen country doesn't have province data yet assigned to it). In this case, I set the data provider on the province box to an inline array with only one value: "Not Applicable".

Tuesday, April 28, 2009

Quivira - Planning 2

This afternoon I'm using a hex editor to analyze the old Commodore 64 "Map Disk" for 7 Cities of Gold, and here's the physical data, starting from file position 00000000:

"Empty" cells are initially marked with an 01 decimal.

Every 0x100 bytes there's a decimal 10 marker.

Starting in cell $01500, and every 0x100 bytes after, there's an 0x4b.

Finally, we get to the disk header block, starting at 0x16500 with:

(hex) 12 01 41 00,
(hex) 15 ff ff 1f, repeated 17 times,
(hex) 11 fc ff 07,
(hex) 13 ff ff 07, repeated 6 times,
(hex) 12 ff ff 03, repeated 6 times,
(hex) 11 ff ff 01, repeated 5 times.

After that comes the disk's title label, in this case, simply "MAP" in PETSCII:

$16590: 4d 41 50, followed by 0xa0 15 times.

Then there's the disk's two identifiers, separated by an a0:

$165a2: 45 41 a0 32 41, then four more a0's.

Then it's zeros until $16601, which is a big fat FF, then another pile of zeros.

Starting at $16700, we resume the 4b every 0x100 bytes, with 01s in between.

It looks like the actual data begins at $17300, with what seems to be blocks of data 0x100 bytes long. In some of the data blocks, there's a two byte header, then another two byte header at 0x080 bytes (I think).

$17300 to $173ff is very sparse.
$17400 to $174ff is a bit less so.
$17500 to $17599 has even more data.
$17600 to $176ff has more.
$17700 to $177ff is quite busy.

$17800 to $178ff is also busy, but has an unusual pattern not found with the others. Starting at 0x66, descending to 0x10, then climbing up to the 0x90s and 0xa0s at the end of the block. Almost a random walk, but with a deterministic bent, whereas the others are relatively random. Climate data? Climate and altitude?

Then $17900 to $179ff, every value except 5 are between 0xf0 and 0xf8. The exceptions are 0x0a, 0x03, 0x03, and 0x0a, scattered among the 0xf- data. These look like "flags" tied to areas of the map, or something.

$17a00 to $17aff are nearly all 0x3a through 0x3f, with 3 exceptions (0xff, 0x00, and 0x00). Interestingly, the two 0x00's correspond exactly to two of the relative positions in the previous data block. I suspect these data may represent native villages, whether they've been visited, whether there's a mission or fort there, etc. I am probably wrong.

$17b00 to $17bff is random-looking data again.

$17c00 to $17cff is somewhat random, with a lot of zeros surrounding strings of numbers that appear related.

$17d00 to $17dff is mostly zeros, with occasional random-appearing numbers. $17dc0 to $17dff are all zeros. I suspect this is not a single block of data.

$17e00 to $17eff is similar to the previous block, except toward the end: from $17e90 to $17ebf there are nothing but zeros, and from $17ec0 to $17eff it's 0xff's.

$17f00 goes back to our "no data" format: 0x4b every 0x100 bytes, with 0x01 filler.


And then we get some funny data starting at $1a400 and lasting until $1a7ff. Lots of repeating values, and maybe some headers, but I'm not sure.

Then from $1a800 to $1bbff we're back to "no data".

Then there's some data structures from $1bc00 to $1bdff.

Then a block of data from $1be00 to $1beff.

Then, something interesting -- a repeated pattern from $1bf00 to $1bfff: a block that appears to be identical to $17800 to $178ff. A copy of the map? What part of the map? There will have to be a copy when something is changed on the player map, so you can reset and start over. Maybe this is native village data, but then why would the numbers decrease, and then increase again?

$1c000 is regular, random-walk-like numbers, starting at 03 and creeping down to 00, then bouncing back up to 04 halfway through... hey wait, that halfway point has a two-byte marker. Many of the ones that I think are "map" related must have this.

$1c100 starts out with zeros, then a semi-repeating pattern of ff ff's interspersed with zeros, with 7s and 8s as boundaries... in other words, multibyte bitstrings of all 1s followed by all 0s, most of the time. This peters out by $1c1a0, turning into mostly zeros with an occasional number.

From $1c1d0 to $1c4ff there's just zeros, except for a 0x01 and an 0x11 at the tail end of the block.

$1c400 to $1c46f are zeros, then there's a string of 0x11s and an 0x21, then from $1c480 on it's zeros again.


But finally I think I can see the actual map -- the terrain. It begins around $1ca40 (probably the ocean is zeros, which could start at any point before here) and billows along until around $1ceff. Then again from $1cf00 (starting with a short header and a pile of zeros) with actual land appearing around $1d200, and again (I think) at $1d700
to $1dfff, again from $1e000 to $1e7ff (?), $1e800 to $1efff, $1f000 to $1f7ff, $1f800 to $1ffff, $20000 to $207ff, $20800 to $20fff, $21000 to $217ff, $21800 to $21fff... I think.

The data consists of 0x01, 0x11, 0x12, 0x1c, 0x2b, 0xb1, 0xbc, 0xcb, 0xbd, 0xdc, 0xcd, 0xbb, 0xcc, 0xdd, 0xdb. I believe these bit patterns correspond to a particular set of tiles.

The blocks here appear to be in 0x80 byte blocks. More interestingly, every 8 bytes appears to represent one layer of a block of map data that's probably 0x80 bytes in size.

The map ends at $289ff. After that, it's just 0x4b every 0x100 bytes, padded in between with 01s.

Analysis comes later, or maybe never.

About

rob
I'm still looking for my niche.
View my complete profile

Followers