/**
* Copyright lizhi ( http://wonderfl.net/user/lizhi )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/n1yR
*/
// forked from lizhi's treeui
package
{
import com.bit101.components.ScrollPane;
import com.bit101.components.TextArea;
import flash.display.Sprite;
import flash.events.Event;
/**
* ...
* @author lizhi http://matrix3d.github.io/
*/
public class TestTreeUI extends Sprite
{
public var sp:ScrollPane;
public var tree:TreeUI;
public var testData:Object = { arr1:[1,2,3,4],a1:"testa1",vec1:Vector.<Number>([1.1,2.2,1.2])};
public var ta:TextArea;
public function TestTreeUI()
{
sp = new ScrollPane(this);
sp.setSize(400, 480);
tree = new TreeUI();
tree.addEventListener(Event.CHANGE, tree_change);
sp.addChild(tree);
tree.treeModel = new ObjectTreeModel;
tree.data = this;
tree.addEventListener(TreeUI.TREE_CLICK, tree_treeClick);
ta = new TextArea(this, 400);
ta.editable = false;
ta.setSize(400, 480);
}
private function tree_treeClick(e:Event):void
{
var tnode:TreeNodeUI = e.target as TreeNodeUI;
try{
ta.text = JSON.stringify(tnode.node.data, null, 4);
}catch (err:Error) {
ta.text = err + "";
}
}
private function tree_change(e:Event):void
{
sp.draw();
}
}
}
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.CapsStyle;
import flash.display.GradientType;
import flash.display.Graphics;
import flash.display.SpreadMethod;
import flash.display.Sprite;
import flash.events.Event;
import flash.events.EventDispatcher;
import flash.events.MouseEvent;
import flash.geom.Matrix;
import flash.text.TextField;
import flash.text.TextFormat;
import flash.utils.describeType;
import flash.utils.getQualifiedClassName;
/**
* ...
* @author lizhi http://matrix3d.github.io/
*/
class TreeUI extends Sprite
{
public static const TREE_CLICK:String="treeclick"
private var rootTree:TreeNode=new TreeNode;
private var treeUI:Sprite = new Sprite;
private var pen:GradientLinesPen = new GradientLinesPen(treeUI.graphics, [0x999999, 0], [1, 0], [1.5, 1.5], 0);
private var _treeModel:TreeModel;
private var lastSelectTreeNodeUI:TreeNodeUI;
private var _data:Object;
public function TreeUI()
{
addChild(treeUI);
treeModel = new TreeModel;
rootTree.closed = false;
treeUI.addEventListener(TREE_CLICK, treeUI_treeClick);
render();
}
private function treeUI_treeClick(e:Event):void
{
var tnode:TreeNodeUI = e.target as TreeNodeUI;
if (lastSelectTreeNodeUI != tnode) {
if(lastSelectTreeNodeUI)
lastSelectTreeNodeUI.select(false);
lastSelectTreeNodeUI = tnode;
lastSelectTreeNodeUI.select(true);
}
}
public function render():void {
treeUI.graphics.clear();
treeUI.removeChildren();
treeUI.graphics.lineStyle(0, 0xff0000);
renderCell(rootTree, 0, 0);
dispatchEvent(new Event(Event.CHANGE));
}
private function renderCell(tree:TreeNode, x:Number, y:Number):Number {
var sy:Number = y;
var tui:TreeNodeUI=new TreeNodeUI(tree, x, y,this)
treeUI.addChild(tui);
y += 20;
if (!tree.closed) {
var vx:Number = x + 28;
var vy:Number = y;
for each(var child:TreeNode in tree.children) {
pen.moveTo(vx, y+8);
pen.lineTo(vx+12, y + 8);
vy = y;
y = renderCell(child, x + 20, y);
}
if(tree.children.length){
pen.moveTo(vx, sy+20);
pen.lineTo(vx, vy + 8);
}
}
tui.update();
return y;
}
public function update():void {
rootTree._children = null;
render();
}
public function get treeModel():TreeModel
{
return _treeModel;
}
public function set treeModel(value:TreeModel):void
{
if (_treeModel) {
_treeModel.removeEventListener(Event.CHANGE, treeModel_change);
}
_treeModel = value;
rootTree.treeModel = value;
if(_treeModel)_treeModel.addEventListener(Event.CHANGE, treeModel_change);
update();
}
public function get data():Object
{
return _data;
}
public function set data(value:Object):void
{
_data = value;
rootTree.data = value;
update();
}
private function treeModel_change(e:Event):void
{
update();
}
}
/**
* 树形节点
* @author lizhi http://matrix3d.github.io/
*/
class TreeNode {
public static var ID:int = 0;
public var treeModel:TreeModel;
public var parent:TreeNode;
public var closed:Boolean = true;
public var name:String;
public var _children:Vector.<TreeNode>;
public var data:Object
public function get children():Vector.<TreeNode>
{
return treeModel.children(this);
}
public function get numChildren():int {
return treeModel.numChildren(this);
}
public function get label():String
{
return treeModel.label(this);
}
}
/**
* 树节点ui
* @author lizhi http://matrix3d.github.io/
*/
class TreeNodeUI extends flash.display.Sprite {
public var tf:TextField;
public var node:TreeNode;
public var treeUI:TreeUI;
public var openBtn:TreeOpenBtn;
private static var DEFICON:BitmapData;
public function TreeNodeUI(node:TreeNode,x:Number,y:Number,main:TreeUI) {
this.node = node;
this.treeUI = main;
//icon
if (DEFICON==null) {
DEFICON = new BitmapData(16, 16, true, 0);
var pen:Sprite = new Sprite;
pen.graphics.beginFill(0xd7a438);
pen.graphics.drawCircle(8, 8, 7);
DEFICON.draw(pen);
}
var wrapper:Sprite = new Sprite;
addChild(wrapper);
var icon:Bitmap = new Bitmap(DEFICON);
wrapper.addChild(icon);
icon.x = 20;
tf = new TextField();
tf.defaultTextFormat = new TextFormat("微软雅黑");
tf.autoSize = "left";
tf.selectable = tf.mouseWheelEnabled = false;
buttonMode = true;
wrapper.addChild(tf);
tf.x = 40;
tf.y = -3;
tf.backgroundColor = 0x3399ff;
this.x = x;
this.y = y;
openBtn = new TreeOpenBtn();
addChild(openBtn);
openBtn.addEventListener(MouseEvent.CLICK, click);
wrapper.addEventListener(MouseEvent.CLICK, tf_click);
}
private function tf_click(e:MouseEvent):void
{
var e2:MouseEvent = new MouseEvent(TreeUI.TREE_CLICK);
dispatchEvent(e2);
}
public function update():void
{
tf.text = node.label;
openBtn.closed = node.closed;
openBtn.visible = node.numChildren != 0;
}
public function select(boolean:Boolean):void
{
tf.background = boolean;
}
private function click(e:MouseEvent):void
{
node.closed = !node.closed;
treeUI.render();
}
}
class TreeOpenBtn extends Sprite
{
private static var addBmd:BitmapData;
private static var plusBmd:BitmapData;
private var image:Bitmap = new Bitmap;
public function TreeOpenBtn()
{
addChild(image);
if (addBmd==null) {
addBmd = new BitmapData(16, 16, true, 0);
plusBmd = new BitmapData(16, 16, true, 0);
var pen:Sprite = new Sprite;
var openBtn:TextField;
openBtn = new TextField();
openBtn.autoSize = "left";
openBtn.defaultTextFormat = new TextFormat("宋体");
openBtn.textColor=0x4b63a7;
addChild(openBtn);
openBtn.selectable = openBtn.mouseWheelEnabled = false;
openBtn.x = 4;
openBtn.y = 1;
pen.addChild(openBtn);
pen.graphics.lineStyle(0,0x919191);
pen.graphics.beginFill(0xededed);
var o:Number = 4;
pen.graphics.drawRect(0 + o, 0 + o, 16 - o * 2, 16 - o * 2);
openBtn.text="+"
addBmd.draw(pen);
openBtn.text = "-";
plusBmd.draw(pen);
}
closed = true;
}
public function set closed(v:Boolean):void {
image.bitmapData = v?addBmd:plusBmd;
}
}
class TreeModel extends EventDispatcher
{
public function numChildren(node:TreeNode):int {
return node._children?node._children.length:-1;
}
public function children(node:TreeNode):Vector.<TreeNode> {
return Vector.<TreeNode>([]);
}
public function label(node:TreeNode):String {
return node.data+"";
}
}
class ObjectTreeModel extends TreeModel
{
override public function numChildren(node:TreeNode):int {
if(node._children==null){
var i:int = 0;
var xml:XML = describeType(node.data);
if (xml.variable.length()!=0) {
for each(var x:XML in xml.variable) {
i++;
}
}else {
for (var name:String in node.data) {
i++;
}
}
return i;
}
return node._children.length;
}
override public function children(node:TreeNode):Vector.<TreeNode> {
if(node._children==null){
node._children = new Vector.<TreeNode>;
var xml:XML = describeType(node.data);
if (xml.variable.length()!=0) {
for each(var x:XML in xml.variable) {
var c:TreeNode = new TreeNode;
c.treeModel = node.treeModel;
c.data = node.data[x.@name];
c.name = x.@name;
node._children.push(c);
}
}else {
for (var name:String in node.data) {
c = new TreeNode;
c.treeModel = node.treeModel;
c.data = node.data[name];
c.name = name;
node._children.push(c)
}
}
}
return node._children;
}
override public function label(node:TreeNode):String {
var cname:String=getQualifiedClassName(node.data)
if (node.data is Array||cname.indexOf("__AS3__.vec::Vector")==0) {
return node.name+" : ["+cname.replace("__AS3__.vec::","")+"] len:" + node.data.length;
}
return node.name+" : "+node.data;
}
}
class GradientLinesPen
{
private var g:Graphics;
private var colors:Array;
private var alphas:Array;
private var ratios:Array;
private var m:Matrix = new Matrix();
private var thickness:Number;
private var sx:Number;
private var sy:Number;
private var w:Number;
public function GradientLinesPen(g:Graphics,colors:Array,alphas:Array,widths:Array,thickness:Number)
{
this.g = g;
setGradientLines(colors, alphas, widths, thickness);
}
public function setGradientLines(colors:Array,alphas:Array,widths:Array,thickness:Number):void {
for (var i:int = colors.length-2; i > 0;i-- ) {
colors.splice(i, 0, colors[i]);
}
this.colors = colors;
for (i = alphas.length-2; i > 0;i-- ) {
alphas.splice(i, 0, alphas[i]);
}
this.alphas = alphas;
w = 0;
for each(var value:Number in widths) {
w += value;
}
ratios = [];
var cw:Number = 0;
for (i = 0; i < widths.length - 1; i++ ) {
cw += 0xff * widths[i] / w;
ratios.push(cw);
ratios.push(cw);
}
this.thickness = thickness;
}
public function moveTo(x:Number, y:Number):void {
g.moveTo(x, y);
sx = x;
sy = y;
}
public function lineTo(x:Number, y:Number):void {
var dx:Number = x - sx;
var dy:Number = y - sy;
var a:Number = Math.atan2(dy, dx);
var m:Matrix = new Matrix();
m.createGradientBox(w, w, a);
g.lineStyle(thickness, 0, 0, false, null, CapsStyle.SQUARE);
g.lineGradientStyle(GradientType.LINEAR, colors, alphas, ratios, m, SpreadMethod.REPEAT);
g.lineTo(x, y);
sx = x;
sy = y;
}
}